summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Speller <crspeller@gmail.com>2016-05-12 23:56:07 -0400
committerChristopher Speller <crspeller@gmail.com>2016-05-12 23:56:07 -0400
commit38ee83e45b4de7edf89bf9f0ef629eb4c6ad0fa8 (patch)
treea4fde09672192b97d453ad605b030bd5a10c5a45
parent84d2482ddbff9564c9ad75b2d30af66e3ddfd44d (diff)
downloadchat-38ee83e45b4de7edf89bf9f0ef629eb4c6ad0fa8.tar.gz
chat-38ee83e45b4de7edf89bf9f0ef629eb4c6ad0fa8.tar.bz2
chat-38ee83e45b4de7edf89bf9f0ef629eb4c6ad0fa8.zip
Moving to glide
-rw-r--r--.gitignore2
-rw-r--r--Godeps/Godeps.json221
-rw-r--r--Godeps/Readme5
-rw-r--r--Makefile31
-rw-r--r--api/apitestlib.go8
-rw-r--r--glide.lock104
-rw-r--r--glide.yaml41
-rw-r--r--vendor/github.com/NYTimes/gziphandler/gzip_test.go134
-rw-r--r--vendor/github.com/NYTimes/gziphandler/testdata/benchmark.json5456
-rw-r--r--vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go14
-rw-r--r--vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go57
-rw-r--r--vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go42
-rw-r--r--vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go18
-rw-r--r--vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go13
-rw-r--r--vendor/github.com/alecthomas/log4go/examples/example.xml47
-rw-r--r--vendor/github.com/alecthomas/log4go/log4go_test.go534
-rw-r--r--vendor/github.com/braintree/manners/helpers_test.go119
-rw-r--r--vendor/github.com/braintree/manners/server_test.go289
-rw-r--r--vendor/github.com/braintree/manners/test_helpers/certs.go29
-rw-r--r--vendor/github.com/braintree/manners/test_helpers/conn.go13
-rw-r--r--vendor/github.com/braintree/manners/test_helpers/listener.go34
-rw-r--r--vendor/github.com/braintree/manners/test_helpers/temp_file.go27
-rw-r--r--vendor/github.com/braintree/manners/test_helpers/wait_group.go33
-rw-r--r--vendor/github.com/braintree/manners/transition_test.go54
-rwxr-xr-xvendor/github.com/cloudfoundry/jibber_jabber/ci/scripts/windows-64-test.bat5
-rw-r--r--vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_suite_test.go13
-rw-r--r--vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix_test.go104
-rw-r--r--vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows_test.go51
-rw-r--r--vendor/github.com/dgryski/dgoogauth/googauth_test.go251
-rw-r--r--vendor/github.com/disintegration/imaging/adjust_test.go504
-rw-r--r--vendor/github.com/disintegration/imaging/effects_test.go190
-rw-r--r--vendor/github.com/disintegration/imaging/helpers_test.go399
-rw-r--r--vendor/github.com/disintegration/imaging/resize_test.go570
-rw-r--r--vendor/github.com/disintegration/imaging/tools_test.go652
-rw-r--r--vendor/github.com/disintegration/imaging/transform_test.go261
-rw-r--r--vendor/github.com/disintegration/imaging/utils_test.go81
-rw-r--r--vendor/github.com/garyburd/redigo/.travis.yml16
-rw-r--r--vendor/github.com/garyburd/redigo/README.markdown50
-rw-r--r--vendor/github.com/garyburd/redigo/internal/commandinfo.go2
-rw-r--r--vendor/github.com/garyburd/redigo/internal/commandinfo_test.go27
-rw-r--r--vendor/github.com/garyburd/redigo/internal/redistest/testdb.go68
-rw-r--r--vendor/github.com/garyburd/redigo/redis/conn_test.go670
-rw-r--r--vendor/github.com/garyburd/redigo/redis/doc.go2
-rw-r--r--vendor/github.com/garyburd/redigo/redis/pool_test.go684
-rw-r--r--vendor/github.com/garyburd/redigo/redis/pubsub_test.go148
-rw-r--r--vendor/github.com/garyburd/redigo/redis/reply_test.go179
-rw-r--r--vendor/github.com/garyburd/redigo/redis/scan_test.go440
-rw-r--r--vendor/github.com/garyburd/redigo/redis/script_test.go100
-rw-r--r--vendor/github.com/garyburd/redigo/redis/test_test.go177
-rw-r--r--vendor/github.com/garyburd/redigo/redis/zpop_example_test.go113
-rw-r--r--vendor/github.com/garyburd/redigo/redisx/connmux.go152
-rw-r--r--vendor/github.com/garyburd/redigo/redisx/connmux_test.go259
-rw-r--r--vendor/github.com/garyburd/redigo/redisx/doc.go17
-rw-r--r--vendor/github.com/go-gorp/gorp/dialect_mysql_test.go204
-rw-r--r--vendor/github.com/go-gorp/gorp/gorp_suite_test.go13
-rw-r--r--vendor/github.com/go-gorp/gorp/gorp_test.go2412
-rwxr-xr-x[-rw-r--r--]vendor/github.com/go-gorp/gorp/test_all.sh0
-rw-r--r--vendor/github.com/go-ldap/ldap/conn_test.go53
-rw-r--r--vendor/github.com/go-ldap/ldap/dn_test.go70
-rw-r--r--vendor/github.com/go-ldap/ldap/error_test.go29
-rw-r--r--vendor/github.com/go-ldap/ldap/example_test.go305
-rw-r--r--vendor/github.com/go-ldap/ldap/filter_test.go248
-rw-r--r--vendor/github.com/go-ldap/ldap/ldap_test.go275
-rw-r--r--vendor/github.com/go-ldap/ldap/search_test.go31
-rw-r--r--vendor/github.com/go-sql-driver/mysql/benchmark_test.go246
-rw-r--r--vendor/github.com/go-sql-driver/mysql/driver_test.go1857
-rw-r--r--vendor/github.com/go-sql-driver/mysql/dsn_test.go207
-rw-r--r--vendor/github.com/go-sql-driver/mysql/errors_test.go42
-rw-r--r--vendor/github.com/go-sql-driver/mysql/utils_test.go197
-rw-r--r--vendor/github.com/goamz/goamz/.gitignore1
-rw-r--r--vendor/github.com/goamz/goamz/.lbox1
-rw-r--r--vendor/github.com/goamz/goamz/.travis.yml32
-rw-r--r--vendor/github.com/goamz/goamz/CHANGES.md5
-rw-r--r--vendor/github.com/goamz/goamz/README.md64
-rw-r--r--vendor/github.com/goamz/goamz/autoscaling/autoscaling.go1768
-rw-r--r--vendor/github.com/goamz/goamz/autoscaling/autoscaling_test.go1180
-rw-r--r--vendor/github.com/goamz/goamz/autoscaling/responses_test.go627
-rw-r--r--vendor/github.com/goamz/goamz/aws/attempt_test.go58
-rw-r--r--vendor/github.com/goamz/goamz/aws/aws_test.go211
-rw-r--r--vendor/github.com/goamz/goamz/aws/client_test.go121
-rw-r--r--vendor/github.com/goamz/goamz/aws/export_test.go29
-rw-r--r--vendor/github.com/goamz/goamz/aws/sign_test.go540
-rw-r--r--vendor/github.com/goamz/goamz/cloudformation/cloudformation.go837
-rw-r--r--vendor/github.com/goamz/goamz/cloudformation/cloudformation_test.go653
-rw-r--r--vendor/github.com/goamz/goamz/cloudformation/responses_test.go371
-rw-r--r--vendor/github.com/goamz/goamz/cloudfront/cloudfront.go135
-rw-r--r--vendor/github.com/goamz/goamz/cloudfront/cloudfront_test.go52
-rw-r--r--vendor/github.com/goamz/goamz/cloudfront/testdata/key.pem15
-rw-r--r--vendor/github.com/goamz/goamz/cloudfront/testdata/key.pub6
-rw-r--r--vendor/github.com/goamz/goamz/cloudwatch/ChangeLog7
-rw-r--r--vendor/github.com/goamz/goamz/cloudwatch/README.md109
-rw-r--r--vendor/github.com/goamz/goamz/cloudwatch/cloudwatch.go404
-rw-r--r--vendor/github.com/goamz/goamz/cloudwatch/cloudwatch_test.go132
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/.gitignore1
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/Makefile13
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/README.md27
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/attribute.go185
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/const.go11
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/dynamodb.go142
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/dynamodb_test.go166
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/item.go351
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/item_test.go446
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/marshaller.go626
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/marshaller_test.go283
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/query.go111
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/query_builder.go362
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/query_builder_test.go380
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/scan.go51
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/stream.go307
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/stream_test.go198
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/table.go259
-rwxr-xr-xvendor/github.com/goamz/goamz/dynamodb/table_test.go79
-rw-r--r--vendor/github.com/goamz/goamz/dynamodb/update_item.go94
-rw-r--r--vendor/github.com/goamz/goamz/ec2/ec2.go2267
-rw-r--r--vendor/github.com/goamz/goamz/ec2/ec2_test.go1280
-rw-r--r--vendor/github.com/goamz/goamz/ec2/ec2i_test.go204
-rw-r--r--vendor/github.com/goamz/goamz/ec2/ec2t_test.go581
-rw-r--r--vendor/github.com/goamz/goamz/ec2/ec2test/filter.go84
-rw-r--r--vendor/github.com/goamz/goamz/ec2/ec2test/server.go993
-rw-r--r--vendor/github.com/goamz/goamz/ec2/export_test.go22
-rw-r--r--vendor/github.com/goamz/goamz/ec2/responses_test.go1084
-rw-r--r--vendor/github.com/goamz/goamz/ec2/sign.go45
-rw-r--r--vendor/github.com/goamz/goamz/ec2/sign_test.go68
-rw-r--r--vendor/github.com/goamz/goamz/ec2/vpc.go399
-rw-r--r--vendor/github.com/goamz/goamz/ec2/vpc_test.go224
-rw-r--r--vendor/github.com/goamz/goamz/ecs/ecs.go1075
-rw-r--r--vendor/github.com/goamz/goamz/ecs/ecs_test.go806
-rw-r--r--vendor/github.com/goamz/goamz/ecs/responses_test.go637
-rw-r--r--vendor/github.com/goamz/goamz/elb/elb.go435
-rw-r--r--vendor/github.com/goamz/goamz/elb/elb_test.go369
-rw-r--r--vendor/github.com/goamz/goamz/elb/elbi_test.go308
-rw-r--r--vendor/github.com/goamz/goamz/elb/elbt_test.go243
-rw-r--r--vendor/github.com/goamz/goamz/elb/elbtest/server.go551
-rw-r--r--vendor/github.com/goamz/goamz/elb/export_test.go9
-rw-r--r--vendor/github.com/goamz/goamz/elb/response_test.go234
-rw-r--r--vendor/github.com/goamz/goamz/elb/sign.go35
-rw-r--r--vendor/github.com/goamz/goamz/elb/sign_test.go66
-rw-r--r--vendor/github.com/goamz/goamz/elb/suite_test.go119
-rw-r--r--vendor/github.com/goamz/goamz/exp/mturk/example_test.go66
-rw-r--r--vendor/github.com/goamz/goamz/exp/mturk/export_test.go9
-rw-r--r--vendor/github.com/goamz/goamz/exp/mturk/mturk.go480
-rw-r--r--vendor/github.com/goamz/goamz/exp/mturk/mturk_test.go170
-rw-r--r--vendor/github.com/goamz/goamz/exp/mturk/responses_test.go36
-rw-r--r--vendor/github.com/goamz/goamz/exp/mturk/sign.go22
-rw-r--r--vendor/github.com/goamz/goamz/exp/mturk/sign_test.go19
-rw-r--r--vendor/github.com/goamz/goamz/exp/sdb/export_test.go9
-rw-r--r--vendor/github.com/goamz/goamz/exp/sdb/responses_test.go120
-rw-r--r--vendor/github.com/goamz/goamz/exp/sdb/sdb.go413
-rw-r--r--vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go219
-rw-r--r--vendor/github.com/goamz/goamz/exp/sdb/sign.go54
-rw-r--r--vendor/github.com/goamz/goamz/exp/sdb/sign_test.go29
-rw-r--r--vendor/github.com/goamz/goamz/exp/ses/ses.go145
-rw-r--r--vendor/github.com/goamz/goamz/exp/ses/ses_test.go69
-rw-r--r--vendor/github.com/goamz/goamz/exp/ses/ses_types.go156
-rw-r--r--vendor/github.com/goamz/goamz/exp/ses/sign.go26
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/Makefile21
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/README1
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/endpoint.go132
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/permissions.go51
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/platform.go135
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/responses_test.go317
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/sign.go72
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/sns.go113
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/sns_test.go455
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/subscription.go165
-rw-r--r--vendor/github.com/goamz/goamz/exp/sns/topic.go104
-rw-r--r--vendor/github.com/goamz/goamz/iam/iam.go643
-rw-r--r--vendor/github.com/goamz/goamz/iam/iam_test.go450
-rw-r--r--vendor/github.com/goamz/goamz/iam/iami_test.go209
-rw-r--r--vendor/github.com/goamz/goamz/iam/iamt_test.go39
-rw-r--r--vendor/github.com/goamz/goamz/iam/iamtest/server.go432
-rw-r--r--vendor/github.com/goamz/goamz/iam/responses_test.go261
-rw-r--r--vendor/github.com/goamz/goamz/iam/sign.go38
-rw-r--r--vendor/github.com/goamz/goamz/rds/rds.go96
-rw-r--r--vendor/github.com/goamz/goamz/rds/rds_test.go77
-rw-r--r--vendor/github.com/goamz/goamz/rds/responses_test.go57
-rw-r--r--vendor/github.com/goamz/goamz/rds/types.go388
-rw-r--r--vendor/github.com/goamz/goamz/route53/route53.go254
-rw-r--r--vendor/github.com/goamz/goamz/s3/export_test.go17
-rw-r--r--vendor/github.com/goamz/goamz/s3/multi_test.go373
-rw-r--r--vendor/github.com/goamz/goamz/s3/responses_test.go202
-rw-r--r--vendor/github.com/goamz/goamz/s3/s3_test.go427
-rw-r--r--vendor/github.com/goamz/goamz/s3/s3i_test.go590
-rw-r--r--vendor/github.com/goamz/goamz/s3/s3t_test.go83
-rw-r--r--vendor/github.com/goamz/goamz/s3/s3test/server.go640
-rw-r--r--vendor/github.com/goamz/goamz/s3/sign_test.go132
-rw-r--r--vendor/github.com/goamz/goamz/sqs/Makefile20
-rw-r--r--vendor/github.com/goamz/goamz/sqs/README.md38
-rw-r--r--vendor/github.com/goamz/goamz/sqs/responses_test.go196
-rw-r--r--vendor/github.com/goamz/goamz/sqs/sqs.go570
-rw-r--r--vendor/github.com/goamz/goamz/sqs/sqs_test.go414
-rw-r--r--vendor/github.com/goamz/goamz/sqs/suite_test.go145
-rw-r--r--vendor/github.com/goamz/goamz/sts/responses_test.go84
-rw-r--r--vendor/github.com/goamz/goamz/sts/sts.go273
-rw-r--r--vendor/github.com/goamz/goamz/sts/sts_test.go151
-rw-r--r--vendor/github.com/goamz/goamz/testutil/http.go180
-rw-r--r--vendor/github.com/goamz/goamz/testutil/suite.go31
-rw-r--r--vendor/github.com/golang/freetype/cmd/print-glyph-points/main.c87
-rw-r--r--vendor/github.com/golang/freetype/example/capjoin/main.go85
-rw-r--r--vendor/github.com/golang/freetype/example/drawer/main.go158
-rw-r--r--vendor/github.com/golang/freetype/example/freetype/main.go150
-rw-r--r--vendor/github.com/golang/freetype/example/gamma/main.go86
-rw-r--r--vendor/github.com/golang/freetype/example/raster/main.go185
-rw-r--r--vendor/github.com/golang/freetype/example/round/main.go110
-rw-r--r--vendor/github.com/golang/freetype/example/truetype/main.go89
-rw-r--r--vendor/github.com/golang/freetype/freetype.go2
-rw-r--r--vendor/github.com/golang/freetype/freetype_test.go59
-rw-r--r--vendor/github.com/golang/freetype/licenses/ftl.txt169
-rw-r--r--vendor/github.com/golang/freetype/licenses/gpl.txt340
-rw-r--r--vendor/github.com/golang/freetype/raster/raster.go2
-rw-r--r--vendor/github.com/golang/freetype/testdata/COPYING42
-rw-r--r--vendor/github.com/golang/freetype/testdata/README13
-rw-r--r--vendor/github.com/golang/freetype/testdata/luximr.ttfbin0 -> 71784 bytes
-rw-r--r--vendor/github.com/golang/freetype/testdata/luximr.ttx24616
-rw-r--r--vendor/github.com/golang/freetype/testdata/luxirr.ttfbin0 -> 88732 bytes
-rw-r--r--vendor/github.com/golang/freetype/testdata/luxirr.ttx30264
-rw-r--r--vendor/github.com/golang/freetype/testdata/luxisr-12pt-sans-hinting.txt392
-rw-r--r--vendor/github.com/golang/freetype/testdata/luxisr-12pt-with-hinting.txt392
-rw-r--r--vendor/github.com/golang/freetype/testdata/luxisr.ttfbin0 -> 67548 bytes
-rw-r--r--vendor/github.com/golang/freetype/testdata/luxisr.ttx22503
-rwxr-xr-xvendor/github.com/golang/freetype/testdata/make-other-hinting-txts.sh34
-rw-r--r--vendor/github.com/golang/freetype/truetype/face_test.go48
-rw-r--r--vendor/github.com/golang/freetype/truetype/hint_test.go675
-rw-r--r--vendor/github.com/golang/freetype/truetype/truetype.go2
-rw-r--r--vendor/github.com/golang/freetype/truetype/truetype_test.go400
-rw-r--r--vendor/github.com/golang/groupcache/.gitignore1
-rw-r--r--vendor/github.com/golang/groupcache/README.md73
-rw-r--r--vendor/github.com/golang/groupcache/byteview.go160
-rw-r--r--vendor/github.com/golang/groupcache/byteview_test.go142
-rw-r--r--vendor/github.com/golang/groupcache/consistenthash/consistenthash.go81
-rw-r--r--vendor/github.com/golang/groupcache/consistenthash/consistenthash_test.go110
-rw-r--r--vendor/github.com/golang/groupcache/groupcache.go489
-rw-r--r--vendor/github.com/golang/groupcache/groupcache_test.go447
-rw-r--r--vendor/github.com/golang/groupcache/groupcachepb/groupcache.pb.go65
-rw-r--r--vendor/github.com/golang/groupcache/groupcachepb/groupcache.proto34
-rw-r--r--vendor/github.com/golang/groupcache/http.go227
-rw-r--r--vendor/github.com/golang/groupcache/http_test.go166
-rw-r--r--vendor/github.com/golang/groupcache/lru/lru_test.go73
-rw-r--r--vendor/github.com/golang/groupcache/peers.go71
-rw-r--r--vendor/github.com/golang/groupcache/singleflight/singleflight.go64
-rw-r--r--vendor/github.com/golang/groupcache/singleflight/singleflight_test.go85
-rw-r--r--vendor/github.com/golang/groupcache/sinks.go322
-rw-r--r--vendor/github.com/golang/groupcache/testpb/test.pb.go235
-rw-r--r--vendor/github.com/golang/groupcache/testpb/test.proto63
-rw-r--r--vendor/github.com/gorilla/context/context_test.go161
-rw-r--r--vendor/github.com/gorilla/handlers/canonical_test.go127
-rw-r--r--vendor/github.com/gorilla/handlers/compress_test.go154
-rw-r--r--vendor/github.com/gorilla/handlers/cors_test.go336
-rw-r--r--vendor/github.com/gorilla/handlers/handlers_test.go354
-rw-r--r--vendor/github.com/gorilla/handlers/proxy_headers_test.go100
-rw-r--r--vendor/github.com/gorilla/handlers/recovery_test.go44
-rw-r--r--vendor/github.com/gorilla/mux/bench_test.go49
-rw-r--r--vendor/github.com/gorilla/mux/mux_test.go1471
-rw-r--r--vendor/github.com/gorilla/mux/old_test.go710
-rw-r--r--vendor/github.com/gorilla/websocket/bench_test.go19
-rw-r--r--vendor/github.com/gorilla/websocket/client_server_test.go451
-rw-r--r--vendor/github.com/gorilla/websocket/client_test.go72
-rw-r--r--vendor/github.com/gorilla/websocket/conn_test.go402
-rw-r--r--vendor/github.com/gorilla/websocket/example_test.go46
-rw-r--r--vendor/github.com/gorilla/websocket/examples/autobahn/README.md13
-rw-r--r--vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json14
-rw-r--r--vendor/github.com/gorilla/websocket/examples/autobahn/server.go246
-rw-r--r--vendor/github.com/gorilla/websocket/examples/chat/README.md20
-rw-r--r--vendor/github.com/gorilla/websocket/examples/chat/conn.go105
-rw-r--r--vendor/github.com/gorilla/websocket/examples/chat/home.html92
-rw-r--r--vendor/github.com/gorilla/websocket/examples/chat/hub.go51
-rw-r--r--vendor/github.com/gorilla/websocket/examples/chat/main.go39
-rw-r--r--vendor/github.com/gorilla/websocket/examples/command/README.md19
-rw-r--r--vendor/github.com/gorilla/websocket/examples/command/home.html96
-rw-r--r--vendor/github.com/gorilla/websocket/examples/command/main.go188
-rw-r--r--vendor/github.com/gorilla/websocket/examples/echo/README.md17
-rw-r--r--vendor/github.com/gorilla/websocket/examples/echo/client.go81
-rw-r--r--vendor/github.com/gorilla/websocket/examples/echo/server.go132
-rw-r--r--vendor/github.com/gorilla/websocket/examples/filewatch/README.md9
-rw-r--r--vendor/github.com/gorilla/websocket/examples/filewatch/main.go193
-rw-r--r--vendor/github.com/gorilla/websocket/json_test.go119
-rw-r--r--vendor/github.com/gorilla/websocket/server_test.go51
-rw-r--r--vendor/github.com/gorilla/websocket/util_test.go34
-rw-r--r--vendor/github.com/lib/pq/.travis.yml3
-rw-r--r--vendor/github.com/lib/pq/README.md4
-rw-r--r--vendor/github.com/lib/pq/bench_test.go435
-rw-r--r--vendor/github.com/lib/pq/certs/README3
-rw-r--r--vendor/github.com/lib/pq/certs/postgresql.crt69
-rw-r--r--vendor/github.com/lib/pq/certs/postgresql.key15
-rw-r--r--vendor/github.com/lib/pq/certs/root.crt24
-rw-r--r--vendor/github.com/lib/pq/certs/server.crt81
-rw-r--r--vendor/github.com/lib/pq/certs/server.key27
-rw-r--r--vendor/github.com/lib/pq/conn_test.go1434
-rw-r--r--vendor/github.com/lib/pq/copy_test.go465
-rw-r--r--vendor/github.com/lib/pq/encode.go3
-rw-r--r--vendor/github.com/lib/pq/encode_test.go727
-rw-r--r--vendor/github.com/lib/pq/hstore/hstore.go118
-rw-r--r--vendor/github.com/lib/pq/hstore/hstore_test.go148
-rw-r--r--vendor/github.com/lib/pq/listen_example/doc.go102
-rw-r--r--vendor/github.com/lib/pq/notify.go22
-rw-r--r--vendor/github.com/lib/pq/notify_test.go574
-rw-r--r--vendor/github.com/lib/pq/ssl_test.go226
-rw-r--r--vendor/github.com/lib/pq/url_test.go66
-rw-r--r--vendor/github.com/mattermost/rsc/.gitignore22
-rw-r--r--vendor/github.com/mattermost/rsc/README.md4
-rw-r--r--vendor/github.com/mattermost/rsc/app/app.go39
-rw-r--r--vendor/github.com/mattermost/rsc/app/app.yaml23
-rw-r--r--vendor/github.com/mattermost/rsc/app/index.yaml16
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/appfile/main.go156
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/appmount/main.go287
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/client/client.go150
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/fs/fs.go273
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/fs/local.go82
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/proto/data.go55
-rw-r--r--vendor/github.com/mattermost/rsc/appfs/server/app.go982
-rw-r--r--vendor/github.com/mattermost/rsc/arq/arq.go663
-rw-r--r--vendor/github.com/mattermost/rsc/arq/arqfs/main.go247
-rw-r--r--vendor/github.com/mattermost/rsc/arq/crypto.go93
-rw-r--r--vendor/github.com/mattermost/rsc/arq/data.go240
-rw-r--r--vendor/github.com/mattermost/rsc/arq/hist/hist.go160
-rw-r--r--vendor/github.com/mattermost/rsc/arq/unpack.go227
-rw-r--r--vendor/github.com/mattermost/rsc/blog/atom/atom.go58
-rw-r--r--vendor/github.com/mattermost/rsc/blog/main.go15
-rw-r--r--vendor/github.com/mattermost/rsc/blog/post/post.go534
-rw-r--r--vendor/github.com/mattermost/rsc/blog/post/qr.go34
-rw-r--r--vendor/github.com/mattermost/rsc/cmd/crypt/crypt.go79
-rw-r--r--vendor/github.com/mattermost/rsc/cmd/issue/issue.go185
-rw-r--r--vendor/github.com/mattermost/rsc/cmd/jfmt/main.go37
-rw-r--r--vendor/github.com/mattermost/rsc/crypt/crypt.go150
-rw-r--r--vendor/github.com/mattermost/rsc/devweb/main.go317
-rw-r--r--vendor/github.com/mattermost/rsc/devweb/slave/slave.go26
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/debug.go20
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/fuse.go1650
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/fuse_kernel.go539
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/fuse_kernel_darwin.go58
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/fuse_kernel_linux.go50
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/fuse_kernel_std.go1
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/fuse_test.go594
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/hellofs/hello.go62
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/mount_darwin.go122
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/mount_linux.go67
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/serve.go1022
-rw-r--r--vendor/github.com/mattermost/rsc/fuse/tree.go93
-rw-r--r--vendor/github.com/mattermost/rsc/gf256/blog_test.go85
-rw-r--r--vendor/github.com/mattermost/rsc/gf256/gf256_test.go194
-rw-r--r--vendor/github.com/mattermost/rsc/google/acme/Chat/main.go575
-rw-r--r--vendor/github.com/mattermost/rsc/google/chat.go39
-rw-r--r--vendor/github.com/mattermost/rsc/google/gmail/gmail.go1241
-rw-r--r--vendor/github.com/mattermost/rsc/google/gmailsend/send.go370
-rw-r--r--vendor/github.com/mattermost/rsc/google/googleserver/chat.go80
-rw-r--r--vendor/github.com/mattermost/rsc/google/googleserver/main.go139
-rw-r--r--vendor/github.com/mattermost/rsc/google/main.go181
-rw-r--r--vendor/github.com/mattermost/rsc/gtfs/gtfs.pb.go440
-rw-r--r--vendor/github.com/mattermost/rsc/imap/Makefile15
-rw-r--r--vendor/github.com/mattermost/rsc/imap/decode.go227
-rw-r--r--vendor/github.com/mattermost/rsc/imap/decode_test.go26
-rw-r--r--vendor/github.com/mattermost/rsc/imap/imap.go1110
-rw-r--r--vendor/github.com/mattermost/rsc/imap/imap_test.go433
-rw-r--r--vendor/github.com/mattermost/rsc/imap/mail.go468
-rw-r--r--vendor/github.com/mattermost/rsc/imap/mail_test.go335
-rw-r--r--vendor/github.com/mattermost/rsc/imap/rfc2045.txt1739
-rw-r--r--vendor/github.com/mattermost/rsc/imap/rfc2971.txt451
-rw-r--r--vendor/github.com/mattermost/rsc/imap/rfc3501.txt6051
-rw-r--r--vendor/github.com/mattermost/rsc/imap/sx.go350
-rw-r--r--vendor/github.com/mattermost/rsc/imap/sx_test.go60
-rw-r--r--vendor/github.com/mattermost/rsc/imap/tcs.go602
-rw-r--r--vendor/github.com/mattermost/rsc/keychain/doc.go28
-rw-r--r--vendor/github.com/mattermost/rsc/keychain/mac.go107
-rw-r--r--vendor/github.com/mattermost/rsc/mbta/Passages.pbbin0 -> 69799 bytes
-rw-r--r--vendor/github.com/mattermost/rsc/mbta/Vehicles.pbbin0 -> 35798 bytes
-rw-r--r--vendor/github.com/mattermost/rsc/mbta/mbta.go28
-rwxr-xr-xvendor/github.com/mattermost/rsc/mkapp51
-rw-r--r--vendor/github.com/mattermost/rsc/plist/plist.go179
-rw-r--r--vendor/github.com/mattermost/rsc/plist/plist_test.go110
-rw-r--r--vendor/github.com/mattermost/rsc/qr/coding/qr_test.go133
-rw-r--r--vendor/github.com/mattermost/rsc/qr/libqrencode/Makefile4
-rw-r--r--vendor/github.com/mattermost/rsc/qr/libqrencode/qrencode.go149
-rw-r--r--vendor/github.com/mattermost/rsc/qr/png_test.go73
-rw-r--r--vendor/github.com/mattermost/rsc/qr/web/pic.go506
-rw-r--r--vendor/github.com/mattermost/rsc/qr/web/play.go1118
-rw-r--r--vendor/github.com/mattermost/rsc/qr/web/resize/resize.go152
-rw-r--r--vendor/github.com/mattermost/rsc/regexp/regmerge/copy.go225
-rw-r--r--vendor/github.com/mattermost/rsc/regexp/regmerge/main.go96
-rw-r--r--vendor/github.com/mattermost/rsc/regexp/regmerge/match.go406
-rw-r--r--vendor/github.com/mattermost/rsc/regexp/regmerge/merge.go103
-rw-r--r--vendor/github.com/mattermost/rsc/regexp/regmerge/sort.go199
-rw-r--r--vendor/github.com/mattermost/rsc/regexp/regmerge/sparse.go80
-rw-r--r--vendor/github.com/mattermost/rsc/regexp/regmerge/utf.go270
-rw-r--r--vendor/github.com/mattermost/rsc/rosetta/graph/Makefile7
-rw-r--r--vendor/github.com/mattermost/rsc/rosetta/graph/graph.go133
-rw-r--r--vendor/github.com/mattermost/rsc/rosetta/maze/Makefile8
-rw-r--r--vendor/github.com/mattermost/rsc/rosetta/maze/maze.go191
-rw-r--r--vendor/github.com/mattermost/rsc/s3get/main.go85
-rw-r--r--vendor/github.com/mattermost/rsc/smugmug/smug.go542
-rw-r--r--vendor/github.com/mattermost/rsc/smugmug/smugup/main.go158
l---------vendor/github.com/mattermost/rsc/tmp/app1
l---------vendor/github.com/mattermost/rsc/tmp/appfs1
l---------vendor/github.com/mattermost/rsc/tmp/arq1
l---------vendor/github.com/mattermost/rsc/tmp/blog1
l---------vendor/github.com/mattermost/rsc/tmp/cmd1
l---------vendor/github.com/mattermost/rsc/tmp/crypt1
l---------vendor/github.com/mattermost/rsc/tmp/devweb1
l---------vendor/github.com/mattermost/rsc/tmp/fuse1
l---------vendor/github.com/mattermost/rsc/tmp/gf2561
l---------vendor/github.com/mattermost/rsc/tmp/google1
l---------vendor/github.com/mattermost/rsc/tmp/gtfs1
l---------vendor/github.com/mattermost/rsc/tmp/imap1
l---------vendor/github.com/mattermost/rsc/tmp/keychain1
l---------vendor/github.com/mattermost/rsc/tmp/mbta1
l---------vendor/github.com/mattermost/rsc/tmp/mkapp1
l---------vendor/github.com/mattermost/rsc/tmp/plist1
l---------vendor/github.com/mattermost/rsc/tmp/qr1
l---------vendor/github.com/mattermost/rsc/tmp/regexp1
l---------vendor/github.com/mattermost/rsc/tmp/rosetta1
l---------vendor/github.com/mattermost/rsc/tmp/s3get1
l---------vendor/github.com/mattermost/rsc/tmp/smugmug1
l---------vendor/github.com/mattermost/rsc/tmp/xmpp1
-rw-r--r--vendor/github.com/mattermost/rsc/xmpp/xmpp.go572
-rw-r--r--vendor/github.com/mssola/user_agent/all_test.go529
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/.gitignore6
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/.travis.yml8
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/CHANGELOG5
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/README.md130
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go59
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh10
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go82
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go127
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go74
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml30
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json65
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json50
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json45
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json1
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json45
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json45
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json54
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json54
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json30
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json26
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/fr-fr.json0
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json54
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json54
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml19
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json26
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/fr-fr.json0
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go289
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go63
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go63
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go62
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh5
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go132
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/plurals.xml230
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go143
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go85
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go45
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go28
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go645
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go733
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go308
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go146
-rw-r--r--vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go17
-rwxr-xr-x[-rw-r--r--]vendor/github.com/pborman/uuid/dce.go0
-rwxr-xr-x[-rw-r--r--]vendor/github.com/pborman/uuid/doc.go0
-rw-r--r--vendor/github.com/pborman/uuid/json_test.go61
-rwxr-xr-x[-rw-r--r--]vendor/github.com/pborman/uuid/node.go0
-rw-r--r--vendor/github.com/pborman/uuid/seq_test.go66
-rw-r--r--vendor/github.com/pborman/uuid/sql_test.go96
-rwxr-xr-x[-rw-r--r--]vendor/github.com/pborman/uuid/time.go0
-rw-r--r--vendor/github.com/pborman/uuid/uuid_test.go543
-rw-r--r--vendor/github.com/rwcarlsen/goexif/.gitignore23
-rw-r--r--vendor/github.com/rwcarlsen/goexif/README.md71
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/corrupt/huge_tag_exif.jpgbin0 -> 65536 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/corrupt/infinite_loop_exif.jpgbin0 -> 3738 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/corrupt/max_uint32_exif.jpgbin0 -> 65536 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/example_test.go42
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/exif_test.go202
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/regress_expected_test.go2293
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2004-01-11-22-45-15-sep-2004-01-11-22-45-15a.jpgbin0 -> 4586 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2006-08-03-16-29-38-sep-2006-08-03-16-29-38a.jpgbin0 -> 9735 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2006-11-11-19-17-56-sep-2006-11-11-19-17-56a.jpgbin0 -> 35406 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-10-23-58-20-sep-2006-12-10-23-58-20a.jpgbin0 -> 8711 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-17-07-09-14-sep-2006-12-17-07-09-14a.jpgbin0 -> 38252 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-21-15-55-26-sep-2006-12-21-15-55-26a.jpgbin0 -> 16072 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-01-12-00-00-sep-2007-01-01-12-00-00a.jpgbin0 -> 17301 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-17-21-49-44-sep-2007-01-17-21-49-44a.jpgbin0 -> 7999 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-02-02-18-13-29-sep-2007-02-02-18-13-29a.jpgbin0 -> 39915 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-02-17-02-21-sep-2007-05-02-17-02-21a.jpgbin0 -> 11783 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-12-08-19-07-sep-2007-05-12-08-19-07a.jpgbin0 -> 35771 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-26-04-49-45-sep-2007-05-26-04-49-45a.jpgbin0 -> 35406 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-30-14-28-01-sep-2007-05-30-14-28-01a.jpgbin0 -> 35406 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-06-16-15-25-sep-2007-06-06-16-15-25a.jpgbin0 -> 35406 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-26-10-13-04-sep-2007-06-26-10-13-04a.jpgbin0 -> 7615 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-07-13-17-02-30-sep-2007-07-13-17-02-30a.jpgbin0 -> 21719 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-15-14-42-46-sep-2007-08-15-14-42-46a.jpgbin0 -> 11549 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-24-02-40-42-sep-2007-08-24-02-40-42a.jpgbin0 -> 7687 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2007-11-07-11-40-44-sep-2007-11-07-11-40-44a.jpgbin0 -> 11223 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-02-10-03-57-sep-2008-06-02-10-03-57a.jpgbin0 -> 9745 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-06-13-29-29-sep-2008-06-06-13-29-29a.jpgbin0 -> 11783 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-17-01-21-30-sep-2008-06-17-01-21-30a.jpgbin0 -> 14564 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2008-09-02-17-43-48-sep-2008-09-02-17-43-48a.jpgbin0 -> 5406 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2009-03-26-09-23-20-sep-2009-03-26-09-23-20a.jpgbin0 -> 10759 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-11-03-01-38-sep-2009-04-11-03-01-38a.jpgbin0 -> 43374 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-23-07-21-35-sep-2009-04-23-07-21-35a.jpgbin0 -> 37208 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-11-19-23-18-sep-2009-06-11-19-23-18a.jpgbin0 -> 7791 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-20-07-59-05-sep-2009-06-20-07-59-05a.jpgbin0 -> 13618 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2009-08-05-08-11-31-sep-2009-08-05-08-11-31a.jpgbin0 -> 9919 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-08-04-44-24-sep-2010-06-08-04-44-24a.jpgbin0 -> 10939 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-20-20-07-39-sep-2010-06-20-20-07-39a.jpgbin0 -> 8551 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2010-09-02-08-43-02-sep-2010-09-02-08-43-02a.jpgbin0 -> 19534 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2011-01-24-22-06-02-sep-2011-01-24-22-06-02a.jpgbin0 -> 29003 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2011-03-07-09-28-03-sep-2011-03-07-09-28-03a.jpgbin0 -> 10529 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2011-05-07-13-02-49-sep-2011-05-07-13-02-49a.jpgbin0 -> 23743 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2011-08-07-19-22-57-sep-2011-08-07-19-22-57a.jpgbin0 -> 9936 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-17-50-18-sep-2011-10-28-17-50-18a.jpgbin0 -> 7487 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-18-25-43-sep-2011-10-28-18-25-43.jpgbin0 -> 7433 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2011-11-18-15-38-34-sep-Photo11181538.jpgbin0 -> 12885 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2012-06-02-10-12-28-sep-2012-06-02-10-12-28.jpgbin0 -> 32165 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2012-09-21-22-07-34-sep-2012-09-21-22-07-34.jpgbin0 -> 10247 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-19-21-38-40-sep-temple_square1.jpgbin0 -> 39182 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-21-11-15-19-sep-IMG_0001.jpgbin0 -> 25269 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2013-02-05-23-12-09-sep-DSCI0001.jpgbin0 -> 10854 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2099-08-12-19-59-29-sep-2099-08-12-19-59-29a.jpgbin0 -> 37491 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/2216-11-15-11-46-51-sep-2216-11-15-11-46-51a.jpgbin0 -> 23011 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/FailedHash-NoDate-sep-remembory.jpgbin0 -> 935 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f1-exif.jpgbin0 -> 992 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f2-exif.jpgbin0 -> 994 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f3-exif.jpgbin0 -> 992 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f4-exif.jpgbin0 -> 994 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f5-exif.jpgbin0 -> 980 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f6-exif.jpgbin0 -> 982 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f7-exif.jpgbin0 -> 980 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/f8-exif.jpgbin0 -> 982 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/geodegrees_as_string.jpgbin0 -> 22420 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exif/samples/has-lens-info.jpgbin0 -> 22493 bytes
-rw-r--r--vendor/github.com/rwcarlsen/goexif/exifstat/main.go60
-rw-r--r--vendor/github.com/rwcarlsen/goexif/mknote/fields.go268
-rw-r--r--vendor/github.com/rwcarlsen/goexif/mknote/mknote.go70
-rw-r--r--vendor/github.com/rwcarlsen/goexif/tiff/tiff_test.go235
-rw-r--r--vendor/github.com/vaughan0/go-ini/ini_linux_test.go43
-rw-r--r--vendor/github.com/vaughan0/go-ini/ini_test.go89
-rw-r--r--vendor/golang.org/x/crypto/.gitattributes10
-rw-r--r--vendor/golang.org/x/crypto/.gitignore2
-rw-r--r--vendor/golang.org/x/crypto/AUTHORS3
-rw-r--r--vendor/golang.org/x/crypto/CONTRIBUTING.md31
-rw-r--r--vendor/golang.org/x/crypto/CONTRIBUTORS3
-rw-r--r--vendor/golang.org/x/crypto/README3
-rw-r--r--vendor/golang.org/x/crypto/acme/internal/acme/acme.go473
-rw-r--r--vendor/golang.org/x/crypto/acme/internal/acme/acme_test.go759
-rw-r--r--vendor/golang.org/x/crypto/acme/internal/acme/jws.go67
-rw-r--r--vendor/golang.org/x/crypto/acme/internal/acme/jws_test.go139
-rw-r--r--vendor/golang.org/x/crypto/acme/internal/acme/types.go181
-rw-r--r--vendor/golang.org/x/crypto/bcrypt/bcrypt.go2
-rw-r--r--vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go226
-rw-r--r--vendor/golang.org/x/crypto/blowfish/blowfish_test.go274
-rw-r--r--vendor/golang.org/x/crypto/blowfish/cipher.go2
-rw-r--r--vendor/golang.org/x/crypto/bn256/bn256.go404
-rw-r--r--vendor/golang.org/x/crypto/bn256/bn256_test.go304
-rw-r--r--vendor/golang.org/x/crypto/bn256/constants.go44
-rw-r--r--vendor/golang.org/x/crypto/bn256/curve.go278
-rw-r--r--vendor/golang.org/x/crypto/bn256/example_test.go43
-rw-r--r--vendor/golang.org/x/crypto/bn256/gfp12.go200
-rw-r--r--vendor/golang.org/x/crypto/bn256/gfp2.go219
-rw-r--r--vendor/golang.org/x/crypto/bn256/gfp6.go296
-rw-r--r--vendor/golang.org/x/crypto/bn256/optate.go395
-rw-r--r--vendor/golang.org/x/crypto/bn256/twist.go249
-rw-r--r--vendor/golang.org/x/crypto/cast5/cast5.go526
-rw-r--r--vendor/golang.org/x/crypto/cast5/cast5_test.go106
-rw-r--r--vendor/golang.org/x/crypto/codereview.cfg1
-rw-r--r--vendor/golang.org/x/crypto/curve25519/const_amd64.s20
-rw-r--r--vendor/golang.org/x/crypto/curve25519/cswap_amd64.s88
-rw-r--r--vendor/golang.org/x/crypto/curve25519/curve25519.go841
-rw-r--r--vendor/golang.org/x/crypto/curve25519/curve25519_test.go29
-rw-r--r--vendor/golang.org/x/crypto/curve25519/doc.go23
-rw-r--r--vendor/golang.org/x/crypto/curve25519/freeze_amd64.s94
-rw-r--r--vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s1398
-rw-r--r--vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go240
-rw-r--r--vendor/golang.org/x/crypto/curve25519/mul_amd64.s191
-rw-r--r--vendor/golang.org/x/crypto/curve25519/square_amd64.s153
-rw-r--r--vendor/golang.org/x/crypto/ed25519/ed25519.go181
-rw-r--r--vendor/golang.org/x/crypto/ed25519/ed25519_test.go183
-rw-r--r--vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go1422
-rw-r--r--vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go1771
-rw-r--r--vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gzbin0 -> 50330 bytes
-rw-r--r--vendor/golang.org/x/crypto/hkdf/example_test.go61
-rw-r--r--vendor/golang.org/x/crypto/hkdf/hkdf.go75
-rw-r--r--vendor/golang.org/x/crypto/hkdf/hkdf_test.go370
-rw-r--r--vendor/golang.org/x/crypto/md4/md4.go118
-rw-r--r--vendor/golang.org/x/crypto/md4/md4_test.go71
-rw-r--r--vendor/golang.org/x/crypto/md4/md4block.go89
-rw-r--r--vendor/golang.org/x/crypto/nacl/box/box.go85
-rw-r--r--vendor/golang.org/x/crypto/nacl/box/box_test.go78
-rw-r--r--vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go149
-rw-r--r--vendor/golang.org/x/crypto/nacl/secretbox/secretbox_test.go91
-rw-r--r--vendor/golang.org/x/crypto/ocsp/ocsp.go673
-rw-r--r--vendor/golang.org/x/crypto/ocsp/ocsp_test.go584
-rw-r--r--vendor/golang.org/x/crypto/openpgp/armor/armor.go219
-rw-r--r--vendor/golang.org/x/crypto/openpgp/armor/armor_test.go95
-rw-r--r--vendor/golang.org/x/crypto/openpgp/armor/encode.go160
-rw-r--r--vendor/golang.org/x/crypto/openpgp/canonical_text.go59
-rw-r--r--vendor/golang.org/x/crypto/openpgp/canonical_text_test.go52
-rw-r--r--vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go376
-rw-r--r--vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go210
-rw-r--r--vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go122
-rw-r--r--vendor/golang.org/x/crypto/openpgp/elgamal/elgamal_test.go49
-rw-r--r--vendor/golang.org/x/crypto/openpgp/errors/errors.go72
-rw-r--r--vendor/golang.org/x/crypto/openpgp/keys.go633
-rw-r--r--vendor/golang.org/x/crypto/openpgp/keys_test.go370
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/compressed.go123
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/compressed_test.go41
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/config.go91
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go199
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go146
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/literal.go89
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/ocfb.go143
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/ocfb_test.go46
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go73
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/opaque.go162
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/opaque_test.go67
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/packet.go539
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/packet_test.go255
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/private_key.go362
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go126
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/public_key.go750
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go202
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go280
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/public_key_v3_test.go82
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/reader.go76
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/signature.go706
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/signature_test.go42
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go146
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/signature_v3_test.go92
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go155
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted_test.go103
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go290
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted_test.go123
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/userattribute.go91
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/userattribute_test.go109
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/userid.go160
-rw-r--r--vendor/golang.org/x/crypto/openpgp/packet/userid_test.go87
-rw-r--r--vendor/golang.org/x/crypto/openpgp/read.go442
-rw-r--r--vendor/golang.org/x/crypto/openpgp/read_test.go613
-rw-r--r--vendor/golang.org/x/crypto/openpgp/s2k/s2k.go273
-rw-r--r--vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go137
-rw-r--r--vendor/golang.org/x/crypto/openpgp/write.go378
-rw-r--r--vendor/golang.org/x/crypto/openpgp/write_test.go273
-rw-r--r--vendor/golang.org/x/crypto/otr/libotr_test_helper.c197
-rw-r--r--vendor/golang.org/x/crypto/otr/otr.go1408
-rw-r--r--vendor/golang.org/x/crypto/otr/otr_test.go470
-rw-r--r--vendor/golang.org/x/crypto/otr/smp.go572
-rw-r--r--vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go77
-rw-r--r--vendor/golang.org/x/crypto/pbkdf2/pbkdf2_test.go157
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/bmp-string.go50
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/bmp-string_test.go63
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/crypto.go131
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/crypto_test.go125
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/errors.go23
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/internal/rc2/bench_test.go27
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go274
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2_test.go93
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/mac.go45
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/mac_test.go42
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/pbkdf.go170
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/pbkdf_test.go34
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/pkcs12.go342
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/pkcs12_test.go138
-rw-r--r--vendor/golang.org/x/crypto/pkcs12/safebags.go57
-rw-r--r--vendor/golang.org/x/crypto/poly1305/const_amd64.s45
-rw-r--r--vendor/golang.org/x/crypto/poly1305/poly1305.go32
-rw-r--r--vendor/golang.org/x/crypto/poly1305/poly1305_amd64.s497
-rw-r--r--vendor/golang.org/x/crypto/poly1305/poly1305_arm.s379
-rw-r--r--vendor/golang.org/x/crypto/poly1305/poly1305_test.go86
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_amd64.go24
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_arm.go24
-rw-r--r--vendor/golang.org/x/crypto/poly1305/sum_ref.go1531
-rw-r--r--vendor/golang.org/x/crypto/ripemd160/ripemd160.go120
-rw-r--r--vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go64
-rw-r--r--vendor/golang.org/x/crypto/ripemd160/ripemd160block.go161
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go144
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa/salsa2020_amd64.s902
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go199
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go23
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go234
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa/salsa_test.go35
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa20.go54
-rw-r--r--vendor/golang.org/x/crypto/salsa20/salsa20_test.go139
-rw-r--r--vendor/golang.org/x/crypto/scrypt/scrypt.go243
-rw-r--r--vendor/golang.org/x/crypto/scrypt/scrypt_test.go160
-rw-r--r--vendor/golang.org/x/crypto/sha3/doc.go66
-rw-r--r--vendor/golang.org/x/crypto/sha3/hashes.go65
-rw-r--r--vendor/golang.org/x/crypto/sha3/keccakf.go410
-rw-r--r--vendor/golang.org/x/crypto/sha3/register.go18
-rw-r--r--vendor/golang.org/x/crypto/sha3/sha3.go193
-rw-r--r--vendor/golang.org/x/crypto/sha3/sha3_test.go306
-rw-r--r--vendor/golang.org/x/crypto/sha3/shake.go60
-rw-r--r--vendor/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflatebin0 -> 521342 bytes
-rw-r--r--vendor/golang.org/x/crypto/sha3/xor.go16
-rw-r--r--vendor/golang.org/x/crypto/sha3/xor_generic.go28
-rw-r--r--vendor/golang.org/x/crypto/sha3/xor_unaligned.go58
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/client.go622
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/client_test.go287
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/example_test.go40
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/forward.go103
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/keyring.go184
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/keyring_test.go78
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/server.go420
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/server_test.go186
-rw-r--r--vendor/golang.org/x/crypto/ssh/agent/testdata_test.go64
-rw-r--r--vendor/golang.org/x/crypto/ssh/benchmark_test.go122
-rw-r--r--vendor/golang.org/x/crypto/ssh/buffer.go98
-rw-r--r--vendor/golang.org/x/crypto/ssh/buffer_test.go87
-rw-r--r--vendor/golang.org/x/crypto/ssh/certs.go503
-rw-r--r--vendor/golang.org/x/crypto/ssh/certs_test.go216
-rw-r--r--vendor/golang.org/x/crypto/ssh/channel.go631
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher.go552
-rw-r--r--vendor/golang.org/x/crypto/ssh/cipher_test.go127
-rw-r--r--vendor/golang.org/x/crypto/ssh/client.go213
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth.go439
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth_test.go393
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_test.go39
-rw-r--r--vendor/golang.org/x/crypto/ssh/common.go356
-rw-r--r--vendor/golang.org/x/crypto/ssh/connection.go144
-rw-r--r--vendor/golang.org/x/crypto/ssh/doc.go18
-rw-r--r--vendor/golang.org/x/crypto/ssh/example_test.go243
-rw-r--r--vendor/golang.org/x/crypto/ssh/handshake.go449
-rw-r--r--vendor/golang.org/x/crypto/ssh/handshake_test.go486
-rw-r--r--vendor/golang.org/x/crypto/ssh/kex.go526
-rw-r--r--vendor/golang.org/x/crypto/ssh/kex_test.go50
-rw-r--r--vendor/golang.org/x/crypto/ssh/keys.go846
-rw-r--r--vendor/golang.org/x/crypto/ssh/keys_test.go440
-rw-r--r--vendor/golang.org/x/crypto/ssh/mac.go57
-rw-r--r--vendor/golang.org/x/crypto/ssh/mempipe_test.go110
-rw-r--r--vendor/golang.org/x/crypto/ssh/messages.go758
-rw-r--r--vendor/golang.org/x/crypto/ssh/messages_test.go288
-rw-r--r--vendor/golang.org/x/crypto/ssh/mux.go330
-rw-r--r--vendor/golang.org/x/crypto/ssh/mux_test.go502
-rw-r--r--vendor/golang.org/x/crypto/ssh/server.go489
-rw-r--r--vendor/golang.org/x/crypto/ssh/session.go612
-rw-r--r--vendor/golang.org/x/crypto/ssh/session_test.go774
-rw-r--r--vendor/golang.org/x/crypto/ssh/tcpip.go407
-rw-r--r--vendor/golang.org/x/crypto/ssh/tcpip_test.go20
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/terminal.go892
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go291
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util.go128
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go12
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_linux.go11
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go58
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_windows.go174
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/agent_unix_test.go59
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/cert_test.go47
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/doc.go7
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/forward_unix_test.go160
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/session_test.go365
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/tcpip_test.go46
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/test_unix_test.go268
-rw-r--r--vendor/golang.org/x/crypto/ssh/test/testdata_test.go64
-rw-r--r--vendor/golang.org/x/crypto/ssh/testdata/doc.go8
-rw-r--r--vendor/golang.org/x/crypto/ssh/testdata/keys.go57
-rw-r--r--vendor/golang.org/x/crypto/ssh/testdata_test.go63
-rw-r--r--vendor/golang.org/x/crypto/ssh/transport.go328
-rw-r--r--vendor/golang.org/x/crypto/ssh/transport_test.go109
-rw-r--r--vendor/golang.org/x/crypto/tea/cipher.go109
-rw-r--r--vendor/golang.org/x/crypto/tea/tea_test.go93
-rw-r--r--vendor/golang.org/x/crypto/twofish/twofish.go342
-rw-r--r--vendor/golang.org/x/crypto/twofish/twofish_test.go129
-rw-r--r--vendor/golang.org/x/crypto/xtea/block.go66
-rw-r--r--vendor/golang.org/x/crypto/xtea/cipher.go82
-rw-r--r--vendor/golang.org/x/crypto/xtea/xtea_test.go229
-rw-r--r--vendor/golang.org/x/crypto/xts/xts.go138
-rw-r--r--vendor/golang.org/x/crypto/xts/xts_test.go85
-rw-r--r--vendor/golang.org/x/image/.gitattributes10
-rw-r--r--vendor/golang.org/x/image/.gitignore2
-rw-r--r--vendor/golang.org/x/image/AUTHORS3
-rw-r--r--vendor/golang.org/x/image/CONTRIBUTING.md31
-rw-r--r--vendor/golang.org/x/image/CONTRIBUTORS3
-rw-r--r--vendor/golang.org/x/image/README3
-rw-r--r--vendor/golang.org/x/image/bmp/reader.go2
-rw-r--r--vendor/golang.org/x/image/bmp/reader_test.go75
-rw-r--r--vendor/golang.org/x/image/bmp/writer_test.go91
-rw-r--r--vendor/golang.org/x/image/cmd/webp-manual-test/main.go215
-rw-r--r--vendor/golang.org/x/image/codereview.cfg1
-rw-r--r--vendor/golang.org/x/image/colornames/colornames.go10
-rw-r--r--vendor/golang.org/x/image/colornames/colornames_test.go42
-rw-r--r--vendor/golang.org/x/image/colornames/gen.go187
-rw-r--r--vendor/golang.org/x/image/colornames/table.go307
-rw-r--r--vendor/golang.org/x/image/draw/draw.go79
-rw-r--r--vendor/golang.org/x/image/draw/example_test.go118
-rw-r--r--vendor/golang.org/x/image/draw/gen.go1403
-rw-r--r--vendor/golang.org/x/image/draw/impl.go6668
-rw-r--r--vendor/golang.org/x/image/draw/scale.go527
-rw-r--r--vendor/golang.org/x/image/draw/scale_test.go731
-rw-r--r--vendor/golang.org/x/image/draw/stdlib_test.go96
-rw-r--r--vendor/golang.org/x/image/example/font/main.go106
-rw-r--r--vendor/golang.org/x/image/font/basicfont/basicfont.go122
-rw-r--r--vendor/golang.org/x/image/font/basicfont/data.go1456
-rw-r--r--vendor/golang.org/x/image/font/basicfont/gen.go115
-rw-r--r--vendor/golang.org/x/image/font/font.go2
-rw-r--r--vendor/golang.org/x/image/font/plan9font/example_test.go92
-rw-r--r--vendor/golang.org/x/image/font/plan9font/plan9font.go585
-rw-r--r--vendor/golang.org/x/image/font/plan9font/plan9font_test.go24
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.0000bin0 -> 3136 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.0100bin0 -> 3908 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.0200bin0 -> 3095 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.0300bin0 -> 2631 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.0400bin0 -> 3623 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.0500bin0 -> 2492 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.0E00bin0 -> 1235 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.1000bin0 -> 2354 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.1600bin0 -> 1825 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.1E00bin0 -> 3713 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.1F00bin0 -> 3012 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2000bin0 -> 2310 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2100bin0 -> 3206 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2200bin0 -> 3532 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2300bin0 -> 1613 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2400bin0 -> 1013 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2500bin0 -> 2747 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2600bin0 -> 1765 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2700bin0 -> 1762 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2800bin0 -> 1918 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.2A00bin0 -> 620 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.3000bin0 -> 569 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.FB00bin0 -> 912 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.FE00bin0 -> 387 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/7x13.FF00bin0 -> 1687 bytes
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/README9
-rw-r--r--vendor/golang.org/x/image/font/testdata/fixed/unicode.7x13.font68
-rw-r--r--vendor/golang.org/x/image/math/f32/f32.go37
-rw-r--r--vendor/golang.org/x/image/math/f64/f64.go37
-rw-r--r--vendor/golang.org/x/image/math/fixed/fixed.go2
-rw-r--r--vendor/golang.org/x/image/math/fixed/fixed_test.go110
-rw-r--r--vendor/golang.org/x/image/riff/example_test.go113
-rw-r--r--vendor/golang.org/x/image/riff/riff.go179
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.lossless.webpbin0 -> 175232 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webpbin0 -> 22678 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webp.ycbcr.pngbin0 -> 118713 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webpbin0 -> 22680 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webp.ycbcr.pngbin0 -> 142114 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.pngbin0 -> 255171 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webpbin0 -> 22680 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webp.ycbcr.pngbin0 -> 132078 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink.lossless.webpbin0 -> 19574 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webpbin0 -> 2450 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webp.ycbcr.pngbin0 -> 11482 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink.lzwcompressed.tiffbin0 -> 38994 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/blue-purple-pink.pngbin0 -> 25003 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/bw-deflate.tiffbin0 -> 594 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/bw-packbits.tiffbin0 -> 890 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/bw-uncompressed.tiffbin0 -> 1396 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-14x18.pngbin0 -> 798 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-280x360.jpegbin0 -> 36888 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-down-ab.pngbin0 -> 21338 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-down-bl.pngbin0 -> 18581 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-down-cr.pngbin0 -> 19519 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-down-nn.pngbin0 -> 21504 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-rotate-ab.pngbin0 -> 7654 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-rotate-bl.pngbin0 -> 7653 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-rotate-cr.pngbin0 -> 7808 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-rotate-nn.pngbin0 -> 4915 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-up-ab.pngbin0 -> 9633 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-up-bl.pngbin0 -> 9639 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-up-cr.pngbin0 -> 10987 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/go-turns-two-up-nn.pngbin0 -> 1368 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.1bpp.lossless.webpbin0 -> 442 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.1bpp.pngbin0 -> 1026 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.2bpp.lossless.webpbin0 -> 772 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.2bpp.pngbin0 -> 1544 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.4bpp.lossless.webpbin0 -> 1456 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.4bpp.pngbin0 -> 2667 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.8bpp.lossless.webpbin0 -> 3504 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/gopher-doc.8bpp.pngbin0 -> 6839 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/no_compress.tiffbin0 -> 1142 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/no_rps.tiffbin0 -> 1294 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/testpattern.pngbin0 -> 3195 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/tux-rotate-ab.pngbin0 -> 3237 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/tux-rotate-bl.pngbin0 -> 3751 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/tux-rotate-cr.pngbin0 -> 3753 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/tux-rotate-nn.pngbin0 -> 3055 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/tux.lossless.webpbin0 -> 29920 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/tux.pngbin0 -> 41427 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001-16bit.tiffbin0 -> 42146 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001-gray-16bit.tiffbin0 -> 31254 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001-gray.tiffbin0 -> 15742 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001-paletted.tiffbin0 -> 11214 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001-strip-64.tiffbin0 -> 30916 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001-tile-64x64.tiffbin0 -> 56404 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001-uncompressed.tiffbin0 -> 46674 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001.bmpbin0 -> 46610 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001.lossy.webpbin0 -> 3266 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001.lossy.webp.ycbcr.pngbin0 -> 12501 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001.pngbin0 -> 29228 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/video-001.tiffbin0 -> 30810 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose-small.bmpbin0 -> 822 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose-small.pngbin0 -> 692 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose.lossless.webpbin0 -> 90752 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webpbin0 -> 11572 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webp.nycbcra.pngbin0 -> 67874 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose.lossy.webpbin0 -> 14708 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose.lossy.webp.ycbcr.pngbin0 -> 60923 bytes
-rw-r--r--vendor/golang.org/x/image/testdata/yellow_rose.pngbin0 -> 125392 bytes
-rw-r--r--vendor/golang.org/x/image/tiff/buffer_test.go36
-rw-r--r--vendor/golang.org/x/image/tiff/lzw/reader.go2
-rw-r--r--vendor/golang.org/x/image/tiff/reader.go2
-rw-r--r--vendor/golang.org/x/image/tiff/reader_test.go377
-rw-r--r--vendor/golang.org/x/image/tiff/writer_test.go95
-rw-r--r--vendor/golang.org/x/image/vp8/decode.go403
-rw-r--r--vendor/golang.org/x/image/vp8/filter.go273
-rw-r--r--vendor/golang.org/x/image/vp8/idct.go98
-rw-r--r--vendor/golang.org/x/image/vp8/partition.go129
-rw-r--r--vendor/golang.org/x/image/vp8/pred.go201
-rw-r--r--vendor/golang.org/x/image/vp8/predfunc.go553
-rw-r--r--vendor/golang.org/x/image/vp8/quant.go98
-rw-r--r--vendor/golang.org/x/image/vp8/reconstruct.go442
-rw-r--r--vendor/golang.org/x/image/vp8/token.go381
-rw-r--r--vendor/golang.org/x/image/vp8l/decode.go603
-rw-r--r--vendor/golang.org/x/image/vp8l/huffman.go245
-rw-r--r--vendor/golang.org/x/image/vp8l/transform.go299
-rw-r--r--vendor/golang.org/x/image/webp/decode.go274
-rw-r--r--vendor/golang.org/x/image/webp/decode_test.go294
-rw-r--r--vendor/golang.org/x/image/webp/nycbcra/nycbcra.go194
-rw-r--r--vendor/golang.org/x/sys/.gitattributes10
-rw-r--r--vendor/golang.org/x/sys/.gitignore2
-rw-r--r--vendor/golang.org/x/sys/AUTHORS3
-rw-r--r--vendor/golang.org/x/sys/CONTRIBUTING.md31
-rw-r--r--vendor/golang.org/x/sys/CONTRIBUTORS3
-rw-r--r--vendor/golang.org/x/sys/README3
-rw-r--r--vendor/golang.org/x/sys/codereview.cfg1
-rw-r--r--vendor/golang.org/x/sys/plan9/asm.s8
-rw-r--r--vendor/golang.org/x/sys/plan9/asm_plan9_386.s (renamed from vendor/golang.org/x/sys/unix/asm_dragonfly_386.s)17
-rw-r--r--vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s30
-rw-r--r--vendor/golang.org/x/sys/plan9/const_plan9.go70
-rw-r--r--vendor/golang.org/x/sys/plan9/dir_plan9.go212
-rw-r--r--vendor/golang.org/x/sys/plan9/env_plan9.go27
-rw-r--r--vendor/golang.org/x/sys/plan9/env_unset.go14
-rw-r--r--vendor/golang.org/x/sys/plan9/errors_plan9.go50
-rwxr-xr-xvendor/golang.org/x/sys/plan9/mkall.sh138
-rwxr-xr-xvendor/golang.org/x/sys/plan9/mkerrors.sh246
-rwxr-xr-xvendor/golang.org/x/sys/plan9/mksyscall.pl319
-rwxr-xr-xvendor/golang.org/x/sys/plan9/mksysnum_plan9.sh23
-rw-r--r--vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go21
-rw-r--r--vendor/golang.org/x/sys/plan9/pwd_plan9.go23
-rw-r--r--vendor/golang.org/x/sys/plan9/race.go30
-rw-r--r--vendor/golang.org/x/sys/plan9/race0.go25
-rw-r--r--vendor/golang.org/x/sys/plan9/str.go22
-rw-r--r--vendor/golang.org/x/sys/plan9/syscall.go74
-rw-r--r--vendor/golang.org/x/sys/plan9/syscall_plan9.go349
-rw-r--r--vendor/golang.org/x/sys/plan9/syscall_test.go33
-rw-r--r--vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go292
-rw-r--r--vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go292
-rw-r--r--vendor/golang.org/x/sys/plan9/zsysnum_plan9.go49
-rw-r--r--vendor/golang.org/x/sys/unix/creds_test.go121
-rw-r--r--vendor/golang.org/x/sys/unix/export_test.go9
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mkall.sh0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mkerrors.sh0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksyscall.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksyscall_solaris.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksysnum_darwin.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksysnum_linux.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl0
-rwxr-xr-x[-rw-r--r--]vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl0
-rw-r--r--vendor/golang.org/x/sys/unix/mmap_unix_test.go23
-rw-r--r--vendor/golang.org/x/sys/unix/syscall.go2
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_bsd_test.go47
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_dragonfly_386.go61
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_freebsd_test.go24
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_linux_test.go110
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_test.go50
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_unix_test.go353
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_dragonfly_386.go1530
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_dragonfly_386.go1412
-rw-r--r--vendor/golang.org/x/sys/unix/zsysnum_dragonfly_386.go304
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_dragonfly_386.go437
-rw-r--r--vendor/golang.org/x/sys/windows/asm_windows_386.s13
-rw-r--r--vendor/golang.org/x/sys/windows/asm_windows_amd64.s13
-rw-r--r--vendor/golang.org/x/sys/windows/dll_windows.go374
-rw-r--r--vendor/golang.org/x/sys/windows/env_unset.go15
-rw-r--r--vendor/golang.org/x/sys/windows/env_windows.go25
-rw-r--r--vendor/golang.org/x/sys/windows/eventlog.go20
-rw-r--r--vendor/golang.org/x/sys/windows/exec_windows.go97
-rw-r--r--vendor/golang.org/x/sys/windows/race.go30
-rw-r--r--vendor/golang.org/x/sys/windows/race0.go25
-rw-r--r--vendor/golang.org/x/sys/windows/registry/export_test.go11
-rw-r--r--vendor/golang.org/x/sys/windows/registry/key.go178
-rw-r--r--vendor/golang.org/x/sys/windows/registry/registry_test.go756
-rw-r--r--vendor/golang.org/x/sys/windows/registry/syscall.go33
-rw-r--r--vendor/golang.org/x/sys/windows/registry/value.go384
-rw-r--r--vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go85
-rw-r--r--vendor/golang.org/x/sys/windows/security_windows.go435
-rw-r--r--vendor/golang.org/x/sys/windows/service.go143
-rw-r--r--vendor/golang.org/x/sys/windows/str.go22
-rw-r--r--vendor/golang.org/x/sys/windows/svc/debug/log.go56
-rw-r--r--vendor/golang.org/x/sys/windows/svc/debug/service.go45
-rw-r--r--vendor/golang.org/x/sys/windows/svc/event.go48
-rw-r--r--vendor/golang.org/x/sys/windows/svc/eventlog/install.go80
-rw-r--r--vendor/golang.org/x/sys/windows/svc/eventlog/log.go70
-rw-r--r--vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go51
-rw-r--r--vendor/golang.org/x/sys/windows/svc/example/beep.go22
-rw-r--r--vendor/golang.org/x/sys/windows/svc/example/install.go92
-rw-r--r--vendor/golang.org/x/sys/windows/svc/example/main.go76
-rw-r--r--vendor/golang.org/x/sys/windows/svc/example/manage.go62
-rw-r--r--vendor/golang.org/x/sys/windows/svc/example/service.go82
-rw-r--r--vendor/golang.org/x/sys/windows/svc/go12.c24
-rw-r--r--vendor/golang.org/x/sys/windows/svc/go12.go11
-rw-r--r--vendor/golang.org/x/sys/windows/svc/go13.go31
-rw-r--r--vendor/golang.org/x/sys/windows/svc/mgr/config.go139
-rw-r--r--vendor/golang.org/x/sys/windows/svc/mgr/mgr.go119
-rw-r--r--vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go154
-rw-r--r--vendor/golang.org/x/sys/windows/svc/mgr/service.go74
-rw-r--r--vendor/golang.org/x/sys/windows/svc/security.go62
-rw-r--r--vendor/golang.org/x/sys/windows/svc/service.go316
-rw-r--r--vendor/golang.org/x/sys/windows/svc/svc_test.go118
-rw-r--r--vendor/golang.org/x/sys/windows/svc/sys_386.s67
-rw-r--r--vendor/golang.org/x/sys/windows/svc/sys_amd64.s41
-rw-r--r--vendor/golang.org/x/sys/windows/syscall.go71
-rw-r--r--vendor/golang.org/x/sys/windows/syscall_test.go33
-rw-r--r--vendor/golang.org/x/sys/windows/syscall_windows.go991
-rw-r--r--vendor/golang.org/x/sys/windows/syscall_windows_test.go107
-rw-r--r--vendor/golang.org/x/sys/windows/zsyscall_windows.go2245
-rw-r--r--vendor/golang.org/x/sys/windows/ztypes_windows.go1242
-rw-r--r--vendor/golang.org/x/sys/windows/ztypes_windows_386.go22
-rw-r--r--vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go22
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/ber_test.go168
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/header_test.go135
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/identifier_test.go344
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/length_test.go158
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/suite_test.go182
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc1.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc10.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc11.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc12.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc13.berbin0 -> 11 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc14.berbin0 -> 7 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc15.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc16.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc17.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc18.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc19.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc2.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc20.berbin0 -> 11 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc21.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc22.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc23.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc24.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc25.berbin0 -> 5 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc26.berbin0 -> 5 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc27.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc28.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc29.berbin0 -> 3 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc3.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc30.berbin0 -> 5 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc31.berbin0 -> 4 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc32.berbin0 -> 2 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc33.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc34.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc35.berbin0 -> 16 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc36.berbin0 -> 20 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc37.berbin0 -> 14 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc38.berbin0 -> 16 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc39.berbin0 -> 2 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc4.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc40.berbin0 -> 2 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc41.berbin0 -> 16 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc42.berbin0 -> 14 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc43.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc44.berbin0 -> 2 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc45.berbin0 -> 2 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc46.berbin0 -> 11 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc47.berbin0 -> 16 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc48.berbin0 -> 16 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc5.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc6.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc7.ber1
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc8.berbin0 -> 5 bytes
-rw-r--r--vendor/gopkg.in/asn1-ber.v1/tests/tc9.ber1
-rw-r--r--vendor/gopkg.in/fsnotify.v1/example_test.go42
-rw-r--r--vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go229
-rw-r--r--vendor/gopkg.in/fsnotify.v1/inotify_test.go344
-rw-r--r--vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go147
-rw-r--r--vendor/gopkg.in/fsnotify.v1/integration_test.go1237
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/common_test.go65
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/delayer_test.go65
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/doc.go2
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/README.md12
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/custom/main.go90
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/interval-many/main.go79
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/main.go74
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/siege-urls4
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/interval/main.go69
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/memstats/main.go97
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/memstats/test-filebin0 -> 65536 bytes
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/examples/rate-limit/main.go101
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/interval_test.go114
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/memstats_test.go64
-rwxr-xr-xvendor/gopkg.in/throttled/throttled.v1/misc/pre-commit38
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/rate_test.go101
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/store/doc.go2
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/store/mem_test.go43
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/store/redis_test.go66
-rw-r--r--vendor/gopkg.in/throttled/throttled.v1/varyby_test.go56
-rw-r--r--vendor/gopkg.in/yaml.v2/decode_test.go988
-rw-r--r--vendor/gopkg.in/yaml.v2/encode_test.go501
-rw-r--r--vendor/gopkg.in/yaml.v2/suite_test.go12
1099 files changed, 277713 insertions, 4019 deletions
diff --git a/.gitignore b/.gitignore
index 882c5a783..1fba4cd03 100644
--- a/.gitignore
+++ b/.gitignore
@@ -69,6 +69,8 @@ web/sass-files/sass/.sass-cache/
data/*
api/data/*
+enterprise
+
.agignore
.ctags
tags
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
deleted file mode 100644
index cf298917d..000000000
--- a/Godeps/Godeps.json
+++ /dev/null
@@ -1,221 +0,0 @@
-{
- "ImportPath": "github.com/mattermost/platform",
- "GoVersion": "go1.6",
- "GodepVersion": "v65",
- "Deps": [
- {
- "ImportPath": "github.com/NYTimes/gziphandler",
- "Rev": "63027b26b87e2ae2ce3810393d4b81021cfd3a35"
- },
- {
- "ImportPath": "github.com/alecthomas/log4go",
- "Rev": "e5dc62318d9bd58682f1dceb53a4b24e8253682f"
- },
- {
- "ImportPath": "github.com/braintree/manners",
- "Comment": "0.4.0-15-g82a8879",
- "Rev": "82a8879fc5fd0381fa8b2d8033b19bf255252088"
- },
- {
- "ImportPath": "github.com/cloudfoundry/jibber_jabber",
- "Rev": "bcc4c8345a21301bf47c032ff42dd1aae2fe3027"
- },
- {
- "ImportPath": "github.com/dgryski/dgoogauth",
- "Rev": "67642ac6f9144f6610279e37e7be9af13f1cd668"
- },
- {
- "ImportPath": "github.com/disintegration/imaging",
- "Rev": "d8bbae1de109b518dabc98c6c1633eb358c148a4"
- },
- {
- "ImportPath": "github.com/garyburd/redigo/internal",
- "Rev": "8873b2f1995f59d4bcdd2b0dc9858e2cb9bf0c13"
- },
- {
- "ImportPath": "github.com/garyburd/redigo/redis",
- "Rev": "8873b2f1995f59d4bcdd2b0dc9858e2cb9bf0c13"
- },
- {
- "ImportPath": "github.com/go-gorp/gorp",
- "Comment": "v1.7-184-g6a3c8a8",
- "Rev": "6a3c8a87d0457cf700e57046c41e19b7cf3c44fa"
- },
- {
- "ImportPath": "github.com/go-ldap/ldap",
- "Comment": "v2.3.0",
- "Rev": "0e7db8eb77695b5a952f0e5d78df9ab160050c73"
- },
- {
- "ImportPath": "github.com/go-sql-driver/mysql",
- "Comment": "v1.2-194-g7ebe0a5",
- "Rev": "7ebe0a500653eeb1859664bed5e48dec1e164e73"
- },
- {
- "ImportPath": "github.com/goamz/goamz/aws",
- "Rev": "02d5144a587b982e33b95f484a34164ce6923c99"
- },
- {
- "ImportPath": "github.com/goamz/goamz/s3",
- "Rev": "02d5144a587b982e33b95f484a34164ce6923c99"
- },
- {
- "ImportPath": "github.com/golang/freetype",
- "Comment": "release-129-gc67e4d9",
- "Rev": "c67e4d98d212356ec0d9436a1edcbb6eb799f847"
- },
- {
- "ImportPath": "github.com/golang/freetype/raster",
- "Comment": "release-129-gc67e4d9",
- "Rev": "c67e4d98d212356ec0d9436a1edcbb6eb799f847"
- },
- {
- "ImportPath": "github.com/golang/freetype/truetype",
- "Comment": "release-129-gc67e4d9",
- "Rev": "c67e4d98d212356ec0d9436a1edcbb6eb799f847"
- },
- {
- "ImportPath": "github.com/golang/groupcache/lru",
- "Rev": "4eab30f13db9d8b25c752e99d1583628ac2fa422"
- },
- {
- "ImportPath": "github.com/gorilla/context",
- "Comment": "v1.1-2-ga8d44e7",
- "Rev": "a8d44e7d8e4d532b6a27a02dd82abb31cc1b01bd"
- },
- {
- "ImportPath": "github.com/gorilla/handlers",
- "Comment": "v1.1-6-g66e6c6f",
- "Rev": "66e6c6f01d8da976ee113437745ca029c2b585a6"
- },
- {
- "ImportPath": "github.com/gorilla/mux",
- "Comment": "v1.1-7-g9c19ed5",
- "Rev": "9c19ed558d5df4da88e2ade9c8940d742aef0e7e"
- },
- {
- "ImportPath": "github.com/gorilla/websocket",
- "Rev": "1f512fc3f05332ba7117626cdfb4e07474e58e60"
- },
- {
- "ImportPath": "github.com/lib/pq",
- "Comment": "go1.0-cutoff-86-gdd3290b",
- "Rev": "dd3290b2f71a8b30bee8e4e75a337a825263d26f"
- },
- {
- "ImportPath": "github.com/lib/pq/oid",
- "Comment": "go1.0-cutoff-86-gdd3290b",
- "Rev": "dd3290b2f71a8b30bee8e4e75a337a825263d26f"
- },
- {
- "ImportPath": "github.com/mattermost/rsc/gf256",
- "Rev": "bbaefb05eaa0389ea712340066837c8ce4d287f9"
- },
- {
- "ImportPath": "github.com/mattermost/rsc/qr",
- "Rev": "bbaefb05eaa0389ea712340066837c8ce4d287f9"
- },
- {
- "ImportPath": "github.com/mattermost/rsc/qr/coding",
- "Rev": "bbaefb05eaa0389ea712340066837c8ce4d287f9"
- },
- {
- "ImportPath": "github.com/mssola/user_agent",
- "Comment": "v0.4.1-14-g8e786bc",
- "Rev": "8e786bcb38b846e5eb8eb5f036d9144fc7b0a1f8"
- },
- {
- "ImportPath": "github.com/nicksnyder/go-i18n/i18n",
- "Comment": "v1.4.0",
- "Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
- },
- {
- "ImportPath": "github.com/nicksnyder/go-i18n/i18n/bundle",
- "Comment": "v1.4.0",
- "Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
- },
- {
- "ImportPath": "github.com/nicksnyder/go-i18n/i18n/language",
- "Comment": "v1.4.0",
- "Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
- },
- {
- "ImportPath": "github.com/nicksnyder/go-i18n/i18n/translation",
- "Comment": "v1.4.0",
- "Rev": "37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3"
- },
- {
- "ImportPath": "github.com/pborman/uuid",
- "Comment": "v1.0-11-gc55201b",
- "Rev": "c55201b036063326c5b1b89ccfe45a184973d073"
- },
- {
- "ImportPath": "github.com/rwcarlsen/goexif/exif",
- "Rev": "709fab3d192d7c62f86043caff1e7e3fb0f42bd8"
- },
- {
- "ImportPath": "github.com/rwcarlsen/goexif/tiff",
- "Rev": "709fab3d192d7c62f86043caff1e7e3fb0f42bd8"
- },
- {
- "ImportPath": "github.com/vaughan0/go-ini",
- "Rev": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1"
- },
- {
- "ImportPath": "golang.org/x/crypto/bcrypt",
- "Rev": "91ab96ae987aef3e74ab78b3aaf026109d206148"
- },
- {
- "ImportPath": "golang.org/x/crypto/blowfish",
- "Rev": "91ab96ae987aef3e74ab78b3aaf026109d206148"
- },
- {
- "ImportPath": "golang.org/x/image/bmp",
- "Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
- },
- {
- "ImportPath": "golang.org/x/image/font",
- "Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
- },
- {
- "ImportPath": "golang.org/x/image/math/fixed",
- "Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
- },
- {
- "ImportPath": "golang.org/x/image/tiff",
- "Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
- },
- {
- "ImportPath": "golang.org/x/image/tiff/lzw",
- "Rev": "f551d3a6b7fc11df315ad9e18b404280680f8bec"
- },
- {
- "ImportPath": "golang.org/x/sys/unix",
- "Rev": "b776ec39b3e54652e09028aaaaac9757f4f8211a"
- },
- {
- "ImportPath": "gopkg.in/asn1-ber.v1",
- "Comment": "v1.1",
- "Rev": "4e86f4367175e39f69d9358a5f17b4dda270378d"
- },
- {
- "ImportPath": "gopkg.in/fsnotify.v1",
- "Comment": "v1.3.0",
- "Rev": "30411dbcefb7a1da7e84f75530ad3abe4011b4f8"
- },
- {
- "ImportPath": "gopkg.in/throttled/throttled.v1",
- "Comment": "v1.0.0",
- "Rev": "74e328a1af88a9b54f9eca1397d74ad98572a6df"
- },
- {
- "ImportPath": "gopkg.in/throttled/throttled.v1/store",
- "Comment": "v1.0.0",
- "Rev": "74e328a1af88a9b54f9eca1397d74ad98572a6df"
- },
- {
- "ImportPath": "gopkg.in/yaml.v2",
- "Rev": "a83829b6f1293c91addabc89d0571c246397bbf4"
- }
- ]
-}
diff --git a/Godeps/Readme b/Godeps/Readme
deleted file mode 100644
index 4cdaa53d5..000000000
--- a/Godeps/Readme
+++ /dev/null
@@ -1,5 +0,0 @@
-This directory tree is generated automatically by godep.
-
-Please do not edit.
-
-See https://github.com/tools/godep for more information.
diff --git a/Makefile b/Makefile
index 4231fe805..2ead86fb5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
.PHONY: build package run stop run-client run-server stop-client stop-server restart-server restart-client start-docker clean-dist clean nuke check-style check-unit-tests test dist setup-mac prepare-enteprise run-client-tests setup-run-client-tests cleanup-run-client-tests test-client build-linux build-osx build-windows
# For golang 1.5.x compatibility (remove when we don't want to support it anymore)
-GO15VENDOREXPERIMENT=1
+export GO15VENDOREXPERIMENT=1
# Build Flags
BUILD_NUMBER ?= $(BUILD_NUMBER:)
@@ -30,9 +30,9 @@ endif
BUILD_WEBAPP_DIR = ./webapp
# Golang Flags
-GOPATH ?= $(GOPATH:)
+GOPATH ?= $(GOPATH:):./vendor
GOFLAGS ?= $(GOFLAGS:)
-GO=$(GOPATH)/bin/godep go
+GO=go
GO_LINKER_FLAGS ?= -ldflags \
"-X github.com/mattermost/platform/model.BuildNumber=$(BUILD_NUMBER)\
-X 'github.com/mattermost/platform/model.BuildDate=$(BUILD_DATE)'\
@@ -143,18 +143,20 @@ check-style:
exit 1; \
fi
-test: start-docker
+test: prepare-enteprise start-docker
@echo Running tests
- $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s ./api || exit 1
- $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1
- $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s ./store || exit 1
- $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1
- $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1
+ #$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s ./api || exit 1
+ #$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1
+ #$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s ./store || exit 1
+ #$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1
+ #$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1
ifeq ($(BUILD_ENTERPRISE_READY),true)
@echo Running Enterprise tests
- $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s $(BUILD_ENTERPRISE_DIR)/ldap || exit 1
- $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s $(BUILD_ENTERPRISE_DIR)/compliance || exit 1
+ $(GO) test $(GOFLAGS) -run=$(TESTS) -c ./enterprise/ldap && ./ldap.test -test.v -test.timeout=120s || exit 1
+ $(GO) test $(GOFLAGS) -run=$(TESTS) -c ./enterprise/compliance && ./compliance.test -test.v -test.timeout=120s || exit 1
+ rm -r ldap.test
+ rm -r compliance.test
endif
setup-run-client-tests:
@@ -173,7 +175,7 @@ test-client: setup-run-client-tests run-server run-client-tests stop-server clea
.prebuild:
@echo Preparation for running go code
- go get $(GOFLAGS) github.com/tools/godep
+ go get $(GOFLAGS) github.com/Masterminds/glide
touch $@
@@ -181,6 +183,8 @@ prepare-enterprise:
ifeq ($(BUILD_ENTERPRISE_READY),true)
@echo Enterprise build selected, preparing
cp $(BUILD_ENTERPRISE_DIR)/imports.go .
+ rm -f enterprise
+ ln -s $(BUILD_ENTERPRISE_DIR) enterprise
endif
build-linux: .prebuild prepare-enterprise
@@ -318,10 +322,9 @@ clean: stop-docker
rm -rf api/data
rm -rf logs
- rm -rf Godeps/_workspace/pkg/
-
rm -f mattermost.log
rm -f .prepare-go
+ rm -f enterprise
nuke: clean clean-docker
@echo BOOM
diff --git a/api/apitestlib.go b/api/apitestlib.go
index 6372ea6b1..ab342c6b7 100644
--- a/api/apitestlib.go
+++ b/api/apitestlib.go
@@ -27,16 +27,16 @@ type TestHelper struct {
SystemAdminChannel *model.Channel
}
-func SetupEnterprise(platformDir string) *TestHelper {
+func SetupEnterprise() *TestHelper {
if Srv == nil {
- utils.LoadConfig(platformDir + "/config/config.json")
- utils.InitTranslationsWithDir(platformDir + "/i18n")
+ utils.LoadConfig("config.json")
+ utils.InitTranslations()
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
utils.DisableDebugLogForTest()
utils.License.Features.SetDefaults()
NewServer()
StartServer()
- utils.InitHTMLWithDir(platformDir + "/templates")
+ utils.InitHTML()
InitApi()
utils.EnableDebugLogForTest()
Srv.Store.MarkSystemRanUnitTests()
diff --git a/glide.lock b/glide.lock
new file mode 100644
index 000000000..1d93d5484
--- /dev/null
+++ b/glide.lock
@@ -0,0 +1,104 @@
+hash: aa2fadc7f997a93e78d46d009d5695fb079697453d83e6a6dd7481d46ce73b7e
+updated: 2016-05-12T19:14:13.836695608-04:00
+imports:
+- name: github.com/alecthomas/log4go
+ version: e5dc62318d9bd58682f1dceb53a4b24e8253682f
+- name: github.com/braintree/manners
+ version: 82a8879fc5fd0381fa8b2d8033b19bf255252088
+- name: github.com/cloudfoundry/jibber_jabber
+ version: bcc4c8345a21301bf47c032ff42dd1aae2fe3027
+- name: github.com/dgryski/dgoogauth
+ version: 67642ac6f9144f6610279e37e7be9af13f1cd668
+- name: github.com/disintegration/imaging
+ version: d8bbae1de109b518dabc98c6c1633eb358c148a4
+- name: github.com/garyburd/redigo
+ version: 8873b2f1995f59d4bcdd2b0dc9858e2cb9bf0c13
+ subpackages:
+ - redis
+ - internal
+- name: github.com/go-gorp/gorp
+ version: 6a3c8a87d0457cf700e57046c41e19b7cf3c44fa
+- name: github.com/go-ldap/ldap
+ version: 0e7db8eb77695b5a952f0e5d78df9ab160050c73
+- name: github.com/go-sql-driver/mysql
+ version: 7ebe0a500653eeb1859664bed5e48dec1e164e73
+- name: github.com/goamz/goamz
+ version: 02d5144a587b982e33b95f484a34164ce6923c99
+ subpackages:
+ - aws
+ - s3
+- name: github.com/golang/freetype
+ version: c67e4d98d212356ec0d9436a1edcbb6eb799f847
+ subpackages:
+ - raster
+ - truetype
+- name: github.com/golang/groupcache
+ version: 4eab30f13db9d8b25c752e99d1583628ac2fa422
+ subpackages:
+ - lru
+- name: github.com/gorilla/context
+ version: a8d44e7d8e4d532b6a27a02dd82abb31cc1b01bd
+- name: github.com/gorilla/handlers
+ version: 66e6c6f01d8da976ee113437745ca029c2b585a6
+- name: github.com/gorilla/mux
+ version: 9c19ed558d5df4da88e2ade9c8940d742aef0e7e
+- name: github.com/gorilla/websocket
+ version: 1f512fc3f05332ba7117626cdfb4e07474e58e60
+- name: github.com/lib/pq
+ version: ee1442bda7bd1b6a84e913bdb421cb1874ec629d
+ subpackages:
+ - oid
+- name: github.com/mattermost/rsc
+ version: bbaefb05eaa0389ea712340066837c8ce4d287f9
+ subpackages:
+ - qr
+ - qr/coding
+ - gf256
+- name: github.com/mssola/user_agent
+ version: 8e786bcb38b846e5eb8eb5f036d9144fc7b0a1f8
+- name: github.com/nicksnyder/go-i18n
+ version: 37e5c2de3e03e4b82693e3fcb4a6aa2cc4eb07e3
+ subpackages:
+ - i18n
+ - i18n/bundle
+ - i18n/language
+ - i18n/translation
+- name: github.com/NYTimes/gziphandler
+ version: 63027b26b87e2ae2ce3810393d4b81021cfd3a35
+- name: github.com/pborman/uuid
+ version: c55201b036063326c5b1b89ccfe45a184973d073
+- name: github.com/rwcarlsen/goexif
+ version: 709fab3d192d7c62f86043caff1e7e3fb0f42bd8
+ subpackages:
+ - exif
+ - tiff
+- name: github.com/vaughan0/go-ini
+ version: a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
+- name: golang.org/x/crypto
+ version: 1e61df8d9ea476e2e1504cd9a32b40280c7c6c7e
+ subpackages:
+ - bcrypt
+ - blowfish
+- name: golang.org/x/image
+ version: f551d3a6b7fc11df315ad9e18b404280680f8bec
+ subpackages:
+ - bmp
+ - tiff
+ - font
+ - math/fixed
+ - tiff/lzw
+- name: golang.org/x/sys
+ version: e82cb4d7dffc35bcec7bc8bf9e402377e0ecf3f4
+ subpackages:
+ - unix
+- name: gopkg.in/asn1-ber.v1
+ version: 4e86f4367175e39f69d9358a5f17b4dda270378d
+- name: gopkg.in/fsnotify.v1
+ version: 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
+- name: gopkg.in/throttled/throttled.v1
+ version: 74e328a1af88a9b54f9eca1397d74ad98572a6df
+ subpackages:
+ - store
+- name: gopkg.in/yaml.v2
+ version: a83829b6f1293c91addabc89d0571c246397bbf4
+devImports: []
diff --git a/glide.yaml b/glide.yaml
new file mode 100644
index 000000000..396b9f81a
--- /dev/null
+++ b/glide.yaml
@@ -0,0 +1,41 @@
+package: github.com/mattermost/platform
+import:
+- package: github.com/NYTimes/gziphandler
+- package: github.com/alecthomas/log4go
+- package: github.com/braintree/manners
+- package: github.com/cloudfoundry/jibber_jabber
+- package: github.com/dgryski/dgoogauth
+- package: github.com/disintegration/imaging
+- package: github.com/go-gorp/gorp
+- package: github.com/go-ldap/ldap
+- package: github.com/go-sql-driver/mysql
+- package: github.com/goamz/goamz
+ subpackages:
+ - aws
+ - s3
+- package: github.com/golang/freetype
+- package: github.com/gorilla/handlers
+- package: github.com/gorilla/mux
+- package: github.com/gorilla/websocket
+- package: github.com/lib/pq
+- package: github.com/mattermost/rsc
+ subpackages:
+ - qr
+- package: github.com/mssola/user_agent
+- package: github.com/nicksnyder/go-i18n
+ subpackages:
+ - i18n
+- package: github.com/pborman/uuid
+- package: github.com/rwcarlsen/goexif
+ subpackages:
+ - exif
+- package: golang.org/x/crypto
+ subpackages:
+ - bcrypt
+- package: golang.org/x/image
+ subpackages:
+ - bmp
+- package: gopkg.in/fsnotify.v1
+- package: gopkg.in/throttled/throttled.v1
+ subpackages:
+ - store
diff --git a/vendor/github.com/NYTimes/gziphandler/gzip_test.go b/vendor/github.com/NYTimes/gziphandler/gzip_test.go
new file mode 100644
index 000000000..9a62bcbaa
--- /dev/null
+++ b/vendor/github.com/NYTimes/gziphandler/gzip_test.go
@@ -0,0 +1,134 @@
+package gziphandler
+
+import (
+ "bytes"
+ "compress/gzip"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestParseEncodings(t *testing.T) {
+
+ examples := map[string]codings{
+
+ // Examples from RFC 2616
+ "compress, gzip": codings{"compress": 1.0, "gzip": 1.0},
+ "": codings{},
+ "*": codings{"*": 1.0},
+ "compress;q=0.5, gzip;q=1.0": codings{"compress": 0.5, "gzip": 1.0},
+ "gzip;q=1.0, identity; q=0.5, *;q=0": codings{"gzip": 1.0, "identity": 0.5, "*": 0.0},
+
+ // More random stuff
+ "AAA;q=1": codings{"aaa": 1.0},
+ "BBB ; q = 2": codings{"bbb": 1.0},
+ }
+
+ for eg, exp := range examples {
+ act, _ := parseEncodings(eg)
+ assert.Equal(t, exp, act)
+ }
+}
+
+func TestGzipHandler(t *testing.T) {
+ testBody := "aaabbbccc"
+
+ // This just exists to provide something for GzipHandler to wrap.
+ handler := newTestHandler(testBody)
+
+ // requests without accept-encoding are passed along as-is
+
+ req1, _ := http.NewRequest("GET", "/whatever", nil)
+ res1 := httptest.NewRecorder()
+ handler.ServeHTTP(res1, req1)
+
+ assert.Equal(t, 200, res1.Code)
+ assert.Equal(t, "", res1.Header().Get("Content-Encoding"))
+ assert.Equal(t, "Accept-Encoding", res1.Header().Get("Vary"))
+ assert.Equal(t, testBody, res1.Body.String())
+
+ // but requests with accept-encoding:gzip are compressed if possible
+
+ req2, _ := http.NewRequest("GET", "/whatever", nil)
+ req2.Header.Set("Accept-Encoding", "gzip")
+ res2 := httptest.NewRecorder()
+ handler.ServeHTTP(res2, req2)
+
+ assert.Equal(t, 200, res2.Code)
+ assert.Equal(t, "gzip", res2.Header().Get("Content-Encoding"))
+ assert.Equal(t, "Accept-Encoding", res2.Header().Get("Vary"))
+ assert.Equal(t, gzipStr(testBody), res2.Body.Bytes())
+
+ // content-type header is correctly set based on uncompressed body
+
+ req3, _ := http.NewRequest("GET", "/whatever", nil)
+ req3.Header.Set("Accept-Encoding", "gzip")
+ res3 := httptest.NewRecorder()
+ handler.ServeHTTP(res3, req3)
+
+ assert.Equal(t, http.DetectContentType([]byte(testBody)), res3.Header().Get("Content-Type"))
+}
+
+// --------------------------------------------------------------------
+
+func BenchmarkGzipHandler_S2k(b *testing.B) { benchmark(b, false, 2048) }
+func BenchmarkGzipHandler_S20k(b *testing.B) { benchmark(b, false, 20480) }
+func BenchmarkGzipHandler_S100k(b *testing.B) { benchmark(b, false, 102400) }
+func BenchmarkGzipHandler_P2k(b *testing.B) { benchmark(b, true, 2048) }
+func BenchmarkGzipHandler_P20k(b *testing.B) { benchmark(b, true, 20480) }
+func BenchmarkGzipHandler_P100k(b *testing.B) { benchmark(b, true, 102400) }
+
+// --------------------------------------------------------------------
+
+func gzipStr(s string) []byte {
+ var b bytes.Buffer
+ w := gzip.NewWriter(&b)
+ io.WriteString(w, s)
+ w.Close()
+ return b.Bytes()
+}
+
+func benchmark(b *testing.B, parallel bool, size int) {
+ bin, err := ioutil.ReadFile("testdata/benchmark.json")
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ req, _ := http.NewRequest("GET", "/whatever", nil)
+ req.Header.Set("Accept-Encoding", "gzip")
+ handler := newTestHandler(string(bin[:size]))
+
+ if parallel {
+ b.ResetTimer()
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ runBenchmark(b, req, handler)
+ }
+ })
+ } else {
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ runBenchmark(b, req, handler)
+ }
+ }
+}
+
+func runBenchmark(b *testing.B, req *http.Request, handler http.Handler) {
+ res := httptest.NewRecorder()
+ handler.ServeHTTP(res, req)
+ if code := res.Code; code != 200 {
+ b.Fatalf("Expected 200 but got %d", code)
+ } else if blen := res.Body.Len(); blen < 500 {
+ b.Fatalf("Expected complete response body, but got %d bytes", blen)
+ }
+}
+
+func newTestHandler(body string) http.Handler {
+ return GzipHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, body)
+ }))
+}
diff --git a/vendor/github.com/NYTimes/gziphandler/testdata/benchmark.json b/vendor/github.com/NYTimes/gziphandler/testdata/benchmark.json
new file mode 100644
index 000000000..d9180d6ac
--- /dev/null
+++ b/vendor/github.com/NYTimes/gziphandler/testdata/benchmark.json
@@ -0,0 +1,5456 @@
+[
+ {
+ "_id": "55d2fc86da7c3f96f90aa005",
+ "age": 20,
+ "name": "Luann Grant",
+ "gender": "female",
+ "company": "ZOGAK",
+ "email": "luanngrant@zogak.com",
+ "phone": "+1 (915) 479-2908"
+ },
+ {
+ "_id": "55d2fc8653953bc9a0958a92",
+ "age": 34,
+ "name": "Sanders Gonzalez",
+ "gender": "male",
+ "company": "PIVITOL",
+ "email": "sandersgonzalez@pivitol.com",
+ "phone": "+1 (914) 563-2007"
+ },
+ {
+ "_id": "55d2fc86a38634b0954fe3c0",
+ "age": 26,
+ "name": "Compton Terry",
+ "gender": "male",
+ "company": "KOZGENE",
+ "email": "comptonterry@kozgene.com",
+ "phone": "+1 (812) 558-2536"
+ },
+ {
+ "_id": "55d2fc86edf1be88253e4e2e",
+ "age": 29,
+ "name": "Erma Armstrong",
+ "gender": "female",
+ "company": "DYNO",
+ "email": "ermaarmstrong@dyno.com",
+ "phone": "+1 (811) 556-3980"
+ },
+ {
+ "_id": "55d2fc86bee1bf1f233f8170",
+ "age": 20,
+ "name": "Carson Garcia",
+ "gender": "male",
+ "company": "JUNIPOOR",
+ "email": "carsongarcia@junipoor.com",
+ "phone": "+1 (820) 410-3221"
+ },
+ {
+ "_id": "55d2fc864810db4a3738dea8",
+ "age": 38,
+ "name": "Henson Townsend",
+ "gender": "male",
+ "company": "OVIUM",
+ "email": "hensontownsend@ovium.com",
+ "phone": "+1 (982) 412-3108"
+ },
+ {
+ "_id": "55d2fc86d714d77af8ed3fe4",
+ "age": 34,
+ "name": "Yesenia Garner",
+ "gender": "female",
+ "company": "TERRAGO",
+ "email": "yeseniagarner@terrago.com",
+ "phone": "+1 (878) 561-2314"
+ },
+ {
+ "_id": "55d2fc867651311b2e11925a",
+ "age": 31,
+ "name": "Rachelle Stanton",
+ "gender": "female",
+ "company": "UNISURE",
+ "email": "rachellestanton@unisure.com",
+ "phone": "+1 (961) 504-3072"
+ },
+ {
+ "_id": "55d2fc866415f6c03d5228eb",
+ "age": 30,
+ "name": "Franklin Rasmussen",
+ "gender": "male",
+ "company": "CAPSCREEN",
+ "email": "franklinrasmussen@capscreen.com",
+ "phone": "+1 (886) 525-2217"
+ },
+ {
+ "_id": "55d2fc86e2e0fa5f81fe5279",
+ "age": 32,
+ "name": "Fischer Humphrey",
+ "gender": "male",
+ "company": "ATGEN",
+ "email": "fischerhumphrey@atgen.com",
+ "phone": "+1 (855) 424-3693"
+ },
+ {
+ "_id": "55d2fc862c2a416777837c76",
+ "age": 29,
+ "name": "Olsen Moran",
+ "gender": "male",
+ "company": "SULTRAX",
+ "email": "olsenmoran@sultrax.com",
+ "phone": "+1 (860) 583-3380"
+ },
+ {
+ "_id": "55d2fc868c3c9e44d59ec2a2",
+ "age": 29,
+ "name": "Mattie Myers",
+ "gender": "female",
+ "company": "VALPREAL",
+ "email": "mattiemyers@valpreal.com",
+ "phone": "+1 (834) 587-2707"
+ },
+ {
+ "_id": "55d2fc860a6afc8beebe477d",
+ "age": 39,
+ "name": "Cleveland Jordan",
+ "gender": "male",
+ "company": "XLEEN",
+ "email": "clevelandjordan@xleen.com",
+ "phone": "+1 (848) 449-2037"
+ },
+ {
+ "_id": "55d2fc8605766af1b531b5ea",
+ "age": 35,
+ "name": "Gordon Rios",
+ "gender": "male",
+ "company": "BULLZONE",
+ "email": "gordonrios@bullzone.com",
+ "phone": "+1 (882) 436-2216"
+ },
+ {
+ "_id": "55d2fc86e052bfb7cf9b5a38",
+ "age": 33,
+ "name": "Todd Burch",
+ "gender": "male",
+ "company": "MOTOVATE",
+ "email": "toddburch@motovate.com",
+ "phone": "+1 (911) 470-2129"
+ },
+ {
+ "_id": "55d2fc86212924928b4112d6",
+ "age": 31,
+ "name": "Autumn Strong",
+ "gender": "female",
+ "company": "NURPLEX",
+ "email": "autumnstrong@nurplex.com",
+ "phone": "+1 (827) 483-2571"
+ },
+ {
+ "_id": "55d2fc86286c9bc87359e326",
+ "age": 27,
+ "name": "Rochelle Fitzgerald",
+ "gender": "female",
+ "company": "RAMEON",
+ "email": "rochellefitzgerald@rameon.com",
+ "phone": "+1 (820) 402-3411"
+ },
+ {
+ "_id": "55d2fc86511439244d21c569",
+ "age": 24,
+ "name": "Perry Hopkins",
+ "gender": "male",
+ "company": "KRAGGLE",
+ "email": "perryhopkins@kraggle.com",
+ "phone": "+1 (826) 469-3928"
+ },
+ {
+ "_id": "55d2fc868b8652b54c66051c",
+ "age": 37,
+ "name": "Guzman Williamson",
+ "gender": "male",
+ "company": "OCTOCORE",
+ "email": "guzmanwilliamson@octocore.com",
+ "phone": "+1 (826) 529-3380"
+ },
+ {
+ "_id": "55d2fc86f16a5a4c310483df",
+ "age": 28,
+ "name": "Sheri Thompson",
+ "gender": "female",
+ "company": "AUTOGRATE",
+ "email": "sherithompson@autograte.com",
+ "phone": "+1 (942) 463-2727"
+ },
+ {
+ "_id": "55d2fc86675d3040fc35daa8",
+ "age": 24,
+ "name": "Walton Macdonald",
+ "gender": "male",
+ "company": "ZIZZLE",
+ "email": "waltonmacdonald@zizzle.com",
+ "phone": "+1 (990) 510-2656"
+ },
+ {
+ "_id": "55d2fc864e90e236f9e5a174",
+ "age": 39,
+ "name": "Gwendolyn Ross",
+ "gender": "female",
+ "company": "XIIX",
+ "email": "gwendolynross@xiix.com",
+ "phone": "+1 (869) 565-2774"
+ },
+ {
+ "_id": "55d2fc866f306c575a36cb97",
+ "age": 23,
+ "name": "Sexton Herring",
+ "gender": "male",
+ "company": "MEDIOT",
+ "email": "sextonherring@mediot.com",
+ "phone": "+1 (935) 510-2049"
+ },
+ {
+ "_id": "55d2fc867526db78550711a3",
+ "age": 26,
+ "name": "Twila Vang",
+ "gender": "female",
+ "company": "ARCTIQ",
+ "email": "twilavang@arctiq.com",
+ "phone": "+1 (979) 429-2135"
+ },
+ {
+ "_id": "55d2fc86fe5e24c1b4b0dc96",
+ "age": 26,
+ "name": "Marjorie Snider",
+ "gender": "female",
+ "company": "QUARX",
+ "email": "marjoriesnider@quarx.com",
+ "phone": "+1 (913) 469-2916"
+ },
+ {
+ "_id": "55d2fc861e85e0104fa7d33e",
+ "age": 36,
+ "name": "Malone Diaz",
+ "gender": "male",
+ "company": "COMVEYOR",
+ "email": "malonediaz@comveyor.com",
+ "phone": "+1 (882) 541-3306"
+ },
+ {
+ "_id": "55d2fc86bc04a4fa0a338403",
+ "age": 39,
+ "name": "Amelia Sanford",
+ "gender": "female",
+ "company": "IPLAX",
+ "email": "ameliasanford@iplax.com",
+ "phone": "+1 (872) 589-3509"
+ },
+ {
+ "_id": "55d2fc86f7854f672e80c1dd",
+ "age": 27,
+ "name": "Kristie Fernandez",
+ "gender": "female",
+ "company": "RONBERT",
+ "email": "kristiefernandez@ronbert.com",
+ "phone": "+1 (983) 419-3564"
+ },
+ {
+ "_id": "55d2fc867faa140f152b7229",
+ "age": 23,
+ "name": "Bray Wyatt",
+ "gender": "male",
+ "company": "DEMINIMUM",
+ "email": "braywyatt@deminimum.com",
+ "phone": "+1 (943) 485-3961"
+ },
+ {
+ "_id": "55d2fc863a42779d68c0dd53",
+ "age": 36,
+ "name": "Meyer Pickett",
+ "gender": "male",
+ "company": "GENEKOM",
+ "email": "meyerpickett@genekom.com",
+ "phone": "+1 (999) 534-3038"
+ },
+ {
+ "_id": "55d2fc86095f5ceb3c57efeb",
+ "age": 22,
+ "name": "Carlson Ramirez",
+ "gender": "male",
+ "company": "KANGLE",
+ "email": "carlsonramirez@kangle.com",
+ "phone": "+1 (972) 590-3152"
+ },
+ {
+ "_id": "55d2fc868036a76e42f30954",
+ "age": 24,
+ "name": "Roth Murray",
+ "gender": "male",
+ "company": "DEEPENDS",
+ "email": "rothmurray@deepends.com",
+ "phone": "+1 (944) 408-2208"
+ },
+ {
+ "_id": "55d2fc8688ac278604ea592b",
+ "age": 24,
+ "name": "Cecelia Lambert",
+ "gender": "female",
+ "company": "SLOFAST",
+ "email": "cecelialambert@slofast.com",
+ "phone": "+1 (907) 485-2284"
+ },
+ {
+ "_id": "55d2fc86b05fc3906ce838a2",
+ "age": 31,
+ "name": "Leah Ferguson",
+ "gender": "female",
+ "company": "NEBULEAN",
+ "email": "leahferguson@nebulean.com",
+ "phone": "+1 (883) 574-2101"
+ },
+ {
+ "_id": "55d2fc86d21f9d73f11076b9",
+ "age": 28,
+ "name": "Therese Mueller",
+ "gender": "female",
+ "company": "STEELFAB",
+ "email": "theresemueller@steelfab.com",
+ "phone": "+1 (920) 485-2265"
+ },
+ {
+ "_id": "55d2fc866254f87d0389dc98",
+ "age": 32,
+ "name": "Wanda Byrd",
+ "gender": "female",
+ "company": "HOTCAKES",
+ "email": "wandabyrd@hotcakes.com",
+ "phone": "+1 (893) 579-3658"
+ },
+ {
+ "_id": "55d2fc868cf04450063aba0e",
+ "age": 25,
+ "name": "Felecia Mccall",
+ "gender": "female",
+ "company": "GINK",
+ "email": "feleciamccall@gink.com",
+ "phone": "+1 (848) 486-3047"
+ },
+ {
+ "_id": "55d2fc86e0ee0341850d35ab",
+ "age": 37,
+ "name": "Goldie Stafford",
+ "gender": "female",
+ "company": "FIREWAX",
+ "email": "goldiestafford@firewax.com",
+ "phone": "+1 (831) 507-3578"
+ },
+ {
+ "_id": "55d2fc868acfa20489a61720",
+ "age": 20,
+ "name": "Amy Patterson",
+ "gender": "female",
+ "company": "KNEEDLES",
+ "email": "amypatterson@kneedles.com",
+ "phone": "+1 (950) 478-3558"
+ },
+ {
+ "_id": "55d2fc8680c104681b074336",
+ "age": 29,
+ "name": "Robles Alford",
+ "gender": "male",
+ "company": "TALENDULA",
+ "email": "roblesalford@talendula.com",
+ "phone": "+1 (813) 424-3650"
+ },
+ {
+ "_id": "55d2fc86faeb57024907ea70",
+ "age": 28,
+ "name": "Adkins Hampton",
+ "gender": "male",
+ "company": "SYNKGEN",
+ "email": "adkinshampton@synkgen.com",
+ "phone": "+1 (974) 522-2517"
+ },
+ {
+ "_id": "55d2fc866ba878e18ee65c0f",
+ "age": 32,
+ "name": "Bernadine Trevino",
+ "gender": "female",
+ "company": "EVENTEX",
+ "email": "bernadinetrevino@eventex.com",
+ "phone": "+1 (914) 577-2655"
+ },
+ {
+ "_id": "55d2fc86524364ec8cb2d0c7",
+ "age": 38,
+ "name": "Robin Le",
+ "gender": "female",
+ "company": "GALLAXIA",
+ "email": "robinle@gallaxia.com",
+ "phone": "+1 (821) 472-2416"
+ },
+ {
+ "_id": "55d2fc86c53dc98dacabc399",
+ "age": 23,
+ "name": "Leanna Hicks",
+ "gender": "female",
+ "company": "ZEROLOGY",
+ "email": "leannahicks@zerology.com",
+ "phone": "+1 (946) 531-3368"
+ },
+ {
+ "_id": "55d2fc86e293b8cfb2d1a5bd",
+ "age": 31,
+ "name": "Herman Bridges",
+ "gender": "male",
+ "company": "DADABASE",
+ "email": "hermanbridges@dadabase.com",
+ "phone": "+1 (836) 408-3169"
+ },
+ {
+ "_id": "55d2fc865dfc0cc61ec50b41",
+ "age": 30,
+ "name": "Olive Terrell",
+ "gender": "female",
+ "company": "ACCRUEX",
+ "email": "oliveterrell@accruex.com",
+ "phone": "+1 (837) 573-2059"
+ },
+ {
+ "_id": "55d2fc8669dc78cdeb374ff5",
+ "age": 26,
+ "name": "Miranda Banks",
+ "gender": "female",
+ "company": "GEOFARM",
+ "email": "mirandabanks@geofarm.com",
+ "phone": "+1 (984) 574-2877"
+ },
+ {
+ "_id": "55d2fc86f471f565df37a756",
+ "age": 31,
+ "name": "Noelle Wolf",
+ "gender": "female",
+ "company": "ENDIPINE",
+ "email": "noellewolf@endipine.com",
+ "phone": "+1 (880) 548-2427"
+ },
+ {
+ "_id": "55d2fc8603e133136e5ca325",
+ "age": 38,
+ "name": "Amber Klein",
+ "gender": "female",
+ "company": "ISOPLEX",
+ "email": "amberklein@isoplex.com",
+ "phone": "+1 (853) 548-3856"
+ },
+ {
+ "_id": "55d2fc86962b00cfd86e9d8d",
+ "age": 32,
+ "name": "Jodie Mcclain",
+ "gender": "female",
+ "company": "BESTO",
+ "email": "jodiemcclain@besto.com",
+ "phone": "+1 (857) 417-2691"
+ },
+ {
+ "_id": "55d2fc8622eaf8052986a5bb",
+ "age": 35,
+ "name": "Margo Melendez",
+ "gender": "female",
+ "company": "KLUGGER",
+ "email": "margomelendez@klugger.com",
+ "phone": "+1 (823) 445-3570"
+ },
+ {
+ "_id": "55d2fc861e37cd298741e801",
+ "age": 37,
+ "name": "Castaneda Dudley",
+ "gender": "male",
+ "company": "URBANSHEE",
+ "email": "castanedadudley@urbanshee.com",
+ "phone": "+1 (865) 449-2445"
+ },
+ {
+ "_id": "55d2fc86e4c07ff933f7b531",
+ "age": 40,
+ "name": "Sherman Combs",
+ "gender": "male",
+ "company": "GRACKER",
+ "email": "shermancombs@gracker.com",
+ "phone": "+1 (817) 472-2316"
+ },
+ {
+ "_id": "55d2fc86c4613e0a622727e6",
+ "age": 31,
+ "name": "Louise Nichols",
+ "gender": "female",
+ "company": "SPORTAN",
+ "email": "louisenichols@sportan.com",
+ "phone": "+1 (823) 543-2230"
+ },
+ {
+ "_id": "55d2fc86d40dd218587cc632",
+ "age": 29,
+ "name": "Daniels Jacobs",
+ "gender": "male",
+ "company": "CALCULA",
+ "email": "danielsjacobs@calcula.com",
+ "phone": "+1 (979) 448-2244"
+ },
+ {
+ "_id": "55d2fc86b44f3ec927f3b2e1",
+ "age": 22,
+ "name": "Cristina Crosby",
+ "gender": "female",
+ "company": "PHUEL",
+ "email": "cristinacrosby@phuel.com",
+ "phone": "+1 (816) 504-3557"
+ },
+ {
+ "_id": "55d2fc86ba635f5436325487",
+ "age": 23,
+ "name": "Tisha Sawyer",
+ "gender": "female",
+ "company": "IMAGEFLOW",
+ "email": "tishasawyer@imageflow.com",
+ "phone": "+1 (894) 551-2933"
+ },
+ {
+ "_id": "55d2fc8640e8af981a47216a",
+ "age": 32,
+ "name": "Janice Graham",
+ "gender": "female",
+ "company": "PYRAMIS",
+ "email": "janicegraham@pyramis.com",
+ "phone": "+1 (986) 409-2529"
+ },
+ {
+ "_id": "55d2fc86cdbe80c5cb184731",
+ "age": 22,
+ "name": "Holman Joyce",
+ "gender": "male",
+ "company": "VERTON",
+ "email": "holmanjoyce@verton.com",
+ "phone": "+1 (955) 445-2054"
+ },
+ {
+ "_id": "55d2fc860f70e0d0890e8e47",
+ "age": 21,
+ "name": "Webb Sears",
+ "gender": "male",
+ "company": "ENQUILITY",
+ "email": "webbsears@enquility.com",
+ "phone": "+1 (961) 406-3600"
+ },
+ {
+ "_id": "55d2fc86150c8385661fde6f",
+ "age": 29,
+ "name": "Bush Farrell",
+ "gender": "male",
+ "company": "ENDICIL",
+ "email": "bushfarrell@endicil.com",
+ "phone": "+1 (894) 550-2963"
+ },
+ {
+ "_id": "55d2fc862e2f1ca9662b03e3",
+ "age": 36,
+ "name": "Gay Walters",
+ "gender": "male",
+ "company": "ZENSURE",
+ "email": "gaywalters@zensure.com",
+ "phone": "+1 (859) 467-3816"
+ },
+ {
+ "_id": "55d2fc86da1249ca6d3a068f",
+ "age": 33,
+ "name": "Marquez Palmer",
+ "gender": "male",
+ "company": "TURNLING",
+ "email": "marquezpalmer@turnling.com",
+ "phone": "+1 (878) 522-3859"
+ },
+ {
+ "_id": "55d2fc86a61a66a69db5c8a9",
+ "age": 29,
+ "name": "Huber Parrish",
+ "gender": "male",
+ "company": "DELPHIDE",
+ "email": "huberparrish@delphide.com",
+ "phone": "+1 (947) 406-3267"
+ },
+ {
+ "_id": "55d2fc86fff10fda8f106c2a",
+ "age": 22,
+ "name": "Foreman Cohen",
+ "gender": "male",
+ "company": "TROPOLIS",
+ "email": "foremancohen@tropolis.com",
+ "phone": "+1 (802) 409-2459"
+ },
+ {
+ "_id": "55d2fc8632b185024494802d",
+ "age": 31,
+ "name": "Kathryn Peterson",
+ "gender": "female",
+ "company": "PROSURE",
+ "email": "kathrynpeterson@prosure.com",
+ "phone": "+1 (811) 531-3085"
+ },
+ {
+ "_id": "55d2fc86f8e11410bb5b8e88",
+ "age": 34,
+ "name": "Aisha Duke",
+ "gender": "female",
+ "company": "APPLICA",
+ "email": "aishaduke@applica.com",
+ "phone": "+1 (977) 438-2754"
+ },
+ {
+ "_id": "55d2fc86190a0097728af887",
+ "age": 37,
+ "name": "Maynard Henderson",
+ "gender": "male",
+ "company": "ILLUMITY",
+ "email": "maynardhenderson@illumity.com",
+ "phone": "+1 (832) 472-2261"
+ },
+ {
+ "_id": "55d2fc86d298e6e1cf9332df",
+ "age": 33,
+ "name": "Villarreal Santiago",
+ "gender": "male",
+ "company": "QUAILCOM",
+ "email": "villarrealsantiago@quailcom.com",
+ "phone": "+1 (981) 422-2572"
+ },
+ {
+ "_id": "55d2fc86b7eb3b9ed01fc186",
+ "age": 30,
+ "name": "Diaz Allison",
+ "gender": "male",
+ "company": "ISOSTREAM",
+ "email": "diazallison@isostream.com",
+ "phone": "+1 (883) 530-2186"
+ },
+ {
+ "_id": "55d2fc86da92ac006d69c236",
+ "age": 20,
+ "name": "Kirkland Mccullough",
+ "gender": "male",
+ "company": "ADORNICA",
+ "email": "kirklandmccullough@adornica.com",
+ "phone": "+1 (950) 556-3562"
+ },
+ {
+ "_id": "55d2fc86195f59929397f2fc",
+ "age": 32,
+ "name": "Dolores Howard",
+ "gender": "female",
+ "company": "ZINCA",
+ "email": "doloreshoward@zinca.com",
+ "phone": "+1 (904) 450-2101"
+ },
+ {
+ "_id": "55d2fc860c9f707c22eaca7c",
+ "age": 26,
+ "name": "Mills Gamble",
+ "gender": "male",
+ "company": "BLEEKO",
+ "email": "millsgamble@bleeko.com",
+ "phone": "+1 (942) 402-2630"
+ },
+ {
+ "_id": "55d2fc86b539183079fcab65",
+ "age": 35,
+ "name": "Walls Dotson",
+ "gender": "male",
+ "company": "GRUPOLI",
+ "email": "wallsdotson@grupoli.com",
+ "phone": "+1 (979) 477-3065"
+ },
+ {
+ "_id": "55d2fc866377b14a737261c3",
+ "age": 29,
+ "name": "Hannah Coleman",
+ "gender": "female",
+ "company": "COMCUR",
+ "email": "hannahcoleman@comcur.com",
+ "phone": "+1 (944) 595-2415"
+ },
+ {
+ "_id": "55d2fc867b77f0e8d5f08276",
+ "age": 25,
+ "name": "Kinney Oneill",
+ "gender": "male",
+ "company": "ELPRO",
+ "email": "kinneyoneill@elpro.com",
+ "phone": "+1 (851) 570-2363"
+ },
+ {
+ "_id": "55d2fc868745f5f71578624c",
+ "age": 32,
+ "name": "Bennett Henson",
+ "gender": "male",
+ "company": "ZISIS",
+ "email": "bennetthenson@zisis.com",
+ "phone": "+1 (958) 584-2257"
+ },
+ {
+ "_id": "55d2fc8604d1e7576b1a83fb",
+ "age": 32,
+ "name": "Ross Chavez",
+ "gender": "male",
+ "company": "DUOFLEX",
+ "email": "rosschavez@duoflex.com",
+ "phone": "+1 (890) 556-2052"
+ },
+ {
+ "_id": "55d2fc86bd556093136802dd",
+ "age": 26,
+ "name": "Raymond Rutledge",
+ "gender": "male",
+ "company": "BUNGA",
+ "email": "raymondrutledge@bunga.com",
+ "phone": "+1 (994) 504-2118"
+ },
+ {
+ "_id": "55d2fc86a122c7d89560c130",
+ "age": 31,
+ "name": "Rosemary Larsen",
+ "gender": "female",
+ "company": "EXOPLODE",
+ "email": "rosemarylarsen@exoplode.com",
+ "phone": "+1 (864) 558-3569"
+ },
+ {
+ "_id": "55d2fc86dd3fe9ea62fdbea1",
+ "age": 27,
+ "name": "Tara Roth",
+ "gender": "female",
+ "company": "GAPTEC",
+ "email": "tararoth@gaptec.com",
+ "phone": "+1 (893) 531-2962"
+ },
+ {
+ "_id": "55d2fc866f372ca411cd425d",
+ "age": 30,
+ "name": "Ronda Sheppard",
+ "gender": "female",
+ "company": "GREEKER",
+ "email": "rondasheppard@greeker.com",
+ "phone": "+1 (963) 569-2851"
+ },
+ {
+ "_id": "55d2fc860a0dc369ac8bed9f",
+ "age": 37,
+ "name": "Nita Washington",
+ "gender": "female",
+ "company": "AQUASURE",
+ "email": "nitawashington@aquasure.com",
+ "phone": "+1 (858) 579-3734"
+ },
+ {
+ "_id": "55d2fc863d59ecccd8b482b7",
+ "age": 34,
+ "name": "Shannon Sanchez",
+ "gender": "male",
+ "company": "QUORDATE",
+ "email": "shannonsanchez@quordate.com",
+ "phone": "+1 (880) 542-2259"
+ },
+ {
+ "_id": "55d2fc861c73e366d8983f98",
+ "age": 23,
+ "name": "Amalia George",
+ "gender": "female",
+ "company": "QUINEX",
+ "email": "amaliageorge@quinex.com",
+ "phone": "+1 (918) 412-3805"
+ },
+ {
+ "_id": "55d2fc866910c4329a167746",
+ "age": 30,
+ "name": "West Parsons",
+ "gender": "male",
+ "company": "RODEMCO",
+ "email": "westparsons@rodemco.com",
+ "phone": "+1 (869) 480-3404"
+ },
+ {
+ "_id": "55d2fc861d97ff31a8eb7f06",
+ "age": 30,
+ "name": "Day Mercado",
+ "gender": "male",
+ "company": "ENJOLA",
+ "email": "daymercado@enjola.com",
+ "phone": "+1 (861) 546-2601"
+ },
+ {
+ "_id": "55d2fc861e100baa15994161",
+ "age": 20,
+ "name": "Hubbard Randolph",
+ "gender": "male",
+ "company": "INSOURCE",
+ "email": "hubbardrandolph@insource.com",
+ "phone": "+1 (939) 422-2753"
+ },
+ {
+ "_id": "55d2fc86dc33a0101292ea57",
+ "age": 32,
+ "name": "Ward Patrick",
+ "gender": "male",
+ "company": "ZUVY",
+ "email": "wardpatrick@zuvy.com",
+ "phone": "+1 (852) 461-3079"
+ },
+ {
+ "_id": "55d2fc863074ff55ec22d7ac",
+ "age": 26,
+ "name": "Barker Small",
+ "gender": "male",
+ "company": "ZIDANT",
+ "email": "barkersmall@zidant.com",
+ "phone": "+1 (901) 514-3653"
+ },
+ {
+ "_id": "55d2fc86008067de21a65447",
+ "age": 26,
+ "name": "Margret Porter",
+ "gender": "female",
+ "company": "DYMI",
+ "email": "margretporter@dymi.com",
+ "phone": "+1 (820) 404-2199"
+ },
+ {
+ "_id": "55d2fc8694b7f8670d10781e",
+ "age": 40,
+ "name": "Roslyn Richmond",
+ "gender": "female",
+ "company": "SONGBIRD",
+ "email": "roslynrichmond@songbird.com",
+ "phone": "+1 (913) 406-3720"
+ },
+ {
+ "_id": "55d2fc86ffff28aef88e1d69",
+ "age": 29,
+ "name": "Jimenez Yates",
+ "gender": "male",
+ "company": "IDETICA",
+ "email": "jimenezyates@idetica.com",
+ "phone": "+1 (803) 421-2358"
+ },
+ {
+ "_id": "55d2fc8604bfeab3a975b2d8",
+ "age": 21,
+ "name": "Mcneil Jensen",
+ "gender": "male",
+ "company": "EXOBLUE",
+ "email": "mcneiljensen@exoblue.com",
+ "phone": "+1 (856) 581-3756"
+ },
+ {
+ "_id": "55d2fc86bee368958f567c45",
+ "age": 40,
+ "name": "Millicent Trujillo",
+ "gender": "female",
+ "company": "ARTWORLDS",
+ "email": "millicenttrujillo@artworlds.com",
+ "phone": "+1 (926) 456-2237"
+ },
+ {
+ "_id": "55d2fc86de2a5a6babe51d48",
+ "age": 26,
+ "name": "Dorothea Duffy",
+ "gender": "female",
+ "company": "EBIDCO",
+ "email": "dorotheaduffy@ebidco.com",
+ "phone": "+1 (873) 458-2694"
+ },
+ {
+ "_id": "55d2fc86f8793320727d2020",
+ "age": 34,
+ "name": "Gloria Ward",
+ "gender": "female",
+ "company": "EXOVENT",
+ "email": "gloriaward@exovent.com",
+ "phone": "+1 (948) 552-3275"
+ },
+ {
+ "_id": "55d2fc86967e5599adde68e8",
+ "age": 33,
+ "name": "Denise Hogan",
+ "gender": "female",
+ "company": "GLEAMINK",
+ "email": "denisehogan@gleamink.com",
+ "phone": "+1 (902) 544-2943"
+ },
+ {
+ "_id": "55d2fc862833baf2918f7860",
+ "age": 23,
+ "name": "Clemons Berger",
+ "gender": "male",
+ "company": "ARTIQ",
+ "email": "clemonsberger@artiq.com",
+ "phone": "+1 (873) 516-2440"
+ },
+ {
+ "_id": "55d2fc8610af4c20d426854a",
+ "age": 40,
+ "name": "Colette Scott",
+ "gender": "female",
+ "company": "INVENTURE",
+ "email": "colettescott@inventure.com",
+ "phone": "+1 (814) 556-3466"
+ },
+ {
+ "_id": "55d2fc8697af4d0d06a2c4a6",
+ "age": 34,
+ "name": "Chavez Aguilar",
+ "gender": "male",
+ "company": "ISBOL",
+ "email": "chavezaguilar@isbol.com",
+ "phone": "+1 (952) 543-3992"
+ },
+ {
+ "_id": "55d2fc861da12d86036c3e48",
+ "age": 29,
+ "name": "Arnold Collier",
+ "gender": "male",
+ "company": "MELBACOR",
+ "email": "arnoldcollier@melbacor.com",
+ "phone": "+1 (907) 404-2090"
+ },
+ {
+ "_id": "55d2fc86deb921c78b56fec1",
+ "age": 24,
+ "name": "Nixon Ingram",
+ "gender": "male",
+ "company": "ELENTRIX",
+ "email": "nixoningram@elentrix.com",
+ "phone": "+1 (884) 596-3023"
+ },
+ {
+ "_id": "55d2fc86a8b288ba6b8aa48f",
+ "age": 28,
+ "name": "Hurst Hull",
+ "gender": "male",
+ "company": "INCUBUS",
+ "email": "hursthull@incubus.com",
+ "phone": "+1 (970) 445-2279"
+ },
+ {
+ "_id": "55d2fc864dc593d113336b1b",
+ "age": 32,
+ "name": "Giles Jacobson",
+ "gender": "male",
+ "company": "MIXERS",
+ "email": "gilesjacobson@mixers.com",
+ "phone": "+1 (868) 402-3161"
+ },
+ {
+ "_id": "55d2fc86fd0246fcd0c8f864",
+ "age": 25,
+ "name": "Millie Giles",
+ "gender": "female",
+ "company": "ZAJ",
+ "email": "milliegiles@zaj.com",
+ "phone": "+1 (831) 535-3535"
+ },
+ {
+ "_id": "55d2fc86dceeca0deb9f6d67",
+ "age": 21,
+ "name": "Sargent Morse",
+ "gender": "male",
+ "company": "ANARCO",
+ "email": "sargentmorse@anarco.com",
+ "phone": "+1 (994) 536-2563"
+ },
+ {
+ "_id": "55d2fc86abbd1add64df6aa2",
+ "age": 26,
+ "name": "Reed Camacho",
+ "gender": "male",
+ "company": "ICOLOGY",
+ "email": "reedcamacho@icology.com",
+ "phone": "+1 (999) 408-3042"
+ },
+ {
+ "_id": "55d2fc86a2593db6d584f022",
+ "age": 21,
+ "name": "Bryant Colon",
+ "gender": "male",
+ "company": "ZANILLA",
+ "email": "bryantcolon@zanilla.com",
+ "phone": "+1 (964) 570-3418"
+ },
+ {
+ "_id": "55d2fc86f980f74ba093fde6",
+ "age": 38,
+ "name": "Rosella Pierce",
+ "gender": "female",
+ "company": "PRIMORDIA",
+ "email": "rosellapierce@primordia.com",
+ "phone": "+1 (936) 579-3014"
+ },
+ {
+ "_id": "55d2fc86797a0001329071fb",
+ "age": 20,
+ "name": "Patrice Mckee",
+ "gender": "female",
+ "company": "GEEKY",
+ "email": "patricemckee@geeky.com",
+ "phone": "+1 (866) 565-3764"
+ },
+ {
+ "_id": "55d2fc86bcc6181d0b8cae17",
+ "age": 29,
+ "name": "Wilkinson Levy",
+ "gender": "male",
+ "company": "FISHLAND",
+ "email": "wilkinsonlevy@fishland.com",
+ "phone": "+1 (998) 509-3800"
+ },
+ {
+ "_id": "55d2fc86784b1e22004d637d",
+ "age": 28,
+ "name": "Isabella Snyder",
+ "gender": "female",
+ "company": "TETRATREX",
+ "email": "isabellasnyder@tetratrex.com",
+ "phone": "+1 (998) 451-2871"
+ },
+ {
+ "_id": "55d2fc8603abab523ff1f02d",
+ "age": 35,
+ "name": "Claudine Berg",
+ "gender": "female",
+ "company": "ZYTREK",
+ "email": "claudineberg@zytrek.com",
+ "phone": "+1 (836) 563-3376"
+ },
+ {
+ "_id": "55d2fc862796e94846a82a8b",
+ "age": 27,
+ "name": "Hyde Simon",
+ "gender": "male",
+ "company": "FUELWORKS",
+ "email": "hydesimon@fuelworks.com",
+ "phone": "+1 (872) 594-2291"
+ },
+ {
+ "_id": "55d2fc86f2fa84a4f7ca4548",
+ "age": 29,
+ "name": "Wendy Roberts",
+ "gender": "female",
+ "company": "OPTICALL",
+ "email": "wendyroberts@opticall.com",
+ "phone": "+1 (895) 534-3852"
+ },
+ {
+ "_id": "55d2fc8651dbb76674b6d2df",
+ "age": 40,
+ "name": "Tasha Erickson",
+ "gender": "female",
+ "company": "PURIA",
+ "email": "tashaerickson@puria.com",
+ "phone": "+1 (905) 526-2175"
+ },
+ {
+ "_id": "55d2fc86b7f867e76e709d68",
+ "age": 32,
+ "name": "Marisa Dunlap",
+ "gender": "female",
+ "company": "GLUKGLUK",
+ "email": "marisadunlap@glukgluk.com",
+ "phone": "+1 (855) 400-2200"
+ },
+ {
+ "_id": "55d2fc8695b6ccc0707570af",
+ "age": 38,
+ "name": "Kaitlin Baldwin",
+ "gender": "female",
+ "company": "EGYPTO",
+ "email": "kaitlinbaldwin@egypto.com",
+ "phone": "+1 (980) 482-3256"
+ },
+ {
+ "_id": "55d2fc86f36b539d4494395d",
+ "age": 38,
+ "name": "Abigail Kirkland",
+ "gender": "female",
+ "company": "INRT",
+ "email": "abigailkirkland@inrt.com",
+ "phone": "+1 (916) 440-3469"
+ },
+ {
+ "_id": "55d2fc86e401343dbf1de380",
+ "age": 34,
+ "name": "Marci Maynard",
+ "gender": "female",
+ "company": "INSURITY",
+ "email": "marcimaynard@insurity.com",
+ "phone": "+1 (917) 482-3601"
+ },
+ {
+ "_id": "55d2fc86ba3f7fdb738899f4",
+ "age": 31,
+ "name": "Tanya Michael",
+ "gender": "female",
+ "company": "ENVIRE",
+ "email": "tanyamichael@envire.com",
+ "phone": "+1 (826) 436-3177"
+ },
+ {
+ "_id": "55d2fc861cb8a1d3151ae2c1",
+ "age": 34,
+ "name": "Farrell Irwin",
+ "gender": "male",
+ "company": "EXTRAGEN",
+ "email": "farrellirwin@extragen.com",
+ "phone": "+1 (948) 442-3796"
+ },
+ {
+ "_id": "55d2fc86b90f948949af3d8e",
+ "age": 27,
+ "name": "Dickson Shepherd",
+ "gender": "male",
+ "company": "COMTOURS",
+ "email": "dicksonshepherd@comtours.com",
+ "phone": "+1 (871) 458-2972"
+ },
+ {
+ "_id": "55d2fc862065aeaf17581fa6",
+ "age": 40,
+ "name": "Fowler Adams",
+ "gender": "male",
+ "company": "NEPTIDE",
+ "email": "fowleradams@neptide.com",
+ "phone": "+1 (836) 431-3585"
+ },
+ {
+ "_id": "55d2fc866aab8b242a30acfd",
+ "age": 22,
+ "name": "Durham Frost",
+ "gender": "male",
+ "company": "SNOWPOKE",
+ "email": "durhamfrost@snowpoke.com",
+ "phone": "+1 (801) 510-2084"
+ },
+ {
+ "_id": "55d2fc86d3a4aafedc274ffa",
+ "age": 27,
+ "name": "Delia Barnes",
+ "gender": "female",
+ "company": "CONFERIA",
+ "email": "deliabarnes@conferia.com",
+ "phone": "+1 (999) 471-2182"
+ },
+ {
+ "_id": "55d2fc8601ed1a317e289785",
+ "age": 27,
+ "name": "Gill Tillman",
+ "gender": "male",
+ "company": "MATRIXITY",
+ "email": "gilltillman@matrixity.com",
+ "phone": "+1 (880) 419-3960"
+ },
+ {
+ "_id": "55d2fc86098dda4fa3812793",
+ "age": 27,
+ "name": "Loraine Saunders",
+ "gender": "female",
+ "company": "DOGTOWN",
+ "email": "lorainesaunders@dogtown.com",
+ "phone": "+1 (868) 500-3061"
+ },
+ {
+ "_id": "55d2fc865f9615b558837892",
+ "age": 34,
+ "name": "Lou Mcdonald",
+ "gender": "female",
+ "company": "COMCUBINE",
+ "email": "loumcdonald@comcubine.com",
+ "phone": "+1 (857) 568-3427"
+ },
+ {
+ "_id": "55d2fc865a5a752bb88dbcd8",
+ "age": 28,
+ "name": "Beth Lester",
+ "gender": "female",
+ "company": "EARTHWAX",
+ "email": "bethlester@earthwax.com",
+ "phone": "+1 (805) 565-2363"
+ },
+ {
+ "_id": "55d2fc862e7d03a2f76c9e58",
+ "age": 37,
+ "name": "Karin Mason",
+ "gender": "female",
+ "company": "GEEKNET",
+ "email": "karinmason@geeknet.com",
+ "phone": "+1 (923) 438-3684"
+ },
+ {
+ "_id": "55d2fc8617970ba4987ed4b3",
+ "age": 39,
+ "name": "Jeanine Watson",
+ "gender": "female",
+ "company": "LINGOAGE",
+ "email": "jeaninewatson@lingoage.com",
+ "phone": "+1 (919) 444-3722"
+ },
+ {
+ "_id": "55d2fc86445181571721c6c9",
+ "age": 20,
+ "name": "Soto Wilkins",
+ "gender": "male",
+ "company": "JUMPSTACK",
+ "email": "sotowilkins@jumpstack.com",
+ "phone": "+1 (818) 518-3028"
+ },
+ {
+ "_id": "55d2fc86b8b146361e17fa83",
+ "age": 20,
+ "name": "Mabel Fields",
+ "gender": "female",
+ "company": "MAGNINA",
+ "email": "mabelfields@magnina.com",
+ "phone": "+1 (861) 583-2161"
+ },
+ {
+ "_id": "55d2fc8667abfe5721a74176",
+ "age": 26,
+ "name": "Ruthie Bailey",
+ "gender": "female",
+ "company": "ROCKLOGIC",
+ "email": "ruthiebailey@rocklogic.com",
+ "phone": "+1 (872) 402-3619"
+ },
+ {
+ "_id": "55d2fc865cfa092adb20dc0f",
+ "age": 22,
+ "name": "Vaughan Vincent",
+ "gender": "male",
+ "company": "ACIUM",
+ "email": "vaughanvincent@acium.com",
+ "phone": "+1 (919) 548-3948"
+ },
+ {
+ "_id": "55d2fc86fe25d347c15e1749",
+ "age": 38,
+ "name": "Myrtle Burris",
+ "gender": "female",
+ "company": "IRACK",
+ "email": "myrtleburris@irack.com",
+ "phone": "+1 (840) 526-2646"
+ },
+ {
+ "_id": "55d2fc8689cd98b47e44118d",
+ "age": 37,
+ "name": "Peggy Mercer",
+ "gender": "female",
+ "company": "ESCENTA",
+ "email": "peggymercer@escenta.com",
+ "phone": "+1 (817) 574-3310"
+ },
+ {
+ "_id": "55d2fc86ae662f567ae09404",
+ "age": 24,
+ "name": "Mollie Simmons",
+ "gender": "female",
+ "company": "STOCKPOST",
+ "email": "molliesimmons@stockpost.com",
+ "phone": "+1 (854) 461-2851"
+ },
+ {
+ "_id": "55d2fc86f738f2bd6ebebd1c",
+ "age": 37,
+ "name": "Case Cox",
+ "gender": "male",
+ "company": "ACCEL",
+ "email": "casecox@accel.com",
+ "phone": "+1 (853) 473-2780"
+ },
+ {
+ "_id": "55d2fc86c80907be4ff386d5",
+ "age": 26,
+ "name": "Snyder Mcclure",
+ "gender": "male",
+ "company": "PLASMOX",
+ "email": "snydermcclure@plasmox.com",
+ "phone": "+1 (980) 583-3213"
+ },
+ {
+ "_id": "55d2fc86ed956580fa2cff25",
+ "age": 31,
+ "name": "Kelly Malone",
+ "gender": "male",
+ "company": "XANIDE",
+ "email": "kellymalone@xanide.com",
+ "phone": "+1 (871) 436-2431"
+ },
+ {
+ "_id": "55d2fc86fcd2b8d749bd1feb",
+ "age": 20,
+ "name": "Jackie Carr",
+ "gender": "female",
+ "company": "VOIPA",
+ "email": "jackiecarr@voipa.com",
+ "phone": "+1 (807) 431-3436"
+ },
+ {
+ "_id": "55d2fc86d9aac03a007489ef",
+ "age": 34,
+ "name": "Cochran Walter",
+ "gender": "male",
+ "company": "NIKUDA",
+ "email": "cochranwalter@nikuda.com",
+ "phone": "+1 (977) 410-3770"
+ },
+ {
+ "_id": "55d2fc86140fefcd667c533f",
+ "age": 22,
+ "name": "Ellen Ortiz",
+ "gender": "female",
+ "company": "NEWCUBE",
+ "email": "ellenortiz@newcube.com",
+ "phone": "+1 (980) 541-3099"
+ },
+ {
+ "_id": "55d2fc86d374c6a649e5877e",
+ "age": 35,
+ "name": "Concetta Beard",
+ "gender": "female",
+ "company": "PLASMOS",
+ "email": "concettabeard@plasmos.com",
+ "phone": "+1 (839) 539-2423"
+ },
+ {
+ "_id": "55d2fc861ee809861b7c2b38",
+ "age": 33,
+ "name": "Josephine Alexander",
+ "gender": "female",
+ "company": "LOVEPAD",
+ "email": "josephinealexander@lovepad.com",
+ "phone": "+1 (880) 452-2208"
+ },
+ {
+ "_id": "55d2fc8677db4f8446d43041",
+ "age": 39,
+ "name": "Melisa Dean",
+ "gender": "female",
+ "company": "GEOFORM",
+ "email": "melisadean@geoform.com",
+ "phone": "+1 (934) 452-2532"
+ },
+ {
+ "_id": "55d2fc861dc0856e2ec744ab",
+ "age": 26,
+ "name": "Morgan Galloway",
+ "gender": "male",
+ "company": "ELEMANTRA",
+ "email": "morgangalloway@elemantra.com",
+ "phone": "+1 (888) 461-2261"
+ },
+ {
+ "_id": "55d2fc869bc97691cec7d569",
+ "age": 26,
+ "name": "Curtis Griffith",
+ "gender": "male",
+ "company": "TINGLES",
+ "email": "curtisgriffith@tingles.com",
+ "phone": "+1 (881) 517-2174"
+ },
+ {
+ "_id": "55d2fc8624b80b5986e1de83",
+ "age": 40,
+ "name": "Gentry Mccarthy",
+ "gender": "male",
+ "company": "GEEKOLA",
+ "email": "gentrymccarthy@geekola.com",
+ "phone": "+1 (908) 559-3049"
+ },
+ {
+ "_id": "55d2fc869c2a158da79f9a7f",
+ "age": 37,
+ "name": "Lancaster Justice",
+ "gender": "male",
+ "company": "NAXDIS",
+ "email": "lancasterjustice@naxdis.com",
+ "phone": "+1 (980) 456-3515"
+ },
+ {
+ "_id": "55d2fc867c8e30a12fddcb79",
+ "age": 28,
+ "name": "Jenifer Barr",
+ "gender": "female",
+ "company": "ZORROMOP",
+ "email": "jeniferbarr@zorromop.com",
+ "phone": "+1 (901) 440-3979"
+ },
+ {
+ "_id": "55d2fc8696d7c8b59507f10c",
+ "age": 35,
+ "name": "Benjamin Nolan",
+ "gender": "male",
+ "company": "DIGITALUS",
+ "email": "benjaminnolan@digitalus.com",
+ "phone": "+1 (828) 582-3041"
+ },
+ {
+ "_id": "55d2fc86b7e719a5c07b9f9e",
+ "age": 27,
+ "name": "Beach Valentine",
+ "gender": "male",
+ "company": "KAGGLE",
+ "email": "beachvalentine@kaggle.com",
+ "phone": "+1 (961) 563-3631"
+ },
+ {
+ "_id": "55d2fc860bb827b4eab70038",
+ "age": 27,
+ "name": "Brady Moore",
+ "gender": "male",
+ "company": "CORPULSE",
+ "email": "bradymoore@corpulse.com",
+ "phone": "+1 (859) 434-2962"
+ },
+ {
+ "_id": "55d2fc862fc00a2ce6ab7f32",
+ "age": 27,
+ "name": "Page Ray",
+ "gender": "male",
+ "company": "BEZAL",
+ "email": "pageray@bezal.com",
+ "phone": "+1 (845) 492-2182"
+ },
+ {
+ "_id": "55d2fc861b57330b56d5b3f8",
+ "age": 40,
+ "name": "Lupe Gould",
+ "gender": "female",
+ "company": "DOGNOSIS",
+ "email": "lupegould@dognosis.com",
+ "phone": "+1 (955) 579-2141"
+ },
+ {
+ "_id": "55d2fc864a8fabbf89d106cd",
+ "age": 23,
+ "name": "Melva Abbott",
+ "gender": "female",
+ "company": "CODACT",
+ "email": "melvaabbott@codact.com",
+ "phone": "+1 (801) 478-2678"
+ },
+ {
+ "_id": "55d2fc86107ad0ad66c9d3ea",
+ "age": 22,
+ "name": "Mendez Middleton",
+ "gender": "male",
+ "company": "CUJO",
+ "email": "mendezmiddleton@cujo.com",
+ "phone": "+1 (908) 430-2032"
+ },
+ {
+ "_id": "55d2fc86d2f5edd1222e87cc",
+ "age": 31,
+ "name": "Meredith Ayers",
+ "gender": "female",
+ "company": "OPTYK",
+ "email": "meredithayers@optyk.com",
+ "phone": "+1 (875) 472-2514"
+ },
+ {
+ "_id": "55d2fc86551f2a796de0f3ad",
+ "age": 21,
+ "name": "Burns Serrano",
+ "gender": "male",
+ "company": "ZOUNDS",
+ "email": "burnsserrano@zounds.com",
+ "phone": "+1 (939) 558-2221"
+ },
+ {
+ "_id": "55d2fc86540849ad56aeac98",
+ "age": 30,
+ "name": "Barr Sykes",
+ "gender": "male",
+ "company": "CORECOM",
+ "email": "barrsykes@corecom.com",
+ "phone": "+1 (982) 523-3577"
+ },
+ {
+ "_id": "55d2fc86e7d43d06e4d135f2",
+ "age": 28,
+ "name": "Julie Johnson",
+ "gender": "female",
+ "company": "BIOTICA",
+ "email": "juliejohnson@biotica.com",
+ "phone": "+1 (918) 487-3230"
+ },
+ {
+ "_id": "55d2fc86450521acf4a465d9",
+ "age": 23,
+ "name": "Dawn Vinson",
+ "gender": "female",
+ "company": "MENBRAIN",
+ "email": "dawnvinson@menbrain.com",
+ "phone": "+1 (936) 525-3273"
+ },
+ {
+ "_id": "55d2fc86df3e093a104f498b",
+ "age": 30,
+ "name": "Ginger Ryan",
+ "gender": "female",
+ "company": "ENTHAZE",
+ "email": "gingerryan@enthaze.com",
+ "phone": "+1 (865) 530-2726"
+ },
+ {
+ "_id": "55d2fc86b6a6fed233908500",
+ "age": 40,
+ "name": "Mcconnell Prince",
+ "gender": "male",
+ "company": "TRIPSCH",
+ "email": "mcconnellprince@tripsch.com",
+ "phone": "+1 (923) 586-2117"
+ },
+ {
+ "_id": "55d2fc8619de2514561b7ac1",
+ "age": 23,
+ "name": "Peck Blackwell",
+ "gender": "male",
+ "company": "ASSISTIA",
+ "email": "peckblackwell@assistia.com",
+ "phone": "+1 (988) 549-3418"
+ },
+ {
+ "_id": "55d2fc8619b2c263aec32e51",
+ "age": 32,
+ "name": "Simmons Benton",
+ "gender": "male",
+ "company": "TROLLERY",
+ "email": "simmonsbenton@trollery.com",
+ "phone": "+1 (924) 439-2962"
+ },
+ {
+ "_id": "55d2fc8612c77e18fa3c743d",
+ "age": 36,
+ "name": "Mari Silva",
+ "gender": "female",
+ "company": "MAGMINA",
+ "email": "marisilva@magmina.com",
+ "phone": "+1 (863) 509-3186"
+ },
+ {
+ "_id": "55d2fc86226a40ce862e518e",
+ "age": 40,
+ "name": "Erin Jefferson",
+ "gender": "female",
+ "company": "VIAGREAT",
+ "email": "erinjefferson@viagreat.com",
+ "phone": "+1 (921) 408-2295"
+ },
+ {
+ "_id": "55d2fc8601013536fc55a097",
+ "age": 37,
+ "name": "Nellie Ballard",
+ "gender": "female",
+ "company": "GEOFORMA",
+ "email": "nellieballard@geoforma.com",
+ "phone": "+1 (918) 406-2600"
+ },
+ {
+ "_id": "55d2fc864402965704b3453a",
+ "age": 27,
+ "name": "Austin Brewer",
+ "gender": "male",
+ "company": "METROZ",
+ "email": "austinbrewer@metroz.com",
+ "phone": "+1 (968) 584-2959"
+ },
+ {
+ "_id": "55d2fc8690a7d6957a09f6c8",
+ "age": 34,
+ "name": "Pickett Buckley",
+ "gender": "male",
+ "company": "SUREPLEX",
+ "email": "pickettbuckley@sureplex.com",
+ "phone": "+1 (975) 520-3259"
+ },
+ {
+ "_id": "55d2fc8695f3020c96b14f95",
+ "age": 39,
+ "name": "Coleen Herman",
+ "gender": "female",
+ "company": "NORALI",
+ "email": "coleenherman@norali.com",
+ "phone": "+1 (916) 506-2704"
+ },
+ {
+ "_id": "55d2fc869b58b96d1d2cdfcc",
+ "age": 37,
+ "name": "Roy Guerrero",
+ "gender": "male",
+ "company": "PLUTORQUE",
+ "email": "royguerrero@plutorque.com",
+ "phone": "+1 (922) 541-3741"
+ },
+ {
+ "_id": "55d2fc86ba1ed1189e9020ee",
+ "age": 29,
+ "name": "Oneal Curtis",
+ "gender": "male",
+ "company": "DATAGEN",
+ "email": "onealcurtis@datagen.com",
+ "phone": "+1 (847) 421-3483"
+ },
+ {
+ "_id": "55d2fc86b5c5e89eb9fe1e79",
+ "age": 29,
+ "name": "Chaney Christian",
+ "gender": "male",
+ "company": "XPLOR",
+ "email": "chaneychristian@xplor.com",
+ "phone": "+1 (847) 517-3918"
+ },
+ {
+ "_id": "55d2fc86f6b5a3d91952d941",
+ "age": 29,
+ "name": "Cantu Richard",
+ "gender": "male",
+ "company": "ZANYMAX",
+ "email": "canturichard@zanymax.com",
+ "phone": "+1 (972) 487-2616"
+ },
+ {
+ "_id": "55d2fc8609b0f98cbc2e101d",
+ "age": 37,
+ "name": "Newton Barrera",
+ "gender": "male",
+ "company": "PORTALINE",
+ "email": "newtonbarrera@portaline.com",
+ "phone": "+1 (964) 527-3130"
+ },
+ {
+ "_id": "55d2fc86d0e063ca7629c11b",
+ "age": 28,
+ "name": "Jodi Pollard",
+ "gender": "female",
+ "company": "GOKO",
+ "email": "jodipollard@goko.com",
+ "phone": "+1 (957) 468-2658"
+ },
+ {
+ "_id": "55d2fc8688d95c5c579bd328",
+ "age": 35,
+ "name": "Effie Nunez",
+ "gender": "female",
+ "company": "SNACKTION",
+ "email": "effienunez@snacktion.com",
+ "phone": "+1 (805) 576-3749"
+ },
+ {
+ "_id": "55d2fc86f36c0eab69222b17",
+ "age": 38,
+ "name": "Haley Battle",
+ "gender": "male",
+ "company": "TERRAGEN",
+ "email": "haleybattle@terragen.com",
+ "phone": "+1 (955) 581-3931"
+ },
+ {
+ "_id": "55d2fc86ee6900b197860a35",
+ "age": 29,
+ "name": "Cathy Vaughn",
+ "gender": "female",
+ "company": "CANOPOLY",
+ "email": "cathyvaughn@canopoly.com",
+ "phone": "+1 (875) 539-3578"
+ },
+ {
+ "_id": "55d2fc86613f698b355e87bc",
+ "age": 26,
+ "name": "Mendoza Maxwell",
+ "gender": "male",
+ "company": "TERAPRENE",
+ "email": "mendozamaxwell@teraprene.com",
+ "phone": "+1 (820) 471-3500"
+ },
+ {
+ "_id": "55d2fc86f86a80f78c45936a",
+ "age": 28,
+ "name": "Rosetta Hughes",
+ "gender": "female",
+ "company": "DEVILTOE",
+ "email": "rosettahughes@deviltoe.com",
+ "phone": "+1 (911) 418-2439"
+ },
+ {
+ "_id": "55d2fc8683d3c4a377a984a5",
+ "age": 28,
+ "name": "Frazier Larson",
+ "gender": "male",
+ "company": "DAIDO",
+ "email": "frazierlarson@daido.com",
+ "phone": "+1 (995) 459-3756"
+ },
+ {
+ "_id": "55d2fc8669baef03c4d6a4a5",
+ "age": 27,
+ "name": "Brittney Ratliff",
+ "gender": "female",
+ "company": "TALKALOT",
+ "email": "brittneyratliff@talkalot.com",
+ "phone": "+1 (865) 568-2986"
+ },
+ {
+ "_id": "55d2fc86404583ccc6b6a4f4",
+ "age": 21,
+ "name": "Hancock Gilliam",
+ "gender": "male",
+ "company": "EXPOSA",
+ "email": "hancockgilliam@exposa.com",
+ "phone": "+1 (894) 519-3139"
+ },
+ {
+ "_id": "55d2fc8675478e0b84bb5ab3",
+ "age": 20,
+ "name": "Lilia Mccormick",
+ "gender": "female",
+ "company": "DENTREX",
+ "email": "liliamccormick@dentrex.com",
+ "phone": "+1 (997) 552-3944"
+ },
+ {
+ "_id": "55d2fc8658bf3954cdf52ebb",
+ "age": 20,
+ "name": "Chrystal Mcneil",
+ "gender": "female",
+ "company": "LIMOZEN",
+ "email": "chrystalmcneil@limozen.com",
+ "phone": "+1 (943) 519-2952"
+ },
+ {
+ "_id": "55d2fc865ebec9e8c7adc383",
+ "age": 31,
+ "name": "Hebert Alston",
+ "gender": "male",
+ "company": "IZZBY",
+ "email": "hebertalston@izzby.com",
+ "phone": "+1 (953) 482-2029"
+ },
+ {
+ "_id": "55d2fc86bf1085e6fd2e9ea1",
+ "age": 23,
+ "name": "Mcfarland Carrillo",
+ "gender": "male",
+ "company": "EQUITOX",
+ "email": "mcfarlandcarrillo@equitox.com",
+ "phone": "+1 (999) 478-3822"
+ },
+ {
+ "_id": "55d2fc8641d4f2d09f539bd6",
+ "age": 40,
+ "name": "Porter Weaver",
+ "gender": "male",
+ "company": "QUILM",
+ "email": "porterweaver@quilm.com",
+ "phone": "+1 (831) 501-2739"
+ },
+ {
+ "_id": "55d2fc869ee5331a50039e30",
+ "age": 23,
+ "name": "Dale Sims",
+ "gender": "male",
+ "company": "SCENTRIC",
+ "email": "dalesims@scentric.com",
+ "phone": "+1 (845) 597-2120"
+ },
+ {
+ "_id": "55d2fc86cb96d31fe71e4a18",
+ "age": 22,
+ "name": "William Dixon",
+ "gender": "male",
+ "company": "NAMEBOX",
+ "email": "williamdixon@namebox.com",
+ "phone": "+1 (970) 448-2651"
+ },
+ {
+ "_id": "55d2fc86e88daeb1e198671d",
+ "age": 33,
+ "name": "Patrica Reed",
+ "gender": "female",
+ "company": "CORPORANA",
+ "email": "patricareed@corporana.com",
+ "phone": "+1 (817) 457-2413"
+ },
+ {
+ "_id": "55d2fc86c33d9f422bf8bfcc",
+ "age": 20,
+ "name": "Marylou Mcmillan",
+ "gender": "female",
+ "company": "RETRACK",
+ "email": "maryloumcmillan@retrack.com",
+ "phone": "+1 (908) 568-2328"
+ },
+ {
+ "_id": "55d2fc86c4b1b139887e76f1",
+ "age": 20,
+ "name": "Maritza David",
+ "gender": "female",
+ "company": "ORBEAN",
+ "email": "maritzadavid@orbean.com",
+ "phone": "+1 (851) 503-3737"
+ },
+ {
+ "_id": "55d2fc86ac0f360d91c740e6",
+ "age": 23,
+ "name": "Lorie Moses",
+ "gender": "female",
+ "company": "ROCKABYE",
+ "email": "loriemoses@rockabye.com",
+ "phone": "+1 (823) 431-2387"
+ },
+ {
+ "_id": "55d2fc86d7d406569b386b17",
+ "age": 35,
+ "name": "Shields Weiss",
+ "gender": "male",
+ "company": "RODEOCEAN",
+ "email": "shieldsweiss@rodeocean.com",
+ "phone": "+1 (957) 490-3725"
+ },
+ {
+ "_id": "55d2fc86e4f66ce770ae2c93",
+ "age": 25,
+ "name": "Eugenia Berry",
+ "gender": "female",
+ "company": "BISBA",
+ "email": "eugeniaberry@bisba.com",
+ "phone": "+1 (948) 403-3403"
+ },
+ {
+ "_id": "55d2fc8618f2f4f428223522",
+ "age": 33,
+ "name": "Howard Compton",
+ "gender": "male",
+ "company": "NAMEGEN",
+ "email": "howardcompton@namegen.com",
+ "phone": "+1 (827) 439-3667"
+ },
+ {
+ "_id": "55d2fc86f5adc0f6dd535ea6",
+ "age": 28,
+ "name": "Key Davis",
+ "gender": "male",
+ "company": "PORTICO",
+ "email": "keydavis@portico.com",
+ "phone": "+1 (873) 533-2980"
+ },
+ {
+ "_id": "55d2fc86876669f4e9431417",
+ "age": 33,
+ "name": "Phillips Solis",
+ "gender": "male",
+ "company": "DANCITY",
+ "email": "phillipssolis@dancity.com",
+ "phone": "+1 (883) 481-3114"
+ },
+ {
+ "_id": "55d2fc86f2bb610d7ad9ea36",
+ "age": 40,
+ "name": "Cash Pugh",
+ "gender": "male",
+ "company": "STUCCO",
+ "email": "cashpugh@stucco.com",
+ "phone": "+1 (873) 512-2106"
+ },
+ {
+ "_id": "55d2fc863be1649d5bd3be39",
+ "age": 21,
+ "name": "Elinor Warner",
+ "gender": "female",
+ "company": "FOSSIEL",
+ "email": "elinorwarner@fossiel.com",
+ "phone": "+1 (950) 431-3679"
+ },
+ {
+ "_id": "55d2fc86fdad2af5536237e2",
+ "age": 35,
+ "name": "Jacquelyn Doyle",
+ "gender": "female",
+ "company": "CYTREX",
+ "email": "jacquelyndoyle@cytrex.com",
+ "phone": "+1 (924) 569-2919"
+ },
+ {
+ "_id": "55d2fc86f3affa20ab27edff",
+ "age": 33,
+ "name": "Jeannine Mosley",
+ "gender": "female",
+ "company": "ACUSAGE",
+ "email": "jeanninemosley@acusage.com",
+ "phone": "+1 (954) 517-2805"
+ },
+ {
+ "_id": "55d2fc8670dd0dbdd6e4d195",
+ "age": 37,
+ "name": "Logan Brady",
+ "gender": "male",
+ "company": "TELLIFLY",
+ "email": "loganbrady@tellifly.com",
+ "phone": "+1 (861) 576-2313"
+ },
+ {
+ "_id": "55d2fc86b9a15e4721982a39",
+ "age": 26,
+ "name": "Houston Joseph",
+ "gender": "male",
+ "company": "BOILICON",
+ "email": "houstonjoseph@boilicon.com",
+ "phone": "+1 (822) 519-3430"
+ },
+ {
+ "_id": "55d2fc86f225999b0b8742d2",
+ "age": 38,
+ "name": "Rita Lindsey",
+ "gender": "female",
+ "company": "FIBEROX",
+ "email": "ritalindsey@fiberox.com",
+ "phone": "+1 (805) 551-3755"
+ },
+ {
+ "_id": "55d2fc86e9dad38b6873b807",
+ "age": 22,
+ "name": "Strong Poole",
+ "gender": "male",
+ "company": "KINDALOO",
+ "email": "strongpoole@kindaloo.com",
+ "phone": "+1 (918) 426-2076"
+ },
+ {
+ "_id": "55d2fc861608b965b2283827",
+ "age": 38,
+ "name": "Hines Mathews",
+ "gender": "male",
+ "company": "INTRADISK",
+ "email": "hinesmathews@intradisk.com",
+ "phone": "+1 (932) 420-2236"
+ },
+ {
+ "_id": "55d2fc863079075f91241a16",
+ "age": 28,
+ "name": "Trina Wiley",
+ "gender": "female",
+ "company": "HATOLOGY",
+ "email": "trinawiley@hatology.com",
+ "phone": "+1 (855) 466-3287"
+ },
+ {
+ "_id": "55d2fc86f2fae1a79253fb61",
+ "age": 23,
+ "name": "Kirby Tucker",
+ "gender": "male",
+ "company": "AQUAMATE",
+ "email": "kirbytucker@aquamate.com",
+ "phone": "+1 (935) 456-3272"
+ },
+ {
+ "_id": "55d2fc86c42bf49f8202b2fa",
+ "age": 28,
+ "name": "Ballard Stein",
+ "gender": "male",
+ "company": "KOOGLE",
+ "email": "ballardstein@koogle.com",
+ "phone": "+1 (943) 586-2225"
+ },
+ {
+ "_id": "55d2fc865db815da198c0776",
+ "age": 36,
+ "name": "Wagner Mcfarland",
+ "gender": "male",
+ "company": "ACCIDENCY",
+ "email": "wagnermcfarland@accidency.com",
+ "phone": "+1 (920) 533-2157"
+ },
+ {
+ "_id": "55d2fc866aeb268fe48fd6be",
+ "age": 22,
+ "name": "Wiley Wilder",
+ "gender": "male",
+ "company": "KIDSTOCK",
+ "email": "wileywilder@kidstock.com",
+ "phone": "+1 (957) 459-3416"
+ },
+ {
+ "_id": "55d2fc8606f67a423d303437",
+ "age": 37,
+ "name": "Rosario Slater",
+ "gender": "female",
+ "company": "SPRINGBEE",
+ "email": "rosarioslater@springbee.com",
+ "phone": "+1 (950) 506-3454"
+ },
+ {
+ "_id": "55d2fc86510fd16a269a0201",
+ "age": 37,
+ "name": "Walker Mcdowell",
+ "gender": "male",
+ "company": "ONTAGENE",
+ "email": "walkermcdowell@ontagene.com",
+ "phone": "+1 (953) 579-3429"
+ },
+ {
+ "_id": "55d2fc867d419d30f9394f56",
+ "age": 32,
+ "name": "Booth Pratt",
+ "gender": "male",
+ "company": "ZIGGLES",
+ "email": "boothpratt@ziggles.com",
+ "phone": "+1 (835) 453-3707"
+ },
+ {
+ "_id": "55d2fc86e631b8f71bbe7b35",
+ "age": 33,
+ "name": "Georgia Carpenter",
+ "gender": "female",
+ "company": "STRALUM",
+ "email": "georgiacarpenter@stralum.com",
+ "phone": "+1 (923) 536-3557"
+ },
+ {
+ "_id": "55d2fc866df6437afa4cfaf6",
+ "age": 26,
+ "name": "Harding Powers",
+ "gender": "male",
+ "company": "BEADZZA",
+ "email": "hardingpowers@beadzza.com",
+ "phone": "+1 (855) 467-2993"
+ },
+ {
+ "_id": "55d2fc867ade492afcfc24a6",
+ "age": 37,
+ "name": "Kaye Brown",
+ "gender": "female",
+ "company": "AMTAS",
+ "email": "kayebrown@amtas.com",
+ "phone": "+1 (926) 444-3936"
+ },
+ {
+ "_id": "55d2fc862bf33dd3169710ff",
+ "age": 24,
+ "name": "Mccray Padilla",
+ "gender": "male",
+ "company": "FUTURIS",
+ "email": "mccraypadilla@futuris.com",
+ "phone": "+1 (969) 561-3819"
+ },
+ {
+ "_id": "55d2fc8666f74690303abf65",
+ "age": 35,
+ "name": "Moon Moss",
+ "gender": "male",
+ "company": "EURON",
+ "email": "moonmoss@euron.com",
+ "phone": "+1 (885) 514-2872"
+ },
+ {
+ "_id": "55d2fc860a8b5abfdf57bd37",
+ "age": 26,
+ "name": "Lane Gregory",
+ "gender": "male",
+ "company": "SKINSERVE",
+ "email": "lanegregory@skinserve.com",
+ "phone": "+1 (818) 455-3048"
+ },
+ {
+ "_id": "55d2fc86f17541fe3b770b26",
+ "age": 30,
+ "name": "Cummings Good",
+ "gender": "male",
+ "company": "GEEKOLOGY",
+ "email": "cummingsgood@geekology.com",
+ "phone": "+1 (821) 426-3476"
+ },
+ {
+ "_id": "55d2fc865b6232d788278e1f",
+ "age": 26,
+ "name": "Lottie Soto",
+ "gender": "female",
+ "company": "INTERGEEK",
+ "email": "lottiesoto@intergeek.com",
+ "phone": "+1 (905) 516-2928"
+ },
+ {
+ "_id": "55d2fc868388a50b97dda5c2",
+ "age": 38,
+ "name": "Bridges Bell",
+ "gender": "male",
+ "company": "MIRACULA",
+ "email": "bridgesbell@miracula.com",
+ "phone": "+1 (917) 438-3079"
+ },
+ {
+ "_id": "55d2fc86cc2120d10b75c41b",
+ "age": 23,
+ "name": "Marcella Lancaster",
+ "gender": "female",
+ "company": "NAVIR",
+ "email": "marcellalancaster@navir.com",
+ "phone": "+1 (851) 478-2535"
+ },
+ {
+ "_id": "55d2fc86f52bd008c87c6993",
+ "age": 32,
+ "name": "Foley Yang",
+ "gender": "male",
+ "company": "APEXTRI",
+ "email": "foleyyang@apextri.com",
+ "phone": "+1 (978) 504-2003"
+ },
+ {
+ "_id": "55d2fc86088b65117b293eef",
+ "age": 21,
+ "name": "Debora Levine",
+ "gender": "female",
+ "company": "VANTAGE",
+ "email": "deboralevine@vantage.com",
+ "phone": "+1 (820) 472-2507"
+ },
+ {
+ "_id": "55d2fc86765d079d8584c281",
+ "age": 30,
+ "name": "Jill Durham",
+ "gender": "female",
+ "company": "FUTURITY",
+ "email": "jilldurham@futurity.com",
+ "phone": "+1 (996) 499-2910"
+ },
+ {
+ "_id": "55d2fc860ed183243d043f79",
+ "age": 28,
+ "name": "Della Sherman",
+ "gender": "female",
+ "company": "EXTRO",
+ "email": "dellasherman@extro.com",
+ "phone": "+1 (893) 541-2867"
+ },
+ {
+ "_id": "55d2fc8646733a05fa448c6e",
+ "age": 30,
+ "name": "Tamara Albert",
+ "gender": "female",
+ "company": "ECOLIGHT",
+ "email": "tamaraalbert@ecolight.com",
+ "phone": "+1 (870) 514-2615"
+ },
+ {
+ "_id": "55d2fc86b8bf0a0f7ffb702e",
+ "age": 39,
+ "name": "Lynn Green",
+ "gender": "male",
+ "company": "SNIPS",
+ "email": "lynngreen@snips.com",
+ "phone": "+1 (938) 464-2073"
+ },
+ {
+ "_id": "55d2fc863e577905fc3ea8e7",
+ "age": 29,
+ "name": "Barbra Tate",
+ "gender": "female",
+ "company": "ACRUEX",
+ "email": "barbratate@acruex.com",
+ "phone": "+1 (809) 418-2604"
+ },
+ {
+ "_id": "55d2fc86335b53151fc242b5",
+ "age": 33,
+ "name": "Potts Dickerson",
+ "gender": "male",
+ "company": "SHADEASE",
+ "email": "pottsdickerson@shadease.com",
+ "phone": "+1 (967) 539-3330"
+ },
+ {
+ "_id": "55d2fc86716df5cb28925d59",
+ "age": 36,
+ "name": "Nancy Woodard",
+ "gender": "female",
+ "company": "ZOSIS",
+ "email": "nancywoodard@zosis.com",
+ "phone": "+1 (811) 434-3223"
+ },
+ {
+ "_id": "55d2fc86058113d9a4909796",
+ "age": 29,
+ "name": "Park Evans",
+ "gender": "male",
+ "company": "XUMONK",
+ "email": "parkevans@xumonk.com",
+ "phone": "+1 (836) 443-2361"
+ },
+ {
+ "_id": "55d2fc8659b6d92fb2880f83",
+ "age": 25,
+ "name": "Nicole Sullivan",
+ "gender": "female",
+ "company": "QUALITEX",
+ "email": "nicolesullivan@qualitex.com",
+ "phone": "+1 (823) 584-2994"
+ },
+ {
+ "_id": "55d2fc86510772cfe78617a9",
+ "age": 33,
+ "name": "Bowers Barnett",
+ "gender": "male",
+ "company": "HOUSEDOWN",
+ "email": "bowersbarnett@housedown.com",
+ "phone": "+1 (872) 466-3548"
+ },
+ {
+ "_id": "55d2fc868dec3ac619cfc262",
+ "age": 21,
+ "name": "Jeri Nielsen",
+ "gender": "female",
+ "company": "MOBILDATA",
+ "email": "jerinielsen@mobildata.com",
+ "phone": "+1 (886) 581-2045"
+ },
+ {
+ "_id": "55d2fc863e89d05123e90aaf",
+ "age": 26,
+ "name": "Delores Farmer",
+ "gender": "female",
+ "company": "XERONK",
+ "email": "deloresfarmer@xeronk.com",
+ "phone": "+1 (872) 556-2716"
+ },
+ {
+ "_id": "55d2fc8618c10cef39c48f97",
+ "age": 38,
+ "name": "Mathis Walsh",
+ "gender": "male",
+ "company": "VURBO",
+ "email": "mathiswalsh@vurbo.com",
+ "phone": "+1 (837) 459-2909"
+ },
+ {
+ "_id": "55d2fc868b3487cb71c8bac4",
+ "age": 20,
+ "name": "Ingrid Shelton",
+ "gender": "female",
+ "company": "ORBIN",
+ "email": "ingridshelton@orbin.com",
+ "phone": "+1 (914) 592-2364"
+ },
+ {
+ "_id": "55d2fc86bcf5c885edacef50",
+ "age": 36,
+ "name": "Socorro Burns",
+ "gender": "female",
+ "company": "NETAGY",
+ "email": "socorroburns@netagy.com",
+ "phone": "+1 (931) 523-3116"
+ },
+ {
+ "_id": "55d2fc8693f704f5c95c48a7",
+ "age": 39,
+ "name": "Jo Ware",
+ "gender": "female",
+ "company": "FLYBOYZ",
+ "email": "joware@flyboyz.com",
+ "phone": "+1 (844) 467-2192"
+ },
+ {
+ "_id": "55d2fc86e87485075df33029",
+ "age": 38,
+ "name": "Emilia Flores",
+ "gender": "female",
+ "company": "ZAGGLES",
+ "email": "emiliaflores@zaggles.com",
+ "phone": "+1 (992) 408-2629"
+ },
+ {
+ "_id": "55d2fc861ab925ca0b9b15c6",
+ "age": 31,
+ "name": "Burks Haney",
+ "gender": "male",
+ "company": "ZYPLE",
+ "email": "burkshaney@zyple.com",
+ "phone": "+1 (882) 401-2811"
+ },
+ {
+ "_id": "55d2fc86e9c252588455b811",
+ "age": 31,
+ "name": "Holly Snow",
+ "gender": "female",
+ "company": "FURNAFIX",
+ "email": "hollysnow@furnafix.com",
+ "phone": "+1 (802) 592-2798"
+ },
+ {
+ "_id": "55d2fc86e07c753096021423",
+ "age": 25,
+ "name": "Frances Hayden",
+ "gender": "female",
+ "company": "SNORUS",
+ "email": "franceshayden@snorus.com",
+ "phone": "+1 (818) 481-2431"
+ },
+ {
+ "_id": "55d2fc86496884876065c346",
+ "age": 28,
+ "name": "Lila Lewis",
+ "gender": "female",
+ "company": "ZOMBOID",
+ "email": "lilalewis@zomboid.com",
+ "phone": "+1 (893) 593-2423"
+ },
+ {
+ "_id": "55d2fc865c6ea080a4d0a5b5",
+ "age": 34,
+ "name": "Torres Finley",
+ "gender": "male",
+ "company": "MAXIMIND",
+ "email": "torresfinley@maximind.com",
+ "phone": "+1 (888) 504-3674"
+ },
+ {
+ "_id": "55d2fc86391c44c545fe989f",
+ "age": 23,
+ "name": "Horne James",
+ "gender": "male",
+ "company": "PETICULAR",
+ "email": "hornejames@peticular.com",
+ "phone": "+1 (865) 558-2517"
+ },
+ {
+ "_id": "55d2fc86c8c2529939eada03",
+ "age": 28,
+ "name": "Jennings Wallace",
+ "gender": "male",
+ "company": "CAXT",
+ "email": "jenningswallace@caxt.com",
+ "phone": "+1 (833) 599-3895"
+ },
+ {
+ "_id": "55d2fc86ee656fe865fbde29",
+ "age": 33,
+ "name": "Lily Gilmore",
+ "gender": "female",
+ "company": "RADIANTIX",
+ "email": "lilygilmore@radiantix.com",
+ "phone": "+1 (854) 561-3148"
+ },
+ {
+ "_id": "55d2fc868455126d596ab537",
+ "age": 35,
+ "name": "Kristy Delacruz",
+ "gender": "female",
+ "company": "EQUICOM",
+ "email": "kristydelacruz@equicom.com",
+ "phone": "+1 (871) 502-3732"
+ },
+ {
+ "_id": "55d2fc863096983ef370ca49",
+ "age": 31,
+ "name": "England Vance",
+ "gender": "male",
+ "company": "VOLAX",
+ "email": "englandvance@volax.com",
+ "phone": "+1 (840) 593-3417"
+ },
+ {
+ "_id": "55d2fc8671f3c1e30bee852f",
+ "age": 23,
+ "name": "Rodriguez Foreman",
+ "gender": "male",
+ "company": "EXTRAWEAR",
+ "email": "rodriguezforeman@extrawear.com",
+ "phone": "+1 (804) 497-2101"
+ },
+ {
+ "_id": "55d2fc86bea38e2b0cd970cb",
+ "age": 35,
+ "name": "Richard Garrett",
+ "gender": "male",
+ "company": "SUPREMIA",
+ "email": "richardgarrett@supremia.com",
+ "phone": "+1 (925) 461-3414"
+ },
+ {
+ "_id": "55d2fc862c5193ab7b4668b7",
+ "age": 40,
+ "name": "Connie Ortega",
+ "gender": "female",
+ "company": "ZILODYNE",
+ "email": "connieortega@zilodyne.com",
+ "phone": "+1 (838) 582-3241"
+ },
+ {
+ "_id": "55d2fc865a6b25d6bc09180e",
+ "age": 24,
+ "name": "Solomon Bates",
+ "gender": "male",
+ "company": "EXOSPACE",
+ "email": "solomonbates@exospace.com",
+ "phone": "+1 (897) 496-2243"
+ },
+ {
+ "_id": "55d2fc86a16a4e077136e4b5",
+ "age": 32,
+ "name": "Valencia Andrews",
+ "gender": "male",
+ "company": "NORSUP",
+ "email": "valenciaandrews@norsup.com",
+ "phone": "+1 (891) 503-3593"
+ },
+ {
+ "_id": "55d2fc86bc5f1bf697a90465",
+ "age": 24,
+ "name": "Briggs Vasquez",
+ "gender": "male",
+ "company": "ZENTIA",
+ "email": "briggsvasquez@zentia.com",
+ "phone": "+1 (802) 415-3377"
+ },
+ {
+ "_id": "55d2fc86c088d6466d83f8fc",
+ "age": 26,
+ "name": "Hester Rice",
+ "gender": "female",
+ "company": "CYTREK",
+ "email": "hesterrice@cytrek.com",
+ "phone": "+1 (855) 544-3905"
+ },
+ {
+ "_id": "55d2fc8622fc3e78977288af",
+ "age": 25,
+ "name": "Shelly Hendrix",
+ "gender": "female",
+ "company": "POWERNET",
+ "email": "shellyhendrix@powernet.com",
+ "phone": "+1 (912) 431-2318"
+ },
+ {
+ "_id": "55d2fc862cdec6cd321df6e0",
+ "age": 22,
+ "name": "Alison Newman",
+ "gender": "female",
+ "company": "COMTOUR",
+ "email": "alisonnewman@comtour.com",
+ "phone": "+1 (836) 582-3513"
+ },
+ {
+ "_id": "55d2fc86e0070d54d4712ca4",
+ "age": 30,
+ "name": "French Rivera",
+ "gender": "male",
+ "company": "ACUMENTOR",
+ "email": "frenchrivera@acumentor.com",
+ "phone": "+1 (902) 579-2193"
+ },
+ {
+ "_id": "55d2fc860f64b4423a9d6ffc",
+ "age": 38,
+ "name": "Terrell Mendez",
+ "gender": "male",
+ "company": "IMAGINART",
+ "email": "terrellmendez@imaginart.com",
+ "phone": "+1 (967) 494-2713"
+ },
+ {
+ "_id": "55d2fc86548793116b225b3b",
+ "age": 30,
+ "name": "Parsons Robertson",
+ "gender": "male",
+ "company": "OBONES",
+ "email": "parsonsrobertson@obones.com",
+ "phone": "+1 (984) 434-2810"
+ },
+ {
+ "_id": "55d2fc865b8b0d6a59db876c",
+ "age": 33,
+ "name": "Livingston Barry",
+ "gender": "male",
+ "company": "TYPHONICA",
+ "email": "livingstonbarry@typhonica.com",
+ "phone": "+1 (976) 560-3878"
+ },
+ {
+ "_id": "55d2fc865ce23fb8b34cae53",
+ "age": 40,
+ "name": "Valeria Stout",
+ "gender": "female",
+ "company": "AVENETRO",
+ "email": "valeriastout@avenetro.com",
+ "phone": "+1 (885) 557-3624"
+ },
+ {
+ "_id": "55d2fc86c03ea1d6e81563ac",
+ "age": 39,
+ "name": "Grimes Dyer",
+ "gender": "male",
+ "company": "GEOLOGIX",
+ "email": "grimesdyer@geologix.com",
+ "phone": "+1 (896) 533-2919"
+ },
+ {
+ "_id": "55d2fc8655c0acb356a06c8f",
+ "age": 29,
+ "name": "Higgins Short",
+ "gender": "male",
+ "company": "BICOL",
+ "email": "higginsshort@bicol.com",
+ "phone": "+1 (976) 444-3073"
+ },
+ {
+ "_id": "55d2fc865b6db005487c52bb",
+ "age": 34,
+ "name": "Gilmore Campos",
+ "gender": "male",
+ "company": "PASTURIA",
+ "email": "gilmorecampos@pasturia.com",
+ "phone": "+1 (862) 442-2147"
+ },
+ {
+ "_id": "55d2fc863df4791bcb269217",
+ "age": 29,
+ "name": "Sloan Kane",
+ "gender": "male",
+ "company": "XELEGYL",
+ "email": "sloankane@xelegyl.com",
+ "phone": "+1 (946) 526-2275"
+ },
+ {
+ "_id": "55d2fc86b2eb7dedbd5a9e8d",
+ "age": 26,
+ "name": "Mcpherson Thornton",
+ "gender": "male",
+ "company": "KAGE",
+ "email": "mcphersonthornton@kage.com",
+ "phone": "+1 (803) 478-2690"
+ },
+ {
+ "_id": "55d2fc8603f6a8c17148c8dd",
+ "age": 31,
+ "name": "Christi Welch",
+ "gender": "female",
+ "company": "WARETEL",
+ "email": "christiwelch@waretel.com",
+ "phone": "+1 (999) 552-3114"
+ },
+ {
+ "_id": "55d2fc86118d83cb9d06aa2e",
+ "age": 29,
+ "name": "Padilla Travis",
+ "gender": "male",
+ "company": "ENERVATE",
+ "email": "padillatravis@enervate.com",
+ "phone": "+1 (897) 577-3387"
+ },
+ {
+ "_id": "55d2fc86aba06801708bed65",
+ "age": 22,
+ "name": "Stanton Casey",
+ "gender": "male",
+ "company": "BUZZMAKER",
+ "email": "stantoncasey@buzzmaker.com",
+ "phone": "+1 (858) 571-2667"
+ },
+ {
+ "_id": "55d2fc86184810b00043a4b7",
+ "age": 29,
+ "name": "Krista Hernandez",
+ "gender": "female",
+ "company": "BIOHAB",
+ "email": "kristahernandez@biohab.com",
+ "phone": "+1 (832) 510-3654"
+ },
+ {
+ "_id": "55d2fc86e9c951b5bcea3938",
+ "age": 36,
+ "name": "Deleon Oliver",
+ "gender": "male",
+ "company": "NETBOOK",
+ "email": "deleonoliver@netbook.com",
+ "phone": "+1 (934) 504-2964"
+ },
+ {
+ "_id": "55d2fc86923000f3ea91ae38",
+ "age": 36,
+ "name": "Vasquez Fowler",
+ "gender": "male",
+ "company": "ORGANICA",
+ "email": "vasquezfowler@organica.com",
+ "phone": "+1 (949) 546-2722"
+ },
+ {
+ "_id": "55d2fc861e12cd0fa6207a9e",
+ "age": 33,
+ "name": "Rutledge Keith",
+ "gender": "male",
+ "company": "COLAIRE",
+ "email": "rutledgekeith@colaire.com",
+ "phone": "+1 (936) 472-3739"
+ },
+ {
+ "_id": "55d2fc86927eca39ef0c7ae9",
+ "age": 26,
+ "name": "Kirsten Valenzuela",
+ "gender": "female",
+ "company": "SEQUITUR",
+ "email": "kirstenvalenzuela@sequitur.com",
+ "phone": "+1 (958) 564-3259"
+ },
+ {
+ "_id": "55d2fc869e922239ce293d2c",
+ "age": 40,
+ "name": "Garza Gutierrez",
+ "gender": "male",
+ "company": "SPLINX",
+ "email": "garzagutierrez@splinx.com",
+ "phone": "+1 (850) 525-3114"
+ },
+ {
+ "_id": "55d2fc869dd88389d4785283",
+ "age": 27,
+ "name": "Shawna Peck",
+ "gender": "female",
+ "company": "UNQ",
+ "email": "shawnapeck@unq.com",
+ "phone": "+1 (961) 579-3704"
+ },
+ {
+ "_id": "55d2fc86722d8e2a714bf7f2",
+ "age": 23,
+ "name": "Aurelia Mcpherson",
+ "gender": "female",
+ "company": "BOINK",
+ "email": "aureliamcpherson@boink.com",
+ "phone": "+1 (946) 479-2080"
+ },
+ {
+ "_id": "55d2fc862324d173c26dfc68",
+ "age": 39,
+ "name": "Maryellen Daugherty",
+ "gender": "female",
+ "company": "ZILCH",
+ "email": "maryellendaugherty@zilch.com",
+ "phone": "+1 (817) 577-3290"
+ },
+ {
+ "_id": "55d2fc86d311107f869da748",
+ "age": 35,
+ "name": "Zelma Hancock",
+ "gender": "female",
+ "company": "EVENTAGE",
+ "email": "zelmahancock@eventage.com",
+ "phone": "+1 (845) 578-3887"
+ },
+ {
+ "_id": "55d2fc86afb4ede1f20a6d15",
+ "age": 34,
+ "name": "Tessa Adkins",
+ "gender": "female",
+ "company": "CONJURICA",
+ "email": "tessaadkins@conjurica.com",
+ "phone": "+1 (807) 497-2845"
+ },
+ {
+ "_id": "55d2fc8648a2e36d6f97fad1",
+ "age": 22,
+ "name": "Wong Shaffer",
+ "gender": "male",
+ "company": "ACCUFARM",
+ "email": "wongshaffer@accufarm.com",
+ "phone": "+1 (865) 589-3833"
+ },
+ {
+ "_id": "55d2fc86c4c10d58f1fe357f",
+ "age": 32,
+ "name": "Ivy Suarez",
+ "gender": "female",
+ "company": "UNCORP",
+ "email": "ivysuarez@uncorp.com",
+ "phone": "+1 (851) 582-2829"
+ },
+ {
+ "_id": "55d2fc867c11d1885ca4d8f9",
+ "age": 25,
+ "name": "Sosa Barber",
+ "gender": "male",
+ "company": "FUELTON",
+ "email": "sosabarber@fuelton.com",
+ "phone": "+1 (831) 404-2343"
+ },
+ {
+ "_id": "55d2fc866405b373cff4d477",
+ "age": 23,
+ "name": "Rosalind Craft",
+ "gender": "female",
+ "company": "OTHERSIDE",
+ "email": "rosalindcraft@otherside.com",
+ "phone": "+1 (847) 455-2079"
+ },
+ {
+ "_id": "55d2fc863a038b06c712b4b9",
+ "age": 30,
+ "name": "Bean Mathis",
+ "gender": "male",
+ "company": "QUILK",
+ "email": "beanmathis@quilk.com",
+ "phone": "+1 (974) 596-2868"
+ },
+ {
+ "_id": "55d2fc86922e4a50dfef56ac",
+ "age": 21,
+ "name": "Kelley Ruiz",
+ "gender": "female",
+ "company": "APEX",
+ "email": "kelleyruiz@apex.com",
+ "phone": "+1 (889) 522-2938"
+ },
+ {
+ "_id": "55d2fc868c7bf8c05a228366",
+ "age": 22,
+ "name": "Georgette Chaney",
+ "gender": "female",
+ "company": "EXOTECHNO",
+ "email": "georgettechaney@exotechno.com",
+ "phone": "+1 (920) 591-3934"
+ },
+ {
+ "_id": "55d2fc86988c5be0c8ba5412",
+ "age": 38,
+ "name": "Tami Bullock",
+ "gender": "female",
+ "company": "ISOTRONIC",
+ "email": "tamibullock@isotronic.com",
+ "phone": "+1 (828) 567-2857"
+ },
+ {
+ "_id": "55d2fc862264a1d2de2e8a6b",
+ "age": 39,
+ "name": "Castillo Rosario",
+ "gender": "male",
+ "company": "KONNECT",
+ "email": "castillorosario@konnect.com",
+ "phone": "+1 (938) 402-3484"
+ },
+ {
+ "_id": "55d2fc8622ee680ff3c522e1",
+ "age": 31,
+ "name": "George Weber",
+ "gender": "male",
+ "company": "FARMAGE",
+ "email": "georgeweber@farmage.com",
+ "phone": "+1 (895) 502-2654"
+ },
+ {
+ "_id": "55d2fc86a0d45d2916aacb5a",
+ "age": 28,
+ "name": "Wheeler Villarreal",
+ "gender": "male",
+ "company": "IMPERIUM",
+ "email": "wheelervillarreal@imperium.com",
+ "phone": "+1 (889) 507-3796"
+ },
+ {
+ "_id": "55d2fc866c6e8e85c17c61ca",
+ "age": 36,
+ "name": "Arlene Bean",
+ "gender": "female",
+ "company": "UNIA",
+ "email": "arlenebean@unia.com",
+ "phone": "+1 (970) 463-2147"
+ },
+ {
+ "_id": "55d2fc86c3c95fd98562a429",
+ "age": 30,
+ "name": "Oneil Madden",
+ "gender": "male",
+ "company": "COMBOGENE",
+ "email": "oneilmadden@combogene.com",
+ "phone": "+1 (849) 507-3555"
+ },
+ {
+ "_id": "55d2fc86b0f7cc31af45078a",
+ "age": 35,
+ "name": "Vaughn Merritt",
+ "gender": "male",
+ "company": "ACCUPHARM",
+ "email": "vaughnmerritt@accupharm.com",
+ "phone": "+1 (886) 428-2966"
+ },
+ {
+ "_id": "55d2fc86ad825cb66f2a2feb",
+ "age": 21,
+ "name": "Duran Bradford",
+ "gender": "male",
+ "company": "SQUISH",
+ "email": "duranbradford@squish.com",
+ "phone": "+1 (930) 434-2976"
+ },
+ {
+ "_id": "55d2fc86efa80c332066194d",
+ "age": 30,
+ "name": "Tanisha Knox",
+ "gender": "female",
+ "company": "FARMEX",
+ "email": "tanishaknox@farmex.com",
+ "phone": "+1 (924) 540-2066"
+ },
+ {
+ "_id": "55d2fc861dbd55c1fd4bdf23",
+ "age": 38,
+ "name": "Esther Foster",
+ "gender": "female",
+ "company": "SENSATE",
+ "email": "estherfoster@sensate.com",
+ "phone": "+1 (812) 417-2687"
+ },
+ {
+ "_id": "55d2fc86115b9a01067db6ad",
+ "age": 35,
+ "name": "Marion Gray",
+ "gender": "female",
+ "company": "HINWAY",
+ "email": "mariongray@hinway.com",
+ "phone": "+1 (850) 526-2167"
+ },
+ {
+ "_id": "55d2fc864b40086c2e4963e2",
+ "age": 38,
+ "name": "Ava Flowers",
+ "gender": "female",
+ "company": "REVERSUS",
+ "email": "avaflowers@reversus.com",
+ "phone": "+1 (989) 415-2504"
+ },
+ {
+ "_id": "55d2fc8686c59f7395222b11",
+ "age": 35,
+ "name": "Katina Burnett",
+ "gender": "female",
+ "company": "DUFLEX",
+ "email": "katinaburnett@duflex.com",
+ "phone": "+1 (843) 464-3718"
+ },
+ {
+ "_id": "55d2fc86e012c977bc5b57d6",
+ "age": 37,
+ "name": "Ester Cooley",
+ "gender": "female",
+ "company": "RUBADUB",
+ "email": "estercooley@rubadub.com",
+ "phone": "+1 (856) 407-3009"
+ },
+ {
+ "_id": "55d2fc865688875c75a158b5",
+ "age": 36,
+ "name": "Dennis Mccray",
+ "gender": "male",
+ "company": "PETIGEMS",
+ "email": "dennismccray@petigems.com",
+ "phone": "+1 (989) 525-3768"
+ },
+ {
+ "_id": "55d2fc86ca333a1c715a35c7",
+ "age": 25,
+ "name": "Mitzi Carson",
+ "gender": "female",
+ "company": "KENEGY",
+ "email": "mitzicarson@kenegy.com",
+ "phone": "+1 (819) 450-2923"
+ },
+ {
+ "_id": "55d2fc86a8eb68257312e735",
+ "age": 33,
+ "name": "Guthrie Tyson",
+ "gender": "male",
+ "company": "GLUID",
+ "email": "guthrietyson@gluid.com",
+ "phone": "+1 (878) 496-3831"
+ },
+ {
+ "_id": "55d2fc865d4f3b3777fc1573",
+ "age": 38,
+ "name": "Sellers Hodges",
+ "gender": "male",
+ "company": "BALOOBA",
+ "email": "sellershodges@balooba.com",
+ "phone": "+1 (895) 557-2331"
+ },
+ {
+ "_id": "55d2fc860a91cf55298e2a24",
+ "age": 32,
+ "name": "Hawkins Hardin",
+ "gender": "male",
+ "company": "ZILLANET",
+ "email": "hawkinshardin@zillanet.com",
+ "phone": "+1 (852) 511-2796"
+ },
+ {
+ "_id": "55d2fc867b1c618fcb9cb2c3",
+ "age": 26,
+ "name": "Bowman Buck",
+ "gender": "male",
+ "company": "APPLIDEC",
+ "email": "bowmanbuck@applidec.com",
+ "phone": "+1 (995) 500-2863"
+ },
+ {
+ "_id": "55d2fc8666610d156551484b",
+ "age": 23,
+ "name": "Mcgee Delgado",
+ "gender": "male",
+ "company": "MANTRO",
+ "email": "mcgeedelgado@mantro.com",
+ "phone": "+1 (917) 490-2295"
+ },
+ {
+ "_id": "55d2fc8685385c63f5a509b3",
+ "age": 24,
+ "name": "Petty Pena",
+ "gender": "male",
+ "company": "EXOSPEED",
+ "email": "pettypena@exospeed.com",
+ "phone": "+1 (929) 470-2022"
+ },
+ {
+ "_id": "55d2fc864296df53bb778e52",
+ "age": 38,
+ "name": "Ray Mclaughlin",
+ "gender": "male",
+ "company": "PYRAMAX",
+ "email": "raymclaughlin@pyramax.com",
+ "phone": "+1 (935) 453-3720"
+ },
+ {
+ "_id": "55d2fc86b157acc34692412b",
+ "age": 22,
+ "name": "Hopkins Wells",
+ "gender": "male",
+ "company": "NORALEX",
+ "email": "hopkinswells@noralex.com",
+ "phone": "+1 (986) 421-2293"
+ },
+ {
+ "_id": "55d2fc861febd65bb3c91219",
+ "age": 38,
+ "name": "Patsy Strickland",
+ "gender": "female",
+ "company": "POLARIA",
+ "email": "patsystrickland@polaria.com",
+ "phone": "+1 (885) 408-2213"
+ },
+ {
+ "_id": "55d2fc8693fbc24aa2bcc5a8",
+ "age": 31,
+ "name": "Wolf Delaney",
+ "gender": "male",
+ "company": "EXERTA",
+ "email": "wolfdelaney@exerta.com",
+ "phone": "+1 (969) 537-3201"
+ },
+ {
+ "_id": "55d2fc86b923e0543d39fed4",
+ "age": 30,
+ "name": "Fulton Hewitt",
+ "gender": "male",
+ "company": "TWIGGERY",
+ "email": "fultonhewitt@twiggery.com",
+ "phone": "+1 (894) 483-2549"
+ },
+ {
+ "_id": "55d2fc8672aff3d2369b2749",
+ "age": 40,
+ "name": "Nona Meadows",
+ "gender": "female",
+ "company": "ULTRIMAX",
+ "email": "nonameadows@ultrimax.com",
+ "phone": "+1 (997) 459-2012"
+ },
+ {
+ "_id": "55d2fc86a3b6922e61cdcd72",
+ "age": 24,
+ "name": "Irwin Russo",
+ "gender": "male",
+ "company": "QUINTITY",
+ "email": "irwinrusso@quintity.com",
+ "phone": "+1 (985) 597-3841"
+ },
+ {
+ "_id": "55d2fc86c28f4a90a41581b7",
+ "age": 34,
+ "name": "Mara Bowman",
+ "gender": "female",
+ "company": "ATOMICA",
+ "email": "marabowman@atomica.com",
+ "phone": "+1 (927) 578-2958"
+ },
+ {
+ "_id": "55d2fc86ef827e1bbb5b3ceb",
+ "age": 40,
+ "name": "Leigh Schroeder",
+ "gender": "female",
+ "company": "ZIORE",
+ "email": "leighschroeder@ziore.com",
+ "phone": "+1 (963) 484-2519"
+ },
+ {
+ "_id": "55d2fc86921329e8e044472a",
+ "age": 27,
+ "name": "Sweeney Riddle",
+ "gender": "male",
+ "company": "ELITA",
+ "email": "sweeneyriddle@elita.com",
+ "phone": "+1 (974) 536-2132"
+ },
+ {
+ "_id": "55d2fc864b6067f7d828f1ba",
+ "age": 23,
+ "name": "Bell Kline",
+ "gender": "male",
+ "company": "ORBOID",
+ "email": "bellkline@orboid.com",
+ "phone": "+1 (827) 461-3466"
+ },
+ {
+ "_id": "55d2fc86a541995fa67027ae",
+ "age": 20,
+ "name": "Morgan Aguirre",
+ "gender": "female",
+ "company": "AEORA",
+ "email": "morganaguirre@aeora.com",
+ "phone": "+1 (987) 494-2357"
+ },
+ {
+ "_id": "55d2fc86af8d98e486bda0f5",
+ "age": 24,
+ "name": "Morrison Mcbride",
+ "gender": "male",
+ "company": "TECHMANIA",
+ "email": "morrisonmcbride@techmania.com",
+ "phone": "+1 (994) 470-2394"
+ },
+ {
+ "_id": "55d2fc86371a2691da434cdd",
+ "age": 22,
+ "name": "Miles Salinas",
+ "gender": "male",
+ "company": "RODEOLOGY",
+ "email": "milessalinas@rodeology.com",
+ "phone": "+1 (898) 461-3008"
+ },
+ {
+ "_id": "55d2fc865196aa926884d957",
+ "age": 36,
+ "name": "Lang Riggs",
+ "gender": "male",
+ "company": "PHOTOBIN",
+ "email": "langriggs@photobin.com",
+ "phone": "+1 (849) 503-2335"
+ },
+ {
+ "_id": "55d2fc86b4e30cd686840e28",
+ "age": 30,
+ "name": "Kathy Phelps",
+ "gender": "female",
+ "company": "INTRAWEAR",
+ "email": "kathyphelps@intrawear.com",
+ "phone": "+1 (992) 499-2474"
+ },
+ {
+ "_id": "55d2fc86f09accb089f91415",
+ "age": 24,
+ "name": "Moss Jimenez",
+ "gender": "male",
+ "company": "PROFLEX",
+ "email": "mossjimenez@proflex.com",
+ "phone": "+1 (842) 546-3491"
+ },
+ {
+ "_id": "55d2fc86e3ba881a25584928",
+ "age": 20,
+ "name": "Moody Sexton",
+ "gender": "male",
+ "company": "CENTREGY",
+ "email": "moodysexton@centregy.com",
+ "phone": "+1 (856) 581-3293"
+ },
+ {
+ "_id": "55d2fc861c85cf26c6d21a64",
+ "age": 31,
+ "name": "Nannie Price",
+ "gender": "female",
+ "company": "GEOSTELE",
+ "email": "nannieprice@geostele.com",
+ "phone": "+1 (936) 447-3486"
+ },
+ {
+ "_id": "55d2fc86f1e23452254fda91",
+ "age": 32,
+ "name": "Summer Johnston",
+ "gender": "female",
+ "company": "EXTRAGENE",
+ "email": "summerjohnston@extragene.com",
+ "phone": "+1 (808) 508-2748"
+ },
+ {
+ "_id": "55d2fc86940fcc0f17d5f213",
+ "age": 24,
+ "name": "Genevieve Lynch",
+ "gender": "female",
+ "company": "COREPAN",
+ "email": "genevievelynch@corepan.com",
+ "phone": "+1 (921) 532-2893"
+ },
+ {
+ "_id": "55d2fc86cdf6056cd058466c",
+ "age": 23,
+ "name": "Stuart Oconnor",
+ "gender": "male",
+ "company": "PUSHCART",
+ "email": "stuartoconnor@pushcart.com",
+ "phone": "+1 (925) 515-3434"
+ },
+ {
+ "_id": "55d2fc863bca896e3e2ac1a7",
+ "age": 21,
+ "name": "Adela Nieves",
+ "gender": "female",
+ "company": "MEDICROIX",
+ "email": "adelanieves@medicroix.com",
+ "phone": "+1 (910) 568-3916"
+ },
+ {
+ "_id": "55d2fc86826d7c7fcfc2562e",
+ "age": 28,
+ "name": "Eaton Mcintosh",
+ "gender": "male",
+ "company": "MEGALL",
+ "email": "eatonmcintosh@megall.com",
+ "phone": "+1 (806) 440-2196"
+ },
+ {
+ "_id": "55d2fc863d76c0458de8afb2",
+ "age": 35,
+ "name": "Sharron Hood",
+ "gender": "female",
+ "company": "UTARIAN",
+ "email": "sharronhood@utarian.com",
+ "phone": "+1 (824) 477-3364"
+ },
+ {
+ "_id": "55d2fc86c0f317fe0cdd6f66",
+ "age": 24,
+ "name": "Allison Osborn",
+ "gender": "female",
+ "company": "TUBALUM",
+ "email": "allisonosborn@tubalum.com",
+ "phone": "+1 (913) 546-3966"
+ },
+ {
+ "_id": "55d2fc86e1521a5a9896e0fa",
+ "age": 38,
+ "name": "Chelsea Jarvis",
+ "gender": "female",
+ "company": "SOPRANO",
+ "email": "chelseajarvis@soprano.com",
+ "phone": "+1 (834) 417-2904"
+ },
+ {
+ "_id": "55d2fc86a5f4df72a31c9201",
+ "age": 22,
+ "name": "Finley Freeman",
+ "gender": "male",
+ "company": "COMBOT",
+ "email": "finleyfreeman@combot.com",
+ "phone": "+1 (886) 448-2820"
+ },
+ {
+ "_id": "55d2fc86c4c2c783570c50eb",
+ "age": 31,
+ "name": "Lynn Miles",
+ "gender": "female",
+ "company": "ZENTIX",
+ "email": "lynnmiles@zentix.com",
+ "phone": "+1 (891) 450-2505"
+ },
+ {
+ "_id": "55d2fc863e649b4a99367f40",
+ "age": 39,
+ "name": "Montoya Greene",
+ "gender": "male",
+ "company": "MEMORA",
+ "email": "montoyagreene@memora.com",
+ "phone": "+1 (809) 402-3541"
+ },
+ {
+ "_id": "55d2fc86b82e96b2275df9f3",
+ "age": 28,
+ "name": "Castro Huff",
+ "gender": "male",
+ "company": "BLUPLANET",
+ "email": "castrohuff@bluplanet.com",
+ "phone": "+1 (966) 554-2469"
+ },
+ {
+ "_id": "55d2fc86f4a8a7700a99e31c",
+ "age": 23,
+ "name": "Guadalupe Harmon",
+ "gender": "female",
+ "company": "ISOLOGIA",
+ "email": "guadalupeharmon@isologia.com",
+ "phone": "+1 (937) 497-2022"
+ },
+ {
+ "_id": "55d2fc86551e7044f31f2520",
+ "age": 25,
+ "name": "Heidi Navarro",
+ "gender": "female",
+ "company": "POLARIUM",
+ "email": "heidinavarro@polarium.com",
+ "phone": "+1 (830) 493-3328"
+ },
+ {
+ "_id": "55d2fc861ee43e4303351a4b",
+ "age": 25,
+ "name": "Fry Webster",
+ "gender": "male",
+ "company": "RENOVIZE",
+ "email": "frywebster@renovize.com",
+ "phone": "+1 (960) 600-3488"
+ },
+ {
+ "_id": "55d2fc86e0d6778a1c6d7195",
+ "age": 35,
+ "name": "Candice Sharpe",
+ "gender": "female",
+ "company": "UNDERTAP",
+ "email": "candicesharpe@undertap.com",
+ "phone": "+1 (989) 436-2856"
+ },
+ {
+ "_id": "55d2fc86267005541d225276",
+ "age": 25,
+ "name": "Vonda Hansen",
+ "gender": "female",
+ "company": "PROVIDCO",
+ "email": "vondahansen@providco.com",
+ "phone": "+1 (883) 484-2047"
+ },
+ {
+ "_id": "55d2fc8605000bc9329d28e0",
+ "age": 21,
+ "name": "Lara Dominguez",
+ "gender": "male",
+ "company": "VIXO",
+ "email": "laradominguez@vixo.com",
+ "phone": "+1 (998) 440-3632"
+ },
+ {
+ "_id": "55d2fc868b364833d935b192",
+ "age": 36,
+ "name": "Jillian Gibbs",
+ "gender": "female",
+ "company": "CUIZINE",
+ "email": "jilliangibbs@cuizine.com",
+ "phone": "+1 (996) 447-3083"
+ },
+ {
+ "_id": "55d2fc863690a0784d2e8bc1",
+ "age": 35,
+ "name": "Frankie Cervantes",
+ "gender": "female",
+ "company": "ISODRIVE",
+ "email": "frankiecervantes@isodrive.com",
+ "phone": "+1 (895) 533-2371"
+ },
+ {
+ "_id": "55d2fc86efb91d645101592f",
+ "age": 36,
+ "name": "Nieves Walton",
+ "gender": "male",
+ "company": "ZILPHUR",
+ "email": "nieveswalton@zilphur.com",
+ "phone": "+1 (866) 412-2377"
+ },
+ {
+ "_id": "55d2fc86cba2fb0dfd9eb8c3",
+ "age": 38,
+ "name": "Celina Orr",
+ "gender": "female",
+ "company": "COMVEX",
+ "email": "celinaorr@comvex.com",
+ "phone": "+1 (960) 433-2380"
+ },
+ {
+ "_id": "55d2fc8650eaf118ae048bce",
+ "age": 33,
+ "name": "Moreno Conway",
+ "gender": "male",
+ "company": "VIOCULAR",
+ "email": "morenoconway@viocular.com",
+ "phone": "+1 (808) 535-2624"
+ },
+ {
+ "_id": "55d2fc860e41c77df0ea1151",
+ "age": 33,
+ "name": "Wilkerson Dodson",
+ "gender": "male",
+ "company": "COMTRAK",
+ "email": "wilkersondodson@comtrak.com",
+ "phone": "+1 (932) 427-2400"
+ },
+ {
+ "_id": "55d2fc86175167613833c577",
+ "age": 21,
+ "name": "Crane Lloyd",
+ "gender": "male",
+ "company": "ARCHITAX",
+ "email": "cranelloyd@architax.com",
+ "phone": "+1 (984) 467-3498"
+ },
+ {
+ "_id": "55d2fc863aa593013e09d04b",
+ "age": 25,
+ "name": "Marguerite Dorsey",
+ "gender": "female",
+ "company": "UNI",
+ "email": "margueritedorsey@uni.com",
+ "phone": "+1 (989) 558-2105"
+ },
+ {
+ "_id": "55d2fc86248902726f0d1c53",
+ "age": 35,
+ "name": "Dillon William",
+ "gender": "male",
+ "company": "ROOFORIA",
+ "email": "dillonwilliam@rooforia.com",
+ "phone": "+1 (879) 600-3589"
+ },
+ {
+ "_id": "55d2fc86caa1b7374cd83a72",
+ "age": 32,
+ "name": "Small Floyd",
+ "gender": "male",
+ "company": "ANACHO",
+ "email": "smallfloyd@anacho.com",
+ "phone": "+1 (906) 463-2357"
+ },
+ {
+ "_id": "55d2fc86c086267c74616688",
+ "age": 32,
+ "name": "Dominique Horn",
+ "gender": "female",
+ "company": "ENTOGROK",
+ "email": "dominiquehorn@entogrok.com",
+ "phone": "+1 (871) 556-2943"
+ },
+ {
+ "_id": "55d2fc86d3f7731c49d48fa7",
+ "age": 35,
+ "name": "Haley Shannon",
+ "gender": "female",
+ "company": "UNEEQ",
+ "email": "haleyshannon@uneeq.com",
+ "phone": "+1 (984) 471-3688"
+ },
+ {
+ "_id": "55d2fc8678e81807871b2b13",
+ "age": 24,
+ "name": "Flowers Richards",
+ "gender": "male",
+ "company": "QUILITY",
+ "email": "flowersrichards@quility.com",
+ "phone": "+1 (956) 548-3667"
+ },
+ {
+ "_id": "55d2fc86b4b462a2743c10d3",
+ "age": 33,
+ "name": "Hopper Rush",
+ "gender": "male",
+ "company": "VERBUS",
+ "email": "hopperrush@verbus.com",
+ "phone": "+1 (866) 578-2948"
+ },
+ {
+ "_id": "55d2fc86d660e6f5bf9c1ce1",
+ "age": 31,
+ "name": "Randall Kelley",
+ "gender": "male",
+ "company": "INSURON",
+ "email": "randallkelley@insuron.com",
+ "phone": "+1 (922) 520-3464"
+ },
+ {
+ "_id": "55d2fc86e70ad03e58c3e01f",
+ "age": 36,
+ "name": "Owens Drake",
+ "gender": "male",
+ "company": "FROLIX",
+ "email": "owensdrake@frolix.com",
+ "phone": "+1 (982) 516-3575"
+ },
+ {
+ "_id": "55d2fc86ef78c8ad566afe4f",
+ "age": 28,
+ "name": "Irma Garrison",
+ "gender": "female",
+ "company": "EXOZENT",
+ "email": "irmagarrison@exozent.com",
+ "phone": "+1 (882) 536-2614"
+ },
+ {
+ "_id": "55d2fc8675d6b4b33c5e482f",
+ "age": 34,
+ "name": "Baldwin Carver",
+ "gender": "male",
+ "company": "PHEAST",
+ "email": "baldwincarver@pheast.com",
+ "phone": "+1 (824) 521-2892"
+ },
+ {
+ "_id": "55d2fc86d382b214a715305f",
+ "age": 23,
+ "name": "Short Harding",
+ "gender": "male",
+ "company": "LIQUICOM",
+ "email": "shortharding@liquicom.com",
+ "phone": "+1 (836) 578-2063"
+ },
+ {
+ "_id": "55d2fc860420ee3ca95e2166",
+ "age": 35,
+ "name": "Christy Roberson",
+ "gender": "female",
+ "company": "BITREX",
+ "email": "christyroberson@bitrex.com",
+ "phone": "+1 (840) 426-2954"
+ },
+ {
+ "_id": "55d2fc86dd67ce4e4f7b6d0c",
+ "age": 21,
+ "name": "Fern Knight",
+ "gender": "female",
+ "company": "ENTROPIX",
+ "email": "fernknight@entropix.com",
+ "phone": "+1 (944) 546-2456"
+ },
+ {
+ "_id": "55d2fc8651510fb366709f12",
+ "age": 40,
+ "name": "Elva Taylor",
+ "gender": "female",
+ "company": "COMFIRM",
+ "email": "elvataylor@comfirm.com",
+ "phone": "+1 (834) 468-2999"
+ },
+ {
+ "_id": "55d2fc869603515857919a7c",
+ "age": 26,
+ "name": "Carmen Bentley",
+ "gender": "female",
+ "company": "LIMAGE",
+ "email": "carmenbentley@limage.com",
+ "phone": "+1 (882) 425-3588"
+ },
+ {
+ "_id": "55d2fc860991d6904808f8b3",
+ "age": 28,
+ "name": "Blair Dunn",
+ "gender": "male",
+ "company": "ESSENSIA",
+ "email": "blairdunn@essensia.com",
+ "phone": "+1 (896) 477-2617"
+ },
+ {
+ "_id": "55d2fc862c99e4fefd17ab8d",
+ "age": 23,
+ "name": "Minerva Swanson",
+ "gender": "female",
+ "company": "EMTRAC",
+ "email": "minervaswanson@emtrac.com",
+ "phone": "+1 (905) 427-3942"
+ },
+ {
+ "_id": "55d2fc86a2b4277d171e6ed6",
+ "age": 40,
+ "name": "Alicia Lawrence",
+ "gender": "female",
+ "company": "CONCILITY",
+ "email": "alicialawrence@concility.com",
+ "phone": "+1 (903) 452-2010"
+ },
+ {
+ "_id": "55d2fc86f98eb74fe02a49f5",
+ "age": 33,
+ "name": "Bernice Fitzpatrick",
+ "gender": "female",
+ "company": "JASPER",
+ "email": "bernicefitzpatrick@jasper.com",
+ "phone": "+1 (987) 518-2248"
+ },
+ {
+ "_id": "55d2fc86070af0b0109b6a4c",
+ "age": 20,
+ "name": "Wilder Blackburn",
+ "gender": "male",
+ "company": "ZENTILITY",
+ "email": "wilderblackburn@zentility.com",
+ "phone": "+1 (921) 548-2995"
+ },
+ {
+ "_id": "55d2fc86249796ecd0b25829",
+ "age": 25,
+ "name": "Lambert Wilson",
+ "gender": "male",
+ "company": "ANIVET",
+ "email": "lambertwilson@anivet.com",
+ "phone": "+1 (920) 592-2261"
+ },
+ {
+ "_id": "55d2fc863c6bdb691f62bdf4",
+ "age": 24,
+ "name": "Cook Lee",
+ "gender": "male",
+ "company": "ZILLADYNE",
+ "email": "cooklee@zilladyne.com",
+ "phone": "+1 (812) 566-2988"
+ },
+ {
+ "_id": "55d2fc86cdeae66cf4fe6582",
+ "age": 29,
+ "name": "Karyn Horne",
+ "gender": "female",
+ "company": "OBLIQ",
+ "email": "karynhorne@obliq.com",
+ "phone": "+1 (909) 452-3599"
+ },
+ {
+ "_id": "55d2fc86bcbabc9eb159e1e4",
+ "age": 23,
+ "name": "Rowe Stokes",
+ "gender": "male",
+ "company": "ANDERSHUN",
+ "email": "rowestokes@andershun.com",
+ "phone": "+1 (948) 531-2335"
+ },
+ {
+ "_id": "55d2fc86a1b344b621d41baa",
+ "age": 27,
+ "name": "Gonzalez Merrill",
+ "gender": "male",
+ "company": "PLAYCE",
+ "email": "gonzalezmerrill@playce.com",
+ "phone": "+1 (989) 418-3057"
+ },
+ {
+ "_id": "55d2fc86300074c184103b47",
+ "age": 33,
+ "name": "Kathie Preston",
+ "gender": "female",
+ "company": "LUMBREX",
+ "email": "kathiepreston@lumbrex.com",
+ "phone": "+1 (911) 586-3177"
+ },
+ {
+ "_id": "55d2fc8646059e576c41ed1f",
+ "age": 26,
+ "name": "Antoinette Stevens",
+ "gender": "female",
+ "company": "APEXIA",
+ "email": "antoinettestevens@apexia.com",
+ "phone": "+1 (828) 597-3083"
+ },
+ {
+ "_id": "55d2fc86b5ec5743baacc091",
+ "age": 22,
+ "name": "Schmidt Morton",
+ "gender": "male",
+ "company": "NORSUL",
+ "email": "schmidtmorton@norsul.com",
+ "phone": "+1 (821) 530-2454"
+ },
+ {
+ "_id": "55d2fc86a521743243b01d2b",
+ "age": 37,
+ "name": "Joyner Wise",
+ "gender": "male",
+ "company": "MANGELICA",
+ "email": "joynerwise@mangelica.com",
+ "phone": "+1 (884) 448-3942"
+ },
+ {
+ "_id": "55d2fc86d7c827b5ded4027f",
+ "age": 22,
+ "name": "Carpenter Carey",
+ "gender": "male",
+ "company": "CENTICE",
+ "email": "carpentercarey@centice.com",
+ "phone": "+1 (823) 585-2581"
+ },
+ {
+ "_id": "55d2fc866866bf441f74abdf",
+ "age": 34,
+ "name": "Luz Hays",
+ "gender": "female",
+ "company": "KONGENE",
+ "email": "luzhays@kongene.com",
+ "phone": "+1 (999) 558-2282"
+ },
+ {
+ "_id": "55d2fc86af95d619737eccb7",
+ "age": 27,
+ "name": "Lesley Frye",
+ "gender": "female",
+ "company": "SUREMAX",
+ "email": "lesleyfrye@suremax.com",
+ "phone": "+1 (982) 485-2811"
+ },
+ {
+ "_id": "55d2fc86b41a0594552e4839",
+ "age": 31,
+ "name": "Jacqueline Ramsey",
+ "gender": "female",
+ "company": "LYRIA",
+ "email": "jacquelineramsey@lyria.com",
+ "phone": "+1 (961) 581-2500"
+ },
+ {
+ "_id": "55d2fc8682aa54548863d4b1",
+ "age": 31,
+ "name": "Ina Ford",
+ "gender": "female",
+ "company": "ENERSOL",
+ "email": "inaford@enersol.com",
+ "phone": "+1 (895) 514-3441"
+ },
+ {
+ "_id": "55d2fc866bc796d86ebd697b",
+ "age": 22,
+ "name": "Francisca Ashley",
+ "gender": "female",
+ "company": "SIGNIDYNE",
+ "email": "franciscaashley@signidyne.com",
+ "phone": "+1 (911) 566-2135"
+ },
+ {
+ "_id": "55d2fc868ccc122c6a517033",
+ "age": 34,
+ "name": "Morton Owen",
+ "gender": "male",
+ "company": "SHOPABOUT",
+ "email": "mortonowen@shopabout.com",
+ "phone": "+1 (932) 576-3821"
+ },
+ {
+ "_id": "55d2fc86751e661b56e6e3cd",
+ "age": 36,
+ "name": "Weber Manning",
+ "gender": "male",
+ "company": "CENTREE",
+ "email": "webermanning@centree.com",
+ "phone": "+1 (865) 582-3809"
+ },
+ {
+ "_id": "55d2fc8620b9766f76797a13",
+ "age": 37,
+ "name": "Edwards Steele",
+ "gender": "male",
+ "company": "KATAKANA",
+ "email": "edwardssteele@katakana.com",
+ "phone": "+1 (959) 402-3657"
+ },
+ {
+ "_id": "55d2fc860a13152e82b74839",
+ "age": 38,
+ "name": "Gabriela Boone",
+ "gender": "female",
+ "company": "OVOLO",
+ "email": "gabrielaboone@ovolo.com",
+ "phone": "+1 (910) 587-2744"
+ },
+ {
+ "_id": "55d2fc864e9ca8a988600768",
+ "age": 32,
+ "name": "Tricia Guy",
+ "gender": "female",
+ "company": "TALKOLA",
+ "email": "triciaguy@talkola.com",
+ "phone": "+1 (960) 474-3508"
+ },
+ {
+ "_id": "55d2fc86ce61b77671fd1f33",
+ "age": 32,
+ "name": "James Romero",
+ "gender": "female",
+ "company": "CANDECOR",
+ "email": "jamesromero@candecor.com",
+ "phone": "+1 (928) 478-3272"
+ },
+ {
+ "_id": "55d2fc86f3cc105e20a44aa9",
+ "age": 25,
+ "name": "Casey Hammond",
+ "gender": "male",
+ "company": "PYRAMIA",
+ "email": "caseyhammond@pyramia.com",
+ "phone": "+1 (965) 539-2923"
+ },
+ {
+ "_id": "55d2fc86429d859d9e54585f",
+ "age": 33,
+ "name": "Moran Wade",
+ "gender": "male",
+ "company": "BUGSALL",
+ "email": "moranwade@bugsall.com",
+ "phone": "+1 (996) 559-2965"
+ },
+ {
+ "_id": "55d2fc86820b562eff651ebc",
+ "age": 34,
+ "name": "Earline Goff",
+ "gender": "female",
+ "company": "DATAGENE",
+ "email": "earlinegoff@datagene.com",
+ "phone": "+1 (976) 565-3513"
+ },
+ {
+ "_id": "55d2fc865f6176e8301edcf3",
+ "age": 38,
+ "name": "Vickie Cherry",
+ "gender": "female",
+ "company": "SILODYNE",
+ "email": "vickiecherry@silodyne.com",
+ "phone": "+1 (943) 522-2438"
+ },
+ {
+ "_id": "55d2fc8633cb19840995984c",
+ "age": 30,
+ "name": "Yates Avery",
+ "gender": "male",
+ "company": "DIGINETIC",
+ "email": "yatesavery@diginetic.com",
+ "phone": "+1 (813) 587-3611"
+ },
+ {
+ "_id": "55d2fc8677d1a1c749d498eb",
+ "age": 24,
+ "name": "Hodges Langley",
+ "gender": "male",
+ "company": "QUOTEZART",
+ "email": "hodgeslangley@quotezart.com",
+ "phone": "+1 (857) 496-3905"
+ },
+ {
+ "_id": "55d2fc86f49e5ceca6ff241d",
+ "age": 35,
+ "name": "Serrano Bartlett",
+ "gender": "male",
+ "company": "EXOSWITCH",
+ "email": "serranobartlett@exoswitch.com",
+ "phone": "+1 (809) 421-3677"
+ },
+ {
+ "_id": "55d2fc86cd4921dcf0316691",
+ "age": 28,
+ "name": "Faye Wood",
+ "gender": "female",
+ "company": "EXOTERIC",
+ "email": "fayewood@exoteric.com",
+ "phone": "+1 (840) 417-2329"
+ },
+ {
+ "_id": "55d2fc8697911f7ca9adfe37",
+ "age": 38,
+ "name": "Jamie Jennings",
+ "gender": "female",
+ "company": "SURETECH",
+ "email": "jamiejennings@suretech.com",
+ "phone": "+1 (945) 599-3768"
+ },
+ {
+ "_id": "55d2fc8614e0225c06b40348",
+ "age": 34,
+ "name": "Levy Sellers",
+ "gender": "male",
+ "company": "STELAECOR",
+ "email": "levysellers@stelaecor.com",
+ "phone": "+1 (805) 519-2578"
+ },
+ {
+ "_id": "55d2fc8635986d3994af8adc",
+ "age": 36,
+ "name": "Kelsey Montgomery",
+ "gender": "female",
+ "company": "IMANT",
+ "email": "kelseymontgomery@imant.com",
+ "phone": "+1 (894) 555-3420"
+ },
+ {
+ "_id": "55d2fc8624dfa620d7b8a991",
+ "age": 33,
+ "name": "Rush Gates",
+ "gender": "male",
+ "company": "DIGIAL",
+ "email": "rushgates@digial.com",
+ "phone": "+1 (891) 477-2651"
+ },
+ {
+ "_id": "55d2fc862d52fe806312e6dd",
+ "age": 40,
+ "name": "Holloway Gay",
+ "gender": "male",
+ "company": "EARTHMARK",
+ "email": "hollowaygay@earthmark.com",
+ "phone": "+1 (811) 540-3123"
+ },
+ {
+ "_id": "55d2fc86a168313cea778ac0",
+ "age": 20,
+ "name": "Cotton Jackson",
+ "gender": "male",
+ "company": "ZOLARITY",
+ "email": "cottonjackson@zolarity.com",
+ "phone": "+1 (980) 445-3468"
+ },
+ {
+ "_id": "55d2fc86577d2794043213ea",
+ "age": 38,
+ "name": "Lakeisha Blanchard",
+ "gender": "female",
+ "company": "SPEEDBOLT",
+ "email": "lakeishablanchard@speedbolt.com",
+ "phone": "+1 (839) 406-2400"
+ },
+ {
+ "_id": "55d2fc8609e2760d5cc298f1",
+ "age": 39,
+ "name": "Alford Church",
+ "gender": "male",
+ "company": "GADTRON",
+ "email": "alfordchurch@gadtron.com",
+ "phone": "+1 (869) 400-2097"
+ },
+ {
+ "_id": "55d2fc867e4a904c96668e08",
+ "age": 30,
+ "name": "Collins Carlson",
+ "gender": "male",
+ "company": "EVEREST",
+ "email": "collinscarlson@everest.com",
+ "phone": "+1 (944) 580-3905"
+ },
+ {
+ "_id": "55d2fc86ddb3ea916627267a",
+ "age": 33,
+ "name": "Cain Hester",
+ "gender": "male",
+ "company": "IMMUNICS",
+ "email": "cainhester@immunics.com",
+ "phone": "+1 (899) 586-2934"
+ },
+ {
+ "_id": "55d2fc86ffaa0a8952d1a400",
+ "age": 23,
+ "name": "Mia Baird",
+ "gender": "female",
+ "company": "NIPAZ",
+ "email": "miabaird@nipaz.com",
+ "phone": "+1 (940) 569-2850"
+ },
+ {
+ "_id": "55d2fc865f259364ad5b4fff",
+ "age": 25,
+ "name": "Ramona Ewing",
+ "gender": "female",
+ "company": "COMTEST",
+ "email": "ramonaewing@comtest.com",
+ "phone": "+1 (879) 546-2754"
+ },
+ {
+ "_id": "55d2fc862d6af75d6794bef5",
+ "age": 34,
+ "name": "Delacruz Goodwin",
+ "gender": "male",
+ "company": "SLOGANAUT",
+ "email": "delacruzgoodwin@sloganaut.com",
+ "phone": "+1 (928) 477-2688"
+ },
+ {
+ "_id": "55d2fc86e34b19d6fd2ae261",
+ "age": 38,
+ "name": "Mcleod Moody",
+ "gender": "male",
+ "company": "ECRAZE",
+ "email": "mcleodmoody@ecraze.com",
+ "phone": "+1 (989) 598-3350"
+ },
+ {
+ "_id": "55d2fc8608e305ebd55e0bac",
+ "age": 34,
+ "name": "Maddox Calhoun",
+ "gender": "male",
+ "company": "TELEPARK",
+ "email": "maddoxcalhoun@telepark.com",
+ "phone": "+1 (815) 593-3540"
+ },
+ {
+ "_id": "55d2fc869e175ca83d7d6597",
+ "age": 36,
+ "name": "Cora Dale",
+ "gender": "female",
+ "company": "ZILLACTIC",
+ "email": "coradale@zillactic.com",
+ "phone": "+1 (866) 545-3632"
+ },
+ {
+ "_id": "55d2fc861968b039322cb743",
+ "age": 27,
+ "name": "Knapp Miranda",
+ "gender": "male",
+ "company": "TOYLETRY",
+ "email": "knappmiranda@toyletry.com",
+ "phone": "+1 (835) 591-3111"
+ },
+ {
+ "_id": "55d2fc86423f7b5a304d2175",
+ "age": 32,
+ "name": "Ida Petersen",
+ "gender": "female",
+ "company": "BILLMED",
+ "email": "idapetersen@billmed.com",
+ "phone": "+1 (898) 492-2148"
+ },
+ {
+ "_id": "55d2fc862cfd92eb67375bba",
+ "age": 37,
+ "name": "Concepcion Wilcox",
+ "gender": "female",
+ "company": "MAXEMIA",
+ "email": "concepcionwilcox@maxemia.com",
+ "phone": "+1 (812) 516-2631"
+ },
+ {
+ "_id": "55d2fc8695ffe246079f8f0c",
+ "age": 40,
+ "name": "Corine Daniel",
+ "gender": "female",
+ "company": "MEDCOM",
+ "email": "corinedaniel@medcom.com",
+ "phone": "+1 (991) 483-2257"
+ },
+ {
+ "_id": "55d2fc861f1ff641b3aa7ee5",
+ "age": 31,
+ "name": "Latasha Byers",
+ "gender": "female",
+ "company": "RUGSTARS",
+ "email": "latashabyers@rugstars.com",
+ "phone": "+1 (817) 542-3231"
+ },
+ {
+ "_id": "55d2fc86724fbfd025371582",
+ "age": 31,
+ "name": "Gayle Barrett",
+ "gender": "female",
+ "company": "PARAGONIA",
+ "email": "gaylebarrett@paragonia.com",
+ "phone": "+1 (870) 547-2454"
+ },
+ {
+ "_id": "55d2fc869add6e70699650fa",
+ "age": 40,
+ "name": "Angelina Tyler",
+ "gender": "female",
+ "company": "VIRVA",
+ "email": "angelinatyler@virva.com",
+ "phone": "+1 (960) 425-3784"
+ },
+ {
+ "_id": "55d2fc864c12d18424ac35be",
+ "age": 27,
+ "name": "Ratliff Franks",
+ "gender": "male",
+ "company": "CEMENTION",
+ "email": "ratlifffranks@cemention.com",
+ "phone": "+1 (958) 424-2396"
+ },
+ {
+ "_id": "55d2fc86bad0be82f6e2f83b",
+ "age": 40,
+ "name": "Landry Zimmerman",
+ "gender": "male",
+ "company": "JETSILK",
+ "email": "landryzimmerman@jetsilk.com",
+ "phone": "+1 (947) 573-2755"
+ },
+ {
+ "_id": "55d2fc86b56ff40ff0ed70e3",
+ "age": 23,
+ "name": "Greta West",
+ "gender": "female",
+ "company": "UBERLUX",
+ "email": "gretawest@uberlux.com",
+ "phone": "+1 (995) 542-3886"
+ },
+ {
+ "_id": "55d2fc8667dfd03049bf08eb",
+ "age": 30,
+ "name": "Camacho Nelson",
+ "gender": "male",
+ "company": "KYAGORO",
+ "email": "camachonelson@kyagoro.com",
+ "phone": "+1 (881) 500-3970"
+ },
+ {
+ "_id": "55d2fc865458ecf3d2995a63",
+ "age": 36,
+ "name": "June Turner",
+ "gender": "female",
+ "company": "RECOGNIA",
+ "email": "juneturner@recognia.com",
+ "phone": "+1 (976) 466-2777"
+ },
+ {
+ "_id": "55d2fc8682f4304f0889c829",
+ "age": 31,
+ "name": "Mckinney Stark",
+ "gender": "male",
+ "company": "OPTICOM",
+ "email": "mckinneystark@opticom.com",
+ "phone": "+1 (951) 500-3946"
+ },
+ {
+ "_id": "55d2fc86ff8211995849d831",
+ "age": 20,
+ "name": "Hammond Fletcher",
+ "gender": "male",
+ "company": "ERSUM",
+ "email": "hammondfletcher@ersum.com",
+ "phone": "+1 (974) 541-3273"
+ },
+ {
+ "_id": "55d2fc86a9792a08912bdb8e",
+ "age": 23,
+ "name": "White Fischer",
+ "gender": "male",
+ "company": "REALMO",
+ "email": "whitefischer@realmo.com",
+ "phone": "+1 (963) 533-2428"
+ },
+ {
+ "_id": "55d2fc86c5ba8287455030be",
+ "age": 36,
+ "name": "Kimberly Mcguire",
+ "gender": "female",
+ "company": "TETAK",
+ "email": "kimberlymcguire@tetak.com",
+ "phone": "+1 (846) 410-3414"
+ },
+ {
+ "_id": "55d2fc862a665bca942115f3",
+ "age": 35,
+ "name": "Sara Hurst",
+ "gender": "female",
+ "company": "FORTEAN",
+ "email": "sarahurst@fortean.com",
+ "phone": "+1 (857) 530-3627"
+ },
+ {
+ "_id": "55d2fc86b72bee240f10055e",
+ "age": 29,
+ "name": "Chandler English",
+ "gender": "male",
+ "company": "PAPRICUT",
+ "email": "chandlerenglish@papricut.com",
+ "phone": "+1 (978) 582-2348"
+ },
+ {
+ "_id": "55d2fc861c2bccedeac29892",
+ "age": 29,
+ "name": "Waters Riley",
+ "gender": "male",
+ "company": "ECSTASIA",
+ "email": "watersriley@ecstasia.com",
+ "phone": "+1 (842) 579-3426"
+ },
+ {
+ "_id": "55d2fc86526f36994de2038a",
+ "age": 34,
+ "name": "Wood Gomez",
+ "gender": "male",
+ "company": "ASSITIA",
+ "email": "woodgomez@assitia.com",
+ "phone": "+1 (954) 565-2413"
+ },
+ {
+ "_id": "55d2fc86bec8fe1e60977c9c",
+ "age": 31,
+ "name": "Fields Decker",
+ "gender": "male",
+ "company": "EMERGENT",
+ "email": "fieldsdecker@emergent.com",
+ "phone": "+1 (992) 489-3712"
+ },
+ {
+ "_id": "55d2fc868b903951ddd71703",
+ "age": 28,
+ "name": "Barry Woods",
+ "gender": "male",
+ "company": "OZEAN",
+ "email": "barrywoods@ozean.com",
+ "phone": "+1 (885) 433-3285"
+ },
+ {
+ "_id": "55d2fc86ca3984177237f17e",
+ "age": 29,
+ "name": "Whitfield Higgins",
+ "gender": "male",
+ "company": "PEARLESEX",
+ "email": "whitfieldhiggins@pearlesex.com",
+ "phone": "+1 (869) 468-3186"
+ },
+ {
+ "_id": "55d2fc8678dd83bf6cc16648",
+ "age": 27,
+ "name": "Haynes Mills",
+ "gender": "male",
+ "company": "ZOARERE",
+ "email": "haynesmills@zoarere.com",
+ "phone": "+1 (886) 576-3206"
+ },
+ {
+ "_id": "55d2fc86b6ba36d7927b8765",
+ "age": 27,
+ "name": "Kellie Hurley",
+ "gender": "female",
+ "company": "GYNKO",
+ "email": "kelliehurley@gynko.com",
+ "phone": "+1 (844) 548-2894"
+ },
+ {
+ "_id": "55d2fc869adb64b23212bdfc",
+ "age": 30,
+ "name": "Brandi Shields",
+ "gender": "female",
+ "company": "KENGEN",
+ "email": "brandishields@kengen.com",
+ "phone": "+1 (947) 447-3081"
+ },
+ {
+ "_id": "55d2fc8617e038558bbd0e5f",
+ "age": 22,
+ "name": "Malinda Gordon",
+ "gender": "female",
+ "company": "QUILCH",
+ "email": "malindagordon@quilch.com",
+ "phone": "+1 (945) 466-2414"
+ },
+ {
+ "_id": "55d2fc8614756992c50aabfd",
+ "age": 30,
+ "name": "Wooten Mcknight",
+ "gender": "male",
+ "company": "APPLIDECK",
+ "email": "wootenmcknight@applideck.com",
+ "phone": "+1 (994) 416-2156"
+ },
+ {
+ "_id": "55d2fc86b44fbdb8c8ea3a67",
+ "age": 36,
+ "name": "Mona Thomas",
+ "gender": "female",
+ "company": "KROG",
+ "email": "monathomas@krog.com",
+ "phone": "+1 (924) 423-3381"
+ },
+ {
+ "_id": "55d2fc86ded545b6b4f5e536",
+ "age": 22,
+ "name": "Bates Cole",
+ "gender": "male",
+ "company": "DIGIRANG",
+ "email": "batescole@digirang.com",
+ "phone": "+1 (956) 409-2471"
+ },
+ {
+ "_id": "55d2fc864abd3a5951c8e07c",
+ "age": 33,
+ "name": "Shirley Potts",
+ "gender": "female",
+ "company": "OMATOM",
+ "email": "shirleypotts@omatom.com",
+ "phone": "+1 (804) 496-2921"
+ },
+ {
+ "_id": "55d2fc864e3992c902987b9c",
+ "age": 22,
+ "name": "Adrian Branch",
+ "gender": "female",
+ "company": "MULTIFLEX",
+ "email": "adrianbranch@multiflex.com",
+ "phone": "+1 (817) 499-3955"
+ },
+ {
+ "_id": "55d2fc8679037ccc9d0d84d0",
+ "age": 25,
+ "name": "Deanne Rosa",
+ "gender": "female",
+ "company": "QUONATA",
+ "email": "deannerosa@quonata.com",
+ "phone": "+1 (896) 463-2190"
+ },
+ {
+ "_id": "55d2fc869ec47f3f9745bcbc",
+ "age": 28,
+ "name": "Sherrie Bowers",
+ "gender": "female",
+ "company": "GOLISTIC",
+ "email": "sherriebowers@golistic.com",
+ "phone": "+1 (854) 539-3836"
+ },
+ {
+ "_id": "55d2fc86c953130389da55f9",
+ "age": 21,
+ "name": "Sharp Douglas",
+ "gender": "male",
+ "company": "CHILLIUM",
+ "email": "sharpdouglas@chillium.com",
+ "phone": "+1 (999) 513-3550"
+ },
+ {
+ "_id": "55d2fc86d42d710fef2a7781",
+ "age": 22,
+ "name": "Sandy Dillard",
+ "gender": "female",
+ "company": "PHARMACON",
+ "email": "sandydillard@pharmacon.com",
+ "phone": "+1 (844) 433-2832"
+ },
+ {
+ "_id": "55d2fc86aa4130e6998a333b",
+ "age": 20,
+ "name": "Naomi Willis",
+ "gender": "female",
+ "company": "SAVVY",
+ "email": "naomiwillis@savvy.com",
+ "phone": "+1 (826) 499-3221"
+ },
+ {
+ "_id": "55d2fc869c2c97145040281b",
+ "age": 38,
+ "name": "Rivera Stone",
+ "gender": "male",
+ "company": "ORBIXTAR",
+ "email": "riverastone@orbixtar.com",
+ "phone": "+1 (994) 439-3810"
+ },
+ {
+ "_id": "55d2fc86e7165c13cd5905c1",
+ "age": 22,
+ "name": "Oliver Day",
+ "gender": "male",
+ "company": "PORTALIS",
+ "email": "oliverday@portalis.com",
+ "phone": "+1 (844) 464-2363"
+ },
+ {
+ "_id": "55d2fc86b6b619b4d04c7640",
+ "age": 39,
+ "name": "Rachael Owens",
+ "gender": "female",
+ "company": "NURALI",
+ "email": "rachaelowens@nurali.com",
+ "phone": "+1 (856) 418-3617"
+ },
+ {
+ "_id": "55d2fc865f2612144e6f27e6",
+ "age": 30,
+ "name": "Winifred Molina",
+ "gender": "female",
+ "company": "NITRACYR",
+ "email": "winifredmolina@nitracyr.com",
+ "phone": "+1 (881) 417-3559"
+ },
+ {
+ "_id": "55d2fc86c38ab2f341eb9717",
+ "age": 33,
+ "name": "Helen Callahan",
+ "gender": "female",
+ "company": "BOLAX",
+ "email": "helencallahan@bolax.com",
+ "phone": "+1 (929) 407-3095"
+ },
+ {
+ "_id": "55d2fc86e6aa094f47df5373",
+ "age": 32,
+ "name": "Leblanc Christensen",
+ "gender": "male",
+ "company": "LIQUIDOC",
+ "email": "leblancchristensen@liquidoc.com",
+ "phone": "+1 (878) 568-2054"
+ },
+ {
+ "_id": "55d2fc86b297912d153c4e8f",
+ "age": 31,
+ "name": "Hill Robbins",
+ "gender": "male",
+ "company": "QUANTALIA",
+ "email": "hillrobbins@quantalia.com",
+ "phone": "+1 (826) 430-2750"
+ },
+ {
+ "_id": "55d2fc86e776e4075d7df74e",
+ "age": 36,
+ "name": "Tabitha Whitley",
+ "gender": "female",
+ "company": "ZILLIDIUM",
+ "email": "tabithawhitley@zillidium.com",
+ "phone": "+1 (838) 516-3637"
+ },
+ {
+ "_id": "55d2fc86197a382bbf34e81f",
+ "age": 36,
+ "name": "May Pearson",
+ "gender": "male",
+ "company": "RODEOMAD",
+ "email": "maypearson@rodeomad.com",
+ "phone": "+1 (854) 429-3462"
+ },
+ {
+ "_id": "55d2fc863ade7d3517aed2c6",
+ "age": 28,
+ "name": "Alvarez Austin",
+ "gender": "male",
+ "company": "CUBIX",
+ "email": "alvarezaustin@cubix.com",
+ "phone": "+1 (847) 594-3735"
+ },
+ {
+ "_id": "55d2fc86b158d5d260362ac4",
+ "age": 31,
+ "name": "Misty Shepard",
+ "gender": "female",
+ "company": "COMVEYER",
+ "email": "mistyshepard@comveyer.com",
+ "phone": "+1 (901) 567-3881"
+ },
+ {
+ "_id": "55d2fc8646bce5646a0b5258",
+ "age": 22,
+ "name": "Yvette Hensley",
+ "gender": "female",
+ "company": "MYOPIUM",
+ "email": "yvettehensley@myopium.com",
+ "phone": "+1 (890) 456-2157"
+ },
+ {
+ "_id": "55d2fc86c362f848f08340c2",
+ "age": 36,
+ "name": "Hernandez Rowe",
+ "gender": "male",
+ "company": "EARTHPLEX",
+ "email": "hernandezrowe@earthplex.com",
+ "phone": "+1 (807) 502-2308"
+ },
+ {
+ "_id": "55d2fc8640a621a6f035ce8d",
+ "age": 39,
+ "name": "Maura Harper",
+ "gender": "female",
+ "company": "ROBOID",
+ "email": "mauraharper@roboid.com",
+ "phone": "+1 (927) 506-2290"
+ },
+ {
+ "_id": "55d2fc86965968be6314d56f",
+ "age": 20,
+ "name": "Luisa Gardner",
+ "gender": "female",
+ "company": "WAAB",
+ "email": "luisagardner@waab.com",
+ "phone": "+1 (964) 514-2189"
+ },
+ {
+ "_id": "55d2fc86e12b5b70fffd430a",
+ "age": 36,
+ "name": "Christa Bradley",
+ "gender": "female",
+ "company": "FURNIGEER",
+ "email": "christabradley@furnigeer.com",
+ "phone": "+1 (871) 587-3404"
+ },
+ {
+ "_id": "55d2fc86153d11b40a9bf8bc",
+ "age": 26,
+ "name": "Murphy Fleming",
+ "gender": "male",
+ "company": "COLLAIRE",
+ "email": "murphyfleming@collaire.com",
+ "phone": "+1 (909) 598-3130"
+ },
+ {
+ "_id": "55d2fc863ec1e4fc29e5ce50",
+ "age": 28,
+ "name": "Bobbi Harrington",
+ "gender": "female",
+ "company": "MEDIFAX",
+ "email": "bobbiharrington@medifax.com",
+ "phone": "+1 (825) 598-2607"
+ },
+ {
+ "_id": "55d2fc86f4b17262ea0129c6",
+ "age": 40,
+ "name": "Paige Flynn",
+ "gender": "female",
+ "company": "PULZE",
+ "email": "paigeflynn@pulze.com",
+ "phone": "+1 (956) 529-3295"
+ },
+ {
+ "_id": "55d2fc861c8dc17cb598e70d",
+ "age": 21,
+ "name": "Nina Moon",
+ "gender": "female",
+ "company": "ZOLAVO",
+ "email": "ninamoon@zolavo.com",
+ "phone": "+1 (863) 540-3993"
+ },
+ {
+ "_id": "55d2fc869d8ee9d95ab9fee4",
+ "age": 36,
+ "name": "Shauna Mckay",
+ "gender": "female",
+ "company": "LUNCHPOD",
+ "email": "shaunamckay@lunchpod.com",
+ "phone": "+1 (879) 435-3179"
+ },
+ {
+ "_id": "55d2fc86a03f430c5e56194b",
+ "age": 36,
+ "name": "Amie Nicholson",
+ "gender": "female",
+ "company": "LETPRO",
+ "email": "amienicholson@letpro.com",
+ "phone": "+1 (839) 600-3014"
+ },
+ {
+ "_id": "55d2fc86062b4615153832f6",
+ "age": 31,
+ "name": "Pennington Whitney",
+ "gender": "male",
+ "company": "TRI@TRIBALOG",
+ "email": "penningtonwhitney@tri@tribalog.com",
+ "phone": "+1 (950) 487-3727"
+ },
+ {
+ "_id": "55d2fc868849f1c7f4f80541",
+ "age": 23,
+ "name": "Gena Barton",
+ "gender": "female",
+ "company": "VORTEXACO",
+ "email": "genabarton@vortexaco.com",
+ "phone": "+1 (889) 515-2172"
+ },
+ {
+ "_id": "55d2fc860c13e786f86024fd",
+ "age": 27,
+ "name": "Ashley Stephens",
+ "gender": "female",
+ "company": "ZENSUS",
+ "email": "ashleystephens@zensus.com",
+ "phone": "+1 (949) 525-3726"
+ },
+ {
+ "_id": "55d2fc86cca3638bdc9c942c",
+ "age": 38,
+ "name": "Cherie Morgan",
+ "gender": "female",
+ "company": "HELIXO",
+ "email": "cheriemorgan@helixo.com",
+ "phone": "+1 (815) 514-2167"
+ },
+ {
+ "_id": "55d2fc8630d769398c9a0788",
+ "age": 31,
+ "name": "Ann Wiggins",
+ "gender": "female",
+ "company": "NIXELT",
+ "email": "annwiggins@nixelt.com",
+ "phone": "+1 (878) 567-2808"
+ },
+ {
+ "_id": "55d2fc86f3d0744abd99ee4a",
+ "age": 36,
+ "name": "Hinton Keller",
+ "gender": "male",
+ "company": "VENOFLEX",
+ "email": "hintonkeller@venoflex.com",
+ "phone": "+1 (978) 499-2652"
+ },
+ {
+ "_id": "55d2fc86714b2f2f7f59ff69",
+ "age": 32,
+ "name": "Marsh Mullins",
+ "gender": "male",
+ "company": "ZIALACTIC",
+ "email": "marshmullins@zialactic.com",
+ "phone": "+1 (908) 537-2112"
+ },
+ {
+ "_id": "55d2fc8644c73b5870be171c",
+ "age": 28,
+ "name": "Holland Underwood",
+ "gender": "male",
+ "company": "ZILLACON",
+ "email": "hollandunderwood@zillacon.com",
+ "phone": "+1 (968) 454-2162"
+ },
+ {
+ "_id": "55d2fc8648b8691a6a646f9e",
+ "age": 31,
+ "name": "Beverly Oneal",
+ "gender": "female",
+ "company": "BYTREX",
+ "email": "beverlyoneal@bytrex.com",
+ "phone": "+1 (969) 522-2598"
+ },
+ {
+ "_id": "55d2fc86b3e9627aa4f5f88a",
+ "age": 24,
+ "name": "Leanne Frazier",
+ "gender": "female",
+ "company": "HOPELI",
+ "email": "leannefrazier@hopeli.com",
+ "phone": "+1 (923) 532-3379"
+ },
+ {
+ "_id": "55d2fc867bdc2935055e4595",
+ "age": 31,
+ "name": "Rhodes Cash",
+ "gender": "male",
+ "company": "PAPRIKUT",
+ "email": "rhodescash@paprikut.com",
+ "phone": "+1 (830) 507-2776"
+ },
+ {
+ "_id": "55d2fc86543e21b2bc15201d",
+ "age": 30,
+ "name": "Cherry Bush",
+ "gender": "male",
+ "company": "PROGENEX",
+ "email": "cherrybush@progenex.com",
+ "phone": "+1 (935) 577-2984"
+ },
+ {
+ "_id": "55d2fc8660c1a32dfdf4fe67",
+ "age": 32,
+ "name": "Jacobs Clark",
+ "gender": "male",
+ "company": "COMDOM",
+ "email": "jacobsclark@comdom.com",
+ "phone": "+1 (947) 434-2665"
+ },
+ {
+ "_id": "55d2fc861641831257904d9c",
+ "age": 37,
+ "name": "Nell Mcmahon",
+ "gender": "female",
+ "company": "SLAMBDA",
+ "email": "nellmcmahon@slambda.com",
+ "phone": "+1 (831) 462-2693"
+ },
+ {
+ "_id": "55d2fc86835340478ec889e2",
+ "age": 37,
+ "name": "Palmer Livingston",
+ "gender": "male",
+ "company": "DIGIGEN",
+ "email": "palmerlivingston@digigen.com",
+ "phone": "+1 (817) 443-2049"
+ },
+ {
+ "_id": "55d2fc8697f9fd666529fa34",
+ "age": 40,
+ "name": "Ayala Schmidt",
+ "gender": "male",
+ "company": "EWAVES",
+ "email": "ayalaschmidt@ewaves.com",
+ "phone": "+1 (899) 576-2845"
+ },
+ {
+ "_id": "55d2fc8682936b03c7c044de",
+ "age": 26,
+ "name": "Lynch Beck",
+ "gender": "male",
+ "company": "INDEXIA",
+ "email": "lynchbeck@indexia.com",
+ "phone": "+1 (942) 411-3724"
+ },
+ {
+ "_id": "55d2fc86bb74729fe35b2bcc",
+ "age": 20,
+ "name": "Yang Hickman",
+ "gender": "male",
+ "company": "UXMOX",
+ "email": "yanghickman@uxmox.com",
+ "phone": "+1 (944) 554-2948"
+ },
+ {
+ "_id": "55d2fc86bb04a1e5e39143b1",
+ "age": 30,
+ "name": "Andrews Lucas",
+ "gender": "male",
+ "company": "CIPROMOX",
+ "email": "andrewslucas@cipromox.com",
+ "phone": "+1 (942) 401-2756"
+ },
+ {
+ "_id": "55d2fc86b862c1492a4c5bc1",
+ "age": 34,
+ "name": "Rosa Valdez",
+ "gender": "female",
+ "company": "ONTALITY",
+ "email": "rosavaldez@ontality.com",
+ "phone": "+1 (963) 414-3056"
+ },
+ {
+ "_id": "55d2fc868ab9f2f25a46a850",
+ "age": 30,
+ "name": "Maria Caldwell",
+ "gender": "female",
+ "company": "ACRODANCE",
+ "email": "mariacaldwell@acrodance.com",
+ "phone": "+1 (963) 433-2398"
+ },
+ {
+ "_id": "55d2fc868d206b4d99f1f0b2",
+ "age": 36,
+ "name": "Gilda Chase",
+ "gender": "female",
+ "company": "KOFFEE",
+ "email": "gildachase@koffee.com",
+ "phone": "+1 (980) 591-3955"
+ },
+ {
+ "_id": "55d2fc86e0c5a2f031b4a0d9",
+ "age": 24,
+ "name": "Dejesus Pittman",
+ "gender": "male",
+ "company": "SLAX",
+ "email": "dejesuspittman@slax.com",
+ "phone": "+1 (819) 574-2826"
+ },
+ {
+ "_id": "55d2fc868190178a9af16ec5",
+ "age": 23,
+ "name": "Valdez Gibson",
+ "gender": "male",
+ "company": "ELECTONIC",
+ "email": "valdezgibson@electonic.com",
+ "phone": "+1 (809) 520-3985"
+ },
+ {
+ "_id": "55d2fc86d3bc3cf86e16bc5b",
+ "age": 21,
+ "name": "Aguilar Bird",
+ "gender": "male",
+ "company": "ULTRASURE",
+ "email": "aguilarbird@ultrasure.com",
+ "phone": "+1 (813) 455-3814"
+ },
+ {
+ "_id": "55d2fc86701c49cc235f0b49",
+ "age": 24,
+ "name": "Bentley Mooney",
+ "gender": "male",
+ "company": "BEDLAM",
+ "email": "bentleymooney@bedlam.com",
+ "phone": "+1 (870) 530-2188"
+ },
+ {
+ "_id": "55d2fc863fe6d9fc492a1ca5",
+ "age": 28,
+ "name": "Ruby Wooten",
+ "gender": "female",
+ "company": "MARKETOID",
+ "email": "rubywooten@marketoid.com",
+ "phone": "+1 (813) 470-3521"
+ },
+ {
+ "_id": "55d2fc8622f489f721743001",
+ "age": 28,
+ "name": "Garrison Blevins",
+ "gender": "male",
+ "company": "KEENGEN",
+ "email": "garrisonblevins@keengen.com",
+ "phone": "+1 (974) 538-2989"
+ },
+ {
+ "_id": "55d2fc863dc60d226c55ece7",
+ "age": 33,
+ "name": "Harper Tanner",
+ "gender": "male",
+ "company": "QABOOS",
+ "email": "harpertanner@qaboos.com",
+ "phone": "+1 (953) 406-3082"
+ },
+ {
+ "_id": "55d2fc86fecd601439c2702e",
+ "age": 32,
+ "name": "Best Robles",
+ "gender": "male",
+ "company": "OCEANICA",
+ "email": "bestrobles@oceanica.com",
+ "phone": "+1 (815) 539-3097"
+ },
+ {
+ "_id": "55d2fc86ba25530a2149beab",
+ "age": 36,
+ "name": "Marian Bradshaw",
+ "gender": "female",
+ "company": "XYQAG",
+ "email": "marianbradshaw@xyqag.com",
+ "phone": "+1 (928) 410-3218"
+ },
+ {
+ "_id": "55d2fc867352b6b799d365e4",
+ "age": 23,
+ "name": "Whitley Oneil",
+ "gender": "male",
+ "company": "XURBAN",
+ "email": "whitleyoneil@xurban.com",
+ "phone": "+1 (802) 578-3671"
+ },
+ {
+ "_id": "55d2fc865ee137dbdee5cde2",
+ "age": 34,
+ "name": "Ella Fox",
+ "gender": "female",
+ "company": "TUBESYS",
+ "email": "ellafox@tubesys.com",
+ "phone": "+1 (920) 524-3066"
+ },
+ {
+ "_id": "55d2fc860cc159486a822879",
+ "age": 30,
+ "name": "Farmer Castro",
+ "gender": "male",
+ "company": "QNEKT",
+ "email": "farmercastro@qnekt.com",
+ "phone": "+1 (866) 578-2968"
+ },
+ {
+ "_id": "55d2fc863b57eefc3015d373",
+ "age": 28,
+ "name": "Guy Cochran",
+ "gender": "male",
+ "company": "VICON",
+ "email": "guycochran@vicon.com",
+ "phone": "+1 (840) 567-2191"
+ },
+ {
+ "_id": "55d2fc863df7dfda22e99029",
+ "age": 32,
+ "name": "Leach Rocha",
+ "gender": "male",
+ "company": "DANJA",
+ "email": "leachrocha@danja.com",
+ "phone": "+1 (971) 589-3164"
+ },
+ {
+ "_id": "55d2fc86aba3b9d7ce3f877c",
+ "age": 36,
+ "name": "Tanner Hayes",
+ "gender": "male",
+ "company": "TELEQUIET",
+ "email": "tannerhayes@telequiet.com",
+ "phone": "+1 (813) 526-2989"
+ },
+ {
+ "_id": "55d2fc862cd6fb84f734fa0e",
+ "age": 30,
+ "name": "Keith Maldonado",
+ "gender": "male",
+ "company": "MAGNEATO",
+ "email": "keithmaldonado@magneato.com",
+ "phone": "+1 (997) 419-3200"
+ },
+ {
+ "_id": "55d2fc8663d4dc1e43943f62",
+ "age": 29,
+ "name": "Winnie Harrell",
+ "gender": "female",
+ "company": "FRENEX",
+ "email": "winnieharrell@frenex.com",
+ "phone": "+1 (966) 565-2447"
+ },
+ {
+ "_id": "55d2fc86b57f9312b0d28a1d",
+ "age": 28,
+ "name": "Sandoval Garza",
+ "gender": "male",
+ "company": "INTERLOO",
+ "email": "sandovalgarza@interloo.com",
+ "phone": "+1 (972) 597-3431"
+ },
+ {
+ "_id": "55d2fc86a356d194d285d160",
+ "age": 23,
+ "name": "Lina Dejesus",
+ "gender": "female",
+ "company": "ORONOKO",
+ "email": "linadejesus@oronoko.com",
+ "phone": "+1 (910) 560-2515"
+ },
+ {
+ "_id": "55d2fc862f4cd754495f93c7",
+ "age": 30,
+ "name": "Jana Spence",
+ "gender": "female",
+ "company": "ZILLACOM",
+ "email": "janaspence@zillacom.com",
+ "phone": "+1 (994) 436-2023"
+ },
+ {
+ "_id": "55d2fc869b25329fae4936d0",
+ "age": 32,
+ "name": "Mcdowell Fisher",
+ "gender": "male",
+ "company": "GYNK",
+ "email": "mcdowellfisher@gynk.com",
+ "phone": "+1 (941) 587-3569"
+ },
+ {
+ "_id": "55d2fc866b52b90a3758bdd3",
+ "age": 28,
+ "name": "Farley Bernard",
+ "gender": "male",
+ "company": "NETROPIC",
+ "email": "farleybernard@netropic.com",
+ "phone": "+1 (856) 540-2658"
+ },
+ {
+ "_id": "55d2fc864086901eaeb80443",
+ "age": 25,
+ "name": "Lorna Howe",
+ "gender": "female",
+ "company": "ISOSWITCH",
+ "email": "lornahowe@isoswitch.com",
+ "phone": "+1 (851) 432-3160"
+ },
+ {
+ "_id": "55d2fc86b4ac38891f11340b",
+ "age": 25,
+ "name": "English Watts",
+ "gender": "male",
+ "company": "INFOTRIPS",
+ "email": "englishwatts@infotrips.com",
+ "phone": "+1 (942) 481-2578"
+ },
+ {
+ "_id": "55d2fc86e0d047d4eb3c224f",
+ "age": 35,
+ "name": "Burch Howell",
+ "gender": "male",
+ "company": "FANFARE",
+ "email": "burchhowell@fanfare.com",
+ "phone": "+1 (986) 507-2725"
+ },
+ {
+ "_id": "55d2fc86330a8dab2ddbc0c4",
+ "age": 39,
+ "name": "Hudson Bender",
+ "gender": "male",
+ "company": "ENORMO",
+ "email": "hudsonbender@enormo.com",
+ "phone": "+1 (982) 553-3993"
+ },
+ {
+ "_id": "55d2fc8600bb27f4ba215be8",
+ "age": 30,
+ "name": "Mcdonald Whitehead",
+ "gender": "male",
+ "company": "SENMAO",
+ "email": "mcdonaldwhitehead@senmao.com",
+ "phone": "+1 (837) 449-3264"
+ },
+ {
+ "_id": "55d2fc8683787d8b7b400408",
+ "age": 31,
+ "name": "Hope Holden",
+ "gender": "female",
+ "company": "EVENTIX",
+ "email": "hopeholden@eventix.com",
+ "phone": "+1 (888) 436-2921"
+ },
+ {
+ "_id": "55d2fc86cd7d2a5c962d2c05",
+ "age": 36,
+ "name": "Suarez Mejia",
+ "gender": "male",
+ "company": "BUZZWORKS",
+ "email": "suarezmejia@buzzworks.com",
+ "phone": "+1 (919) 526-3966"
+ },
+ {
+ "_id": "55d2fc8612bf58c9b2d953cf",
+ "age": 27,
+ "name": "Michele Little",
+ "gender": "female",
+ "company": "VINCH",
+ "email": "michelelittle@vinch.com",
+ "phone": "+1 (817) 414-2165"
+ },
+ {
+ "_id": "55d2fc864a8103126f905972",
+ "age": 25,
+ "name": "Patrick Cooke",
+ "gender": "male",
+ "company": "BEDDER",
+ "email": "patrickcooke@bedder.com",
+ "phone": "+1 (993) 587-2086"
+ },
+ {
+ "_id": "55d2fc865ddf784cac1f023c",
+ "age": 31,
+ "name": "Holcomb Beasley",
+ "gender": "male",
+ "company": "TECHTRIX",
+ "email": "holcombbeasley@techtrix.com",
+ "phone": "+1 (879) 458-3507"
+ },
+ {
+ "_id": "55d2fc86e27a28e9e9b0d232",
+ "age": 34,
+ "name": "Catalina Donovan",
+ "gender": "female",
+ "company": "FILODYNE",
+ "email": "catalinadonovan@filodyne.com",
+ "phone": "+1 (818) 542-2296"
+ },
+ {
+ "_id": "55d2fc861801cbac57fa3186",
+ "age": 21,
+ "name": "Leslie Bryan",
+ "gender": "female",
+ "company": "LUXURIA",
+ "email": "lesliebryan@luxuria.com",
+ "phone": "+1 (917) 590-3272"
+ },
+ {
+ "_id": "55d2fc86d3aa760444ec40cc",
+ "age": 37,
+ "name": "Hobbs Noel",
+ "gender": "male",
+ "company": "ZILLA",
+ "email": "hobbsnoel@zilla.com",
+ "phone": "+1 (917) 430-3792"
+ },
+ {
+ "_id": "55d2fc86f53d0267e33ddb67",
+ "age": 38,
+ "name": "Nunez Meyers",
+ "gender": "male",
+ "company": "ENTROFLEX",
+ "email": "nunezmeyers@entroflex.com",
+ "phone": "+1 (940) 419-3943"
+ },
+ {
+ "_id": "55d2fc867805cf4262e648a9",
+ "age": 37,
+ "name": "Sonya Sloan",
+ "gender": "female",
+ "company": "SURELOGIC",
+ "email": "sonyasloan@surelogic.com",
+ "phone": "+1 (924) 561-3268"
+ },
+ {
+ "_id": "55d2fc86a3b756eaaef9f9fa",
+ "age": 31,
+ "name": "Angeline Sargent",
+ "gender": "female",
+ "company": "QUIZMO",
+ "email": "angelinesargent@quizmo.com",
+ "phone": "+1 (952) 539-3859"
+ },
+ {
+ "_id": "55d2fc860f0e4be242c866a3",
+ "age": 40,
+ "name": "Norris Webb",
+ "gender": "male",
+ "company": "ZENCO",
+ "email": "norriswebb@zenco.com",
+ "phone": "+1 (834) 527-2399"
+ },
+ {
+ "_id": "55d2fc86b2da030fb755d74c",
+ "age": 38,
+ "name": "Wise Bonner",
+ "gender": "male",
+ "company": "KINETICA",
+ "email": "wisebonner@kinetica.com",
+ "phone": "+1 (938) 416-3537"
+ },
+ {
+ "_id": "55d2fc8699036f35ee214843",
+ "age": 25,
+ "name": "Imogene Blankenship",
+ "gender": "female",
+ "company": "POLARAX",
+ "email": "imogeneblankenship@polarax.com",
+ "phone": "+1 (877) 476-3735"
+ },
+ {
+ "_id": "55d2fc86009b5a1658986a92",
+ "age": 27,
+ "name": "Silva Schneider",
+ "gender": "male",
+ "company": "MINGA",
+ "email": "silvaschneider@minga.com",
+ "phone": "+1 (884) 420-2111"
+ },
+ {
+ "_id": "55d2fc86e3dcb6d4996e9813",
+ "age": 40,
+ "name": "Lawanda Cortez",
+ "gender": "female",
+ "company": "HOMETOWN",
+ "email": "lawandacortez@hometown.com",
+ "phone": "+1 (946) 525-3826"
+ },
+ {
+ "_id": "55d2fc8641977ef422e73176",
+ "age": 40,
+ "name": "Clements Waters",
+ "gender": "male",
+ "company": "FLEETMIX",
+ "email": "clementswaters@fleetmix.com",
+ "phone": "+1 (973) 523-2395"
+ },
+ {
+ "_id": "55d2fc869d0f5363ad055935",
+ "age": 20,
+ "name": "Ofelia Gilbert",
+ "gender": "female",
+ "company": "ECRATER",
+ "email": "ofeliagilbert@ecrater.com",
+ "phone": "+1 (828) 404-2646"
+ },
+ {
+ "_id": "55d2fc86c39b876162269895",
+ "age": 23,
+ "name": "Valenzuela Carney",
+ "gender": "male",
+ "company": "HYDROCOM",
+ "email": "valenzuelacarney@hydrocom.com",
+ "phone": "+1 (842) 566-3650"
+ },
+ {
+ "_id": "55d2fc86546c31933b02dd85",
+ "age": 28,
+ "name": "Wells Santana",
+ "gender": "male",
+ "company": "ZIDOX",
+ "email": "wellssantana@zidox.com",
+ "phone": "+1 (886) 527-2963"
+ },
+ {
+ "_id": "55d2fc86a981c3741ad50f8c",
+ "age": 29,
+ "name": "Karla Carroll",
+ "gender": "female",
+ "company": "MAGNEMO",
+ "email": "karlacarroll@magnemo.com",
+ "phone": "+1 (922) 418-3361"
+ },
+ {
+ "_id": "55d2fc861054327ef76378e3",
+ "age": 29,
+ "name": "Juliet Butler",
+ "gender": "female",
+ "company": "ORBAXTER",
+ "email": "julietbutler@orbaxter.com",
+ "phone": "+1 (838) 554-2269"
+ },
+ {
+ "_id": "55d2fc868120c8a8e4eb9149",
+ "age": 26,
+ "name": "Lisa Copeland",
+ "gender": "female",
+ "company": "SOFTMICRO",
+ "email": "lisacopeland@softmicro.com",
+ "phone": "+1 (915) 577-2302"
+ },
+ {
+ "_id": "55d2fc86b0eb908d67787f43",
+ "age": 37,
+ "name": "Mcmahon Spencer",
+ "gender": "male",
+ "company": "BOILCAT",
+ "email": "mcmahonspencer@boilcat.com",
+ "phone": "+1 (871) 501-2558"
+ },
+ {
+ "_id": "55d2fc860c0b6f5fb520ad2a",
+ "age": 38,
+ "name": "Campbell Baxter",
+ "gender": "male",
+ "company": "DREAMIA",
+ "email": "campbellbaxter@dreamia.com",
+ "phone": "+1 (858) 524-3012"
+ },
+ {
+ "_id": "55d2fc86460508fbed08e924",
+ "age": 23,
+ "name": "Lindsay Sharp",
+ "gender": "male",
+ "company": "SYBIXTEX",
+ "email": "lindsaysharp@sybixtex.com",
+ "phone": "+1 (974) 573-3073"
+ },
+ {
+ "_id": "55d2fc860bf5295ce5679523",
+ "age": 35,
+ "name": "Kathrine Browning",
+ "gender": "female",
+ "company": "LUNCHPAD",
+ "email": "kathrinebrowning@lunchpad.com",
+ "phone": "+1 (922) 458-2466"
+ },
+ {
+ "_id": "55d2fc86d2311e0208cd17a2",
+ "age": 35,
+ "name": "Alice Faulkner",
+ "gender": "female",
+ "company": "PLEXIA",
+ "email": "alicefaulkner@plexia.com",
+ "phone": "+1 (939) 419-3621"
+ },
+ {
+ "_id": "55d2fc86e85116cc8d6c0d70",
+ "age": 32,
+ "name": "Ford Mclean",
+ "gender": "male",
+ "company": "QUADEEBO",
+ "email": "fordmclean@quadeebo.com",
+ "phone": "+1 (974) 521-2540"
+ },
+ {
+ "_id": "55d2fc86f60393147a3a8a07",
+ "age": 29,
+ "name": "Ollie Cannon",
+ "gender": "female",
+ "company": "RAMJOB",
+ "email": "olliecannon@ramjob.com",
+ "phone": "+1 (961) 497-3201"
+ },
+ {
+ "_id": "55d2fc8661d02152a5ba425a",
+ "age": 36,
+ "name": "Calderon Vaughan",
+ "gender": "male",
+ "company": "DIGIQUE",
+ "email": "calderonvaughan@digique.com",
+ "phone": "+1 (912) 553-3902"
+ },
+ {
+ "_id": "55d2fc86a55890c6ce345bf0",
+ "age": 28,
+ "name": "Warren Henry",
+ "gender": "male",
+ "company": "ZERBINA",
+ "email": "warrenhenry@zerbina.com",
+ "phone": "+1 (850) 464-3656"
+ },
+ {
+ "_id": "55d2fc86ccead2741ea21e0e",
+ "age": 21,
+ "name": "Liliana York",
+ "gender": "female",
+ "company": "ANIXANG",
+ "email": "lilianayork@anixang.com",
+ "phone": "+1 (956) 403-2096"
+ },
+ {
+ "_id": "55d2fc86d72dd184f6884371",
+ "age": 33,
+ "name": "Lora Alvarez",
+ "gender": "female",
+ "company": "BLURRYBUS",
+ "email": "loraalvarez@blurrybus.com",
+ "phone": "+1 (917) 457-2866"
+ },
+ {
+ "_id": "55d2fc86fda0c180ccc9598a",
+ "age": 22,
+ "name": "Luna Ellis",
+ "gender": "male",
+ "company": "SLUMBERIA",
+ "email": "lunaellis@slumberia.com",
+ "phone": "+1 (878) 589-3511"
+ },
+ {
+ "_id": "55d2fc860dd81b364fc1c2a9",
+ "age": 30,
+ "name": "Phoebe Chang",
+ "gender": "female",
+ "company": "OPTICON",
+ "email": "phoebechang@opticon.com",
+ "phone": "+1 (962) 559-3475"
+ },
+ {
+ "_id": "55d2fc8657954cc73c166579",
+ "age": 40,
+ "name": "Anna Crane",
+ "gender": "female",
+ "company": "AQUAFIRE",
+ "email": "annacrane@aquafire.com",
+ "phone": "+1 (989) 567-3649"
+ },
+ {
+ "_id": "55d2fc86d996f0f466a006c8",
+ "age": 39,
+ "name": "Matthews French",
+ "gender": "male",
+ "company": "CINESANCT",
+ "email": "matthewsfrench@cinesanct.com",
+ "phone": "+1 (896) 518-2965"
+ },
+ {
+ "_id": "55d2fc8601aad1428aa65531",
+ "age": 34,
+ "name": "Hutchinson Ellison",
+ "gender": "male",
+ "company": "MOREGANIC",
+ "email": "hutchinsonellison@moreganic.com",
+ "phone": "+1 (860) 563-2707"
+ },
+ {
+ "_id": "55d2fc86ec14a6c798e22d72",
+ "age": 21,
+ "name": "Gwen Russell",
+ "gender": "female",
+ "company": "COMVOY",
+ "email": "gwenrussell@comvoy.com",
+ "phone": "+1 (873) 468-2314"
+ },
+ {
+ "_id": "55d2fc865123af00125fd9bd",
+ "age": 22,
+ "name": "Natalie Stuart",
+ "gender": "female",
+ "company": "MOMENTIA",
+ "email": "nataliestuart@momentia.com",
+ "phone": "+1 (908) 573-2177"
+ },
+ {
+ "_id": "55d2fc8688af31f1e9ff0d20",
+ "age": 28,
+ "name": "Brianna Meyer",
+ "gender": "female",
+ "company": "VIASIA",
+ "email": "briannameyer@viasia.com",
+ "phone": "+1 (860) 475-3139"
+ },
+ {
+ "_id": "55d2fc8687f0ff5daa16cbbd",
+ "age": 28,
+ "name": "Trisha Castillo",
+ "gender": "female",
+ "company": "CYCLONICA",
+ "email": "trishacastillo@cyclonica.com",
+ "phone": "+1 (869) 564-2957"
+ },
+ {
+ "_id": "55d2fc863b1c51f11ce4e921",
+ "age": 36,
+ "name": "Powers Weeks",
+ "gender": "male",
+ "company": "BIZMATIC",
+ "email": "powersweeks@bizmatic.com",
+ "phone": "+1 (981) 464-3668"
+ },
+ {
+ "_id": "55d2fc86d8f5d2bef6f84bba",
+ "age": 23,
+ "name": "Young Cabrera",
+ "gender": "female",
+ "company": "CINASTER",
+ "email": "youngcabrera@cinaster.com",
+ "phone": "+1 (897) 528-3924"
+ },
+ {
+ "_id": "55d2fc86861238b57e2932fd",
+ "age": 27,
+ "name": "Maxine Rodgers",
+ "gender": "female",
+ "company": "CHORIZON",
+ "email": "maxinerodgers@chorizon.com",
+ "phone": "+1 (996) 449-2805"
+ },
+ {
+ "_id": "55d2fc86fe5b2f6823cc295f",
+ "age": 26,
+ "name": "Davis Norris",
+ "gender": "male",
+ "company": "CORIANDER",
+ "email": "davisnorris@coriander.com",
+ "phone": "+1 (947) 512-2093"
+ },
+ {
+ "_id": "55d2fc86862e7d0bba1ab524",
+ "age": 25,
+ "name": "Ericka Conner",
+ "gender": "female",
+ "company": "STRALOY",
+ "email": "erickaconner@straloy.com",
+ "phone": "+1 (922) 565-2956"
+ },
+ {
+ "_id": "55d2fc8625bf91e39382ab4c",
+ "age": 21,
+ "name": "Payne Joyner",
+ "gender": "male",
+ "company": "OMNIGOG",
+ "email": "paynejoyner@omnigog.com",
+ "phone": "+1 (998) 521-3917"
+ },
+ {
+ "_id": "55d2fc866835ee51ccea79bb",
+ "age": 24,
+ "name": "Fletcher Payne",
+ "gender": "male",
+ "company": "AMTAP",
+ "email": "fletcherpayne@amtap.com",
+ "phone": "+1 (991) 517-3798"
+ },
+ {
+ "_id": "55d2fc863df3424f70db684c",
+ "age": 38,
+ "name": "Mosley Cobb",
+ "gender": "male",
+ "company": "HONOTRON",
+ "email": "mosleycobb@honotron.com",
+ "phone": "+1 (873) 593-2248"
+ },
+ {
+ "_id": "55d2fc867c4ad9b233d15983",
+ "age": 24,
+ "name": "Webster Sandoval",
+ "gender": "male",
+ "company": "HOMELUX",
+ "email": "webstersandoval@homelux.com",
+ "phone": "+1 (967) 431-2940"
+ },
+ {
+ "_id": "55d2fc8613bf2fe49b1a1f8c",
+ "age": 36,
+ "name": "Colon Mcgee",
+ "gender": "male",
+ "company": "ZAPPIX",
+ "email": "colonmcgee@zappix.com",
+ "phone": "+1 (806) 444-2451"
+ },
+ {
+ "_id": "55d2fc8681a8ccebe8aacd93",
+ "age": 32,
+ "name": "Monique Logan",
+ "gender": "female",
+ "company": "CALLFLEX",
+ "email": "moniquelogan@callflex.com",
+ "phone": "+1 (957) 577-3780"
+ },
+ {
+ "_id": "55d2fc868756d302f29fddb2",
+ "age": 38,
+ "name": "Stewart Ball",
+ "gender": "male",
+ "company": "NETPLODE",
+ "email": "stewartball@netplode.com",
+ "phone": "+1 (966) 435-2206"
+ },
+ {
+ "_id": "55d2fc86457f4d474388d2c8",
+ "age": 23,
+ "name": "Montgomery Carter",
+ "gender": "male",
+ "company": "OLUCORE",
+ "email": "montgomerycarter@olucore.com",
+ "phone": "+1 (894) 556-2662"
+ },
+ {
+ "_id": "55d2fc866da04e0d15b12b36",
+ "age": 28,
+ "name": "Brenda Mccoy",
+ "gender": "female",
+ "company": "AQUAZURE",
+ "email": "brendamccoy@aquazure.com",
+ "phone": "+1 (837) 483-3741"
+ },
+ {
+ "_id": "55d2fc86e2a61a730a8d5c8f",
+ "age": 34,
+ "name": "Eddie Buchanan",
+ "gender": "female",
+ "company": "COGNICODE",
+ "email": "eddiebuchanan@cognicode.com",
+ "phone": "+1 (924) 479-3753"
+ },
+ {
+ "_id": "55d2fc8616e7989042f61488",
+ "age": 23,
+ "name": "Eva Mendoza",
+ "gender": "female",
+ "company": "SOLGAN",
+ "email": "evamendoza@solgan.com",
+ "phone": "+1 (899) 522-3051"
+ },
+ {
+ "_id": "55d2fc86152fd9e4c5471fd7",
+ "age": 21,
+ "name": "Dawson Medina",
+ "gender": "male",
+ "company": "AQUASSEUR",
+ "email": "dawsonmedina@aquasseur.com",
+ "phone": "+1 (877) 580-2295"
+ },
+ {
+ "_id": "55d2fc86a3633b3a799a7811",
+ "age": 34,
+ "name": "Terrie Hobbs",
+ "gender": "female",
+ "company": "VORATAK",
+ "email": "terriehobbs@voratak.com",
+ "phone": "+1 (938) 511-2077"
+ },
+ {
+ "_id": "55d2fc8665a05f05f07bb790",
+ "age": 37,
+ "name": "Iris Bishop",
+ "gender": "female",
+ "company": "INSURESYS",
+ "email": "irisbishop@insuresys.com",
+ "phone": "+1 (819) 415-3840"
+ },
+ {
+ "_id": "55d2fc8799e7556a033b93f6",
+ "age": 29,
+ "name": "Estelle Grant",
+ "gender": "female",
+ "company": "ZOGAK",
+ "email": "estellegrant@zogak.com",
+ "phone": "+1 (854) 437-2898"
+ },
+ {
+ "_id": "55d2fc87745c675e697af04c",
+ "age": 30,
+ "name": "Dianna Gonzalez",
+ "gender": "female",
+ "company": "PIVITOL",
+ "email": "diannagonzalez@pivitol.com",
+ "phone": "+1 (816) 545-3520"
+ }
+]
diff --git a/vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go b/vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go
new file mode 100644
index 000000000..698dd332d
--- /dev/null
+++ b/vendor/github.com/alecthomas/log4go/examples/ConsoleLogWriter_Manual.go
@@ -0,0 +1,14 @@
+package main
+
+import (
+ "time"
+)
+
+import l4g "code.google.com/p/log4go"
+
+func main() {
+ log := l4g.NewLogger()
+ defer log.Close()
+ log.AddFilter("stdout", l4g.DEBUG, l4g.NewConsoleLogWriter())
+ log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
+}
diff --git a/vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go b/vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go
new file mode 100644
index 000000000..efd596aa6
--- /dev/null
+++ b/vendor/github.com/alecthomas/log4go/examples/FileLogWriter_Manual.go
@@ -0,0 +1,57 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "time"
+)
+
+import l4g "code.google.com/p/log4go"
+
+const (
+ filename = "flw.log"
+)
+
+func main() {
+ // Get a new logger instance
+ log := l4g.NewLogger()
+
+ // Create a default logger that is logging messages of FINE or higher
+ log.AddFilter("file", l4g.FINE, l4g.NewFileLogWriter(filename, false))
+ log.Close()
+
+ /* Can also specify manually via the following: (these are the defaults) */
+ flw := l4g.NewFileLogWriter(filename, false)
+ flw.SetFormat("[%D %T] [%L] (%S) %M")
+ flw.SetRotate(false)
+ flw.SetRotateSize(0)
+ flw.SetRotateLines(0)
+ flw.SetRotateDaily(false)
+ log.AddFilter("file", l4g.FINE, flw)
+
+ // Log some experimental messages
+ log.Finest("Everything is created now (notice that I will not be printing to the file)")
+ log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
+ log.Critical("Time to close out!")
+
+ // Close the log
+ log.Close()
+
+ // Print what was logged to the file (yes, I know I'm skipping error checking)
+ fd, _ := os.Open(filename)
+ in := bufio.NewReader(fd)
+ fmt.Print("Messages logged to file were: (line numbers not included)\n")
+ for lineno := 1; ; lineno++ {
+ line, err := in.ReadString('\n')
+ if err == io.EOF {
+ break
+ }
+ fmt.Printf("%3d:\t%s", lineno, line)
+ }
+ fd.Close()
+
+ // Remove the file so it's not lying around
+ os.Remove(filename)
+}
diff --git a/vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go b/vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go
new file mode 100644
index 000000000..83c80ad12
--- /dev/null
+++ b/vendor/github.com/alecthomas/log4go/examples/SimpleNetLogServer.go
@@ -0,0 +1,42 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "net"
+ "os"
+)
+
+var (
+ port = flag.String("p", "12124", "Port number to listen on")
+)
+
+func e(err error) {
+ if err != nil {
+ fmt.Printf("Erroring out: %s\n", err)
+ os.Exit(1)
+ }
+}
+
+func main() {
+ flag.Parse()
+
+ // Bind to the port
+ bind, err := net.ResolveUDPAddr("0.0.0.0:" + *port)
+ e(err)
+
+ // Create listener
+ listener, err := net.ListenUDP("udp", bind)
+ e(err)
+
+ fmt.Printf("Listening to port %s...\n", *port)
+ for {
+ // read into a new buffer
+ buffer := make([]byte, 1024)
+ _, _, err := listener.ReadFrom(buffer)
+ e(err)
+
+ // log to standard output
+ fmt.Println(string(buffer))
+ }
+}
diff --git a/vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go b/vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go
new file mode 100644
index 000000000..400b698ca
--- /dev/null
+++ b/vendor/github.com/alecthomas/log4go/examples/SocketLogWriter_Manual.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "time"
+)
+
+import l4g "code.google.com/p/log4go"
+
+func main() {
+ log := l4g.NewLogger()
+ log.AddFilter("network", l4g.FINEST, l4g.NewSocketLogWriter("udp", "192.168.1.255:12124"))
+
+ // Run `nc -u -l -p 12124` or similar before you run this to see the following message
+ log.Info("The time is now: %s", time.Now().Format("15:04:05 MST 2006/01/02"))
+
+ // This makes sure the output stream buffer is written
+ log.Close()
+}
diff --git a/vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go b/vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go
new file mode 100644
index 000000000..164c2add4
--- /dev/null
+++ b/vendor/github.com/alecthomas/log4go/examples/XMLConfigurationExample.go
@@ -0,0 +1,13 @@
+package main
+
+import l4g "code.google.com/p/log4go"
+
+func main() {
+ // Load the configuration (isn't this easy?)
+ l4g.LoadConfiguration("example.xml")
+
+ // And now we're ready!
+ l4g.Finest("This will only go to those of you really cool UDP kids! If you change enabled=true.")
+ l4g.Debug("Oh no! %d + %d = %d!", 2, 2, 2+2)
+ l4g.Info("About that time, eh chaps?")
+}
diff --git a/vendor/github.com/alecthomas/log4go/examples/example.xml b/vendor/github.com/alecthomas/log4go/examples/example.xml
new file mode 100644
index 000000000..e791278ce
--- /dev/null
+++ b/vendor/github.com/alecthomas/log4go/examples/example.xml
@@ -0,0 +1,47 @@
+<logging>
+ <filter enabled="true">
+ <tag>stdout</tag>
+ <type>console</type>
+ <!-- level is (:?FINEST|FINE|DEBUG|TRACE|INFO|WARNING|ERROR) -->
+ <level>DEBUG</level>
+ </filter>
+ <filter enabled="true">
+ <tag>file</tag>
+ <type>file</type>
+ <level>FINEST</level>
+ <property name="filename">test.log</property>
+ <!--
+ %T - Time (15:04:05 MST)
+ %t - Time (15:04)
+ %D - Date (2006/01/02)
+ %d - Date (01/02/06)
+ %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)
+ %S - Source
+ %M - Message
+ It ignores unknown format strings (and removes them)
+ Recommended: "[%D %T] [%L] (%S) %M"
+ -->
+ <property name="format">[%D %T] [%L] (%S) %M</property>
+ <property name="rotate">false</property> <!-- true enables log rotation, otherwise append -->
+ <property name="maxsize">0M</property> <!-- \d+[KMG]? Suffixes are in terms of 2**10 -->
+ <property name="maxlines">0K</property> <!-- \d+[KMG]? Suffixes are in terms of thousands -->
+ <property name="daily">true</property> <!-- Automatically rotates when a log message is written after midnight -->
+ </filter>
+ <filter enabled="true">
+ <tag>xmllog</tag>
+ <type>xml</type>
+ <level>TRACE</level>
+ <property name="filename">trace.xml</property>
+ <property name="rotate">true</property> <!-- true enables log rotation, otherwise append -->
+ <property name="maxsize">100M</property> <!-- \d+[KMG]? Suffixes are in terms of 2**10 -->
+ <property name="maxrecords">6K</property> <!-- \d+[KMG]? Suffixes are in terms of thousands -->
+ <property name="daily">false</property> <!-- Automatically rotates when a log message is written after midnight -->
+ </filter>
+ <filter enabled="false"><!-- enabled=false means this logger won't actually be created -->
+ <tag>donotopen</tag>
+ <type>socket</type>
+ <level>FINEST</level>
+ <property name="endpoint">192.168.1.255:12124</property> <!-- recommend UDP broadcast -->
+ <property name="protocol">udp</property> <!-- tcp or udp -->
+ </filter>
+</logging>
diff --git a/vendor/github.com/alecthomas/log4go/log4go_test.go b/vendor/github.com/alecthomas/log4go/log4go_test.go
new file mode 100644
index 000000000..c4b92f6a7
--- /dev/null
+++ b/vendor/github.com/alecthomas/log4go/log4go_test.go
@@ -0,0 +1,534 @@
+// Copyright (C) 2010, Kyle Lemons <kyle@kylelemons.net>. All rights reserved.
+
+package log4go
+
+import (
+ "crypto/md5"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "runtime"
+ "testing"
+ "time"
+)
+
+const testLogFile = "_logtest.log"
+
+var now time.Time = time.Unix(0, 1234567890123456789).In(time.UTC)
+
+func newLogRecord(lvl Level, src string, msg string) *LogRecord {
+ return &LogRecord{
+ Level: lvl,
+ Source: src,
+ Created: now,
+ Message: msg,
+ }
+}
+
+func TestELog(t *testing.T) {
+ fmt.Printf("Testing %s\n", L4G_VERSION)
+ lr := newLogRecord(CRITICAL, "source", "message")
+ if lr.Level != CRITICAL {
+ t.Errorf("Incorrect level: %d should be %d", lr.Level, CRITICAL)
+ }
+ if lr.Source != "source" {
+ t.Errorf("Incorrect source: %s should be %s", lr.Source, "source")
+ }
+ if lr.Message != "message" {
+ t.Errorf("Incorrect message: %s should be %s", lr.Source, "message")
+ }
+}
+
+var formatTests = []struct {
+ Test string
+ Record *LogRecord
+ Formats map[string]string
+}{
+ {
+ Test: "Standard formats",
+ Record: &LogRecord{
+ Level: ERROR,
+ Source: "source",
+ Message: "message",
+ Created: now,
+ },
+ Formats: map[string]string{
+ // TODO(kevlar): How can I do this so it'll work outside of PST?
+ FORMAT_DEFAULT: "[2009/02/13 23:31:30 UTC] [EROR] (source) message\n",
+ FORMAT_SHORT: "[23:31 13/02/09] [EROR] message\n",
+ FORMAT_ABBREV: "[EROR] message\n",
+ },
+ },
+}
+
+func TestFormatLogRecord(t *testing.T) {
+ for _, test := range formatTests {
+ name := test.Test
+ for fmt, want := range test.Formats {
+ if got := FormatLogRecord(fmt, test.Record); got != want {
+ t.Errorf("%s - %s:", name, fmt)
+ t.Errorf(" got %q", got)
+ t.Errorf(" want %q", want)
+ }
+ }
+ }
+}
+
+var logRecordWriteTests = []struct {
+ Test string
+ Record *LogRecord
+ Console string
+}{
+ {
+ Test: "Normal message",
+ Record: &LogRecord{
+ Level: CRITICAL,
+ Source: "source",
+ Message: "message",
+ Created: now,
+ },
+ Console: "[23:31:30 UTC 2009/02/13] [CRIT] message\n",
+ },
+}
+
+func TestConsoleLogWriter(t *testing.T) {
+ console := make(ConsoleLogWriter)
+
+ r, w := io.Pipe()
+ go console.run(w)
+ defer console.Close()
+
+ buf := make([]byte, 1024)
+
+ for _, test := range logRecordWriteTests {
+ name := test.Test
+
+ console.LogWrite(test.Record)
+ n, _ := r.Read(buf)
+
+ if got, want := string(buf[:n]), test.Console; got != want {
+ t.Errorf("%s: got %q", name, got)
+ t.Errorf("%s: want %q", name, want)
+ }
+ }
+}
+
+func TestFileLogWriter(t *testing.T) {
+ defer func(buflen int) {
+ LogBufferLength = buflen
+ }(LogBufferLength)
+ LogBufferLength = 0
+
+ w := NewFileLogWriter(testLogFile, false)
+ if w == nil {
+ t.Fatalf("Invalid return: w should not be nil")
+ }
+ defer os.Remove(testLogFile)
+
+ w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
+ w.Close()
+ runtime.Gosched()
+
+ if contents, err := ioutil.ReadFile(testLogFile); err != nil {
+ t.Errorf("read(%q): %s", testLogFile, err)
+ } else if len(contents) != 50 {
+ t.Errorf("malformed filelog: %q (%d bytes)", string(contents), len(contents))
+ }
+}
+
+func TestXMLLogWriter(t *testing.T) {
+ defer func(buflen int) {
+ LogBufferLength = buflen
+ }(LogBufferLength)
+ LogBufferLength = 0
+
+ w := NewXMLLogWriter(testLogFile, false)
+ if w == nil {
+ t.Fatalf("Invalid return: w should not be nil")
+ }
+ defer os.Remove(testLogFile)
+
+ w.LogWrite(newLogRecord(CRITICAL, "source", "message"))
+ w.Close()
+ runtime.Gosched()
+
+ if contents, err := ioutil.ReadFile(testLogFile); err != nil {
+ t.Errorf("read(%q): %s", testLogFile, err)
+ } else if len(contents) != 185 {
+ t.Errorf("malformed xmllog: %q (%d bytes)", string(contents), len(contents))
+ }
+}
+
+func TestLogger(t *testing.T) {
+ sl := NewDefaultLogger(WARNING)
+ if sl == nil {
+ t.Fatalf("NewDefaultLogger should never return nil")
+ }
+ if lw, exist := sl["stdout"]; lw == nil || exist != true {
+ t.Fatalf("NewDefaultLogger produced invalid logger (DNE or nil)")
+ }
+ if sl["stdout"].Level != WARNING {
+ t.Fatalf("NewDefaultLogger produced invalid logger (incorrect level)")
+ }
+ if len(sl) != 1 {
+ t.Fatalf("NewDefaultLogger produced invalid logger (incorrect map count)")
+ }
+
+ //func (l *Logger) AddFilter(name string, level int, writer LogWriter) {}
+ l := make(Logger)
+ l.AddFilter("stdout", DEBUG, NewConsoleLogWriter())
+ if lw, exist := l["stdout"]; lw == nil || exist != true {
+ t.Fatalf("AddFilter produced invalid logger (DNE or nil)")
+ }
+ if l["stdout"].Level != DEBUG {
+ t.Fatalf("AddFilter produced invalid logger (incorrect level)")
+ }
+ if len(l) != 1 {
+ t.Fatalf("AddFilter produced invalid logger (incorrect map count)")
+ }
+
+ //func (l *Logger) Warn(format string, args ...interface{}) error {}
+ if err := l.Warn("%s %d %#v", "Warning:", 1, []int{}); err.Error() != "Warning: 1 []int{}" {
+ t.Errorf("Warn returned invalid error: %s", err)
+ }
+
+ //func (l *Logger) Error(format string, args ...interface{}) error {}
+ if err := l.Error("%s %d %#v", "Error:", 10, []string{}); err.Error() != "Error: 10 []string{}" {
+ t.Errorf("Error returned invalid error: %s", err)
+ }
+
+ //func (l *Logger) Critical(format string, args ...interface{}) error {}
+ if err := l.Critical("%s %d %#v", "Critical:", 100, []int64{}); err.Error() != "Critical: 100 []int64{}" {
+ t.Errorf("Critical returned invalid error: %s", err)
+ }
+
+ // Already tested or basically untestable
+ //func (l *Logger) Log(level int, source, message string) {}
+ //func (l *Logger) Logf(level int, format string, args ...interface{}) {}
+ //func (l *Logger) intLogf(level int, format string, args ...interface{}) string {}
+ //func (l *Logger) Finest(format string, args ...interface{}) {}
+ //func (l *Logger) Fine(format string, args ...interface{}) {}
+ //func (l *Logger) Debug(format string, args ...interface{}) {}
+ //func (l *Logger) Trace(format string, args ...interface{}) {}
+ //func (l *Logger) Info(format string, args ...interface{}) {}
+}
+
+func TestLogOutput(t *testing.T) {
+ const (
+ expected = "fdf3e51e444da56b4cb400f30bc47424"
+ )
+
+ // Unbuffered output
+ defer func(buflen int) {
+ LogBufferLength = buflen
+ }(LogBufferLength)
+ LogBufferLength = 0
+
+ l := make(Logger)
+
+ // Delete and open the output log without a timestamp (for a constant md5sum)
+ l.AddFilter("file", FINEST, NewFileLogWriter(testLogFile, false).SetFormat("[%L] %M"))
+ defer os.Remove(testLogFile)
+
+ // Send some log messages
+ l.Log(CRITICAL, "testsrc1", fmt.Sprintf("This message is level %d", int(CRITICAL)))
+ l.Logf(ERROR, "This message is level %v", ERROR)
+ l.Logf(WARNING, "This message is level %s", WARNING)
+ l.Logc(INFO, func() string { return "This message is level INFO" })
+ l.Trace("This message is level %d", int(TRACE))
+ l.Debug("This message is level %s", DEBUG)
+ l.Fine(func() string { return fmt.Sprintf("This message is level %v", FINE) })
+ l.Finest("This message is level %v", FINEST)
+ l.Finest(FINEST, "is also this message's level")
+
+ l.Close()
+
+ contents, err := ioutil.ReadFile(testLogFile)
+ if err != nil {
+ t.Fatalf("Could not read output log: %s", err)
+ }
+
+ sum := md5.New()
+ sum.Write(contents)
+ if sumstr := hex.EncodeToString(sum.Sum(nil)); sumstr != expected {
+ t.Errorf("--- Log Contents:\n%s---", string(contents))
+ t.Fatalf("Checksum does not match: %s (expecting %s)", sumstr, expected)
+ }
+}
+
+func TestCountMallocs(t *testing.T) {
+ const N = 1
+ var m runtime.MemStats
+ getMallocs := func() uint64 {
+ runtime.ReadMemStats(&m)
+ return m.Mallocs
+ }
+
+ // Console logger
+ sl := NewDefaultLogger(INFO)
+ mallocs := 0 - getMallocs()
+ for i := 0; i < N; i++ {
+ sl.Log(WARNING, "here", "This is a WARNING message")
+ }
+ mallocs += getMallocs()
+ fmt.Printf("mallocs per sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
+
+ // Console logger formatted
+ mallocs = 0 - getMallocs()
+ for i := 0; i < N; i++ {
+ sl.Logf(WARNING, "%s is a log message with level %d", "This", WARNING)
+ }
+ mallocs += getMallocs()
+ fmt.Printf("mallocs per sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
+
+ // Console logger (not logged)
+ sl = NewDefaultLogger(INFO)
+ mallocs = 0 - getMallocs()
+ for i := 0; i < N; i++ {
+ sl.Log(DEBUG, "here", "This is a DEBUG log message")
+ }
+ mallocs += getMallocs()
+ fmt.Printf("mallocs per unlogged sl.Log((WARNING, \"here\", \"This is a log message\"): %d\n", mallocs/N)
+
+ // Console logger formatted (not logged)
+ mallocs = 0 - getMallocs()
+ for i := 0; i < N; i++ {
+ sl.Logf(DEBUG, "%s is a log message with level %d", "This", DEBUG)
+ }
+ mallocs += getMallocs()
+ fmt.Printf("mallocs per unlogged sl.Logf(WARNING, \"%%s is a log message with level %%d\", \"This\", WARNING): %d\n", mallocs/N)
+}
+
+func TestXMLConfig(t *testing.T) {
+ const (
+ configfile = "example.xml"
+ )
+
+ fd, err := os.Create(configfile)
+ if err != nil {
+ t.Fatalf("Could not open %s for writing: %s", configfile, err)
+ }
+
+ fmt.Fprintln(fd, "<logging>")
+ fmt.Fprintln(fd, " <filter enabled=\"true\">")
+ fmt.Fprintln(fd, " <tag>stdout</tag>")
+ fmt.Fprintln(fd, " <type>console</type>")
+ fmt.Fprintln(fd, " <!-- level is (:?FINEST|FINE|DEBUG|TRACE|INFO|WARNING|ERROR) -->")
+ fmt.Fprintln(fd, " <level>DEBUG</level>")
+ fmt.Fprintln(fd, " </filter>")
+ fmt.Fprintln(fd, " <filter enabled=\"true\">")
+ fmt.Fprintln(fd, " <tag>file</tag>")
+ fmt.Fprintln(fd, " <type>file</type>")
+ fmt.Fprintln(fd, " <level>FINEST</level>")
+ fmt.Fprintln(fd, " <property name=\"filename\">test.log</property>")
+ fmt.Fprintln(fd, " <!--")
+ fmt.Fprintln(fd, " %T - Time (15:04:05 MST)")
+ fmt.Fprintln(fd, " %t - Time (15:04)")
+ fmt.Fprintln(fd, " %D - Date (2006/01/02)")
+ fmt.Fprintln(fd, " %d - Date (01/02/06)")
+ fmt.Fprintln(fd, " %L - Level (FNST, FINE, DEBG, TRAC, WARN, EROR, CRIT)")
+ fmt.Fprintln(fd, " %S - Source")
+ fmt.Fprintln(fd, " %M - Message")
+ fmt.Fprintln(fd, " It ignores unknown format strings (and removes them)")
+ fmt.Fprintln(fd, " Recommended: \"[%D %T] [%L] (%S) %M\"")
+ fmt.Fprintln(fd, " -->")
+ fmt.Fprintln(fd, " <property name=\"format\">[%D %T] [%L] (%S) %M</property>")
+ fmt.Fprintln(fd, " <property name=\"rotate\">false</property> <!-- true enables log rotation, otherwise append -->")
+ fmt.Fprintln(fd, " <property name=\"maxsize\">0M</property> <!-- \\d+[KMG]? Suffixes are in terms of 2**10 -->")
+ fmt.Fprintln(fd, " <property name=\"maxlines\">0K</property> <!-- \\d+[KMG]? Suffixes are in terms of thousands -->")
+ fmt.Fprintln(fd, " <property name=\"daily\">true</property> <!-- Automatically rotates when a log message is written after midnight -->")
+ fmt.Fprintln(fd, " </filter>")
+ fmt.Fprintln(fd, " <filter enabled=\"true\">")
+ fmt.Fprintln(fd, " <tag>xmllog</tag>")
+ fmt.Fprintln(fd, " <type>xml</type>")
+ fmt.Fprintln(fd, " <level>TRACE</level>")
+ fmt.Fprintln(fd, " <property name=\"filename\">trace.xml</property>")
+ fmt.Fprintln(fd, " <property name=\"rotate\">true</property> <!-- true enables log rotation, otherwise append -->")
+ fmt.Fprintln(fd, " <property name=\"maxsize\">100M</property> <!-- \\d+[KMG]? Suffixes are in terms of 2**10 -->")
+ fmt.Fprintln(fd, " <property name=\"maxrecords\">6K</property> <!-- \\d+[KMG]? Suffixes are in terms of thousands -->")
+ fmt.Fprintln(fd, " <property name=\"daily\">false</property> <!-- Automatically rotates when a log message is written after midnight -->")
+ fmt.Fprintln(fd, " </filter>")
+ fmt.Fprintln(fd, " <filter enabled=\"false\"><!-- enabled=false means this logger won't actually be created -->")
+ fmt.Fprintln(fd, " <tag>donotopen</tag>")
+ fmt.Fprintln(fd, " <type>socket</type>")
+ fmt.Fprintln(fd, " <level>FINEST</level>")
+ fmt.Fprintln(fd, " <property name=\"endpoint\">192.168.1.255:12124</property> <!-- recommend UDP broadcast -->")
+ fmt.Fprintln(fd, " <property name=\"protocol\">udp</property> <!-- tcp or udp -->")
+ fmt.Fprintln(fd, " </filter>")
+ fmt.Fprintln(fd, "</logging>")
+ fd.Close()
+
+ log := make(Logger)
+ log.LoadConfiguration(configfile)
+ defer os.Remove("trace.xml")
+ defer os.Remove("test.log")
+ defer log.Close()
+
+ // Make sure we got all loggers
+ if len(log) != 3 {
+ t.Fatalf("XMLConfig: Expected 3 filters, found %d", len(log))
+ }
+
+ // Make sure they're the right keys
+ if _, ok := log["stdout"]; !ok {
+ t.Errorf("XMLConfig: Expected stdout logger")
+ }
+ if _, ok := log["file"]; !ok {
+ t.Fatalf("XMLConfig: Expected file logger")
+ }
+ if _, ok := log["xmllog"]; !ok {
+ t.Fatalf("XMLConfig: Expected xmllog logger")
+ }
+
+ // Make sure they're the right type
+ if _, ok := log["stdout"].LogWriter.(ConsoleLogWriter); !ok {
+ t.Fatalf("XMLConfig: Expected stdout to be ConsoleLogWriter, found %T", log["stdout"].LogWriter)
+ }
+ if _, ok := log["file"].LogWriter.(*FileLogWriter); !ok {
+ t.Fatalf("XMLConfig: Expected file to be *FileLogWriter, found %T", log["file"].LogWriter)
+ }
+ if _, ok := log["xmllog"].LogWriter.(*FileLogWriter); !ok {
+ t.Fatalf("XMLConfig: Expected xmllog to be *FileLogWriter, found %T", log["xmllog"].LogWriter)
+ }
+
+ // Make sure levels are set
+ if lvl := log["stdout"].Level; lvl != DEBUG {
+ t.Errorf("XMLConfig: Expected stdout to be set to level %d, found %d", DEBUG, lvl)
+ }
+ if lvl := log["file"].Level; lvl != FINEST {
+ t.Errorf("XMLConfig: Expected file to be set to level %d, found %d", FINEST, lvl)
+ }
+ if lvl := log["xmllog"].Level; lvl != TRACE {
+ t.Errorf("XMLConfig: Expected xmllog to be set to level %d, found %d", TRACE, lvl)
+ }
+
+ // Make sure the w is open and points to the right file
+ if fname := log["file"].LogWriter.(*FileLogWriter).file.Name(); fname != "test.log" {
+ t.Errorf("XMLConfig: Expected file to have opened %s, found %s", "test.log", fname)
+ }
+
+ // Make sure the XLW is open and points to the right file
+ if fname := log["xmllog"].LogWriter.(*FileLogWriter).file.Name(); fname != "trace.xml" {
+ t.Errorf("XMLConfig: Expected xmllog to have opened %s, found %s", "trace.xml", fname)
+ }
+
+ // Move XML log file
+ os.Rename(configfile, "examples/"+configfile) // Keep this so that an example with the documentation is available
+}
+
+func BenchmarkFormatLogRecord(b *testing.B) {
+ const updateEvery = 1
+ rec := &LogRecord{
+ Level: CRITICAL,
+ Created: now,
+ Source: "source",
+ Message: "message",
+ }
+ for i := 0; i < b.N; i++ {
+ rec.Created = rec.Created.Add(1 * time.Second / updateEvery)
+ if i%2 == 0 {
+ FormatLogRecord(FORMAT_DEFAULT, rec)
+ } else {
+ FormatLogRecord(FORMAT_SHORT, rec)
+ }
+ }
+}
+
+func BenchmarkConsoleLog(b *testing.B) {
+ /* This doesn't seem to work on OS X
+ sink, err := os.Open(os.DevNull)
+ if err != nil {
+ panic(err)
+ }
+ if err := syscall.Dup2(int(sink.Fd()), syscall.Stdout); err != nil {
+ panic(err)
+ }
+ */
+
+ stdout = ioutil.Discard
+ sl := NewDefaultLogger(INFO)
+ for i := 0; i < b.N; i++ {
+ sl.Log(WARNING, "here", "This is a log message")
+ }
+}
+
+func BenchmarkConsoleNotLogged(b *testing.B) {
+ sl := NewDefaultLogger(INFO)
+ for i := 0; i < b.N; i++ {
+ sl.Log(DEBUG, "here", "This is a log message")
+ }
+}
+
+func BenchmarkConsoleUtilLog(b *testing.B) {
+ sl := NewDefaultLogger(INFO)
+ for i := 0; i < b.N; i++ {
+ sl.Info("%s is a log message", "This")
+ }
+}
+
+func BenchmarkConsoleUtilNotLog(b *testing.B) {
+ sl := NewDefaultLogger(INFO)
+ for i := 0; i < b.N; i++ {
+ sl.Debug("%s is a log message", "This")
+ }
+}
+
+func BenchmarkFileLog(b *testing.B) {
+ sl := make(Logger)
+ b.StopTimer()
+ sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ sl.Log(WARNING, "here", "This is a log message")
+ }
+ b.StopTimer()
+ os.Remove("benchlog.log")
+}
+
+func BenchmarkFileNotLogged(b *testing.B) {
+ sl := make(Logger)
+ b.StopTimer()
+ sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ sl.Log(DEBUG, "here", "This is a log message")
+ }
+ b.StopTimer()
+ os.Remove("benchlog.log")
+}
+
+func BenchmarkFileUtilLog(b *testing.B) {
+ sl := make(Logger)
+ b.StopTimer()
+ sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ sl.Info("%s is a log message", "This")
+ }
+ b.StopTimer()
+ os.Remove("benchlog.log")
+}
+
+func BenchmarkFileUtilNotLog(b *testing.B) {
+ sl := make(Logger)
+ b.StopTimer()
+ sl.AddFilter("file", INFO, NewFileLogWriter("benchlog.log", false))
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ sl.Debug("%s is a log message", "This")
+ }
+ b.StopTimer()
+ os.Remove("benchlog.log")
+}
+
+// Benchmark results (darwin amd64 6g)
+//elog.BenchmarkConsoleLog 100000 22819 ns/op
+//elog.BenchmarkConsoleNotLogged 2000000 879 ns/op
+//elog.BenchmarkConsoleUtilLog 50000 34380 ns/op
+//elog.BenchmarkConsoleUtilNotLog 1000000 1339 ns/op
+//elog.BenchmarkFileLog 100000 26497 ns/op
+//elog.BenchmarkFileNotLogged 2000000 821 ns/op
+//elog.BenchmarkFileUtilLog 50000 33945 ns/op
+//elog.BenchmarkFileUtilNotLog 1000000 1258 ns/op
diff --git a/vendor/github.com/braintree/manners/helpers_test.go b/vendor/github.com/braintree/manners/helpers_test.go
new file mode 100644
index 000000000..3c11a081d
--- /dev/null
+++ b/vendor/github.com/braintree/manners/helpers_test.go
@@ -0,0 +1,119 @@
+package manners
+
+import (
+ "bufio"
+ "crypto/tls"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "testing"
+)
+
+// a simple step-controllable http client
+type client struct {
+ tls bool
+ addr net.Addr
+ connected chan error
+ sendrequest chan bool
+ response chan *rawResponse
+ closed chan bool
+}
+
+type rawResponse struct {
+ body []string
+ err error
+}
+
+func (c *client) Run() {
+ go func() {
+ var err error
+ conn, err := net.Dial(c.addr.Network(), c.addr.String())
+ if err != nil {
+ c.connected <- err
+ return
+ }
+ if c.tls {
+ conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
+ }
+ c.connected <- nil
+ for <-c.sendrequest {
+ _, err = conn.Write([]byte("GET / HTTP/1.1\nHost: localhost:8000\n\n"))
+ if err != nil {
+ c.response <- &rawResponse{err: err}
+ }
+ // Read response; no content
+ scanner := bufio.NewScanner(conn)
+ var lines []string
+ for scanner.Scan() {
+ // our null handler doesn't send a body, so we know the request is
+ // done when we reach the blank line after the headers
+ line := scanner.Text()
+ if line == "" {
+ break
+ }
+ lines = append(lines, line)
+ }
+ c.response <- &rawResponse{lines, scanner.Err()}
+ }
+ conn.Close()
+ ioutil.ReadAll(conn)
+ c.closed <- true
+ }()
+}
+
+func newClient(addr net.Addr, tls bool) *client {
+ return &client{
+ addr: addr,
+ tls: tls,
+ connected: make(chan error),
+ sendrequest: make(chan bool),
+ response: make(chan *rawResponse),
+ closed: make(chan bool),
+ }
+}
+
+// a handler that returns 200 ok with no body
+var nullHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+func startGenericServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState, runner func() error) (l net.Listener, errc chan error) {
+ server.Addr = "localhost:0"
+ server.Handler = nullHandler
+ if statechanged != nil {
+ // Wrap the ConnState handler with something that will notify
+ // the statechanged channel when a state change happens
+ server.ConnState = func(conn net.Conn, newState http.ConnState) {
+ statechanged <- newState
+ }
+ }
+
+ server.up = make(chan net.Listener)
+ exitchan := make(chan error)
+
+ go func() {
+ exitchan <- runner()
+ }()
+
+ // wait for server socket to be bound
+ select {
+ case l = <-server.up:
+ // all good
+
+ case err := <-exitchan:
+ // all bad
+ t.Fatal("Server failed to start", err)
+ }
+ return l, exitchan
+}
+
+func startServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState) (
+ l net.Listener, errc chan error) {
+ return startGenericServer(t, server, statechanged, server.ListenAndServe)
+}
+
+func startTLSServer(t *testing.T, server *GracefulServer, certFile, keyFile string, statechanged chan http.ConnState) (l net.Listener, errc chan error) {
+ runner := func() error {
+ return server.ListenAndServeTLS(certFile, keyFile)
+ }
+
+ return startGenericServer(t, server, statechanged, runner)
+}
diff --git a/vendor/github.com/braintree/manners/server_test.go b/vendor/github.com/braintree/manners/server_test.go
new file mode 100644
index 000000000..994284216
--- /dev/null
+++ b/vendor/github.com/braintree/manners/server_test.go
@@ -0,0 +1,289 @@
+package manners
+
+import (
+ "net"
+ "net/http"
+ "testing"
+ "time"
+
+ helpers "github.com/braintree/manners/test_helpers"
+)
+
+type httpInterface interface {
+ ListenAndServe() error
+ ListenAndServeTLS(certFile, keyFile string) error
+ Serve(listener net.Listener) error
+}
+
+// Test that the method signatures of the methods we override from net/http/Server match those of the original.
+func TestInterface(t *testing.T) {
+ var original, ours interface{}
+ original = &http.Server{}
+ ours = &GracefulServer{}
+ if _, ok := original.(httpInterface); !ok {
+ t.Errorf("httpInterface definition does not match the canonical server!")
+ }
+ if _, ok := ours.(httpInterface); !ok {
+ t.Errorf("GracefulServer does not implement httpInterface")
+ }
+}
+
+// Tests that the server allows in-flight requests to complete
+// before shutting down.
+func TestGracefulness(t *testing.T) {
+ server := NewServer()
+ wg := helpers.NewWaitGroup()
+ server.wg = wg
+ statechanged := make(chan http.ConnState)
+ listener, exitchan := startServer(t, server, statechanged)
+
+ client := newClient(listener.Addr(), false)
+ client.Run()
+
+ // wait for client to connect, but don't let it send the request yet
+ if err := <-client.connected; err != nil {
+ t.Fatal("Client failed to connect to server", err)
+ }
+ // Even though the client is connected, the server ConnState handler may
+ // not know about that yet. So wait until it is called.
+ waitForState(t, statechanged, http.StateNew, "Request not received")
+
+ server.Close()
+
+ waiting := <-wg.WaitCalled
+ if waiting < 1 {
+ t.Errorf("Expected the waitgroup to equal 1 at shutdown; actually %d", waiting)
+ }
+
+ // allow the client to finish sending the request and make sure the server exits after
+ // (client will be in connected but idle state at that point)
+ client.sendrequest <- true
+ close(client.sendrequest)
+ if err := <-exitchan; err != nil {
+ t.Error("Unexpected error during shutdown", err)
+ }
+}
+
+// Tests that starting the server and closing in 2 new, separate goroutines doesnot
+// get flagged by the race detector (need to run 'go test' w/the -race flag)
+func TestRacyClose(t *testing.T) {
+ go func() {
+ ListenAndServe(":9000", nil)
+ }()
+
+ go func() {
+ Close()
+ }()
+}
+
+// Tests that the server begins to shut down when told to and does not accept
+// new requests once shutdown has begun
+func TestShutdown(t *testing.T) {
+ server := NewServer()
+ wg := helpers.NewWaitGroup()
+ server.wg = wg
+ statechanged := make(chan http.ConnState)
+ listener, exitchan := startServer(t, server, statechanged)
+
+ client1 := newClient(listener.Addr(), false)
+ client1.Run()
+
+ // wait for client1 to connect
+ if err := <-client1.connected; err != nil {
+ t.Fatal("Client failed to connect to server", err)
+ }
+ // Even though the client is connected, the server ConnState handler may
+ // not know about that yet. So wait until it is called.
+ waitForState(t, statechanged, http.StateNew, "Request not received")
+
+ // start the shutdown; once it hits waitgroup.Wait()
+ // the listener should of been closed, though client1 is still connected
+ if server.Close() != true {
+ t.Fatal("first call to Close returned false")
+ }
+ if server.Close() != false {
+ t.Fatal("second call to Close returned true")
+ }
+
+ waiting := <-wg.WaitCalled
+ if waiting != 1 {
+ t.Errorf("Waitcount should be one, got %d", waiting)
+ }
+
+ // should get connection refused at this point
+ client2 := newClient(listener.Addr(), false)
+ client2.Run()
+
+ if err := <-client2.connected; err == nil {
+ t.Fatal("client2 connected when it should of received connection refused")
+ }
+
+ // let client1 finish so the server can exit
+ close(client1.sendrequest) // don't bother sending an actual request
+
+ <-exitchan
+}
+
+// If a request is sent to a closed server via a kept alive connection then
+// the server closes the connection upon receiving the request.
+func TestRequestAfterClose(t *testing.T) {
+ // Given
+ server := NewServer()
+ srvStateChangedCh := make(chan http.ConnState, 100)
+ listener, srvClosedCh := startServer(t, server, srvStateChangedCh)
+
+ client := newClient(listener.Addr(), false)
+ client.Run()
+ <-client.connected
+ client.sendrequest <- true
+ <-client.response
+
+ server.Close()
+ if err := <-srvClosedCh; err != nil {
+ t.Error("Unexpected error during shutdown", err)
+ }
+
+ // When
+ client.sendrequest <- true
+ rr := <-client.response
+
+ // Then
+ if rr.body != nil || rr.err != nil {
+ t.Errorf("Request should be rejected, body=%v, err=%v", rr.body, rr.err)
+ }
+}
+
+func waitForState(t *testing.T, waiter chan http.ConnState, state http.ConnState, errmsg string) {
+ for {
+ select {
+ case ns := <-waiter:
+ if ns == state {
+ return
+ }
+ case <-time.After(time.Second):
+ t.Fatal(errmsg)
+ }
+ }
+}
+
+// Test that a request moving from active->idle->active using an actual
+// network connection still results in a corect shutdown
+func TestStateTransitionActiveIdleActive(t *testing.T) {
+ server := NewServer()
+ wg := helpers.NewWaitGroup()
+ statechanged := make(chan http.ConnState)
+ server.wg = wg
+ listener, exitchan := startServer(t, server, statechanged)
+
+ client := newClient(listener.Addr(), false)
+ client.Run()
+
+ // wait for client to connect, but don't let it send the request
+ if err := <-client.connected; err != nil {
+ t.Fatal("Client failed to connect to server", err)
+ }
+
+ for i := 0; i < 2; i++ {
+ client.sendrequest <- true
+ waitForState(t, statechanged, http.StateActive, "Client failed to reach active state")
+ <-client.response
+ waitForState(t, statechanged, http.StateIdle, "Client failed to reach idle state")
+ }
+
+ // client is now in an idle state
+
+ server.Close()
+ waiting := <-wg.WaitCalled
+ if waiting != 0 {
+ t.Errorf("Waitcount should be zero, got %d", waiting)
+ }
+
+ if err := <-exitchan; err != nil {
+ t.Error("Unexpected error during shutdown", err)
+ }
+}
+
+// Test state transitions from new->active->-idle->closed using an actual
+// network connection and make sure the waitgroup count is correct at the end.
+func TestStateTransitionActiveIdleClosed(t *testing.T) {
+ var (
+ listener net.Listener
+ exitchan chan error
+ )
+
+ keyFile, err1 := helpers.NewTempFile(helpers.Key)
+ certFile, err2 := helpers.NewTempFile(helpers.Cert)
+ defer keyFile.Unlink()
+ defer certFile.Unlink()
+
+ if err1 != nil || err2 != nil {
+ t.Fatal("Failed to create temporary files", err1, err2)
+ }
+
+ for _, withTLS := range []bool{false, true} {
+ server := NewServer()
+ wg := helpers.NewWaitGroup()
+ statechanged := make(chan http.ConnState)
+ server.wg = wg
+ if withTLS {
+ listener, exitchan = startTLSServer(t, server, certFile.Name(), keyFile.Name(), statechanged)
+ } else {
+ listener, exitchan = startServer(t, server, statechanged)
+ }
+
+ client := newClient(listener.Addr(), withTLS)
+ client.Run()
+
+ // wait for client to connect, but don't let it send the request
+ if err := <-client.connected; err != nil {
+ t.Fatal("Client failed to connect to server", err)
+ }
+
+ client.sendrequest <- true
+ waitForState(t, statechanged, http.StateActive, "Client failed to reach active state")
+
+ rr := <-client.response
+ if rr.err != nil {
+ t.Fatalf("tls=%t unexpected error from client %s", withTLS, rr.err)
+ }
+
+ waitForState(t, statechanged, http.StateIdle, "Client failed to reach idle state")
+
+ // client is now in an idle state
+ close(client.sendrequest)
+ <-client.closed
+ waitForState(t, statechanged, http.StateClosed, "Client failed to reach closed state")
+
+ server.Close()
+ waiting := <-wg.WaitCalled
+ if waiting != 0 {
+ t.Errorf("Waitcount should be zero, got %d", waiting)
+ }
+
+ if err := <-exitchan; err != nil {
+ t.Error("Unexpected error during shutdown", err)
+ }
+ }
+}
+
+func TestRoutinesCount(t *testing.T) {
+ var count int
+ server := NewServer()
+
+ count = server.RoutinesCount()
+ if count != 0 {
+ t.Errorf("Expected the routines count to equal 0; actually %d", count)
+ }
+
+ server.StartRoutine()
+ count = server.RoutinesCount()
+ if count != 1 {
+ t.Errorf("Expected the routines count to equal 1; actually %d", count)
+ }
+
+ server.FinishRoutine()
+ count = server.RoutinesCount()
+ if count != 0 {
+ t.Errorf("Expected the routines count to equal 0; actually %d", count)
+ }
+}
diff --git a/vendor/github.com/braintree/manners/test_helpers/certs.go b/vendor/github.com/braintree/manners/test_helpers/certs.go
new file mode 100644
index 000000000..ede248b3d
--- /dev/null
+++ b/vendor/github.com/braintree/manners/test_helpers/certs.go
@@ -0,0 +1,29 @@
+package test_helpers
+
+// A PEM-encoded TLS cert with SAN IPs "127.0.0.1" and "[::1]", expiring at the
+// last second of 2049 (the end of ASN.1 time).
+
+// generated from src/pkg/crypto/tls:
+// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+var (
+ Cert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
+bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
+bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
+IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
+AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
+EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
+AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
+Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+-----END CERTIFICATE-----`)
+
+ Key = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
+0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
+NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
+AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
+MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
+EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
+1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
+-----END RSA PRIVATE KEY-----`)
+)
diff --git a/vendor/github.com/braintree/manners/test_helpers/conn.go b/vendor/github.com/braintree/manners/test_helpers/conn.go
new file mode 100644
index 000000000..8c610f58e
--- /dev/null
+++ b/vendor/github.com/braintree/manners/test_helpers/conn.go
@@ -0,0 +1,13 @@
+package test_helpers
+
+import "net"
+
+type Conn struct {
+ net.Conn
+ CloseCalled bool
+}
+
+func (c *Conn) Close() error {
+ c.CloseCalled = true
+ return nil
+}
diff --git a/vendor/github.com/braintree/manners/test_helpers/listener.go b/vendor/github.com/braintree/manners/test_helpers/listener.go
new file mode 100644
index 000000000..e3af35a6e
--- /dev/null
+++ b/vendor/github.com/braintree/manners/test_helpers/listener.go
@@ -0,0 +1,34 @@
+package test_helpers
+
+import (
+ "errors"
+ "net"
+)
+
+type Listener struct {
+ AcceptRelease chan bool
+ CloseCalled chan bool
+}
+
+func NewListener() *Listener {
+ return &Listener{
+ make(chan bool, 1),
+ make(chan bool, 1),
+ }
+}
+
+func (l *Listener) Addr() net.Addr {
+ addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")
+ return addr
+}
+
+func (l *Listener) Close() error {
+ l.CloseCalled <- true
+ l.AcceptRelease <- true
+ return nil
+}
+
+func (l *Listener) Accept() (net.Conn, error) {
+ <-l.AcceptRelease
+ return nil, errors.New("connection closed")
+}
diff --git a/vendor/github.com/braintree/manners/test_helpers/temp_file.go b/vendor/github.com/braintree/manners/test_helpers/temp_file.go
new file mode 100644
index 000000000..c4aa263a0
--- /dev/null
+++ b/vendor/github.com/braintree/manners/test_helpers/temp_file.go
@@ -0,0 +1,27 @@
+package test_helpers
+
+import (
+ "io/ioutil"
+ "os"
+)
+
+type TempFile struct {
+ *os.File
+}
+
+func NewTempFile(content []byte) (*TempFile, error) {
+ f, err := ioutil.TempFile("", "graceful-test")
+ if err != nil {
+ return nil, err
+ }
+
+ f.Write(content)
+ return &TempFile{f}, nil
+}
+
+func (tf *TempFile) Unlink() {
+ if tf.File != nil {
+ os.Remove(tf.Name())
+ tf.File = nil
+ }
+}
diff --git a/vendor/github.com/braintree/manners/test_helpers/wait_group.go b/vendor/github.com/braintree/manners/test_helpers/wait_group.go
new file mode 100644
index 000000000..1df590db7
--- /dev/null
+++ b/vendor/github.com/braintree/manners/test_helpers/wait_group.go
@@ -0,0 +1,33 @@
+package test_helpers
+
+import "sync"
+
+type WaitGroup struct {
+ sync.Mutex
+ Count int
+ WaitCalled chan int
+}
+
+func NewWaitGroup() *WaitGroup {
+ return &WaitGroup{
+ WaitCalled: make(chan int, 1),
+ }
+}
+
+func (wg *WaitGroup) Add(delta int) {
+ wg.Lock()
+ wg.Count++
+ wg.Unlock()
+}
+
+func (wg *WaitGroup) Done() {
+ wg.Lock()
+ wg.Count--
+ wg.Unlock()
+}
+
+func (wg *WaitGroup) Wait() {
+ wg.Lock()
+ wg.WaitCalled <- wg.Count
+ wg.Unlock()
+}
diff --git a/vendor/github.com/braintree/manners/transition_test.go b/vendor/github.com/braintree/manners/transition_test.go
new file mode 100644
index 000000000..5d398514e
--- /dev/null
+++ b/vendor/github.com/braintree/manners/transition_test.go
@@ -0,0 +1,54 @@
+package manners
+
+import (
+ helpers "github.com/braintree/manners/test_helpers"
+ "net/http"
+ "strings"
+ "testing"
+)
+
+func TestStateTransitions(t *testing.T) {
+ tests := []transitionTest{
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive}, 1},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateClosed}, 0},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateClosed}, 0},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateHijacked}, 0},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle}, 0},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive}, 1},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateIdle}, 0},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateClosed}, 0},
+ transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateIdle, http.StateClosed}, 0},
+ }
+
+ for _, test := range tests {
+ testStateTransition(t, test)
+ }
+}
+
+type transitionTest struct {
+ states []http.ConnState
+ expectedWgCount int
+}
+
+func testStateTransition(t *testing.T, test transitionTest) {
+ server := NewServer()
+ wg := helpers.NewWaitGroup()
+ server.wg = wg
+ startServer(t, server, nil)
+
+ conn := &helpers.Conn{}
+ for _, newState := range test.states {
+ server.ConnState(conn, newState)
+ }
+
+ server.Close()
+ waiting := <-wg.WaitCalled
+ if waiting != test.expectedWgCount {
+ names := make([]string, len(test.states))
+ for i, s := range test.states {
+ names[i] = s.String()
+ }
+ transitions := strings.Join(names, " -> ")
+ t.Errorf("%s - Waitcount should be %d, got %d", transitions, test.expectedWgCount, waiting)
+ }
+}
diff --git a/vendor/github.com/cloudfoundry/jibber_jabber/ci/scripts/windows-64-test.bat b/vendor/github.com/cloudfoundry/jibber_jabber/ci/scripts/windows-64-test.bat
new file mode 100755
index 000000000..b9a87bf7a
--- /dev/null
+++ b/vendor/github.com/cloudfoundry/jibber_jabber/ci/scripts/windows-64-test.bat
@@ -0,0 +1,5 @@
+git fetch
+git checkout %GIT_COMMIT%
+
+SET GOPATH=%CD%\Godeps\_workspace;c:\Users\Administrator\go
+c:\Go\bin\go test -v .
diff --git a/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_suite_test.go b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_suite_test.go
new file mode 100644
index 000000000..3da19c84b
--- /dev/null
+++ b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_suite_test.go
@@ -0,0 +1,13 @@
+package jibber_jabber_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestJibberJabber(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Jibber Jabber Suite")
+}
diff --git a/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix_test.go b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix_test.go
new file mode 100644
index 000000000..a5e3074a2
--- /dev/null
+++ b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_unix_test.go
@@ -0,0 +1,104 @@
+// +build darwin freebsd linux netbsd openbsd
+
+package jibber_jabber_test
+
+import (
+ "os"
+
+ . "github.com/cloudfoundry/jibber_jabber"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Unix", func() {
+ AfterEach(func() {
+ os.Setenv("LC_ALL", "")
+ os.Setenv("LANG", "en_US.UTF-8")
+ })
+
+ Describe("#DetectIETF", func() {
+ Context("Returns IETF encoded locale", func() {
+ It("should return the locale set to LC_ALL", func() {
+ os.Setenv("LC_ALL", "fr_FR.UTF-8")
+ result, _ := DetectIETF()
+ Ω(result).Should(Equal("fr-FR"))
+ })
+
+ It("should return the locale set to LANG if LC_ALL isn't set", func() {
+ os.Setenv("LANG", "fr_FR.UTF-8")
+
+ result, _ := DetectIETF()
+ Ω(result).Should(Equal("fr-FR"))
+ })
+
+ It("should return an error if it cannot detect a locale", func() {
+ os.Setenv("LANG", "")
+
+ _, err := DetectIETF()
+ Ω(err.Error()).Should(Equal(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE))
+ })
+ })
+
+ Context("when the locale is simply 'fr'", func() {
+ BeforeEach(func() {
+ os.Setenv("LANG", "fr")
+ })
+
+ It("should return the locale without a territory", func() {
+ language, err := DetectIETF()
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(language).Should(Equal("fr"))
+ })
+ })
+ })
+
+ Describe("#DetectLanguage", func() {
+ Context("Returns encoded language", func() {
+ It("should return the language set to LC_ALL", func() {
+ os.Setenv("LC_ALL", "fr_FR.UTF-8")
+ result, _ := DetectLanguage()
+ Ω(result).Should(Equal("fr"))
+ })
+
+ It("should return the language set to LANG if LC_ALL isn't set", func() {
+ os.Setenv("LANG", "fr_FR.UTF-8")
+
+ result, _ := DetectLanguage()
+ Ω(result).Should(Equal("fr"))
+ })
+
+ It("should return an error if it cannot detect a language", func() {
+ os.Setenv("LANG", "")
+
+ _, err := DetectLanguage()
+ Ω(err.Error()).Should(Equal(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE))
+ })
+ })
+ })
+
+ Describe("#DetectTerritory", func() {
+ Context("Returns encoded territory", func() {
+ It("should return the territory set to LC_ALL", func() {
+ os.Setenv("LC_ALL", "fr_FR.UTF-8")
+ result, _ := DetectTerritory()
+ Ω(result).Should(Equal("FR"))
+ })
+
+ It("should return the territory set to LANG if LC_ALL isn't set", func() {
+ os.Setenv("LANG", "fr_FR.UTF-8")
+
+ result, _ := DetectTerritory()
+ Ω(result).Should(Equal("FR"))
+ })
+
+ It("should return an error if it cannot detect a territory", func() {
+ os.Setenv("LANG", "")
+
+ _, err := DetectTerritory()
+ Ω(err.Error()).Should(Equal(COULD_NOT_DETECT_PACKAGE_ERROR_MESSAGE))
+ })
+ })
+ })
+
+})
diff --git a/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows_test.go b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows_test.go
new file mode 100644
index 000000000..f325d981e
--- /dev/null
+++ b/vendor/github.com/cloudfoundry/jibber_jabber/jibber_jabber_windows_test.go
@@ -0,0 +1,51 @@
+// +build windows
+
+package jibber_jabber_test
+
+import (
+ "regexp"
+
+ . "github.com/cloudfoundry/jibber_jabber"
+
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+const (
+ LOCALE_REGEXP = "^[a-z]{2}-[A-Z]{2}$"
+ LANGUAGE_REGEXP = "^[a-z]{2}$"
+ TERRITORY_REGEXP = "^[A-Z]{2}$"
+)
+
+var _ = Describe("Windows", func() {
+ BeforeEach(func() {
+ locale, err := DetectIETF()
+ Ω(err).Should(BeNil())
+ Ω(locale).ShouldNot(BeNil())
+ Ω(locale).ShouldNot(Equal(""))
+ })
+
+ Describe("#DetectIETF", func() {
+ It("detects correct IETF locale", func() {
+ locale, _ := DetectIETF()
+ matched, _ := regexp.MatchString(LOCALE_REGEXP, locale)
+ Ω(matched).Should(BeTrue())
+ })
+ })
+
+ Describe("#DetectLanguage", func() {
+ It("detects correct Language", func() {
+ language, _ := DetectLanguage()
+ matched, _ := regexp.MatchString(LANGUAGE_REGEXP, language)
+ Ω(matched).Should(BeTrue())
+ })
+ })
+
+ Describe("#DetectTerritory", func() {
+ It("detects correct Territory", func() {
+ territory, _ := DetectTerritory()
+ matched, _ := regexp.MatchString(TERRITORY_REGEXP, territory)
+ Ω(matched).Should(BeTrue())
+ })
+ })
+})
diff --git a/vendor/github.com/dgryski/dgoogauth/googauth_test.go b/vendor/github.com/dgryski/dgoogauth/googauth_test.go
new file mode 100644
index 000000000..031922c47
--- /dev/null
+++ b/vendor/github.com/dgryski/dgoogauth/googauth_test.go
@@ -0,0 +1,251 @@
+package dgoogauth
+
+import (
+ "strconv"
+ "testing"
+ "time"
+)
+
+// Test vectors via:
+// http://code.google.com/p/google-authenticator/source/browse/libpam/pam_google_authenticator_unittest.c
+// https://google-authenticator.googlecode.com/hg/libpam/totp.html
+
+var codeTests = []struct {
+ secret string
+ value int64
+ code int
+}{
+ {"2SH3V3GDW7ZNMGYE", 1, 293240},
+ {"2SH3V3GDW7ZNMGYE", 5, 932068},
+ {"2SH3V3GDW7ZNMGYE", 10000, 50548},
+}
+
+func TestCode(t *testing.T) {
+
+ for _, v := range codeTests {
+ c := ComputeCode(v.secret, v.value)
+
+ if c != v.code {
+ t.Errorf("computeCode(%s, %d): got %d expected %d\n", v.secret, v.value, c, v.code)
+ }
+
+ }
+}
+
+func TestScratchCode(t *testing.T) {
+
+ var cotp OTPConfig
+
+ cotp.ScratchCodes = []int{11112222, 22223333}
+
+ var scratchTests = []struct {
+ code int
+ result bool
+ }{
+ {33334444, false},
+ {11112222, true},
+ {11112222, false},
+ {22223333, true},
+ {22223333, false},
+ {33334444, false},
+ }
+
+ for _, s := range scratchTests {
+ r := cotp.checkScratchCodes(s.code)
+ if r != s.result {
+ t.Errorf("scratchcode(%d) failed: got %t expected %t", s.code, r, s.result)
+ }
+ }
+}
+
+func TestHotpCode(t *testing.T) {
+
+ var cotp OTPConfig
+
+ // reuse our test values from above
+ // perhaps create more?
+ cotp.Secret = "2SH3V3GDW7ZNMGYE"
+ cotp.HotpCounter = 1
+ cotp.WindowSize = 3
+
+ var counterCodes = []struct {
+ code int
+ result bool
+ counter int
+ }{
+ { /* 1 */ 293240, true, 2}, // increments on success
+ { /* 1 */ 293240, false, 3}, // and failure
+ { /* 5 */ 932068, true, 6}, // inside of window
+ { /* 10 */ 481725, false, 7}, // outside of window
+ { /* 10 */ 481725, false, 8}, // outside of window
+ { /* 10 */ 481725, true, 11}, // now inside of window
+ }
+
+ for i, s := range counterCodes {
+ r := cotp.checkHotpCode(s.code)
+ if r != s.result {
+ t.Errorf("counterCode(%d) (step %d) failed: got %t expected %t", s.code, i, r, s.result)
+ }
+ if cotp.HotpCounter != s.counter {
+ t.Errorf("hotpCounter incremented poorly: got %d expected %d", cotp.HotpCounter, s.counter)
+ }
+ }
+}
+
+func TestTotpCode(t *testing.T) {
+
+ var cotp OTPConfig
+
+ // reuse our test values from above
+ cotp.Secret = "2SH3V3GDW7ZNMGYE"
+ cotp.WindowSize = 5
+
+ var windowTest = []struct {
+ code int
+ t0 int
+ result bool
+ }{
+ {50548, 9997, false},
+ {50548, 9998, true},
+ {50548, 9999, true},
+ {50548, 10000, true},
+ {50548, 10001, true},
+ {50548, 10002, true},
+ {50548, 10003, false},
+ }
+
+ for i, s := range windowTest {
+ r := cotp.checkTotpCode(s.t0, s.code)
+ if r != s.result {
+ t.Errorf("counterCode(%d) (step %d) failed: got %t expected %t", s.code, i, r, s.result)
+ }
+ }
+
+ cotp.DisallowReuse = make([]int, 0)
+ var noreuseTest = []struct {
+ code int
+ t0 int
+ result bool
+ disallowed []int
+ }{
+ {50548 /* 10000 */, 9997, false, []int{}},
+ {50548 /* 10000 */, 9998, true, []int{10000}},
+ {50548 /* 10000 */, 9999, false, []int{10000}},
+ {478726 /* 10001 */, 10001, true, []int{10000, 10001}},
+ {646986 /* 10002 */, 10002, true, []int{10000, 10001, 10002}},
+ {842639 /* 10003 */, 10003, true, []int{10001, 10002, 10003}},
+ }
+
+ for i, s := range noreuseTest {
+ r := cotp.checkTotpCode(s.t0, s.code)
+ if r != s.result {
+ t.Errorf("timeCode(%d) (step %d) failed: got %t expected %t", s.code, i, r, s.result)
+ }
+ if len(cotp.DisallowReuse) != len(s.disallowed) {
+ t.Errorf("timeCode(%d) (step %d) failed: disallowReuse len mismatch: got %d expected %d", s.code, i, len(cotp.DisallowReuse), len(s.disallowed))
+ } else {
+ same := true
+ for j := range s.disallowed {
+ if s.disallowed[j] != cotp.DisallowReuse[j] {
+ same = false
+ }
+ }
+ if !same {
+ t.Errorf("timeCode(%d) (step %d) failed: disallowReused: got %v expected %v", s.code, i, cotp.DisallowReuse, s.disallowed)
+ }
+ }
+ }
+}
+
+func TestAuthenticate(t *testing.T) {
+
+ otpconf := &OTPConfig{
+ Secret: "2SH3V3GDW7ZNMGYE",
+ WindowSize: 3,
+ HotpCounter: 1,
+ ScratchCodes: []int{11112222, 22223333},
+ }
+
+ type attempt struct {
+ code string
+ result bool
+ }
+
+ var attempts = []attempt{
+ {"foobar", false}, // not digits
+ {"1fooba", false}, // not valid number
+ {"1111111", false}, // bad length
+ { /* 1 */ "293240", true}, // hopt increments on success
+ { /* 1 */ "293240", false}, // hopt failure
+ {"33334444", false}, // scratch
+ {"11112222", true},
+ {"11112222", false},
+ }
+
+ for _, a := range attempts {
+ r, _ := otpconf.Authenticate(a.code)
+ if r != a.result {
+ t.Errorf("bad result from code=%s: got %t expected %t\n", a.code, r, a.result)
+ }
+ }
+
+ // let's check some time-based codes
+ otpconf.HotpCounter = 0
+ // I haven't mocked the clock, so we'll just compute one
+ var t0 int64
+ if otpconf.UTC {
+ t0 = int64(time.Now().UTC().Unix() / 30)
+ } else {
+ t0 = int64(time.Now().Unix() / 30)
+ }
+ c := ComputeCode(otpconf.Secret, t0)
+
+ invalid := c + 1
+ attempts = []attempt{
+ {strconv.Itoa(invalid), false},
+ {strconv.Itoa(c), true},
+ }
+
+ for _, a := range attempts {
+ r, _ := otpconf.Authenticate(a.code)
+ if r != a.result {
+ t.Errorf("bad result from code=%s: got %t expected %t\n", a.code, r, a.result)
+ }
+
+ otpconf.UTC = true
+ r, _ = otpconf.Authenticate(a.code)
+ if r != a.result {
+ t.Errorf("bad result from code=%s: got %t expected %t\n", a.code, r, a.result)
+ }
+ otpconf.UTC = false
+ }
+
+}
+
+func TestProvisionURI(t *testing.T) {
+ otpconf := OTPConfig{
+ Secret: "x",
+ }
+
+ cases := []struct {
+ user, iss string
+ hotp bool
+ out string
+ }{
+ {"test", "", false, "otpauth://totp/test?secret=x"},
+ {"test", "", true, "otpauth://hotp/test?counter=1&secret=x"},
+ {"test", "Company", true, "otpauth://hotp/Company:test?counter=1&issuer=Company&secret=x"},
+ {"test", "Company", false, "otpauth://totp/Company:test?issuer=Company&secret=x"},
+ }
+
+ for i, c := range cases {
+ otpconf.HotpCounter = 0
+ if c.hotp {
+ otpconf.HotpCounter = 1
+ }
+ got := otpconf.ProvisionURIWithIssuer(c.user, c.iss)
+ if got != c.out {
+ t.Errorf("%d: want %q, got %q", i, c.out, got)
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/adjust_test.go b/vendor/github.com/disintegration/imaging/adjust_test.go
new file mode 100644
index 000000000..99898b0dc
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/adjust_test.go
@@ -0,0 +1,504 @@
+package imaging
+
+import (
+ "image"
+ "testing"
+)
+
+func TestGrayscale(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Grayscale 3x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x3d, 0x3d, 0x3d, 0x01, 0x78, 0x78, 0x78, 0x02, 0x17, 0x17, 0x17, 0x03,
+ 0x1f, 0x1f, 0x1f, 0xff, 0x25, 0x25, 0x25, 0xff, 0x66, 0x66, 0x66, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Grayscale(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestInvert(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Invert 3x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x33, 0xff, 0xff, 0x01, 0xff, 0x33, 0xff, 0x02, 0xff, 0xff, 0x33, 0x03,
+ 0xee, 0xdd, 0xcc, 0xff, 0xcc, 0xdd, 0xee, 0xff, 0x55, 0xcc, 0x44, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Invert(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestAdjustContrast(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ p float64
+ want *image.NRGBA
+ }{
+ {
+ "AdjustContrast 3x3 10",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 10,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xd5, 0x00, 0x00, 0x01, 0x00, 0xd5, 0x00, 0x02, 0x00, 0x00, 0xd5, 0x03,
+ 0x05, 0x18, 0x2b, 0xff, 0x2b, 0x18, 0x05, 0xff, 0xaf, 0x2b, 0xc2, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustContrast 3x3 100",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 100,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x02, 0x00, 0x00, 0xff, 0x03,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustContrast 3x3 -10",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ -10,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xc4, 0x0d, 0x0d, 0x01, 0x0d, 0xc4, 0x0d, 0x02, 0x0d, 0x0d, 0xc4, 0x03,
+ 0x1c, 0x2b, 0x3b, 0xff, 0x3b, 0x2b, 0x1c, 0xff, 0xa6, 0x3b, 0xb5, 0xff,
+ 0x0d, 0x0d, 0x0d, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xf2, 0xf2, 0xf2, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustContrast 3x3 -100",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ -100,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x80, 0x80, 0x80, 0x01, 0x80, 0x80, 0x80, 0x02, 0x80, 0x80, 0x80, 0x03,
+ 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff,
+ 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustContrast 3x3 0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := AdjustContrast(d.src, d.p)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestAdjustBrightness(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ p float64
+ want *image.NRGBA
+ }{
+ {
+ "AdjustBrightness 3x3 10",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 10,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xe6, 0x1a, 0x1a, 0x01, 0x1a, 0xe6, 0x1a, 0x02, 0x1a, 0x1a, 0xe6, 0x03,
+ 0x2b, 0x3c, 0x4d, 0xff, 0x4d, 0x3c, 0x2b, 0xff, 0xc4, 0x4d, 0xd5, 0xff,
+ 0x1a, 0x1a, 0x1a, 0xff, 0x4d, 0x4d, 0x4d, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustBrightness 3x3 100",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 100,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0x03,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustBrightness 3x3 -10",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ -10,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xb3, 0x00, 0x00, 0x01, 0x00, 0xb3, 0x00, 0x02, 0x00, 0x00, 0xb3, 0x03,
+ 0x00, 0x09, 0x1a, 0xff, 0x1a, 0x09, 0x00, 0xff, 0x91, 0x1a, 0xa2, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x1a, 0x1a, 0x1a, 0xff, 0xe6, 0xe6, 0xe6, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustBrightness 3x3 -100",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ -100,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustBrightness 3x3 0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := AdjustBrightness(d.src, d.p)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestAdjustGamma(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ p float64
+ want *image.NRGBA
+ }{
+ {
+ "AdjustGamma 3x3 0.75",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 0.75,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xbd, 0x00, 0x00, 0x01, 0x00, 0xbd, 0x00, 0x02, 0x00, 0x00, 0xbd, 0x03,
+ 0x07, 0x11, 0x1e, 0xff, 0x1e, 0x11, 0x07, 0xff, 0x95, 0x1e, 0xa9, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x1e, 0x1e, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustGamma 3x3 1.5",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 1.5,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xdc, 0x00, 0x00, 0x01, 0x00, 0xdc, 0x00, 0x02, 0x00, 0x00, 0xdc, 0x03,
+ 0x2a, 0x43, 0x57, 0xff, 0x57, 0x43, 0x2a, 0xff, 0xc3, 0x57, 0xcf, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x57, 0x57, 0x57, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustGamma 3x3 1.0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 1.0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := AdjustGamma(d.src, d.p)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestAdjustSigmoid(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ m float64
+ p float64
+ want *image.NRGBA
+ }{
+ {
+ "AdjustSigmoid 3x3 0.5 3.0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 0.5,
+ 3.0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xd4, 0x00, 0x00, 0x01, 0x00, 0xd4, 0x00, 0x02, 0x00, 0x00, 0xd4, 0x03,
+ 0x0d, 0x1b, 0x2b, 0xff, 0x2b, 0x1b, 0x0d, 0xff, 0xb1, 0x2b, 0xc3, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x2b, 0x2b, 0x2b, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustSigmoid 3x3 0.5 -3.0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 0.5,
+ -3.0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xc4, 0x00, 0x00, 0x01, 0x00, 0xc4, 0x00, 0x02, 0x00, 0x00, 0xc4, 0x03,
+ 0x16, 0x2a, 0x3b, 0xff, 0x3b, 0x2a, 0x16, 0xff, 0xa4, 0x3b, 0xb3, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "AdjustSigmoid 3x3 0.5 0.0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 0.5,
+ 0.0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0x00, 0x00, 0x01, 0x00, 0xcc, 0x00, 0x02, 0x00, 0x00, 0xcc, 0x03,
+ 0x11, 0x22, 0x33, 0xff, 0x33, 0x22, 0x11, 0xff, 0xaa, 0x33, 0xbb, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x33, 0x33, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := AdjustSigmoid(d.src, d.m, d.p)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/effects_test.go b/vendor/github.com/disintegration/imaging/effects_test.go
new file mode 100644
index 000000000..a7e8cfffe
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/effects_test.go
@@ -0,0 +1,190 @@
+package imaging
+
+import (
+ "image"
+ "testing"
+)
+
+func TestBlur(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ sigma float64
+ want *image.NRGBA
+ }{
+ {
+ "Blur 3x3 0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ },
+ 0.0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ },
+ },
+ {
+ "Blur 3x3 0.5",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ },
+ 0.5,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x01, 0x02, 0x04, 0x04, 0x0a, 0x10, 0x18, 0x18, 0x01, 0x02, 0x04, 0x04,
+ 0x09, 0x10, 0x18, 0x18, 0x3f, 0x69, 0x9e, 0x9e, 0x09, 0x10, 0x18, 0x18,
+ 0x01, 0x02, 0x04, 0x04, 0x0a, 0x10, 0x18, 0x18, 0x01, 0x02, 0x04, 0x04,
+ },
+ },
+ },
+ {
+ "Blur 3x3 10",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x66, 0xaa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ },
+ 10,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c,
+ 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c,
+ 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c, 0x0b, 0x13, 0x1c, 0x1c,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Blur(d.src, d.sigma)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestSharpen(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ sigma float64
+ want *image.NRGBA
+ }{
+ {
+ "Sharpen 3x3 0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ },
+ },
+ 0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ },
+ },
+ },
+ {
+ "Sharpen 3x3 0.5",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ },
+ },
+ 0.5,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
+ 0x64, 0x64, 0x64, 0x64, 0x7e, 0x7e, 0x7e, 0x7e, 0x64, 0x64, 0x64, 0x64,
+ 0x66, 0x66, 0x66, 0x66, 0x64, 0x64, 0x64, 0x64, 0x66, 0x66, 0x66, 0x66,
+ },
+ },
+ },
+ {
+ "Sharpen 3x3 100",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x77, 0x77, 0x77, 0x77, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ },
+ },
+ 100,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 3),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
+ 0x64, 0x64, 0x64, 0x64, 0x86, 0x86, 0x86, 0x86, 0x64, 0x64, 0x64, 0x64,
+ 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
+ },
+ },
+ },
+ {
+ "Sharpen 3x1 10",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 0),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 10,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 1),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Sharpen(d.src, d.sigma)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/helpers_test.go b/vendor/github.com/disintegration/imaging/helpers_test.go
new file mode 100644
index 000000000..1287ec588
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/helpers_test.go
@@ -0,0 +1,399 @@
+package imaging
+
+import (
+ "bytes"
+ "image"
+ "image/color"
+ "testing"
+)
+
+func compareNRGBA(img1, img2 *image.NRGBA, delta int) bool {
+ if !img1.Rect.Eq(img2.Rect) {
+ return false
+ }
+
+ if len(img1.Pix) != len(img2.Pix) {
+ return false
+ }
+
+ for i := 0; i < len(img1.Pix); i++ {
+ if absint(int(img1.Pix[i])-int(img2.Pix[i])) > delta {
+ return false
+ }
+ }
+
+ return true
+}
+
+func TestEncodeDecode(t *testing.T) {
+ imgWithAlpha := image.NewNRGBA(image.Rect(0, 0, 3, 3))
+ imgWithAlpha.Pix = []uint8{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
+ 244, 245, 246, 247, 248, 249, 250, 252, 252, 253, 254, 255,
+ }
+
+ imgWithoutAlpha := image.NewNRGBA(image.Rect(0, 0, 3, 3))
+ imgWithoutAlpha.Pix = []uint8{
+ 0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 10, 255,
+ 127, 128, 129, 255, 131, 132, 133, 255, 135, 136, 137, 255,
+ 244, 245, 246, 255, 248, 249, 250, 255, 252, 253, 254, 255,
+ }
+
+ for _, format := range []Format{JPEG, PNG, GIF, BMP, TIFF} {
+ img := imgWithoutAlpha
+ if format == PNG {
+ img = imgWithAlpha
+ }
+
+ buf := &bytes.Buffer{}
+ err := Encode(buf, img, format)
+ if err != nil {
+ t.Errorf("fail encoding format %s", format)
+ continue
+ }
+
+ img2, err := Decode(buf)
+ if err != nil {
+ t.Errorf("fail decoding format %s", format)
+ continue
+ }
+ img2cloned := Clone(img2)
+
+ delta := 0
+ if format == JPEG {
+ delta = 3
+ } else if format == GIF {
+ delta = 16
+ }
+
+ if !compareNRGBA(img, img2cloned, delta) {
+ t.Errorf("test [DecodeEncode %s] failed: %#v %#v", format, img, img2cloned)
+ continue
+ }
+ }
+
+ buf := &bytes.Buffer{}
+ err := Encode(buf, imgWithAlpha, JPEG)
+ if err != nil {
+ t.Errorf("failed encoding alpha to JPEG format %s", err)
+ }
+
+ buf = &bytes.Buffer{}
+ err = Encode(buf, imgWithAlpha, Format(100))
+ if err != ErrUnsupportedFormat {
+ t.Errorf("expected ErrUnsupportedFormat")
+ }
+
+ buf = bytes.NewBuffer([]byte("bad data"))
+ _, err = Decode(buf)
+ if err == nil {
+ t.Errorf("decoding bad data, expected error")
+ }
+}
+
+func TestNew(t *testing.T) {
+ td := []struct {
+ desc string
+ w, h int
+ c color.Color
+ dstBounds image.Rectangle
+ dstPix []uint8
+ }{
+ {
+ "New 1x1 black",
+ 1, 1,
+ color.NRGBA{0, 0, 0, 0},
+ image.Rect(0, 0, 1, 1),
+ []uint8{0x00, 0x00, 0x00, 0x00},
+ },
+ {
+ "New 1x2 red",
+ 1, 2,
+ color.NRGBA{255, 0, 0, 255},
+ image.Rect(0, 0, 1, 2),
+ []uint8{0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff},
+ },
+ {
+ "New 2x1 white",
+ 2, 1,
+ color.NRGBA{255, 255, 255, 255},
+ image.Rect(0, 0, 2, 1),
+ []uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ },
+ {
+ "New 0x0 white",
+ 0, 0,
+ color.NRGBA{255, 255, 255, 255},
+ image.Rect(0, 0, 0, 0),
+ nil,
+ },
+ }
+
+ for _, d := range td {
+ got := New(d.w, d.h, d.c)
+ want := image.NewNRGBA(d.dstBounds)
+ want.Pix = d.dstPix
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestClone(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Clone NRGBA",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone NRGBA64",
+ &image.NRGBA64{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 8,
+ Pix: []uint8{
+ 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone RGBA",
+ &image.RGBA{
+ Rect: image.Rect(-1, -1, 0, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 3),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone RGBA64",
+ &image.RGBA64{
+ Rect: image.Rect(-1, -1, 0, 2),
+ Stride: 1 * 8,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
+ 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 3),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone Gray",
+ &image.Gray{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 1,
+ Pix: []uint8{0x11, 0xee},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone Gray16",
+ &image.Gray16{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 2,
+ Pix: []uint8{0x11, 0x11, 0xee, 0xee},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
+ },
+ },
+ {
+ "Clone Alpha",
+ &image.Alpha{
+ Rect: image.Rect(-1, -1, 0, 1),
+ Stride: 1 * 1,
+ Pix: []uint8{0x11, 0xee},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
+ },
+ },
+ {
+ "Clone YCbCr",
+ &image.YCbCr{
+ Rect: image.Rect(-1, -1, 5, 0),
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
+ YStride: 6,
+ CStride: 6,
+ Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
+ Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
+ Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 6, 1),
+ Stride: 6 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x7f, 0x7f, 0x7f, 0xff,
+ 0x7f, 0x00, 0x00, 0xff,
+ 0x00, 0x7f, 0x00, 0xff,
+ 0x00, 0x00, 0x7f, 0xff,
+ },
+ },
+ },
+ {
+ "Clone YCbCr 444",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
+ Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
+ YStride: 4,
+ CStride: 4,
+ SubsampleRatio: image.YCbCrSubsampleRatio444,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone YCbCr 440",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
+ Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
+ YStride: 4,
+ CStride: 4,
+ SubsampleRatio: image.YCbCrSubsampleRatio440,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone YCbCr 422",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
+ Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
+ YStride: 4,
+ CStride: 2,
+ SubsampleRatio: image.YCbCrSubsampleRatio422,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone YCbCr 420",
+ &image.YCbCr{
+ Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
+ Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
+ Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
+ YStride: 4, CStride: 2,
+ SubsampleRatio: image.YCbCrSubsampleRatio420,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ &image.NRGBA{
+ Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
+ Stride: 16,
+ Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
+ },
+ },
+ {
+ "Clone Paletted",
+ &image.Paletted{
+ Rect: image.Rect(-1, -1, 5, 0),
+ Stride: 6 * 1,
+ Palette: color.Palette{
+ color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
+ color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
+ color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
+ color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
+ color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
+ color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
+ },
+ Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 6, 1),
+ Stride: 6 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ 0x7f, 0x7f, 0x7f, 0xff,
+ 0x7f, 0x00, 0x00, 0xff,
+ 0x00, 0x7f, 0x00, 0xff,
+ 0x00, 0x00, 0x7f, 0xff,
+ },
+ },
+ },
+ }
+
+ for _, d := range td {
+ got := Clone(d.src)
+ want := d.want
+
+ delta := 0
+ if _, ok := d.src.(*image.YCbCr); ok {
+ delta = 1
+ }
+
+ if !compareNRGBA(got, want, delta) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestFormats(t *testing.T) {
+ formatNames := map[Format]string{
+ JPEG: "JPEG",
+ PNG: "PNG",
+ GIF: "GIF",
+ BMP: "BMP",
+ TIFF: "TIFF",
+ Format(-1): "Unsupported",
+ }
+ for format, name := range formatNames {
+ got := format.String()
+ if got != name {
+ t.Errorf("test [Format names] failed: got %#v want %#v", got, name)
+ continue
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/resize_test.go b/vendor/github.com/disintegration/imaging/resize_test.go
new file mode 100644
index 000000000..08d7f2d85
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/resize_test.go
@@ -0,0 +1,570 @@
+package imaging
+
+import (
+ "image"
+ "testing"
+)
+
+func TestResize(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ w, h int
+ f ResampleFilter
+ want *image.NRGBA
+ }{
+ {
+ "Resize 2x2 1x1 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 1, 1,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
+ },
+ },
+ {
+ "Resize 2x2 2x2 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 2, 2,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "Resize 3x1 1x1 nearest",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 2, 0),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 1, 1,
+ NearestNeighbor,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x00, 0xff, 0x00, 0xff},
+ },
+ },
+ {
+ "Resize 2x2 0x4 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 0, 4,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 4, 4),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "Resize 2x2 4x0 linear",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 4, 0,
+ Linear,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 4, 4),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0xbf, 0x00, 0x00, 0xbf, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0x40, 0x00, 0x40, 0x30, 0x30, 0x10, 0x70, 0x8f, 0x10, 0x30, 0xcf, 0xbf, 0x00, 0x40, 0xff,
+ 0x00, 0xbf, 0x00, 0xbf, 0x10, 0x8f, 0x30, 0xcf, 0x30, 0x30, 0x8f, 0xef, 0x40, 0x00, 0xbf, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xbf, 0x40, 0xff, 0x00, 0x40, 0xbf, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "Resize 0x0 1x1 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, -1, -1),
+ Stride: 0,
+ Pix: []uint8{},
+ },
+ 1, 1,
+ Box,
+ &image.NRGBA{},
+ },
+ {
+ "Resize 2x2 0x0 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 0, 0,
+ Box,
+ &image.NRGBA{},
+ },
+ {
+ "Resize 2x2 -1x0 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ -1, 0,
+ Box,
+ &image.NRGBA{},
+ },
+ }
+ for _, d := range td {
+ got := Resize(d.src, d.w, d.h, d.f)
+ want := d.want
+ if !compareNRGBA(got, want, 1) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+
+ for i, filter := range []ResampleFilter{
+ NearestNeighbor,
+ Box,
+ Linear,
+ Hermite,
+ MitchellNetravali,
+ CatmullRom,
+ BSpline,
+ Gaussian,
+ Lanczos,
+ Hann,
+ Hamming,
+ Blackman,
+ Bartlett,
+ Welch,
+ Cosine,
+ } {
+ src := image.NewNRGBA(image.Rect(-1, -1, 2, 3))
+ got := Resize(src, 5, 6, filter)
+ want := image.NewNRGBA(image.Rect(0, 0, 5, 6))
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [Resize all filters #%d] failed: %#v", i, got)
+ }
+
+ if filter.Kernel != nil {
+ x := filter.Kernel(filter.Support + 0.0001)
+ if x != 0 {
+ t.Errorf("test [ResampleFilter edge cases #%d] failed: %f", i, x)
+ }
+ }
+ }
+
+ bcs2 := bcspline(2, 1, 0)
+ if bcs2 != 0 {
+ t.Errorf("test [bcspline 2] failed: %f", bcs2)
+ }
+}
+
+func TestFit(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ w, h int
+ f ResampleFilter
+ want *image.NRGBA
+ }{
+ {
+ "Fit 2x2 1x10 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 1, 10,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
+ },
+ },
+ {
+ "Fit 2x2 10x1 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 10, 1,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
+ },
+ },
+ {
+ "Fit 2x2 10x10 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 10, 10,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ },
+ {
+ "Fit 0x0 1x1 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, -1, -1),
+ Stride: 0,
+ Pix: []uint8{},
+ },
+ 1, 1,
+ Box,
+ &image.NRGBA{},
+ },
+ {
+ "Fit 2x2 0x0 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ 0, 0,
+ Box,
+ &image.NRGBA{},
+ },
+ {
+ "Fit 2x2 -1x0 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ },
+ },
+ -1, 0,
+ Box,
+ &image.NRGBA{},
+ },
+ }
+ for _, d := range td {
+ got := Fit(d.src, d.w, d.h, d.f)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestFill(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ w, h int
+ a Anchor
+ f ResampleFilter
+ want *image.NRGBA
+ }{
+ {
+ "Fill 4x4 2x2 Center Nearest",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ Center,
+ NearestNeighbor,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x14, 0x15, 0x16, 0x17, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x34, 0x35, 0x36, 0x37, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ },
+ {
+ "Fill 4x4 1x4 TopLeft Nearest",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 1, 4,
+ TopLeft,
+ NearestNeighbor,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 4),
+ Stride: 1 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03,
+ 0x10, 0x11, 0x12, 0x13,
+ 0x20, 0x21, 0x22, 0x23,
+ 0x30, 0x31, 0x32, 0x33,
+ },
+ },
+ },
+ {
+ "Fill 4x4 8x2 Bottom Nearest",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 8, 2,
+ Bottom,
+ NearestNeighbor,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 8, 2),
+ Stride: 8 * 4,
+ Pix: []uint8{
+ 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ },
+ {
+ "Fill 4x4 2x8 Top Nearest",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 8,
+ Top,
+ NearestNeighbor,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 8),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ },
+ },
+ },
+ {
+ "Fill 4x4 4x4 TopRight Box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 4, 4,
+ TopRight,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 4, 4),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ },
+ {
+ "Fill 4x4 0x4 Left Box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 0, 4,
+ Left,
+ Box,
+ &image.NRGBA{},
+ },
+ {
+ "Fill 0x0 4x4 Right Box",
+ &image.NRGBA{},
+ 4, 4,
+ Right,
+ Box,
+ &image.NRGBA{},
+ },
+ }
+ for _, d := range td {
+ got := Fill(d.src, d.w, d.h, d.a, d.f)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestThumbnail(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ w, h int
+ f ResampleFilter
+ want *image.NRGBA
+ }{
+ {
+ "Thumbnail 6x2 1x1 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 5, 1),
+ Stride: 6 * 4,
+ Pix: []uint8{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 1, 1,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
+ },
+ },
+ {
+ "Thumbnail 2x6 1x1 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 5),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 1, 1,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 1),
+ Stride: 1 * 4,
+ Pix: []uint8{0x40, 0x40, 0x40, 0xc0},
+ },
+ },
+ {
+ "Thumbnail 1x3 2x2 box",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 0, 2),
+ Stride: 1 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff,
+ },
+ },
+ 2, 2,
+ Box,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Thumbnail(d.src, d.w, d.h, d.f)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/tools_test.go b/vendor/github.com/disintegration/imaging/tools_test.go
new file mode 100644
index 000000000..2ac7b31d3
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/tools_test.go
@@ -0,0 +1,652 @@
+package imaging
+
+import (
+ "image"
+ "testing"
+)
+
+func TestCrop(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ r image.Rectangle
+ want *image.NRGBA
+ }{
+ {
+ "Crop 2x3 2x1",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ image.Rect(-1, 0, 1, 1),
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Crop(d.src, d.r)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestCropCenter(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ w, h int
+ want *image.NRGBA
+ }{
+ {
+ "CropCenter 2x3 2x1",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ 2, 1,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ },
+ },
+ },
+ {
+ "CropCenter 2x3 0x1",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ 0, 1,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 0, 0),
+ Stride: 0,
+ Pix: []uint8{},
+ },
+ },
+ {
+ "CropCenter 2x3 5x5",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ 5, 5,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := CropCenter(d.src, d.w, d.h)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestCropAnchor(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ w, h int
+ anchor Anchor
+ want *image.NRGBA
+ }{
+ {
+ "CropAnchor 4x4 2x2 TopLeft",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ TopLeft,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 Top",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ Top,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 TopRight",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ TopRight,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 Left",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ Left,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 Center",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ Center,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 Right",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ Right,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 BottomLeft",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ BottomLeft,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 Bottom",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ Bottom,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 2x2 BottomRight",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 2, 2,
+ BottomRight,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 0x0 BottomRight",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 0, 0,
+ BottomRight,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 0, 0),
+ Stride: 0,
+ Pix: []uint8{},
+ },
+ },
+ {
+ "CropAnchor 4x4 100x100 BottomRight",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 100, 100,
+ BottomRight,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 4, 4),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 1x100 BottomRight",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 1, 100,
+ BottomRight,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 1, 4),
+ Stride: 1 * 4,
+ Pix: []uint8{
+ 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ },
+ {
+ "CropAnchor 4x4 0x100 BottomRight",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 3, 3),
+ Stride: 4 * 4,
+ Pix: []uint8{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ },
+ 0, 100,
+ BottomRight,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 0, 0),
+ Stride: 0,
+ Pix: []uint8{},
+ },
+ },
+ }
+ for _, d := range td {
+ got := CropAnchor(d.src, d.w, d.h, d.anchor)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestPaste(t *testing.T) {
+ td := []struct {
+ desc string
+ src1 image.Image
+ src2 image.Image
+ p image.Point
+ want *image.NRGBA
+ }{
+ {
+ "Paste 2x3 2x1",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(1, 1, 3, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ },
+ },
+ image.Pt(-1, 0),
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Paste(d.src1, d.src2, d.p)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestPasteCenter(t *testing.T) {
+ td := []struct {
+ desc string
+ src1 image.Image
+ src2 image.Image
+ want *image.NRGBA
+ }{
+ {
+ "PasteCenter 2x3 2x1",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(1, 1, 3, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := PasteCenter(d.src1, d.src2)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestOverlay(t *testing.T) {
+ td := []struct {
+ desc string
+ src1 image.Image
+ src2 image.Image
+ p image.Point
+ a float64
+ want *image.NRGBA
+ }{
+ {
+ "Overlay 2x3 2x1 1.0",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0x60, 0x00, 0x90, 0xff, 0xff, 0x00, 0x99, 0x7f,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(1, 1, 3, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x20, 0x40, 0x80, 0x7f, 0xaa, 0xbb, 0xcc, 0xff,
+ },
+ },
+ image.Pt(-1, 0),
+ 1.0,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0x40, 0x1f, 0x88, 0xff, 0xaa, 0xbb, 0xcc, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ {
+ "Overlay 2x2 2x2 0.5",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0x20, 0x20, 0x20, 0x00,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 1),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0xff, 0x20, 0x20, 0x20, 0xff,
+ },
+ },
+ image.Pt(-1, -1),
+ 0.5,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xff, 0x7f, 0x7f, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x7f, 0x7f, 0x7f, 0xff, 0x20, 0x20, 0x20, 0x7f,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Overlay(d.src1, d.src2, d.p, d.a)
+ want := d.want
+ if !compareNRGBA(got, want, 1) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestOverlayCenter(t *testing.T) {
+ td := []struct {
+ desc string
+ src1 image.Image
+ src2 image.Image
+ a float64
+ want *image.NRGBA
+ }{
+ {
+ "OverlayCenter 2x3 2x1",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
+ 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
+ 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(1, 1, 3, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ },
+ },
+ 0.5,
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
+ 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff,
+ 0x10, 0x10, 0x10, 0xff, 0x10, 0x10, 0x10, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := OverlayCenter(d.src1, d.src2, 0.5)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/transform_test.go b/vendor/github.com/disintegration/imaging/transform_test.go
new file mode 100644
index 000000000..6e64082f4
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/transform_test.go
@@ -0,0 +1,261 @@
+package imaging
+
+import (
+ "image"
+ "testing"
+)
+
+func TestRotate90(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Rotate90 2x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Rotate90(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestRotate180(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Rotate180 2x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Rotate180(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestRotate270(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Rotate270 2x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Rotate270(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestFlipV(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "FlipV 2x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := FlipV(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestFlipH(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "FlipH 2x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 2, 3),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := FlipH(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestTranspose(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Transpose 2x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xcc, 0xdd, 0xee, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Transpose(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
+
+func TestTransverse(t *testing.T) {
+ td := []struct {
+ desc string
+ src image.Image
+ want *image.NRGBA
+ }{
+ {
+ "Transverse 2x3",
+ &image.NRGBA{
+ Rect: image.Rect(-1, -1, 1, 2),
+ Stride: 2 * 4,
+ Pix: []uint8{
+ 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ },
+ },
+ &image.NRGBA{
+ Rect: image.Rect(0, 0, 3, 2),
+ Stride: 3 * 4,
+ Pix: []uint8{
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33,
+ },
+ },
+ },
+ }
+ for _, d := range td {
+ got := Transverse(d.src)
+ want := d.want
+ if !compareNRGBA(got, want, 0) {
+ t.Errorf("test [%s] failed: %#v", d.desc, got)
+ }
+ }
+}
diff --git a/vendor/github.com/disintegration/imaging/utils_test.go b/vendor/github.com/disintegration/imaging/utils_test.go
new file mode 100644
index 000000000..99aa8c82f
--- /dev/null
+++ b/vendor/github.com/disintegration/imaging/utils_test.go
@@ -0,0 +1,81 @@
+package imaging
+
+import (
+ "runtime"
+ "testing"
+)
+
+func testParallelN(enabled bool, n, procs int) bool {
+ data := make([]bool, n)
+ before := runtime.GOMAXPROCS(0)
+ runtime.GOMAXPROCS(procs)
+ parallel(n, func(start, end int) {
+ for i := start; i < end; i++ {
+ data[i] = true
+ }
+ })
+ for i := 0; i < n; i++ {
+ if data[i] != true {
+ return false
+ }
+ }
+ runtime.GOMAXPROCS(before)
+ return true
+}
+
+func TestParallel(t *testing.T) {
+ for _, e := range []bool{true, false} {
+ for _, n := range []int{1, 10, 100, 1000} {
+ for _, p := range []int{1, 2, 4, 8, 16, 100} {
+ if testParallelN(e, n, p) != true {
+ t.Errorf("test [parallel %v %d %d] failed", e, n, p)
+ }
+ }
+ }
+ }
+}
+
+func TestClamp(t *testing.T) {
+ td := []struct {
+ f float64
+ u uint8
+ }{
+ {0, 0},
+ {255, 255},
+ {128, 128},
+ {0.49, 0},
+ {0.50, 1},
+ {254.9, 255},
+ {254.0, 254},
+ {256, 255},
+ {2500, 255},
+ {-10, 0},
+ {127.6, 128},
+ }
+
+ for _, d := range td {
+ if clamp(d.f) != d.u {
+ t.Errorf("test [clamp %v %v] failed: %v", d.f, d.u, clamp(d.f))
+ }
+ }
+}
+
+func TestClampint32(t *testing.T) {
+ td := []struct {
+ i int32
+ u uint8
+ }{
+ {0, 0},
+ {255, 255},
+ {128, 128},
+ {256, 255},
+ {2500, 255},
+ {-10, 0},
+ }
+
+ for _, d := range td {
+ if clampint32(d.i) != d.u {
+ t.Errorf("test [clampint32 %v %v] failed: %v", d.i, d.u, clampint32(d.i))
+ }
+ }
+}
diff --git a/vendor/github.com/garyburd/redigo/.travis.yml b/vendor/github.com/garyburd/redigo/.travis.yml
new file mode 100644
index 000000000..80c179fe5
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/.travis.yml
@@ -0,0 +1,16 @@
+language: go
+sudo: false
+services:
+ - redis-server
+
+go:
+ - 1.4
+ - 1.5
+ - 1.6
+ - tip
+
+script:
+ - go get -t -v ./...
+ - diff -u <(echo -n) <(gofmt -d .)
+ - go vet $(go list ./... | grep -v /vendor/)
+ - go test -v -race ./...
diff --git a/vendor/github.com/garyburd/redigo/README.markdown b/vendor/github.com/garyburd/redigo/README.markdown
new file mode 100644
index 000000000..662690b3d
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/README.markdown
@@ -0,0 +1,50 @@
+Redigo
+======
+
+[![Build Status](https://travis-ci.org/garyburd/redigo.svg?branch=master)](https://travis-ci.org/garyburd/redigo)
+[![GoDoc](https://godoc.org/github.com/garyburd/redigo/redis?status.svg)](https://godoc.org/github.com/garyburd/redigo/redis)
+
+Redigo is a [Go](http://golang.org/) client for the [Redis](http://redis.io/) database.
+
+Features
+-------
+
+* A [Print-like](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Executing_Commands) API with support for all Redis commands.
+* [Pipelining](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Pipelining), including pipelined transactions.
+* [Publish/Subscribe](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Publish_and_Subscribe).
+* [Connection pooling](http://godoc.org/github.com/garyburd/redigo/redis#Pool).
+* [Script helper type](http://godoc.org/github.com/garyburd/redigo/redis#Script) with optimistic use of EVALSHA.
+* [Helper functions](http://godoc.org/github.com/garyburd/redigo/redis#hdr-Reply_Helpers) for working with command replies.
+
+Documentation
+-------------
+
+- [API Reference](http://godoc.org/github.com/garyburd/redigo/redis)
+- [FAQ](https://github.com/garyburd/redigo/wiki/FAQ)
+
+Installation
+------------
+
+Install Redigo using the "go get" command:
+
+ go get github.com/garyburd/redigo/redis
+
+The Go distribution is Redigo's only dependency.
+
+Related Projects
+----------------
+
+- [rafaeljusto/redigomock](https://godoc.org/github.com/rafaeljusto/redigomock) - A mock library for Redigo.
+- [chasex/redis-go-cluster](https://github.com/chasex/redis-go-cluster) - A Redis cluster client implementation.
+- [FZambia/go-sentinel](https://github.com/FZambia/go-sentinel) - Redis Sentinel support for Redigo
+- [PuerkitoBio/redisc](https://github.com/PuerkitoBio/redisc) - Redis Cluster client built on top of Redigo
+
+Contributing
+------------
+
+Send email to Gary Burd (address in GitHub profile) before doing any work on Redigo.
+
+License
+-------
+
+Redigo is available under the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
diff --git a/vendor/github.com/garyburd/redigo/internal/commandinfo.go b/vendor/github.com/garyburd/redigo/internal/commandinfo.go
index dbc60fc8e..11e584257 100644
--- a/vendor/github.com/garyburd/redigo/internal/commandinfo.go
+++ b/vendor/github.com/garyburd/redigo/internal/commandinfo.go
@@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
-package internal
+package internal // import "github.com/garyburd/redigo/internal"
import (
"strings"
diff --git a/vendor/github.com/garyburd/redigo/internal/commandinfo_test.go b/vendor/github.com/garyburd/redigo/internal/commandinfo_test.go
new file mode 100644
index 000000000..118e94b67
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/internal/commandinfo_test.go
@@ -0,0 +1,27 @@
+package internal
+
+import "testing"
+
+func TestLookupCommandInfo(t *testing.T) {
+ for _, n := range []string{"watch", "WATCH", "wAtch"} {
+ if LookupCommandInfo(n) == (CommandInfo{}) {
+ t.Errorf("LookupCommandInfo(%q) = CommandInfo{}, expected non-zero value", n)
+ }
+ }
+}
+
+func benchmarkLookupCommandInfo(b *testing.B, names ...string) {
+ for i := 0; i < b.N; i++ {
+ for _, c := range names {
+ LookupCommandInfo(c)
+ }
+ }
+}
+
+func BenchmarkLookupCommandInfoCorrectCase(b *testing.B) {
+ benchmarkLookupCommandInfo(b, "watch", "WATCH", "monitor", "MONITOR")
+}
+
+func BenchmarkLookupCommandInfoMixedCase(b *testing.B) {
+ benchmarkLookupCommandInfo(b, "wAtch", "WeTCH", "monItor", "MONiTOR")
+}
diff --git a/vendor/github.com/garyburd/redigo/internal/redistest/testdb.go b/vendor/github.com/garyburd/redigo/internal/redistest/testdb.go
new file mode 100644
index 000000000..b6f205b7f
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/internal/redistest/testdb.go
@@ -0,0 +1,68 @@
+// Copyright 2014 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package redistest contains utilities for writing Redigo tests.
+package redistest
+
+import (
+ "errors"
+ "time"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+type testConn struct {
+ redis.Conn
+}
+
+func (t testConn) Close() error {
+ _, err := t.Conn.Do("SELECT", "9")
+ if err != nil {
+ return nil
+ }
+ _, err = t.Conn.Do("FLUSHDB")
+ if err != nil {
+ return err
+ }
+ return t.Conn.Close()
+}
+
+// Dial dials the local Redis server and selects database 9. To prevent
+// stomping on real data, DialTestDB fails if database 9 contains data. The
+// returned connection flushes database 9 on close.
+func Dial() (redis.Conn, error) {
+ c, err := redis.DialTimeout("tcp", ":6379", 0, 1*time.Second, 1*time.Second)
+ if err != nil {
+ return nil, err
+ }
+
+ _, err = c.Do("SELECT", "9")
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+
+ n, err := redis.Int(c.Do("DBSIZE"))
+ if err != nil {
+ c.Close()
+ return nil, err
+ }
+
+ if n != 0 {
+ c.Close()
+ return nil, errors.New("database #9 is not empty, test can not continue")
+ }
+
+ return testConn{c}, nil
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/conn_test.go b/vendor/github.com/garyburd/redigo/redis/conn_test.go
new file mode 100644
index 000000000..2ead63326
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/conn_test.go
@@ -0,0 +1,670 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis_test
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "net"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+type testConn struct {
+ io.Reader
+ io.Writer
+}
+
+func (*testConn) Close() error { return nil }
+func (*testConn) LocalAddr() net.Addr { return nil }
+func (*testConn) RemoteAddr() net.Addr { return nil }
+func (*testConn) SetDeadline(t time.Time) error { return nil }
+func (*testConn) SetReadDeadline(t time.Time) error { return nil }
+func (*testConn) SetWriteDeadline(t time.Time) error { return nil }
+
+func dialTestConn(r io.Reader, w io.Writer) redis.DialOption {
+ return redis.DialNetDial(func(net, addr string) (net.Conn, error) {
+ return &testConn{Reader: r, Writer: w}, nil
+ })
+}
+
+var writeTests = []struct {
+ args []interface{}
+ expected string
+}{
+ {
+ []interface{}{"SET", "key", "value"},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
+ },
+ {
+ []interface{}{"SET", "key", "value"},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n",
+ },
+ {
+ []interface{}{"SET", "key", byte(100)},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
+ },
+ {
+ []interface{}{"SET", "key", 100},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$3\r\n100\r\n",
+ },
+ {
+ []interface{}{"SET", "key", int64(math.MinInt64)},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$20\r\n-9223372036854775808\r\n",
+ },
+ {
+ []interface{}{"SET", "key", float64(1349673917.939762)},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$21\r\n1.349673917939762e+09\r\n",
+ },
+ {
+ []interface{}{"SET", "key", ""},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
+ },
+ {
+ []interface{}{"SET", "key", nil},
+ "*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$0\r\n\r\n",
+ },
+ {
+ []interface{}{"ECHO", true, false},
+ "*3\r\n$4\r\nECHO\r\n$1\r\n1\r\n$1\r\n0\r\n",
+ },
+}
+
+func TestWrite(t *testing.T) {
+ for _, tt := range writeTests {
+ var buf bytes.Buffer
+ c, _ := redis.Dial("", "", dialTestConn(nil, &buf))
+ err := c.Send(tt.args[0].(string), tt.args[1:]...)
+ if err != nil {
+ t.Errorf("Send(%v) returned error %v", tt.args, err)
+ continue
+ }
+ c.Flush()
+ actual := buf.String()
+ if actual != tt.expected {
+ t.Errorf("Send(%v) = %q, want %q", tt.args, actual, tt.expected)
+ }
+ }
+}
+
+var errorSentinel = &struct{}{}
+
+var readTests = []struct {
+ reply string
+ expected interface{}
+}{
+ {
+ "+OK\r\n",
+ "OK",
+ },
+ {
+ "+PONG\r\n",
+ "PONG",
+ },
+ {
+ "@OK\r\n",
+ errorSentinel,
+ },
+ {
+ "$6\r\nfoobar\r\n",
+ []byte("foobar"),
+ },
+ {
+ "$-1\r\n",
+ nil,
+ },
+ {
+ ":1\r\n",
+ int64(1),
+ },
+ {
+ ":-2\r\n",
+ int64(-2),
+ },
+ {
+ "*0\r\n",
+ []interface{}{},
+ },
+ {
+ "*-1\r\n",
+ nil,
+ },
+ {
+ "*4\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$5\r\nHello\r\n$5\r\nWorld\r\n",
+ []interface{}{[]byte("foo"), []byte("bar"), []byte("Hello"), []byte("World")},
+ },
+ {
+ "*3\r\n$3\r\nfoo\r\n$-1\r\n$3\r\nbar\r\n",
+ []interface{}{[]byte("foo"), nil, []byte("bar")},
+ },
+
+ {
+ // "x" is not a valid length
+ "$x\r\nfoobar\r\n",
+ errorSentinel,
+ },
+ {
+ // -2 is not a valid length
+ "$-2\r\n",
+ errorSentinel,
+ },
+ {
+ // "x" is not a valid integer
+ ":x\r\n",
+ errorSentinel,
+ },
+ {
+ // missing \r\n following value
+ "$6\r\nfoobar",
+ errorSentinel,
+ },
+ {
+ // short value
+ "$6\r\nxx",
+ errorSentinel,
+ },
+ {
+ // long value
+ "$6\r\nfoobarx\r\n",
+ errorSentinel,
+ },
+}
+
+func TestRead(t *testing.T) {
+ for _, tt := range readTests {
+ c, _ := redis.Dial("", "", dialTestConn(strings.NewReader(tt.reply), nil))
+ actual, err := c.Receive()
+ if tt.expected == errorSentinel {
+ if err == nil {
+ t.Errorf("Receive(%q) did not return expected error", tt.reply)
+ }
+ } else {
+ if err != nil {
+ t.Errorf("Receive(%q) returned error %v", tt.reply, err)
+ continue
+ }
+ if !reflect.DeepEqual(actual, tt.expected) {
+ t.Errorf("Receive(%q) = %v, want %v", tt.reply, actual, tt.expected)
+ }
+ }
+ }
+}
+
+var testCommands = []struct {
+ args []interface{}
+ expected interface{}
+}{
+ {
+ []interface{}{"PING"},
+ "PONG",
+ },
+ {
+ []interface{}{"SET", "foo", "bar"},
+ "OK",
+ },
+ {
+ []interface{}{"GET", "foo"},
+ []byte("bar"),
+ },
+ {
+ []interface{}{"GET", "nokey"},
+ nil,
+ },
+ {
+ []interface{}{"MGET", "nokey", "foo"},
+ []interface{}{nil, []byte("bar")},
+ },
+ {
+ []interface{}{"INCR", "mycounter"},
+ int64(1),
+ },
+ {
+ []interface{}{"LPUSH", "mylist", "foo"},
+ int64(1),
+ },
+ {
+ []interface{}{"LPUSH", "mylist", "bar"},
+ int64(2),
+ },
+ {
+ []interface{}{"LRANGE", "mylist", 0, -1},
+ []interface{}{[]byte("bar"), []byte("foo")},
+ },
+ {
+ []interface{}{"MULTI"},
+ "OK",
+ },
+ {
+ []interface{}{"LRANGE", "mylist", 0, -1},
+ "QUEUED",
+ },
+ {
+ []interface{}{"PING"},
+ "QUEUED",
+ },
+ {
+ []interface{}{"EXEC"},
+ []interface{}{
+ []interface{}{[]byte("bar"), []byte("foo")},
+ "PONG",
+ },
+ },
+}
+
+func TestDoCommands(t *testing.T) {
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ for _, cmd := range testCommands {
+ actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...)
+ if err != nil {
+ t.Errorf("Do(%v) returned error %v", cmd.args, err)
+ continue
+ }
+ if !reflect.DeepEqual(actual, cmd.expected) {
+ t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected)
+ }
+ }
+}
+
+func TestPipelineCommands(t *testing.T) {
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ for _, cmd := range testCommands {
+ if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
+ t.Fatalf("Send(%v) returned error %v", cmd.args, err)
+ }
+ }
+ if err := c.Flush(); err != nil {
+ t.Errorf("Flush() returned error %v", err)
+ }
+ for _, cmd := range testCommands {
+ actual, err := c.Receive()
+ if err != nil {
+ t.Fatalf("Receive(%v) returned error %v", cmd.args, err)
+ }
+ if !reflect.DeepEqual(actual, cmd.expected) {
+ t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
+ }
+ }
+}
+
+func TestBlankCommmand(t *testing.T) {
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ for _, cmd := range testCommands {
+ if err := c.Send(cmd.args[0].(string), cmd.args[1:]...); err != nil {
+ t.Fatalf("Send(%v) returned error %v", cmd.args, err)
+ }
+ }
+ reply, err := redis.Values(c.Do(""))
+ if err != nil {
+ t.Fatalf("Do() returned error %v", err)
+ }
+ if len(reply) != len(testCommands) {
+ t.Fatalf("len(reply)=%d, want %d", len(reply), len(testCommands))
+ }
+ for i, cmd := range testCommands {
+ actual := reply[i]
+ if !reflect.DeepEqual(actual, cmd.expected) {
+ t.Errorf("Receive(%v) = %v, want %v", cmd.args, actual, cmd.expected)
+ }
+ }
+}
+
+func TestRecvBeforeSend(t *testing.T) {
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+ done := make(chan struct{})
+ go func() {
+ c.Receive()
+ close(done)
+ }()
+ time.Sleep(time.Millisecond)
+ c.Send("PING")
+ c.Flush()
+ <-done
+ _, err = c.Do("")
+ if err != nil {
+ t.Fatalf("error=%v", err)
+ }
+}
+
+func TestError(t *testing.T) {
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ c.Do("SET", "key", "val")
+ _, err = c.Do("HSET", "key", "fld", "val")
+ if err == nil {
+ t.Errorf("Expected err for HSET on string key.")
+ }
+ if c.Err() != nil {
+ t.Errorf("Conn has Err()=%v, expect nil", c.Err())
+ }
+ _, err = c.Do("SET", "key", "val")
+ if err != nil {
+ t.Errorf("Do(SET, key, val) returned error %v, expected nil.", err)
+ }
+}
+
+func TestReadTimeout(t *testing.T) {
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("net.Listen returned %v", err)
+ }
+ defer l.Close()
+
+ go func() {
+ for {
+ c, err := l.Accept()
+ if err != nil {
+ return
+ }
+ go func() {
+ time.Sleep(time.Second)
+ c.Write([]byte("+OK\r\n"))
+ c.Close()
+ }()
+ }
+ }()
+
+ // Do
+
+ c1, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
+ if err != nil {
+ t.Fatalf("redis.Dial returned %v", err)
+ }
+ defer c1.Close()
+
+ _, err = c1.Do("PING")
+ if err == nil {
+ t.Fatalf("c1.Do() returned nil, expect error")
+ }
+ if c1.Err() == nil {
+ t.Fatalf("c1.Err() = nil, expect error")
+ }
+
+ // Send/Flush/Receive
+
+ c2, err := redis.Dial(l.Addr().Network(), l.Addr().String(), redis.DialReadTimeout(time.Millisecond))
+ if err != nil {
+ t.Fatalf("redis.Dial returned %v", err)
+ }
+ defer c2.Close()
+
+ c2.Send("PING")
+ c2.Flush()
+ _, err = c2.Receive()
+ if err == nil {
+ t.Fatalf("c2.Receive() returned nil, expect error")
+ }
+ if c2.Err() == nil {
+ t.Fatalf("c2.Err() = nil, expect error")
+ }
+}
+
+var dialErrors = []struct {
+ rawurl string
+ expectedError string
+}{
+ {
+ "localhost",
+ "invalid redis URL scheme",
+ },
+ // The error message for invalid hosts is diffferent in different
+ // versions of Go, so just check that there is an error message.
+ {
+ "redis://weird url",
+ "",
+ },
+ {
+ "redis://foo:bar:baz",
+ "",
+ },
+ {
+ "http://www.google.com",
+ "invalid redis URL scheme: http",
+ },
+ {
+ "redis://localhost:6379/abc123",
+ "invalid database: abc123",
+ },
+}
+
+func TestDialURLErrors(t *testing.T) {
+ for _, d := range dialErrors {
+ _, err := redis.DialURL(d.rawurl)
+ if err == nil || !strings.Contains(err.Error(), d.expectedError) {
+ t.Errorf("DialURL did not return expected error (expected %v to contain %s)", err, d.expectedError)
+ }
+ }
+}
+
+func TestDialURLPort(t *testing.T) {
+ checkPort := func(network, address string) (net.Conn, error) {
+ if address != "localhost:6379" {
+ t.Errorf("DialURL did not set port to 6379 by default (got %v)", address)
+ }
+ return nil, nil
+ }
+ _, err := redis.DialURL("redis://localhost", redis.DialNetDial(checkPort))
+ if err != nil {
+ t.Error("dial error:", err)
+ }
+}
+
+func TestDialURLHost(t *testing.T) {
+ checkHost := func(network, address string) (net.Conn, error) {
+ if address != "localhost:6379" {
+ t.Errorf("DialURL did not set host to localhost by default (got %v)", address)
+ }
+ return nil, nil
+ }
+ _, err := redis.DialURL("redis://:6379", redis.DialNetDial(checkHost))
+ if err != nil {
+ t.Error("dial error:", err)
+ }
+}
+
+func TestDialURLPassword(t *testing.T) {
+ var buf bytes.Buffer
+ _, err := redis.DialURL("redis://x:abc123@localhost", dialTestConn(strings.NewReader("+OK\r\n"), &buf))
+ if err != nil {
+ t.Error("dial error:", err)
+ }
+ expected := "*2\r\n$4\r\nAUTH\r\n$6\r\nabc123\r\n"
+ actual := buf.String()
+ if actual != expected {
+ t.Errorf("commands = %q, want %q", actual, expected)
+ }
+}
+
+func TestDialURLDatabase(t *testing.T) {
+ var buf3 bytes.Buffer
+ _, err3 := redis.DialURL("redis://localhost/3", dialTestConn(strings.NewReader("+OK\r\n"), &buf3))
+ if err3 != nil {
+ t.Error("dial error:", err3)
+ }
+ expected3 := "*2\r\n$6\r\nSELECT\r\n$1\r\n3\r\n"
+ actual3 := buf3.String()
+ if actual3 != expected3 {
+ t.Errorf("commands = %q, want %q", actual3, expected3)
+ }
+ // empty DB means 0
+ var buf0 bytes.Buffer
+ _, err0 := redis.DialURL("redis://localhost/", dialTestConn(strings.NewReader("+OK\r\n"), &buf0))
+ if err0 != nil {
+ t.Error("dial error:", err0)
+ }
+ expected0 := ""
+ actual0 := buf0.String()
+ if actual0 != expected0 {
+ t.Errorf("commands = %q, want %q", actual0, expected0)
+ }
+}
+
+// Connect to local instance of Redis running on the default port.
+func ExampleDial() {
+ c, err := redis.Dial("tcp", ":6379")
+ if err != nil {
+ // handle error
+ }
+ defer c.Close()
+}
+
+// Connect to remote instance of Redis using a URL.
+func ExampleDialURL() {
+ c, err := redis.DialURL(os.Getenv("REDIS_URL"))
+ if err != nil {
+ // handle connection error
+ }
+ defer c.Close()
+}
+
+// TextExecError tests handling of errors in a transaction. See
+// http://redis.io/topics/transactions for information on how Redis handles
+// errors in a transaction.
+func TestExecError(t *testing.T) {
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ // Execute commands that fail before EXEC is called.
+
+ c.Do("DEL", "k0")
+ c.Do("ZADD", "k0", 0, 0)
+ c.Send("MULTI")
+ c.Send("NOTACOMMAND", "k0", 0, 0)
+ c.Send("ZINCRBY", "k0", 0, 0)
+ v, err := c.Do("EXEC")
+ if err == nil {
+ t.Fatalf("EXEC returned values %v, expected error", v)
+ }
+
+ // Execute commands that fail after EXEC is called. The first command
+ // returns an error.
+
+ c.Do("DEL", "k1")
+ c.Do("ZADD", "k1", 0, 0)
+ c.Send("MULTI")
+ c.Send("HSET", "k1", 0, 0)
+ c.Send("ZINCRBY", "k1", 0, 0)
+ v, err = c.Do("EXEC")
+ if err != nil {
+ t.Fatalf("EXEC returned error %v", err)
+ }
+
+ vs, err := redis.Values(v, nil)
+ if err != nil {
+ t.Fatalf("Values(v) returned error %v", err)
+ }
+
+ if len(vs) != 2 {
+ t.Fatalf("len(vs) == %d, want 2", len(vs))
+ }
+
+ if _, ok := vs[0].(error); !ok {
+ t.Fatalf("first result is type %T, expected error", vs[0])
+ }
+
+ if _, ok := vs[1].([]byte); !ok {
+ t.Fatalf("second result is type %T, expected []byte", vs[1])
+ }
+
+ // Execute commands that fail after EXEC is called. The second command
+ // returns an error.
+
+ c.Do("ZADD", "k2", 0, 0)
+ c.Send("MULTI")
+ c.Send("ZINCRBY", "k2", 0, 0)
+ c.Send("HSET", "k2", 0, 0)
+ v, err = c.Do("EXEC")
+ if err != nil {
+ t.Fatalf("EXEC returned error %v", err)
+ }
+
+ vs, err = redis.Values(v, nil)
+ if err != nil {
+ t.Fatalf("Values(v) returned error %v", err)
+ }
+
+ if len(vs) != 2 {
+ t.Fatalf("len(vs) == %d, want 2", len(vs))
+ }
+
+ if _, ok := vs[0].([]byte); !ok {
+ t.Fatalf("first result is type %T, expected []byte", vs[0])
+ }
+
+ if _, ok := vs[1].(error); !ok {
+ t.Fatalf("second result is type %T, expected error", vs[2])
+ }
+}
+
+func BenchmarkDoEmpty(b *testing.B) {
+ b.StopTimer()
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer c.Close()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if _, err := c.Do(""); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkDoPing(b *testing.B) {
+ b.StopTimer()
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer c.Close()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if _, err := c.Do("PING"); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/doc.go b/vendor/github.com/garyburd/redigo/redis/doc.go
index 1ae6f0cc2..a5cd454af 100644
--- a/vendor/github.com/garyburd/redigo/redis/doc.go
+++ b/vendor/github.com/garyburd/redigo/redis/doc.go
@@ -166,4 +166,4 @@
// if _, err := redis.Scan(reply, &value1, &value2); err != nil {
// // handle error
// }
-package redis
+package redis // import "github.com/garyburd/redigo/redis"
diff --git a/vendor/github.com/garyburd/redigo/redis/pool_test.go b/vendor/github.com/garyburd/redigo/redis/pool_test.go
new file mode 100644
index 000000000..9419a128f
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/pool_test.go
@@ -0,0 +1,684 @@
+// Copyright 2011 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis_test
+
+import (
+ "errors"
+ "io"
+ "reflect"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+type poolTestConn struct {
+ d *poolDialer
+ err error
+ redis.Conn
+}
+
+func (c *poolTestConn) Close() error {
+ c.d.mu.Lock()
+ c.d.open -= 1
+ c.d.mu.Unlock()
+ return c.Conn.Close()
+}
+
+func (c *poolTestConn) Err() error { return c.err }
+
+func (c *poolTestConn) Do(commandName string, args ...interface{}) (interface{}, error) {
+ if commandName == "ERR" {
+ c.err = args[0].(error)
+ commandName = "PING"
+ }
+ if commandName != "" {
+ c.d.commands = append(c.d.commands, commandName)
+ }
+ return c.Conn.Do(commandName, args...)
+}
+
+func (c *poolTestConn) Send(commandName string, args ...interface{}) error {
+ c.d.commands = append(c.d.commands, commandName)
+ return c.Conn.Send(commandName, args...)
+}
+
+type poolDialer struct {
+ mu sync.Mutex
+ t *testing.T
+ dialed int
+ open int
+ commands []string
+ dialErr error
+}
+
+func (d *poolDialer) dial() (redis.Conn, error) {
+ d.mu.Lock()
+ d.dialed += 1
+ dialErr := d.dialErr
+ d.mu.Unlock()
+ if dialErr != nil {
+ return nil, d.dialErr
+ }
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ return nil, err
+ }
+ d.mu.Lock()
+ d.open += 1
+ d.mu.Unlock()
+ return &poolTestConn{d: d, Conn: c}, nil
+}
+
+func (d *poolDialer) check(message string, p *redis.Pool, dialed, open int) {
+ d.mu.Lock()
+ if d.dialed != dialed {
+ d.t.Errorf("%s: dialed=%d, want %d", message, d.dialed, dialed)
+ }
+ if d.open != open {
+ d.t.Errorf("%s: open=%d, want %d", message, d.open, open)
+ }
+ if active := p.ActiveCount(); active != open {
+ d.t.Errorf("%s: active=%d, want %d", message, active, open)
+ }
+ d.mu.Unlock()
+}
+
+func TestPoolReuse(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ Dial: d.dial,
+ }
+
+ for i := 0; i < 10; i++ {
+ c1 := p.Get()
+ c1.Do("PING")
+ c2 := p.Get()
+ c2.Do("PING")
+ c1.Close()
+ c2.Close()
+ }
+
+ d.check("before close", p, 2, 2)
+ p.Close()
+ d.check("after close", p, 2, 0)
+}
+
+func TestPoolMaxIdle(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ for i := 0; i < 10; i++ {
+ c1 := p.Get()
+ c1.Do("PING")
+ c2 := p.Get()
+ c2.Do("PING")
+ c3 := p.Get()
+ c3.Do("PING")
+ c1.Close()
+ c2.Close()
+ c3.Close()
+ }
+ d.check("before close", p, 12, 2)
+ p.Close()
+ d.check("after close", p, 12, 0)
+}
+
+func TestPoolError(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ c.Do("ERR", io.EOF)
+ if c.Err() == nil {
+ t.Errorf("expected c.Err() != nil")
+ }
+ c.Close()
+
+ c = p.Get()
+ c.Do("ERR", io.EOF)
+ c.Close()
+
+ d.check(".", p, 2, 0)
+}
+
+func TestPoolClose(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ c1 := p.Get()
+ c1.Do("PING")
+ c2 := p.Get()
+ c2.Do("PING")
+ c3 := p.Get()
+ c3.Do("PING")
+
+ c1.Close()
+ if _, err := c1.Do("PING"); err == nil {
+ t.Errorf("expected error after connection closed")
+ }
+
+ c2.Close()
+ c2.Close()
+
+ p.Close()
+
+ d.check("after pool close", p, 3, 1)
+
+ if _, err := c1.Do("PING"); err == nil {
+ t.Errorf("expected error after connection and pool closed")
+ }
+
+ c3.Close()
+
+ d.check("after conn close", p, 3, 0)
+
+ c1 = p.Get()
+ if _, err := c1.Do("PING"); err == nil {
+ t.Errorf("expected error after pool closed")
+ }
+}
+
+func TestPoolTimeout(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ IdleTimeout: 300 * time.Second,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ now := time.Now()
+ redis.SetNowFunc(func() time.Time { return now })
+ defer redis.SetNowFunc(time.Now)
+
+ c := p.Get()
+ c.Do("PING")
+ c.Close()
+
+ d.check("1", p, 1, 1)
+
+ now = now.Add(p.IdleTimeout)
+
+ c = p.Get()
+ c.Do("PING")
+ c.Close()
+
+ d.check("2", p, 2, 1)
+}
+
+func TestPoolConcurrenSendReceive(t *testing.T) {
+ p := &redis.Pool{
+ Dial: redis.DialDefaultServer,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ done := make(chan error, 1)
+ go func() {
+ _, err := c.Receive()
+ done <- err
+ }()
+ c.Send("PING")
+ c.Flush()
+ err := <-done
+ if err != nil {
+ t.Fatalf("Receive() returned error %v", err)
+ }
+ _, err = c.Do("")
+ if err != nil {
+ t.Fatalf("Do() returned error %v", err)
+ }
+ c.Close()
+}
+
+func TestPoolBorrowCheck(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ Dial: d.dial,
+ TestOnBorrow: func(redis.Conn, time.Time) error { return redis.Error("BLAH") },
+ }
+ defer p.Close()
+
+ for i := 0; i < 10; i++ {
+ c := p.Get()
+ c.Do("PING")
+ c.Close()
+ }
+ d.check("1", p, 10, 1)
+}
+
+func TestPoolMaxActive(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ MaxActive: 2,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ c1 := p.Get()
+ c1.Do("PING")
+ c2 := p.Get()
+ c2.Do("PING")
+
+ d.check("1", p, 2, 2)
+
+ c3 := p.Get()
+ if _, err := c3.Do("PING"); err != redis.ErrPoolExhausted {
+ t.Errorf("expected pool exhausted")
+ }
+
+ c3.Close()
+ d.check("2", p, 2, 2)
+ c2.Close()
+ d.check("3", p, 2, 2)
+
+ c3 = p.Get()
+ if _, err := c3.Do("PING"); err != nil {
+ t.Errorf("expected good channel, err=%v", err)
+ }
+ c3.Close()
+
+ d.check("4", p, 2, 2)
+}
+
+func TestPoolMonitorCleanup(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ MaxActive: 2,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ c.Send("MONITOR")
+ c.Close()
+
+ d.check("", p, 1, 0)
+}
+
+func TestPoolPubSubCleanup(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ MaxActive: 2,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ c.Send("SUBSCRIBE", "x")
+ c.Close()
+
+ want := []string{"SUBSCRIBE", "UNSUBSCRIBE", "PUNSUBSCRIBE", "ECHO"}
+ if !reflect.DeepEqual(d.commands, want) {
+ t.Errorf("got commands %v, want %v", d.commands, want)
+ }
+ d.commands = nil
+
+ c = p.Get()
+ c.Send("PSUBSCRIBE", "x*")
+ c.Close()
+
+ want = []string{"PSUBSCRIBE", "UNSUBSCRIBE", "PUNSUBSCRIBE", "ECHO"}
+ if !reflect.DeepEqual(d.commands, want) {
+ t.Errorf("got commands %v, want %v", d.commands, want)
+ }
+ d.commands = nil
+}
+
+func TestPoolTransactionCleanup(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 2,
+ MaxActive: 2,
+ Dial: d.dial,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ c.Do("WATCH", "key")
+ c.Do("PING")
+ c.Close()
+
+ want := []string{"WATCH", "PING", "UNWATCH"}
+ if !reflect.DeepEqual(d.commands, want) {
+ t.Errorf("got commands %v, want %v", d.commands, want)
+ }
+ d.commands = nil
+
+ c = p.Get()
+ c.Do("WATCH", "key")
+ c.Do("UNWATCH")
+ c.Do("PING")
+ c.Close()
+
+ want = []string{"WATCH", "UNWATCH", "PING"}
+ if !reflect.DeepEqual(d.commands, want) {
+ t.Errorf("got commands %v, want %v", d.commands, want)
+ }
+ d.commands = nil
+
+ c = p.Get()
+ c.Do("WATCH", "key")
+ c.Do("MULTI")
+ c.Do("PING")
+ c.Close()
+
+ want = []string{"WATCH", "MULTI", "PING", "DISCARD"}
+ if !reflect.DeepEqual(d.commands, want) {
+ t.Errorf("got commands %v, want %v", d.commands, want)
+ }
+ d.commands = nil
+
+ c = p.Get()
+ c.Do("WATCH", "key")
+ c.Do("MULTI")
+ c.Do("DISCARD")
+ c.Do("PING")
+ c.Close()
+
+ want = []string{"WATCH", "MULTI", "DISCARD", "PING"}
+ if !reflect.DeepEqual(d.commands, want) {
+ t.Errorf("got commands %v, want %v", d.commands, want)
+ }
+ d.commands = nil
+
+ c = p.Get()
+ c.Do("WATCH", "key")
+ c.Do("MULTI")
+ c.Do("EXEC")
+ c.Do("PING")
+ c.Close()
+
+ want = []string{"WATCH", "MULTI", "EXEC", "PING"}
+ if !reflect.DeepEqual(d.commands, want) {
+ t.Errorf("got commands %v, want %v", d.commands, want)
+ }
+ d.commands = nil
+}
+
+func startGoroutines(p *redis.Pool, cmd string, args ...interface{}) chan error {
+ errs := make(chan error, 10)
+ for i := 0; i < cap(errs); i++ {
+ go func() {
+ c := p.Get()
+ _, err := c.Do(cmd, args...)
+ errs <- err
+ c.Close()
+ }()
+ }
+
+ // Wait for goroutines to block.
+ time.Sleep(time.Second / 4)
+
+ return errs
+}
+
+func TestWaitPool(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 1,
+ MaxActive: 1,
+ Dial: d.dial,
+ Wait: true,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ errs := startGoroutines(p, "PING")
+ d.check("before close", p, 1, 1)
+ c.Close()
+ timeout := time.After(2 * time.Second)
+ for i := 0; i < cap(errs); i++ {
+ select {
+ case err := <-errs:
+ if err != nil {
+ t.Fatal(err)
+ }
+ case <-timeout:
+ t.Fatalf("timeout waiting for blocked goroutine %d", i)
+ }
+ }
+ d.check("done", p, 1, 1)
+}
+
+func TestWaitPoolClose(t *testing.T) {
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 1,
+ MaxActive: 1,
+ Dial: d.dial,
+ Wait: true,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ if _, err := c.Do("PING"); err != nil {
+ t.Fatal(err)
+ }
+ errs := startGoroutines(p, "PING")
+ d.check("before close", p, 1, 1)
+ p.Close()
+ timeout := time.After(2 * time.Second)
+ for i := 0; i < cap(errs); i++ {
+ select {
+ case err := <-errs:
+ switch err {
+ case nil:
+ t.Fatal("blocked goroutine did not get error")
+ case redis.ErrPoolExhausted:
+ t.Fatal("blocked goroutine got pool exhausted error")
+ }
+ case <-timeout:
+ t.Fatal("timeout waiting for blocked goroutine")
+ }
+ }
+ c.Close()
+ d.check("done", p, 1, 0)
+}
+
+func TestWaitPoolCommandError(t *testing.T) {
+ testErr := errors.New("test")
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 1,
+ MaxActive: 1,
+ Dial: d.dial,
+ Wait: true,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ errs := startGoroutines(p, "ERR", testErr)
+ d.check("before close", p, 1, 1)
+ c.Close()
+ timeout := time.After(2 * time.Second)
+ for i := 0; i < cap(errs); i++ {
+ select {
+ case err := <-errs:
+ if err != nil {
+ t.Fatal(err)
+ }
+ case <-timeout:
+ t.Fatalf("timeout waiting for blocked goroutine %d", i)
+ }
+ }
+ d.check("done", p, cap(errs), 0)
+}
+
+func TestWaitPoolDialError(t *testing.T) {
+ testErr := errors.New("test")
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: 1,
+ MaxActive: 1,
+ Dial: d.dial,
+ Wait: true,
+ }
+ defer p.Close()
+
+ c := p.Get()
+ errs := startGoroutines(p, "ERR", testErr)
+ d.check("before close", p, 1, 1)
+
+ d.dialErr = errors.New("dial")
+ c.Close()
+
+ nilCount := 0
+ errCount := 0
+ timeout := time.After(2 * time.Second)
+ for i := 0; i < cap(errs); i++ {
+ select {
+ case err := <-errs:
+ switch err {
+ case nil:
+ nilCount++
+ case d.dialErr:
+ errCount++
+ default:
+ t.Fatalf("expected dial error or nil, got %v", err)
+ }
+ case <-timeout:
+ t.Fatalf("timeout waiting for blocked goroutine %d", i)
+ }
+ }
+ if nilCount != 1 {
+ t.Errorf("expected one nil error, got %d", nilCount)
+ }
+ if errCount != cap(errs)-1 {
+ t.Errorf("expected %d dial erors, got %d", cap(errs)-1, errCount)
+ }
+ d.check("done", p, cap(errs), 0)
+}
+
+// Borrowing requires us to iterate over the idle connections, unlock the pool,
+// and perform a blocking operation to check the connection still works. If
+// TestOnBorrow fails, we must reacquire the lock and continue iteration. This
+// test ensures that iteration will work correctly if multiple threads are
+// iterating simultaneously.
+func TestLocking_TestOnBorrowFails_PoolDoesntCrash(t *testing.T) {
+ const count = 100
+
+ // First we'll Create a pool where the pilfering of idle connections fails.
+ d := poolDialer{t: t}
+ p := &redis.Pool{
+ MaxIdle: count,
+ MaxActive: count,
+ Dial: d.dial,
+ TestOnBorrow: func(c redis.Conn, t time.Time) error {
+ return errors.New("No way back into the real world.")
+ },
+ }
+ defer p.Close()
+
+ // Fill the pool with idle connections.
+ conns := make([]redis.Conn, count)
+ for i := range conns {
+ conns[i] = p.Get()
+ }
+ for i := range conns {
+ conns[i].Close()
+ }
+
+ // Spawn a bunch of goroutines to thrash the pool.
+ var wg sync.WaitGroup
+ wg.Add(count)
+ for i := 0; i < count; i++ {
+ go func() {
+ c := p.Get()
+ if c.Err() != nil {
+ t.Errorf("pool get failed: %v", c.Err())
+ }
+ c.Close()
+ wg.Done()
+ }()
+ }
+ wg.Wait()
+ if d.dialed != count*2 {
+ t.Errorf("Expected %d dials, got %d", count*2, d.dialed)
+ }
+}
+
+func BenchmarkPoolGet(b *testing.B) {
+ b.StopTimer()
+ p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
+ c := p.Get()
+ if err := c.Err(); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ defer p.Close()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ c = p.Get()
+ c.Close()
+ }
+}
+
+func BenchmarkPoolGetErr(b *testing.B) {
+ b.StopTimer()
+ p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
+ c := p.Get()
+ if err := c.Err(); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ defer p.Close()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ c = p.Get()
+ if err := c.Err(); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ }
+}
+
+func BenchmarkPoolGetPing(b *testing.B) {
+ b.StopTimer()
+ p := redis.Pool{Dial: redis.DialDefaultServer, MaxIdle: 2}
+ c := p.Get()
+ if err := c.Err(); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ defer p.Close()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ c = p.Get()
+ if _, err := c.Do("PING"); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ }
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/pubsub_test.go b/vendor/github.com/garyburd/redigo/redis/pubsub_test.go
new file mode 100644
index 000000000..b95513155
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/pubsub_test.go
@@ -0,0 +1,148 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis_test
+
+import (
+ "fmt"
+ "reflect"
+ "sync"
+ "testing"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+func publish(channel, value interface{}) {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+ c.Do("PUBLISH", channel, value)
+}
+
+// Applications can receive pushed messages from one goroutine and manage subscriptions from another goroutine.
+func ExamplePubSubConn() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+ var wg sync.WaitGroup
+ wg.Add(2)
+
+ psc := redis.PubSubConn{Conn: c}
+
+ // This goroutine receives and prints pushed notifications from the server.
+ // The goroutine exits when the connection is unsubscribed from all
+ // channels or there is an error.
+ go func() {
+ defer wg.Done()
+ for {
+ switch n := psc.Receive().(type) {
+ case redis.Message:
+ fmt.Printf("Message: %s %s\n", n.Channel, n.Data)
+ case redis.PMessage:
+ fmt.Printf("PMessage: %s %s %s\n", n.Pattern, n.Channel, n.Data)
+ case redis.Subscription:
+ fmt.Printf("Subscription: %s %s %d\n", n.Kind, n.Channel, n.Count)
+ if n.Count == 0 {
+ return
+ }
+ case error:
+ fmt.Printf("error: %v\n", n)
+ return
+ }
+ }
+ }()
+
+ // This goroutine manages subscriptions for the connection.
+ go func() {
+ defer wg.Done()
+
+ psc.Subscribe("example")
+ psc.PSubscribe("p*")
+
+ // The following function calls publish a message using another
+ // connection to the Redis server.
+ publish("example", "hello")
+ publish("example", "world")
+ publish("pexample", "foo")
+ publish("pexample", "bar")
+
+ // Unsubscribe from all connections. This will cause the receiving
+ // goroutine to exit.
+ psc.Unsubscribe()
+ psc.PUnsubscribe()
+ }()
+
+ wg.Wait()
+
+ // Output:
+ // Subscription: subscribe example 1
+ // Subscription: psubscribe p* 2
+ // Message: example hello
+ // Message: example world
+ // PMessage: p* pexample foo
+ // PMessage: p* pexample bar
+ // Subscription: unsubscribe example 1
+ // Subscription: punsubscribe p* 0
+}
+
+func expectPushed(t *testing.T, c redis.PubSubConn, message string, expected interface{}) {
+ actual := c.Receive()
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("%s = %v, want %v", message, actual, expected)
+ }
+}
+
+func TestPushed(t *testing.T) {
+ pc, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer pc.Close()
+
+ sc, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer sc.Close()
+
+ c := redis.PubSubConn{Conn: sc}
+
+ c.Subscribe("c1")
+ expectPushed(t, c, "Subscribe(c1)", redis.Subscription{Kind: "subscribe", Channel: "c1", Count: 1})
+ c.Subscribe("c2")
+ expectPushed(t, c, "Subscribe(c2)", redis.Subscription{Kind: "subscribe", Channel: "c2", Count: 2})
+ c.PSubscribe("p1")
+ expectPushed(t, c, "PSubscribe(p1)", redis.Subscription{Kind: "psubscribe", Channel: "p1", Count: 3})
+ c.PSubscribe("p2")
+ expectPushed(t, c, "PSubscribe(p2)", redis.Subscription{Kind: "psubscribe", Channel: "p2", Count: 4})
+ c.PUnsubscribe()
+ expectPushed(t, c, "Punsubscribe(p1)", redis.Subscription{Kind: "punsubscribe", Channel: "p1", Count: 3})
+ expectPushed(t, c, "Punsubscribe()", redis.Subscription{Kind: "punsubscribe", Channel: "p2", Count: 2})
+
+ pc.Do("PUBLISH", "c1", "hello")
+ expectPushed(t, c, "PUBLISH c1 hello", redis.Message{Channel: "c1", Data: []byte("hello")})
+
+ c.Ping("hello")
+ expectPushed(t, c, `Ping("hello")`, redis.Pong{Data: "hello"})
+
+ c.Conn.Send("PING")
+ c.Conn.Flush()
+ expectPushed(t, c, `Send("PING")`, redis.Pong{})
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/reply_test.go b/vendor/github.com/garyburd/redigo/redis/reply_test.go
new file mode 100644
index 000000000..2c774866d
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/reply_test.go
@@ -0,0 +1,179 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+type valueError struct {
+ v interface{}
+ err error
+}
+
+func ve(v interface{}, err error) valueError {
+ return valueError{v, err}
+}
+
+var replyTests = []struct {
+ name interface{}
+ actual valueError
+ expected valueError
+}{
+ {
+ "ints([v1, v2])",
+ ve(redis.Ints([]interface{}{[]byte("4"), []byte("5")}, nil)),
+ ve([]int{4, 5}, nil),
+ },
+ {
+ "ints(nil)",
+ ve(redis.Ints(nil, nil)),
+ ve([]int(nil), redis.ErrNil),
+ },
+ {
+ "strings([v1, v2])",
+ ve(redis.Strings([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
+ ve([]string{"v1", "v2"}, nil),
+ },
+ {
+ "strings(nil)",
+ ve(redis.Strings(nil, nil)),
+ ve([]string(nil), redis.ErrNil),
+ },
+ {
+ "byteslices([v1, v2])",
+ ve(redis.ByteSlices([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
+ ve([][]byte{[]byte("v1"), []byte("v2")}, nil),
+ },
+ {
+ "byteslices(nil)",
+ ve(redis.ByteSlices(nil, nil)),
+ ve([][]byte(nil), redis.ErrNil),
+ },
+ {
+ "values([v1, v2])",
+ ve(redis.Values([]interface{}{[]byte("v1"), []byte("v2")}, nil)),
+ ve([]interface{}{[]byte("v1"), []byte("v2")}, nil),
+ },
+ {
+ "values(nil)",
+ ve(redis.Values(nil, nil)),
+ ve([]interface{}(nil), redis.ErrNil),
+ },
+ {
+ "float64(1.0)",
+ ve(redis.Float64([]byte("1.0"), nil)),
+ ve(float64(1.0), nil),
+ },
+ {
+ "float64(nil)",
+ ve(redis.Float64(nil, nil)),
+ ve(float64(0.0), redis.ErrNil),
+ },
+ {
+ "uint64(1)",
+ ve(redis.Uint64(int64(1), nil)),
+ ve(uint64(1), nil),
+ },
+ {
+ "uint64(-1)",
+ ve(redis.Uint64(int64(-1), nil)),
+ ve(uint64(0), redis.ErrNegativeInt),
+ },
+}
+
+func TestReply(t *testing.T) {
+ for _, rt := range replyTests {
+ if rt.actual.err != rt.expected.err {
+ t.Errorf("%s returned err %v, want %v", rt.name, rt.actual.err, rt.expected.err)
+ continue
+ }
+ if !reflect.DeepEqual(rt.actual.v, rt.expected.v) {
+ t.Errorf("%s=%+v, want %+v", rt.name, rt.actual.v, rt.expected.v)
+ }
+ }
+}
+
+// dial wraps DialDefaultServer() with a more suitable function name for examples.
+func dial() (redis.Conn, error) {
+ return redis.DialDefaultServer()
+}
+
+func ExampleBool() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ c.Do("SET", "foo", 1)
+ exists, _ := redis.Bool(c.Do("EXISTS", "foo"))
+ fmt.Printf("%#v\n", exists)
+ // Output:
+ // true
+}
+
+func ExampleInt() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ c.Do("SET", "k1", 1)
+ n, _ := redis.Int(c.Do("GET", "k1"))
+ fmt.Printf("%#v\n", n)
+ n, _ = redis.Int(c.Do("INCR", "k1"))
+ fmt.Printf("%#v\n", n)
+ // Output:
+ // 1
+ // 2
+}
+
+func ExampleInts() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ c.Do("SADD", "set_with_integers", 4, 5, 6)
+ ints, _ := redis.Ints(c.Do("SMEMBERS", "set_with_integers"))
+ fmt.Printf("%#v\n", ints)
+ // Output:
+ // []int{4, 5, 6}
+}
+
+func ExampleString() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ c.Do("SET", "hello", "world")
+ s, err := redis.String(c.Do("GET", "hello"))
+ fmt.Printf("%#v\n", s)
+ // Output:
+ // "world"
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/scan_test.go b/vendor/github.com/garyburd/redigo/redis/scan_test.go
new file mode 100644
index 000000000..d364dff42
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/scan_test.go
@@ -0,0 +1,440 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis_test
+
+import (
+ "fmt"
+ "math"
+ "reflect"
+ "testing"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+var scanConversionTests = []struct {
+ src interface{}
+ dest interface{}
+}{
+ {[]byte("-inf"), math.Inf(-1)},
+ {[]byte("+inf"), math.Inf(1)},
+ {[]byte("0"), float64(0)},
+ {[]byte("3.14159"), float64(3.14159)},
+ {[]byte("3.14"), float32(3.14)},
+ {[]byte("-100"), int(-100)},
+ {[]byte("101"), int(101)},
+ {int64(102), int(102)},
+ {[]byte("103"), uint(103)},
+ {int64(104), uint(104)},
+ {[]byte("105"), int8(105)},
+ {int64(106), int8(106)},
+ {[]byte("107"), uint8(107)},
+ {int64(108), uint8(108)},
+ {[]byte("0"), false},
+ {int64(0), false},
+ {[]byte("f"), false},
+ {[]byte("1"), true},
+ {int64(1), true},
+ {[]byte("t"), true},
+ {"hello", "hello"},
+ {[]byte("hello"), "hello"},
+ {[]byte("world"), []byte("world")},
+ {[]interface{}{[]byte("foo")}, []interface{}{[]byte("foo")}},
+ {[]interface{}{[]byte("foo")}, []string{"foo"}},
+ {[]interface{}{[]byte("hello"), []byte("world")}, []string{"hello", "world"}},
+ {[]interface{}{[]byte("bar")}, [][]byte{[]byte("bar")}},
+ {[]interface{}{[]byte("1")}, []int{1}},
+ {[]interface{}{[]byte("1"), []byte("2")}, []int{1, 2}},
+ {[]interface{}{[]byte("1"), []byte("2")}, []float64{1, 2}},
+ {[]interface{}{[]byte("1")}, []byte{1}},
+ {[]interface{}{[]byte("1")}, []bool{true}},
+}
+
+func TestScanConversion(t *testing.T) {
+ for _, tt := range scanConversionTests {
+ values := []interface{}{tt.src}
+ dest := reflect.New(reflect.TypeOf(tt.dest))
+ values, err := redis.Scan(values, dest.Interface())
+ if err != nil {
+ t.Errorf("Scan(%v) returned error %v", tt, err)
+ continue
+ }
+ if !reflect.DeepEqual(tt.dest, dest.Elem().Interface()) {
+ t.Errorf("Scan(%v) returned %v, want %v", tt, dest.Elem().Interface(), tt.dest)
+ }
+ }
+}
+
+var scanConversionErrorTests = []struct {
+ src interface{}
+ dest interface{}
+}{
+ {[]byte("1234"), byte(0)},
+ {int64(1234), byte(0)},
+ {[]byte("-1"), byte(0)},
+ {int64(-1), byte(0)},
+ {[]byte("junk"), false},
+ {redis.Error("blah"), false},
+}
+
+func TestScanConversionError(t *testing.T) {
+ for _, tt := range scanConversionErrorTests {
+ values := []interface{}{tt.src}
+ dest := reflect.New(reflect.TypeOf(tt.dest))
+ values, err := redis.Scan(values, dest.Interface())
+ if err == nil {
+ t.Errorf("Scan(%v) did not return error", tt)
+ }
+ }
+}
+
+func ExampleScan() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ c.Send("HMSET", "album:1", "title", "Red", "rating", 5)
+ c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1)
+ c.Send("HMSET", "album:3", "title", "Beat")
+ c.Send("LPUSH", "albums", "1")
+ c.Send("LPUSH", "albums", "2")
+ c.Send("LPUSH", "albums", "3")
+ values, err := redis.Values(c.Do("SORT", "albums",
+ "BY", "album:*->rating",
+ "GET", "album:*->title",
+ "GET", "album:*->rating"))
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ for len(values) > 0 {
+ var title string
+ rating := -1 // initialize to illegal value to detect nil.
+ values, err = redis.Scan(values, &title, &rating)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ if rating == -1 {
+ fmt.Println(title, "not-rated")
+ } else {
+ fmt.Println(title, rating)
+ }
+ }
+ // Output:
+ // Beat not-rated
+ // Earthbound 1
+ // Red 5
+}
+
+type s0 struct {
+ X int
+ Y int `redis:"y"`
+ Bt bool
+}
+
+type s1 struct {
+ X int `redis:"-"`
+ I int `redis:"i"`
+ U uint `redis:"u"`
+ S string `redis:"s"`
+ P []byte `redis:"p"`
+ B bool `redis:"b"`
+ Bt bool
+ Bf bool
+ s0
+}
+
+var scanStructTests = []struct {
+ title string
+ reply []string
+ value interface{}
+}{
+ {"basic",
+ []string{"i", "-1234", "u", "5678", "s", "hello", "p", "world", "b", "t", "Bt", "1", "Bf", "0", "X", "123", "y", "456"},
+ &s1{I: -1234, U: 5678, S: "hello", P: []byte("world"), B: true, Bt: true, Bf: false, s0: s0{X: 123, Y: 456}},
+ },
+}
+
+func TestScanStruct(t *testing.T) {
+ for _, tt := range scanStructTests {
+
+ var reply []interface{}
+ for _, v := range tt.reply {
+ reply = append(reply, []byte(v))
+ }
+
+ value := reflect.New(reflect.ValueOf(tt.value).Type().Elem())
+
+ if err := redis.ScanStruct(reply, value.Interface()); err != nil {
+ t.Fatalf("ScanStruct(%s) returned error %v", tt.title, err)
+ }
+
+ if !reflect.DeepEqual(value.Interface(), tt.value) {
+ t.Fatalf("ScanStruct(%s) returned %v, want %v", tt.title, value.Interface(), tt.value)
+ }
+ }
+}
+
+func TestBadScanStructArgs(t *testing.T) {
+ x := []interface{}{"A", "b"}
+ test := func(v interface{}) {
+ if err := redis.ScanStruct(x, v); err == nil {
+ t.Errorf("Expect error for ScanStruct(%T, %T)", x, v)
+ }
+ }
+
+ test(nil)
+
+ var v0 *struct{}
+ test(v0)
+
+ var v1 int
+ test(&v1)
+
+ x = x[:1]
+ v2 := struct{ A string }{}
+ test(&v2)
+}
+
+var scanSliceTests = []struct {
+ src []interface{}
+ fieldNames []string
+ ok bool
+ dest interface{}
+}{
+ {
+ []interface{}{[]byte("1"), nil, []byte("-1")},
+ nil,
+ true,
+ []int{1, 0, -1},
+ },
+ {
+ []interface{}{[]byte("1"), nil, []byte("2")},
+ nil,
+ true,
+ []uint{1, 0, 2},
+ },
+ {
+ []interface{}{[]byte("-1")},
+ nil,
+ false,
+ []uint{1},
+ },
+ {
+ []interface{}{[]byte("hello"), nil, []byte("world")},
+ nil,
+ true,
+ [][]byte{[]byte("hello"), nil, []byte("world")},
+ },
+ {
+ []interface{}{[]byte("hello"), nil, []byte("world")},
+ nil,
+ true,
+ []string{"hello", "", "world"},
+ },
+ {
+ []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
+ nil,
+ true,
+ []struct{ A, B string }{{"a1", "b1"}, {"a2", "b2"}},
+ },
+ {
+ []interface{}{[]byte("a1"), []byte("b1")},
+ nil,
+ false,
+ []struct{ A, B, C string }{{"a1", "b1", ""}},
+ },
+ {
+ []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
+ nil,
+ true,
+ []*struct{ A, B string }{{"a1", "b1"}, {"a2", "b2"}},
+ },
+ {
+ []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
+ []string{"A", "B"},
+ true,
+ []struct{ A, C, B string }{{"a1", "", "b1"}, {"a2", "", "b2"}},
+ },
+ {
+ []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
+ nil,
+ false,
+ []struct{}{},
+ },
+}
+
+func TestScanSlice(t *testing.T) {
+ for _, tt := range scanSliceTests {
+
+ typ := reflect.ValueOf(tt.dest).Type()
+ dest := reflect.New(typ)
+
+ err := redis.ScanSlice(tt.src, dest.Interface(), tt.fieldNames...)
+ if tt.ok != (err == nil) {
+ t.Errorf("ScanSlice(%v, []%s, %v) returned error %v", tt.src, typ, tt.fieldNames, err)
+ continue
+ }
+ if tt.ok && !reflect.DeepEqual(dest.Elem().Interface(), tt.dest) {
+ t.Errorf("ScanSlice(src, []%s) returned %#v, want %#v", typ, dest.Elem().Interface(), tt.dest)
+ }
+ }
+}
+
+func ExampleScanSlice() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ c.Send("HMSET", "album:1", "title", "Red", "rating", 5)
+ c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1)
+ c.Send("HMSET", "album:3", "title", "Beat", "rating", 4)
+ c.Send("LPUSH", "albums", "1")
+ c.Send("LPUSH", "albums", "2")
+ c.Send("LPUSH", "albums", "3")
+ values, err := redis.Values(c.Do("SORT", "albums",
+ "BY", "album:*->rating",
+ "GET", "album:*->title",
+ "GET", "album:*->rating"))
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ var albums []struct {
+ Title string
+ Rating int
+ }
+ if err := redis.ScanSlice(values, &albums); err != nil {
+ fmt.Println(err)
+ return
+ }
+ fmt.Printf("%v\n", albums)
+ // Output:
+ // [{Earthbound 1} {Beat 4} {Red 5}]
+}
+
+var argsTests = []struct {
+ title string
+ actual redis.Args
+ expected redis.Args
+}{
+ {"struct ptr",
+ redis.Args{}.AddFlat(&struct {
+ I int `redis:"i"`
+ U uint `redis:"u"`
+ S string `redis:"s"`
+ P []byte `redis:"p"`
+ M map[string]string `redis:"m"`
+ Bt bool
+ Bf bool
+ }{
+ -1234, 5678, "hello", []byte("world"), map[string]string{"hello": "world"}, true, false,
+ }),
+ redis.Args{"i", int(-1234), "u", uint(5678), "s", "hello", "p", []byte("world"), "m", map[string]string{"hello": "world"}, "Bt", true, "Bf", false},
+ },
+ {"struct",
+ redis.Args{}.AddFlat(struct{ I int }{123}),
+ redis.Args{"I", 123},
+ },
+ {"slice",
+ redis.Args{}.Add(1).AddFlat([]string{"a", "b", "c"}).Add(2),
+ redis.Args{1, "a", "b", "c", 2},
+ },
+ {"struct omitempty",
+ redis.Args{}.AddFlat(&struct {
+ I int `redis:"i,omitempty"`
+ U uint `redis:"u,omitempty"`
+ S string `redis:"s,omitempty"`
+ P []byte `redis:"p,omitempty"`
+ M map[string]string `redis:"m,omitempty"`
+ Bt bool `redis:"Bt,omitempty"`
+ Bf bool `redis:"Bf,omitempty"`
+ }{
+ 0, 0, "", []byte{}, map[string]string{}, true, false,
+ }),
+ redis.Args{"Bt", true},
+ },
+}
+
+func TestArgs(t *testing.T) {
+ for _, tt := range argsTests {
+ if !reflect.DeepEqual(tt.actual, tt.expected) {
+ t.Fatalf("%s is %v, want %v", tt.title, tt.actual, tt.expected)
+ }
+ }
+}
+
+func ExampleArgs() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ var p1, p2 struct {
+ Title string `redis:"title"`
+ Author string `redis:"author"`
+ Body string `redis:"body"`
+ }
+
+ p1.Title = "Example"
+ p1.Author = "Gary"
+ p1.Body = "Hello"
+
+ if _, err := c.Do("HMSET", redis.Args{}.Add("id1").AddFlat(&p1)...); err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ m := map[string]string{
+ "title": "Example2",
+ "author": "Steve",
+ "body": "Map",
+ }
+
+ if _, err := c.Do("HMSET", redis.Args{}.Add("id2").AddFlat(m)...); err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ for _, id := range []string{"id1", "id2"} {
+
+ v, err := redis.Values(c.Do("HGETALL", id))
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ if err := redis.ScanStruct(v, &p2); err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fmt.Printf("%+v\n", p2)
+ }
+
+ // Output:
+ // {Title:Example Author:Gary Body:Hello}
+ // {Title:Example2 Author:Steve Body:Map}
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/script_test.go b/vendor/github.com/garyburd/redigo/redis/script_test.go
new file mode 100644
index 000000000..af282415c
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/script_test.go
@@ -0,0 +1,100 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis_test
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+ "time"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+var (
+ // These variables are declared at package level to remove distracting
+ // details from the examples.
+ c redis.Conn
+ reply interface{}
+ err error
+)
+
+func ExampleScript() {
+ // Initialize a package-level variable with a script.
+ var getScript = redis.NewScript(1, `return redis.call('get', KEYS[1])`)
+
+ // In a function, use the script Do method to evaluate the script. The Do
+ // method optimistically uses the EVALSHA command. If the script is not
+ // loaded, then the Do method falls back to the EVAL command.
+ reply, err = getScript.Do(c, "foo")
+}
+
+func TestScript(t *testing.T) {
+ c, err := redis.DialDefaultServer()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ // To test fall back in Do, we make script unique by adding comment with current time.
+ script := fmt.Sprintf("--%d\nreturn {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}", time.Now().UnixNano())
+ s := redis.NewScript(2, script)
+ reply := []interface{}{[]byte("key1"), []byte("key2"), []byte("arg1"), []byte("arg2")}
+
+ v, err := s.Do(c, "key1", "key2", "arg1", "arg2")
+ if err != nil {
+ t.Errorf("s.Do(c, ...) returned %v", err)
+ }
+
+ if !reflect.DeepEqual(v, reply) {
+ t.Errorf("s.Do(c, ..); = %v, want %v", v, reply)
+ }
+
+ err = s.Load(c)
+ if err != nil {
+ t.Errorf("s.Load(c) returned %v", err)
+ }
+
+ err = s.SendHash(c, "key1", "key2", "arg1", "arg2")
+ if err != nil {
+ t.Errorf("s.SendHash(c, ...) returned %v", err)
+ }
+
+ err = c.Flush()
+ if err != nil {
+ t.Errorf("c.Flush() returned %v", err)
+ }
+
+ v, err = c.Receive()
+ if !reflect.DeepEqual(v, reply) {
+ t.Errorf("s.SendHash(c, ..); c.Receive() = %v, want %v", v, reply)
+ }
+
+ err = s.Send(c, "key1", "key2", "arg1", "arg2")
+ if err != nil {
+ t.Errorf("s.Send(c, ...) returned %v", err)
+ }
+
+ err = c.Flush()
+ if err != nil {
+ t.Errorf("c.Flush() returned %v", err)
+ }
+
+ v, err = c.Receive()
+ if !reflect.DeepEqual(v, reply) {
+ t.Errorf("s.Send(c, ..); c.Receive() = %v, want %v", v, reply)
+ }
+
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/test_test.go b/vendor/github.com/garyburd/redigo/redis/test_test.go
new file mode 100644
index 000000000..7240fa1f3
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/test_test.go
@@ -0,0 +1,177 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis
+
+import (
+ "bufio"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+func SetNowFunc(f func() time.Time) {
+ nowFunc = f
+}
+
+var (
+ ErrNegativeInt = errNegativeInt
+
+ serverPath = flag.String("redis-server", "redis-server", "Path to redis server binary")
+ serverBasePort = flag.Int("redis-port", 16379, "Beginning of port range for test servers")
+ serverLogName = flag.String("redis-log", "", "Write Redis server logs to `filename`")
+ serverLog = ioutil.Discard
+
+ defaultServerMu sync.Mutex
+ defaultServer *Server
+ defaultServerErr error
+)
+
+type Server struct {
+ name string
+ cmd *exec.Cmd
+ done chan struct{}
+}
+
+func NewServer(name string, args ...string) (*Server, error) {
+ s := &Server{
+ name: name,
+ cmd: exec.Command(*serverPath, args...),
+ done: make(chan struct{}),
+ }
+
+ r, err := s.cmd.StdoutPipe()
+ if err != nil {
+ return nil, err
+ }
+
+ err = s.cmd.Start()
+ if err != nil {
+ return nil, err
+ }
+
+ ready := make(chan error, 1)
+ go s.watch(r, ready)
+
+ select {
+ case err = <-ready:
+ case <-time.After(time.Second * 10):
+ err = errors.New("timeout waiting for server to start")
+ }
+
+ if err != nil {
+ s.Stop()
+ return nil, err
+ }
+
+ return s, nil
+}
+
+func (s *Server) watch(r io.Reader, ready chan error) {
+ fmt.Fprintf(serverLog, "%d START %s \n", s.cmd.Process.Pid, s.name)
+ var listening bool
+ var text string
+ scn := bufio.NewScanner(r)
+ for scn.Scan() {
+ text = scn.Text()
+ fmt.Fprintf(serverLog, "%s\n", text)
+ if !listening {
+ if strings.Contains(text, "The server is now ready to accept connections on port") {
+ listening = true
+ ready <- nil
+ }
+ }
+ }
+ if !listening {
+ ready <- fmt.Errorf("server exited: %s", text)
+ }
+ s.cmd.Wait()
+ fmt.Fprintf(serverLog, "%d STOP %s \n", s.cmd.Process.Pid, s.name)
+ close(s.done)
+}
+
+func (s *Server) Stop() {
+ s.cmd.Process.Signal(os.Interrupt)
+ <-s.done
+}
+
+// stopDefaultServer stops the server created by DialDefaultServer.
+func stopDefaultServer() {
+ defaultServerMu.Lock()
+ defer defaultServerMu.Unlock()
+ if defaultServer != nil {
+ defaultServer.Stop()
+ defaultServer = nil
+ }
+}
+
+// startDefaultServer starts the default server if not already running.
+func startDefaultServer() error {
+ defaultServerMu.Lock()
+ defer defaultServerMu.Unlock()
+ if defaultServer != nil || defaultServerErr != nil {
+ return defaultServerErr
+ }
+ defaultServer, defaultServerErr = NewServer(
+ "default",
+ "--port", strconv.Itoa(*serverBasePort),
+ "--save", "",
+ "--appendonly", "no")
+ return defaultServerErr
+}
+
+// DialDefaultServer starts the test server if not already started and dials a
+// connection to the server.
+func DialDefaultServer() (Conn, error) {
+ if err := startDefaultServer(); err != nil {
+ return nil, err
+ }
+ c, err := Dial("tcp", fmt.Sprintf(":%d", *serverBasePort), DialReadTimeout(1*time.Second), DialWriteTimeout(1*time.Second))
+ if err != nil {
+ return nil, err
+ }
+ c.Do("FLUSHDB")
+ return c, nil
+}
+
+func TestMain(m *testing.M) {
+ os.Exit(func() int {
+ flag.Parse()
+
+ var f *os.File
+ if *serverLogName != "" {
+ var err error
+ f, err = os.OpenFile(*serverLogName, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error opening redis-log: %v\n", err)
+ return 1
+ }
+ defer f.Close()
+ serverLog = f
+ }
+
+ defer stopDefaultServer()
+
+ return m.Run()
+ }())
+}
diff --git a/vendor/github.com/garyburd/redigo/redis/zpop_example_test.go b/vendor/github.com/garyburd/redigo/redis/zpop_example_test.go
new file mode 100644
index 000000000..1d86ee6ce
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redis/zpop_example_test.go
@@ -0,0 +1,113 @@
+// Copyright 2013 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redis_test
+
+import (
+ "fmt"
+ "github.com/garyburd/redigo/redis"
+)
+
+// zpop pops a value from the ZSET key using WATCH/MULTI/EXEC commands.
+func zpop(c redis.Conn, key string) (result string, err error) {
+
+ defer func() {
+ // Return connection to normal state on error.
+ if err != nil {
+ c.Do("DISCARD")
+ }
+ }()
+
+ // Loop until transaction is successful.
+ for {
+ if _, err := c.Do("WATCH", key); err != nil {
+ return "", err
+ }
+
+ members, err := redis.Strings(c.Do("ZRANGE", key, 0, 0))
+ if err != nil {
+ return "", err
+ }
+ if len(members) != 1 {
+ return "", redis.ErrNil
+ }
+
+ c.Send("MULTI")
+ c.Send("ZREM", key, members[0])
+ queued, err := c.Do("EXEC")
+ if err != nil {
+ return "", err
+ }
+
+ if queued != nil {
+ result = members[0]
+ break
+ }
+ }
+
+ return result, nil
+}
+
+// zpopScript pops a value from a ZSET.
+var zpopScript = redis.NewScript(1, `
+ local r = redis.call('ZRANGE', KEYS[1], 0, 0)
+ if r ~= nil then
+ r = r[1]
+ redis.call('ZREM', KEYS[1], r)
+ end
+ return r
+`)
+
+// This example implements ZPOP as described at
+// http://redis.io/topics/transactions using WATCH/MULTI/EXEC and scripting.
+func Example_zpop() {
+ c, err := dial()
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ defer c.Close()
+
+ // Add test data using a pipeline.
+
+ for i, member := range []string{"red", "blue", "green"} {
+ c.Send("ZADD", "zset", i, member)
+ }
+ if _, err := c.Do(""); err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ // Pop using WATCH/MULTI/EXEC
+
+ v, err := zpop(c, "zset")
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ fmt.Println(v)
+
+ // Pop using a script.
+
+ v, err = redis.String(zpopScript.Do(c, "zset"))
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ fmt.Println(v)
+
+ // Output:
+ // red
+ // blue
+}
diff --git a/vendor/github.com/garyburd/redigo/redisx/connmux.go b/vendor/github.com/garyburd/redigo/redisx/connmux.go
new file mode 100644
index 000000000..af2cced3f
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redisx/connmux.go
@@ -0,0 +1,152 @@
+// Copyright 2014 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redisx
+
+import (
+ "errors"
+ "sync"
+
+ "github.com/garyburd/redigo/internal"
+ "github.com/garyburd/redigo/redis"
+)
+
+// ConnMux multiplexes one or more connections to a single underlying
+// connection. The ConnMux connections do not support concurrency, commands
+// that associate server side state with the connection or commands that put
+// the connection in a special mode.
+type ConnMux struct {
+ c redis.Conn
+
+ sendMu sync.Mutex
+ sendID uint
+
+ recvMu sync.Mutex
+ recvID uint
+ recvWait map[uint]chan struct{}
+}
+
+func NewConnMux(c redis.Conn) *ConnMux {
+ return &ConnMux{c: c, recvWait: make(map[uint]chan struct{})}
+}
+
+// Get gets a connection. The application must close the returned connection.
+func (p *ConnMux) Get() redis.Conn {
+ c := &muxConn{p: p}
+ c.ids = c.buf[:0]
+ return c
+}
+
+// Close closes the underlying connection.
+func (p *ConnMux) Close() error {
+ return p.c.Close()
+}
+
+type muxConn struct {
+ p *ConnMux
+ ids []uint
+ buf [8]uint
+}
+
+func (c *muxConn) send(flush bool, cmd string, args ...interface{}) error {
+ if internal.LookupCommandInfo(cmd).Set != 0 {
+ return errors.New("command not supported by mux pool")
+ }
+ p := c.p
+ p.sendMu.Lock()
+ id := p.sendID
+ c.ids = append(c.ids, id)
+ p.sendID++
+ err := p.c.Send(cmd, args...)
+ if flush {
+ err = p.c.Flush()
+ }
+ p.sendMu.Unlock()
+ return err
+}
+
+func (c *muxConn) Send(cmd string, args ...interface{}) error {
+ return c.send(false, cmd, args...)
+}
+
+func (c *muxConn) Flush() error {
+ p := c.p
+ p.sendMu.Lock()
+ err := p.c.Flush()
+ p.sendMu.Unlock()
+ return err
+}
+
+func (c *muxConn) Receive() (interface{}, error) {
+ if len(c.ids) == 0 {
+ return nil, errors.New("mux pool underflow")
+ }
+
+ id := c.ids[0]
+ c.ids = c.ids[1:]
+ if len(c.ids) == 0 {
+ c.ids = c.buf[:0]
+ }
+
+ p := c.p
+ p.recvMu.Lock()
+ if p.recvID != id {
+ ch := make(chan struct{})
+ p.recvWait[id] = ch
+ p.recvMu.Unlock()
+ <-ch
+ p.recvMu.Lock()
+ if p.recvID != id {
+ panic("out of sync")
+ }
+ }
+
+ v, err := p.c.Receive()
+
+ id++
+ p.recvID = id
+ ch, ok := p.recvWait[id]
+ if ok {
+ delete(p.recvWait, id)
+ }
+ p.recvMu.Unlock()
+ if ok {
+ ch <- struct{}{}
+ }
+
+ return v, err
+}
+
+func (c *muxConn) Close() error {
+ var err error
+ if len(c.ids) == 0 {
+ return nil
+ }
+ c.Flush()
+ for _ = range c.ids {
+ _, err = c.Receive()
+ }
+ return err
+}
+
+func (c *muxConn) Do(cmd string, args ...interface{}) (interface{}, error) {
+ if err := c.send(true, cmd, args...); err != nil {
+ return nil, err
+ }
+ return c.Receive()
+}
+
+func (c *muxConn) Err() error {
+ return c.p.c.Err()
+}
diff --git a/vendor/github.com/garyburd/redigo/redisx/connmux_test.go b/vendor/github.com/garyburd/redigo/redisx/connmux_test.go
new file mode 100644
index 000000000..9c3c8b162
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redisx/connmux_test.go
@@ -0,0 +1,259 @@
+// Copyright 2014 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+package redisx_test
+
+import (
+ "net/textproto"
+ "sync"
+ "testing"
+
+ "github.com/garyburd/redigo/internal/redistest"
+ "github.com/garyburd/redigo/redis"
+ "github.com/garyburd/redigo/redisx"
+)
+
+func TestConnMux(t *testing.T) {
+ c, err := redistest.Dial()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ m := redisx.NewConnMux(c)
+ defer m.Close()
+
+ c1 := m.Get()
+ c2 := m.Get()
+ c1.Send("ECHO", "hello")
+ c2.Send("ECHO", "world")
+ c1.Flush()
+ c2.Flush()
+ s, err := redis.String(c1.Receive())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s != "hello" {
+ t.Fatalf("echo returned %q, want %q", s, "hello")
+ }
+ s, err = redis.String(c2.Receive())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s != "world" {
+ t.Fatalf("echo returned %q, want %q", s, "world")
+ }
+ c1.Close()
+ c2.Close()
+}
+
+func TestConnMuxClose(t *testing.T) {
+ c, err := redistest.Dial()
+ if err != nil {
+ t.Fatalf("error connection to database, %v", err)
+ }
+ m := redisx.NewConnMux(c)
+ defer m.Close()
+
+ c1 := m.Get()
+ c2 := m.Get()
+
+ if err := c1.Send("ECHO", "hello"); err != nil {
+ t.Fatal(err)
+ }
+ if err := c1.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ if err := c2.Send("ECHO", "world"); err != nil {
+ t.Fatal(err)
+ }
+ if err := c2.Flush(); err != nil {
+ t.Fatal(err)
+ }
+
+ s, err := redis.String(c2.Receive())
+ if err != nil {
+ t.Fatal(err)
+ }
+ if s != "world" {
+ t.Fatalf("echo returned %q, want %q", s, "world")
+ }
+ c2.Close()
+}
+
+func BenchmarkConn(b *testing.B) {
+ b.StopTimer()
+ c, err := redistest.Dial()
+ if err != nil {
+ b.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ if _, err := c.Do("PING"); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkConnMux(b *testing.B) {
+ b.StopTimer()
+ c, err := redistest.Dial()
+ if err != nil {
+ b.Fatalf("error connection to database, %v", err)
+ }
+ m := redisx.NewConnMux(c)
+ defer m.Close()
+
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ c := m.Get()
+ if _, err := c.Do("PING"); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ }
+}
+
+func BenchmarkPool(b *testing.B) {
+ b.StopTimer()
+
+ p := redis.Pool{Dial: redistest.Dial, MaxIdle: 1}
+ defer p.Close()
+
+ // Fill the pool.
+ c := p.Get()
+ if err := c.Err(); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ c := p.Get()
+ if _, err := c.Do("PING"); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ }
+}
+
+const numConcurrent = 10
+
+func BenchmarkConnMuxConcurrent(b *testing.B) {
+ b.StopTimer()
+ c, err := redistest.Dial()
+ if err != nil {
+ b.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ m := redisx.NewConnMux(c)
+
+ var wg sync.WaitGroup
+ wg.Add(numConcurrent)
+
+ b.StartTimer()
+
+ for i := 0; i < numConcurrent; i++ {
+ go func() {
+ defer wg.Done()
+ for i := 0; i < b.N; i++ {
+ c := m.Get()
+ if _, err := c.Do("PING"); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func BenchmarkPoolConcurrent(b *testing.B) {
+ b.StopTimer()
+
+ p := redis.Pool{Dial: redistest.Dial, MaxIdle: numConcurrent}
+ defer p.Close()
+
+ // Fill the pool.
+ conns := make([]redis.Conn, numConcurrent)
+ for i := range conns {
+ c := p.Get()
+ if err := c.Err(); err != nil {
+ b.Fatal(err)
+ }
+ conns[i] = c
+ }
+ for _, c := range conns {
+ c.Close()
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(numConcurrent)
+
+ b.StartTimer()
+
+ for i := 0; i < numConcurrent; i++ {
+ go func() {
+ defer wg.Done()
+ for i := 0; i < b.N; i++ {
+ c := p.Get()
+ if _, err := c.Do("PING"); err != nil {
+ b.Fatal(err)
+ }
+ c.Close()
+ }
+ }()
+ }
+ wg.Wait()
+}
+
+func BenchmarkPipelineConcurrency(b *testing.B) {
+ b.StopTimer()
+ c, err := redistest.Dial()
+ if err != nil {
+ b.Fatalf("error connection to database, %v", err)
+ }
+ defer c.Close()
+
+ var wg sync.WaitGroup
+ wg.Add(numConcurrent)
+
+ var pipeline textproto.Pipeline
+
+ b.StartTimer()
+
+ for i := 0; i < numConcurrent; i++ {
+ go func() {
+ defer wg.Done()
+ for i := 0; i < b.N; i++ {
+ id := pipeline.Next()
+ pipeline.StartRequest(id)
+ c.Send("PING")
+ c.Flush()
+ pipeline.EndRequest(id)
+ pipeline.StartResponse(id)
+ _, err := c.Receive()
+ if err != nil {
+ b.Fatal(err)
+ }
+ pipeline.EndResponse(id)
+ }
+ }()
+ }
+ wg.Wait()
+}
diff --git a/vendor/github.com/garyburd/redigo/redisx/doc.go b/vendor/github.com/garyburd/redigo/redisx/doc.go
new file mode 100644
index 000000000..91653dbe2
--- /dev/null
+++ b/vendor/github.com/garyburd/redigo/redisx/doc.go
@@ -0,0 +1,17 @@
+// Copyright 2012 Gary Burd
+//
+// Licensed under the Apache License, Version 2.0 (the "License"): you may
+// not use this file except in compliance with the License. You may obtain
+// a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+
+// Package redisx contains experimental features for Redigo. Features in this
+// package may be modified or deleted at any time.
+package redisx // import "github.com/garyburd/redigo/redisx"
diff --git a/vendor/github.com/go-gorp/gorp/dialect_mysql_test.go b/vendor/github.com/go-gorp/gorp/dialect_mysql_test.go
new file mode 100644
index 000000000..d1018cf69
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/dialect_mysql_test.go
@@ -0,0 +1,204 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// Package gorp provides a simple way to marshal Go structs to and from
+// SQL databases. It uses the database/sql package, and should work with any
+// compliant database/sql driver.
+//
+// Source code and project home:
+// https://github.com/go-gorp/gorp
+
+package gorp_test
+
+import (
+ "database/sql"
+ "reflect"
+ "time"
+
+ // ginkgo/gomega functions read better as dot-imports.
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/ginkgo/extensions/table"
+ . "github.com/onsi/gomega"
+
+ "github.com/go-gorp/gorp"
+)
+
+var _ = Describe("MySQLDialect", func() {
+ var (
+ engine, encoding string
+ dialect gorp.MySQLDialect
+ )
+
+ JustBeforeEach(func() {
+ dialect = gorp.MySQLDialect{
+ Engine: engine,
+ Encoding: encoding,
+ }
+ })
+
+ DescribeTable("ToSqlType",
+ func(value interface{}, maxsize int, autoIncr bool, expected string) {
+ typ := reflect.TypeOf(value)
+ sqlType := dialect.ToSqlType(typ, maxsize, autoIncr)
+ Expect(sqlType).To(Equal(expected))
+ },
+ Entry("bool", true, 0, false, "boolean"),
+ Entry("int8", int8(1), 0, false, "tinyint"),
+ Entry("uint8", uint8(1), 0, false, "tinyint unsigned"),
+ Entry("int16", int16(1), 0, false, "smallint"),
+ Entry("uint16", uint16(1), 0, false, "smallint unsigned"),
+ Entry("int32", int32(1), 0, false, "int"),
+ Entry("int (treated as int32)", int(1), 0, false, "int"),
+ Entry("uint32", uint32(1), 0, false, "int unsigned"),
+ Entry("uint (treated as uint32)", uint(1), 0, false, "int unsigned"),
+ Entry("int64", int64(1), 0, false, "bigint"),
+ Entry("uint64", uint64(1), 0, false, "bigint unsigned"),
+ Entry("float32", float32(1), 0, false, "double"),
+ Entry("float64", float64(1), 0, false, "double"),
+ Entry("[]uint8", []uint8{1}, 0, false, "mediumblob"),
+ Entry("NullInt64", sql.NullInt64{}, 0, false, "bigint"),
+ Entry("NullFloat64", sql.NullFloat64{}, 0, false, "double"),
+ Entry("NullBool", sql.NullBool{}, 0, false, "tinyint"),
+ Entry("Time", time.Time{}, 0, false, "datetime"),
+ Entry("default-size string", "", 0, false, "varchar(255)"),
+ Entry("sized string", "", 50, false, "varchar(50)"),
+ Entry("large string", "", 1024, false, "text"),
+ )
+
+ Describe("AutoIncrStr", func() {
+ It("returns the auto increment string", func() {
+ Expect(dialect.AutoIncrStr()).To(Equal("auto_increment"))
+ })
+ })
+
+ Describe("AutoIncrBindValue", func() {
+ It("returns the value used to bind the auto-increment value", func() {
+ Expect(dialect.AutoIncrBindValue()).To(Equal("null"))
+ })
+ })
+
+ Describe("AutoIncrInsertSuffix", func() {
+ It("returns the suffix needed for auto-incrementing", func() {
+ Expect(dialect.AutoIncrInsertSuffix(nil)).To(BeEmpty())
+ })
+ })
+
+ Describe("CreateTableSuffix", func() {
+ Context("with an empty engine", func() {
+ BeforeEach(func() {
+ engine = ""
+ encoding = "foo"
+ })
+ It("panics", func() {
+ Expect(func() {
+ dialect.CreateTableSuffix()
+ }).To(Panic())
+ })
+ })
+
+ Context("with an empty encoding", func() {
+ BeforeEach(func() {
+ engine = "foo"
+ encoding = ""
+ })
+ It("panics", func() {
+ Expect(func() {
+ dialect.CreateTableSuffix()
+ }).To(Panic())
+ })
+ })
+
+ Context("with an engine and an encoding", func() {
+ BeforeEach(func() {
+ engine = "foo"
+ encoding = "bar"
+ })
+ It("returns a valid suffix", func() {
+ Expect(dialect.CreateTableSuffix()).To(Equal(" engine=foo charset=bar"))
+ })
+ })
+ })
+
+ Describe("CreateIndexSuffix", func() {
+ It("returns the suffix for creating indexes", func() {
+ Expect(dialect.CreateIndexSuffix()).To(Equal("using"))
+ })
+ })
+
+ Describe("DropIndexSuffix", func() {
+ It("returns the suffix for deleting indexes", func() {
+ Expect(dialect.DropIndexSuffix()).To(Equal("on"))
+ })
+ })
+
+ Describe("TruncateClause", func() {
+ It("returns the clause for truncating a table", func() {
+ Expect(dialect.TruncateClause()).To(Equal("truncate"))
+ })
+ })
+
+ Describe("BindVar", func() {
+ It("returns the variable binding sequence", func() {
+ Expect(dialect.BindVar(0)).To(Equal("?"))
+ })
+ })
+
+ PDescribe("InsertAutoIncr", func() {})
+
+ Describe("QuoteField", func() {
+ It("returns the argument quoted as a field", func() {
+ Expect(dialect.QuoteField("foo")).To(Equal("`foo`"))
+ })
+ })
+
+ Describe("QuotedTableForQuery", func() {
+ var (
+ schema, table string
+
+ quotedTable string
+ )
+
+ JustBeforeEach(func() {
+ quotedTable = dialect.QuotedTableForQuery(schema, table)
+ })
+
+ Context("using the default schema", func() {
+ BeforeEach(func() {
+ schema = ""
+ table = "foo"
+ })
+ It("returns just the table", func() {
+ Expect(quotedTable).To(Equal("`foo`"))
+ })
+ })
+
+ Context("with a supplied schema", func() {
+ BeforeEach(func() {
+ schema = "foo"
+ table = "bar"
+ })
+ It("returns the schema and table", func() {
+ Expect(quotedTable).To(Equal("foo.`bar`"))
+ })
+ })
+ })
+
+ Describe("IfSchemaNotExists", func() {
+ It("appends 'if not exists' to the command", func() {
+ Expect(dialect.IfSchemaNotExists("foo", "bar")).To(Equal("foo if not exists"))
+ })
+ })
+
+ Describe("IfTableExists", func() {
+ It("appends 'if exists' to the command", func() {
+ Expect(dialect.IfTableExists("foo", "bar", "baz")).To(Equal("foo if exists"))
+ })
+ })
+
+ Describe("IfTableNotExists", func() {
+ It("appends 'if not exists' to the command", func() {
+ Expect(dialect.IfTableNotExists("foo", "bar", "baz")).To(Equal("foo if not exists"))
+ })
+ })
+})
diff --git a/vendor/github.com/go-gorp/gorp/gorp_suite_test.go b/vendor/github.com/go-gorp/gorp/gorp_suite_test.go
new file mode 100644
index 000000000..2abcaaf71
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/gorp_suite_test.go
@@ -0,0 +1,13 @@
+package gorp_test
+
+import (
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+
+ "testing"
+)
+
+func TestGorp(t *testing.T) {
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Gorp Suite")
+}
diff --git a/vendor/github.com/go-gorp/gorp/gorp_test.go b/vendor/github.com/go-gorp/gorp/gorp_test.go
new file mode 100644
index 000000000..7b2307158
--- /dev/null
+++ b/vendor/github.com/go-gorp/gorp/gorp_test.go
@@ -0,0 +1,2412 @@
+// Copyright 2012 James Cooper. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+// Package gorp provides a simple way to marshal Go structs to and from
+// SQL databases. It uses the database/sql package, and should work with any
+// compliant database/sql driver.
+//
+// Source code and project home:
+// https://github.com/go-gorp/gorp
+
+package gorp_test
+
+import (
+ "bytes"
+ "database/sql"
+ "database/sql/driver"
+ "encoding/json"
+ "errors"
+ "flag"
+ "fmt"
+ "log"
+ "math/rand"
+ "os"
+ "reflect"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/go-gorp/gorp"
+
+ _ "github.com/go-sql-driver/mysql"
+ _ "github.com/lib/pq"
+ _ "github.com/mattn/go-sqlite3"
+ _ "github.com/ziutek/mymysql/godrv"
+)
+
+var (
+ // verify interface compliance
+ _ = []gorp.Dialect{
+ gorp.SqliteDialect{},
+ gorp.PostgresDialect{},
+ gorp.MySQLDialect{},
+ gorp.SqlServerDialect{},
+ gorp.OracleDialect{},
+ }
+
+ debug bool
+)
+
+func init() {
+ flag.BoolVar(&debug, "trace", true, "Turn on or off database tracing (DbMap.TraceOn)")
+ flag.Parse()
+}
+
+type testable interface {
+ GetId() int64
+ Rand()
+}
+
+type Invoice struct {
+ Id int64
+ Created int64
+ Updated int64
+ Memo string
+ PersonId int64
+ IsPaid bool
+}
+
+type InvoiceWithValuer struct {
+ Id int64
+ Created int64
+ Updated int64
+ Memo string
+ Person PersonValuerScanner `db:"personid"`
+ IsPaid bool
+}
+
+func (me *Invoice) GetId() int64 { return me.Id }
+func (me *Invoice) Rand() {
+ me.Memo = fmt.Sprintf("random %d", rand.Int63())
+ me.Created = rand.Int63()
+ me.Updated = rand.Int63()
+}
+
+type InvoiceTag struct {
+ Id int64 `db:"myid, primarykey, autoincrement"`
+ Created int64 `db:"myCreated"`
+ Updated int64 `db:"date_updated"`
+ Memo string
+ PersonId int64 `db:"person_id"`
+ IsPaid bool `db:"is_Paid"`
+}
+
+func (me *InvoiceTag) GetId() int64 { return me.Id }
+func (me *InvoiceTag) Rand() {
+ me.Memo = fmt.Sprintf("random %d", rand.Int63())
+ me.Created = rand.Int63()
+ me.Updated = rand.Int63()
+}
+
+// See: https://github.com/go-gorp/gorp/issues/175
+type AliasTransientField struct {
+ Id int64 `db:"id"`
+ Bar int64 `db:"-"`
+ BarStr string `db:"bar"`
+}
+
+func (me *AliasTransientField) GetId() int64 { return me.Id }
+func (me *AliasTransientField) Rand() {
+ me.BarStr = fmt.Sprintf("random %d", rand.Int63())
+}
+
+type OverriddenInvoice struct {
+ Invoice
+ Id string
+}
+
+type Person struct {
+ Id int64
+ Created int64
+ Updated int64
+ FName string
+ LName string
+ Version int64
+}
+
+// PersonValuerScanner is used as a field in test types to ensure that we
+// make use of "database/sql/driver".Valuer for choosing column types when
+// creating tables and that we don't get in the way of the underlying
+// database libraries when they make use of either Valuer or
+// "database/sql".Scanner.
+type PersonValuerScanner struct {
+ Person
+}
+
+// Value implements "database/sql/driver".Valuer. It will be automatically
+// run by the "database/sql" package when inserting/updating data.
+func (p PersonValuerScanner) Value() (driver.Value, error) {
+ return p.Id, nil
+}
+
+// Scan implements "database/sql".Scanner. It will be automatically run
+// by the "database/sql" package when reading column data into a field
+// of type PersonValuerScanner.
+func (p *PersonValuerScanner) Scan(value interface{}) (err error) {
+ switch src := value.(type) {
+ case []byte:
+ // TODO: this case is here for mysql only. For some reason,
+ // one (both?) of the mysql libraries opt to pass us a []byte
+ // instead of an int64 for the bigint column. We should add
+ // table tests around valuers/scanners and try to solve these
+ // types of odd discrepencies to make it easier for users of
+ // gorp to migrate to other database engines.
+ p.Id, err = strconv.ParseInt(string(src), 10, 64)
+ case int64:
+ // Most libraries pass in the type we'd expect.
+ p.Id = src
+ default:
+ typ := reflect.TypeOf(value)
+ return fmt.Errorf("Expected person value to be convertible to int64, got %v (type %s)", value, typ)
+ }
+ return
+}
+
+type FNameOnly struct {
+ FName string
+}
+
+type InvoicePersonView struct {
+ InvoiceId int64
+ PersonId int64
+ Memo string
+ FName string
+ LegacyVersion int64
+}
+
+type TableWithNull struct {
+ Id int64
+ Str sql.NullString
+ Int64 sql.NullInt64
+ Float64 sql.NullFloat64
+ Bool sql.NullBool
+ Bytes []byte
+}
+
+type WithIgnoredColumn struct {
+ internal int64 `db:"-"`
+ Id int64
+ Created int64
+}
+
+type IdCreated struct {
+ Id int64
+ Created int64
+}
+
+type IdCreatedExternal struct {
+ IdCreated
+ External int64
+}
+
+type WithStringPk struct {
+ Id string
+ Name string
+}
+
+type CustomStringType string
+
+type TypeConversionExample struct {
+ Id int64
+ PersonJSON Person
+ Name CustomStringType
+}
+
+type PersonUInt32 struct {
+ Id uint32
+ Name string
+}
+
+type PersonUInt64 struct {
+ Id uint64
+ Name string
+}
+
+type PersonUInt16 struct {
+ Id uint16
+ Name string
+}
+
+type WithEmbeddedStruct struct {
+ Id int64
+ Names
+}
+
+type WithEmbeddedStructConflictingEmbeddedMemberNames struct {
+ Id int64
+ Names
+ NamesConflict
+}
+
+type WithEmbeddedStructSameMemberName struct {
+ Id int64
+ SameName
+}
+
+type WithEmbeddedStructBeforeAutoincrField struct {
+ Names
+ Id int64
+}
+
+type WithEmbeddedAutoincr struct {
+ WithEmbeddedStruct
+ MiddleName string
+}
+
+type Names struct {
+ FirstName string
+ LastName string
+}
+
+type NamesConflict struct {
+ FirstName string
+ Surname string
+}
+
+type SameName struct {
+ SameName string
+}
+
+type UniqueColumns struct {
+ FirstName string
+ LastName string
+ City string
+ ZipCode int64
+}
+
+type SingleColumnTable struct {
+ SomeId string
+}
+
+type CustomDate struct {
+ time.Time
+}
+
+type WithCustomDate struct {
+ Id int64
+ Added CustomDate
+}
+
+type WithNullTime struct {
+ Id int64
+ Time gorp.NullTime
+}
+
+type testTypeConverter struct{}
+
+func (me testTypeConverter) ToDb(val interface{}) (interface{}, error) {
+
+ switch t := val.(type) {
+ case Person:
+ b, err := json.Marshal(t)
+ if err != nil {
+ return "", err
+ }
+ return string(b), nil
+ case CustomStringType:
+ return string(t), nil
+ case CustomDate:
+ return t.Time, nil
+ }
+
+ return val, nil
+}
+
+func (me testTypeConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) {
+ switch target.(type) {
+ case *Person:
+ binder := func(holder, target interface{}) error {
+ s, ok := holder.(*string)
+ if !ok {
+ return errors.New("FromDb: Unable to convert Person to *string")
+ }
+ b := []byte(*s)
+ return json.Unmarshal(b, target)
+ }
+ return gorp.CustomScanner{new(string), target, binder}, true
+ case *CustomStringType:
+ binder := func(holder, target interface{}) error {
+ s, ok := holder.(*string)
+ if !ok {
+ return errors.New("FromDb: Unable to convert CustomStringType to *string")
+ }
+ st, ok := target.(*CustomStringType)
+ if !ok {
+ return errors.New(fmt.Sprint("FromDb: Unable to convert target to *CustomStringType: ", reflect.TypeOf(target)))
+ }
+ *st = CustomStringType(*s)
+ return nil
+ }
+ return gorp.CustomScanner{new(string), target, binder}, true
+ case *CustomDate:
+ binder := func(holder, target interface{}) error {
+ t, ok := holder.(*time.Time)
+ if !ok {
+ return errors.New("FromDb: Unable to convert CustomDate to *time.Time")
+ }
+ dateTarget, ok := target.(*CustomDate)
+ if !ok {
+ return errors.New(fmt.Sprint("FromDb: Unable to convert target to *CustomDate: ", reflect.TypeOf(target)))
+ }
+ dateTarget.Time = *t
+ return nil
+ }
+ return gorp.CustomScanner{new(time.Time), target, binder}, true
+ }
+
+ return gorp.CustomScanner{}, false
+}
+
+func (p *Person) PreInsert(s gorp.SqlExecutor) error {
+ p.Created = time.Now().UnixNano()
+ p.Updated = p.Created
+ if p.FName == "badname" {
+ return fmt.Errorf("Invalid name: %s", p.FName)
+ }
+ return nil
+}
+
+func (p *Person) PostInsert(s gorp.SqlExecutor) error {
+ p.LName = "postinsert"
+ return nil
+}
+
+func (p *Person) PreUpdate(s gorp.SqlExecutor) error {
+ p.FName = "preupdate"
+ return nil
+}
+
+func (p *Person) PostUpdate(s gorp.SqlExecutor) error {
+ p.LName = "postupdate"
+ return nil
+}
+
+func (p *Person) PreDelete(s gorp.SqlExecutor) error {
+ p.FName = "predelete"
+ return nil
+}
+
+func (p *Person) PostDelete(s gorp.SqlExecutor) error {
+ p.LName = "postdelete"
+ return nil
+}
+
+func (p *Person) PostGet(s gorp.SqlExecutor) error {
+ p.LName = "postget"
+ return nil
+}
+
+type PersistentUser struct {
+ Key int32
+ Id string
+ PassedTraining bool
+}
+
+func TestCreateTablesIfNotExists(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ err := dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestTruncateTables(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+ err := dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ t.Error(err)
+ }
+
+ // Insert some data
+ p1 := &Person{0, 0, 0, "Bob", "Smith", 0}
+ dbmap.Insert(p1)
+ inv := &Invoice{0, 0, 1, "my invoice", 0, true}
+ dbmap.Insert(inv)
+
+ err = dbmap.TruncateTables()
+ if err != nil {
+ t.Error(err)
+ }
+
+ // Make sure all rows are deleted
+ rows, _ := dbmap.Select(Person{}, "SELECT * FROM person_test")
+ if len(rows) != 0 {
+ t.Errorf("Expected 0 person rows, got %d", len(rows))
+ }
+ rows, _ = dbmap.Select(Invoice{}, "SELECT * FROM invoice_test")
+ if len(rows) != 0 {
+ t.Errorf("Expected 0 invoice rows, got %d", len(rows))
+ }
+}
+
+func TestCustomDateType(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.TypeConverter = testTypeConverter{}
+ dbmap.AddTable(WithCustomDate{}).SetKeys(true, "Id")
+ err := dbmap.CreateTables()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+
+ test1 := &WithCustomDate{Added: CustomDate{Time: time.Now().Truncate(time.Second)}}
+ err = dbmap.Insert(test1)
+ if err != nil {
+ t.Errorf("Could not insert struct with custom date field: %s", err)
+ t.FailNow()
+ }
+ // Unfortunately, the mysql driver doesn't handle time.Time
+ // values properly during Get(). I can't find a way to work
+ // around that problem - every other type that I've tried is just
+ // silently converted. time.Time is the only type that causes
+ // the issue that this test checks for. As such, if the driver is
+ // mysql, we'll just skip the rest of this test.
+ if _, driver := dialectAndDriver(); driver == "mysql" {
+ t.Skip("TestCustomDateType can't run Get() with the mysql driver; skipping the rest of this test...")
+ }
+ result, err := dbmap.Get(new(WithCustomDate), test1.Id)
+ if err != nil {
+ t.Errorf("Could not get struct with custom date field: %s", err)
+ t.FailNow()
+ }
+ test2 := result.(*WithCustomDate)
+ if test2.Added.UTC() != test1.Added.UTC() {
+ t.Errorf("Custom dates do not match: %v != %v", test2.Added.UTC(), test1.Added.UTC())
+ }
+}
+
+func TestUIntPrimaryKey(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.AddTable(PersonUInt64{}).SetKeys(true, "Id")
+ dbmap.AddTable(PersonUInt32{}).SetKeys(true, "Id")
+ dbmap.AddTable(PersonUInt16{}).SetKeys(true, "Id")
+ err := dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+
+ p1 := &PersonUInt64{0, "name1"}
+ p2 := &PersonUInt32{0, "name2"}
+ p3 := &PersonUInt16{0, "name3"}
+ err = dbmap.Insert(p1, p2, p3)
+ if err != nil {
+ t.Error(err)
+ }
+ if p1.Id != 1 {
+ t.Errorf("%d != 1", p1.Id)
+ }
+ if p2.Id != 1 {
+ t.Errorf("%d != 1", p2.Id)
+ }
+ if p3.Id != 1 {
+ t.Errorf("%d != 1", p3.Id)
+ }
+}
+
+func TestSetUniqueTogether(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.AddTable(UniqueColumns{}).SetUniqueTogether("FirstName", "LastName").SetUniqueTogether("City", "ZipCode")
+ err := dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+
+ n1 := &UniqueColumns{"Steve", "Jobs", "Cupertino", 95014}
+ err = dbmap.Insert(n1)
+ if err != nil {
+ t.Error(err)
+ }
+
+ // Should fail because of the first constraint
+ n2 := &UniqueColumns{"Steve", "Jobs", "Sunnyvale", 94085}
+ err = dbmap.Insert(n2)
+ if err == nil {
+ t.Error(err)
+ }
+ // "unique" for Postgres/SQLite, "Duplicate entry" for MySQL
+ errLower := strings.ToLower(err.Error())
+ if !strings.Contains(errLower, "unique") && !strings.Contains(errLower, "duplicate entry") {
+ t.Error(err)
+ }
+
+ // Should also fail because of the second unique-together
+ n3 := &UniqueColumns{"Steve", "Wozniak", "Cupertino", 95014}
+ err = dbmap.Insert(n3)
+ if err == nil {
+ t.Error(err)
+ }
+ // "unique" for Postgres/SQLite, "Duplicate entry" for MySQL
+ errLower = strings.ToLower(err.Error())
+ if !strings.Contains(errLower, "unique") && !strings.Contains(errLower, "duplicate entry") {
+ t.Error(err)
+ }
+
+ // This one should finally succeed
+ n4 := &UniqueColumns{"Steve", "Wozniak", "Sunnyvale", 94085}
+ err = dbmap.Insert(n4)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestPersistentUser(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.Exec("drop table if exists PersistentUser")
+ table := dbmap.AddTable(PersistentUser{}).SetKeys(false, "Key")
+ table.ColMap("Key").Rename("mykey")
+ err := dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+ pu := &PersistentUser{43, "33r", false}
+ err = dbmap.Insert(pu)
+ if err != nil {
+ panic(err)
+ }
+
+ // prove we can pass a pointer into Get
+ pu2, err := dbmap.Get(pu, pu.Key)
+ if err != nil {
+ panic(err)
+ }
+ if !reflect.DeepEqual(pu, pu2) {
+ t.Errorf("%v!=%v", pu, pu2)
+ }
+
+ arr, err := dbmap.Select(pu, "select * from "+tableName(dbmap, PersistentUser{}))
+ if err != nil {
+ panic(err)
+ }
+ if !reflect.DeepEqual(pu, arr[0]) {
+ t.Errorf("%v!=%v", pu, arr[0])
+ }
+
+ // prove we can get the results back in a slice
+ var puArr []*PersistentUser
+ _, err = dbmap.Select(&puArr, "select * from "+tableName(dbmap, PersistentUser{}))
+ if err != nil {
+ panic(err)
+ }
+ if len(puArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(pu, puArr[0]) {
+ t.Errorf("%v!=%v", pu, puArr[0])
+ }
+
+ // prove we can get the results back in a non-pointer slice
+ var puValues []PersistentUser
+ _, err = dbmap.Select(&puValues, "select * from "+tableName(dbmap, PersistentUser{}))
+ if err != nil {
+ panic(err)
+ }
+ if len(puValues) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(*pu, puValues[0]) {
+ t.Errorf("%v!=%v", *pu, puValues[0])
+ }
+
+ // prove we can get the results back in a string slice
+ var idArr []*string
+ _, err = dbmap.Select(&idArr, "select "+columnName(dbmap, PersistentUser{}, "Id")+" from "+tableName(dbmap, PersistentUser{}))
+ if err != nil {
+ panic(err)
+ }
+ if len(idArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(pu.Id, *idArr[0]) {
+ t.Errorf("%v!=%v", pu.Id, *idArr[0])
+ }
+
+ // prove we can get the results back in an int slice
+ var keyArr []*int32
+ _, err = dbmap.Select(&keyArr, "select mykey from "+tableName(dbmap, PersistentUser{}))
+ if err != nil {
+ panic(err)
+ }
+ if len(keyArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(pu.Key, *keyArr[0]) {
+ t.Errorf("%v!=%v", pu.Key, *keyArr[0])
+ }
+
+ // prove we can get the results back in a bool slice
+ var passedArr []*bool
+ _, err = dbmap.Select(&passedArr, "select "+columnName(dbmap, PersistentUser{}, "PassedTraining")+" from "+tableName(dbmap, PersistentUser{}))
+ if err != nil {
+ panic(err)
+ }
+ if len(passedArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(pu.PassedTraining, *passedArr[0]) {
+ t.Errorf("%v!=%v", pu.PassedTraining, *passedArr[0])
+ }
+
+ // prove we can get the results back in a non-pointer slice
+ var stringArr []string
+ _, err = dbmap.Select(&stringArr, "select "+columnName(dbmap, PersistentUser{}, "Id")+" from "+tableName(dbmap, PersistentUser{}))
+ if err != nil {
+ panic(err)
+ }
+ if len(stringArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(pu.Id, stringArr[0]) {
+ t.Errorf("%v!=%v", pu.Id, stringArr[0])
+ }
+}
+
+func TestNamedQueryMap(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.Exec("drop table if exists PersistentUser")
+ table := dbmap.AddTable(PersistentUser{}).SetKeys(false, "Key")
+ table.ColMap("Key").Rename("mykey")
+ err := dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+ pu := &PersistentUser{43, "33r", false}
+ pu2 := &PersistentUser{500, "abc", false}
+ err = dbmap.Insert(pu, pu2)
+ if err != nil {
+ panic(err)
+ }
+
+ // Test simple case
+ var puArr []*PersistentUser
+ _, err = dbmap.Select(&puArr, "select * from "+tableName(dbmap, PersistentUser{})+" where mykey = :Key", map[string]interface{}{
+ "Key": 43,
+ })
+ if err != nil {
+ t.Errorf("Failed to select: %s", err)
+ t.FailNow()
+ }
+ if len(puArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(pu, puArr[0]) {
+ t.Errorf("%v!=%v", pu, puArr[0])
+ }
+
+ // Test more specific map value type is ok
+ puArr = nil
+ _, err = dbmap.Select(&puArr, "select * from "+tableName(dbmap, PersistentUser{})+" where mykey = :Key", map[string]int{
+ "Key": 43,
+ })
+ if err != nil {
+ t.Errorf("Failed to select: %s", err)
+ t.FailNow()
+ }
+ if len(puArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+
+ // Test multiple parameters set.
+ puArr = nil
+ _, err = dbmap.Select(&puArr, `
+select * from `+tableName(dbmap, PersistentUser{})+`
+ where mykey = :Key
+ and `+columnName(dbmap, PersistentUser{}, "PassedTraining")+` = :PassedTraining
+ and `+columnName(dbmap, PersistentUser{}, "Id")+` = :Id`, map[string]interface{}{
+ "Key": 43,
+ "PassedTraining": false,
+ "Id": "33r",
+ })
+ if err != nil {
+ t.Errorf("Failed to select: %s", err)
+ t.FailNow()
+ }
+ if len(puArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+
+ // Test colon within a non-key string
+ // Test having extra, unused properties in the map.
+ puArr = nil
+ _, err = dbmap.Select(&puArr, `
+select * from `+tableName(dbmap, PersistentUser{})+`
+ where mykey = :Key
+ and `+columnName(dbmap, PersistentUser{}, "Id")+` != 'abc:def'`, map[string]interface{}{
+ "Key": 43,
+ "PassedTraining": false,
+ })
+ if err != nil {
+ t.Errorf("Failed to select: %s", err)
+ t.FailNow()
+ }
+ if len(puArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+
+ // Test to delete with Exec and named params.
+ result, err := dbmap.Exec("delete from "+tableName(dbmap, PersistentUser{})+" where mykey = :Key", map[string]interface{}{
+ "Key": 43,
+ })
+ count, err := result.RowsAffected()
+ if err != nil {
+ t.Errorf("Failed to exec: %s", err)
+ t.FailNow()
+ }
+ if count != 1 {
+ t.Errorf("Expected 1 persistentuser to be deleted, but %d deleted", count)
+ }
+}
+
+func TestNamedQueryStruct(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.Exec("drop table if exists PersistentUser")
+ table := dbmap.AddTable(PersistentUser{}).SetKeys(false, "Key")
+ table.ColMap("Key").Rename("mykey")
+ err := dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+ pu := &PersistentUser{43, "33r", false}
+ pu2 := &PersistentUser{500, "abc", false}
+ err = dbmap.Insert(pu, pu2)
+ if err != nil {
+ panic(err)
+ }
+
+ // Test select self
+ var puArr []*PersistentUser
+ _, err = dbmap.Select(&puArr, `
+select * from `+tableName(dbmap, PersistentUser{})+`
+ where mykey = :Key
+ and `+columnName(dbmap, PersistentUser{}, "PassedTraining")+` = :PassedTraining
+ and `+columnName(dbmap, PersistentUser{}, "Id")+` = :Id`, pu)
+ if err != nil {
+ t.Errorf("Failed to select: %s", err)
+ t.FailNow()
+ }
+ if len(puArr) != 1 {
+ t.Errorf("Expected one persistentuser, found none")
+ }
+ if !reflect.DeepEqual(pu, puArr[0]) {
+ t.Errorf("%v!=%v", pu, puArr[0])
+ }
+
+ // Test delete self.
+ result, err := dbmap.Exec(`
+delete from `+tableName(dbmap, PersistentUser{})+`
+ where mykey = :Key
+ and `+columnName(dbmap, PersistentUser{}, "PassedTraining")+` = :PassedTraining
+ and `+columnName(dbmap, PersistentUser{}, "Id")+` = :Id`, pu)
+ count, err := result.RowsAffected()
+ if err != nil {
+ t.Errorf("Failed to exec: %s", err)
+ t.FailNow()
+ }
+ if count != 1 {
+ t.Errorf("Expected 1 persistentuser to be deleted, but %d deleted", count)
+ }
+}
+
+// Ensure that the slices containing SQL results are non-nil when the result set is empty.
+func TestReturnsNonNilSlice(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+ noResultsSQL := "select * from invoice_test where " + columnName(dbmap, Invoice{}, "Id") + "=99999"
+ var r1 []*Invoice
+ rawSelect(dbmap, &r1, noResultsSQL)
+ if r1 == nil {
+ t.Errorf("r1==nil")
+ }
+
+ r2 := rawSelect(dbmap, Invoice{}, noResultsSQL)
+ if r2 == nil {
+ t.Errorf("r2==nil")
+ }
+}
+
+func TestOverrideVersionCol(t *testing.T) {
+ dbmap := newDbMap()
+ t1 := dbmap.AddTable(InvoicePersonView{}).SetKeys(false, "InvoiceId", "PersonId")
+ err := dbmap.CreateTables()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+ c1 := t1.SetVersionCol("LegacyVersion")
+ if c1.ColumnName != "LegacyVersion" {
+ t.Errorf("Wrong col returned: %v", c1)
+ }
+
+ ipv := &InvoicePersonView{1, 2, "memo", "fname", 0}
+ _update(dbmap, ipv)
+ if ipv.LegacyVersion != 1 {
+ t.Errorf("LegacyVersion not updated: %d", ipv.LegacyVersion)
+ }
+}
+
+func TestOptimisticLocking(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ p1 := &Person{0, 0, 0, "Bob", "Smith", 0}
+ dbmap.Insert(p1) // Version is now 1
+ if p1.Version != 1 {
+ t.Errorf("Insert didn't incr Version: %d != %d", 1, p1.Version)
+ return
+ }
+ if p1.Id == 0 {
+ t.Errorf("Insert didn't return a generated PK")
+ return
+ }
+
+ obj, err := dbmap.Get(Person{}, p1.Id)
+ if err != nil {
+ panic(err)
+ }
+ p2 := obj.(*Person)
+ p2.LName = "Edwards"
+ dbmap.Update(p2) // Version is now 2
+ if p2.Version != 2 {
+ t.Errorf("Update didn't incr Version: %d != %d", 2, p2.Version)
+ }
+
+ p1.LName = "Howard"
+ count, err := dbmap.Update(p1)
+ if _, ok := err.(gorp.OptimisticLockError); !ok {
+ t.Errorf("update - Expected gorp.OptimisticLockError, got: %v", err)
+ }
+ if count != -1 {
+ t.Errorf("update - Expected -1 count, got: %d", count)
+ }
+
+ count, err = dbmap.Delete(p1)
+ if _, ok := err.(gorp.OptimisticLockError); !ok {
+ t.Errorf("delete - Expected gorp.OptimisticLockError, got: %v", err)
+ }
+ if count != -1 {
+ t.Errorf("delete - Expected -1 count, got: %d", count)
+ }
+}
+
+// what happens if a legacy table has a null value?
+func TestDoubleAddTable(t *testing.T) {
+ dbmap := newDbMap()
+ t1 := dbmap.AddTable(TableWithNull{}).SetKeys(false, "Id")
+ t2 := dbmap.AddTable(TableWithNull{})
+ if t1 != t2 {
+ t.Errorf("%v != %v", t1, t2)
+ }
+}
+
+// what happens if a legacy table has a null value?
+func TestNullValues(t *testing.T) {
+ dbmap := initDbMapNulls()
+ defer dropAndClose(dbmap)
+
+ // insert a row directly
+ rawExec(dbmap, "insert into "+tableName(dbmap, TableWithNull{})+" values (10, null, "+
+ "null, null, null, null)")
+
+ // try to load it
+ expected := &TableWithNull{Id: 10}
+ obj := _get(dbmap, TableWithNull{}, 10)
+ t1 := obj.(*TableWithNull)
+ if !reflect.DeepEqual(expected, t1) {
+ t.Errorf("%v != %v", expected, t1)
+ }
+
+ // update it
+ t1.Str = sql.NullString{"hi", true}
+ expected.Str = t1.Str
+ t1.Int64 = sql.NullInt64{999, true}
+ expected.Int64 = t1.Int64
+ t1.Float64 = sql.NullFloat64{53.33, true}
+ expected.Float64 = t1.Float64
+ t1.Bool = sql.NullBool{true, true}
+ expected.Bool = t1.Bool
+ t1.Bytes = []byte{1, 30, 31, 33}
+ expected.Bytes = t1.Bytes
+ _update(dbmap, t1)
+
+ obj = _get(dbmap, TableWithNull{}, 10)
+ t1 = obj.(*TableWithNull)
+ if t1.Str.String != "hi" {
+ t.Errorf("%s != hi", t1.Str.String)
+ }
+ if !reflect.DeepEqual(expected, t1) {
+ t.Errorf("%v != %v", expected, t1)
+ }
+}
+
+func TestScannerValuer(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.AddTableWithName(PersonValuerScanner{}, "person_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(InvoiceWithValuer{}, "invoice_test").SetKeys(true, "Id")
+ err := dbmap.CreateTables()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+
+ pv := PersonValuerScanner{}
+ pv.FName = "foo"
+ pv.LName = "bar"
+ err = dbmap.Insert(&pv)
+ if err != nil {
+ t.Errorf("Could not insert PersonValuerScanner using Person table: %v", err)
+ t.FailNow()
+ }
+
+ inv := InvoiceWithValuer{}
+ inv.Memo = "foo"
+ inv.Person = pv
+ err = dbmap.Insert(&inv)
+ if err != nil {
+ t.Errorf("Could not insert InvoiceWithValuer using Invoice table: %v", err)
+ t.FailNow()
+ }
+
+ res, err := dbmap.Get(InvoiceWithValuer{}, inv.Id)
+ if err != nil {
+ t.Errorf("Could not get InvoiceWithValuer: %v", err)
+ t.FailNow()
+ }
+ dbInv := res.(*InvoiceWithValuer)
+
+ if dbInv.Person.Id != pv.Id {
+ t.Errorf("InvoiceWithValuer got wrong person ID: %d (expected) != %d (actual)", pv.Id, dbInv.Person.Id)
+ }
+}
+
+func TestColumnProps(t *testing.T) {
+ dbmap := newDbMap()
+ t1 := dbmap.AddTable(Invoice{}).SetKeys(true, "Id")
+ t1.ColMap("Created").Rename("date_created")
+ t1.ColMap("Updated").SetTransient(true)
+ t1.ColMap("Memo").SetMaxSize(10)
+ t1.ColMap("PersonId").SetUnique(true)
+
+ err := dbmap.CreateTables()
+ if err != nil {
+ panic(err)
+ }
+ defer dropAndClose(dbmap)
+
+ // test transient
+ inv := &Invoice{0, 0, 1, "my invoice", 0, true}
+ _insert(dbmap, inv)
+ obj := _get(dbmap, Invoice{}, inv.Id)
+ inv = obj.(*Invoice)
+ if inv.Updated != 0 {
+ t.Errorf("Saved transient column 'Updated'")
+ }
+
+ // test max size
+ inv.Memo = "this memo is too long"
+ err = dbmap.Insert(inv)
+ if err == nil {
+ t.Errorf("max size exceeded, but Insert did not fail.")
+ }
+
+ // test unique - same person id
+ inv = &Invoice{0, 0, 1, "my invoice2", 0, false}
+ err = dbmap.Insert(inv)
+ if err == nil {
+ t.Errorf("same PersonId inserted, but Insert did not fail.")
+ }
+}
+
+func TestRawSelect(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ p1 := &Person{0, 0, 0, "bob", "smith", 0}
+ _insert(dbmap, p1)
+
+ inv1 := &Invoice{0, 0, 0, "xmas order", p1.Id, true}
+ _insert(dbmap, inv1)
+
+ expected := &InvoicePersonView{inv1.Id, p1.Id, inv1.Memo, p1.FName, 0}
+
+ query := "select i." + columnName(dbmap, Invoice{}, "Id") + " InvoiceId, p." + columnName(dbmap, Person{}, "Id") + " PersonId, i." + columnName(dbmap, Invoice{}, "Memo") + ", p." + columnName(dbmap, Person{}, "FName") + " " +
+ "from invoice_test i, person_test p " +
+ "where i." + columnName(dbmap, Invoice{}, "PersonId") + " = p." + columnName(dbmap, Person{}, "Id")
+ list := rawSelect(dbmap, InvoicePersonView{}, query)
+ if len(list) != 1 {
+ t.Errorf("len(list) != 1: %d", len(list))
+ } else if !reflect.DeepEqual(expected, list[0]) {
+ t.Errorf("%v != %v", expected, list[0])
+ }
+}
+
+func TestHooks(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ p1 := &Person{0, 0, 0, "bob", "smith", 0}
+ _insert(dbmap, p1)
+ if p1.Created == 0 || p1.Updated == 0 {
+ t.Errorf("p1.PreInsert() didn't run: %v", p1)
+ } else if p1.LName != "postinsert" {
+ t.Errorf("p1.PostInsert() didn't run: %v", p1)
+ }
+
+ obj := _get(dbmap, Person{}, p1.Id)
+ p1 = obj.(*Person)
+ if p1.LName != "postget" {
+ t.Errorf("p1.PostGet() didn't run: %v", p1)
+ }
+
+ _update(dbmap, p1)
+ if p1.FName != "preupdate" {
+ t.Errorf("p1.PreUpdate() didn't run: %v", p1)
+ } else if p1.LName != "postupdate" {
+ t.Errorf("p1.PostUpdate() didn't run: %v", p1)
+ }
+
+ var persons []*Person
+ bindVar := dbmap.Dialect.BindVar(0)
+ rawSelect(dbmap, &persons, "select * from person_test where "+columnName(dbmap, Person{}, "Id")+" = "+bindVar, p1.Id)
+ if persons[0].LName != "postget" {
+ t.Errorf("p1.PostGet() didn't run after select: %v", p1)
+ }
+
+ _del(dbmap, p1)
+ if p1.FName != "predelete" {
+ t.Errorf("p1.PreDelete() didn't run: %v", p1)
+ } else if p1.LName != "postdelete" {
+ t.Errorf("p1.PostDelete() didn't run: %v", p1)
+ }
+
+ // Test error case
+ p2 := &Person{0, 0, 0, "badname", "", 0}
+ err := dbmap.Insert(p2)
+ if err == nil {
+ t.Errorf("p2.PreInsert() didn't return an error")
+ }
+}
+
+func TestTransaction(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ inv1 := &Invoice{0, 100, 200, "t1", 0, true}
+ inv2 := &Invoice{0, 100, 200, "t2", 0, false}
+
+ trans, err := dbmap.Begin()
+ if err != nil {
+ panic(err)
+ }
+ trans.Insert(inv1, inv2)
+ err = trans.Commit()
+ if err != nil {
+ panic(err)
+ }
+
+ obj, err := dbmap.Get(Invoice{}, inv1.Id)
+ if err != nil {
+ panic(err)
+ }
+ if !reflect.DeepEqual(inv1, obj) {
+ t.Errorf("%v != %v", inv1, obj)
+ }
+ obj, err = dbmap.Get(Invoice{}, inv2.Id)
+ if err != nil {
+ panic(err)
+ }
+ if !reflect.DeepEqual(inv2, obj) {
+ t.Errorf("%v != %v", inv2, obj)
+ }
+}
+
+func TestSavepoint(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ inv1 := &Invoice{0, 100, 200, "unpaid", 0, false}
+
+ trans, err := dbmap.Begin()
+ if err != nil {
+ panic(err)
+ }
+ trans.Insert(inv1)
+
+ var checkMemo = func(want string) {
+ memo, err := trans.SelectStr("select " + columnName(dbmap, Invoice{}, "Memo") + " from invoice_test")
+ if err != nil {
+ panic(err)
+ }
+ if memo != want {
+ t.Errorf("%q != %q", want, memo)
+ }
+ }
+ checkMemo("unpaid")
+
+ err = trans.Savepoint("foo")
+ if err != nil {
+ panic(err)
+ }
+ checkMemo("unpaid")
+
+ inv1.Memo = "paid"
+ _, err = trans.Update(inv1)
+ if err != nil {
+ panic(err)
+ }
+ checkMemo("paid")
+
+ err = trans.RollbackToSavepoint("foo")
+ if err != nil {
+ panic(err)
+ }
+ checkMemo("unpaid")
+
+ err = trans.Rollback()
+ if err != nil {
+ panic(err)
+ }
+}
+
+func TestMultiple(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ inv1 := &Invoice{0, 100, 200, "a", 0, false}
+ inv2 := &Invoice{0, 100, 200, "b", 0, true}
+ _insert(dbmap, inv1, inv2)
+
+ inv1.Memo = "c"
+ inv2.Memo = "d"
+ _update(dbmap, inv1, inv2)
+
+ count := _del(dbmap, inv1, inv2)
+ if count != 2 {
+ t.Errorf("%d != 2", count)
+ }
+}
+
+func TestCrud(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ inv := &Invoice{0, 100, 200, "first order", 0, true}
+ testCrudInternal(t, dbmap, inv)
+
+ invtag := &InvoiceTag{0, 300, 400, "some order", 33, false}
+ testCrudInternal(t, dbmap, invtag)
+
+ foo := &AliasTransientField{BarStr: "some bar"}
+ testCrudInternal(t, dbmap, foo)
+}
+
+func testCrudInternal(t *testing.T, dbmap *gorp.DbMap, val testable) {
+ table, err := dbmap.TableFor(reflect.TypeOf(val).Elem(), false)
+ if err != nil {
+ t.Errorf("couldn't call TableFor: val=%v err=%v", val, err)
+ }
+
+ _, err = dbmap.Exec("delete from " + table.TableName)
+ if err != nil {
+ t.Errorf("couldn't delete rows from: val=%v err=%v", val, err)
+ }
+
+ // INSERT row
+ _insert(dbmap, val)
+ if val.GetId() == 0 {
+ t.Errorf("val.GetId() was not set on INSERT")
+ return
+ }
+
+ // SELECT row
+ val2 := _get(dbmap, val, val.GetId())
+ if !reflect.DeepEqual(val, val2) {
+ t.Errorf("%v != %v", val, val2)
+ }
+
+ // UPDATE row and SELECT
+ val.Rand()
+ count := _update(dbmap, val)
+ if count != 1 {
+ t.Errorf("update 1 != %d", count)
+ }
+ val2 = _get(dbmap, val, val.GetId())
+ if !reflect.DeepEqual(val, val2) {
+ t.Errorf("%v != %v", val, val2)
+ }
+
+ // Select *
+ rows, err := dbmap.Select(val, "select * from "+dbmap.Dialect.QuoteField(table.TableName))
+ if err != nil {
+ t.Errorf("couldn't select * from %s err=%v", dbmap.Dialect.QuoteField(table.TableName), err)
+ } else if len(rows) != 1 {
+ t.Errorf("unexpected row count in %s: %d", dbmap.Dialect.QuoteField(table.TableName), len(rows))
+ } else if !reflect.DeepEqual(val, rows[0]) {
+ t.Errorf("select * result: %v != %v", val, rows[0])
+ }
+
+ // DELETE row
+ deleted := _del(dbmap, val)
+ if deleted != 1 {
+ t.Errorf("Did not delete row with Id: %d", val.GetId())
+ return
+ }
+
+ // VERIFY deleted
+ val2 = _get(dbmap, val, val.GetId())
+ if val2 != nil {
+ t.Errorf("Found invoice with id: %d after Delete()", val.GetId())
+ }
+}
+
+func TestWithIgnoredColumn(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ ic := &WithIgnoredColumn{-1, 0, 1}
+ _insert(dbmap, ic)
+ expected := &WithIgnoredColumn{0, 1, 1}
+ ic2 := _get(dbmap, WithIgnoredColumn{}, ic.Id).(*WithIgnoredColumn)
+
+ if !reflect.DeepEqual(expected, ic2) {
+ t.Errorf("%v != %v", expected, ic2)
+ }
+ if _del(dbmap, ic) != 1 {
+ t.Errorf("Did not delete row with Id: %d", ic.Id)
+ return
+ }
+ if _get(dbmap, WithIgnoredColumn{}, ic.Id) != nil {
+ t.Errorf("Found id: %d after Delete()", ic.Id)
+ }
+}
+
+func TestColumnFilter(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ inv1 := &Invoice{0, 100, 200, "a", 0, false}
+ _insert(dbmap, inv1)
+
+ inv1.Memo = "c"
+ inv1.IsPaid = true
+ _updateColumns(dbmap, func(col *gorp.ColumnMap) bool {
+ return col.ColumnName == "Memo"
+ }, inv1)
+
+ inv2 := &Invoice{}
+ inv2 = _get(dbmap, inv2, inv1.Id).(*Invoice)
+ if inv2.Memo != "c" {
+ t.Errorf("Expected column to be updated (%#v)", inv2)
+ }
+ if inv2.IsPaid {
+ t.Error("IsPaid shouldn't have been updated")
+ }
+}
+
+func TestTypeConversionExample(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ p := Person{FName: "Bob", LName: "Smith"}
+ tc := &TypeConversionExample{-1, p, CustomStringType("hi")}
+ _insert(dbmap, tc)
+
+ expected := &TypeConversionExample{1, p, CustomStringType("hi")}
+ tc2 := _get(dbmap, TypeConversionExample{}, tc.Id).(*TypeConversionExample)
+ if !reflect.DeepEqual(expected, tc2) {
+ t.Errorf("tc2 %v != %v", expected, tc2)
+ }
+
+ tc2.Name = CustomStringType("hi2")
+ tc2.PersonJSON = Person{FName: "Jane", LName: "Doe"}
+ _update(dbmap, tc2)
+
+ expected = &TypeConversionExample{1, tc2.PersonJSON, CustomStringType("hi2")}
+ tc3 := _get(dbmap, TypeConversionExample{}, tc.Id).(*TypeConversionExample)
+ if !reflect.DeepEqual(expected, tc3) {
+ t.Errorf("tc3 %v != %v", expected, tc3)
+ }
+
+ if _del(dbmap, tc) != 1 {
+ t.Errorf("Did not delete row with Id: %d", tc.Id)
+ }
+
+}
+
+func TestWithEmbeddedStruct(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ es := &WithEmbeddedStruct{-1, Names{FirstName: "Alice", LastName: "Smith"}}
+ _insert(dbmap, es)
+ expected := &WithEmbeddedStruct{1, Names{FirstName: "Alice", LastName: "Smith"}}
+ es2 := _get(dbmap, WithEmbeddedStruct{}, es.Id).(*WithEmbeddedStruct)
+ if !reflect.DeepEqual(expected, es2) {
+ t.Errorf("%v != %v", expected, es2)
+ }
+
+ es2.FirstName = "Bob"
+ expected.FirstName = "Bob"
+ _update(dbmap, es2)
+ es2 = _get(dbmap, WithEmbeddedStruct{}, es.Id).(*WithEmbeddedStruct)
+ if !reflect.DeepEqual(expected, es2) {
+ t.Errorf("%v != %v", expected, es2)
+ }
+
+ ess := rawSelect(dbmap, WithEmbeddedStruct{}, "select * from embedded_struct_test")
+ if !reflect.DeepEqual(es2, ess[0]) {
+ t.Errorf("%v != %v", es2, ess[0])
+ }
+}
+
+/*
+func TestWithEmbeddedStructConflictingEmbeddedMemberNames(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ es := &WithEmbeddedStructConflictingEmbeddedMemberNames{-1, Names{FirstName: "Alice", LastName: "Smith"}, NamesConflict{FirstName: "Andrew", Surname: "Wiggin"}}
+ _insert(dbmap, es)
+ expected := &WithEmbeddedStructConflictingEmbeddedMemberNames{-1, Names{FirstName: "Alice", LastName: "Smith"}, NamesConflict{FirstName: "Andrew", Surname: "Wiggin"}}
+ es2 := _get(dbmap, WithEmbeddedStructConflictingEmbeddedMemberNames{}, es.Id).(*WithEmbeddedStructConflictingEmbeddedMemberNames)
+ if !reflect.DeepEqual(expected, es2) {
+ t.Errorf("%v != %v", expected, es2)
+ }
+
+ es2.Names.FirstName = "Bob"
+ expected.Names.FirstName = "Bob"
+ _update(dbmap, es2)
+ es2 = _get(dbmap, WithEmbeddedStructConflictingEmbeddedMemberNames{}, es.Id).(*WithEmbeddedStructConflictingEmbeddedMemberNames)
+ if !reflect.DeepEqual(expected, es2) {
+ t.Errorf("%v != %v", expected, es2)
+ }
+
+ ess := rawSelect(dbmap, WithEmbeddedStructConflictingEmbeddedMemberNames{}, "select * from embedded_struct_conflict_name_test")
+ if !reflect.DeepEqual(es2, ess[0]) {
+ t.Errorf("%v != %v", es2, ess[0])
+ }
+}
+
+func TestWithEmbeddedStructSameMemberName(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ es := &WithEmbeddedStructSameMemberName{-1, SameName{SameName: "Alice"}}
+ _insert(dbmap, es)
+ expected := &WithEmbeddedStructSameMemberName{-1, SameName{SameName: "Alice"}}
+ es2 := _get(dbmap, WithEmbeddedStructSameMemberName{}, es.Id).(*WithEmbeddedStructSameMemberName)
+ if !reflect.DeepEqual(expected, es2) {
+ t.Errorf("%v != %v", expected, es2)
+ }
+
+ es2.SameName = SameName{"Bob"}
+ expected.SameName = SameName{"Bob"}
+ _update(dbmap, es2)
+ es2 = _get(dbmap, WithEmbeddedStructSameMemberName{}, es.Id).(*WithEmbeddedStructSameMemberName)
+ if !reflect.DeepEqual(expected, es2) {
+ t.Errorf("%v != %v", expected, es2)
+ }
+
+ ess := rawSelect(dbmap, WithEmbeddedStructSameMemberName{}, "select * from embedded_struct_same_member_name_test")
+ if !reflect.DeepEqual(es2, ess[0]) {
+ t.Errorf("%v != %v", es2, ess[0])
+ }
+}
+//*/
+
+func TestWithEmbeddedStructBeforeAutoincr(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ esba := &WithEmbeddedStructBeforeAutoincrField{Names: Names{FirstName: "Alice", LastName: "Smith"}}
+ _insert(dbmap, esba)
+ var expectedAutoincrId int64 = 1
+ if esba.Id != expectedAutoincrId {
+ t.Errorf("%d != %d", expectedAutoincrId, esba.Id)
+ }
+}
+
+func TestWithEmbeddedAutoincr(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ esa := &WithEmbeddedAutoincr{
+ WithEmbeddedStruct: WithEmbeddedStruct{Names: Names{FirstName: "Alice", LastName: "Smith"}},
+ MiddleName: "Rose",
+ }
+ _insert(dbmap, esa)
+ var expectedAutoincrId int64 = 1
+ if esa.Id != expectedAutoincrId {
+ t.Errorf("%d != %d", expectedAutoincrId, esa.Id)
+ }
+}
+
+func TestSelectVal(t *testing.T) {
+ dbmap := initDbMapNulls()
+ defer dropAndClose(dbmap)
+
+ bindVar := dbmap.Dialect.BindVar(0)
+
+ t1 := TableWithNull{Str: sql.NullString{"abc", true},
+ Int64: sql.NullInt64{78, true},
+ Float64: sql.NullFloat64{32.2, true},
+ Bool: sql.NullBool{true, true},
+ Bytes: []byte("hi")}
+ _insert(dbmap, &t1)
+
+ // SelectInt
+ i64 := selectInt(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Int64")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='abc'")
+ if i64 != 78 {
+ t.Errorf("int64 %d != 78", i64)
+ }
+ i64 = selectInt(dbmap, "select count(*) from "+tableName(dbmap, TableWithNull{}))
+ if i64 != 1 {
+ t.Errorf("int64 count %d != 1", i64)
+ }
+ i64 = selectInt(dbmap, "select count(*) from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"="+bindVar, "asdfasdf")
+ if i64 != 0 {
+ t.Errorf("int64 no rows %d != 0", i64)
+ }
+
+ // SelectNullInt
+ n := selectNullInt(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Int64")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='notfound'")
+ if !reflect.DeepEqual(n, sql.NullInt64{0, false}) {
+ t.Errorf("nullint %v != 0,false", n)
+ }
+
+ n = selectNullInt(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Int64")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='abc'")
+ if !reflect.DeepEqual(n, sql.NullInt64{78, true}) {
+ t.Errorf("nullint %v != 78, true", n)
+ }
+
+ // SelectFloat
+ f64 := selectFloat(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Float64")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='abc'")
+ if f64 != 32.2 {
+ t.Errorf("float64 %d != 32.2", f64)
+ }
+ f64 = selectFloat(dbmap, "select min("+columnName(dbmap, TableWithNull{}, "Float64")+") from "+tableName(dbmap, TableWithNull{}))
+ if f64 != 32.2 {
+ t.Errorf("float64 min %d != 32.2", f64)
+ }
+ f64 = selectFloat(dbmap, "select count(*) from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"="+bindVar, "asdfasdf")
+ if f64 != 0 {
+ t.Errorf("float64 no rows %d != 0", f64)
+ }
+
+ // SelectNullFloat
+ nf := selectNullFloat(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Float64")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='notfound'")
+ if !reflect.DeepEqual(nf, sql.NullFloat64{0, false}) {
+ t.Errorf("nullfloat %v != 0,false", nf)
+ }
+
+ nf = selectNullFloat(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Float64")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='abc'")
+ if !reflect.DeepEqual(nf, sql.NullFloat64{32.2, true}) {
+ t.Errorf("nullfloat %v != 32.2, true", nf)
+ }
+
+ // SelectStr
+ s := selectStr(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Str")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Int64")+"="+bindVar, 78)
+ if s != "abc" {
+ t.Errorf("s %s != abc", s)
+ }
+ s = selectStr(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Str")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='asdfasdf'")
+ if s != "" {
+ t.Errorf("s no rows %s != ''", s)
+ }
+
+ // SelectNullStr
+ ns := selectNullStr(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Str")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Int64")+"="+bindVar, 78)
+ if !reflect.DeepEqual(ns, sql.NullString{"abc", true}) {
+ t.Errorf("nullstr %v != abc,true", ns)
+ }
+ ns = selectNullStr(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Str")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"='asdfasdf'")
+ if !reflect.DeepEqual(ns, sql.NullString{"", false}) {
+ t.Errorf("nullstr no rows %v != '',false", ns)
+ }
+
+ // SelectInt/Str with named parameters
+ i64 = selectInt(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Int64")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Str")+"=:abc", map[string]string{"abc": "abc"})
+ if i64 != 78 {
+ t.Errorf("int64 %d != 78", i64)
+ }
+ ns = selectNullStr(dbmap, "select "+columnName(dbmap, TableWithNull{}, "Str")+" from "+tableName(dbmap, TableWithNull{})+" where "+columnName(dbmap, TableWithNull{}, "Int64")+"=:num", map[string]int{"num": 78})
+ if !reflect.DeepEqual(ns, sql.NullString{"abc", true}) {
+ t.Errorf("nullstr %v != abc,true", ns)
+ }
+}
+
+func TestVersionMultipleRows(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ persons := []*Person{
+ &Person{0, 0, 0, "Bob", "Smith", 0},
+ &Person{0, 0, 0, "Jane", "Smith", 0},
+ &Person{0, 0, 0, "Mike", "Smith", 0},
+ }
+
+ _insert(dbmap, persons[0], persons[1], persons[2])
+
+ for x, p := range persons {
+ if p.Version != 1 {
+ t.Errorf("person[%d].Version != 1: %d", x, p.Version)
+ }
+ }
+}
+
+func TestWithStringPk(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.AddTableWithName(WithStringPk{}, "string_pk_test").SetKeys(true, "Id")
+ _, err := dbmap.Exec("create table string_pk_test (Id varchar(255), Name varchar(255));")
+ if err != nil {
+ t.Errorf("couldn't create string_pk_test: %v", err)
+ }
+ defer dropAndClose(dbmap)
+
+ row := &WithStringPk{"1", "foo"}
+ err = dbmap.Insert(row)
+ if err == nil {
+ t.Errorf("Expected error when inserting into table w/non Int PK and autoincr set true")
+ }
+}
+
+// TestSqlExecutorInterfaceSelects ensures that all gorp.DbMap methods starting with Select...
+// are also exposed in the gorp.SqlExecutor interface. Select... functions can always
+// run on Pre/Post hooks.
+func TestSqlExecutorInterfaceSelects(t *testing.T) {
+ dbMapType := reflect.TypeOf(&gorp.DbMap{})
+ sqlExecutorType := reflect.TypeOf((*gorp.SqlExecutor)(nil)).Elem()
+ numDbMapMethods := dbMapType.NumMethod()
+ for i := 0; i < numDbMapMethods; i += 1 {
+ dbMapMethod := dbMapType.Method(i)
+ if !strings.HasPrefix(dbMapMethod.Name, "Select") {
+ continue
+ }
+ if _, found := sqlExecutorType.MethodByName(dbMapMethod.Name); !found {
+ t.Errorf("Method %s is defined on gorp.DbMap but not implemented in gorp.SqlExecutor",
+ dbMapMethod.Name)
+ }
+ }
+}
+
+func TestNullTime(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ // if time is null
+ ent := &WithNullTime{
+ Id: 0,
+ Time: gorp.NullTime{
+ Valid: false,
+ }}
+ err := dbmap.Insert(ent)
+ if err != nil {
+ t.Error("failed insert on %s", err.Error())
+ }
+ err = dbmap.SelectOne(ent, `select * from nulltime_test where `+columnName(dbmap, WithNullTime{}, "Id")+`=:Id`, map[string]interface{}{
+ "Id": ent.Id,
+ })
+ if err != nil {
+ t.Error("failed select on %s", err.Error())
+ }
+ if ent.Time.Valid {
+ t.Error("gorp.NullTime returns valid but expected null.")
+ }
+
+ // if time is not null
+ ts, err := time.Parse(time.Stamp, "Jan 2 15:04:05")
+ ent = &WithNullTime{
+ Id: 1,
+ Time: gorp.NullTime{
+ Valid: true,
+ Time: ts,
+ }}
+ err = dbmap.Insert(ent)
+ if err != nil {
+ t.Error("failed insert on %s", err.Error())
+ }
+ err = dbmap.SelectOne(ent, `select * from nulltime_test where `+columnName(dbmap, WithNullTime{}, "Id")+`=:Id`, map[string]interface{}{
+ "Id": ent.Id,
+ })
+ if err != nil {
+ t.Error("failed select on %s", err.Error())
+ }
+ if !ent.Time.Valid {
+ t.Error("gorp.NullTime returns invalid but expected valid.")
+ }
+ if ent.Time.Time.UTC() != ts.UTC() {
+ t.Errorf("expect %v but got %v.", ts, ent.Time.Time)
+ }
+
+ return
+}
+
+type WithTime struct {
+ Id int64
+ Time time.Time
+}
+
+type Times struct {
+ One time.Time
+ Two time.Time
+}
+
+type EmbeddedTime struct {
+ Id string
+ Times
+}
+
+func parseTimeOrPanic(format, date string) time.Time {
+ t1, err := time.Parse(format, date)
+ if err != nil {
+ panic(err)
+ }
+ return t1
+}
+
+// TODO: re-enable next two tests when this is merged:
+// https://github.com/ziutek/mymysql/pull/77
+//
+// This test currently fails w/MySQL b/c tz info is lost
+func testWithTime(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ t1 := parseTimeOrPanic("2006-01-02 15:04:05 -0700 MST",
+ "2013-08-09 21:30:43 +0800 CST")
+ w1 := WithTime{1, t1}
+ _insert(dbmap, &w1)
+
+ obj := _get(dbmap, WithTime{}, w1.Id)
+ w2 := obj.(*WithTime)
+ if w1.Time.UnixNano() != w2.Time.UnixNano() {
+ t.Errorf("%v != %v", w1, w2)
+ }
+}
+
+// See: https://github.com/go-gorp/gorp/issues/86
+func testEmbeddedTime(t *testing.T) {
+ dbmap := newDbMap()
+ dbmap.AddTable(EmbeddedTime{}).SetKeys(false, "Id")
+ defer dropAndClose(dbmap)
+ err := dbmap.CreateTables()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ time1 := parseTimeOrPanic("2006-01-02 15:04:05", "2013-08-09 21:30:43")
+
+ t1 := &EmbeddedTime{Id: "abc", Times: Times{One: time1, Two: time1.Add(10 * time.Second)}}
+ _insert(dbmap, t1)
+
+ x := _get(dbmap, EmbeddedTime{}, t1.Id)
+ t2, _ := x.(*EmbeddedTime)
+ if t1.One.UnixNano() != t2.One.UnixNano() || t1.Two.UnixNano() != t2.Two.UnixNano() {
+ t.Errorf("%v != %v", t1, t2)
+ }
+}
+
+func TestWithTimeSelect(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ halfhourago := time.Now().UTC().Add(-30 * time.Minute)
+
+ w1 := WithTime{1, halfhourago.Add(time.Minute * -1)}
+ w2 := WithTime{2, halfhourago.Add(time.Second)}
+ _insert(dbmap, &w1, &w2)
+
+ var caseIds []int64
+ _, err := dbmap.Select(&caseIds, "SELECT "+columnName(dbmap, WithTime{}, "Id")+" FROM time_test WHERE "+columnName(dbmap, WithTime{}, "Time")+" < "+dbmap.Dialect.BindVar(0), halfhourago)
+
+ if err != nil {
+ t.Error(err)
+ }
+ if len(caseIds) != 1 {
+ t.Errorf("%d != 1", len(caseIds))
+ }
+ if caseIds[0] != w1.Id {
+ t.Errorf("%d != %d", caseIds[0], w1.Id)
+ }
+}
+
+func TestInvoicePersonView(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ // Create some rows
+ p1 := &Person{0, 0, 0, "bob", "smith", 0}
+ dbmap.Insert(p1)
+
+ // notice how we can wire up p1.Id to the invoice easily
+ inv1 := &Invoice{0, 0, 0, "xmas order", p1.Id, false}
+ dbmap.Insert(inv1)
+
+ // Run your query
+ query := "select i." + columnName(dbmap, Invoice{}, "Id") + " InvoiceId, p." + columnName(dbmap, Person{}, "Id") + " PersonId, i." + columnName(dbmap, Invoice{}, "Memo") + ", p." + columnName(dbmap, Person{}, "FName") + " " +
+ "from invoice_test i, person_test p " +
+ "where i." + columnName(dbmap, Invoice{}, "PersonId") + " = p." + columnName(dbmap, Person{}, "Id")
+
+ // pass a slice of pointers to Select()
+ // this avoids the need to type assert after the query is run
+ var list []*InvoicePersonView
+ _, err := dbmap.Select(&list, query)
+ if err != nil {
+ panic(err)
+ }
+
+ // this should test true
+ expected := &InvoicePersonView{inv1.Id, p1.Id, inv1.Memo, p1.FName, 0}
+ if !reflect.DeepEqual(list[0], expected) {
+ t.Errorf("%v != %v", list[0], expected)
+ }
+}
+
+func TestQuoteTableNames(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ quotedTableName := dbmap.Dialect.QuoteField("person_test")
+
+ // Use a buffer to hold the log to check generated queries
+ logBuffer := &bytes.Buffer{}
+ dbmap.TraceOn("", log.New(logBuffer, "gorptest:", log.Lmicroseconds))
+
+ // Create some rows
+ p1 := &Person{0, 0, 0, "bob", "smith", 0}
+ errorTemplate := "Expected quoted table name %v in query but didn't find it"
+
+ // Check if Insert quotes the table name
+ id := dbmap.Insert(p1)
+ if !bytes.Contains(logBuffer.Bytes(), []byte(quotedTableName)) {
+ t.Errorf(errorTemplate, quotedTableName)
+ }
+ logBuffer.Reset()
+
+ // Check if Get quotes the table name
+ dbmap.Get(Person{}, id)
+ if !bytes.Contains(logBuffer.Bytes(), []byte(quotedTableName)) {
+ t.Errorf(errorTemplate, quotedTableName)
+ }
+ logBuffer.Reset()
+}
+
+func TestSelectTooManyCols(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ p1 := &Person{0, 0, 0, "bob", "smith", 0}
+ p2 := &Person{0, 0, 0, "jane", "doe", 0}
+ _insert(dbmap, p1)
+ _insert(dbmap, p2)
+
+ obj := _get(dbmap, Person{}, p1.Id)
+ p1 = obj.(*Person)
+ obj = _get(dbmap, Person{}, p2.Id)
+ p2 = obj.(*Person)
+
+ params := map[string]interface{}{
+ "Id": p1.Id,
+ }
+
+ var p3 FNameOnly
+ err := dbmap.SelectOne(&p3, "select * from person_test where "+columnName(dbmap, Person{}, "Id")+"=:Id", params)
+ if err != nil {
+ if !gorp.NonFatalError(err) {
+ t.Error(err)
+ }
+ } else {
+ t.Errorf("Non-fatal error expected")
+ }
+
+ if p1.FName != p3.FName {
+ t.Errorf("%v != %v", p1.FName, p3.FName)
+ }
+
+ var pSlice []FNameOnly
+ _, err = dbmap.Select(&pSlice, "select * from person_test order by "+columnName(dbmap, Person{}, "FName")+" asc")
+ if err != nil {
+ if !gorp.NonFatalError(err) {
+ t.Error(err)
+ }
+ } else {
+ t.Errorf("Non-fatal error expected")
+ }
+
+ if p1.FName != pSlice[0].FName {
+ t.Errorf("%v != %v", p1.FName, pSlice[0].FName)
+ }
+ if p2.FName != pSlice[1].FName {
+ t.Errorf("%v != %v", p2.FName, pSlice[1].FName)
+ }
+}
+
+func TestSelectSingleVal(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ p1 := &Person{0, 0, 0, "bob", "smith", 0}
+ _insert(dbmap, p1)
+
+ obj := _get(dbmap, Person{}, p1.Id)
+ p1 = obj.(*Person)
+
+ params := map[string]interface{}{
+ "Id": p1.Id,
+ }
+
+ var p2 Person
+ err := dbmap.SelectOne(&p2, "select * from person_test where "+columnName(dbmap, Person{}, "Id")+"=:Id", params)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if !reflect.DeepEqual(p1, &p2) {
+ t.Errorf("%v != %v", p1, &p2)
+ }
+
+ // verify SelectOne allows non-struct holders
+ var s string
+ err = dbmap.SelectOne(&s, "select "+columnName(dbmap, Person{}, "FName")+" from person_test where "+columnName(dbmap, Person{}, "Id")+"=:Id", params)
+ if err != nil {
+ t.Error(err)
+ }
+ if s != "bob" {
+ t.Error("Expected bob but got: " + s)
+ }
+
+ // verify SelectOne requires pointer receiver
+ err = dbmap.SelectOne(s, "select "+columnName(dbmap, Person{}, "FName")+" from person_test where "+columnName(dbmap, Person{}, "Id")+"=:Id", params)
+ if err == nil {
+ t.Error("SelectOne should have returned error for non-pointer holder")
+ }
+
+ // verify SelectOne works with uninitialized pointers
+ var p3 *Person
+ err = dbmap.SelectOne(&p3, "select * from person_test where "+columnName(dbmap, Person{}, "Id")+"=:Id", params)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if !reflect.DeepEqual(p1, p3) {
+ t.Errorf("%v != %v", p1, p3)
+ }
+
+ // verify that the receiver is still nil if nothing was found
+ var p4 *Person
+ dbmap.SelectOne(&p3, "select * from person_test where 2<1 AND "+columnName(dbmap, Person{}, "Id")+"=:Id", params)
+ if p4 != nil {
+ t.Error("SelectOne should not have changed a nil receiver when no rows were found")
+ }
+
+ // verify that the error is set to sql.ErrNoRows if not found
+ err = dbmap.SelectOne(&p2, "select * from person_test where "+columnName(dbmap, Person{}, "Id")+"=:Id", map[string]interface{}{
+ "Id": -2222,
+ })
+ if err == nil || err != sql.ErrNoRows {
+ t.Error("SelectOne should have returned an sql.ErrNoRows")
+ }
+
+ _insert(dbmap, &Person{0, 0, 0, "bob", "smith", 0})
+ err = dbmap.SelectOne(&p2, "select * from person_test where "+columnName(dbmap, Person{}, "FName")+"='bob'")
+ if err == nil {
+ t.Error("Expected error when two rows found")
+ }
+
+ // tests for #150
+ var tInt int64
+ var tStr string
+ var tBool bool
+ var tFloat float64
+ primVals := []interface{}{tInt, tStr, tBool, tFloat}
+ for _, prim := range primVals {
+ err = dbmap.SelectOne(&prim, "select * from person_test where "+columnName(dbmap, Person{}, "Id")+"=-123")
+ if err == nil || err != sql.ErrNoRows {
+ t.Error("primVals: SelectOne should have returned sql.ErrNoRows")
+ }
+ }
+}
+
+func TestSelectAlias(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ p1 := &IdCreatedExternal{IdCreated: IdCreated{Id: 1, Created: 3}, External: 2}
+
+ // Insert using embedded IdCreated, which reflects the structure of the table
+ _insert(dbmap, &p1.IdCreated)
+
+ // Select into IdCreatedExternal type, which includes some fields not present
+ // in id_created_test
+ var p2 IdCreatedExternal
+ err := dbmap.SelectOne(&p2, "select * from id_created_test where "+columnName(dbmap, IdCreatedExternal{}, "Id")+"=1")
+ if err != nil {
+ t.Error(err)
+ }
+ if p2.Id != 1 || p2.Created != 3 || p2.External != 0 {
+ t.Error("Expected ignored field defaults to not set")
+ }
+
+ // Prove that we can supply an aliased value in the select, and that it will
+ // automatically map to IdCreatedExternal.External
+ err = dbmap.SelectOne(&p2, "SELECT *, 1 AS external FROM id_created_test")
+ if err != nil {
+ t.Error(err)
+ }
+ if p2.External != 1 {
+ t.Error("Expected select as can map to exported field.")
+ }
+
+ var rows *sql.Rows
+ var cols []string
+ rows, err = dbmap.Db.Query("SELECT * FROM id_created_test")
+ cols, err = rows.Columns()
+ if err != nil || len(cols) != 2 {
+ t.Error("Expected ignored column not created")
+ }
+}
+
+func TestMysqlPanicIfDialectNotInitialized(t *testing.T) {
+ _, driver := dialectAndDriver()
+ // this test only applies to MySQL
+ if os.Getenv("GORP_TEST_DIALECT") != "mysql" {
+ return
+ }
+
+ // The expected behaviour is to catch a panic.
+ // Here is the deferred function which will check if a panic has indeed occurred :
+ defer func() {
+ r := recover()
+ if r == nil {
+ t.Error("db.CreateTables() should panic if db is initialized with an incorrect gorp.MySQLDialect")
+ }
+ }()
+
+ // invalid MySQLDialect : does not contain Engine or Encoding specification
+ dialect := gorp.MySQLDialect{}
+ db := &gorp.DbMap{Db: connect(driver), Dialect: dialect}
+ db.AddTableWithName(Invoice{}, "invoice")
+ // the following call should panic :
+ db.CreateTables()
+}
+
+func TestSingleColumnKeyDbReturnsZeroRowsUpdatedOnPKChange(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+ dbmap.AddTableWithName(SingleColumnTable{}, "single_column_table").SetKeys(false, "SomeId")
+ err := dbmap.DropTablesIfExists()
+ if err != nil {
+ t.Error("Drop tables failed")
+ }
+ err = dbmap.CreateTablesIfNotExists()
+ if err != nil {
+ t.Error("Create tables failed")
+ }
+ err = dbmap.TruncateTables()
+ if err != nil {
+ t.Error("Truncate tables failed")
+ }
+
+ sct := SingleColumnTable{
+ SomeId: "A Unique Id String",
+ }
+
+ count, err := dbmap.Update(&sct)
+ if err != nil {
+ t.Error(err)
+ }
+ if count != 0 {
+ t.Errorf("Expected 0 updated rows, got %d", count)
+ }
+
+}
+
+func TestPrepare(t *testing.T) {
+ dbmap := initDbMap()
+ defer dropAndClose(dbmap)
+
+ inv1 := &Invoice{0, 100, 200, "prepare-foo", 0, false}
+ inv2 := &Invoice{0, 100, 200, "prepare-bar", 0, false}
+ _insert(dbmap, inv1, inv2)
+
+ bindVar0 := dbmap.Dialect.BindVar(0)
+ bindVar1 := dbmap.Dialect.BindVar(1)
+ stmt, err := dbmap.Prepare(fmt.Sprintf("UPDATE invoice_test SET "+columnName(dbmap, Invoice{}, "Memo")+"=%s WHERE "+columnName(dbmap, Invoice{}, "Id")+"=%s", bindVar0, bindVar1))
+ if err != nil {
+ t.Error(err)
+ }
+ defer stmt.Close()
+ _, err = stmt.Exec("prepare-baz", inv1.Id)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dbmap.SelectOne(inv1, "SELECT * from invoice_test WHERE "+columnName(dbmap, Invoice{}, "Memo")+"='prepare-baz'")
+ if err != nil {
+ t.Error(err)
+ }
+
+ trans, err := dbmap.Begin()
+ if err != nil {
+ t.Error(err)
+ }
+ transStmt, err := trans.Prepare(fmt.Sprintf("UPDATE invoice_test SET "+columnName(dbmap, Invoice{}, "IsPaid")+"=%s WHERE "+columnName(dbmap, Invoice{}, "Id")+"=%s", bindVar0, bindVar1))
+ if err != nil {
+ t.Error(err)
+ }
+ defer transStmt.Close()
+ _, err = transStmt.Exec(true, inv2.Id)
+ if err != nil {
+ t.Error(err)
+ }
+ err = dbmap.SelectOne(inv2, fmt.Sprintf("SELECT * from invoice_test WHERE "+columnName(dbmap, Invoice{}, "IsPaid")+"=%s", bindVar0), true)
+ if err == nil || err != sql.ErrNoRows {
+ t.Error("SelectOne should have returned an sql.ErrNoRows")
+ }
+ err = trans.SelectOne(inv2, fmt.Sprintf("SELECT * from invoice_test WHERE "+columnName(dbmap, Invoice{}, "IsPaid")+"=%s", bindVar0), true)
+ if err != nil {
+ t.Error(err)
+ }
+ err = trans.Commit()
+ if err != nil {
+ t.Error(err)
+ }
+ err = dbmap.SelectOne(inv2, fmt.Sprintf("SELECT * from invoice_test WHERE "+columnName(dbmap, Invoice{}, "IsPaid")+"=%s", bindVar0), true)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func BenchmarkNativeCrud(b *testing.B) {
+ b.StopTimer()
+ dbmap := initDbMapBench()
+ defer dropAndClose(dbmap)
+ columnId := columnName(dbmap, Invoice{}, "Id")
+ columnCreated := columnName(dbmap, Invoice{}, "Created")
+ columnUpdated := columnName(dbmap, Invoice{}, "Updated")
+ columnMemo := columnName(dbmap, Invoice{}, "Memo")
+ columnPersonId := columnName(dbmap, Invoice{}, "PersonId")
+ b.StartTimer()
+
+ var insert, sel, update, delete string
+ if os.Getenv("GORP_TEST_DIALECT") != "postgres" {
+ insert = "insert into invoice_test (" + columnCreated + ", " + columnUpdated + ", " + columnMemo + ", " + columnPersonId + ") values (?, ?, ?, ?)"
+ sel = "select " + columnId + ", " + columnCreated + ", " + columnUpdated + ", " + columnMemo + ", " + columnPersonId + " from invoice_test where " + columnId + "=?"
+ update = "update invoice_test set " + columnCreated + "=?, " + columnUpdated + "=?, " + columnMemo + "=?, " + columnPersonId + "=? where " + columnId + "=?"
+ delete = "delete from invoice_test where " + columnId + "=?"
+ } else {
+ insert = "insert into invoice_test (" + columnCreated + ", " + columnUpdated + ", " + columnMemo + ", " + columnPersonId + ") values ($1, $2, $3, $4)"
+ sel = "select " + columnId + ", " + columnCreated + ", " + columnUpdated + ", " + columnMemo + ", " + columnPersonId + " from invoice_test where " + columnId + "=$1"
+ update = "update invoice_test set " + columnCreated + "=$1, " + columnUpdated + "=$2, " + columnMemo + "=$3, " + columnPersonId + "=$4 where " + columnId + "=$5"
+ delete = "delete from invoice_test where " + columnId + "=$1"
+ }
+
+ inv := &Invoice{0, 100, 200, "my memo", 0, false}
+
+ for i := 0; i < b.N; i++ {
+ res, err := dbmap.Db.Exec(insert, inv.Created, inv.Updated,
+ inv.Memo, inv.PersonId)
+ if err != nil {
+ panic(err)
+ }
+
+ newid, err := res.LastInsertId()
+ if err != nil {
+ panic(err)
+ }
+ inv.Id = newid
+
+ row := dbmap.Db.QueryRow(sel, inv.Id)
+ err = row.Scan(&inv.Id, &inv.Created, &inv.Updated, &inv.Memo,
+ &inv.PersonId)
+ if err != nil {
+ panic(err)
+ }
+
+ inv.Created = 1000
+ inv.Updated = 2000
+ inv.Memo = "my memo 2"
+ inv.PersonId = 3000
+
+ _, err = dbmap.Db.Exec(update, inv.Created, inv.Updated, inv.Memo,
+ inv.PersonId, inv.Id)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = dbmap.Db.Exec(delete, inv.Id)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+}
+
+func BenchmarkGorpCrud(b *testing.B) {
+ b.StopTimer()
+ dbmap := initDbMapBench()
+ defer dropAndClose(dbmap)
+ b.StartTimer()
+
+ inv := &Invoice{0, 100, 200, "my memo", 0, true}
+ for i := 0; i < b.N; i++ {
+ err := dbmap.Insert(inv)
+ if err != nil {
+ panic(err)
+ }
+
+ obj, err := dbmap.Get(Invoice{}, inv.Id)
+ if err != nil {
+ panic(err)
+ }
+
+ inv2, ok := obj.(*Invoice)
+ if !ok {
+ panic(fmt.Sprintf("expected *Invoice, got: %v", obj))
+ }
+
+ inv2.Created = 1000
+ inv2.Updated = 2000
+ inv2.Memo = "my memo 2"
+ inv2.PersonId = 3000
+ _, err = dbmap.Update(inv2)
+ if err != nil {
+ panic(err)
+ }
+
+ _, err = dbmap.Delete(inv2)
+ if err != nil {
+ panic(err)
+ }
+
+ }
+}
+
+func initDbMapBench() *gorp.DbMap {
+ dbmap := newDbMap()
+ dbmap.Db.Exec("drop table if exists invoice_test")
+ dbmap.AddTableWithName(Invoice{}, "invoice_test").SetKeys(true, "Id")
+ err := dbmap.CreateTables()
+ if err != nil {
+ panic(err)
+ }
+ return dbmap
+}
+
+func initDbMap() *gorp.DbMap {
+ dbmap := newDbMap()
+ dbmap.AddTableWithName(Invoice{}, "invoice_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(InvoiceTag{}, "invoice_tag_test") //key is set via primarykey attribute
+ dbmap.AddTableWithName(AliasTransientField{}, "alias_trans_field_test").SetKeys(true, "id")
+ dbmap.AddTableWithName(OverriddenInvoice{}, "invoice_override_test").SetKeys(false, "Id")
+ dbmap.AddTableWithName(Person{}, "person_test").SetKeys(true, "Id").SetVersionCol("Version")
+ dbmap.AddTableWithName(WithIgnoredColumn{}, "ignored_column_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(IdCreated{}, "id_created_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(TypeConversionExample{}, "type_conv_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(WithEmbeddedStruct{}, "embedded_struct_test").SetKeys(true, "Id")
+ //dbmap.AddTableWithName(WithEmbeddedStructConflictingEmbeddedMemberNames{}, "embedded_struct_conflict_name_test").SetKeys(true, "Id")
+ //dbmap.AddTableWithName(WithEmbeddedStructSameMemberName{}, "embedded_struct_same_member_name_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(WithEmbeddedStructBeforeAutoincrField{}, "embedded_struct_before_autoincr_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(WithEmbeddedAutoincr{}, "embedded_autoincr_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(WithTime{}, "time_test").SetKeys(true, "Id")
+ dbmap.AddTableWithName(WithNullTime{}, "nulltime_test").SetKeys(false, "Id")
+ dbmap.TypeConverter = testTypeConverter{}
+ err := dbmap.DropTablesIfExists()
+ if err != nil {
+ panic(err)
+ }
+ err = dbmap.CreateTables()
+ if err != nil {
+ panic(err)
+ }
+
+ // See #146 and TestSelectAlias - this type is mapped to the same
+ // table as IdCreated, but includes an extra field that isn't in the table
+ dbmap.AddTableWithName(IdCreatedExternal{}, "id_created_test").SetKeys(true, "Id")
+
+ return dbmap
+}
+
+func initDbMapNulls() *gorp.DbMap {
+ dbmap := newDbMap()
+ dbmap.AddTable(TableWithNull{}).SetKeys(false, "Id")
+ err := dbmap.CreateTables()
+ if err != nil {
+ panic(err)
+ }
+ return dbmap
+}
+
+func newDbMap() *gorp.DbMap {
+ dialect, driver := dialectAndDriver()
+ dbmap := &gorp.DbMap{Db: connect(driver), Dialect: dialect}
+ if debug {
+ dbmap.TraceOn("", log.New(os.Stdout, "gorptest: ", log.Lmicroseconds))
+ }
+ return dbmap
+}
+
+func dropAndClose(dbmap *gorp.DbMap) {
+ dbmap.DropTablesIfExists()
+ dbmap.Db.Close()
+}
+
+func connect(driver string) *sql.DB {
+ dsn := os.Getenv("GORP_TEST_DSN")
+ if dsn == "" {
+ panic("GORP_TEST_DSN env variable is not set. Please see README.md")
+ }
+
+ db, err := sql.Open(driver, dsn)
+ if err != nil {
+ panic("Error connecting to db: " + err.Error())
+ }
+ return db
+}
+
+func dialectAndDriver() (gorp.Dialect, string) {
+ switch os.Getenv("GORP_TEST_DIALECT") {
+ case "mysql":
+ return gorp.MySQLDialect{"InnoDB", "UTF8"}, "mymysql"
+ case "gomysql":
+ return gorp.MySQLDialect{"InnoDB", "UTF8"}, "mysql"
+ case "postgres":
+ return gorp.PostgresDialect{}, "postgres"
+ case "sqlite":
+ return gorp.SqliteDialect{}, "sqlite3"
+ }
+ panic("GORP_TEST_DIALECT env variable is not set or is invalid. Please see README.md")
+}
+
+func _insert(dbmap *gorp.DbMap, list ...interface{}) {
+ err := dbmap.Insert(list...)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func _update(dbmap *gorp.DbMap, list ...interface{}) int64 {
+ count, err := dbmap.Update(list...)
+ if err != nil {
+ panic(err)
+ }
+ return count
+}
+
+func _updateColumns(dbmap *gorp.DbMap, filter gorp.ColumnFilter, list ...interface{}) int64 {
+ count, err := dbmap.UpdateColumns(filter, list...)
+ if err != nil {
+ panic(err)
+ }
+ return count
+}
+
+func _del(dbmap *gorp.DbMap, list ...interface{}) int64 {
+ count, err := dbmap.Delete(list...)
+ if err != nil {
+ panic(err)
+ }
+
+ return count
+}
+
+func _get(dbmap *gorp.DbMap, i interface{}, keys ...interface{}) interface{} {
+ obj, err := dbmap.Get(i, keys...)
+ if err != nil {
+ panic(err)
+ }
+
+ return obj
+}
+
+func selectInt(dbmap *gorp.DbMap, query string, args ...interface{}) int64 {
+ i64, err := gorp.SelectInt(dbmap, query, args...)
+ if err != nil {
+ panic(err)
+ }
+
+ return i64
+}
+
+func selectNullInt(dbmap *gorp.DbMap, query string, args ...interface{}) sql.NullInt64 {
+ i64, err := gorp.SelectNullInt(dbmap, query, args...)
+ if err != nil {
+ panic(err)
+ }
+
+ return i64
+}
+
+func selectFloat(dbmap *gorp.DbMap, query string, args ...interface{}) float64 {
+ f64, err := gorp.SelectFloat(dbmap, query, args...)
+ if err != nil {
+ panic(err)
+ }
+
+ return f64
+}
+
+func selectNullFloat(dbmap *gorp.DbMap, query string, args ...interface{}) sql.NullFloat64 {
+ f64, err := gorp.SelectNullFloat(dbmap, query, args...)
+ if err != nil {
+ panic(err)
+ }
+
+ return f64
+}
+
+func selectStr(dbmap *gorp.DbMap, query string, args ...interface{}) string {
+ s, err := gorp.SelectStr(dbmap, query, args...)
+ if err != nil {
+ panic(err)
+ }
+
+ return s
+}
+
+func selectNullStr(dbmap *gorp.DbMap, query string, args ...interface{}) sql.NullString {
+ s, err := gorp.SelectNullStr(dbmap, query, args...)
+ if err != nil {
+ panic(err)
+ }
+
+ return s
+}
+
+func rawExec(dbmap *gorp.DbMap, query string, args ...interface{}) sql.Result {
+ res, err := dbmap.Exec(query, args...)
+ if err != nil {
+ panic(err)
+ }
+ return res
+}
+
+func rawSelect(dbmap *gorp.DbMap, i interface{}, query string, args ...interface{}) []interface{} {
+ list, err := dbmap.Select(i, query, args...)
+ if err != nil {
+ panic(err)
+ }
+ return list
+}
+
+func tableName(dbmap *gorp.DbMap, i interface{}) string {
+ t := reflect.TypeOf(i)
+ if table, err := dbmap.TableFor(t, false); table != nil && err == nil {
+ return dbmap.Dialect.QuoteField(table.TableName)
+ }
+ return t.Name()
+}
+
+func columnName(dbmap *gorp.DbMap, i interface{}, fieldName string) string {
+ t := reflect.TypeOf(i)
+ if table, err := dbmap.TableFor(t, false); table != nil && err == nil {
+ return dbmap.Dialect.QuoteField(table.ColMap(fieldName).ColumnName)
+ }
+ return fieldName
+}
diff --git a/vendor/github.com/go-gorp/gorp/test_all.sh b/vendor/github.com/go-gorp/gorp/test_all.sh
index 4c99584ef..4c99584ef 100644..100755
--- a/vendor/github.com/go-gorp/gorp/test_all.sh
+++ b/vendor/github.com/go-gorp/gorp/test_all.sh
diff --git a/vendor/github.com/go-ldap/ldap/conn_test.go b/vendor/github.com/go-ldap/ldap/conn_test.go
new file mode 100644
index 000000000..8394e5339
--- /dev/null
+++ b/vendor/github.com/go-ldap/ldap/conn_test.go
@@ -0,0 +1,53 @@
+package ldap
+
+import (
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+ "time"
+
+ "gopkg.in/asn1-ber.v1"
+)
+
+func TestUnresponsiveConnection(t *testing.T) {
+ // The do-nothing server that accepts requests and does nothing
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ }))
+ defer ts.Close()
+ c, err := net.Dial(ts.Listener.Addr().Network(), ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatalf("error connecting to localhost tcp: %v", err)
+ }
+
+ // Create an Ldap connection
+ conn := NewConn(c, false)
+ conn.SetTimeout(time.Millisecond)
+ conn.Start()
+ defer conn.Close()
+
+ // Mock a packet
+ messageID := conn.nextMessageID()
+ packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
+ packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID"))
+ bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
+ bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
+ packet.AppendChild(bindRequest)
+
+ // Send packet and test response
+ channel, err := conn.sendMessage(packet)
+ if err != nil {
+ t.Fatalf("error sending message: %v", err)
+ }
+ packetResponse, ok := <-channel
+ if !ok {
+ t.Fatalf("no PacketResponse in response channel")
+ }
+ packet, err = packetResponse.ReadPacket()
+ if err == nil {
+ t.Fatalf("expected timeout error")
+ }
+ if err.Error() != "ldap: connection timed out" {
+ t.Fatalf("unexpected error: %v", err)
+ }
+}
diff --git a/vendor/github.com/go-ldap/ldap/dn_test.go b/vendor/github.com/go-ldap/ldap/dn_test.go
new file mode 100644
index 000000000..39817c427
--- /dev/null
+++ b/vendor/github.com/go-ldap/ldap/dn_test.go
@@ -0,0 +1,70 @@
+package ldap_test
+
+import (
+ "reflect"
+ "testing"
+
+ "gopkg.in/ldap.v2"
+)
+
+func TestSuccessfulDNParsing(t *testing.T) {
+ testcases := map[string]ldap.DN{
+ "": ldap.DN{[]*ldap.RelativeDN{}},
+ "cn=Jim\\2C \\22Hasse Hö\\22 Hansson!,dc=dummy,dc=com": ldap.DN{[]*ldap.RelativeDN{
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"cn", "Jim, \"Hasse Hö\" Hansson!"}}},
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "dummy"}}},
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"dc", "com"}}}}},
+ "UID=jsmith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"UID", "jsmith"}}},
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
+ "OU=Sales+CN=J. Smith,DC=example,DC=net": ldap.DN{[]*ldap.RelativeDN{
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{
+ &ldap.AttributeTypeAndValue{"OU", "Sales"},
+ &ldap.AttributeTypeAndValue{"CN", "J. Smith"}}},
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "example"}}},
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
+ "1.3.6.1.4.1.1466.0=#04024869": ldap.DN{[]*ldap.RelativeDN{
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}}}},
+ "1.3.6.1.4.1.1466.0=#04024869,DC=net": ldap.DN{[]*ldap.RelativeDN{
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"1.3.6.1.4.1.1466.0", "Hi"}}},
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"DC", "net"}}}}},
+ "CN=Lu\\C4\\8Di\\C4\\87": ldap.DN{[]*ldap.RelativeDN{
+ &ldap.RelativeDN{[]*ldap.AttributeTypeAndValue{&ldap.AttributeTypeAndValue{"CN", "Lučić"}}}}},
+ }
+
+ for test, answer := range testcases {
+ dn, err := ldap.ParseDN(test)
+ if err != nil {
+ t.Errorf(err.Error())
+ continue
+ }
+ if !reflect.DeepEqual(dn, &answer) {
+ t.Errorf("Parsed DN %s is not equal to the expected structure", test)
+ for _, rdn := range dn.RDNs {
+ for _, attribs := range rdn.Attributes {
+ t.Logf("#%v\n", attribs)
+ }
+ }
+ }
+ }
+}
+
+func TestErrorDNParsing(t *testing.T) {
+ testcases := map[string]string{
+ "*": "DN ended with incomplete type, value pair",
+ "cn=Jim\\0Test": "Failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'",
+ "cn=Jim\\0": "Got corrupted escaped character",
+ "DC=example,=net": "DN ended with incomplete type, value pair",
+ "1=#0402486": "Failed to decode BER encoding: encoding/hex: odd length hex string",
+ }
+
+ for test, answer := range testcases {
+ _, err := ldap.ParseDN(test)
+ if err == nil {
+ t.Errorf("Expected %s to fail parsing but succeeded\n", test)
+ } else if err.Error() != answer {
+ t.Errorf("Unexpected error on %s:\n%s\nvs.\n%s\n", test, answer, err.Error())
+ }
+ }
+}
diff --git a/vendor/github.com/go-ldap/ldap/error_test.go b/vendor/github.com/go-ldap/ldap/error_test.go
new file mode 100644
index 000000000..4ec720d9f
--- /dev/null
+++ b/vendor/github.com/go-ldap/ldap/error_test.go
@@ -0,0 +1,29 @@
+package ldap
+
+import (
+ "testing"
+
+ "gopkg.in/asn1-ber.v1"
+)
+
+// TestNilPacket tests that nil packets don't cause a panic.
+func TestNilPacket(t *testing.T) {
+ // Test for nil packet
+ code, _ := getLDAPResultCode(nil)
+ if code != ErrorUnexpectedResponse {
+ t.Errorf("Should have an 'ErrorUnexpectedResponse' error in nil packets, got: %v", code)
+ }
+
+ // Test for nil result
+ kids := []*ber.Packet{
+ &ber.Packet{}, // Unused
+ nil, // Can't be nil
+ }
+ pack := &ber.Packet{Children: kids}
+ code, _ = getLDAPResultCode(pack)
+
+ if code != ErrorUnexpectedResponse {
+ t.Errorf("Should have an 'ErrorUnexpectedResponse' error in nil packets, got: %v", code)
+ }
+
+}
diff --git a/vendor/github.com/go-ldap/ldap/example_test.go b/vendor/github.com/go-ldap/ldap/example_test.go
new file mode 100644
index 000000000..b018a9664
--- /dev/null
+++ b/vendor/github.com/go-ldap/ldap/example_test.go
@@ -0,0 +1,305 @@
+package ldap_test
+
+import (
+ "crypto/tls"
+ "fmt"
+ "log"
+
+ "gopkg.in/ldap.v2"
+)
+
+// ExampleConn_Bind demonstrates how to bind a connection to an ldap user
+// allowing access to restricted attrabutes that user has access to
+func ExampleConn_Bind() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ err = l.Bind("cn=read-only-admin,dc=example,dc=com", "password")
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+// ExampleConn_Search demonstrates how to use the search interface
+func ExampleConn_Search() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ searchRequest := ldap.NewSearchRequest(
+ "dc=example,dc=com", // The base dn to search
+ ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
+ "(&(objectClass=organizationalPerson))", // The filter to apply
+ []string{"dn", "cn"}, // A list attributes to retrieve
+ nil,
+ )
+
+ sr, err := l.Search(searchRequest)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for _, entry := range sr.Entries {
+ fmt.Printf("%s: %v\n", entry.DN, entry.GetAttributeValue("cn"))
+ }
+}
+
+// ExampleStartTLS demonstrates how to start a TLS connection
+func ExampleConn_StartTLS() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ // Reconnect with TLS
+ err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Opertations via l are now encrypted
+}
+
+// ExampleConn_Compare demonstrates how to comapre an attribute with a value
+func ExampleConn_Compare() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ matched, err := l.Compare("cn=user,dc=example,dc=com", "uid", "someuserid")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Println(matched)
+}
+
+func ExampleConn_PasswordModify_admin() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ err = l.Bind("cn=admin,dc=example,dc=com", "password")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ passwordModifyRequest := ldap.NewPasswordModifyRequest("cn=user,dc=example,dc=com", "", "NewPassword")
+ _, err = l.PasswordModify(passwordModifyRequest)
+
+ if err != nil {
+ log.Fatalf("Password could not be changed: %s", err.Error())
+ }
+}
+
+func ExampleConn_PasswordModify_generatedPassword() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ err = l.Bind("cn=user,dc=example,dc=com", "password")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "")
+ passwordModifyResponse, err := l.PasswordModify(passwordModifyRequest)
+ if err != nil {
+ log.Fatalf("Password could not be changed: %s", err.Error())
+ }
+
+ generatedPassword := passwordModifyResponse.GeneratedPassword
+ log.Printf("Generated password: %s\n", generatedPassword)
+}
+
+func ExampleConn_PasswordModify_setNewPassword() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ err = l.Bind("cn=user,dc=example,dc=com", "password")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ passwordModifyRequest := ldap.NewPasswordModifyRequest("", "OldPassword", "NewPassword")
+ _, err = l.PasswordModify(passwordModifyRequest)
+
+ if err != nil {
+ log.Fatalf("Password could not be changed: %s", err.Error())
+ }
+}
+
+func ExampleConn_Modify() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ // Add a description, and replace the mail attributes
+ modify := ldap.NewModifyRequest("cn=user,dc=example,dc=com")
+ modify.Add("description", []string{"An example user"})
+ modify.Replace("mail", []string{"user@example.org"})
+
+ err = l.Modify(modify)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+// Example User Authentication shows how a typical application can verify a login attempt
+func Example_userAuthentication() {
+ // The username and password we want to check
+ username := "someuser"
+ password := "userpassword"
+
+ bindusername := "readonly"
+ bindpassword := "password"
+
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ // Reconnect with TLS
+ err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // First bind with a read only user
+ err = l.Bind(bindusername, bindpassword)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Search for the given username
+ searchRequest := ldap.NewSearchRequest(
+ "dc=example,dc=com",
+ ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
+ fmt.Sprintf("(&(objectClass=organizationalPerson)&(uid=%s))", username),
+ []string{"dn"},
+ nil,
+ )
+
+ sr, err := l.Search(searchRequest)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if len(sr.Entries) != 1 {
+ log.Fatal("User does not exist or too many entries returned")
+ }
+
+ userdn := sr.Entries[0].DN
+
+ // Bind as the user to verify their password
+ err = l.Bind(userdn, password)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Rebind as the read only user for any futher queries
+ err = l.Bind(bindusername, bindpassword)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+func Example_beherappolicy() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+
+ controls := []ldap.Control{}
+ controls = append(controls, ldap.NewControlBeheraPasswordPolicy())
+ bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", controls)
+
+ r, err := l.SimpleBind(bindRequest)
+ ppolicyControl := ldap.FindControl(r.Controls, ldap.ControlTypeBeheraPasswordPolicy)
+
+ var ppolicy *ldap.ControlBeheraPasswordPolicy
+ if ppolicyControl != nil {
+ ppolicy = ppolicyControl.(*ldap.ControlBeheraPasswordPolicy)
+ } else {
+ log.Printf("ppolicyControl response not avaliable.\n")
+ }
+ if err != nil {
+ errStr := "ERROR: Cannot bind: " + err.Error()
+ if ppolicy != nil && ppolicy.Error >= 0 {
+ errStr += ":" + ppolicy.ErrorString
+ }
+ log.Print(errStr)
+ } else {
+ logStr := "Login Ok"
+ if ppolicy != nil {
+ if ppolicy.Expire >= 0 {
+ logStr += fmt.Sprintf(". Password expires in %d seconds\n", ppolicy.Expire)
+ } else if ppolicy.Grace >= 0 {
+ logStr += fmt.Sprintf(". Password expired, %d grace logins remain\n", ppolicy.Grace)
+ }
+ }
+ log.Print(logStr)
+ }
+}
+
+func Example_vchuppolicy() {
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer l.Close()
+ l.Debug = true
+
+ bindRequest := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=com", "password", nil)
+
+ r, err := l.SimpleBind(bindRequest)
+
+ passwordMustChangeControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordMustChange)
+ var passwordMustChange *ldap.ControlVChuPasswordMustChange
+ if passwordMustChangeControl != nil {
+ passwordMustChange = passwordMustChangeControl.(*ldap.ControlVChuPasswordMustChange)
+ }
+
+ if passwordMustChange != nil && passwordMustChange.MustChange {
+ log.Printf("Password Must be changed.\n")
+ }
+
+ passwordWarningControl := ldap.FindControl(r.Controls, ldap.ControlTypeVChuPasswordWarning)
+
+ var passwordWarning *ldap.ControlVChuPasswordWarning
+ if passwordWarningControl != nil {
+ passwordWarning = passwordWarningControl.(*ldap.ControlVChuPasswordWarning)
+ } else {
+ log.Printf("ppolicyControl response not available.\n")
+ }
+ if err != nil {
+ log.Print("ERROR: Cannot bind: " + err.Error())
+ } else {
+ logStr := "Login Ok"
+ if passwordWarning != nil {
+ if passwordWarning.Expire >= 0 {
+ logStr += fmt.Sprintf(". Password expires in %d seconds\n", passwordWarning.Expire)
+ }
+ }
+ log.Print(logStr)
+ }
+}
diff --git a/vendor/github.com/go-ldap/ldap/filter_test.go b/vendor/github.com/go-ldap/ldap/filter_test.go
new file mode 100644
index 000000000..ae1b79b0c
--- /dev/null
+++ b/vendor/github.com/go-ldap/ldap/filter_test.go
@@ -0,0 +1,248 @@
+package ldap_test
+
+import (
+ "strings"
+ "testing"
+
+ "gopkg.in/asn1-ber.v1"
+ "gopkg.in/ldap.v2"
+)
+
+type compileTest struct {
+ filterStr string
+
+ expectedFilter string
+ expectedType int
+ expectedErr string
+}
+
+var testFilters = []compileTest{
+ compileTest{
+ filterStr: "(&(sn=Miller)(givenName=Bob))",
+ expectedFilter: "(&(sn=Miller)(givenName=Bob))",
+ expectedType: ldap.FilterAnd,
+ },
+ compileTest{
+ filterStr: "(|(sn=Miller)(givenName=Bob))",
+ expectedFilter: "(|(sn=Miller)(givenName=Bob))",
+ expectedType: ldap.FilterOr,
+ },
+ compileTest{
+ filterStr: "(!(sn=Miller))",
+ expectedFilter: "(!(sn=Miller))",
+ expectedType: ldap.FilterNot,
+ },
+ compileTest{
+ filterStr: "(sn=Miller)",
+ expectedFilter: "(sn=Miller)",
+ expectedType: ldap.FilterEqualityMatch,
+ },
+ compileTest{
+ filterStr: "(sn=Mill*)",
+ expectedFilter: "(sn=Mill*)",
+ expectedType: ldap.FilterSubstrings,
+ },
+ compileTest{
+ filterStr: "(sn=*Mill)",
+ expectedFilter: "(sn=*Mill)",
+ expectedType: ldap.FilterSubstrings,
+ },
+ compileTest{
+ filterStr: "(sn=*Mill*)",
+ expectedFilter: "(sn=*Mill*)",
+ expectedType: ldap.FilterSubstrings,
+ },
+ compileTest{
+ filterStr: "(sn=*i*le*)",
+ expectedFilter: "(sn=*i*le*)",
+ expectedType: ldap.FilterSubstrings,
+ },
+ compileTest{
+ filterStr: "(sn=Mi*l*r)",
+ expectedFilter: "(sn=Mi*l*r)",
+ expectedType: ldap.FilterSubstrings,
+ },
+ // substring filters escape properly
+ compileTest{
+ filterStr: `(sn=Mi*함*r)`,
+ expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
+ expectedType: ldap.FilterSubstrings,
+ },
+ // already escaped substring filters don't get double-escaped
+ compileTest{
+ filterStr: `(sn=Mi*\ed\95\a8*r)`,
+ expectedFilter: `(sn=Mi*\ed\95\a8*r)`,
+ expectedType: ldap.FilterSubstrings,
+ },
+ compileTest{
+ filterStr: "(sn=Mi*le*)",
+ expectedFilter: "(sn=Mi*le*)",
+ expectedType: ldap.FilterSubstrings,
+ },
+ compileTest{
+ filterStr: "(sn=*i*ler)",
+ expectedFilter: "(sn=*i*ler)",
+ expectedType: ldap.FilterSubstrings,
+ },
+ compileTest{
+ filterStr: "(sn>=Miller)",
+ expectedFilter: "(sn>=Miller)",
+ expectedType: ldap.FilterGreaterOrEqual,
+ },
+ compileTest{
+ filterStr: "(sn<=Miller)",
+ expectedFilter: "(sn<=Miller)",
+ expectedType: ldap.FilterLessOrEqual,
+ },
+ compileTest{
+ filterStr: "(sn=*)",
+ expectedFilter: "(sn=*)",
+ expectedType: ldap.FilterPresent,
+ },
+ compileTest{
+ filterStr: "(sn~=Miller)",
+ expectedFilter: "(sn~=Miller)",
+ expectedType: ldap.FilterApproxMatch,
+ },
+ compileTest{
+ filterStr: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
+ expectedFilter: `(objectGUID='\fc\fe\a3\ab\f9\90N\aaGm\d5I~\d12)`,
+ expectedType: ldap.FilterEqualityMatch,
+ },
+ compileTest{
+ filterStr: `(objectGUID=абвгдеёжзийклмнопрстуфхцчшщъыьэюя)`,
+ expectedFilter: `(objectGUID=\d0\b0\d0\b1\d0\b2\d0\b3\d0\b4\d0\b5\d1\91\d0\b6\d0\b7\d0\b8\d0\b9\d0\ba\d0\bb\d0\bc\d0\bd\d0\be\d0\bf\d1\80\d1\81\d1\82\d1\83\d1\84\d1\85\d1\86\d1\87\d1\88\d1\89\d1\8a\d1\8b\d1\8c\d1\8d\d1\8e\d1\8f)`,
+ expectedType: ldap.FilterEqualityMatch,
+ },
+ compileTest{
+ filterStr: `(objectGUID=함수목록)`,
+ expectedFilter: `(objectGUID=\ed\95\a8\ec\88\98\eb\aa\a9\eb\a1\9d)`,
+ expectedType: ldap.FilterEqualityMatch,
+ },
+ compileTest{
+ filterStr: `(objectGUID=`,
+ expectedFilter: ``,
+ expectedType: 0,
+ expectedErr: "unexpected end of filter",
+ },
+ compileTest{
+ filterStr: `(objectGUID=함수목록`,
+ expectedFilter: ``,
+ expectedType: 0,
+ expectedErr: "unexpected end of filter",
+ },
+ compileTest{
+ filterStr: `(&(objectclass=inetorgperson)(cn=中文))`,
+ expectedFilter: `(&(objectclass=inetorgperson)(cn=\e4\b8\ad\e6\96\87))`,
+ expectedType: 0,
+ },
+ // attr extension
+ compileTest{
+ filterStr: `(memberOf:=foo)`,
+ expectedFilter: `(memberOf:=foo)`,
+ expectedType: ldap.FilterExtensibleMatch,
+ },
+ // attr+named matching rule extension
+ compileTest{
+ filterStr: `(memberOf:test:=foo)`,
+ expectedFilter: `(memberOf:test:=foo)`,
+ expectedType: ldap.FilterExtensibleMatch,
+ },
+ // attr+oid matching rule extension
+ compileTest{
+ filterStr: `(cn:1.2.3.4.5:=Fred Flintstone)`,
+ expectedFilter: `(cn:1.2.3.4.5:=Fred Flintstone)`,
+ expectedType: ldap.FilterExtensibleMatch,
+ },
+ // attr+dn+oid matching rule extension
+ compileTest{
+ filterStr: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
+ expectedFilter: `(sn:dn:2.4.6.8.10:=Barney Rubble)`,
+ expectedType: ldap.FilterExtensibleMatch,
+ },
+ // attr+dn extension
+ compileTest{
+ filterStr: `(o:dn:=Ace Industry)`,
+ expectedFilter: `(o:dn:=Ace Industry)`,
+ expectedType: ldap.FilterExtensibleMatch,
+ },
+ // dn extension
+ compileTest{
+ filterStr: `(:dn:2.4.6.8.10:=Dino)`,
+ expectedFilter: `(:dn:2.4.6.8.10:=Dino)`,
+ expectedType: ldap.FilterExtensibleMatch,
+ },
+ compileTest{
+ filterStr: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
+ expectedFilter: `(memberOf:1.2.840.113556.1.4.1941:=CN=User1,OU=blah,DC=mydomain,DC=net)`,
+ expectedType: ldap.FilterExtensibleMatch,
+ },
+
+ // compileTest{ filterStr: "()", filterType: FilterExtensibleMatch },
+}
+
+var testInvalidFilters = []string{
+ `(objectGUID=\zz)`,
+ `(objectGUID=\a)`,
+}
+
+func TestFilter(t *testing.T) {
+ // Test Compiler and Decompiler
+ for _, i := range testFilters {
+ filter, err := ldap.CompileFilter(i.filterStr)
+ if err != nil {
+ if i.expectedErr == "" || !strings.Contains(err.Error(), i.expectedErr) {
+ t.Errorf("Problem compiling '%s' - '%v' (expected error to contain '%v')", i.filterStr, err, i.expectedErr)
+ }
+ } else if filter.Tag != ber.Tag(i.expectedType) {
+ t.Errorf("%q Expected %q got %q", i.filterStr, ldap.FilterMap[uint64(i.expectedType)], ldap.FilterMap[uint64(filter.Tag)])
+ } else {
+ o, err := ldap.DecompileFilter(filter)
+ if err != nil {
+ t.Errorf("Problem compiling %s - %s", i.filterStr, err.Error())
+ } else if i.expectedFilter != o {
+ t.Errorf("%q expected, got %q", i.expectedFilter, o)
+ }
+ }
+ }
+}
+
+func TestInvalidFilter(t *testing.T) {
+ for _, filterStr := range testInvalidFilters {
+ if _, err := ldap.CompileFilter(filterStr); err == nil {
+ t.Errorf("Problem compiling %s - expected err", filterStr)
+ }
+ }
+}
+
+func BenchmarkFilterCompile(b *testing.B) {
+ b.StopTimer()
+ filters := make([]string, len(testFilters))
+
+ // Test Compiler and Decompiler
+ for idx, i := range testFilters {
+ filters[idx] = i.filterStr
+ }
+
+ maxIdx := len(filters)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ ldap.CompileFilter(filters[i%maxIdx])
+ }
+}
+
+func BenchmarkFilterDecompile(b *testing.B) {
+ b.StopTimer()
+ filters := make([]*ber.Packet, len(testFilters))
+
+ // Test Compiler and Decompiler
+ for idx, i := range testFilters {
+ filters[idx], _ = ldap.CompileFilter(i.filterStr)
+ }
+
+ maxIdx := len(filters)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ ldap.DecompileFilter(filters[i%maxIdx])
+ }
+}
diff --git a/vendor/github.com/go-ldap/ldap/ldap_test.go b/vendor/github.com/go-ldap/ldap/ldap_test.go
new file mode 100644
index 000000000..9f4305180
--- /dev/null
+++ b/vendor/github.com/go-ldap/ldap/ldap_test.go
@@ -0,0 +1,275 @@
+package ldap_test
+
+import (
+ "crypto/tls"
+ "fmt"
+ "testing"
+
+ "gopkg.in/ldap.v2"
+)
+
+var ldapServer = "ldap.itd.umich.edu"
+var ldapPort = uint16(389)
+var ldapTLSPort = uint16(636)
+var baseDN = "dc=umich,dc=edu"
+var filter = []string{
+ "(cn=cis-fac)",
+ "(&(owner=*)(cn=cis-fac))",
+ "(&(objectclass=rfc822mailgroup)(cn=*Computer*))",
+ "(&(objectclass=rfc822mailgroup)(cn=*Mathematics*))"}
+var attributes = []string{
+ "cn",
+ "description"}
+
+func TestDial(t *testing.T) {
+ fmt.Printf("TestDial: starting...\n")
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ defer l.Close()
+ fmt.Printf("TestDial: finished...\n")
+}
+
+func TestDialTLS(t *testing.T) {
+ fmt.Printf("TestDialTLS: starting...\n")
+ l, err := ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ defer l.Close()
+ fmt.Printf("TestDialTLS: finished...\n")
+}
+
+func TestStartTLS(t *testing.T) {
+ fmt.Printf("TestStartTLS: starting...\n")
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ fmt.Printf("TestStartTLS: finished...\n")
+}
+
+func TestSearch(t *testing.T) {
+ fmt.Printf("TestSearch: starting...\n")
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ defer l.Close()
+
+ searchRequest := ldap.NewSearchRequest(
+ baseDN,
+ ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
+ filter[0],
+ attributes,
+ nil)
+
+ sr, err := l.Search(searchRequest)
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ fmt.Printf("TestSearch: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
+}
+
+func TestSearchStartTLS(t *testing.T) {
+ fmt.Printf("TestSearchStartTLS: starting...\n")
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ defer l.Close()
+
+ searchRequest := ldap.NewSearchRequest(
+ baseDN,
+ ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
+ filter[0],
+ attributes,
+ nil)
+
+ sr, err := l.Search(searchRequest)
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
+
+ fmt.Printf("TestSearchStartTLS: upgrading with startTLS\n")
+ err = l.StartTLS(&tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ sr, err = l.Search(searchRequest)
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ fmt.Printf("TestSearchStartTLS: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
+}
+
+func TestSearchWithPaging(t *testing.T) {
+ fmt.Printf("TestSearchWithPaging: starting...\n")
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ defer l.Close()
+
+ err = l.Bind("", "")
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ searchRequest := ldap.NewSearchRequest(
+ baseDN,
+ ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
+ filter[2],
+ attributes,
+ nil)
+ sr, err := l.SearchWithPaging(searchRequest, 5)
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
+
+ searchRequest = ldap.NewSearchRequest(
+ baseDN,
+ ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
+ filter[2],
+ attributes,
+ []ldap.Control{ldap.NewControlPaging(5)})
+ sr, err = l.SearchWithPaging(searchRequest, 5)
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ fmt.Printf("TestSearchWithPaging: %s -> num of entries = %d\n", searchRequest.Filter, len(sr.Entries))
+
+ searchRequest = ldap.NewSearchRequest(
+ baseDN,
+ ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
+ filter[2],
+ attributes,
+ []ldap.Control{ldap.NewControlPaging(500)})
+ sr, err = l.SearchWithPaging(searchRequest, 5)
+ if err == nil {
+ t.Errorf("expected an error when paging size in control in search request doesn't match size given in call, got none")
+ return
+ }
+}
+
+func searchGoroutine(t *testing.T, l *ldap.Conn, results chan *ldap.SearchResult, i int) {
+ searchRequest := ldap.NewSearchRequest(
+ baseDN,
+ ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
+ filter[i],
+ attributes,
+ nil)
+ sr, err := l.Search(searchRequest)
+ if err != nil {
+ t.Errorf(err.Error())
+ results <- nil
+ return
+ }
+ results <- sr
+}
+
+func testMultiGoroutineSearch(t *testing.T, TLS bool, startTLS bool) {
+ fmt.Printf("TestMultiGoroutineSearch: starting...\n")
+ var l *ldap.Conn
+ var err error
+ if TLS {
+ l, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapTLSPort), &tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ defer l.Close()
+ } else {
+ l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+ if startTLS {
+ fmt.Printf("TestMultiGoroutineSearch: using StartTLS...\n")
+ err := l.StartTLS(&tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ }
+ }
+
+ results := make([]chan *ldap.SearchResult, len(filter))
+ for i := range filter {
+ results[i] = make(chan *ldap.SearchResult)
+ go searchGoroutine(t, l, results[i], i)
+ }
+ for i := range filter {
+ sr := <-results[i]
+ if sr == nil {
+ t.Errorf("Did not receive results from goroutine for %q", filter[i])
+ } else {
+ fmt.Printf("TestMultiGoroutineSearch(%d): %s -> num of entries = %d\n", i, filter[i], len(sr.Entries))
+ }
+ }
+}
+
+func TestMultiGoroutineSearch(t *testing.T) {
+ testMultiGoroutineSearch(t, false, false)
+ testMultiGoroutineSearch(t, true, true)
+ testMultiGoroutineSearch(t, false, true)
+}
+
+func TestEscapeFilter(t *testing.T) {
+ if got, want := ldap.EscapeFilter("a\x00b(c)d*e\\f"), `a\00b\28c\29d\2ae\5cf`; got != want {
+ t.Errorf("Got %s, expected %s", want, got)
+ }
+ if got, want := ldap.EscapeFilter("Lučić"), `Lu\c4\8di\c4\87`; got != want {
+ t.Errorf("Got %s, expected %s", want, got)
+ }
+}
+
+func TestCompare(t *testing.T) {
+ fmt.Printf("TestCompare: starting...\n")
+ l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", ldapServer, ldapPort))
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ defer l.Close()
+
+ dn := "cn=math mich,ou=User Groups,ou=Groups,dc=umich,dc=edu"
+ attribute := "cn"
+ value := "math mich"
+
+ sr, err := l.Compare(dn, attribute, value)
+ if err != nil {
+ t.Errorf(err.Error())
+ return
+ }
+
+ fmt.Printf("TestCompare: -> %v\n", sr)
+}
diff --git a/vendor/github.com/go-ldap/ldap/search_test.go b/vendor/github.com/go-ldap/ldap/search_test.go
new file mode 100644
index 000000000..efb8147d1
--- /dev/null
+++ b/vendor/github.com/go-ldap/ldap/search_test.go
@@ -0,0 +1,31 @@
+package ldap
+
+import (
+ "reflect"
+ "testing"
+)
+
+// TestNewEntry tests that repeated calls to NewEntry return the same value with the same input
+func TestNewEntry(t *testing.T) {
+ dn := "testDN"
+ attributes := map[string][]string{
+ "alpha": {"value"},
+ "beta": {"value"},
+ "gamma": {"value"},
+ "delta": {"value"},
+ "epsilon": {"value"},
+ }
+ exectedEntry := NewEntry(dn, attributes)
+
+ iteration := 0
+ for {
+ if iteration == 100 {
+ break
+ }
+ testEntry := NewEntry(dn, attributes)
+ if !reflect.DeepEqual(exectedEntry, testEntry) {
+ t.Fatalf("consequent calls to NewEntry did not yield the same result:\n\texpected:\n\t%s\n\tgot:\n\t%s\n", exectedEntry, testEntry)
+ }
+ iteration = iteration + 1
+ }
+}
diff --git a/vendor/github.com/go-sql-driver/mysql/benchmark_test.go b/vendor/github.com/go-sql-driver/mysql/benchmark_test.go
new file mode 100644
index 000000000..8f721139b
--- /dev/null
+++ b/vendor/github.com/go-sql-driver/mysql/benchmark_test.go
@@ -0,0 +1,246 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "bytes"
+ "database/sql"
+ "database/sql/driver"
+ "math"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+type TB testing.B
+
+func (tb *TB) check(err error) {
+ if err != nil {
+ tb.Fatal(err)
+ }
+}
+
+func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB {
+ tb.check(err)
+ return db
+}
+
+func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows {
+ tb.check(err)
+ return rows
+}
+
+func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt {
+ tb.check(err)
+ return stmt
+}
+
+func initDB(b *testing.B, queries ...string) *sql.DB {
+ tb := (*TB)(b)
+ db := tb.checkDB(sql.Open("mysql", dsn))
+ for _, query := range queries {
+ if _, err := db.Exec(query); err != nil {
+ if w, ok := err.(MySQLWarnings); ok {
+ b.Logf("warning on %q: %v", query, w)
+ } else {
+ b.Fatalf("error on %q: %v", query, err)
+ }
+ }
+ }
+ return db
+}
+
+const concurrencyLevel = 10
+
+func BenchmarkQuery(b *testing.B) {
+ tb := (*TB)(b)
+ b.StopTimer()
+ b.ReportAllocs()
+ db := initDB(b,
+ "DROP TABLE IF EXISTS foo",
+ "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))",
+ `INSERT INTO foo VALUES (1, "one")`,
+ `INSERT INTO foo VALUES (2, "two")`,
+ )
+ db.SetMaxIdleConns(concurrencyLevel)
+ defer db.Close()
+
+ stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?"))
+ defer stmt.Close()
+
+ remain := int64(b.N)
+ var wg sync.WaitGroup
+ wg.Add(concurrencyLevel)
+ defer wg.Wait()
+ b.StartTimer()
+
+ for i := 0; i < concurrencyLevel; i++ {
+ go func() {
+ for {
+ if atomic.AddInt64(&remain, -1) < 0 {
+ wg.Done()
+ return
+ }
+
+ var got string
+ tb.check(stmt.QueryRow(1).Scan(&got))
+ if got != "one" {
+ b.Errorf("query = %q; want one", got)
+ wg.Done()
+ return
+ }
+ }
+ }()
+ }
+}
+
+func BenchmarkExec(b *testing.B) {
+ tb := (*TB)(b)
+ b.StopTimer()
+ b.ReportAllocs()
+ db := tb.checkDB(sql.Open("mysql", dsn))
+ db.SetMaxIdleConns(concurrencyLevel)
+ defer db.Close()
+
+ stmt := tb.checkStmt(db.Prepare("DO 1"))
+ defer stmt.Close()
+
+ remain := int64(b.N)
+ var wg sync.WaitGroup
+ wg.Add(concurrencyLevel)
+ defer wg.Wait()
+ b.StartTimer()
+
+ for i := 0; i < concurrencyLevel; i++ {
+ go func() {
+ for {
+ if atomic.AddInt64(&remain, -1) < 0 {
+ wg.Done()
+ return
+ }
+
+ if _, err := stmt.Exec(); err != nil {
+ b.Fatal(err.Error())
+ }
+ }
+ }()
+ }
+}
+
+// data, but no db writes
+var roundtripSample []byte
+
+func initRoundtripBenchmarks() ([]byte, int, int) {
+ if roundtripSample == nil {
+ roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024))
+ }
+ return roundtripSample, 16, len(roundtripSample)
+}
+
+func BenchmarkRoundtripTxt(b *testing.B) {
+ b.StopTimer()
+ sample, min, max := initRoundtripBenchmarks()
+ sampleString := string(sample)
+ b.ReportAllocs()
+ tb := (*TB)(b)
+ db := tb.checkDB(sql.Open("mysql", dsn))
+ defer db.Close()
+ b.StartTimer()
+ var result string
+ for i := 0; i < b.N; i++ {
+ length := min + i
+ if length > max {
+ length = max
+ }
+ test := sampleString[0:length]
+ rows := tb.checkRows(db.Query(`SELECT "` + test + `"`))
+ if !rows.Next() {
+ rows.Close()
+ b.Fatalf("crashed")
+ }
+ err := rows.Scan(&result)
+ if err != nil {
+ rows.Close()
+ b.Fatalf("crashed")
+ }
+ if result != test {
+ rows.Close()
+ b.Errorf("mismatch")
+ }
+ rows.Close()
+ }
+}
+
+func BenchmarkRoundtripBin(b *testing.B) {
+ b.StopTimer()
+ sample, min, max := initRoundtripBenchmarks()
+ b.ReportAllocs()
+ tb := (*TB)(b)
+ db := tb.checkDB(sql.Open("mysql", dsn))
+ defer db.Close()
+ stmt := tb.checkStmt(db.Prepare("SELECT ?"))
+ defer stmt.Close()
+ b.StartTimer()
+ var result sql.RawBytes
+ for i := 0; i < b.N; i++ {
+ length := min + i
+ if length > max {
+ length = max
+ }
+ test := sample[0:length]
+ rows := tb.checkRows(stmt.Query(test))
+ if !rows.Next() {
+ rows.Close()
+ b.Fatalf("crashed")
+ }
+ err := rows.Scan(&result)
+ if err != nil {
+ rows.Close()
+ b.Fatalf("crashed")
+ }
+ if !bytes.Equal(result, test) {
+ rows.Close()
+ b.Errorf("mismatch")
+ }
+ rows.Close()
+ }
+}
+
+func BenchmarkInterpolation(b *testing.B) {
+ mc := &mysqlConn{
+ cfg: &Config{
+ InterpolateParams: true,
+ Loc: time.UTC,
+ },
+ maxPacketAllowed: maxPacketSize,
+ maxWriteSize: maxPacketSize - 1,
+ buf: newBuffer(nil),
+ }
+
+ args := []driver.Value{
+ int64(42424242),
+ float64(math.Pi),
+ false,
+ time.Unix(1423411542, 807015000),
+ []byte("bytes containing special chars ' \" \a \x00"),
+ "string containing special chars ' \" \a \x00",
+ }
+ q := "SELECT ?, ?, ?, ?, ?, ?"
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := mc.interpolateParams(q, args)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/vendor/github.com/go-sql-driver/mysql/driver_test.go b/vendor/github.com/go-sql-driver/mysql/driver_test.go
new file mode 100644
index 000000000..efbc4925c
--- /dev/null
+++ b/vendor/github.com/go-sql-driver/mysql/driver_test.go
@@ -0,0 +1,1857 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "bytes"
+ "crypto/tls"
+ "database/sql"
+ "database/sql/driver"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/url"
+ "os"
+ "strings"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+var (
+ user string
+ pass string
+ prot string
+ addr string
+ dbname string
+ dsn string
+ netAddr string
+ available bool
+)
+
+var (
+ tDate = time.Date(2012, 6, 14, 0, 0, 0, 0, time.UTC)
+ sDate = "2012-06-14"
+ tDateTime = time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)
+ sDateTime = "2011-11-20 21:27:37"
+ tDate0 = time.Time{}
+ sDate0 = "0000-00-00"
+ sDateTime0 = "0000-00-00 00:00:00"
+)
+
+// See https://github.com/go-sql-driver/mysql/wiki/Testing
+func init() {
+ // get environment variables
+ env := func(key, defaultValue string) string {
+ if value := os.Getenv(key); value != "" {
+ return value
+ }
+ return defaultValue
+ }
+ user = env("MYSQL_TEST_USER", "root")
+ pass = env("MYSQL_TEST_PASS", "")
+ prot = env("MYSQL_TEST_PROT", "tcp")
+ addr = env("MYSQL_TEST_ADDR", "localhost:3306")
+ dbname = env("MYSQL_TEST_DBNAME", "gotest")
+ netAddr = fmt.Sprintf("%s(%s)", prot, addr)
+ dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&strict=true", user, pass, netAddr, dbname)
+ c, err := net.Dial(prot, addr)
+ if err == nil {
+ available = true
+ c.Close()
+ }
+}
+
+type DBTest struct {
+ *testing.T
+ db *sql.DB
+}
+
+func runTestsWithMultiStatement(t *testing.T, dsn string, tests ...func(dbt *DBTest)) {
+ if !available {
+ t.Skipf("MySQL server not running on %s", netAddr)
+ }
+
+ dsn += "&multiStatements=true"
+ var db *sql.DB
+ if _, err := ParseDSN(dsn); err != errInvalidDSNUnsafeCollation {
+ db, err = sql.Open("mysql", dsn)
+ if err != nil {
+ t.Fatalf("error connecting: %s", err.Error())
+ }
+ defer db.Close()
+ }
+
+ dbt := &DBTest{t, db}
+ for _, test := range tests {
+ test(dbt)
+ dbt.db.Exec("DROP TABLE IF EXISTS test")
+ }
+}
+
+func runTests(t *testing.T, dsn string, tests ...func(dbt *DBTest)) {
+ if !available {
+ t.Skipf("MySQL server not running on %s", netAddr)
+ }
+
+ db, err := sql.Open("mysql", dsn)
+ if err != nil {
+ t.Fatalf("error connecting: %s", err.Error())
+ }
+ defer db.Close()
+
+ db.Exec("DROP TABLE IF EXISTS test")
+
+ dsn2 := dsn + "&interpolateParams=true"
+ var db2 *sql.DB
+ if _, err := ParseDSN(dsn2); err != errInvalidDSNUnsafeCollation {
+ db2, err = sql.Open("mysql", dsn2)
+ if err != nil {
+ t.Fatalf("error connecting: %s", err.Error())
+ }
+ defer db2.Close()
+ }
+
+ dsn3 := dsn + "&multiStatements=true"
+ var db3 *sql.DB
+ if _, err := ParseDSN(dsn3); err != errInvalidDSNUnsafeCollation {
+ db3, err = sql.Open("mysql", dsn3)
+ if err != nil {
+ t.Fatalf("error connecting: %s", err.Error())
+ }
+ defer db3.Close()
+ }
+
+ dbt := &DBTest{t, db}
+ dbt2 := &DBTest{t, db2}
+ dbt3 := &DBTest{t, db3}
+ for _, test := range tests {
+ test(dbt)
+ dbt.db.Exec("DROP TABLE IF EXISTS test")
+ if db2 != nil {
+ test(dbt2)
+ dbt2.db.Exec("DROP TABLE IF EXISTS test")
+ }
+ if db3 != nil {
+ test(dbt3)
+ dbt3.db.Exec("DROP TABLE IF EXISTS test")
+ }
+ }
+}
+
+func (dbt *DBTest) fail(method, query string, err error) {
+ if len(query) > 300 {
+ query = "[query too large to print]"
+ }
+ dbt.Fatalf("error on %s %s: %s", method, query, err.Error())
+}
+
+func (dbt *DBTest) mustExec(query string, args ...interface{}) (res sql.Result) {
+ res, err := dbt.db.Exec(query, args...)
+ if err != nil {
+ dbt.fail("exec", query, err)
+ }
+ return res
+}
+
+func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows) {
+ rows, err := dbt.db.Query(query, args...)
+ if err != nil {
+ dbt.fail("query", query, err)
+ }
+ return rows
+}
+
+func TestEmptyQuery(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ // just a comment, no query
+ rows := dbt.mustQuery("--")
+ // will hang before #255
+ if rows.Next() {
+ dbt.Errorf("next on rows must be false")
+ }
+ })
+}
+
+func TestCRUD(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ // Create Table
+ dbt.mustExec("CREATE TABLE test (value BOOL)")
+
+ // Test for unexpected data
+ var out bool
+ rows := dbt.mustQuery("SELECT * FROM test")
+ if rows.Next() {
+ dbt.Error("unexpected data in empty table")
+ }
+
+ // Create Data
+ res := dbt.mustExec("INSERT INTO test VALUES (1)")
+ count, err := res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 1 {
+ dbt.Fatalf("expected 1 affected row, got %d", count)
+ }
+
+ id, err := res.LastInsertId()
+ if err != nil {
+ dbt.Fatalf("res.LastInsertId() returned error: %s", err.Error())
+ }
+ if id != 0 {
+ dbt.Fatalf("expected InsertId 0, got %d", id)
+ }
+
+ // Read
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if true != out {
+ dbt.Errorf("true != %t", out)
+ }
+
+ if rows.Next() {
+ dbt.Error("unexpected data")
+ }
+ } else {
+ dbt.Error("no data")
+ }
+
+ // Update
+ res = dbt.mustExec("UPDATE test SET value = ? WHERE value = ?", false, true)
+ count, err = res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 1 {
+ dbt.Fatalf("expected 1 affected row, got %d", count)
+ }
+
+ // Check Update
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if false != out {
+ dbt.Errorf("false != %t", out)
+ }
+
+ if rows.Next() {
+ dbt.Error("unexpected data")
+ }
+ } else {
+ dbt.Error("no data")
+ }
+
+ // Delete
+ res = dbt.mustExec("DELETE FROM test WHERE value = ?", false)
+ count, err = res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 1 {
+ dbt.Fatalf("expected 1 affected row, got %d", count)
+ }
+
+ // Check for unexpected rows
+ res = dbt.mustExec("DELETE FROM test")
+ count, err = res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 0 {
+ dbt.Fatalf("expected 0 affected row, got %d", count)
+ }
+ })
+}
+
+func TestMultiQuery(t *testing.T) {
+ runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) {
+ // Create Table
+ dbt.mustExec("CREATE TABLE `test` (`id` int(11) NOT NULL, `value` int(11) NOT NULL) ")
+
+ // Create Data
+ res := dbt.mustExec("INSERT INTO test VALUES (1, 1)")
+ count, err := res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 1 {
+ dbt.Fatalf("expected 1 affected row, got %d", count)
+ }
+
+ // Update
+ res = dbt.mustExec("UPDATE test SET value = 3 WHERE id = 1; UPDATE test SET value = 4 WHERE id = 1; UPDATE test SET value = 5 WHERE id = 1;")
+ count, err = res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 1 {
+ dbt.Fatalf("expected 1 affected row, got %d", count)
+ }
+
+ // Read
+ var out int
+ rows := dbt.mustQuery("SELECT value FROM test WHERE id=1;")
+ if rows.Next() {
+ rows.Scan(&out)
+ if 5 != out {
+ dbt.Errorf("5 != %d", out)
+ }
+
+ if rows.Next() {
+ dbt.Error("unexpected data")
+ }
+ } else {
+ dbt.Error("no data")
+ }
+
+ })
+}
+
+func TestInt(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ types := [5]string{"TINYINT", "SMALLINT", "MEDIUMINT", "INT", "BIGINT"}
+ in := int64(42)
+ var out int64
+ var rows *sql.Rows
+
+ // SIGNED
+ for _, v := range types {
+ dbt.mustExec("CREATE TABLE test (value " + v + ")")
+
+ dbt.mustExec("INSERT INTO test VALUES (?)", in)
+
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if in != out {
+ dbt.Errorf("%s: %d != %d", v, in, out)
+ }
+ } else {
+ dbt.Errorf("%s: no data", v)
+ }
+
+ dbt.mustExec("DROP TABLE IF EXISTS test")
+ }
+
+ // UNSIGNED ZEROFILL
+ for _, v := range types {
+ dbt.mustExec("CREATE TABLE test (value " + v + " ZEROFILL)")
+
+ dbt.mustExec("INSERT INTO test VALUES (?)", in)
+
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if in != out {
+ dbt.Errorf("%s ZEROFILL: %d != %d", v, in, out)
+ }
+ } else {
+ dbt.Errorf("%s ZEROFILL: no data", v)
+ }
+
+ dbt.mustExec("DROP TABLE IF EXISTS test")
+ }
+ })
+}
+
+func TestFloat32(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ types := [2]string{"FLOAT", "DOUBLE"}
+ in := float32(42.23)
+ var out float32
+ var rows *sql.Rows
+ for _, v := range types {
+ dbt.mustExec("CREATE TABLE test (value " + v + ")")
+ dbt.mustExec("INSERT INTO test VALUES (?)", in)
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if in != out {
+ dbt.Errorf("%s: %g != %g", v, in, out)
+ }
+ } else {
+ dbt.Errorf("%s: no data", v)
+ }
+ dbt.mustExec("DROP TABLE IF EXISTS test")
+ }
+ })
+}
+
+func TestFloat64(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ types := [2]string{"FLOAT", "DOUBLE"}
+ var expected float64 = 42.23
+ var out float64
+ var rows *sql.Rows
+ for _, v := range types {
+ dbt.mustExec("CREATE TABLE test (value " + v + ")")
+ dbt.mustExec("INSERT INTO test VALUES (42.23)")
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if expected != out {
+ dbt.Errorf("%s: %g != %g", v, expected, out)
+ }
+ } else {
+ dbt.Errorf("%s: no data", v)
+ }
+ dbt.mustExec("DROP TABLE IF EXISTS test")
+ }
+ })
+}
+
+func TestFloat64Placeholder(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ types := [2]string{"FLOAT", "DOUBLE"}
+ var expected float64 = 42.23
+ var out float64
+ var rows *sql.Rows
+ for _, v := range types {
+ dbt.mustExec("CREATE TABLE test (id int, value " + v + ")")
+ dbt.mustExec("INSERT INTO test VALUES (1, 42.23)")
+ rows = dbt.mustQuery("SELECT value FROM test WHERE id = ?", 1)
+ if rows.Next() {
+ rows.Scan(&out)
+ if expected != out {
+ dbt.Errorf("%s: %g != %g", v, expected, out)
+ }
+ } else {
+ dbt.Errorf("%s: no data", v)
+ }
+ dbt.mustExec("DROP TABLE IF EXISTS test")
+ }
+ })
+}
+
+func TestString(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ types := [6]string{"CHAR(255)", "VARCHAR(255)", "TINYTEXT", "TEXT", "MEDIUMTEXT", "LONGTEXT"}
+ in := "κόσμε üöäßñóùéàâÿœ'îë Árvíztűrő いろはにほへとちりぬるを イロハニホヘト דג סקרן чащах น่าฟังเอย"
+ var out string
+ var rows *sql.Rows
+
+ for _, v := range types {
+ dbt.mustExec("CREATE TABLE test (value " + v + ") CHARACTER SET utf8")
+
+ dbt.mustExec("INSERT INTO test VALUES (?)", in)
+
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if in != out {
+ dbt.Errorf("%s: %s != %s", v, in, out)
+ }
+ } else {
+ dbt.Errorf("%s: no data", v)
+ }
+
+ dbt.mustExec("DROP TABLE IF EXISTS test")
+ }
+
+ // BLOB
+ dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8")
+
+ id := 2
+ in = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " +
+ "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " +
+ "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " +
+ "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. " +
+ "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, " +
+ "sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, " +
+ "sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. " +
+ "Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+ dbt.mustExec("INSERT INTO test VALUES (?, ?)", id, in)
+
+ err := dbt.db.QueryRow("SELECT value FROM test WHERE id = ?", id).Scan(&out)
+ if err != nil {
+ dbt.Fatalf("Error on BLOB-Query: %s", err.Error())
+ } else if out != in {
+ dbt.Errorf("BLOB: %s != %s", in, out)
+ }
+ })
+}
+
+type timeTests struct {
+ dbtype string
+ tlayout string
+ tests []timeTest
+}
+
+type timeTest struct {
+ s string // leading "!": do not use t as value in queries
+ t time.Time
+}
+
+type timeMode byte
+
+func (t timeMode) String() string {
+ switch t {
+ case binaryString:
+ return "binary:string"
+ case binaryTime:
+ return "binary:time.Time"
+ case textString:
+ return "text:string"
+ }
+ panic("unsupported timeMode")
+}
+
+func (t timeMode) Binary() bool {
+ switch t {
+ case binaryString, binaryTime:
+ return true
+ }
+ return false
+}
+
+const (
+ binaryString timeMode = iota
+ binaryTime
+ textString
+)
+
+func (t timeTest) genQuery(dbtype string, mode timeMode) string {
+ var inner string
+ if mode.Binary() {
+ inner = "?"
+ } else {
+ inner = `"%s"`
+ }
+ return `SELECT cast(` + inner + ` as ` + dbtype + `)`
+}
+
+func (t timeTest) run(dbt *DBTest, dbtype, tlayout string, mode timeMode) {
+ var rows *sql.Rows
+ query := t.genQuery(dbtype, mode)
+ switch mode {
+ case binaryString:
+ rows = dbt.mustQuery(query, t.s)
+ case binaryTime:
+ rows = dbt.mustQuery(query, t.t)
+ case textString:
+ query = fmt.Sprintf(query, t.s)
+ rows = dbt.mustQuery(query)
+ default:
+ panic("unsupported mode")
+ }
+ defer rows.Close()
+ var err error
+ if !rows.Next() {
+ err = rows.Err()
+ if err == nil {
+ err = fmt.Errorf("no data")
+ }
+ dbt.Errorf("%s [%s]: %s", dbtype, mode, err)
+ return
+ }
+ var dst interface{}
+ err = rows.Scan(&dst)
+ if err != nil {
+ dbt.Errorf("%s [%s]: %s", dbtype, mode, err)
+ return
+ }
+ switch val := dst.(type) {
+ case []uint8:
+ str := string(val)
+ if str == t.s {
+ return
+ }
+ if mode.Binary() && dbtype == "DATETIME" && len(str) == 26 && str[:19] == t.s {
+ // a fix mainly for TravisCI:
+ // accept full microsecond resolution in result for DATETIME columns
+ // where the binary protocol was used
+ return
+ }
+ dbt.Errorf("%s [%s] to string: expected %q, got %q",
+ dbtype, mode,
+ t.s, str,
+ )
+ case time.Time:
+ if val == t.t {
+ return
+ }
+ dbt.Errorf("%s [%s] to string: expected %q, got %q",
+ dbtype, mode,
+ t.s, val.Format(tlayout),
+ )
+ default:
+ fmt.Printf("%#v\n", []interface{}{dbtype, tlayout, mode, t.s, t.t})
+ dbt.Errorf("%s [%s]: unhandled type %T (is '%v')",
+ dbtype, mode,
+ val, val,
+ )
+ }
+}
+
+func TestDateTime(t *testing.T) {
+ afterTime := func(t time.Time, d string) time.Time {
+ dur, err := time.ParseDuration(d)
+ if err != nil {
+ panic(err)
+ }
+ return t.Add(dur)
+ }
+ // NOTE: MySQL rounds DATETIME(x) up - but that's not included in the tests
+ format := "2006-01-02 15:04:05.999999"
+ t0 := time.Time{}
+ tstr0 := "0000-00-00 00:00:00.000000"
+ testcases := []timeTests{
+ {"DATE", format[:10], []timeTest{
+ {t: time.Date(2011, 11, 20, 0, 0, 0, 0, time.UTC)},
+ {t: t0, s: tstr0[:10]},
+ }},
+ {"DATETIME", format[:19], []timeTest{
+ {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)},
+ {t: t0, s: tstr0[:19]},
+ }},
+ {"DATETIME(0)", format[:21], []timeTest{
+ {t: time.Date(2011, 11, 20, 21, 27, 37, 0, time.UTC)},
+ {t: t0, s: tstr0[:19]},
+ }},
+ {"DATETIME(1)", format[:21], []timeTest{
+ {t: time.Date(2011, 11, 20, 21, 27, 37, 100000000, time.UTC)},
+ {t: t0, s: tstr0[:21]},
+ }},
+ {"DATETIME(6)", format, []timeTest{
+ {t: time.Date(2011, 11, 20, 21, 27, 37, 123456000, time.UTC)},
+ {t: t0, s: tstr0},
+ }},
+ {"TIME", format[11:19], []timeTest{
+ {t: afterTime(t0, "12345s")},
+ {s: "!-12:34:56"},
+ {s: "!-838:59:59"},
+ {s: "!838:59:59"},
+ {t: t0, s: tstr0[11:19]},
+ }},
+ {"TIME(0)", format[11:19], []timeTest{
+ {t: afterTime(t0, "12345s")},
+ {s: "!-12:34:56"},
+ {s: "!-838:59:59"},
+ {s: "!838:59:59"},
+ {t: t0, s: tstr0[11:19]},
+ }},
+ {"TIME(1)", format[11:21], []timeTest{
+ {t: afterTime(t0, "12345600ms")},
+ {s: "!-12:34:56.7"},
+ {s: "!-838:59:58.9"},
+ {s: "!838:59:58.9"},
+ {t: t0, s: tstr0[11:21]},
+ }},
+ {"TIME(6)", format[11:], []timeTest{
+ {t: afterTime(t0, "1234567890123000ns")},
+ {s: "!-12:34:56.789012"},
+ {s: "!-838:59:58.999999"},
+ {s: "!838:59:58.999999"},
+ {t: t0, s: tstr0[11:]},
+ }},
+ }
+ dsns := []string{
+ dsn + "&parseTime=true",
+ dsn + "&parseTime=false",
+ }
+ for _, testdsn := range dsns {
+ runTests(t, testdsn, func(dbt *DBTest) {
+ microsecsSupported := false
+ zeroDateSupported := false
+ var rows *sql.Rows
+ var err error
+ rows, err = dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`)
+ if err == nil {
+ rows.Scan(&microsecsSupported)
+ rows.Close()
+ }
+ rows, err = dbt.db.Query(`SELECT cast("0000-00-00" as DATE) = "0000-00-00"`)
+ if err == nil {
+ rows.Scan(&zeroDateSupported)
+ rows.Close()
+ }
+ for _, setups := range testcases {
+ if t := setups.dbtype; !microsecsSupported && t[len(t)-1:] == ")" {
+ // skip fractional second tests if unsupported by server
+ continue
+ }
+ for _, setup := range setups.tests {
+ allowBinTime := true
+ if setup.s == "" {
+ // fill time string whereever Go can reliable produce it
+ setup.s = setup.t.Format(setups.tlayout)
+ } else if setup.s[0] == '!' {
+ // skip tests using setup.t as source in queries
+ allowBinTime = false
+ // fix setup.s - remove the "!"
+ setup.s = setup.s[1:]
+ }
+ if !zeroDateSupported && setup.s == tstr0[:len(setup.s)] {
+ // skip disallowed 0000-00-00 date
+ continue
+ }
+ setup.run(dbt, setups.dbtype, setups.tlayout, textString)
+ setup.run(dbt, setups.dbtype, setups.tlayout, binaryString)
+ if allowBinTime {
+ setup.run(dbt, setups.dbtype, setups.tlayout, binaryTime)
+ }
+ }
+ }
+ })
+ }
+}
+
+func TestTimestampMicros(t *testing.T) {
+ format := "2006-01-02 15:04:05.999999"
+ f0 := format[:19]
+ f1 := format[:21]
+ f6 := format[:26]
+ runTests(t, dsn, func(dbt *DBTest) {
+ // check if microseconds are supported.
+ // Do not use timestamp(x) for that check - before 5.5.6, x would mean display width
+ // and not precision.
+ // Se last paragraph at http://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html
+ microsecsSupported := false
+ if rows, err := dbt.db.Query(`SELECT cast("00:00:00.1" as TIME(1)) = "00:00:00.1"`); err == nil {
+ rows.Scan(&microsecsSupported)
+ rows.Close()
+ }
+ if !microsecsSupported {
+ // skip test
+ return
+ }
+ _, err := dbt.db.Exec(`
+ CREATE TABLE test (
+ value0 TIMESTAMP NOT NULL DEFAULT '` + f0 + `',
+ value1 TIMESTAMP(1) NOT NULL DEFAULT '` + f1 + `',
+ value6 TIMESTAMP(6) NOT NULL DEFAULT '` + f6 + `'
+ )`,
+ )
+ if err != nil {
+ dbt.Error(err)
+ }
+ defer dbt.mustExec("DROP TABLE IF EXISTS test")
+ dbt.mustExec("INSERT INTO test SET value0=?, value1=?, value6=?", f0, f1, f6)
+ var res0, res1, res6 string
+ rows := dbt.mustQuery("SELECT * FROM test")
+ if !rows.Next() {
+ dbt.Errorf("test contained no selectable values")
+ }
+ err = rows.Scan(&res0, &res1, &res6)
+ if err != nil {
+ dbt.Error(err)
+ }
+ if res0 != f0 {
+ dbt.Errorf("expected %q, got %q", f0, res0)
+ }
+ if res1 != f1 {
+ dbt.Errorf("expected %q, got %q", f1, res1)
+ }
+ if res6 != f6 {
+ dbt.Errorf("expected %q, got %q", f6, res6)
+ }
+ })
+}
+
+func TestNULL(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ nullStmt, err := dbt.db.Prepare("SELECT NULL")
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ defer nullStmt.Close()
+
+ nonNullStmt, err := dbt.db.Prepare("SELECT 1")
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ defer nonNullStmt.Close()
+
+ // NullBool
+ var nb sql.NullBool
+ // Invalid
+ if err = nullStmt.QueryRow().Scan(&nb); err != nil {
+ dbt.Fatal(err)
+ }
+ if nb.Valid {
+ dbt.Error("valid NullBool which should be invalid")
+ }
+ // Valid
+ if err = nonNullStmt.QueryRow().Scan(&nb); err != nil {
+ dbt.Fatal(err)
+ }
+ if !nb.Valid {
+ dbt.Error("invalid NullBool which should be valid")
+ } else if nb.Bool != true {
+ dbt.Errorf("Unexpected NullBool value: %t (should be true)", nb.Bool)
+ }
+
+ // NullFloat64
+ var nf sql.NullFloat64
+ // Invalid
+ if err = nullStmt.QueryRow().Scan(&nf); err != nil {
+ dbt.Fatal(err)
+ }
+ if nf.Valid {
+ dbt.Error("valid NullFloat64 which should be invalid")
+ }
+ // Valid
+ if err = nonNullStmt.QueryRow().Scan(&nf); err != nil {
+ dbt.Fatal(err)
+ }
+ if !nf.Valid {
+ dbt.Error("invalid NullFloat64 which should be valid")
+ } else if nf.Float64 != float64(1) {
+ dbt.Errorf("unexpected NullFloat64 value: %f (should be 1.0)", nf.Float64)
+ }
+
+ // NullInt64
+ var ni sql.NullInt64
+ // Invalid
+ if err = nullStmt.QueryRow().Scan(&ni); err != nil {
+ dbt.Fatal(err)
+ }
+ if ni.Valid {
+ dbt.Error("valid NullInt64 which should be invalid")
+ }
+ // Valid
+ if err = nonNullStmt.QueryRow().Scan(&ni); err != nil {
+ dbt.Fatal(err)
+ }
+ if !ni.Valid {
+ dbt.Error("invalid NullInt64 which should be valid")
+ } else if ni.Int64 != int64(1) {
+ dbt.Errorf("unexpected NullInt64 value: %d (should be 1)", ni.Int64)
+ }
+
+ // NullString
+ var ns sql.NullString
+ // Invalid
+ if err = nullStmt.QueryRow().Scan(&ns); err != nil {
+ dbt.Fatal(err)
+ }
+ if ns.Valid {
+ dbt.Error("valid NullString which should be invalid")
+ }
+ // Valid
+ if err = nonNullStmt.QueryRow().Scan(&ns); err != nil {
+ dbt.Fatal(err)
+ }
+ if !ns.Valid {
+ dbt.Error("invalid NullString which should be valid")
+ } else if ns.String != `1` {
+ dbt.Error("unexpected NullString value:" + ns.String + " (should be `1`)")
+ }
+
+ // nil-bytes
+ var b []byte
+ // Read nil
+ if err = nullStmt.QueryRow().Scan(&b); err != nil {
+ dbt.Fatal(err)
+ }
+ if b != nil {
+ dbt.Error("non-nil []byte wich should be nil")
+ }
+ // Read non-nil
+ if err = nonNullStmt.QueryRow().Scan(&b); err != nil {
+ dbt.Fatal(err)
+ }
+ if b == nil {
+ dbt.Error("nil []byte wich should be non-nil")
+ }
+ // Insert nil
+ b = nil
+ success := false
+ if err = dbt.db.QueryRow("SELECT ? IS NULL", b).Scan(&success); err != nil {
+ dbt.Fatal(err)
+ }
+ if !success {
+ dbt.Error("inserting []byte(nil) as NULL failed")
+ }
+ // Check input==output with input==nil
+ b = nil
+ if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil {
+ dbt.Fatal(err)
+ }
+ if b != nil {
+ dbt.Error("non-nil echo from nil input")
+ }
+ // Check input==output with input!=nil
+ b = []byte("")
+ if err = dbt.db.QueryRow("SELECT ?", b).Scan(&b); err != nil {
+ dbt.Fatal(err)
+ }
+ if b == nil {
+ dbt.Error("nil echo from non-nil input")
+ }
+
+ // Insert NULL
+ dbt.mustExec("CREATE TABLE test (dummmy1 int, value int, dummy2 int)")
+
+ dbt.mustExec("INSERT INTO test VALUES (?, ?, ?)", 1, nil, 2)
+
+ var out interface{}
+ rows := dbt.mustQuery("SELECT * FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if out != nil {
+ dbt.Errorf("%v != nil", out)
+ }
+ } else {
+ dbt.Error("no data")
+ }
+ })
+}
+
+func TestUint64(t *testing.T) {
+ const (
+ u0 = uint64(0)
+ uall = ^u0
+ uhigh = uall >> 1
+ utop = ^uhigh
+ s0 = int64(0)
+ sall = ^s0
+ shigh = int64(uhigh)
+ stop = ^shigh
+ )
+ runTests(t, dsn, func(dbt *DBTest) {
+ stmt, err := dbt.db.Prepare(`SELECT ?, ?, ? ,?, ?, ?, ?, ?`)
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ defer stmt.Close()
+ row := stmt.QueryRow(
+ u0, uhigh, utop, uall,
+ s0, shigh, stop, sall,
+ )
+
+ var ua, ub, uc, ud uint64
+ var sa, sb, sc, sd int64
+
+ err = row.Scan(&ua, &ub, &uc, &ud, &sa, &sb, &sc, &sd)
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ switch {
+ case ua != u0,
+ ub != uhigh,
+ uc != utop,
+ ud != uall,
+ sa != s0,
+ sb != shigh,
+ sc != stop,
+ sd != sall:
+ dbt.Fatal("unexpected result value")
+ }
+ })
+}
+
+func TestLongData(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ var maxAllowedPacketSize int
+ err := dbt.db.QueryRow("select @@max_allowed_packet").Scan(&maxAllowedPacketSize)
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ maxAllowedPacketSize--
+
+ // don't get too ambitious
+ if maxAllowedPacketSize > 1<<25 {
+ maxAllowedPacketSize = 1 << 25
+ }
+
+ dbt.mustExec("CREATE TABLE test (value LONGBLOB)")
+
+ in := strings.Repeat(`a`, maxAllowedPacketSize+1)
+ var out string
+ var rows *sql.Rows
+
+ // Long text data
+ const nonDataQueryLen = 28 // length query w/o value
+ inS := in[:maxAllowedPacketSize-nonDataQueryLen]
+ dbt.mustExec("INSERT INTO test VALUES('" + inS + "')")
+ rows = dbt.mustQuery("SELECT value FROM test")
+ if rows.Next() {
+ rows.Scan(&out)
+ if inS != out {
+ dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(inS), len(out))
+ }
+ if rows.Next() {
+ dbt.Error("LONGBLOB: unexpexted row")
+ }
+ } else {
+ dbt.Fatalf("LONGBLOB: no data")
+ }
+
+ // Empty table
+ dbt.mustExec("TRUNCATE TABLE test")
+
+ // Long binary data
+ dbt.mustExec("INSERT INTO test VALUES(?)", in)
+ rows = dbt.mustQuery("SELECT value FROM test WHERE 1=?", 1)
+ if rows.Next() {
+ rows.Scan(&out)
+ if in != out {
+ dbt.Fatalf("LONGBLOB: length in: %d, length out: %d", len(in), len(out))
+ }
+ if rows.Next() {
+ dbt.Error("LONGBLOB: unexpexted row")
+ }
+ } else {
+ if err = rows.Err(); err != nil {
+ dbt.Fatalf("LONGBLOB: no data (err: %s)", err.Error())
+ } else {
+ dbt.Fatal("LONGBLOB: no data (err: <nil>)")
+ }
+ }
+ })
+}
+
+func TestLoadData(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ verifyLoadDataResult := func() {
+ rows, err := dbt.db.Query("SELECT * FROM test")
+ if err != nil {
+ dbt.Fatal(err.Error())
+ }
+
+ i := 0
+ values := [4]string{
+ "a string",
+ "a string containing a \t",
+ "a string containing a \n",
+ "a string containing both \t\n",
+ }
+
+ var id int
+ var value string
+
+ for rows.Next() {
+ i++
+ err = rows.Scan(&id, &value)
+ if err != nil {
+ dbt.Fatal(err.Error())
+ }
+ if i != id {
+ dbt.Fatalf("%d != %d", i, id)
+ }
+ if values[i-1] != value {
+ dbt.Fatalf("%q != %q", values[i-1], value)
+ }
+ }
+ err = rows.Err()
+ if err != nil {
+ dbt.Fatal(err.Error())
+ }
+
+ if i != 4 {
+ dbt.Fatalf("rows count mismatch. Got %d, want 4", i)
+ }
+ }
+ file, err := ioutil.TempFile("", "gotest")
+ defer os.Remove(file.Name())
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n")
+ file.Close()
+
+ dbt.db.Exec("DROP TABLE IF EXISTS test")
+ dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8")
+
+ // Local File
+ RegisterLocalFile(file.Name())
+ dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name()))
+ verifyLoadDataResult()
+ // negative test
+ _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'doesnotexist' INTO TABLE test")
+ if err == nil {
+ dbt.Fatal("load non-existent file didn't fail")
+ } else if err.Error() != "local file 'doesnotexist' is not registered" {
+ dbt.Fatal(err.Error())
+ }
+
+ // Empty table
+ dbt.mustExec("TRUNCATE TABLE test")
+
+ // Reader
+ RegisterReaderHandler("test", func() io.Reader {
+ file, err = os.Open(file.Name())
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ return file
+ })
+ dbt.mustExec("LOAD DATA LOCAL INFILE 'Reader::test' INTO TABLE test")
+ verifyLoadDataResult()
+ // negative test
+ _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'Reader::doesnotexist' INTO TABLE test")
+ if err == nil {
+ dbt.Fatal("load non-existent Reader didn't fail")
+ } else if err.Error() != "Reader 'doesnotexist' is not registered" {
+ dbt.Fatal(err.Error())
+ }
+ })
+}
+
+func TestFoundRows(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)")
+ dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)")
+
+ res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0")
+ count, err := res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 2 {
+ dbt.Fatalf("Expected 2 affected rows, got %d", count)
+ }
+ res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1")
+ count, err = res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 2 {
+ dbt.Fatalf("Expected 2 affected rows, got %d", count)
+ }
+ })
+ runTests(t, dsn+"&clientFoundRows=true", func(dbt *DBTest) {
+ dbt.mustExec("CREATE TABLE test (id INT NOT NULL ,data INT NOT NULL)")
+ dbt.mustExec("INSERT INTO test (id, data) VALUES (0, 0),(0, 0),(1, 0),(1, 0),(1, 1)")
+
+ res := dbt.mustExec("UPDATE test SET data = 1 WHERE id = 0")
+ count, err := res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 2 {
+ dbt.Fatalf("Expected 2 matched rows, got %d", count)
+ }
+ res = dbt.mustExec("UPDATE test SET data = 1 WHERE id = 1")
+ count, err = res.RowsAffected()
+ if err != nil {
+ dbt.Fatalf("res.RowsAffected() returned error: %s", err.Error())
+ }
+ if count != 3 {
+ dbt.Fatalf("Expected 3 matched rows, got %d", count)
+ }
+ })
+}
+
+func TestStrict(t *testing.T) {
+ // ALLOW_INVALID_DATES to get rid of stricter modes - we want to test for warnings, not errors
+ relaxedDsn := dsn + "&sql_mode='ALLOW_INVALID_DATES,NO_AUTO_CREATE_USER'"
+ // make sure the MySQL version is recent enough with a separate connection
+ // before running the test
+ conn, err := MySQLDriver{}.Open(relaxedDsn)
+ if conn != nil {
+ conn.Close()
+ }
+ if me, ok := err.(*MySQLError); ok && me.Number == 1231 {
+ // Error 1231: Variable 'sql_mode' can't be set to the value of 'ALLOW_INVALID_DATES'
+ // => skip test, MySQL server version is too old
+ return
+ }
+ runTests(t, relaxedDsn, func(dbt *DBTest) {
+ dbt.mustExec("CREATE TABLE test (a TINYINT NOT NULL, b CHAR(4))")
+
+ var queries = [...]struct {
+ in string
+ codes []string
+ }{
+ {"DROP TABLE IF EXISTS no_such_table", []string{"1051"}},
+ {"INSERT INTO test VALUES(10,'mysql'),(NULL,'test'),(300,'Open Source')", []string{"1265", "1048", "1264", "1265"}},
+ }
+ var err error
+
+ var checkWarnings = func(err error, mode string, idx int) {
+ if err == nil {
+ dbt.Errorf("expected STRICT error on query [%s] %s", mode, queries[idx].in)
+ }
+
+ if warnings, ok := err.(MySQLWarnings); ok {
+ var codes = make([]string, len(warnings))
+ for i := range warnings {
+ codes[i] = warnings[i].Code
+ }
+ if len(codes) != len(queries[idx].codes) {
+ dbt.Errorf("unexpected STRICT error count on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
+ }
+
+ for i := range warnings {
+ if codes[i] != queries[idx].codes[i] {
+ dbt.Errorf("unexpected STRICT error codes on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes)
+ return
+ }
+ }
+
+ } else {
+ dbt.Errorf("unexpected error on query [%s] %s: %s", mode, queries[idx].in, err.Error())
+ }
+ }
+
+ // text protocol
+ for i := range queries {
+ _, err = dbt.db.Exec(queries[i].in)
+ checkWarnings(err, "text", i)
+ }
+
+ var stmt *sql.Stmt
+
+ // binary protocol
+ for i := range queries {
+ stmt, err = dbt.db.Prepare(queries[i].in)
+ if err != nil {
+ dbt.Errorf("error on preparing query %s: %s", queries[i].in, err.Error())
+ }
+
+ _, err = stmt.Exec()
+ checkWarnings(err, "binary", i)
+
+ err = stmt.Close()
+ if err != nil {
+ dbt.Errorf("error on closing stmt for query %s: %s", queries[i].in, err.Error())
+ }
+ }
+ })
+}
+
+func TestTLS(t *testing.T) {
+ tlsTest := func(dbt *DBTest) {
+ if err := dbt.db.Ping(); err != nil {
+ if err == ErrNoTLS {
+ dbt.Skip("server does not support TLS")
+ } else {
+ dbt.Fatalf("error on Ping: %s", err.Error())
+ }
+ }
+
+ rows := dbt.mustQuery("SHOW STATUS LIKE 'Ssl_cipher'")
+
+ var variable, value *sql.RawBytes
+ for rows.Next() {
+ if err := rows.Scan(&variable, &value); err != nil {
+ dbt.Fatal(err.Error())
+ }
+
+ if value == nil {
+ dbt.Fatal("no Cipher")
+ }
+ }
+ }
+
+ runTests(t, dsn+"&tls=skip-verify", tlsTest)
+
+ // Verify that registering / using a custom cfg works
+ RegisterTLSConfig("custom-skip-verify", &tls.Config{
+ InsecureSkipVerify: true,
+ })
+ runTests(t, dsn+"&tls=custom-skip-verify", tlsTest)
+}
+
+func TestReuseClosedConnection(t *testing.T) {
+ // this test does not use sql.database, it uses the driver directly
+ if !available {
+ t.Skipf("MySQL server not running on %s", netAddr)
+ }
+
+ md := &MySQLDriver{}
+ conn, err := md.Open(dsn)
+ if err != nil {
+ t.Fatalf("error connecting: %s", err.Error())
+ }
+ stmt, err := conn.Prepare("DO 1")
+ if err != nil {
+ t.Fatalf("error preparing statement: %s", err.Error())
+ }
+ _, err = stmt.Exec(nil)
+ if err != nil {
+ t.Fatalf("error executing statement: %s", err.Error())
+ }
+ err = conn.Close()
+ if err != nil {
+ t.Fatalf("error closing connection: %s", err.Error())
+ }
+
+ defer func() {
+ if err := recover(); err != nil {
+ t.Errorf("panic after reusing a closed connection: %v", err)
+ }
+ }()
+ _, err = stmt.Exec(nil)
+ if err != nil && err != driver.ErrBadConn {
+ t.Errorf("unexpected error '%s', expected '%s'",
+ err.Error(), driver.ErrBadConn.Error())
+ }
+}
+
+func TestCharset(t *testing.T) {
+ if !available {
+ t.Skipf("MySQL server not running on %s", netAddr)
+ }
+
+ mustSetCharset := func(charsetParam, expected string) {
+ runTests(t, dsn+"&"+charsetParam, func(dbt *DBTest) {
+ rows := dbt.mustQuery("SELECT @@character_set_connection")
+ defer rows.Close()
+
+ if !rows.Next() {
+ dbt.Fatalf("error getting connection charset: %s", rows.Err())
+ }
+
+ var got string
+ rows.Scan(&got)
+
+ if got != expected {
+ dbt.Fatalf("expected connection charset %s but got %s", expected, got)
+ }
+ })
+ }
+
+ // non utf8 test
+ mustSetCharset("charset=ascii", "ascii")
+
+ // when the first charset is invalid, use the second
+ mustSetCharset("charset=none,utf8", "utf8")
+
+ // when the first charset is valid, use it
+ mustSetCharset("charset=ascii,utf8", "ascii")
+ mustSetCharset("charset=utf8,ascii", "utf8")
+}
+
+func TestFailingCharset(t *testing.T) {
+ runTests(t, dsn+"&charset=none", func(dbt *DBTest) {
+ // run query to really establish connection...
+ _, err := dbt.db.Exec("SELECT 1")
+ if err == nil {
+ dbt.db.Close()
+ t.Fatalf("connection must not succeed without a valid charset")
+ }
+ })
+}
+
+func TestCollation(t *testing.T) {
+ if !available {
+ t.Skipf("MySQL server not running on %s", netAddr)
+ }
+
+ defaultCollation := "utf8_general_ci"
+ testCollations := []string{
+ "", // do not set
+ defaultCollation, // driver default
+ "latin1_general_ci",
+ "binary",
+ "utf8_unicode_ci",
+ "cp1257_bin",
+ }
+
+ for _, collation := range testCollations {
+ var expected, tdsn string
+ if collation != "" {
+ tdsn = dsn + "&collation=" + collation
+ expected = collation
+ } else {
+ tdsn = dsn
+ expected = defaultCollation
+ }
+
+ runTests(t, tdsn, func(dbt *DBTest) {
+ var got string
+ if err := dbt.db.QueryRow("SELECT @@collation_connection").Scan(&got); err != nil {
+ dbt.Fatal(err)
+ }
+
+ if got != expected {
+ dbt.Fatalf("expected connection collation %s but got %s", expected, got)
+ }
+ })
+ }
+}
+
+func TestColumnsWithAlias(t *testing.T) {
+ runTests(t, dsn+"&columnsWithAlias=true", func(dbt *DBTest) {
+ rows := dbt.mustQuery("SELECT 1 AS A")
+ defer rows.Close()
+ cols, _ := rows.Columns()
+ if len(cols) != 1 {
+ t.Fatalf("expected 1 column, got %d", len(cols))
+ }
+ if cols[0] != "A" {
+ t.Fatalf("expected column name \"A\", got \"%s\"", cols[0])
+ }
+ rows.Close()
+
+ rows = dbt.mustQuery("SELECT * FROM (SELECT 1 AS one) AS A")
+ cols, _ = rows.Columns()
+ if len(cols) != 1 {
+ t.Fatalf("expected 1 column, got %d", len(cols))
+ }
+ if cols[0] != "A.one" {
+ t.Fatalf("expected column name \"A.one\", got \"%s\"", cols[0])
+ }
+ })
+}
+
+func TestRawBytesResultExceedsBuffer(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ // defaultBufSize from buffer.go
+ expected := strings.Repeat("abc", defaultBufSize)
+
+ rows := dbt.mustQuery("SELECT '" + expected + "'")
+ defer rows.Close()
+ if !rows.Next() {
+ dbt.Error("expected result, got none")
+ }
+ var result sql.RawBytes
+ rows.Scan(&result)
+ if expected != string(result) {
+ dbt.Error("result did not match expected value")
+ }
+ })
+}
+
+func TestTimezoneConversion(t *testing.T) {
+ zones := []string{"UTC", "US/Central", "US/Pacific", "Local"}
+
+ // Regression test for timezone handling
+ tzTest := func(dbt *DBTest) {
+
+ // Create table
+ dbt.mustExec("CREATE TABLE test (ts TIMESTAMP)")
+
+ // Insert local time into database (should be converted)
+ usCentral, _ := time.LoadLocation("US/Central")
+ reftime := time.Date(2014, 05, 30, 18, 03, 17, 0, time.UTC).In(usCentral)
+ dbt.mustExec("INSERT INTO test VALUE (?)", reftime)
+
+ // Retrieve time from DB
+ rows := dbt.mustQuery("SELECT ts FROM test")
+ if !rows.Next() {
+ dbt.Fatal("did not get any rows out")
+ }
+
+ var dbTime time.Time
+ err := rows.Scan(&dbTime)
+ if err != nil {
+ dbt.Fatal("Err", err)
+ }
+
+ // Check that dates match
+ if reftime.Unix() != dbTime.Unix() {
+ dbt.Errorf("times do not match.\n")
+ dbt.Errorf(" Now(%v)=%v\n", usCentral, reftime)
+ dbt.Errorf(" Now(UTC)=%v\n", dbTime)
+ }
+ }
+
+ for _, tz := range zones {
+ runTests(t, dsn+"&parseTime=true&loc="+url.QueryEscape(tz), tzTest)
+ }
+}
+
+// Special cases
+
+func TestRowsClose(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ rows, err := dbt.db.Query("SELECT 1")
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ err = rows.Close()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ if rows.Next() {
+ dbt.Fatal("unexpected row after rows.Close()")
+ }
+
+ err = rows.Err()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ })
+}
+
+// dangling statements
+// http://code.google.com/p/go/issues/detail?id=3865
+func TestCloseStmtBeforeRows(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ stmt, err := dbt.db.Prepare("SELECT 1")
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ rows, err := stmt.Query()
+ if err != nil {
+ stmt.Close()
+ dbt.Fatal(err)
+ }
+ defer rows.Close()
+
+ err = stmt.Close()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ if !rows.Next() {
+ dbt.Fatal("getting row failed")
+ } else {
+ err = rows.Err()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ var out bool
+ err = rows.Scan(&out)
+ if err != nil {
+ dbt.Fatalf("error on rows.Scan(): %s", err.Error())
+ }
+ if out != true {
+ dbt.Errorf("true != %t", out)
+ }
+ }
+ })
+}
+
+// It is valid to have multiple Rows for the same Stmt
+// http://code.google.com/p/go/issues/detail?id=3734
+func TestStmtMultiRows(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ stmt, err := dbt.db.Prepare("SELECT 1 UNION SELECT 0")
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ rows1, err := stmt.Query()
+ if err != nil {
+ stmt.Close()
+ dbt.Fatal(err)
+ }
+ defer rows1.Close()
+
+ rows2, err := stmt.Query()
+ if err != nil {
+ stmt.Close()
+ dbt.Fatal(err)
+ }
+ defer rows2.Close()
+
+ var out bool
+
+ // 1
+ if !rows1.Next() {
+ dbt.Fatal("first rows1.Next failed")
+ } else {
+ err = rows1.Err()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ err = rows1.Scan(&out)
+ if err != nil {
+ dbt.Fatalf("error on rows.Scan(): %s", err.Error())
+ }
+ if out != true {
+ dbt.Errorf("true != %t", out)
+ }
+ }
+
+ if !rows2.Next() {
+ dbt.Fatal("first rows2.Next failed")
+ } else {
+ err = rows2.Err()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ err = rows2.Scan(&out)
+ if err != nil {
+ dbt.Fatalf("error on rows.Scan(): %s", err.Error())
+ }
+ if out != true {
+ dbt.Errorf("true != %t", out)
+ }
+ }
+
+ // 2
+ if !rows1.Next() {
+ dbt.Fatal("second rows1.Next failed")
+ } else {
+ err = rows1.Err()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ err = rows1.Scan(&out)
+ if err != nil {
+ dbt.Fatalf("error on rows.Scan(): %s", err.Error())
+ }
+ if out != false {
+ dbt.Errorf("false != %t", out)
+ }
+
+ if rows1.Next() {
+ dbt.Fatal("unexpected row on rows1")
+ }
+ err = rows1.Close()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ }
+
+ if !rows2.Next() {
+ dbt.Fatal("second rows2.Next failed")
+ } else {
+ err = rows2.Err()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+
+ err = rows2.Scan(&out)
+ if err != nil {
+ dbt.Fatalf("error on rows.Scan(): %s", err.Error())
+ }
+ if out != false {
+ dbt.Errorf("false != %t", out)
+ }
+
+ if rows2.Next() {
+ dbt.Fatal("unexpected row on rows2")
+ }
+ err = rows2.Close()
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ }
+ })
+}
+
+// Regression test for
+// * more than 32 NULL parameters (issue 209)
+// * more parameters than fit into the buffer (issue 201)
+func TestPreparedManyCols(t *testing.T) {
+ const numParams = defaultBufSize
+ runTests(t, dsn, func(dbt *DBTest) {
+ query := "SELECT ?" + strings.Repeat(",?", numParams-1)
+ stmt, err := dbt.db.Prepare(query)
+ if err != nil {
+ dbt.Fatal(err)
+ }
+ defer stmt.Close()
+ // create more parameters than fit into the buffer
+ // which will take nil-values
+ params := make([]interface{}, numParams)
+ rows, err := stmt.Query(params...)
+ if err != nil {
+ stmt.Close()
+ dbt.Fatal(err)
+ }
+ defer rows.Close()
+ })
+}
+
+func TestConcurrent(t *testing.T) {
+ if enabled, _ := readBool(os.Getenv("MYSQL_TEST_CONCURRENT")); !enabled {
+ t.Skip("MYSQL_TEST_CONCURRENT env var not set")
+ }
+
+ runTests(t, dsn, func(dbt *DBTest) {
+ var max int
+ err := dbt.db.QueryRow("SELECT @@max_connections").Scan(&max)
+ if err != nil {
+ dbt.Fatalf("%s", err.Error())
+ }
+ dbt.Logf("testing up to %d concurrent connections \r\n", max)
+
+ var remaining, succeeded int32 = int32(max), 0
+
+ var wg sync.WaitGroup
+ wg.Add(max)
+
+ var fatalError string
+ var once sync.Once
+ fatalf := func(s string, vals ...interface{}) {
+ once.Do(func() {
+ fatalError = fmt.Sprintf(s, vals...)
+ })
+ }
+
+ for i := 0; i < max; i++ {
+ go func(id int) {
+ defer wg.Done()
+
+ tx, err := dbt.db.Begin()
+ atomic.AddInt32(&remaining, -1)
+
+ if err != nil {
+ if err.Error() != "Error 1040: Too many connections" {
+ fatalf("error on conn %d: %s", id, err.Error())
+ }
+ return
+ }
+
+ // keep the connection busy until all connections are open
+ for remaining > 0 {
+ if _, err = tx.Exec("DO 1"); err != nil {
+ fatalf("error on conn %d: %s", id, err.Error())
+ return
+ }
+ }
+
+ if err = tx.Commit(); err != nil {
+ fatalf("error on conn %d: %s", id, err.Error())
+ return
+ }
+
+ // everything went fine with this connection
+ atomic.AddInt32(&succeeded, 1)
+ }(i)
+ }
+
+ // wait until all conections are open
+ wg.Wait()
+
+ if fatalError != "" {
+ dbt.Fatal(fatalError)
+ }
+
+ dbt.Logf("reached %d concurrent connections\r\n", succeeded)
+ })
+}
+
+// Tests custom dial functions
+func TestCustomDial(t *testing.T) {
+ if !available {
+ t.Skipf("MySQL server not running on %s", netAddr)
+ }
+
+ // our custom dial function which justs wraps net.Dial here
+ RegisterDial("mydial", func(addr string) (net.Conn, error) {
+ return net.Dial(prot, addr)
+ })
+
+ db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s&strict=true", user, pass, addr, dbname))
+ if err != nil {
+ t.Fatalf("error connecting: %s", err.Error())
+ }
+ defer db.Close()
+
+ if _, err = db.Exec("DO 1"); err != nil {
+ t.Fatalf("connection failed: %s", err.Error())
+ }
+}
+
+func TestSQLInjection(t *testing.T) {
+ createTest := func(arg string) func(dbt *DBTest) {
+ return func(dbt *DBTest) {
+ dbt.mustExec("CREATE TABLE test (v INTEGER)")
+ dbt.mustExec("INSERT INTO test VALUES (?)", 1)
+
+ var v int
+ // NULL can't be equal to anything, the idea here is to inject query so it returns row
+ // This test verifies that escapeQuotes and escapeBackslash are working properly
+ err := dbt.db.QueryRow("SELECT v FROM test WHERE NULL = ?", arg).Scan(&v)
+ if err == sql.ErrNoRows {
+ return // success, sql injection failed
+ } else if err == nil {
+ dbt.Errorf("sql injection successful with arg: %s", arg)
+ } else {
+ dbt.Errorf("error running query with arg: %s; err: %s", arg, err.Error())
+ }
+ }
+ }
+
+ dsns := []string{
+ dsn,
+ dsn + "&sql_mode='NO_BACKSLASH_ESCAPES,NO_AUTO_CREATE_USER'",
+ }
+ for _, testdsn := range dsns {
+ runTests(t, testdsn, createTest("1 OR 1=1"))
+ runTests(t, testdsn, createTest("' OR '1'='1"))
+ }
+}
+
+// Test if inserted data is correctly retrieved after being escaped
+func TestInsertRetrieveEscapedData(t *testing.T) {
+ testData := func(dbt *DBTest) {
+ dbt.mustExec("CREATE TABLE test (v VARCHAR(255))")
+
+ // All sequences that are escaped by escapeQuotes and escapeBackslash
+ v := "foo \x00\n\r\x1a\"'\\"
+ dbt.mustExec("INSERT INTO test VALUES (?)", v)
+
+ var out string
+ err := dbt.db.QueryRow("SELECT v FROM test").Scan(&out)
+ if err != nil {
+ dbt.Fatalf("%s", err.Error())
+ }
+
+ if out != v {
+ dbt.Errorf("%q != %q", out, v)
+ }
+ }
+
+ dsns := []string{
+ dsn,
+ dsn + "&sql_mode='NO_BACKSLASH_ESCAPES,NO_AUTO_CREATE_USER'",
+ }
+ for _, testdsn := range dsns {
+ runTests(t, testdsn, testData)
+ }
+}
+
+func TestUnixSocketAuthFail(t *testing.T) {
+ runTests(t, dsn, func(dbt *DBTest) {
+ // Save the current logger so we can restore it.
+ oldLogger := errLog
+
+ // Set a new logger so we can capture its output.
+ buffer := bytes.NewBuffer(make([]byte, 0, 64))
+ newLogger := log.New(buffer, "prefix: ", 0)
+ SetLogger(newLogger)
+
+ // Restore the logger.
+ defer SetLogger(oldLogger)
+
+ // Make a new DSN that uses the MySQL socket file and a bad password, which
+ // we can make by simply appending any character to the real password.
+ badPass := pass + "x"
+ socket := ""
+ if prot == "unix" {
+ socket = addr
+ } else {
+ // Get socket file from MySQL.
+ err := dbt.db.QueryRow("SELECT @@socket").Scan(&socket)
+ if err != nil {
+ t.Fatalf("error on SELECT @@socket: %s", err.Error())
+ }
+ }
+ t.Logf("socket: %s", socket)
+ badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s&strict=true", user, badPass, socket, dbname)
+ db, err := sql.Open("mysql", badDSN)
+ if err != nil {
+ t.Fatalf("error connecting: %s", err.Error())
+ }
+ defer db.Close()
+
+ // Connect to MySQL for real. This will cause an auth failure.
+ err = db.Ping()
+ if err == nil {
+ t.Error("expected Ping() to return an error")
+ }
+
+ // The driver should not log anything.
+ if actual := buffer.String(); actual != "" {
+ t.Errorf("expected no output, got %q", actual)
+ }
+ })
+}
diff --git a/vendor/github.com/go-sql-driver/mysql/dsn_test.go b/vendor/github.com/go-sql-driver/mysql/dsn_test.go
new file mode 100644
index 000000000..80949e18a
--- /dev/null
+++ b/vendor/github.com/go-sql-driver/mysql/dsn_test.go
@@ -0,0 +1,207 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2016 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net/url"
+ "testing"
+)
+
+var testDSNs = []struct {
+ in string
+ out string
+}{
+ {"username:password@protocol(address)/dbname?param=value", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:true InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"username:password@protocol(address)/dbname?param=value&columnsWithAlias=true&multiStatements=true", "&{User:username Passwd:password Net:protocol Addr:address DBName:dbname Params:map[param:value] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:true InterpolateParams:false MultiStatements:true ParseTime:false Strict:false}"},
+ {"user@unix(/path/to/socket)/dbname?charset=utf8", "&{User:user Passwd: Net:unix Addr:/path/to/socket DBName:dbname Params:map[charset:utf8] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", "&{User:user Passwd:password Net:tcp Addr:localhost:5555 DBName:dbname Params:map[charset:utf8] Collation:utf8_general_ci Loc:UTC TLSConfig:true tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", "&{User:user Passwd:password Net:tcp Addr:localhost:5555 DBName:dbname Params:map[charset:utf8mb4,utf8] Collation:utf8_general_ci Loc:UTC TLSConfig:skip-verify tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci", "&{User:user Passwd:password Net:tcp Addr:127.0.0.1:3306 DBName:dbname Params:map[] Collation:utf8mb4_unicode_ci Loc:UTC TLSConfig: tls:<nil> Timeout:30s ReadTimeout:1s WriteTimeout:1s AllowAllFiles:true AllowCleartextPasswords:false AllowOldPasswords:true ClientFoundRows:true ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", "&{User:user Passwd:p@ss(word) Net:tcp Addr:[de:ad:be:ef::ca:fe]:80 DBName:dbname Params:map[] Collation:utf8_general_ci Loc:Local TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"/dbname", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName:dbname Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"@/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"/", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"", "&{User: Passwd: Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"user:p@/ssword@/", "&{User:user Passwd:p@/ssword Net:tcp Addr:127.0.0.1:3306 DBName: Params:map[] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+ {"unix/?arg=%2Fsome%2Fpath.ext", "&{User: Passwd: Net:unix Addr:/tmp/mysql.sock DBName: Params:map[arg:/some/path.ext] Collation:utf8_general_ci Loc:UTC TLSConfig: tls:<nil> Timeout:0 ReadTimeout:0 WriteTimeout:0 AllowAllFiles:false AllowCleartextPasswords:false AllowOldPasswords:false ClientFoundRows:false ColumnsWithAlias:false InterpolateParams:false MultiStatements:false ParseTime:false Strict:false}"},
+}
+
+func TestDSNParser(t *testing.T) {
+ var cfg *Config
+ var err error
+ var res string
+
+ for i, tst := range testDSNs {
+ cfg, err = ParseDSN(tst.in)
+ if err != nil {
+ t.Error(err.Error())
+ }
+
+ // pointer not static
+ cfg.tls = nil
+
+ res = fmt.Sprintf("%+v", cfg)
+ if res != tst.out {
+ t.Errorf("%d. ParseDSN(%q) => %q, want %q", i, tst.in, res, tst.out)
+ }
+ }
+}
+
+func TestDSNParserInvalid(t *testing.T) {
+ var invalidDSNs = []string{
+ "@net(addr/", // no closing brace
+ "@tcp(/", // no closing brace
+ "tcp(/", // no closing brace
+ "(/", // no closing brace
+ "net(addr)//", // unescaped
+ "User:pass@tcp(1.2.3.4:3306)", // no trailing slash
+ //"/dbname?arg=/some/unescaped/path",
+ }
+
+ for i, tst := range invalidDSNs {
+ if _, err := ParseDSN(tst); err == nil {
+ t.Errorf("invalid DSN #%d. (%s) didn't error!", i, tst)
+ }
+ }
+}
+
+func TestDSNReformat(t *testing.T) {
+ for i, tst := range testDSNs {
+ dsn1 := tst.in
+ cfg1, err := ParseDSN(dsn1)
+ if err != nil {
+ t.Error(err.Error())
+ continue
+ }
+ cfg1.tls = nil // pointer not static
+ res1 := fmt.Sprintf("%+v", cfg1)
+
+ dsn2 := cfg1.FormatDSN()
+ cfg2, err := ParseDSN(dsn2)
+ if err != nil {
+ t.Error(err.Error())
+ continue
+ }
+ cfg2.tls = nil // pointer not static
+ res2 := fmt.Sprintf("%+v", cfg2)
+
+ if res1 != res2 {
+ t.Errorf("%d. %q does not match %q", i, res2, res1)
+ }
+ }
+}
+
+func TestDSNWithCustomTLS(t *testing.T) {
+ baseDSN := "User:password@tcp(localhost:5555)/dbname?tls="
+ tlsCfg := tls.Config{}
+
+ RegisterTLSConfig("utils_test", &tlsCfg)
+
+ // Custom TLS is missing
+ tst := baseDSN + "invalid_tls"
+ cfg, err := ParseDSN(tst)
+ if err == nil {
+ t.Errorf("invalid custom TLS in DSN (%s) but did not error. Got config: %#v", tst, cfg)
+ }
+
+ tst = baseDSN + "utils_test"
+
+ // Custom TLS with a server name
+ name := "foohost"
+ tlsCfg.ServerName = name
+ cfg, err = ParseDSN(tst)
+
+ if err != nil {
+ t.Error(err.Error())
+ } else if cfg.tls.ServerName != name {
+ t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, tst)
+ }
+
+ // Custom TLS without a server name
+ name = "localhost"
+ tlsCfg.ServerName = ""
+ cfg, err = ParseDSN(tst)
+
+ if err != nil {
+ t.Error(err.Error())
+ } else if cfg.tls.ServerName != name {
+ t.Errorf("did not get the correct ServerName (%s) parsing DSN (%s).", name, tst)
+ }
+
+ DeregisterTLSConfig("utils_test")
+}
+
+func TestDSNWithCustomTLSQueryEscape(t *testing.T) {
+ const configKey = "&%!:"
+ dsn := "User:password@tcp(localhost:5555)/dbname?tls=" + url.QueryEscape(configKey)
+ name := "foohost"
+ tlsCfg := tls.Config{ServerName: name}
+
+ RegisterTLSConfig(configKey, &tlsCfg)
+
+ cfg, err := ParseDSN(dsn)
+
+ if err != nil {
+ t.Error(err.Error())
+ } else if cfg.tls.ServerName != name {
+ t.Errorf("did not get the correct TLS ServerName (%s) parsing DSN (%s).", name, dsn)
+ }
+}
+
+func TestDSNUnsafeCollation(t *testing.T) {
+ _, err := ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=true")
+ if err != errInvalidDSNUnsafeCollation {
+ t.Errorf("expected %v, got %v", errInvalidDSNUnsafeCollation, err)
+ }
+
+ _, err = ParseDSN("/dbname?collation=gbk_chinese_ci&interpolateParams=false")
+ if err != nil {
+ t.Errorf("expected %v, got %v", nil, err)
+ }
+
+ _, err = ParseDSN("/dbname?collation=gbk_chinese_ci")
+ if err != nil {
+ t.Errorf("expected %v, got %v", nil, err)
+ }
+
+ _, err = ParseDSN("/dbname?collation=ascii_bin&interpolateParams=true")
+ if err != nil {
+ t.Errorf("expected %v, got %v", nil, err)
+ }
+
+ _, err = ParseDSN("/dbname?collation=latin1_german1_ci&interpolateParams=true")
+ if err != nil {
+ t.Errorf("expected %v, got %v", nil, err)
+ }
+
+ _, err = ParseDSN("/dbname?collation=utf8_general_ci&interpolateParams=true")
+ if err != nil {
+ t.Errorf("expected %v, got %v", nil, err)
+ }
+
+ _, err = ParseDSN("/dbname?collation=utf8mb4_general_ci&interpolateParams=true")
+ if err != nil {
+ t.Errorf("expected %v, got %v", nil, err)
+ }
+}
+
+func BenchmarkParseDSN(b *testing.B) {
+ b.ReportAllocs()
+
+ for i := 0; i < b.N; i++ {
+ for _, tst := range testDSNs {
+ if _, err := ParseDSN(tst.in); err != nil {
+ b.Error(err.Error())
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/go-sql-driver/mysql/errors_test.go b/vendor/github.com/go-sql-driver/mysql/errors_test.go
new file mode 100644
index 000000000..96f9126d6
--- /dev/null
+++ b/vendor/github.com/go-sql-driver/mysql/errors_test.go
@@ -0,0 +1,42 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "bytes"
+ "log"
+ "testing"
+)
+
+func TestErrorsSetLogger(t *testing.T) {
+ previous := errLog
+ defer func() {
+ errLog = previous
+ }()
+
+ // set up logger
+ const expected = "prefix: test\n"
+ buffer := bytes.NewBuffer(make([]byte, 0, 64))
+ logger := log.New(buffer, "prefix: ", 0)
+
+ // print
+ SetLogger(logger)
+ errLog.Print("test")
+
+ // check result
+ if actual := buffer.String(); actual != expected {
+ t.Errorf("expected %q, got %q", expected, actual)
+ }
+}
+
+func TestErrorsStrictIgnoreNotes(t *testing.T) {
+ runTests(t, dsn+"&sql_notes=false", func(dbt *DBTest) {
+ dbt.mustExec("DROP TABLE IF EXISTS does_not_exist")
+ })
+}
diff --git a/vendor/github.com/go-sql-driver/mysql/utils_test.go b/vendor/github.com/go-sql-driver/mysql/utils_test.go
new file mode 100644
index 000000000..0d6c6684f
--- /dev/null
+++ b/vendor/github.com/go-sql-driver/mysql/utils_test.go
@@ -0,0 +1,197 @@
+// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
+//
+// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this file,
+// You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package mysql
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "testing"
+ "time"
+)
+
+func TestScanNullTime(t *testing.T) {
+ var scanTests = []struct {
+ in interface{}
+ error bool
+ valid bool
+ time time.Time
+ }{
+ {tDate, false, true, tDate},
+ {sDate, false, true, tDate},
+ {[]byte(sDate), false, true, tDate},
+ {tDateTime, false, true, tDateTime},
+ {sDateTime, false, true, tDateTime},
+ {[]byte(sDateTime), false, true, tDateTime},
+ {tDate0, false, true, tDate0},
+ {sDate0, false, true, tDate0},
+ {[]byte(sDate0), false, true, tDate0},
+ {sDateTime0, false, true, tDate0},
+ {[]byte(sDateTime0), false, true, tDate0},
+ {"", true, false, tDate0},
+ {"1234", true, false, tDate0},
+ {0, true, false, tDate0},
+ }
+
+ var nt = NullTime{}
+ var err error
+
+ for _, tst := range scanTests {
+ err = nt.Scan(tst.in)
+ if (err != nil) != tst.error {
+ t.Errorf("%v: expected error status %t, got %t", tst.in, tst.error, (err != nil))
+ }
+ if nt.Valid != tst.valid {
+ t.Errorf("%v: expected valid status %t, got %t", tst.in, tst.valid, nt.Valid)
+ }
+ if nt.Time != tst.time {
+ t.Errorf("%v: expected time %v, got %v", tst.in, tst.time, nt.Time)
+ }
+ }
+}
+
+func TestLengthEncodedInteger(t *testing.T) {
+ var integerTests = []struct {
+ num uint64
+ encoded []byte
+ }{
+ {0x0000000000000000, []byte{0x00}},
+ {0x0000000000000012, []byte{0x12}},
+ {0x00000000000000fa, []byte{0xfa}},
+ {0x0000000000000100, []byte{0xfc, 0x00, 0x01}},
+ {0x0000000000001234, []byte{0xfc, 0x34, 0x12}},
+ {0x000000000000ffff, []byte{0xfc, 0xff, 0xff}},
+ {0x0000000000010000, []byte{0xfd, 0x00, 0x00, 0x01}},
+ {0x0000000000123456, []byte{0xfd, 0x56, 0x34, 0x12}},
+ {0x0000000000ffffff, []byte{0xfd, 0xff, 0xff, 0xff}},
+ {0x0000000001000000, []byte{0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00}},
+ {0x123456789abcdef0, []byte{0xfe, 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12}},
+ {0xffffffffffffffff, []byte{0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
+ }
+
+ for _, tst := range integerTests {
+ num, isNull, numLen := readLengthEncodedInteger(tst.encoded)
+ if isNull {
+ t.Errorf("%x: expected %d, got NULL", tst.encoded, tst.num)
+ }
+ if num != tst.num {
+ t.Errorf("%x: expected %d, got %d", tst.encoded, tst.num, num)
+ }
+ if numLen != len(tst.encoded) {
+ t.Errorf("%x: expected size %d, got %d", tst.encoded, len(tst.encoded), numLen)
+ }
+ encoded := appendLengthEncodedInteger(nil, num)
+ if !bytes.Equal(encoded, tst.encoded) {
+ t.Errorf("%v: expected %x, got %x", num, tst.encoded, encoded)
+ }
+ }
+}
+
+func TestOldPass(t *testing.T) {
+ scramble := []byte{9, 8, 7, 6, 5, 4, 3, 2}
+ vectors := []struct {
+ pass string
+ out string
+ }{
+ {" pass", "47575c5a435b4251"},
+ {"pass ", "47575c5a435b4251"},
+ {"123\t456", "575c47505b5b5559"},
+ {"C0mpl!ca ted#PASS123", "5d5d554849584a45"},
+ }
+ for _, tuple := range vectors {
+ ours := scrambleOldPassword(scramble, []byte(tuple.pass))
+ if tuple.out != fmt.Sprintf("%x", ours) {
+ t.Errorf("Failed old password %q", tuple.pass)
+ }
+ }
+}
+
+func TestFormatBinaryDateTime(t *testing.T) {
+ rawDate := [11]byte{}
+ binary.LittleEndian.PutUint16(rawDate[:2], 1978) // years
+ rawDate[2] = 12 // months
+ rawDate[3] = 30 // days
+ rawDate[4] = 15 // hours
+ rawDate[5] = 46 // minutes
+ rawDate[6] = 23 // seconds
+ binary.LittleEndian.PutUint32(rawDate[7:], 987654) // microseconds
+ expect := func(expected string, inlen, outlen uint8) {
+ actual, _ := formatBinaryDateTime(rawDate[:inlen], outlen, false)
+ bytes, ok := actual.([]byte)
+ if !ok {
+ t.Errorf("formatBinaryDateTime must return []byte, was %T", actual)
+ }
+ if string(bytes) != expected {
+ t.Errorf(
+ "expected %q, got %q for length in %d, out %d",
+ bytes, actual, inlen, outlen,
+ )
+ }
+ }
+ expect("0000-00-00", 0, 10)
+ expect("0000-00-00 00:00:00", 0, 19)
+ expect("1978-12-30", 4, 10)
+ expect("1978-12-30 15:46:23", 7, 19)
+ expect("1978-12-30 15:46:23.987654", 11, 26)
+}
+
+func TestEscapeBackslash(t *testing.T) {
+ expect := func(expected, value string) {
+ actual := string(escapeBytesBackslash([]byte{}, []byte(value)))
+ if actual != expected {
+ t.Errorf(
+ "expected %s, got %s",
+ expected, actual,
+ )
+ }
+
+ actual = string(escapeStringBackslash([]byte{}, value))
+ if actual != expected {
+ t.Errorf(
+ "expected %s, got %s",
+ expected, actual,
+ )
+ }
+ }
+
+ expect("foo\\0bar", "foo\x00bar")
+ expect("foo\\nbar", "foo\nbar")
+ expect("foo\\rbar", "foo\rbar")
+ expect("foo\\Zbar", "foo\x1abar")
+ expect("foo\\\"bar", "foo\"bar")
+ expect("foo\\\\bar", "foo\\bar")
+ expect("foo\\'bar", "foo'bar")
+}
+
+func TestEscapeQuotes(t *testing.T) {
+ expect := func(expected, value string) {
+ actual := string(escapeBytesQuotes([]byte{}, []byte(value)))
+ if actual != expected {
+ t.Errorf(
+ "expected %s, got %s",
+ expected, actual,
+ )
+ }
+
+ actual = string(escapeStringQuotes([]byte{}, value))
+ if actual != expected {
+ t.Errorf(
+ "expected %s, got %s",
+ expected, actual,
+ )
+ }
+ }
+
+ expect("foo\x00bar", "foo\x00bar") // not affected
+ expect("foo\nbar", "foo\nbar") // not affected
+ expect("foo\rbar", "foo\rbar") // not affected
+ expect("foo\x1abar", "foo\x1abar") // not affected
+ expect("foo''bar", "foo'bar") // affected
+ expect("foo\"bar", "foo\"bar") // not affected
+}
diff --git a/vendor/github.com/goamz/goamz/.gitignore b/vendor/github.com/goamz/goamz/.gitignore
new file mode 100644
index 000000000..1377554eb
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/.gitignore
@@ -0,0 +1 @@
+*.swp
diff --git a/vendor/github.com/goamz/goamz/.lbox b/vendor/github.com/goamz/goamz/.lbox
new file mode 100644
index 000000000..75e124512
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/.lbox
@@ -0,0 +1 @@
+propose -for=lp:goamz -cr
diff --git a/vendor/github.com/goamz/goamz/.travis.yml b/vendor/github.com/goamz/goamz/.travis.yml
new file mode 100644
index 000000000..3c26b1759
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/.travis.yml
@@ -0,0 +1,32 @@
+language: go
+
+go:
+ - 1.1
+ - 1.2
+ - 1.3
+ - 1.4
+ - tip
+
+before_script:
+ - FIXED=$(go fmt ./... | wc -l); if [ $FIXED -gt 0 ]; then echo "gofmt - $FIXED file(s) not formatted correctly, please run gofmt to fix this." && exit 1; fi
+
+script:
+ - go test -v ./autoscaling/
+ - go test -v ./aws/
+ - go test -v ./cloudformation/
+ - go test -v ./cloudfront/
+ - go test -v ./cloudwatch/
+ - go test -v ./dynamodb/
+ - go test -v ./ec2/
+ - go test -v ./ecs/
+ - go test -v ./elb/
+ - go test -v ./iam/
+ - go test -v ./rds/
+ - go test -v ./route53/
+ - go test -v ./s3/
+ - go test -v ./sqs/
+ - go test -v ./sts/
+ - go test -v ./exp/mturk/
+ - go test -v ./exp/sdb/
+ # - go test -v ./exp/ses/
+ # - go test -v ./exp/sns/
diff --git a/vendor/github.com/goamz/goamz/CHANGES.md b/vendor/github.com/goamz/goamz/CHANGES.md
new file mode 100644
index 000000000..3d047b896
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/CHANGES.md
@@ -0,0 +1,5 @@
+# Changes in this fork
+
+* Added CNNorth Region
+* Change SignV2 to SignV4
+* V4Signer.canonicalQueryString empty value must append "=" \ No newline at end of file
diff --git a/vendor/github.com/goamz/goamz/README.md b/vendor/github.com/goamz/goamz/README.md
new file mode 100644
index 000000000..e1b617484
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/README.md
@@ -0,0 +1,64 @@
+# goamz - An Amazon Library for Go
+
+[![Build Status](http://travis-ci.org/goamz/goamz.png?branch=master)](https://travis-ci.org/goamz/goamz)
+
+The _goamz_ package enables Go programs to interact with Amazon Web Services.
+
+This is a fork of the version [developed within Canonical](https://wiki.ubuntu.com/goamz) with additional functionality and services from [a number of contributors](https://github.com/goamz/goamz/contributors)!
+
+The API of AWS is very comprehensive, though, and goamz doesn't even scratch the surface of it. That said, it's fairly well tested, and is the foundation in which further calls can easily be integrated. We'll continue extending the API as necessary - Pull Requests are _very_ welcome!
+
+The following packages are available at the moment:
+
+```
+github.com/goamz/goamz/autoscaling
+github.com/goamz/goamz/aws
+github.com/goamz/goamz/cloudformation
+github.com/goamz/goamz/cloudfront
+github.com/goamz/goamz/cloudwatch
+github.com/goamz/goamz/dynamodb
+github.com/goamz/goamz/ecs
+github.com/goamz/goamz/ec2
+github.com/goamz/goamz/elb
+github.com/goamz/goamz/iam
+github.com/goamz/goamz/rds
+github.com/goamz/goamz/route53
+github.com/goamz/goamz/s3
+github.com/goamz/goamz/sqs
+github.com/goamz/goamz/sts
+
+github.com/goamz/goamz/exp/mturk
+github.com/goamz/goamz/exp/sdb
+github.com/goamz/goamz/exp/sns
+```
+
+Packages under `exp/` are still in an experimental or unfinished/unpolished state.
+
+## API documentation
+
+The API documentation is currently available at:
+
+[http://godoc.org/github.com/goamz/goamz](http://godoc.org/github.com/goamz/goamz)
+
+## How to build and install goamz
+
+Just use `go get` with any of the available packages. For example:
+
+* `$ go get github.com/goamz/goamz/ec2`
+* `$ go get github.com/goamz/goamz/s3`
+
+## Running tests
+
+To run tests, first install gocheck with:
+
+`$ go get gopkg.in/check.v1`
+
+Then run go test as usual:
+
+`$ go test github.com/goamz/goamz/...`
+
+_Note:_ running all tests with the command `go test ./...` will currently fail as tests do not tear down their HTTP listeners.
+
+If you want to run integration tests (costs money), set up the EC2 environment variables as usual, and run:
+
+$ gotest -i
diff --git a/vendor/github.com/goamz/goamz/autoscaling/autoscaling.go b/vendor/github.com/goamz/goamz/autoscaling/autoscaling.go
new file mode 100644
index 000000000..8e9f8ab02
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/autoscaling/autoscaling.go
@@ -0,0 +1,1768 @@
+//
+// autoscaling: This package provides types and functions to interact with the AWS Auto Scale API
+//
+// Depends on https://wiki.ubuntu.com/goamz
+//
+
+package autoscaling
+
+import (
+ "encoding/base64"
+ "encoding/xml"
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+const debug = false
+
+var timeNow = time.Now
+
+// AutoScaling contains the details of the AWS region to perform operations against.
+type AutoScaling struct {
+ aws.Auth
+ aws.Region
+}
+
+// New creates a new AutoScaling Client.
+func New(auth aws.Auth, region aws.Region) *AutoScaling {
+ return &AutoScaling{auth, region}
+}
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+// Error encapsulates an error returned by the AWS Auto Scaling API.
+//
+// See http://goo.gl/VZGuC for more details.
+type Error struct {
+ // HTTP status code (200, 403, ...)
+ StatusCode int
+ // AutoScaling error code ("UnsupportedOperation", ...)
+ Code string
+ // The error type
+ Type string
+ // The human-oriented error message
+ Message string
+ RequestId string `xml:"RequestID"`
+}
+
+func (err *Error) Error() string {
+ if err.Code == "" {
+ return err.Message
+ }
+
+ return fmt.Sprintf("%s (%s)", err.Message, err.Code)
+}
+
+type xmlErrors struct {
+ RequestId string `xml:"RequestId"`
+ Errors []Error `xml:"Error"`
+}
+
+func (as *AutoScaling) query(params map[string]string, resp interface{}) error {
+ params["Version"] = "2011-01-01"
+ data := strings.NewReader(multimap(params).Encode())
+
+ hreq, err := http.NewRequest("POST", as.Region.AutoScalingEndpoint+"/", data)
+ if err != nil {
+ return err
+ }
+
+ hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+ token := as.Auth.Token()
+ if token != "" {
+ hreq.Header.Set("X-Amz-Security-Token", token)
+ }
+
+ signer := aws.NewV4Signer(as.Auth, "autoscaling", as.Region)
+ signer.Sign(hreq)
+
+ if debug {
+ log.Printf("%v -> {\n", hreq)
+ }
+ r, err := http.DefaultClient.Do(hreq)
+
+ if err != nil {
+ log.Printf("Error calling Amazon %v", err)
+ return err
+ }
+
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("response:\n")
+ log.Printf("%v\n}\n", string(dump))
+ }
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+func buildError(r *http.Response) error {
+ var (
+ err Error
+ errors xmlErrors
+ )
+ xml.NewDecoder(r.Body).Decode(&errors)
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+
+ err.RequestId = errors.RequestId
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+func addParamsList(params map[string]string, label string, ids []string) {
+ for i, id := range ids {
+ params[label+"."+strconv.Itoa(i+1)] = id
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Filtering helper.
+
+// Filter builds filtering parameters to be used in an autoscaling query which supports
+// filtering. For example:
+//
+// filter := NewFilter()
+// filter.Add("architecture", "i386")
+// filter.Add("launch-index", "0")
+// resp, err := as.DescribeTags(filter,nil,nil)
+//
+type Filter struct {
+ m map[string][]string
+}
+
+// NewFilter creates a new Filter.
+func NewFilter() *Filter {
+ return &Filter{make(map[string][]string)}
+}
+
+// Add appends a filtering parameter with the given name and value(s).
+func (f *Filter) Add(name string, value ...string) {
+ f.m[name] = append(f.m[name], value...)
+}
+
+func (f *Filter) addParams(params map[string]string) {
+ if f != nil {
+ a := make([]string, len(f.m))
+ i := 0
+ for k := range f.m {
+ a[i] = k
+ i++
+ }
+ sort.StringSlice(a).Sort()
+ for i, k := range a {
+ prefix := "Filters.member." + strconv.Itoa(i+1)
+ params[prefix+".Name"] = k
+ for j, v := range f.m[k] {
+ params[prefix+".Values.member."+strconv.Itoa(j+1)] = v
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Auto Scaling base types and related functions.
+
+// SimpleResp is the basic response from most actions.
+type SimpleResp struct {
+ XMLName xml.Name
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// EnabledMetric encapsulates a metric associated with an Auto Scaling Group
+//
+// See http://goo.gl/hXiH17 for more details
+type EnabledMetric struct {
+ Granularity string `xml:"Granularity"` // The granularity of the enabled metric.
+ Metric string `xml:"Metric"` // The name of the enabled metric.
+}
+
+// Instance encapsulates an instance type as returned by the Auto Scaling API
+//
+// See http://goo.gl/NwBxGh and http://goo.gl/OuoqhS for more details.
+type Instance struct {
+ // General instance information
+ AutoScalingGroupName string `xml:"AutoScalingGroupName"`
+ AvailabilityZone string `xml:"AvailabilityZone"`
+ HealthStatus string `xml:"HealthStatus"`
+ InstanceId string `xml:"InstanceId"`
+ LaunchConfigurationName string `xml:"LaunchConfigurationName"`
+ LifecycleState string `xml:"LifecycleState"`
+}
+
+// SuspenedProcess encapsulates an Auto Scaling process that has been suspended
+//
+// See http://goo.gl/iObPgF for more details
+type SuspendedProcess struct {
+ ProcessName string `xml:"ProcessName"`
+ SuspensionReason string `xml:"SuspensionReason"`
+}
+
+// Tag encapsulates tag applied to an Auto Scaling group.
+//
+// See http://goo.gl/MG1hqs for more details
+type Tag struct {
+ Key string `xml:"Key"`
+ PropagateAtLaunch bool `xml:"PropagateAtLaunch"` // Specifies whether the new tag will be applied to instances launched after the tag is created
+ ResourceId string `xml:"ResourceId"` // the name of the Auto Scaling group - not required if creating ASG
+ ResourceType string `xml:"ResourceType"` // currently only auto-scaling-group is supported - not required if creating ASG
+ Value string `xml:"Value"`
+}
+
+// AutoScalingGroup encapsulates an Auto Scaling Group object
+//
+// See http://goo.gl/fJdYhg for more details.
+type AutoScalingGroup struct {
+ AutoScalingGroupARN string `xml:"AutoScalingGroupARN"`
+ AutoScalingGroupName string `xml:"AutoScalingGroupName"`
+ AvailabilityZones []string `xml:"AvailabilityZones>member"`
+ CreatedTime time.Time `xml:"CreatedTime"`
+ DefaultCooldown int `xml:"DefaultCooldown"`
+ DesiredCapacity int `xml:"DesiredCapacity"`
+ EnabledMetrics []EnabledMetric `xml:"EnabledMetric>member"`
+ HealthCheckGracePeriod int `xml:"HealthCheckGracePeriod"`
+ HealthCheckType string `xml:"HealthCheckType"`
+ Instances []Instance `xml:"Instances>member"`
+ LaunchConfigurationName string `xml:"LaunchConfigurationName"`
+ LoadBalancerNames []string `xml:"LoadBalancerNames>member"`
+ MaxSize int `xml:"MaxSize"`
+ MinSize int `xml:"MinSize"`
+ PlacementGroup string `xml:"PlacementGroup"`
+ Status string `xml:"Status"`
+ SuspendedProcesses []SuspendedProcess `xml:"SuspendedProcesses>member"`
+ Tags []Tag `xml:"Tags>member"`
+ TerminationPolicies []string `xml:"TerminationPolicies>member"`
+ VPCZoneIdentifier string `xml:"VPCZoneIdentifier"`
+}
+
+// CreateAutoScalingGroupParams type encapsulates options for the respective request.
+//
+// See http://goo.gl/3S13Bv for more details.
+type CreateAutoScalingGroupParams struct {
+ AutoScalingGroupName string
+ AvailabilityZones []string
+ DefaultCooldown int
+ DesiredCapacity int
+ HealthCheckGracePeriod int
+ HealthCheckType string
+ InstanceId string
+ LaunchConfigurationName string
+ LoadBalancerNames []string
+ MaxSize int
+ MinSize int
+ PlacementGroup string
+ Tags []Tag
+ TerminationPolicies []string
+ VPCZoneIdentifier string
+}
+
+// AttachInstances Attach running instances to an autoscaling group
+//
+// See http://goo.gl/zDZbuQ for more details.
+func (as *AutoScaling) AttachInstances(name string, instanceIds []string) (resp *SimpleResp, err error) {
+ params := makeParams("AttachInstances")
+ params["AutoScalingGroupName"] = name
+
+ for i, id := range instanceIds {
+ key := fmt.Sprintf("InstanceIds.member.%d", i+1)
+ params[key] = id
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// CreateAutoScalingGroup creates an Auto Scaling Group on AWS
+//
+// Required params: AutoScalingGroupName, MinSize, MaxSize
+//
+// See http://goo.gl/3S13Bv for more details.
+func (as *AutoScaling) CreateAutoScalingGroup(options *CreateAutoScalingGroupParams) (
+ resp *SimpleResp, err error) {
+ params := makeParams("CreateAutoScalingGroup")
+
+ params["AutoScalingGroupName"] = options.AutoScalingGroupName
+ params["MaxSize"] = strconv.Itoa(options.MaxSize)
+ params["MinSize"] = strconv.Itoa(options.MinSize)
+ params["DesiredCapacity"] = strconv.Itoa(options.DesiredCapacity)
+
+ if options.DefaultCooldown > 0 {
+ params["DefaultCooldown"] = strconv.Itoa(options.DefaultCooldown)
+ }
+ if options.HealthCheckGracePeriod > 0 {
+ params["HealthCheckGracePeriod"] = strconv.Itoa(options.HealthCheckGracePeriod)
+ }
+ if options.HealthCheckType != "" {
+ params["HealthCheckType"] = options.HealthCheckType
+ }
+ if options.InstanceId != "" {
+ params["InstanceId"] = options.InstanceId
+ }
+ if options.LaunchConfigurationName != "" {
+ params["LaunchConfigurationName"] = options.LaunchConfigurationName
+ }
+ if options.PlacementGroup != "" {
+ params["PlacementGroup"] = options.PlacementGroup
+ }
+ if options.VPCZoneIdentifier != "" {
+ params["VPCZoneIdentifier"] = options.VPCZoneIdentifier
+ }
+ if len(options.LoadBalancerNames) > 0 {
+ addParamsList(params, "LoadBalancerNames.member", options.LoadBalancerNames)
+ }
+ if len(options.AvailabilityZones) > 0 {
+ addParamsList(params, "AvailabilityZones.member", options.AvailabilityZones)
+ }
+ if len(options.TerminationPolicies) > 0 {
+ addParamsList(params, "TerminationPolicies.member", options.TerminationPolicies)
+ }
+ for i, t := range options.Tags {
+ key := "Tags.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "Key")] = t.Key
+ params[fmt.Sprintf(key, index, "Value")] = t.Value
+ params[fmt.Sprintf(key, index, "PropagateAtLaunch")] = strconv.FormatBool(t.PropagateAtLaunch)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// EBS represents the AWS EBS volume data type
+//
+// See http://goo.gl/nDUL2h for more details
+type EBS struct {
+ DeleteOnTermination bool `xml:"DeleteOnTermination"`
+ Iops int `xml:"Iops"`
+ SnapshotId string `xml:"SnapshotId"`
+ VolumeSize int `xml:"VolumeSize"`
+ VolumeType string `xml:"VolumeType"`
+}
+
+// BlockDeviceMapping represents the association of a block device with ebs volume.
+//
+// See http://goo.gl/wEGwkU for more details.
+type BlockDeviceMapping struct {
+ DeviceName string `xml:"DeviceName"`
+ Ebs EBS `xml:"Ebs"`
+ NoDevice bool `xml:"NoDevice"`
+ VirtualName string `xml:"VirtualName"`
+}
+
+// InstanceMonitoring data type
+//
+// See http://goo.gl/TfaPwz for more details
+type InstanceMonitoring struct {
+ Enabled bool `xml:"Enabled"`
+}
+
+// LaunchConfiguration encapsulates the LaunchConfiguration Data Type
+//
+// See http://goo.gl/TOJunp
+type LaunchConfiguration struct {
+ AssociatePublicIpAddress bool `xml:"AssociatePublicIpAddress"`
+ BlockDeviceMappings []BlockDeviceMapping `xml:"BlockDeviceMappings>member"`
+ CreatedTime time.Time `xml:"CreatedTime"`
+ EbsOptimized bool `xml:"EbsOptimized"`
+ IamInstanceProfile string `xml:"IamInstanceProfile"`
+ ImageId string `xml:"ImageId"`
+ InstanceId string `xml:"InstanceId"`
+ InstanceMonitoring InstanceMonitoring `xml:"InstanceMonitoring"`
+ InstanceType string `xml:"InstanceType"`
+ KernelId string `xml:"KernelId"`
+ KeyName string `xml:"KeyName"`
+ LaunchConfigurationARN string `xml:"LaunchConfigurationARN"`
+ LaunchConfigurationName string `xml:"LaunchConfigurationName"`
+ RamdiskId string `xml:"RamdiskId"`
+ SecurityGroups []string `xml:"SecurityGroups>member"`
+ SpotPrice string `xml:"SpotPrice"`
+ UserData string `xml:"UserData"`
+}
+
+// CreateLaunchConfiguration creates a launch configuration
+//
+// Required params: AutoScalingGroupName, MinSize, MaxSize
+//
+// See http://goo.gl/8e0BSF for more details.
+func (as *AutoScaling) CreateLaunchConfiguration(lc *LaunchConfiguration) (
+ resp *SimpleResp, err error) {
+
+ var b64 = base64.StdEncoding
+
+ params := makeParams("CreateLaunchConfiguration")
+ params["LaunchConfigurationName"] = lc.LaunchConfigurationName
+
+ if lc.AssociatePublicIpAddress {
+ params["AssociatePublicIpAddress"] = strconv.FormatBool(lc.AssociatePublicIpAddress)
+ }
+ if lc.EbsOptimized {
+ params["EbsOptimized"] = strconv.FormatBool(lc.EbsOptimized)
+ }
+ if lc.IamInstanceProfile != "" {
+ params["IamInstanceProfile"] = lc.IamInstanceProfile
+ }
+ if lc.ImageId != "" {
+ params["ImageId"] = lc.ImageId
+ }
+ if lc.InstanceId != "" {
+ params["InstanceId"] = lc.InstanceId
+ }
+ if lc.InstanceMonitoring != (InstanceMonitoring{}) {
+ params["InstanceMonitoring.Enabled"] = strconv.FormatBool(lc.InstanceMonitoring.Enabled)
+ }
+ if lc.InstanceType != "" {
+ params["InstanceType"] = lc.InstanceType
+ }
+ if lc.KernelId != "" {
+ params["KernelId"] = lc.KernelId
+ }
+ if lc.KeyName != "" {
+ params["KeyName"] = lc.KeyName
+ }
+ if lc.RamdiskId != "" {
+ params["RamdiskId"] = lc.RamdiskId
+ }
+ if lc.SpotPrice != "" {
+ params["SpotPrice"] = lc.SpotPrice
+ }
+ if lc.UserData != "" {
+ params["UserData"] = b64.EncodeToString([]byte(lc.UserData))
+ }
+
+ // Add our block device mappings
+ for i, bdm := range lc.BlockDeviceMappings {
+ key := "BlockDeviceMappings.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "DeviceName")] = bdm.DeviceName
+ params[fmt.Sprintf(key, index, "VirtualName")] = bdm.VirtualName
+
+ if bdm.NoDevice {
+ params[fmt.Sprintf(key, index, "NoDevice")] = "true"
+ }
+
+ if bdm.Ebs != (EBS{}) {
+ key := "BlockDeviceMappings.member.%d.Ebs.%s"
+
+ // Defaults to true
+ params[fmt.Sprintf(key, index, "DeleteOnTermination")] = strconv.FormatBool(bdm.Ebs.DeleteOnTermination)
+
+ if bdm.Ebs.Iops > 0 {
+ params[fmt.Sprintf(key, index, "Iops")] = strconv.Itoa(bdm.Ebs.Iops)
+ }
+ if bdm.Ebs.SnapshotId != "" {
+ params[fmt.Sprintf(key, index, "SnapshotId")] = bdm.Ebs.SnapshotId
+ }
+ if bdm.Ebs.VolumeSize > 0 {
+ params[fmt.Sprintf(key, index, "VolumeSize")] = strconv.Itoa(bdm.Ebs.VolumeSize)
+ }
+ if bdm.Ebs.VolumeType != "" {
+ params[fmt.Sprintf(key, index, "VolumeType")] = bdm.Ebs.VolumeType
+ }
+ }
+ }
+
+ if len(lc.SecurityGroups) > 0 {
+ addParamsList(params, "SecurityGroups.member", lc.SecurityGroups)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// CreateOrUpdateTags creates or updates Auto Scaling Group Tags
+//
+// See http://goo.gl/e1UIXb for more details.
+func (as *AutoScaling) CreateOrUpdateTags(tags []Tag) (resp *SimpleResp, err error) {
+ params := makeParams("CreateOrUpdateTags")
+
+ for i, t := range tags {
+ key := "Tags.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "Key")] = t.Key
+ params[fmt.Sprintf(key, index, "Value")] = t.Value
+ params[fmt.Sprintf(key, index, "PropagateAtLaunch")] = strconv.FormatBool(t.PropagateAtLaunch)
+ params[fmt.Sprintf(key, index, "ResourceId")] = t.ResourceId
+ if t.ResourceType != "" {
+ params[fmt.Sprintf(key, index, "ResourceType")] = t.ResourceType
+ } else {
+ params[fmt.Sprintf(key, index, "ResourceType")] = "auto-scaling-group"
+ }
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+type CompleteLifecycleActionParams struct {
+ AutoScalingGroupName string
+ LifecycleActionResult string
+ LifecycleActionToken string
+ LifecycleHookName string
+}
+
+// CompleteLifecycleAction completes the lifecycle action for the associated token initiated under the given lifecycle hook with the specified result.
+//
+// Part of the basic sequence for adding a lifecycle hook to an Auto Scaling group:
+// 1) Create a notification target (SQS queue || SNS Topic)
+// 2) Create an IAM role to allow the ASG topublish lifecycle notifications to the designated SQS queue or SNS topic
+// 3) Create the lifecycle hook. You can create a hook that acts when instances launch or when instances terminate
+// 4) If necessary, record the lifecycle action heartbeat to keep the instance in a pending state
+// 5) ***Complete the lifecycle action***
+//
+// See http://goo.gl/k4fl0p for more details
+func (as *AutoScaling) CompleteLifecycleAction(options *CompleteLifecycleActionParams) (
+ resp *SimpleResp, err error) {
+ params := makeParams("CompleteLifecycleAction")
+
+ params["AutoScalingGroupName"] = options.AutoScalingGroupName
+ params["LifecycleActionResult"] = options.LifecycleActionResult
+ params["LifecycleActionToken"] = options.LifecycleActionToken
+ params["LifecycleHookName"] = options.LifecycleHookName
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteAutoScalingGroup deletes an Auto Scaling Group
+//
+// See http://goo.gl/us7VSffor for more details.
+func (as *AutoScaling) DeleteAutoScalingGroup(asgName string, forceDelete bool) (
+ resp *SimpleResp, err error) {
+ params := makeParams("DeleteAutoScalingGroup")
+ params["AutoScalingGroupName"] = asgName
+
+ if forceDelete {
+ params["ForceDelete"] = "true"
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteLaunchConfiguration deletes a Launch Configuration
+//
+// See http://goo.gl/xksfyR for more details.
+func (as *AutoScaling) DeleteLaunchConfiguration(name string) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteLaunchConfiguration")
+ params["LaunchConfigurationName"] = name
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteLifecycleHook eletes the specified lifecycle hook.
+// If there are any outstanding lifecycle actions, they are completed first
+//
+// See http://goo.gl/MwX1vG for more details.
+func (as *AutoScaling) DeleteLifecycleHook(asgName, lifecycleHookName string) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteLifecycleHook")
+ params["AutoScalingGroupName"] = asgName
+ params["LifecycleHookName"] = lifecycleHookName
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteNotificationConfiguration deletes notifications created by PutNotificationConfiguration.
+//
+// See http://goo.gl/jTqoYz for more details
+func (as *AutoScaling) DeleteNotificationConfiguration(asgName string, topicARN string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("DeleteNotificationConfiguration")
+ params["AutoScalingGroupName"] = asgName
+ params["TopicARN"] = topicARN
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeletePolicy deletes a policy created by PutScalingPolicy.
+//
+// policyName might be the policy name or ARN
+//
+// See http://goo.gl/aOQPH2 for more details
+func (as *AutoScaling) DeletePolicy(asgName string, policyName string) (resp *SimpleResp, err error) {
+ params := makeParams("DeletePolicy")
+ params["AutoScalingGroupName"] = asgName
+ params["PolicyName"] = policyName
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteScheduledAction deletes a scheduled action previously created using the PutScheduledUpdateGroupAction.
+//
+// See http://goo.gl/Zss9CH for more details
+func (as *AutoScaling) DeleteScheduledAction(asgName string, scheduledActionName string) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteScheduledAction")
+ params["AutoScalingGroupName"] = asgName
+ params["ScheduledActionName"] = scheduledActionName
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteTags deletes autoscaling group tags
+//
+// See http://goo.gl/o8HzAk for more details.
+func (as *AutoScaling) DeleteTags(tags []Tag) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteTags")
+
+ for i, t := range tags {
+ key := "Tags.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "Key")] = t.Key
+ params[fmt.Sprintf(key, index, "Value")] = t.Value
+ params[fmt.Sprintf(key, index, "PropagateAtLaunch")] = strconv.FormatBool(t.PropagateAtLaunch)
+ params[fmt.Sprintf(key, index, "ResourceId")] = t.ResourceId
+ params[fmt.Sprintf(key, index, "ResourceType")] = "auto-scaling-group"
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+//DescribeAccountLimits response wrapper
+//
+// See http://goo.gl/tKsMN0 for more details.
+type DescribeAccountLimitsResp struct {
+ MaxNumberOfAutoScalingGroups int `xml:"DescribeAccountLimitsResult>MaxNumberOfAutoScalingGroups"`
+ MaxNumberOfLaunchConfigurations int `xml:"DescribeAccountLimitsResult>MaxNumberOfLaunchConfigurations"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeAccountLimits - Returns the limits for the Auto Scaling resources currently allowed for your AWS account.
+//
+// See http://goo.gl/tKsMN0 for more details.
+func (as *AutoScaling) DescribeAccountLimits() (resp *DescribeAccountLimitsResp, err error) {
+ params := makeParams("DescribeAccountLimits")
+
+ resp = new(DescribeAccountLimitsResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// AdjustmentType specifies whether the PutScalingPolicy ScalingAdjustment parameter is an absolute number or a percentage of the current capacity.
+//
+// See http://goo.gl/tCFqeL for more details
+type AdjustmentType struct {
+ AdjustmentType string //Valid values are ChangeInCapacity, ExactCapacity, and PercentChangeInCapacity.
+}
+
+//DescribeAdjustmentTypes response wrapper
+//
+// See http://goo.gl/hGx3Pc for more details.
+type DescribeAdjustmentTypesResp struct {
+ AdjustmentTypes []AdjustmentType `xml:"DescribeAdjustmentTypesResult>AdjustmentTypes>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeAdjustmentTypes returns policy adjustment types for use in the PutScalingPolicy action.
+//
+// See http://goo.gl/hGx3Pc for more details.
+func (as *AutoScaling) DescribeAdjustmentTypes() (resp *DescribeAdjustmentTypesResp, err error) {
+ params := makeParams("DescribeAdjustmentTypes")
+
+ resp = new(DescribeAdjustmentTypesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeAutoScalingGroups response wrapper
+//
+// See http://goo.gl/nW74Ut for more details.
+type DescribeAutoScalingGroupsResp struct {
+ AutoScalingGroups []AutoScalingGroup `xml:"DescribeAutoScalingGroupsResult>AutoScalingGroups>member"`
+ NextToken string `xml:"DescribeAutoScalingGroupsResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeAutoScalingGroups returns a full description of each Auto Scaling group in the given list
+// If no autoscaling groups are provided, returns the details of all autoscaling groups
+// Supports pagination by using the returned "NextToken" parameter for subsequent calls
+//
+// See http://goo.gl/nW74Ut for more details.
+func (as *AutoScaling) DescribeAutoScalingGroups(names []string, maxRecords int, nextToken string) (
+ resp *DescribeAutoScalingGroupsResp, err error) {
+ params := makeParams("DescribeAutoScalingGroups")
+
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+ if len(names) > 0 {
+ addParamsList(params, "AutoScalingGroupNames.member", names)
+ }
+
+ resp = new(DescribeAutoScalingGroupsResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeAutoScalingInstances response wrapper
+//
+// See http://goo.gl/ckzORt for more details.
+type DescribeAutoScalingInstancesResp struct {
+ AutoScalingInstances []Instance `xml:"DescribeAutoScalingInstancesResult>AutoScalingInstances>member"`
+ NextToken string `xml:"DescribeAutoScalingInstancesResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeAutoScalingInstances returns a description of each Auto Scaling instance in the InstanceIds list.
+// If a list is not provided, the service returns the full details of all instances up to a maximum of 50
+// By default, the service returns a list of 20 items.
+// Supports pagination by using the returned "NextToken" parameter for subsequent calls
+//
+// See http://goo.gl/ckzORt for more details.
+func (as *AutoScaling) DescribeAutoScalingInstances(ids []string, maxRecords int, nextToken string) (
+ resp *DescribeAutoScalingInstancesResp, err error) {
+ params := makeParams("DescribeAutoScalingInstances")
+
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+ if len(ids) > 0 {
+ addParamsList(params, "InstanceIds.member", ids)
+ }
+
+ resp = new(DescribeAutoScalingInstancesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeAutoScalingNotificationTypes response wrapper
+//
+// See http://goo.gl/pmLIoE for more details.
+type DescribeAutoScalingNotificationTypesResp struct {
+ AutoScalingNotificationTypes []string `xml:"DescribeAutoScalingNotificationTypesResult>AutoScalingNotificationTypes>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeAutoScalingNotificationTypes returns a list of all notification types that are supported by Auto Scaling
+//
+// See http://goo.gl/pmLIoE for more details.
+func (as *AutoScaling) DescribeAutoScalingNotificationTypes() (resp *DescribeAutoScalingNotificationTypesResp, err error) {
+ params := makeParams("DescribeAutoScalingNotificationTypes")
+
+ resp = new(DescribeAutoScalingNotificationTypesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeLaunchConfigurationResp defines the basic response structure for launch configuration
+// requests
+//
+// See http://goo.gl/y31YYE for more details.
+type DescribeLaunchConfigurationsResp struct {
+ LaunchConfigurations []LaunchConfiguration `xml:"DescribeLaunchConfigurationsResult>LaunchConfigurations>member"`
+ NextToken string `xml:"DescribeLaunchConfigurationsResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeLaunchConfigurations returns details about the launch configurations supplied in
+// the list. If the list is nil, information is returned about all launch configurations in the
+// region.
+//
+// See http://goo.gl/y31YYE for more details.
+func (as *AutoScaling) DescribeLaunchConfigurations(names []string, maxRecords int, nextToken string) (
+ resp *DescribeLaunchConfigurationsResp, err error) {
+ params := makeParams("DescribeLaunchConfigurations")
+
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+ if len(names) > 0 {
+ addParamsList(params, "LaunchConfigurationNames.member", names)
+ }
+
+ resp = new(DescribeLaunchConfigurationsResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
+// DescribeLifecycleHookTypesResult wraps a DescribeLifecycleHookTypes response
+//
+// See http://goo.gl/qiAH31 for more details.
+type DescribeLifecycleHookTypesResult struct {
+ LifecycleHookTypes []string `xml:"DescribeLifecycleHookTypesResult>LifecycleHookTypes>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeLifecycleHookTypes describes the available types of lifecycle hooks
+//
+// See http://goo.gl/E9IBtY for more information
+func (as *AutoScaling) DescribeLifecycleHookTypes() (
+ resp *DescribeLifecycleHookTypesResult, err error) {
+ params := makeParams("DescribeLifecycleHookTypes")
+
+ resp = new(DescribeLifecycleHookTypesResult)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// LifecycleHook represents a lifecyclehook object
+//
+// See http://goo.gl/j62Iqu for more information
+type LifecycleHook struct {
+ AutoScalingGroupName string `xml:"AutoScalingGroupName"`
+ DefaultResult string `xml:"DefaultResult"`
+ GlobalTimeout int `xml:"GlobalTimeout"`
+ HeartbeatTimeout int `xml:"HeartbeatTimeout"`
+ LifecycleHookName string `xml:"LifecycleHookName"`
+ LifecycleTransition string `xml:"LifecycleTransition"`
+ NotificationMetadata string `xml:"NotificationMetadata"`
+ NotificationTargetARN string `xml:"NotificationTargetARN"`
+ RoleARN string `xml:"RoleARN"`
+}
+
+// DescribeLifecycleHooks wraps a DescribeLifecycleHooks response
+//
+// See http://goo.gl/wQkWiz for more details.
+type DescribeLifecycleHooksResult struct {
+ LifecycleHooks []string `xml:"DescribeLifecycleHooksResult>LifecycleHooks>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeLifecycleHooks describes the lifecycle hooks that currently belong to the specified Auto Scaling group
+//
+// See http://goo.gl/wQkWiz for more information
+func (as *AutoScaling) DescribeLifecycleHooks(asgName string, hookNames []string) (
+ resp *DescribeLifecycleHooksResult, err error) {
+ params := makeParams("DescribeLifecycleHooks")
+ params["AutoScalingGroupName"] = asgName
+
+ if len(hookNames) > 0 {
+ addParamsList(params, "LifecycleHookNames.member", hookNames)
+ }
+
+ resp = new(DescribeLifecycleHooksResult)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// MetricGranularity encapsulates the MetricGranularityType
+//
+// See http://goo.gl/WJ82AA for more details
+type MetricGranularity struct {
+ Granularity string `xml:"Granularity"`
+}
+
+//MetricCollection encapsulates the MetricCollectionType
+//
+// See http://goo.gl/YrEG6h for more details
+type MetricCollection struct {
+ Metric string `xml:"Metric"`
+}
+
+// DescribeMetricCollectionTypesResp response wrapper
+//
+// See http://goo.gl/UyYc3i for more details.
+type DescribeMetricCollectionTypesResp struct {
+ Granularities []MetricGranularity `xml:"DescribeMetricCollectionTypesResult>Granularities>member"`
+ Metrics []MetricCollection `xml:"DescribeMetricCollectionTypesResult>Metrics>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeMetricCollectionTypes returns a list of metrics and a corresponding list of granularities for each metric
+//
+// See http://goo.gl/UyYc3i for more details.
+func (as *AutoScaling) DescribeMetricCollectionTypes() (resp *DescribeMetricCollectionTypesResp, err error) {
+ params := makeParams("DescribeMetricCollectionTypes")
+
+ resp = new(DescribeMetricCollectionTypesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// NotificationConfiguration encapsulates the NotificationConfigurationType
+//
+// See http://goo.gl/M8xYOQ for more details
+type NotificationConfiguration struct {
+ AutoScalingGroupName string `xml:"AutoScalingGroupName"`
+ NotificationType string `xml:"NotificationType"`
+ TopicARN string `xml:"TopicARN"`
+}
+
+// DescribeNotificationConfigurations response wrapper
+//
+// See http://goo.gl/qiAH31 for more details.
+type DescribeNotificationConfigurationsResp struct {
+ NotificationConfigurations []NotificationConfiguration `xml:"DescribeNotificationConfigurationsResult>NotificationConfigurations>member"`
+ NextToken string `xml:"DescribeNotificationConfigurationsResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeNotificationConfigurations returns a list of notification actions associated with Auto Scaling groups for specified events.
+// Supports pagination by using the returned "NextToken" parameter for subsequent calls
+//
+// http://goo.gl/qiAH31 for more details.
+func (as *AutoScaling) DescribeNotificationConfigurations(asgNames []string, maxRecords int, nextToken string) (
+ resp *DescribeNotificationConfigurationsResp, err error) {
+ params := makeParams("DescribeNotificationConfigurations")
+
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+ if len(asgNames) > 0 {
+ addParamsList(params, "AutoScalingGroupNames.member", asgNames)
+ }
+
+ resp = new(DescribeNotificationConfigurationsResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Alarm encapsulates the Alarm data type.
+//
+// See http://goo.gl/Q0uPAB for more details
+type Alarm struct {
+ AlarmARN string `xml:"AlarmARN"`
+ AlarmName string `xml:"AlarmName"`
+}
+
+// ScalingPolicy encapsulates the ScalingPolicyType
+//
+// See http://goo.gl/BYAT18 for more details
+type ScalingPolicy struct {
+ AdjustmentType string `xml:"AdjustmentType"` // ChangeInCapacity, ExactCapacity, and PercentChangeInCapacity
+ Alarms []Alarm `xml:"Alarms>member"` // A list of CloudWatch Alarms related to the policy
+ AutoScalingGroupName string `xml:"AutoScalingGroupName"`
+ Cooldown int `xml:"Cooldown"`
+ MinAdjustmentStep int `xml:"MinAdjustmentStep"` // Changes the DesiredCapacity of ASG by at least the specified number of instances.
+ PolicyARN string `xml:"PolicyARN"`
+ PolicyName string `xml:"PolicyName"`
+ ScalingAdjustment int `xml:"ScalingAdjustment"`
+}
+
+// DescribePolicies response wrapper
+//
+// http://goo.gl/bN7A9T for more details.
+type DescribePoliciesResp struct {
+ ScalingPolicies []ScalingPolicy `xml:"DescribePoliciesResult>ScalingPolicies>member"`
+ NextToken string `xml:"DescribePoliciesResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribePolicies returns descriptions of what each policy does.
+// Supports pagination by using the returned "NextToken" parameter for subsequent calls
+//
+// http://goo.gl/bN7A9Tfor more details.
+func (as *AutoScaling) DescribePolicies(asgName string, policyNames []string, maxRecords int, nextToken string) (
+ resp *DescribePoliciesResp, err error) {
+ params := makeParams("DescribePolicies")
+
+ if asgName != "" {
+ params["AutoScalingGroupName"] = asgName
+ }
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+ if len(policyNames) > 0 {
+ addParamsList(params, "PolicyNames.member", policyNames)
+ }
+
+ resp = new(DescribePoliciesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Activity encapsulates the Activity data type
+//
+// See http://goo.gl/fRaVi1 for more details
+type Activity struct {
+ ActivityId string `xml:"ActivityId"`
+ AutoScalingGroupName string `xml:"AutoScalingGroupName"`
+ Cause string `xml:"Cause"`
+ Description string `xml:"Description"`
+ Details string `xml:"Details"`
+ EndTime time.Time `xml:"EndTime"`
+ Progress int `xml:"Progress"`
+ StartTime time.Time `xml:"StartTime"`
+ StatusCode string `xml:"StatusCode"`
+ StatusMessage string `xml:"StatusMessage"`
+}
+
+// DescribeScalingActivities response wrapper
+//
+// http://goo.gl/noOXIC for more details.
+type DescribeScalingActivitiesResp struct {
+ Activities []Activity `xml:"DescribeScalingActivitiesResult>Activities>member"`
+ NextToken string `xml:"DescribeScalingActivitiesResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeScalingActivities returns the scaling activities for the specified Auto Scaling group.
+// Supports pagination by using the returned "NextToken" parameter for subsequent calls
+//
+// http://goo.gl/noOXIC more details.
+func (as *AutoScaling) DescribeScalingActivities(asgName string, activityIds []string, maxRecords int, nextToken string) (
+ resp *DescribeScalingActivitiesResp, err error) {
+ params := makeParams("DescribeScalingActivities")
+
+ if asgName != "" {
+ params["AutoScalingGroupName"] = asgName
+ }
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+ if len(activityIds) > 0 {
+ addParamsList(params, "ActivityIds.member", activityIds)
+ }
+
+ resp = new(DescribeScalingActivitiesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ProcessType encapsulates the Auto Scaling process data type
+//
+// See http://goo.gl/9BvNik for more details.
+type ProcessType struct {
+ ProcessName string `xml:"ProcessName"`
+}
+
+// DescribeScalingProcessTypes response wrapper
+//
+// See http://goo.gl/rkp2tw for more details.
+type DescribeScalingProcessTypesResp struct {
+ Processes []ProcessType `xml:"DescribeScalingProcessTypesResult>Processes>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeScalingProcessTypes returns scaling process types for use in the ResumeProcesses and SuspendProcesses actions.
+//
+// See http://goo.gl/rkp2tw for more details.
+func (as *AutoScaling) DescribeScalingProcessTypes() (resp *DescribeScalingProcessTypesResp, err error) {
+ params := makeParams("DescribeScalingProcessTypes")
+
+ resp = new(DescribeScalingProcessTypesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ScheduledUpdateGroupAction contains the information to be used in a scheduled update to an
+// AutoScalingGroup
+//
+// See http://goo.gl/z2Kfxe for more details
+type ScheduledUpdateGroupAction struct {
+ AutoScalingGroupName string `xml:"AutoScalingGroupName"`
+ DesiredCapacity int `xml:"DesiredCapacity"`
+ EndTime time.Time `xml:"EndTime"`
+ MaxSize int `xml:"MaxSize"`
+ MinSize int `xml:"MinSize"`
+ Recurrence string `xml:"Recurrence"`
+ ScheduledActionARN string `xml:"ScheduledActionARN"`
+ ScheduledActionName string `xml:"ScheduledActionName"`
+ StartTime time.Time `xml:"StartTime"`
+ Time time.Time `xml:"Time"`
+}
+
+// DescribeScheduledActionsResult contains the response from a DescribeScheduledActions.
+//
+// See http://goo.gl/zqrJLx for more details.
+type DescribeScheduledActionsResult struct {
+ ScheduledUpdateGroupActions []ScheduledUpdateGroupAction `xml:"DescribeScheduledActionsResult>ScheduledUpdateGroupActions>member"`
+ NextToken string `xml:"DescribeScheduledActionsResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ScheduledActionsRequestParams contains the items that can be specified when making
+// a ScheduledActions request
+type DescribeScheduledActionsParams struct {
+ AutoScalingGroupName string
+ EndTime time.Time
+ MaxRecords int
+ ScheduledActionNames []string
+ StartTime time.Time
+ NextToken string
+}
+
+// DescribeScheduledActions returns a list of the current scheduled actions. If the
+// AutoScalingGroup name is provided it will list all the scheduled actions for that group.
+//
+// See http://goo.gl/zqrJLx for more details.
+func (as *AutoScaling) DescribeScheduledActions(options *DescribeScheduledActionsParams) (
+ resp *DescribeScheduledActionsResult, err error) {
+ params := makeParams("DescribeScheduledActions")
+
+ if options.AutoScalingGroupName != "" {
+ params["AutoScalingGroupName"] = options.AutoScalingGroupName
+ }
+ if !options.StartTime.IsZero() {
+ params["StartTime"] = options.StartTime.Format(time.RFC3339)
+ }
+ if !options.EndTime.IsZero() {
+ params["EndTime"] = options.EndTime.Format(time.RFC3339)
+ }
+ if options.MaxRecords > 0 {
+ params["MaxRecords"] = strconv.Itoa(options.MaxRecords)
+ }
+ if options.NextToken != "" {
+ params["NextToken"] = options.NextToken
+ }
+ if len(options.ScheduledActionNames) > 0 {
+ addParamsList(params, "ScheduledActionNames.member", options.ScheduledActionNames)
+ }
+
+ resp = new(DescribeScheduledActionsResult)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeTags response wrapper
+//
+// See http://goo.gl/ZTEU3G for more details.
+type DescribeTagsResp struct {
+ Tags []Tag `xml:"DescribeTagsResult>Tags>member"`
+ NextToken string `xml:"DescribeTagsResult>NextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeTags lists the Auto Scaling group tags.
+// Supports pagination by using the returned "NextToken" parameter for subsequent calls
+//
+// See http://goo.gl/ZTEU3G for more details.
+func (as *AutoScaling) DescribeTags(filter *Filter, maxRecords int, nextToken string) (
+ resp *DescribeTagsResp, err error) {
+ params := makeParams("DescribeTags")
+
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ filter.addParams(params)
+
+ resp = new(DescribeTagsResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeTerminationPolicyTypes response wrapper
+//
+// See http://goo.gl/ZTEU3G for more details.
+type DescribeTerminationPolicyTypesResp struct {
+ TerminationPolicyTypes []string `xml:"DescribeTerminationPolicyTypesResult>TerminationPolicyTypes>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeTerminationPolicyTypes returns a list of all termination policies supported by Auto Scaling
+//
+// See http://goo.gl/ZTEU3G for more details.
+func (as *AutoScaling) DescribeTerminationPolicyTypes() (resp *DescribeTerminationPolicyTypesResp, err error) {
+ params := makeParams("DescribeTerminationPolicyTypes")
+
+ resp = new(DescribeTerminationPolicyTypesResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DetachInstancesResult wraps a DetachInstances response
+type DetachInstancesResult struct {
+ Activities []Activity `xml:"DetachInstancesResult>Activities>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DetachInstances removes an instance from an Auto Scaling group
+//
+// See http://goo.gl/cNwrqF for more details
+func (as *AutoScaling) DetachInstances(asgName string, instanceIds []string, decrementCapacity bool) (
+ resp *DetachInstancesResult, err error) {
+ params := makeParams("DetachInstances")
+ params["AutoScalingGroupName"] = asgName
+ params["ShouldDecrementDesiredCapacity"] = strconv.FormatBool(decrementCapacity)
+
+ if len(instanceIds) > 0 {
+ addParamsList(params, "InstanceIds.member", instanceIds)
+ }
+
+ resp = new(DetachInstancesResult)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DisableMetricsCollection disables monitoring of group metrics for the Auto Scaling group specified in asgName.
+// You can specify the list of affected metrics with the metrics parameter. If no metrics are specified, all metrics are disabled
+//
+// See http://goo.gl/kAvzQw for more details.
+func (as *AutoScaling) DisableMetricsCollection(asgName string, metrics []string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("DisableMetricsCollection")
+ params["AutoScalingGroupName"] = asgName
+
+ if len(metrics) > 0 {
+ addParamsList(params, "Metrics.member", metrics)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// EnableMetricsCollection enables monitoring of group metrics for the Auto Scaling group specified in asNmae.
+// You can specify the list of affected metrics with the metrics parameter.
+// Auto Scaling metrics collection can be turned on only if the InstanceMonitoring flag is set to true.
+// Currently, the only legal granularity is "1Minute".
+//
+// See http://goo.gl/UcVDWn for more details.
+func (as *AutoScaling) EnableMetricsCollection(asgName string, metrics []string, granularity string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("EnableMetricsCollection")
+ params["AutoScalingGroupName"] = asgName
+ params["Granularity"] = granularity
+
+ if len(metrics) > 0 {
+ addParamsList(params, "Metrics.member", metrics)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// EnterStandbyResult wraps an EnterStandby response
+type EnterStandbyResult struct {
+ Activities []Activity `xml:"EnterStandbyResult>Activities>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// EnterStandby moves instances in an Auto Scaling group into a Standby mode.
+//
+// See http://goo.gl/BJ3lXs for more information
+func (as *AutoScaling) EnterStandby(asgName string, instanceIds []string, decrementCapacity bool) (
+ resp *EnterStandbyResult, err error) {
+ params := makeParams("EnterStandby")
+ params["AutoScalingGroupName"] = asgName
+ params["ShouldDecrementDesiredCapacity"] = strconv.FormatBool(decrementCapacity)
+
+ if len(instanceIds) > 0 {
+ addParamsList(params, "InstanceIds.member", instanceIds)
+ }
+
+ resp = new(EnterStandbyResult)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ExecutePolicy executes the specified policy.
+//
+// See http://goo.gl/BxHpFc for more details.
+func (as *AutoScaling) ExecutePolicy(policyName string, asgName string, honorCooldown bool) (
+ resp *SimpleResp, err error) {
+ params := makeParams("ExecutePolicy")
+ params["PolicyName"] = policyName
+
+ if asgName != "" {
+ params["AutoScalingGroupName"] = asgName
+ }
+ if honorCooldown {
+ params["HonorCooldown"] = strconv.FormatBool(honorCooldown)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ExitStandbyResult wraps an ExitStandby response
+type ExitStandbyResult struct {
+ Activities []Activity `xml:"ExitStandbyResult>Activities>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ExitStandby moves an instance out of Standby mode.
+//
+// See http://goo.gl/9zQV4G for more information
+func (as *AutoScaling) ExitStandby(asgName string, instanceIds []string) (
+ resp *ExitStandbyResult, err error) {
+ params := makeParams("ExitStandby")
+ params["AutoScalingGroupName"] = asgName
+
+ if len(instanceIds) > 0 {
+ addParamsList(params, "InstanceIds.member", instanceIds)
+ }
+
+ resp = new(ExitStandbyResult)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// PutLifecycleHookParams wraps a PutLifecycleHook request
+//
+// See http://goo.gl/zsNqp5 for more details
+type PutLifecycleHookParams struct {
+ AutoScalingGroupName string
+ DefaultResult string
+ HeartbeatTimeout int
+ LifecycleHookName string
+ LifecycleTransition string
+ NotificationMetadata string
+ NotificationTargetARN string
+ RoleARN string
+}
+
+// PutLifecycleHook Creates or updates a lifecycle hook for an Auto Scaling Group.
+//
+// Part of the basic sequence for adding a lifecycle hook to an Auto Scaling group:
+// 1) Create a notification target (SQS queue || SNS Topic)
+// 2) Create an IAM role to allow the ASG topublish lifecycle notifications to the designated SQS queue or SNS topic
+// 3) *** Create the lifecycle hook. You can create a hook that acts when instances launch or when instances terminate***
+// 4) If necessary, record the lifecycle action heartbeat to keep the instance in a pending state
+// 5) Complete the lifecycle action
+//
+// See http://goo.gl/9XrROq for more details.
+func (as *AutoScaling) PutLifecycleHook(options *PutLifecycleHookParams) (
+ resp *SimpleResp, err error) {
+ params := makeParams("PutLifecycleHook")
+ params["AutoScalingGroupName"] = options.AutoScalingGroupName
+ params["LifecycleHookName"] = options.LifecycleHookName
+
+ if options.DefaultResult != "" {
+ params["DefaultResult"] = options.DefaultResult
+ }
+ if options.HeartbeatTimeout != 0 {
+ params["HeartbeatTimeout"] = strconv.Itoa(options.HeartbeatTimeout)
+ }
+ if options.LifecycleTransition != "" {
+ params["LifecycleTransition"] = options.LifecycleTransition
+ }
+ if options.NotificationMetadata != "" {
+ params["NotificationMetadata"] = options.NotificationMetadata
+ }
+ if options.NotificationTargetARN != "" {
+ params["NotificationTargetARN"] = options.NotificationTargetARN
+ }
+ if options.RoleARN != "" {
+ params["RoleARN"] = options.RoleARN
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// PutNotificationConfiguration configures an Auto Scaling group to send notifications when specified events take place.
+//
+// See http://goo.gl/9XrROq for more details.
+func (as *AutoScaling) PutNotificationConfiguration(asgName string, notificationTypes []string, topicARN string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("PutNotificationConfiguration")
+ params["AutoScalingGroupName"] = asgName
+ params["TopicARN"] = topicARN
+
+ if len(notificationTypes) > 0 {
+ addParamsList(params, "NotificationTypes.member", notificationTypes)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// PutScalingPolicyParams wraps a PutScalingPolicyParams request
+//
+// See http://goo.gl/o0E8hl for more details.
+type PutScalingPolicyParams struct {
+ AutoScalingGroupName string
+ PolicyName string
+ ScalingAdjustment int
+ AdjustmentType string
+ Cooldown int
+ MinAdjustmentStep int
+}
+
+// PutScalingPolicy response wrapper
+//
+// See http://goo.gl/o0E8hl for more details.
+type PutScalingPolicyResp struct {
+ PolicyARN string `xml:"PutScalingPolicyResult>PolicyARN"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// PutScalingPolicy creates or updates a policy for an Auto Scaling group
+//
+// See http://goo.gl/o0E8hl for more details.
+func (as *AutoScaling) PutScalingPolicy(options *PutScalingPolicyParams) (
+ resp *PutScalingPolicyResp, err error) {
+ params := makeParams("PutScalingPolicy")
+ params["AutoScalingGroupName"] = options.AutoScalingGroupName
+ params["PolicyName"] = options.PolicyName
+ params["ScalingAdjustment"] = strconv.Itoa(options.ScalingAdjustment)
+ params["AdjustmentType"] = options.AdjustmentType
+
+ if options.Cooldown != 0 {
+ params["Cooldown"] = strconv.Itoa(options.Cooldown)
+ }
+ if options.MinAdjustmentStep != 0 {
+ params["MinAdjustmentStep"] = strconv.Itoa(options.MinAdjustmentStep)
+ }
+
+ resp = new(PutScalingPolicyResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// PutScheduledUpdateGroupActionParams contains the details of the ScheduledAction to be added.
+//
+// See http://goo.gl/sLPi0d for more details
+type PutScheduledUpdateGroupActionParams struct {
+ AutoScalingGroupName string
+ DesiredCapacity int
+ EndTime time.Time
+ MaxSize int
+ MinSize int
+ Recurrence string
+ ScheduledActionName string
+ StartTime time.Time
+}
+
+// PutScheduledUpdateGroupAction creates or updates a scheduled scaling action for an
+// AutoScaling group. Scheduled actions can be made up to thirty days in advance. When updating
+// a scheduled scaling action, if you leave a parameter unspecified, the corresponding value
+// remains unchanged in the affected AutoScaling group.
+//
+// Auto Scaling supports the date and time expressed in "YYYY-MM-DDThh:mm:ssZ" format in UTC/GMT
+// only.
+//
+// See http://goo.gl/sLPi0d for more details.
+func (as *AutoScaling) PutScheduledUpdateGroupAction(options *PutScheduledUpdateGroupActionParams) (
+ resp *SimpleResp, err error) {
+ params := makeParams("PutScheduledUpdateGroupAction")
+ params["AutoScalingGroupName"] = options.AutoScalingGroupName
+ params["ScheduledActionName"] = options.ScheduledActionName
+ params["MinSize"] = strconv.Itoa(options.MinSize)
+ params["MaxSize"] = strconv.Itoa(options.MaxSize)
+ params["DesiredCapacity"] = strconv.Itoa(options.DesiredCapacity)
+
+ if !options.StartTime.IsZero() {
+ params["StartTime"] = options.StartTime.Format(time.RFC3339)
+ }
+ if !options.EndTime.IsZero() {
+ params["EndTime"] = options.EndTime.Format(time.RFC3339)
+ }
+ if options.Recurrence != "" {
+ params["Recurrence"] = options.Recurrence
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// RecordLifecycleActionHeartbeat ecords a heartbeat for the lifecycle action associated with a specific token.
+// This extends the timeout by the length of time defined by the HeartbeatTimeout parameter of the
+// PutLifecycleHook operation.
+//
+// Part of the basic sequence for adding a lifecycle hook to an Auto Scaling group:
+// 1) Create a notification target (SQS queue || SNS Topic)
+// 2) Create an IAM role to allow the ASG topublish lifecycle notifications to the designated SQS queue or SNS topic
+// 3) Create the lifecycle hook. You can create a hook that acts when instances launch or when instances terminate
+// 4) ***If necessary, record the lifecycle action heartbeat to keep the instance in a pending state***
+// 5) Complete the lifecycle action
+//
+// See http://goo.gl/jc70xp for more details.
+func (as *AutoScaling) RecordLifecycleActionHeartbeat(asgName, lifecycleActionToken, hookName string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("RecordLifecycleActionHeartbeat")
+ params["AutoScalingGroupName"] = asgName
+ params["LifecycleActionToken"] = lifecycleActionToken
+ params["LifecycleHookName"] = hookName
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ResumeProcesses resumes the scaling processes for the scaling group. If no processes are
+// provided, all processes are resumed.
+//
+// See http://goo.gl/XWIIg1 for more details.
+func (as *AutoScaling) ResumeProcesses(asgName string, processes []string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("ResumeProcesses")
+ params["AutoScalingGroupName"] = asgName
+
+ if len(processes) > 0 {
+ addParamsList(params, "ScalingProcesses.member", processes)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// SetDesiredCapacity changes the DesiredCapacity of an AutoScaling group.
+//
+// See http://goo.gl/3WGZbI for more details.
+func (as *AutoScaling) SetDesiredCapacity(asgName string, desiredCapacity int, honorCooldown bool) (
+ resp *SimpleResp, err error) {
+ params := makeParams("SetDesiredCapacity")
+ params["AutoScalingGroupName"] = asgName
+ params["DesiredCapacity"] = strconv.Itoa(desiredCapacity)
+ params["HonorCooldown"] = strconv.FormatBool(honorCooldown)
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// SetInstanceHealth sets the health status of a specified instance that belongs to any of your Auto Scaling groups.
+//
+// See http://goo.gl/j4ZRxh for more details.
+func (as *AutoScaling) SetInstanceHealth(id string, healthStatus string, respectGracePeriod bool) (
+ resp *SimpleResp, err error) {
+ params := makeParams("SetInstanceHealth")
+ params["HealthStatus"] = healthStatus
+ params["InstanceId"] = id
+ // Default is true
+ params["ShouldRespectGracePeriod"] = strconv.FormatBool(respectGracePeriod)
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// SuspendProcesses suspends the processes for the autoscaling group. If no processes are
+// provided, all processes are suspended.
+//
+// If you suspend either of the two primary processes (Launch or Terminate), this can prevent other
+// process types from functioning properly.
+//
+// See http://goo.gl/DUJpQy for more details.
+func (as *AutoScaling) SuspendProcesses(asgName string, processes []string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("SuspendProcesses")
+ params["AutoScalingGroupName"] = asgName
+
+ if len(processes) > 0 {
+ addParamsList(params, "ScalingProcesses.member", processes)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// TerminateInstanceInAutoScalingGroupResp response wrapper
+//
+// See http://goo.gl/ki5hMh for more details.
+type TerminateInstanceInAutoScalingGroupResp struct {
+ Activity Activity `xml:"TerminateInstanceInAutoScalingGroupResult>Activity"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// TerminateInstanceInAutoScalingGroup terminates the specified instance.
+// Optionally, the desired group size can be adjusted by setting decrCap to true
+//
+// See http://goo.gl/ki5hMh for more details.
+func (as *AutoScaling) TerminateInstanceInAutoScalingGroup(id string, decrCap bool) (
+ resp *TerminateInstanceInAutoScalingGroupResp, err error) {
+ params := makeParams("TerminateInstanceInAutoScalingGroup")
+ params["InstanceId"] = id
+ params["ShouldDecrementDesiredCapacity"] = strconv.FormatBool(decrCap)
+
+ resp = new(TerminateInstanceInAutoScalingGroupResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// UpdateAutoScalingGroup updates the scaling group.
+//
+// To update an auto scaling group with a launch configuration that has the InstanceMonitoring
+// flag set to False, you must first ensure that collection of group metrics is disabled.
+// Otherwise calls to UpdateAutoScalingGroup will fail.
+//
+// See http://goo.gl/rqrmxy for more details.
+func (as *AutoScaling) UpdateAutoScalingGroup(asg *AutoScalingGroup) (resp *SimpleResp, err error) {
+ params := makeParams("UpdateAutoScalingGroup")
+
+ params["AutoScalingGroupName"] = asg.AutoScalingGroupName
+ params["MaxSize"] = strconv.Itoa(asg.MaxSize)
+ params["MinSize"] = strconv.Itoa(asg.MinSize)
+ params["DesiredCapacity"] = strconv.Itoa(asg.DesiredCapacity)
+
+ if asg.DefaultCooldown > 0 {
+ params["DefaultCooldown"] = strconv.Itoa(asg.DefaultCooldown)
+ }
+ if asg.HealthCheckGracePeriod > 0 {
+ params["HealthCheckGracePeriod"] = strconv.Itoa(asg.HealthCheckGracePeriod)
+ }
+ if asg.HealthCheckType != "" {
+ params["HealthCheckType"] = asg.HealthCheckType
+ }
+ if asg.LaunchConfigurationName != "" {
+ params["LaunchConfigurationName"] = asg.LaunchConfigurationName
+ }
+ if asg.PlacementGroup != "" {
+ params["PlacementGroup"] = asg.PlacementGroup
+ }
+ if asg.VPCZoneIdentifier != "" {
+ params["VPCZoneIdentifier"] = asg.VPCZoneIdentifier
+ }
+
+ if len(asg.AvailabilityZones) > 0 {
+ addParamsList(params, "AvailabilityZones.member", asg.AvailabilityZones)
+ }
+ if len(asg.TerminationPolicies) > 0 {
+ addParamsList(params, "TerminationPolicies.member", asg.TerminationPolicies)
+ }
+
+ resp = new(SimpleResp)
+ if err := as.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
diff --git a/vendor/github.com/goamz/goamz/autoscaling/autoscaling_test.go b/vendor/github.com/goamz/goamz/autoscaling/autoscaling_test.go
new file mode 100644
index 000000000..b728a1cf4
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/autoscaling/autoscaling_test.go
@@ -0,0 +1,1180 @@
+package autoscaling
+
+import (
+ "testing"
+ "time"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/testutil"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ as *AutoScaling
+}
+
+var testServer = testutil.NewHTTPServer()
+
+var mockTest bool
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.as = New(auth, aws.Region{AutoScalingEndpoint: testServer.URL})
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func TestBasicGroupRequest(t *testing.T) {
+ var as *AutoScaling
+ awsAuth, err := aws.EnvAuth()
+ if err != nil {
+ mockTest = true
+ t.Log("Running mock tests as AWS environment variables are not set")
+ awsAuth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ as = New(awsAuth, aws.Region{AutoScalingEndpoint: testServer.URL})
+ testServer.Start()
+ go testServer.WaitRequest()
+ testServer.Response(200, nil, BasicGroupResponse)
+ } else {
+ as = New(awsAuth, aws.USWest2)
+ }
+
+ groupResp, err := as.DescribeAutoScalingGroups(nil, 10, "")
+
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(groupResp.AutoScalingGroups) > 0 {
+ firstGroup := groupResp.AutoScalingGroups[0]
+ if len(firstGroup.AutoScalingGroupName) > 0 {
+ t.Logf("Found AutoScaling group %s\n",
+ firstGroup.AutoScalingGroupName)
+ }
+ }
+ testServer.Flush()
+}
+
+func TestAutoScalingGroup(t *testing.T) {
+ var as *AutoScaling
+ // Launch configuration test config
+ lc := new(LaunchConfiguration)
+ lc.LaunchConfigurationName = "LConf1"
+ lc.ImageId = "ami-03e47533" // Octave debian ami
+ lc.KernelId = "aki-98e26fa8"
+ lc.KeyName = "testAWS" // Replace with valid key for your account
+ lc.InstanceType = "m1.small"
+
+ // CreateAutoScalingGroup params test config
+ asgReq := new(CreateAutoScalingGroupParams)
+ asgReq.AutoScalingGroupName = "ASGTest1"
+ asgReq.LaunchConfigurationName = lc.LaunchConfigurationName
+ asgReq.DefaultCooldown = 300
+ asgReq.HealthCheckGracePeriod = 300
+ asgReq.DesiredCapacity = 1
+ asgReq.MinSize = 1
+ asgReq.MaxSize = 5
+ asgReq.AvailabilityZones = []string{"us-west-2a"}
+
+ asg := new(AutoScalingGroup)
+ asg.AutoScalingGroupName = "ASGTest1"
+ asg.LaunchConfigurationName = lc.LaunchConfigurationName
+ asg.DefaultCooldown = 300
+ asg.HealthCheckGracePeriod = 300
+ asg.DesiredCapacity = 1
+ asg.MinSize = 1
+ asg.MaxSize = 5
+ asg.AvailabilityZones = []string{"us-west-2a"}
+
+ awsAuth, err := aws.EnvAuth()
+ if err != nil {
+ mockTest = true
+ t.Log("Running mock tests as AWS environment variables are not set")
+ awsAuth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ as = New(awsAuth, aws.Region{AutoScalingEndpoint: testServer.URL})
+ } else {
+ as = New(awsAuth, aws.USWest2)
+ }
+
+ // Create the launch configuration
+ if mockTest {
+ testServer.Response(200, nil, CreateLaunchConfigurationResponse)
+ }
+ _, err = as.CreateLaunchConfiguration(lc)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Check that we can get the launch configuration details
+ if mockTest {
+ testServer.Response(200, nil, DescribeLaunchConfigurationsResponse)
+ }
+ _, err = as.DescribeLaunchConfigurations([]string{lc.LaunchConfigurationName}, 10, "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Create the AutoScalingGroup
+ if mockTest {
+ testServer.Response(200, nil, CreateAutoScalingGroupResponse)
+ }
+ _, err = as.CreateAutoScalingGroup(asgReq)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Check that we can get the autoscaling group details
+ if mockTest {
+ testServer.Response(200, nil, DescribeAutoScalingGroupsResponse)
+ }
+ _, err = as.DescribeAutoScalingGroups(nil, 10, "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Suspend the scaling processes for the test AutoScalingGroup
+ if mockTest {
+ testServer.Response(200, nil, SuspendProcessesResponse)
+ }
+ _, err = as.SuspendProcesses(asg.AutoScalingGroupName, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Resume scaling processes for the test AutoScalingGroup
+ if mockTest {
+ testServer.Response(200, nil, ResumeProcessesResponse)
+ }
+ _, err = as.ResumeProcesses(asg.AutoScalingGroupName, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Change the desired capacity from 1 to 2. This will launch a second instance
+ if mockTest {
+ testServer.Response(200, nil, SetDesiredCapacityResponse)
+ }
+ _, err = as.SetDesiredCapacity(asg.AutoScalingGroupName, 2, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Change the desired capacity from 2 to 1. This will terminate one of the instances
+ if mockTest {
+ testServer.Response(200, nil, SetDesiredCapacityResponse)
+ }
+
+ _, err = as.SetDesiredCapacity(asg.AutoScalingGroupName, 1, false)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Update the max capacity for the scaling group
+ if mockTest {
+ testServer.Response(200, nil, UpdateAutoScalingGroupResponse)
+ }
+ asg.MinSize = 1
+ asg.MaxSize = 6
+ asg.DesiredCapacity = 1
+ _, err = as.UpdateAutoScalingGroup(asg)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Add a scheduled action to the group
+ psar := new(PutScheduledUpdateGroupActionParams)
+ psar.AutoScalingGroupName = asg.AutoScalingGroupName
+ psar.MaxSize = 4
+ psar.ScheduledActionName = "SATest1"
+ psar.Recurrence = "30 0 1 1,6,12 *"
+ if mockTest {
+ testServer.Response(200, nil, PutScheduledUpdateGroupActionResponse)
+ }
+ _, err = as.PutScheduledUpdateGroupAction(psar)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // List the scheduled actions for the group
+ sar := new(DescribeScheduledActionsParams)
+ sar.AutoScalingGroupName = asg.AutoScalingGroupName
+ if mockTest {
+ testServer.Response(200, nil, DescribeScheduledActionsResponse)
+ }
+ _, err = as.DescribeScheduledActions(sar)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Delete the test scheduled action from the group
+ if mockTest {
+ testServer.Response(200, nil, DeleteScheduledActionResponse)
+ }
+ _, err = as.DeleteScheduledAction(asg.AutoScalingGroupName, psar.ScheduledActionName)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testServer.Flush()
+}
+
+// --------------------------------------------------------------------------
+// Detailed Unit Tests
+
+func (s *S) TestAttachInstances(c *C) {
+ testServer.Response(200, nil, AttachInstancesResponse)
+ resp, err := s.as.AttachInstances("my-test-asg", []string{"i-21321afs", "i-baaffg23"})
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "AttachInstances")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("InstanceIds.member.1"), Equals, "i-21321afs")
+ c.Assert(values.Get("InstanceIds.member.2"), Equals, "i-baaffg23")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestCreateAutoScalingGroup(c *C) {
+ testServer.Response(200, nil, CreateAutoScalingGroupResponse)
+ testServer.Response(200, nil, DeleteAutoScalingGroupResponse)
+
+ createAS := &CreateAutoScalingGroupParams{
+ AutoScalingGroupName: "my-test-asg",
+ AvailabilityZones: []string{"us-east-1a", "us-east-1b"},
+ MinSize: 3,
+ MaxSize: 3,
+ DefaultCooldown: 600,
+ DesiredCapacity: 0,
+ LaunchConfigurationName: "my-test-lc",
+ LoadBalancerNames: []string{"elb-1", "elb-2"},
+ Tags: []Tag{
+ {
+ Key: "foo",
+ Value: "bar",
+ },
+ {
+ Key: "baz",
+ Value: "qux",
+ },
+ },
+ VPCZoneIdentifier: "subnet-610acd08,subnet-530fc83a",
+ }
+ resp, err := s.as.CreateAutoScalingGroup(createAS)
+ c.Assert(err, IsNil)
+ defer s.as.DeleteAutoScalingGroup(createAS.AutoScalingGroupName, true)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "CreateAutoScalingGroup")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("AvailabilityZones.member.1"), Equals, "us-east-1a")
+ c.Assert(values.Get("AvailabilityZones.member.2"), Equals, "us-east-1b")
+ c.Assert(values.Get("MinSize"), Equals, "3")
+ c.Assert(values.Get("MaxSize"), Equals, "3")
+ c.Assert(values.Get("DefaultCooldown"), Equals, "600")
+ c.Assert(values.Get("DesiredCapacity"), Equals, "0")
+ c.Assert(values.Get("LaunchConfigurationName"), Equals, "my-test-lc")
+ c.Assert(values.Get("LoadBalancerNames.member.1"), Equals, "elb-1")
+ c.Assert(values.Get("LoadBalancerNames.member.2"), Equals, "elb-2")
+ c.Assert(values.Get("Tags.member.1.Key"), Equals, "foo")
+ c.Assert(values.Get("Tags.member.1.Value"), Equals, "bar")
+ c.Assert(values.Get("Tags.member.2.Key"), Equals, "baz")
+ c.Assert(values.Get("Tags.member.2.Value"), Equals, "qux")
+ c.Assert(values.Get("VPCZoneIdentifier"), Equals, "subnet-610acd08,subnet-530fc83a")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestCreateLaunchConfiguration(c *C) {
+ testServer.Response(200, nil, CreateLaunchConfigurationResponse)
+ testServer.Response(200, nil, DeleteLaunchConfigurationResponse)
+
+ launchConfig := &LaunchConfiguration{
+ LaunchConfigurationName: "my-test-lc",
+ AssociatePublicIpAddress: true,
+ EbsOptimized: true,
+ SecurityGroups: []string{"sec-grp1", "sec-grp2"},
+ UserData: "1234",
+ KeyName: "secretKeyPair",
+ ImageId: "ami-0078da69",
+ InstanceType: "m1.small",
+ SpotPrice: "0.03",
+ BlockDeviceMappings: []BlockDeviceMapping{
+ {
+ DeviceName: "/dev/sda1",
+ VirtualName: "ephemeral0",
+ },
+ {
+ DeviceName: "/dev/sdb",
+ VirtualName: "ephemeral1",
+ },
+ {
+ DeviceName: "/dev/sdf",
+ Ebs: EBS{
+ DeleteOnTermination: true,
+ SnapshotId: "snap-2a2b3c4d",
+ VolumeSize: 100,
+ },
+ },
+ },
+ InstanceMonitoring: InstanceMonitoring{
+ Enabled: true,
+ },
+ }
+ resp, err := s.as.CreateLaunchConfiguration(launchConfig)
+ c.Assert(err, IsNil)
+ defer s.as.DeleteLaunchConfiguration(launchConfig.LaunchConfigurationName)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "CreateLaunchConfiguration")
+ c.Assert(values.Get("LaunchConfigurationName"), Equals, "my-test-lc")
+ c.Assert(values.Get("AssociatePublicIpAddress"), Equals, "true")
+ c.Assert(values.Get("EbsOptimized"), Equals, "true")
+ c.Assert(values.Get("SecurityGroups.member.1"), Equals, "sec-grp1")
+ c.Assert(values.Get("SecurityGroups.member.2"), Equals, "sec-grp2")
+ c.Assert(values.Get("UserData"), Equals, "MTIzNA==")
+ c.Assert(values.Get("KeyName"), Equals, "secretKeyPair")
+ c.Assert(values.Get("ImageId"), Equals, "ami-0078da69")
+ c.Assert(values.Get("InstanceType"), Equals, "m1.small")
+ c.Assert(values.Get("SpotPrice"), Equals, "0.03")
+ c.Assert(values.Get("BlockDeviceMappings.member.1.DeviceName"), Equals, "/dev/sda1")
+ c.Assert(values.Get("BlockDeviceMappings.member.1.VirtualName"), Equals, "ephemeral0")
+ c.Assert(values.Get("BlockDeviceMappings.member.2.DeviceName"), Equals, "/dev/sdb")
+ c.Assert(values.Get("BlockDeviceMappings.member.2.VirtualName"), Equals, "ephemeral1")
+ c.Assert(values.Get("BlockDeviceMappings.member.3.DeviceName"), Equals, "/dev/sdf")
+ c.Assert(values.Get("BlockDeviceMappings.member.3.Ebs.DeleteOnTermination"), Equals, "true")
+ c.Assert(values.Get("BlockDeviceMappings.member.3.Ebs.SnapshotId"), Equals, "snap-2a2b3c4d")
+ c.Assert(values.Get("BlockDeviceMappings.member.3.Ebs.VolumeSize"), Equals, "100")
+ c.Assert(values.Get("InstanceMonitoring.Enabled"), Equals, "true")
+ c.Assert(resp.RequestId, Equals, "7c6e177f-f082-11e1-ac58-3714bEXAMPLE")
+}
+
+func (s *S) TestCreateOrUpdateTags(c *C) {
+ testServer.Response(200, nil, CreateOrUpdateTagsResponse)
+ tags := []Tag{
+ {
+ Key: "foo",
+ Value: "bar",
+ ResourceId: "my-test-asg",
+ },
+ {
+ Key: "baz",
+ Value: "qux",
+ ResourceId: "my-test-asg",
+ PropagateAtLaunch: true,
+ },
+ }
+ resp, err := s.as.CreateOrUpdateTags(tags)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "CreateOrUpdateTags")
+ c.Assert(values.Get("Tags.member.1.Key"), Equals, "foo")
+ c.Assert(values.Get("Tags.member.1.Value"), Equals, "bar")
+ c.Assert(values.Get("Tags.member.1.ResourceId"), Equals, "my-test-asg")
+ c.Assert(values.Get("Tags.member.2.Key"), Equals, "baz")
+ c.Assert(values.Get("Tags.member.2.Value"), Equals, "qux")
+ c.Assert(values.Get("Tags.member.2.ResourceId"), Equals, "my-test-asg")
+ c.Assert(values.Get("Tags.member.2.PropagateAtLaunch"), Equals, "true")
+ c.Assert(resp.RequestId, Equals, "b0203919-bf1b-11e2-8a01-13263EXAMPLE")
+}
+
+func (s *S) TestDeleteAutoScalingGroup(c *C) {
+ testServer.Response(200, nil, DeleteAutoScalingGroupResponse)
+ resp, err := s.as.DeleteAutoScalingGroup("my-test-asg", true)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DeleteAutoScalingGroup")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(resp.RequestId, Equals, "70a76d42-9665-11e2-9fdf-211deEXAMPLE")
+}
+
+func (s *S) TestDeleteAutoScalingGroupWithExistingInstances(c *C) {
+ testServer.Response(400, nil, DeleteAutoScalingGroupErrorResponse)
+ resp, err := s.as.DeleteAutoScalingGroup("my-test-asg", false)
+ testServer.WaitRequest()
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ e, ok := err.(*Error)
+ if !ok {
+ c.Errorf("Unable to unmarshal error into AWS Autoscaling Error")
+ }
+ c.Assert(ok, Equals, true)
+ c.Assert(e.Message, Equals, "You cannot delete an AutoScalingGroup while there are instances or pending Spot instance request(s) still in the group.")
+ c.Assert(e.Code, Equals, "ResourceInUse")
+ c.Assert(e.StatusCode, Equals, 400)
+ c.Assert(e.RequestId, Equals, "70a76d42-9665-11e2-9fdf-211deEXAMPLE")
+}
+
+func (s *S) TestDeleteLaunchConfiguration(c *C) {
+ testServer.Response(200, nil, DeleteLaunchConfigurationResponse)
+ resp, err := s.as.DeleteLaunchConfiguration("my-test-lc")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DeleteLaunchConfiguration")
+ c.Assert(values.Get("LaunchConfigurationName"), Equals, "my-test-lc")
+ c.Assert(resp.RequestId, Equals, "7347261f-97df-11e2-8756-35eEXAMPLE")
+}
+
+func (s *S) TestDeleteLaunchConfigurationInUse(c *C) {
+ testServer.Response(400, nil, DeleteLaunchConfigurationInUseResponse)
+ resp, err := s.as.DeleteLaunchConfiguration("my-test-lc")
+ testServer.WaitRequest()
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ e, ok := err.(*Error)
+ if !ok {
+ c.Errorf("Unable to unmarshal error into AWS Autoscaling Error")
+ }
+ c.Logf("%v %v %v", e.Code, e.Message, e.RequestId)
+ c.Assert(ok, Equals, true)
+ c.Assert(e.Message, Equals, "Cannot delete launch configuration my-test-lc because it is attached to AutoScalingGroup test")
+ c.Assert(e.Code, Equals, "ResourceInUse")
+ c.Assert(e.StatusCode, Equals, 400)
+ c.Assert(e.RequestId, Equals, "7347261f-97df-11e2-8756-35eEXAMPLE")
+}
+
+func (s *S) TestDeleteTags(c *C) {
+ testServer.Response(200, nil, DeleteTagsResponse)
+ tags := []Tag{
+ {
+ Key: "foo",
+ Value: "bar",
+ ResourceId: "my-test-asg",
+ },
+ {
+ Key: "baz",
+ Value: "qux",
+ ResourceId: "my-test-asg",
+ PropagateAtLaunch: true,
+ },
+ }
+ resp, err := s.as.DeleteTags(tags)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DeleteTags")
+ c.Assert(values.Get("Tags.member.1.Key"), Equals, "foo")
+ c.Assert(values.Get("Tags.member.1.Value"), Equals, "bar")
+ c.Assert(values.Get("Tags.member.1.ResourceId"), Equals, "my-test-asg")
+ c.Assert(values.Get("Tags.member.2.Key"), Equals, "baz")
+ c.Assert(values.Get("Tags.member.2.Value"), Equals, "qux")
+ c.Assert(values.Get("Tags.member.2.ResourceId"), Equals, "my-test-asg")
+ c.Assert(values.Get("Tags.member.2.PropagateAtLaunch"), Equals, "true")
+ c.Assert(resp.RequestId, Equals, "b0203919-bf1b-11e2-8a01-13263EXAMPLE")
+}
+
+func (s *S) TestDescribeAccountLimits(c *C) {
+ testServer.Response(200, nil, DescribeAccountLimitsResponse)
+
+ resp, err := s.as.DescribeAccountLimits()
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeAccountLimits")
+ c.Assert(resp.RequestId, Equals, "a32bd184-519d-11e3-a8a4-c1c467cbcc3b")
+ c.Assert(resp.MaxNumberOfAutoScalingGroups, Equals, 20)
+ c.Assert(resp.MaxNumberOfLaunchConfigurations, Equals, 100)
+
+}
+
+func (s *S) TestDescribeAdjustmentTypes(c *C) {
+ testServer.Response(200, nil, DescribeAdjustmentTypesResponse)
+ resp, err := s.as.DescribeAdjustmentTypes()
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeAdjustmentTypes")
+ c.Assert(resp.RequestId, Equals, "cc5f0337-b694-11e2-afc0-6544dEXAMPLE")
+ c.Assert(resp.AdjustmentTypes, DeepEquals, []AdjustmentType{{"ChangeInCapacity"}, {"ExactCapacity"}, {"PercentChangeInCapacity"}})
+}
+
+func (s *S) TestDescribeAutoScalingGroups(c *C) {
+ testServer.Response(200, nil, DescribeAutoScalingGroupsResponse)
+ resp, err := s.as.DescribeAutoScalingGroups([]string{"my-test-asg-lbs"}, 0, "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ t, _ := time.Parse(time.RFC3339, "2013-05-06T17:47:15.107Z")
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeAutoScalingGroups")
+ c.Assert(values.Get("AutoScalingGroupNames.member.1"), Equals, "my-test-asg-lbs")
+
+ expected := &DescribeAutoScalingGroupsResp{
+ AutoScalingGroups: []AutoScalingGroup{
+ {
+ AutoScalingGroupName: "my-test-asg-lbs",
+ Tags: []Tag{
+ {
+ Key: "foo",
+ Value: "bar",
+ ResourceId: "my-test-asg-lbs",
+ PropagateAtLaunch: true,
+ ResourceType: "auto-scaling-group",
+ },
+ {
+ Key: "baz",
+ Value: "qux",
+ ResourceId: "my-test-asg-lbs",
+ PropagateAtLaunch: true,
+ ResourceType: "auto-scaling-group",
+ },
+ },
+ Instances: []Instance{
+ {
+ AvailabilityZone: "us-east-1b",
+ HealthStatus: "Healthy",
+ InstanceId: "i-zb1f313",
+ LaunchConfigurationName: "my-test-lc",
+ LifecycleState: "InService",
+ },
+ {
+ AvailabilityZone: "us-east-1a",
+ HealthStatus: "Healthy",
+ InstanceId: "i-90123adv",
+ LaunchConfigurationName: "my-test-lc",
+ LifecycleState: "InService",
+ },
+ },
+ HealthCheckType: "ELB",
+ CreatedTime: t,
+ LaunchConfigurationName: "my-test-lc",
+ DesiredCapacity: 2,
+ AvailabilityZones: []string{"us-east-1b", "us-east-1a"},
+ LoadBalancerNames: []string{"my-test-asg-loadbalancer"},
+ MinSize: 2,
+ MaxSize: 10,
+ VPCZoneIdentifier: "subnet-32131da1,subnet-1312dad2",
+ HealthCheckGracePeriod: 120,
+ DefaultCooldown: 300,
+ AutoScalingGroupARN: "arn:aws:autoscaling:us-east-1:803981987763:autoScalingGroup:ca861182-c8f9-4ca7-b1eb-cd35505f5ebb:autoScalingGroupName/my-test-asg-lbs",
+ TerminationPolicies: []string{"Default"},
+ },
+ },
+ RequestId: "0f02a07d-b677-11e2-9eb0-dd50EXAMPLE",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeAutoScalingInstances(c *C) {
+ testServer.Response(200, nil, DescribeAutoScalingInstancesResponse)
+ resp, err := s.as.DescribeAutoScalingInstances([]string{"i-78e0d40b"}, 0, "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeAutoScalingInstances")
+ c.Assert(resp.RequestId, Equals, "df992dc3-b72f-11e2-81e1-750aa6EXAMPLE")
+ c.Assert(resp.AutoScalingInstances, DeepEquals, []Instance{
+ {
+ AutoScalingGroupName: "my-test-asg",
+ AvailabilityZone: "us-east-1a",
+ HealthStatus: "Healthy",
+ InstanceId: "i-78e0d40b",
+ LaunchConfigurationName: "my-test-lc",
+ LifecycleState: "InService",
+ },
+ })
+}
+
+func (s *S) TestDescribeLaunchConfigurations(c *C) {
+ testServer.Response(200, nil, DescribeLaunchConfigurationsResponse)
+ resp, err := s.as.DescribeLaunchConfigurations([]string{"my-test-lc"}, 0, "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ t, _ := time.Parse(time.RFC3339, "2013-01-21T23:04:42.200Z")
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeLaunchConfigurations")
+ c.Assert(values.Get("LaunchConfigurationNames.member.1"), Equals, "my-test-lc")
+ expected := &DescribeLaunchConfigurationsResp{
+ LaunchConfigurations: []LaunchConfiguration{
+ {
+ AssociatePublicIpAddress: true,
+ BlockDeviceMappings: []BlockDeviceMapping{
+ {
+ DeviceName: "/dev/sdb",
+ VirtualName: "ephemeral0",
+ },
+ {
+ DeviceName: "/dev/sdf",
+ Ebs: EBS{
+ SnapshotId: "snap-XXXXYYY",
+ VolumeSize: 100,
+ Iops: 50,
+ VolumeType: "io1",
+ DeleteOnTermination: true,
+ },
+ },
+ },
+ EbsOptimized: false,
+ CreatedTime: t,
+ LaunchConfigurationName: "my-test-lc",
+ InstanceType: "m1.small",
+ ImageId: "ami-514ac838",
+ InstanceMonitoring: InstanceMonitoring{Enabled: true},
+ LaunchConfigurationARN: "arn:aws:autoscaling:us-east-1:803981987763:launchConfiguration:9dbbbf87-6141-428a-a409-0752edbe6cad:launchConfigurationName/my-test-lc",
+ },
+ },
+ RequestId: "d05a22f8-b690-11e2-bf8e-2113fEXAMPLE",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeMetricCollectionTypes(c *C) {
+ testServer.Response(200, nil, DescribeMetricCollectionTypesResponse)
+ resp, err := s.as.DescribeMetricCollectionTypes()
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeMetricCollectionTypes")
+ c.Assert(resp.RequestId, Equals, "07f3fea2-bf3c-11e2-9b6f-f3cdbb80c073")
+ c.Assert(resp.Metrics, DeepEquals, []MetricCollection{
+ {
+ Metric: "GroupMinSize",
+ },
+ {
+ Metric: "GroupMaxSize",
+ },
+ {
+ Metric: "GroupDesiredCapacity",
+ },
+ {
+ Metric: "GroupInServiceInstances",
+ },
+ {
+ Metric: "GroupPendingInstances",
+ },
+ {
+ Metric: "GroupTerminatingInstances",
+ },
+ {
+ Metric: "GroupTotalInstances",
+ },
+ })
+ c.Assert(resp.Granularities, DeepEquals, []MetricGranularity{
+ {
+ Granularity: "1Minute",
+ },
+ })
+}
+
+func (s *S) TestDescribeNotificationConfigurations(c *C) {
+ testServer.Response(200, nil, DescribeNotificationConfigurationsResponse)
+ resp, err := s.as.DescribeNotificationConfigurations([]string{"i-78e0d40b"}, 0, "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeNotificationConfigurations")
+ c.Assert(resp.RequestId, Equals, "07f3fea2-bf3c-11e2-9b6f-f3cdbb80c073")
+ c.Assert(resp.NotificationConfigurations, DeepEquals, []NotificationConfiguration{
+ {
+ AutoScalingGroupName: "my-test-asg",
+ NotificationType: "autoscaling: EC2_INSTANCE_LAUNCH",
+ TopicARN: "vajdoafj231j41231/topic",
+ },
+ })
+}
+
+func (s *S) TestDescribePolicies(c *C) {
+ testServer.Response(200, nil, DescribePoliciesResponse)
+ resp, err := s.as.DescribePolicies("my-test-asg", []string{}, 2, "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribePolicies")
+ c.Assert(values.Get("MaxRecords"), Equals, "2")
+ expected := &DescribePoliciesResp{
+ RequestId: "ec3bffad-b739-11e2-b38d-15fbEXAMPLE",
+ NextToken: "3ef417fe-9202-12-8ddd-d13e1313413",
+ ScalingPolicies: []ScalingPolicy{
+ {
+ PolicyARN: "arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c322761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/my-test-asg:policyName/MyScaleDownPolicy",
+ AdjustmentType: "ChangeInCapacity",
+ ScalingAdjustment: -1,
+ PolicyName: "MyScaleDownPolicy",
+ AutoScalingGroupName: "my-test-asg",
+ Cooldown: 60,
+ Alarms: []Alarm{
+ {
+ AlarmName: "TestQueue",
+ AlarmARN: "arn:aws:cloudwatch:us-east-1:803981987763:alarm:TestQueue",
+ },
+ },
+ },
+ {
+ PolicyARN: "arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c55a5cdd-9be0-435b-b60b-a8dd313159f5:autoScalingGroupName/my-test-asg:policyName/MyScaleUpPolicy",
+ AdjustmentType: "ChangeInCapacity",
+ ScalingAdjustment: 1,
+ PolicyName: "MyScaleUpPolicy",
+ AutoScalingGroupName: "my-test-asg",
+ Cooldown: 60,
+ Alarms: []Alarm{
+ {
+ AlarmName: "TestQueue",
+ AlarmARN: "arn:aws:cloudwatch:us-east-1:803981987763:alarm:TestQueue",
+ },
+ },
+ },
+ },
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeScalingActivities(c *C) {
+ testServer.Response(200, nil, DescribeScalingActivitiesResponse)
+ resp, err := s.as.DescribeScalingActivities("my-test-asg", []string{}, 1, "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeScalingActivities")
+ c.Assert(values.Get("MaxRecords"), Equals, "1")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ st, _ := time.Parse(time.RFC3339, "2012-04-12T17:32:07.882Z")
+ et, _ := time.Parse(time.RFC3339, "2012-04-12T17:32:08Z")
+ expected := &DescribeScalingActivitiesResp{
+ RequestId: "7a641adc-84c5-11e1-a8a5-217ebEXAMPLE",
+ NextToken: "3ef417fe-9202-12-8ddd-d13e1313413",
+ Activities: []Activity{
+ {
+ StatusCode: "Failed",
+ Progress: 0,
+ ActivityId: "063308ae-aa22-4a9b-94f4-9faeEXAMPLE",
+ StartTime: st,
+ AutoScalingGroupName: "my-test-asg",
+ Details: "{}",
+ Cause: "At 2012-04-12T17:31:30Z a user request created an AutoScalingGroup changing the desired capacity from 0 to 1. At 2012-04-12T17:32:07Z an instance was started in response to a difference between desired and actual capacity, increasing the capacity from 0 to 1.",
+ Description: "Launching a new EC2 instance. Status Reason: The image id 'ami-4edb0327' does not exist. Launching EC2 instance failed.",
+ EndTime: et,
+ StatusMessage: "The image id 'ami-4edb0327' does not exist. Launching EC2 instance failed.",
+ },
+ },
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeScalingProcessTypes(c *C) {
+ testServer.Response(200, nil, DescribeScalingProcessTypesResponse)
+ resp, err := s.as.DescribeScalingProcessTypes()
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeScalingProcessTypes")
+ c.Assert(resp.RequestId, Equals, "27f2eacc-b73f-11e2-ad99-c7aba3a9c963")
+ c.Assert(resp.Processes, DeepEquals, []ProcessType{
+ {"AZRebalance"},
+ {"AddToLoadBalancer"},
+ {"AlarmNotification"},
+ {"HealthCheck"},
+ {"Launch"},
+ {"ReplaceUnhealthy"},
+ {"ScheduledActions"},
+ {"Terminate"},
+ })
+}
+
+func (s *S) TestDescribeScheduledActions(c *C) {
+ testServer.Response(200, nil, DescribeScheduledActionsResponse)
+ st, _ := time.Parse(time.RFC3339, "2014-06-01T00:30:00Z")
+ request := &DescribeScheduledActionsParams{
+ AutoScalingGroupName: "ASGTest1",
+ MaxRecords: 1,
+ StartTime: st,
+ }
+ resp, err := s.as.DescribeScheduledActions(request)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeScheduledActions")
+ c.Assert(resp.RequestId, Equals, "0eb4217f-8421-11e3-9233-7100ef811766")
+ c.Assert(resp.ScheduledUpdateGroupActions, DeepEquals, []ScheduledUpdateGroupAction{
+ {
+ AutoScalingGroupName: "ASGTest1",
+ ScheduledActionARN: "arn:aws:autoscaling:us-west-2:193024542802:scheduledUpdateGroupAction:61f68b2c-bde3-4316-9a81-eb95dc246509:autoScalingGroupName/ASGTest1:scheduledActionName/SATest1",
+ ScheduledActionName: "SATest1",
+ Recurrence: "30 0 1 1,6,12 *",
+ MaxSize: 4,
+ StartTime: st,
+ Time: st,
+ },
+ })
+}
+
+func (s *S) TestDescribeTags(c *C) {
+ testServer.Response(200, nil, DescribeTagsResponse)
+ filter := NewFilter()
+ filter.Add("auto-scaling-group", "my-test-asg")
+ resp, err := s.as.DescribeTags(filter, 1, "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeTags")
+ c.Assert(values.Get("MaxRecords"), Equals, "1")
+ c.Assert(values.Get("Filters.member.1.Name"), Equals, "auto-scaling-group")
+ c.Assert(values.Get("Filters.member.1.Values.member.1"), Equals, "my-test-asg")
+ c.Assert(resp.RequestId, Equals, "086265fd-bf3e-11e2-85fc-fbb1EXAMPLE")
+ c.Assert(resp.Tags, DeepEquals, []Tag{
+ {
+ Key: "version",
+ Value: "1.0",
+ ResourceId: "my-test-asg",
+ PropagateAtLaunch: true,
+ ResourceType: "auto-scaling-group",
+ },
+ })
+}
+
+func (s *S) TestDescribeTerminationPolicyTypes(c *C) {
+ testServer.Response(200, nil, DescribeTerminationPolicyTypesResponse)
+ resp, err := s.as.DescribeTerminationPolicyTypes()
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DescribeTerminationPolicyTypes")
+ c.Assert(resp.RequestId, Equals, "d9a05827-b735-11e2-a40c-c79a5EXAMPLE")
+ c.Assert(resp.TerminationPolicyTypes, DeepEquals, []string{"ClosestToNextInstanceHour", "Default", "NewestInstance", "OldestInstance", "OldestLaunchConfiguration"})
+}
+
+func (s *S) TestDetachInstances(c *C) {
+ testServer.Response(200, nil, DetachInstancesResponse)
+ resp, err := s.as.DetachInstances("my-asg", []string{"i-5f2e8a0d"}, true)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DetachInstances")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-asg")
+ c.Assert(values.Get("ShouldDecrementDesiredCapacity"), Equals, "true")
+ c.Assert(values.Get("InstanceIds.member.1"), Equals, "i-5f2e8a0d")
+ st, _ := time.Parse(time.RFC3339, "2014-06-14T00:07:30.280Z")
+ expected := &DetachInstancesResult{
+ RequestId: "e04f3b11-f357-11e3-a434-7f10009d5849",
+ Activities: []Activity{
+ {
+ StatusCode: "InProgress",
+ Progress: 50,
+ ActivityId: "e54ff599-bf05-4076-8b95-a0f090ed90bb",
+ StartTime: st,
+ AutoScalingGroupName: "my-asg",
+ Details: "{\"Availability Zone\":\"us-east-1a\"}",
+ Cause: "At 2014-06-14T00:07:30Z instance i-5f2e8a0d was detached in response to a user request, shrinking the capacity from 4 to 3.",
+ Description: "Detaching EC2 instance: i-5f2e8a0d",
+ },
+ },
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDisableMetricsCollection(c *C) {
+ testServer.Response(200, nil, DisableMetricsCollectionResponse)
+ resp, err := s.as.DisableMetricsCollection("my-test-asg", []string{"GroupMinSize"})
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "DisableMetricsCollection")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("Metrics.member.1"), Equals, "GroupMinSize")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestEnableMetricsCollection(c *C) {
+ testServer.Response(200, nil, DisableMetricsCollectionResponse)
+ resp, err := s.as.EnableMetricsCollection("my-test-asg", []string{"GroupMinSize", "GroupMaxSize"}, "1Minute")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "EnableMetricsCollection")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("Granularity"), Equals, "1Minute")
+ c.Assert(values.Get("Metrics.member.1"), Equals, "GroupMinSize")
+ c.Assert(values.Get("Metrics.member.2"), Equals, "GroupMaxSize")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestEnterStandby(c *C) {
+ testServer.Response(200, nil, EnterStandbyResponse)
+ resp, err := s.as.EnterStandby("my-asg", []string{"i-5b73d709"}, true)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "EnterStandby")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-asg")
+ c.Assert(values.Get("ShouldDecrementDesiredCapacity"), Equals, "true")
+ c.Assert(values.Get("InstanceIds.member.1"), Equals, "i-5b73d709")
+ st, _ := time.Parse(time.RFC3339, "2014-06-13T22:35:50.884Z")
+ expected := &EnterStandbyResult{
+ RequestId: "126f2f31-f34b-11e3-bc51-b35178f0274f",
+ Activities: []Activity{
+ {
+ StatusCode: "InProgress",
+ Progress: 50,
+ ActivityId: "462b4bc3-ad3b-4e67-a58d-96cd00f02f9e",
+ StartTime: st,
+ AutoScalingGroupName: "my-asg",
+ Details: "{\"Availability Zone\":\"us-east-1a\"}",
+ Cause: "At 2014-06-13T22:35:50Z instance i-5b73d709 was moved to standby in response to a user request, shrinking the capacity from 4 to 3.",
+ Description: "Moving EC2 instance to Standby: i-5b73d709",
+ },
+ },
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestExecutePolicy(c *C) {
+ testServer.Response(200, nil, ExecutePolicyResponse)
+ resp, err := s.as.ExecutePolicy("my-scaleout-policy", "my-test-asg", true)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "ExecutePolicy")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("PolicyName"), Equals, "my-scaleout-policy")
+ c.Assert(values.Get("HonorCooldown"), Equals, "true")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestExitStandby(c *C) {
+ testServer.Response(200, nil, ExitStandbyResponse)
+ resp, err := s.as.ExitStandby("my-asg", []string{"i-5b73d709"})
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "ExitStandby")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-asg")
+ c.Assert(values.Get("InstanceIds.member.1"), Equals, "i-5b73d709")
+ st, _ := time.Parse(time.RFC3339, "2014-06-13T22:43:53.523Z")
+ expected := &ExitStandbyResult{
+ RequestId: "321a11c8-f34c-11e3-a434-7f10009d5849",
+ Activities: []Activity{
+ {
+ StatusCode: "PreInService",
+ Progress: 30,
+ ActivityId: "dca4efcf-eea6-4844-8064-cab1fecd1aa2",
+ StartTime: st,
+ AutoScalingGroupName: "my-asg",
+ Details: "{\"Availability Zone\":\"us-east-1a\"}",
+ Cause: "At 2014-06-13T22:43:53Z instance i-5b73d709 was moved out of standby in response to a user request, increasing the capacity from 3 to 4.",
+ Description: "Moving EC2 instance out of Standby: i-5b73d709",
+ },
+ },
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestPutLifecycleHook(c *C) {
+ testServer.Response(200, nil, PutLifecycleHookResponse)
+ request := &PutLifecycleHookParams{
+ AutoScalingGroupName: "my-asg",
+ LifecycleHookName: "ReadyForSoftwareInstall",
+ LifecycleTransition: "autoscaling:EC2_INSTANCE_LAUNCHING",
+ NotificationTargetARN: "arn:aws:sqs:us-east-1:896650972448:lifecyclehookqueue",
+ RoleARN: "arn:aws:iam::896650972448:role/AutoScaling",
+ }
+ resp, err := s.as.PutLifecycleHook(request)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "PutLifecycleHook")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-asg")
+ c.Assert(values.Get("LifecycleHookName"), Equals, "ReadyForSoftwareInstall")
+ c.Assert(values.Get("RoleARN"), Equals, "arn:aws:iam::896650972448:role/AutoScaling")
+ c.Assert(values.Get("LifecycleTransition"), Equals, "autoscaling:EC2_INSTANCE_LAUNCHING")
+ c.Assert(values.Get("NotificationTargetARN"), Equals, "arn:aws:sqs:us-east-1:896650972448:lifecyclehookqueue")
+ c.Assert(values.Get("DefaultResult"), Equals, "")
+ c.Assert(values.Get("HeartbeatTimeout"), Equals, "")
+ c.Assert(values.Get("NotificationMetadata"), Equals, "")
+ c.Assert(resp.RequestId, Equals, "1952f458-f645-11e3-bc51-b35178f0274f")
+}
+
+func (s *S) TestPutNotificationConfiguration(c *C) {
+ testServer.Response(200, nil, PutNotificationConfigurationResponse)
+ resp, err := s.as.PutNotificationConfiguration("my-test-asg", []string{"autoscaling:EC2_INSTANCE_LAUNCH", "autoscaling:EC2_INSTANCE_LAUNCH_ERROR"}, "myTopicARN")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "PutNotificationConfiguration")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("TopicARN"), Equals, "myTopicARN")
+ c.Assert(values.Get("NotificationTypes.member.1"), Equals, "autoscaling:EC2_INSTANCE_LAUNCH")
+ c.Assert(values.Get("NotificationTypes.member.2"), Equals, "autoscaling:EC2_INSTANCE_LAUNCH_ERROR")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestPutScalingPolicy(c *C) {
+ testServer.Response(200, nil, PutScalingPolicyResponse)
+ request := &PutScalingPolicyParams{
+ AutoScalingGroupName: "my-test-asg",
+ PolicyName: "my-scaleout-policy",
+ ScalingAdjustment: 30,
+ AdjustmentType: "PercentChangeInCapacity",
+ Cooldown: 0,
+ MinAdjustmentStep: 0,
+ }
+ resp, err := s.as.PutScalingPolicy(request)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "PutScalingPolicy")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("PolicyName"), Equals, "my-scaleout-policy")
+ c.Assert(values.Get("AdjustmentType"), Equals, "PercentChangeInCapacity")
+ c.Assert(values.Get("ScalingAdjustment"), Equals, "30")
+ c.Assert(resp.RequestId, Equals, "3cfc6fef-c08b-11e2-a697-2922EXAMPLE")
+ c.Assert(resp.PolicyARN, Equals, "arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:b0dcf5e8-02e6-4e31-9719-0675d0dc31ae:autoScalingGroupName/my-test-asg:policyName/my-scaleout-policy")
+}
+
+func (s *S) TestPutScheduledUpdateGroupAction(c *C) {
+ testServer.Response(200, nil, PutScheduledUpdateGroupActionResponse)
+ st, _ := time.Parse(time.RFC3339, "2013-05-25T08:00:00Z")
+ request := &PutScheduledUpdateGroupActionParams{
+ AutoScalingGroupName: "my-test-asg",
+ DesiredCapacity: 3,
+ ScheduledActionName: "ScaleUp",
+ StartTime: st,
+ }
+ resp, err := s.as.PutScheduledUpdateGroupAction(request)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "PutScheduledUpdateGroupAction")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("ScheduledActionName"), Equals, "ScaleUp")
+ c.Assert(values.Get("DesiredCapacity"), Equals, "3")
+ c.Assert(values.Get("StartTime"), Equals, "2013-05-25T08:00:00Z")
+ c.Assert(resp.RequestId, Equals, "3bc8c9bc-6a62-11e2-8a51-4b8a1EXAMPLE")
+}
+
+func (s *S) TestPutScheduledUpdateGroupActionCron(c *C) {
+ testServer.Response(200, nil, PutScheduledUpdateGroupActionResponse)
+ st, _ := time.Parse(time.RFC3339, "2013-05-25T08:00:00Z")
+ request := &PutScheduledUpdateGroupActionParams{
+ AutoScalingGroupName: "my-test-asg",
+ DesiredCapacity: 3,
+ ScheduledActionName: "scaleup-schedule-year",
+ StartTime: st,
+ Recurrence: "30 0 1 1,6,12 *",
+ }
+ resp, err := s.as.PutScheduledUpdateGroupAction(request)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "PutScheduledUpdateGroupAction")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("ScheduledActionName"), Equals, "scaleup-schedule-year")
+ c.Assert(values.Get("DesiredCapacity"), Equals, "3")
+ c.Assert(values.Get("Recurrence"), Equals, "30 0 1 1,6,12 *")
+ c.Assert(resp.RequestId, Equals, "3bc8c9bc-6a62-11e2-8a51-4b8a1EXAMPLE")
+
+}
+
+func (s *S) TestResumeProcesses(c *C) {
+ testServer.Response(200, nil, ResumeProcessesResponse)
+ resp, err := s.as.ResumeProcesses("my-test-asg", []string{"Launch", "Terminate"})
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "ResumeProcesses")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("ScalingProcesses.member.1"), Equals, "Launch")
+ c.Assert(values.Get("ScalingProcesses.member.2"), Equals, "Terminate")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+
+}
+
+func (s *S) TestSetDesiredCapacity(c *C) {
+ testServer.Response(200, nil, SetDesiredCapacityResponse)
+ resp, err := s.as.SetDesiredCapacity("my-test-asg", 3, true)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "SetDesiredCapacity")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("HonorCooldown"), Equals, "true")
+ c.Assert(values.Get("DesiredCapacity"), Equals, "3")
+ c.Assert(resp.RequestId, Equals, "9fb7e2db-6998-11e2-a985-57c82EXAMPLE")
+}
+
+func (s *S) TestSetInstanceHealth(c *C) {
+ testServer.Response(200, nil, SetInstanceHealthResponse)
+ resp, err := s.as.SetInstanceHealth("i-baha3121", "Unhealthy", false)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "SetInstanceHealth")
+ c.Assert(values.Get("HealthStatus"), Equals, "Unhealthy")
+ c.Assert(values.Get("InstanceId"), Equals, "i-baha3121")
+ c.Assert(values.Get("ShouldRespectGracePeriod"), Equals, "false")
+ c.Assert(resp.RequestId, Equals, "9fb7e2db-6998-11e2-a985-57c82EXAMPLE")
+}
+
+func (s *S) TestSuspendProcesses(c *C) {
+ testServer.Response(200, nil, SuspendProcessesResponse)
+ resp, err := s.as.SuspendProcesses("my-test-asg", []string{"Launch", "Terminate"})
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "SuspendProcesses")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("ScalingProcesses.member.1"), Equals, "Launch")
+ c.Assert(values.Get("ScalingProcesses.member.2"), Equals, "Terminate")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestTerminateInstanceInAutoScalingGroup(c *C) {
+ testServer.Response(200, nil, TerminateInstanceInAutoScalingGroupResponse)
+ st, _ := time.Parse(time.RFC3339, "2014-01-26T14:08:30.560Z")
+ resp, err := s.as.TerminateInstanceInAutoScalingGroup("i-br234123", false)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "TerminateInstanceInAutoScalingGroup")
+ c.Assert(values.Get("InstanceId"), Equals, "i-br234123")
+ c.Assert(values.Get("ShouldDecrementDesiredCapacity"), Equals, "false")
+ expected := &TerminateInstanceInAutoScalingGroupResp{
+ Activity: Activity{
+ ActivityId: "cczc44a87-7d04-dsa15-31-d27c219864c5",
+ Cause: "At 2014-01-26T14:08:30Z instance i-br234123 was taken out of service in response to a user request.",
+ Description: "Terminating EC2 instance: i-br234123",
+ Details: "{\"Availability Zone\":\"us-east-1b\"}",
+ Progress: 0,
+ StartTime: st,
+ StatusCode: "InProgress",
+ },
+ RequestId: "8d798a29-f083-11e1-bdfb-cb223EXAMPLE",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestUpdateAutoScalingGroup(c *C) {
+ testServer.Response(200, nil, UpdateAutoScalingGroupResponse)
+
+ asg := &AutoScalingGroup{
+ AutoScalingGroupName: "my-test-asg",
+ AvailabilityZones: []string{"us-east-1a", "us-east-1b"},
+ MinSize: 3,
+ MaxSize: 3,
+ DefaultCooldown: 600,
+ DesiredCapacity: 3,
+ LaunchConfigurationName: "my-test-lc",
+ VPCZoneIdentifier: "subnet-610acd08,subnet-530fc83a",
+ }
+ resp, err := s.as.UpdateAutoScalingGroup(asg)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2011-01-01")
+ c.Assert(values.Get("Action"), Equals, "UpdateAutoScalingGroup")
+ c.Assert(values.Get("AutoScalingGroupName"), Equals, "my-test-asg")
+ c.Assert(values.Get("AvailabilityZones.member.1"), Equals, "us-east-1a")
+ c.Assert(values.Get("AvailabilityZones.member.2"), Equals, "us-east-1b")
+ c.Assert(values.Get("MinSize"), Equals, "3")
+ c.Assert(values.Get("MaxSize"), Equals, "3")
+ c.Assert(values.Get("DefaultCooldown"), Equals, "600")
+ c.Assert(values.Get("DesiredCapacity"), Equals, "3")
+ c.Assert(values.Get("LaunchConfigurationName"), Equals, "my-test-lc")
+ c.Assert(values.Get("VPCZoneIdentifier"), Equals, "subnet-610acd08,subnet-530fc83a")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
diff --git a/vendor/github.com/goamz/goamz/autoscaling/responses_test.go b/vendor/github.com/goamz/goamz/autoscaling/responses_test.go
new file mode 100644
index 000000000..935231aa2
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/autoscaling/responses_test.go
@@ -0,0 +1,627 @@
+package autoscaling
+
+var AttachInstancesResponse = `
+<AttachInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</AttachInstancesResponse>
+`
+var BasicGroupResponse = `
+<DescribeAutoScalingGroupsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeAutoScalingGroupsResult>
+ <AutoScalingGroups/>
+ </DescribeAutoScalingGroupsResult>
+ <ResponseMetadata>
+ <RequestId>08c3bedc-8421-11e3-9bb5-bfa219b29cce</RequestId>
+ </ResponseMetadata>
+</DescribeAutoScalingGroupsResponse>
+`
+var CreateAutoScalingGroupResponse = `
+<CreateAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateAutoScalingGroupResponse>
+`
+var CreateLaunchConfigurationResponse = `
+<CreateLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+<ResponseMetadata>
+ <RequestId>7c6e177f-f082-11e1-ac58-3714bEXAMPLE</RequestId>
+</ResponseMetadata>
+</CreateLaunchConfigurationResponse>
+`
+var CreateOrUpdateTagsResponse = `
+<CreateOrUpdateTagsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>b0203919-bf1b-11e2-8a01-13263EXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateOrUpdateTagsResponse>
+`
+var DeleteAutoScalingGroupResponse = `
+ <DeleteAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>70a76d42-9665-11e2-9fdf-211deEXAMPLE</RequestId>
+ </ResponseMetadata>
+ </DeleteAutoScalingGroupResponse>
+`
+var DeleteAutoScalingGroupErrorResponse = `
+<ErrorResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>ResourceInUse</Code>
+ <Message>You cannot delete an AutoScalingGroup while there are instances or pending Spot instance request(s) still in the group.</Message>
+ </Error>
+ <RequestId>70a76d42-9665-11e2-9fdf-211deEXAMPLE</RequestId>
+</ErrorResponse>
+`
+var DeleteLaunchConfigurationResponse = `
+<DeleteLaunchConfigurationResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>7347261f-97df-11e2-8756-35eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</DeleteLaunchConfigurationResponse>
+`
+var DeleteLaunchConfigurationInUseResponse = `
+<ErrorResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>ResourceInUse</Code>
+ <Message>Cannot delete launch configuration my-test-lc because it is attached to AutoScalingGroup test</Message>
+ </Error>
+ <RequestId>7347261f-97df-11e2-8756-35eEXAMPLE</RequestId>
+</ErrorResponse>
+`
+var DeleteScheduledActionResponse = `
+<DeleteScheduledActionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>0f38bb02-8421-11e3-9bb5-bfa219b29cce</RequestId>
+ </ResponseMetadata>
+</DeleteScheduledActionResponse>
+`
+var DeleteTagsResponse = `
+<CreateOrUpdateTagsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>b0203919-bf1b-11e2-8a01-13263EXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateOrUpdateTagsResponse>
+`
+var DescribeAccountLimitsResponse = `
+<DescribeAccountLimitsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeAccountLimitsResult>
+ <MaxNumberOfLaunchConfigurations>100</MaxNumberOfLaunchConfigurations>
+ <MaxNumberOfAutoScalingGroups>20</MaxNumberOfAutoScalingGroups>
+ </DescribeAccountLimitsResult>
+ <ResponseMetadata>
+ <RequestId>a32bd184-519d-11e3-a8a4-c1c467cbcc3b</RequestId>
+ </ResponseMetadata>
+</DescribeAccountLimitsResponse>
+`
+var DescribeAdjustmentTypesResponse = `
+<DescribeAdjustmentTypesResponse xmlns="http://autoscaling.amazonaws.com/doc/201-01-01/">
+ <DescribeAdjustmentTypesResult>
+ <AdjustmentTypes>
+ <member>
+ <AdjustmentType>ChangeInCapacity</AdjustmentType>
+ </member>
+ <member>
+ <AdjustmentType>ExactCapacity</AdjustmentType>
+ </member>
+ <member>
+ <AdjustmentType>PercentChangeInCapacity</AdjustmentType>
+ </member>
+ </AdjustmentTypes>
+ </DescribeAdjustmentTypesResult>
+ <ResponseMetadata>
+ <RequestId>cc5f0337-b694-11e2-afc0-6544dEXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeAdjustmentTypesResponse>
+`
+var DescribeAutoScalingGroupsResponse = `
+<DescribeAutoScalingGroupsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+<DescribeAutoScalingGroupsResult>
+ <AutoScalingGroups>
+ <member>
+ <Tags>
+ <member>
+ <ResourceId>my-test-asg-lbs</ResourceId>
+ <PropagateAtLaunch>true</PropagateAtLaunch>
+ <Value>bar</Value>
+ <Key>foo</Key>
+ <ResourceType>auto-scaling-group</ResourceType>
+ </member>
+ <member>
+ <ResourceId>my-test-asg-lbs</ResourceId>
+ <PropagateAtLaunch>true</PropagateAtLaunch>
+ <Value>qux</Value>
+ <Key>baz</Key>
+ <ResourceType>auto-scaling-group</ResourceType>
+ </member>
+ </Tags>
+ <SuspendedProcesses/>
+ <AutoScalingGroupName>my-test-asg-lbs</AutoScalingGroupName>
+ <HealthCheckType>ELB</HealthCheckType>
+ <CreatedTime>2013-05-06T17:47:15.107Z</CreatedTime>
+ <EnabledMetrics/>
+ <LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
+ <Instances>
+ <member>
+ <HealthStatus>Healthy</HealthStatus>
+ <AvailabilityZone>us-east-1b</AvailabilityZone>
+ <InstanceId>i-zb1f313</InstanceId>
+ <LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
+ <LifecycleState>InService</LifecycleState>
+ </member>
+ <member>
+ <HealthStatus>Healthy</HealthStatus>
+ <AvailabilityZone>us-east-1a</AvailabilityZone>
+ <InstanceId>i-90123adv</InstanceId>
+ <LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
+ <LifecycleState>InService</LifecycleState>
+ </member>
+ </Instances>
+ <DesiredCapacity>2</DesiredCapacity>
+ <AvailabilityZones>
+ <member>us-east-1b</member>
+ <member>us-east-1a</member>
+ </AvailabilityZones>
+ <LoadBalancerNames>
+ <member>my-test-asg-loadbalancer</member>
+ </LoadBalancerNames>
+ <MinSize>2</MinSize>
+ <VPCZoneIdentifier>subnet-32131da1,subnet-1312dad2</VPCZoneIdentifier>
+ <HealthCheckGracePeriod>120</HealthCheckGracePeriod>
+ <DefaultCooldown>300</DefaultCooldown>
+ <AutoScalingGroupARN>arn:aws:autoscaling:us-east-1:803981987763:autoScalingGroup:ca861182-c8f9-4ca7-b1eb-cd35505f5ebb:autoScalingGroupName/my-test-asg-lbs</AutoScalingGroupARN>
+ <TerminationPolicies>
+ <member>Default</member>
+ </TerminationPolicies>
+ <MaxSize>10</MaxSize>
+ </member>
+ </AutoScalingGroups>
+ </DescribeAutoScalingGroupsResult>
+ <ResponseMetadata>
+ <RequestId>0f02a07d-b677-11e2-9eb0-dd50EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeAutoScalingGroupsResponse>
+`
+var DescribeAutoScalingInstancesResponse = `
+<DescribeAutoScalingInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeAutoScalingInstancesResult>
+ <AutoScalingInstances>
+ <member>
+ <HealthStatus>Healthy</HealthStatus>
+ <AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
+ <AvailabilityZone>us-east-1a</AvailabilityZone>
+ <InstanceId>i-78e0d40b</InstanceId>
+ <LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
+ <LifecycleState>InService</LifecycleState>
+ </member>
+ </AutoScalingInstances>
+ </DescribeAutoScalingInstancesResult>
+ <ResponseMetadata>
+ <RequestId>df992dc3-b72f-11e2-81e1-750aa6EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeAutoScalingInstancesResponse>
+`
+var DescribeLaunchConfigurationsResponse = `
+<DescribeLaunchConfigurationsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeLaunchConfigurationsResult>
+ <LaunchConfigurations>
+ <member>
+ <AssociatePublicIpAddress>true</AssociatePublicIpAddress>
+ <SecurityGroups/>
+ <CreatedTime>2013-01-21T23:04:42.200Z</CreatedTime>
+ <KernelId/>
+ <LaunchConfigurationName>my-test-lc</LaunchConfigurationName>
+ <UserData/>
+ <InstanceType>m1.small</InstanceType>
+ <LaunchConfigurationARN>arn:aws:autoscaling:us-east-1:803981987763:launchConfiguration:9dbbbf87-6141-428a-a409-0752edbe6cad:launchConfigurationName/my-test-lc</LaunchConfigurationARN>
+ <BlockDeviceMappings>
+ <member>
+ <VirtualName>ephemeral0</VirtualName>
+ <DeviceName>/dev/sdb</DeviceName>
+ </member>
+ <member>
+ <Ebs>
+ <SnapshotId>snap-XXXXYYY</SnapshotId>
+ <VolumeSize>100</VolumeSize>
+ <Iops>50</Iops>
+ <VolumeType>io1</VolumeType>
+ <DeleteOnTermination>true</DeleteOnTermination>
+ </Ebs>
+ <DeviceName>/dev/sdf</DeviceName>
+ </member>
+ </BlockDeviceMappings>
+ <ImageId>ami-514ac838</ImageId>
+ <KeyName/>
+ <RamdiskId/>
+ <InstanceMonitoring>
+ <Enabled>true</Enabled>
+ </InstanceMonitoring>
+ <EbsOptimized>false</EbsOptimized>
+ </member>
+ </LaunchConfigurations>
+ </DescribeLaunchConfigurationsResult>
+ <ResponseMetadata>
+ <RequestId>d05a22f8-b690-11e2-bf8e-2113fEXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeLaunchConfigurationsResponse>
+`
+var DescribeMetricCollectionTypesResponse = `
+<DescribeMetricCollectionTypesResponse xmlns="http://autoscaling.amazonaws.co
+oc/2011-01-01/">
+ <DescribeMetricCollectionTypesResult>
+ <Metrics>
+ <member>
+ <Metric>GroupMinSize</Metric>
+ </member>
+ <member>
+ <Metric>GroupMaxSize</Metric>
+ </member>
+ <member>
+ <Metric>GroupDesiredCapacity</Metric>
+ </member>
+ <member>
+ <Metric>GroupInServiceInstances</Metric>
+ </member>
+ <member>
+ <Metric>GroupPendingInstances</Metric>
+ </member>
+ <member>
+ <Metric>GroupTerminatingInstances</Metric>
+ </member>
+ <member>
+ <Metric>GroupTotalInstances</Metric>
+ </member>
+ </Metrics>
+ <Granularities>
+ <member>
+ <Granularity>1Minute</Granularity>
+ </member>
+ </Granularities>
+ </DescribeMetricCollectionTypesResult>
+ <ResponseMetadata>
+ <RequestId>07f3fea2-bf3c-11e2-9b6f-f3cdbb80c073</RequestId>
+ </ResponseMetadata>
+</DescribeMetricCollectionTypesResponse>
+`
+var DescribeNotificationConfigurationsResponse = `
+<DescribeNotificationConfigurationsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeNotificationConfigurationsResult>
+ <NotificationConfigurations>
+ <member>
+ <AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
+ <NotificationType>autoscaling: EC2_INSTANCE_LAUNCH</NotificationType>
+ <TopicARN>vajdoafj231j41231/topic</TopicARN>
+ </member>
+ </NotificationConfigurations>
+ </DescribeNotificationConfigurationsResult>
+ <ResponseMetadata>
+ <RequestId>07f3fea2-bf3c-11e2-9b6f-f3cdbb80c073</RequestId>
+ </ResponseMetadata>
+</DescribeNotificationConfigurationsResponse>
+`
+var DescribePoliciesResponse = `
+<DescribePoliciesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribePoliciesResult>
+ <NextToken>3ef417fe-9202-12-8ddd-d13e1313413</NextToken>
+ <ScalingPolicies>
+ <member>
+ <PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c322761b-3172-4d56-9a21-0ed9d6161d67:autoScalingGroupName/my-test-asg:policyName/MyScaleDownPolicy</PolicyARN>
+ <AdjustmentType>ChangeInCapacity</AdjustmentType>
+ <ScalingAdjustment>-1</ScalingAdjustment>
+ <PolicyName>MyScaleDownPolicy</PolicyName>
+ <AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
+ <Cooldown>60</Cooldown>
+ <Alarms>
+ <member>
+ <AlarmName>TestQueue</AlarmName>
+ <AlarmARN>arn:aws:cloudwatch:us-east-1:803981987763:alarm:TestQueue</AlarmARN>
+ </member>
+ </Alarms>
+ </member>
+ <member>
+ <PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:c55a5cdd-9be0-435b-b60b-a8dd313159f5:autoScalingGroupName/my-test-asg:policyName/MyScaleUpPolicy</PolicyARN>
+ <AdjustmentType>ChangeInCapacity</AdjustmentType>
+ <ScalingAdjustment>1</ScalingAdjustment>
+ <PolicyName>MyScaleUpPolicy</PolicyName>
+ <AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
+ <Cooldown>60</Cooldown>
+ <Alarms>
+ <member>
+ <AlarmName>TestQueue</AlarmName>
+ <AlarmARN>arn:aws:cloudwatch:us-east-1:803981987763:alarm:TestQueue</AlarmARN>
+ </member>
+ </Alarms>
+ </member>
+ </ScalingPolicies>
+ </DescribePoliciesResult>
+ <ResponseMetadata>
+ <RequestId>ec3bffad-b739-11e2-b38d-15fbEXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribePoliciesResponse>
+`
+var DescribeScalingActivitiesResponse = `
+<DescribeScalingActivitiesResponse xmlns="http://ec2.amazonaws.com/doc/2011-01-01/">
+<DescribeScalingActivitiesResult>
+ <NextToken>3ef417fe-9202-12-8ddd-d13e1313413</NextToken>
+<Activities>
+ <member>
+ <StatusCode>Failed</StatusCode>
+ <Progress>0</Progress>
+ <ActivityId>063308ae-aa22-4a9b-94f4-9faeEXAMPLE</ActivityId>
+ <StartTime>2012-04-12T17:32:07.882Z</StartTime>
+ <AutoScalingGroupName>my-test-asg</AutoScalingGroupName>
+ <Cause>At 2012-04-12T17:31:30Z a user request created an AutoScalingGroup changing the desired capacity from 0 to 1. At 2012-04-12T17:32:07Z an instance was started in response to a difference between desired and actual capacity, increasing the capacity from 0 to 1.</Cause>
+ <Details>{}</Details>
+ <Description>Launching a new EC2 instance. Status Reason: The image id 'ami-4edb0327' does not exist. Launching EC2 instance failed.</Description>
+ <EndTime>2012-04-12T17:32:08Z</EndTime>
+ <StatusMessage>The image id 'ami-4edb0327' does not exist. Launching EC2 instance failed.</StatusMessage>
+ </member>
+</Activities>
+ </DescribeScalingActivitiesResult>
+ <ResponseMetadata>
+ <RequestId>7a641adc-84c5-11e1-a8a5-217ebEXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeScalingActivitiesResponse>
+`
+var DescribeScalingProcessTypesResponse = `
+<DescribeScalingProcessTypesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeScalingProcessTypesResult>
+ <Processes>
+ <member>
+ <ProcessName>AZRebalance</ProcessName>
+ </member>
+ <member>
+ <ProcessName>AddToLoadBalancer</ProcessName>
+ </member>
+ <member>
+ <ProcessName>AlarmNotification</ProcessName>
+ </member>
+ <member>
+ <ProcessName>HealthCheck</ProcessName>
+ </member>
+ <member>
+ <ProcessName>Launch</ProcessName>
+ </member>
+ <member>
+ <ProcessName>ReplaceUnhealthy</ProcessName>
+ </member>
+ <member>
+ <ProcessName>ScheduledActions</ProcessName>
+ </member>
+ <member>
+ <ProcessName>Terminate</ProcessName>
+ </member>
+ </Processes>
+ </DescribeScalingProcessTypesResult>
+ <ResponseMetadata>
+ <RequestId>27f2eacc-b73f-11e2-ad99-c7aba3a9c963</RequestId>
+ </ResponseMetadata>
+</DescribeScalingProcessTypesResponse>
+`
+var DescribeScheduledActionsResponse = `
+<DescribeScheduledActionsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeScheduledActionsResult>
+ <ScheduledUpdateGroupActions>
+ <member>
+ <ScheduledActionName>SATest1</ScheduledActionName>
+ <StartTime>2014-06-01T00:30:00Z</StartTime>
+ <Time>2014-06-01T00:30:00Z</Time>
+ <ScheduledActionARN>arn:aws:autoscaling:us-west-2:193024542802:scheduledUpdateGroupAction:61f68b2c-bde3-4316-9a81-eb95dc246509:autoScalingGroupName/ASGTest1:scheduledActionName/SATest1</ScheduledActionARN>
+ <AutoScalingGroupName>ASGTest1</AutoScalingGroupName>
+ <Recurrence>30 0 1 1,6,12 *</Recurrence>
+ <MaxSize>4</MaxSize>
+ </member>
+ </ScheduledUpdateGroupActions>
+ </DescribeScheduledActionsResult>
+ <ResponseMetadata>
+ <RequestId>0eb4217f-8421-11e3-9233-7100ef811766</RequestId>
+ </ResponseMetadata>
+</DescribeScheduledActionsResponse>
+`
+
+var DescribeTerminationPolicyTypesResponse = `
+<DescribeTerminationPolicyTypesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeTerminationPolicyTypesResult>
+ <TerminationPolicyTypes>
+ <member>ClosestToNextInstanceHour</member>
+ <member>Default</member>
+ <member>NewestInstance</member>
+ <member>OldestInstance</member>
+ <member>OldestLaunchConfiguration</member>
+ </TerminationPolicyTypes>
+ </DescribeTerminationPolicyTypesResult>
+ <ResponseMetadata>
+ <RequestId>d9a05827-b735-11e2-a40c-c79a5EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeTerminationPolicyTypesResponse>
+`
+var DescribeTagsResponse = `
+<DescribeTagsResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DescribeTagsResult>
+ <Tags>
+ <member>
+ <ResourceId>my-test-asg</ResourceId>
+ <PropagateAtLaunch>true</PropagateAtLaunch>
+ <Value>1.0</Value>
+ <Key>version</Key>
+ <ResourceType>auto-scaling-group</ResourceType>
+ </member>
+ </Tags>
+ </DescribeTagsResult>
+ <ResponseMetadata>
+ <RequestId>086265fd-bf3e-11e2-85fc-fbb1EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeTagsResponse>
+`
+var DetachInstancesResponse = `
+<DetachInstancesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <DetachInstancesResult>
+ <Activities>
+ <member>
+ <ActivityId>e54ff599-bf05-4076-8b95-a0f090ed90bb</ActivityId>
+ <Progress>50</Progress>
+ <StatusCode>InProgress</StatusCode>
+ <StartTime>2014-06-14T00:07:30.280Z</StartTime>
+ <Cause>At 2014-06-14T00:07:30Z instance i-5f2e8a0d was detached in response to a user request, shrinking the capacity from 4 to 3.</Cause>
+ <AutoScalingGroupName>my-asg</AutoScalingGroupName>
+ <Details>{"Availability Zone":"us-east-1a"}</Details>
+ <Description>Detaching EC2 instance: i-5f2e8a0d</Description>
+ </member>
+ </Activities>
+ </DetachInstancesResult>
+ <ResponseMetadata>
+ <RequestId>e04f3b11-f357-11e3-a434-7f10009d5849</RequestId>
+ </ResponseMetadata>
+</DetachInstancesResponse>
+`
+var DisableMetricsCollectionResponse = `
+<DisableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DisableMetricsCollectionResponse>
+`
+var EnableMetricsCollectionResponse = `
+<EnableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</EnableMetricsCollectionResponse>
+`
+var EnterStandbyResponse = `
+<EnterStandbyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <EnterStandbyResult>
+ <Activities>
+ <member>
+ <ActivityId>462b4bc3-ad3b-4e67-a58d-96cd00f02f9e</ActivityId>
+ <Progress>50</Progress>
+ <StatusCode>InProgress</StatusCode>
+ <StartTime>2014-06-13T22:35:50.884Z</StartTime>
+ <Cause>At 2014-06-13T22:35:50Z instance i-5b73d709 was moved to standby in response to a user request, shrinking the capacity from 4 to 3.</Cause>
+ <AutoScalingGroupName>my-asg</AutoScalingGroupName>
+ <Details>{"Availability Zone":"us-east-1a"}</Details>
+ <Description>Moving EC2 instance to Standby: i-5b73d709</Description>
+ </member>
+ </Activities>
+ </EnterStandbyResult>
+ <ResponseMetadata>
+ <RequestId>126f2f31-f34b-11e3-bc51-b35178f0274f</RequestId>
+ </ResponseMetadata>
+</EnterStandbyResponse>
+`
+var ExecutePolicyResponse = `
+<EnableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</EnableMetricsCollectionResponse>
+`
+var ExitStandbyResponse = `
+<ExitStandbyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ExitStandbyResult>
+ <Activities>
+ <member>
+ <ActivityId>dca4efcf-eea6-4844-8064-cab1fecd1aa2</ActivityId>
+ <Progress>30</Progress>
+ <StatusCode>PreInService</StatusCode>
+ <StartTime>2014-06-13T22:43:53.523Z</StartTime>
+ <Cause>At 2014-06-13T22:43:53Z instance i-5b73d709 was moved out of standby in response to a user request, increasing the capacity from 3 to 4.</Cause>
+ <AutoScalingGroupName>my-asg</AutoScalingGroupName>
+ <Details>{"Availability Zone":"us-east-1a"}</Details>
+ <Description>Moving EC2 instance out of Standby: i-5b73d709</Description>
+ </member>
+ </Activities>
+ </ExitStandbyResult>
+ <ResponseMetadata>
+ <RequestId>321a11c8-f34c-11e3-a434-7f10009d5849</RequestId>
+ </ResponseMetadata>
+</ExitStandbyResponse>
+`
+var PutLifecycleHookResponse = `
+<PutLifecycleHookResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <PutLifecycleHookResult/>
+ <ResponseMetadata>
+ <RequestId>1952f458-f645-11e3-bc51-b35178f0274f</RequestId>
+ </ResponseMetadata>
+</PutLifecycleHookResponse>
+`
+var PutNotificationConfigurationResponse = `
+<EnableMetricsCollectionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</EnableMetricsCollectionResponse>
+`
+var PutScalingPolicyResponse = `
+<PutScalingPolicyResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <PutScalingPolicyResult>
+ <PolicyARN>arn:aws:autoscaling:us-east-1:803981987763:scalingPolicy:b0dcf5e8-02e6-4e31-9719-0675d0dc31ae:autoScalingGroupName/my-test-asg:policyName/my-scaleout-policy</PolicyARN>
+ </PutScalingPolicyResult>
+ <ResponseMetadata>
+ <RequestId>3cfc6fef-c08b-11e2-a697-2922EXAMPLE</RequestId>
+ </ResponseMetadata>
+</PutScalingPolicyResponse>
+`
+var PutScheduledUpdateGroupActionResponse = `
+<PutScheduledUpdateGroupActionResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>3bc8c9bc-6a62-11e2-8a51-4b8a1EXAMPLE</RequestId>
+ </ResponseMetadata>
+ </PutScheduledUpdateGroupActionResponse>
+ `
+var ResumeProcessesResponse = `
+<ResumeProcessesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</ResumeProcessesResponse>
+`
+var SetDesiredCapacityResponse = `
+<SetDesiredCapacityResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>9fb7e2db-6998-11e2-a985-57c82EXAMPLE</RequestId>
+ </ResponseMetadata>
+</SetDesiredCapacityResponse>
+`
+var SetInstanceHealthResponse = `
+<SetInstanceHealthResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>9fb7e2db-6998-11e2-a985-57c82EXAMPLE</RequestId>
+ </ResponseMetadata>
+</SetInstanceHealthResponse>
+`
+var SuspendProcessesResponse = `
+<SuspendProcessesResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</SuspendProcessesResponse>
+`
+var TerminateInstanceInAutoScalingGroupResponse = `
+<TerminateInstanceInAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <TerminateInstanceInAutoScalingGroupResult>
+ <Activity>
+ <StatusCode>InProgress</StatusCode>
+ <ActivityId>cczc44a87-7d04-dsa15-31-d27c219864c5</ActivityId>
+ <Progress>0</Progress>
+ <StartTime>2014-01-26T14:08:30.560Z</StartTime>
+ <Cause>At 2014-01-26T14:08:30Z instance i-br234123 was taken out of service in response to a user request.</Cause>
+ <Details>{&quot;Availability Zone&quot;:&quot;us-east-1b&quot;}</Details>
+ <Description>Terminating EC2 instance: i-br234123</Description>
+ </Activity>
+ </TerminateInstanceInAutoScalingGroupResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</TerminateInstanceInAutoScalingGroupResponse>
+`
+var UpdateAutoScalingGroupResponse = `
+<UpdateAutoScalingGroupResponse xmlns="http://autoscaling.amazonaws.com/doc/2011-01-01/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</UpdateAutoScalingGroupResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/aws/attempt_test.go b/vendor/github.com/goamz/goamz/aws/attempt_test.go
new file mode 100644
index 000000000..8ba497715
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/aws/attempt_test.go
@@ -0,0 +1,58 @@
+package aws_test
+
+import (
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ . "gopkg.in/check.v1"
+)
+
+func (S) TestAttemptTiming(c *C) {
+ testAttempt := aws.AttemptStrategy{
+ Total: 0.25e9,
+ Delay: 0.1e9,
+ }
+ want := []time.Duration{0, 0.1e9, 0.2e9, 0.2e9}
+ got := make([]time.Duration, 0, len(want)) // avoid allocation when testing timing
+ t0 := time.Now()
+ for a := testAttempt.Start(); a.Next(); {
+ got = append(got, time.Now().Sub(t0))
+ }
+ got = append(got, time.Now().Sub(t0))
+ c.Assert(got, HasLen, len(want))
+ const margin = 0.01e9
+ for i, got := range want {
+ lo := want[i] - margin
+ hi := want[i] + margin
+ if got < lo || got > hi {
+ c.Errorf("attempt %d want %g got %g", i, want[i].Seconds(), got.Seconds())
+ }
+ }
+}
+
+func (S) TestAttemptNextHasNext(c *C) {
+ a := aws.AttemptStrategy{}.Start()
+ c.Assert(a.Next(), Equals, true)
+ c.Assert(a.Next(), Equals, false)
+
+ a = aws.AttemptStrategy{}.Start()
+ c.Assert(a.Next(), Equals, true)
+ c.Assert(a.HasNext(), Equals, false)
+ c.Assert(a.Next(), Equals, false)
+
+ a = aws.AttemptStrategy{Total: 2e8}.Start()
+ c.Assert(a.Next(), Equals, true)
+ c.Assert(a.HasNext(), Equals, true)
+ time.Sleep(2e8)
+ c.Assert(a.HasNext(), Equals, true)
+ c.Assert(a.Next(), Equals, true)
+ c.Assert(a.Next(), Equals, false)
+
+ a = aws.AttemptStrategy{Total: 1e8, Min: 2}.Start()
+ time.Sleep(1e8)
+ c.Assert(a.Next(), Equals, true)
+ c.Assert(a.HasNext(), Equals, true)
+ c.Assert(a.Next(), Equals, true)
+ c.Assert(a.HasNext(), Equals, false)
+ c.Assert(a.Next(), Equals, false)
+}
diff --git a/vendor/github.com/goamz/goamz/aws/aws_test.go b/vendor/github.com/goamz/goamz/aws/aws_test.go
new file mode 100644
index 000000000..0c74a7905
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/aws/aws_test.go
@@ -0,0 +1,211 @@
+package aws_test
+
+import (
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ environ []string
+}
+
+func (s *S) SetUpSuite(c *C) {
+ s.environ = os.Environ()
+}
+
+func (s *S) TearDownTest(c *C) {
+ os.Clearenv()
+ for _, kv := range s.environ {
+ l := strings.SplitN(kv, "=", 2)
+ os.Setenv(l[0], l[1])
+ }
+}
+
+func (s *S) TestSharedAuthNoHome(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_PROFILE", "foo")
+ _, err := aws.SharedAuth()
+ c.Assert(err, ErrorMatches, "Could not get HOME")
+}
+
+func (s *S) TestSharedAuthNoCredentialsFile(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_PROFILE", "foo")
+ os.Setenv("HOME", "/tmp")
+ _, err := aws.SharedAuth()
+ c.Assert(err, ErrorMatches, "Couldn't parse AWS credentials file")
+}
+
+func (s *S) TestSharedAuthNoProfileInFile(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_PROFILE", "foo")
+
+ d, err := ioutil.TempDir("", "")
+ if err != nil {
+ panic(err)
+ }
+ defer os.RemoveAll(d)
+
+ err = os.Mkdir(d+"/.aws", 0755)
+ if err != nil {
+ panic(err)
+ }
+
+ ioutil.WriteFile(d+"/.aws/credentials", []byte("[bar]\n"), 0644)
+ os.Setenv("HOME", d)
+
+ _, err = aws.SharedAuth()
+ c.Assert(err, ErrorMatches, "Couldn't find profile in AWS credentials file")
+}
+
+func (s *S) TestSharedAuthNoKeysInProfile(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_PROFILE", "bar")
+
+ d, err := ioutil.TempDir("", "")
+ if err != nil {
+ panic(err)
+ }
+ defer os.RemoveAll(d)
+
+ err = os.Mkdir(d+"/.aws", 0755)
+ if err != nil {
+ panic(err)
+ }
+
+ ioutil.WriteFile(d+"/.aws/credentials", []byte("[bar]\nawsaccesskeyid = AK.."), 0644)
+ os.Setenv("HOME", d)
+
+ _, err = aws.SharedAuth()
+ c.Assert(err, ErrorMatches, "AWS_SECRET_ACCESS_KEY not found in credentials file")
+}
+
+func (s *S) TestSharedAuthDefaultCredentials(c *C) {
+ os.Clearenv()
+
+ d, err := ioutil.TempDir("", "")
+ if err != nil {
+ panic(err)
+ }
+ defer os.RemoveAll(d)
+
+ err = os.Mkdir(d+"/.aws", 0755)
+ if err != nil {
+ panic(err)
+ }
+
+ ioutil.WriteFile(d+"/.aws/credentials", []byte("[default]\naws_access_key_id = access\naws_secret_access_key = secret\n"), 0644)
+ os.Setenv("HOME", d)
+
+ auth, err := aws.SharedAuth()
+ c.Assert(err, IsNil)
+ c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
+}
+
+func (s *S) TestSharedAuth(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_PROFILE", "bar")
+
+ d, err := ioutil.TempDir("", "")
+ if err != nil {
+ panic(err)
+ }
+ defer os.RemoveAll(d)
+
+ err = os.Mkdir(d+"/.aws", 0755)
+ if err != nil {
+ panic(err)
+ }
+
+ ioutil.WriteFile(d+"/.aws/credentials", []byte("[bar]\naws_access_key_id = access\naws_secret_access_key = secret\n"), 0644)
+ os.Setenv("HOME", d)
+
+ auth, err := aws.SharedAuth()
+ c.Assert(err, IsNil)
+ c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
+}
+
+func (s *S) TestEnvAuthNoSecret(c *C) {
+ os.Clearenv()
+ _, err := aws.EnvAuth()
+ c.Assert(err, ErrorMatches, "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment")
+}
+
+func (s *S) TestEnvAuthNoAccess(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_SECRET_ACCESS_KEY", "foo")
+ _, err := aws.EnvAuth()
+ c.Assert(err, ErrorMatches, "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment")
+}
+
+func (s *S) TestEnvAuth(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
+ os.Setenv("AWS_ACCESS_KEY_ID", "access")
+ auth, err := aws.EnvAuth()
+ c.Assert(err, IsNil)
+ c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
+}
+
+func (s *S) TestEnvAuthAlt(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_SECRET_KEY", "secret")
+ os.Setenv("AWS_ACCESS_KEY", "access")
+ auth, err := aws.EnvAuth()
+ c.Assert(err, IsNil)
+ c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
+}
+
+func (s *S) TestEnvAuthToken(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_SECRET_KEY", "secret")
+ os.Setenv("AWS_ACCESS_KEY", "access")
+ os.Setenv("AWS_SESSION_TOKEN", "token")
+ auth, err := aws.EnvAuth()
+ c.Assert(err, IsNil)
+ c.Assert(auth.SecretKey, Equals, "secret")
+ c.Assert(auth.AccessKey, Equals, "access")
+ c.Assert(auth.Token(), Equals, "token")
+}
+
+func (s *S) TestGetAuthStatic(c *C) {
+ exptdate := time.Now().Add(time.Hour)
+ auth, err := aws.GetAuth("access", "secret", "token", exptdate)
+ c.Assert(err, IsNil)
+ c.Assert(auth.AccessKey, Equals, "access")
+ c.Assert(auth.SecretKey, Equals, "secret")
+ c.Assert(auth.Token(), Equals, "token")
+ c.Assert(auth.Expiration(), Equals, exptdate)
+}
+
+func (s *S) TestGetAuthEnv(c *C) {
+ os.Clearenv()
+ os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
+ os.Setenv("AWS_ACCESS_KEY_ID", "access")
+ auth, err := aws.GetAuth("", "", "", time.Time{})
+ c.Assert(err, IsNil)
+ c.Assert(auth, Equals, aws.Auth{SecretKey: "secret", AccessKey: "access"})
+}
+
+func (s *S) TestEncode(c *C) {
+ c.Assert(aws.Encode("foo"), Equals, "foo")
+ c.Assert(aws.Encode("/"), Equals, "%2F")
+}
+
+func (s *S) TestRegionsAreNamed(c *C) {
+ for n, r := range aws.Regions {
+ c.Assert(n, Equals, r.Name)
+ }
+}
diff --git a/vendor/github.com/goamz/goamz/aws/client_test.go b/vendor/github.com/goamz/goamz/aws/client_test.go
new file mode 100644
index 000000000..c66a86333
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/aws/client_test.go
@@ -0,0 +1,121 @@
+package aws_test
+
+import (
+ "fmt"
+ "github.com/goamz/goamz/aws"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+ "time"
+)
+
+// Retrieve the response from handler using aws.RetryingClient
+func serveAndGet(handler http.HandlerFunc) (body string, err error) {
+ ts := httptest.NewServer(handler)
+ defer ts.Close()
+ resp, err := aws.RetryingClient.Get(ts.URL)
+ if err != nil {
+ return
+ }
+ if resp.StatusCode != 200 {
+ return "", fmt.Errorf("Bad status code: %d", resp.StatusCode)
+ }
+ greeting, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ return
+ }
+ return strings.TrimSpace(string(greeting)), nil
+}
+
+func TestClient_expected(t *testing.T) {
+ body := "foo bar"
+
+ resp, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintln(w, body)
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != body {
+ t.Fatal("Body not as expected.")
+ }
+}
+
+func TestClient_delay(t *testing.T) {
+ body := "baz"
+ wait := 4
+ resp, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
+ if wait < 0 {
+ // If we dipped to zero delay and still failed.
+ t.Fatal("Never succeeded.")
+ }
+ wait -= 1
+ time.Sleep(time.Second * time.Duration(wait))
+ fmt.Fprintln(w, body)
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != body {
+ t.Fatal("Body not as expected.", resp)
+ }
+}
+
+func TestClient_no4xxRetry(t *testing.T) {
+ tries := 0
+
+ // Fail once before succeeding.
+ _, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
+ tries += 1
+ http.Error(w, "error", 404)
+ })
+
+ if err == nil {
+ t.Fatal("should have error")
+ }
+
+ if tries != 1 {
+ t.Fatalf("should only try once: %d", tries)
+ }
+}
+
+func TestClient_retries(t *testing.T) {
+ body := "biz"
+ failed := false
+ // Fail once before succeeding.
+ resp, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
+ if !failed {
+ http.Error(w, "error", 500)
+ failed = true
+ } else {
+ fmt.Fprintln(w, body)
+ }
+ })
+ if failed != true {
+ t.Error("We didn't retry!")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ if resp != body {
+ t.Fatal("Body not as expected.")
+ }
+}
+
+func TestClient_fails(t *testing.T) {
+ tries := 0
+ // Fail 3 times and return the last error.
+ _, err := serveAndGet(func(w http.ResponseWriter, r *http.Request) {
+ tries += 1
+ http.Error(w, "error", 500)
+ })
+ if err == nil {
+ t.Fatal(err)
+ }
+ if tries != 3 {
+ t.Fatal("Didn't retry enough")
+ }
+}
diff --git a/vendor/github.com/goamz/goamz/aws/export_test.go b/vendor/github.com/goamz/goamz/aws/export_test.go
new file mode 100644
index 000000000..c4aca1d72
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/aws/export_test.go
@@ -0,0 +1,29 @@
+package aws
+
+import (
+ "net/http"
+ "time"
+)
+
+// V4Signer:
+// Exporting methods for testing
+
+func (s *V4Signer) RequestTime(req *http.Request) time.Time {
+ return s.requestTime(req)
+}
+
+func (s *V4Signer) CanonicalRequest(req *http.Request) string {
+ return s.canonicalRequest(req)
+}
+
+func (s *V4Signer) StringToSign(t time.Time, creq string) string {
+ return s.stringToSign(t, creq)
+}
+
+func (s *V4Signer) Signature(t time.Time, sts string) string {
+ return s.signature(t, sts)
+}
+
+func (s *V4Signer) Authorization(header http.Header, t time.Time, signature string) string {
+ return s.authorization(header, t, signature)
+}
diff --git a/vendor/github.com/goamz/goamz/aws/sign_test.go b/vendor/github.com/goamz/goamz/aws/sign_test.go
new file mode 100644
index 000000000..4ce2ff9a0
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/aws/sign_test.go
@@ -0,0 +1,540 @@
+package aws_test
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ . "gopkg.in/check.v1"
+)
+
+var _ = Suite(&V4SignerSuite{})
+
+type V4SignerSuite struct {
+ auth aws.Auth
+ region aws.Region
+ cases []V4SignerSuiteCase
+}
+
+type V4SignerSuiteCase struct {
+ label string
+ request V4SignerSuiteCaseRequest
+ canonicalRequest string
+ stringToSign string
+ signature string
+ authorization string
+}
+
+type V4SignerSuiteCaseRequest struct {
+ method string
+ host string
+ url string
+ headers []string
+ body string
+}
+
+func (s *V4SignerSuite) SetUpSuite(c *C) {
+ s.auth = aws.Auth{AccessKey: "AKIDEXAMPLE", SecretKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"}
+ s.region = aws.USEast
+
+ // Test cases from the Signature Version 4 Test Suite (http://goo.gl/nguvs0)
+ s.cases = append(s.cases,
+
+ // get-header-key-duplicate
+ V4SignerSuiteCase{
+ label: "get-header-key-duplicate",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "ZOO:zoobar", "zoo:foobar", "zoo:zoobar"},
+ },
+ canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:foobar,zoobar,zoobar\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n3c52f0eaae2b61329c0a332e3fa15842a37bc5812cf4d80eb64784308850e313",
+ signature: "54afcaaf45b331f81cd2edb974f7b824ff4dd594cbbaa945ed636b48477368ed",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=54afcaaf45b331f81cd2edb974f7b824ff4dd594cbbaa945ed636b48477368ed",
+ },
+
+ // get-header-value-order
+ V4SignerSuiteCase{
+ label: "get-header-value-order",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "p:z", "p:a", "p:p", "p:a"},
+ },
+ canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\np:a,a,p,z\n\ndate;host;p\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n94c0389fefe0988cbbedc8606f0ca0b485b48da010d09fc844b45b697c8924fe",
+ signature: "d2973954263943b11624a11d1c963ca81fb274169c7868b2858c04f083199e3d",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=d2973954263943b11624a11d1c963ca81fb274169c7868b2858c04f083199e3d",
+ },
+
+ // get-header-value-trim
+ V4SignerSuiteCase{
+ label: "get-header-value-trim",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "p: phfft "},
+ },
+ canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\np:phfft\n\ndate;host;p\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ndddd1902add08da1ac94782b05f9278c08dc7468db178a84f8950d93b30b1f35",
+ signature: "debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;p, Signature=debf546796015d6f6ded8626f5ce98597c33b47b9164cf6b17b4642036fcb592",
+ },
+
+ // get-relative-relative
+ V4SignerSuiteCase{
+ label: "get-relative-relative",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/foo/bar/../..",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
+ signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ },
+
+ // get-relative
+ V4SignerSuiteCase{
+ label: "get-relative",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/foo/..",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
+ signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ },
+
+ // get-slash-dot-slash
+ V4SignerSuiteCase{
+ label: "get-slash-dot-slash",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/./",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
+ signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ },
+
+ // get-slash-pointless-dot
+ V4SignerSuiteCase{
+ label: "get-slash-pointless-dot",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/./foo",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/foo\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n8021a97572ee460f87ca67f4e8c0db763216d84715f5424a843a5312a3321e2d",
+ signature: "910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=910e4d6c9abafaf87898e1eb4c929135782ea25bb0279703146455745391e63a",
+ },
+
+ // get-slash
+ V4SignerSuiteCase{
+ label: "get-slash",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "//",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
+ signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ },
+
+ // get-slashes
+ V4SignerSuiteCase{
+ label: "get-slashes",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "//foo//",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/foo/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n6bb4476ee8745730c9cb79f33a0c70baa6d8af29c0077fa12e4e8f1dd17e7098",
+ signature: "b00392262853cfe3201e47ccf945601079e9b8a7f51ee4c3d9ee4f187aa9bf19",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b00392262853cfe3201e47ccf945601079e9b8a7f51ee4c3d9ee4f187aa9bf19",
+ },
+
+ // get-space
+ V4SignerSuiteCase{
+ label: "get-space",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/%20/foo",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/%20/foo\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n69c45fb9fe3fd76442b5086e50b2e9fec8298358da957b293ef26e506fdfb54b",
+ signature: "f309cfbd10197a230c42dd17dbf5cca8a0722564cb40a872d25623cfa758e374",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=f309cfbd10197a230c42dd17dbf5cca8a0722564cb40a872d25623cfa758e374",
+ },
+
+ // get-unreserved
+ V4SignerSuiteCase{
+ label: "get-unreserved",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ndf63ee3247c0356c696a3b21f8d8490b01fa9cd5bc6550ef5ef5f4636b7b8901",
+ signature: "830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=830cc36d03f0f84e6ee4953fbe701c1c8b71a0372c63af9255aa364dd183281e",
+ },
+
+ // get-utf8
+ V4SignerSuiteCase{
+ label: "get-utf8",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/%E1%88%B4",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/%E1%88%B4\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n27ba31df5dbc6e063d8f87d62eb07143f7f271c5330a917840586ac1c85b6f6b",
+ signature: "8d6634c189aa8c75c2e51e106b6b5121bed103fdb351f7d7d4381c738823af74",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=8d6634c189aa8c75c2e51e106b6b5121bed103fdb351f7d7d4381c738823af74",
+ },
+
+ // get-vanilla-empty-query-key
+ V4SignerSuiteCase{
+ label: "get-vanilla-empty-query-key",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/?foo=bar",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n0846c2945b0832deb7a463c66af5c4f8bd54ec28c438e67a214445b157c9ddf8",
+ signature: "56c054473fd260c13e4e7393eb203662195f5d4a1fada5314b8b52b23f985e9f",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=56c054473fd260c13e4e7393eb203662195f5d4a1fada5314b8b52b23f985e9f",
+ },
+
+ // get-vanilla-space-query-parameters
+ V4SignerSuiteCase{
+ label: "get-vanilla-space-query-parameters",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/?foo foo=bar bar",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\nfoo%20foo=bar%20bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n6a81658ae0a0a4f73aa72ca7d3b01c9cb0c5d4099f7a5ee897f5a571bfe6f7ff",
+ signature: "c8556bc676129d0806ea8fe6ef182dc095666f4c1582c3d9751d47e4306037c9",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=c8556bc676129d0806ea8fe6ef182dc095666f4c1582c3d9751d47e4306037c9",
+ },
+
+ // get-vanilla-query-order-key-case
+ V4SignerSuiteCase{
+ label: "get-vanilla-query-order-key-case",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/?foo=Zoo&foo=aha",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\nfoo=Zoo&foo=aha\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ne25f777ba161a0f1baf778a87faf057187cf5987f17953320e3ca399feb5f00d",
+ signature: "be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=be7148d34ebccdc6423b19085378aa0bee970bdc61d144bd1a8c48c33079ab09",
+ },
+
+ // get-vanilla-query-order-key
+ V4SignerSuiteCase{
+ label: "get-vanilla-query-order-key",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/?a=foo&b=foo",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\na=foo&b=foo\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n2f23d14fe13caebf6dfda346285c6d9c14f49eaca8f5ec55c627dd7404f7a727",
+ signature: "0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=0dc122f3b28b831ab48ba65cb47300de53fbe91b577fe113edac383730254a3b",
+ },
+
+ // get-vanilla-query-order-value
+ V4SignerSuiteCase{
+ label: "get-vanilla-query-order-value",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/?foo=b&foo=a",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\nfoo=a&foo=b\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n33dffc220e89131f8f6157a35c40903daa658608d9129ff9489e5cf5bbd9b11b",
+ signature: "feb926e49e382bec75c9d7dcb2a1b6dc8aa50ca43c25d2bc51143768c0875acc",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=feb926e49e382bec75c9d7dcb2a1b6dc8aa50ca43c25d2bc51143768c0875acc",
+ },
+
+ // get-vanilla-query-unreserved
+ V4SignerSuiteCase{
+ label: "get-vanilla-query-unreserved",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/?-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nd2578f3156d4c9d180713d1ff20601d8a3eed0dd35447d24603d7d67414bd6b5",
+ signature: "f1498ddb4d6dae767d97c466fb92f1b59a2c71ca29ac954692663f9db03426fb",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=f1498ddb4d6dae767d97c466fb92f1b59a2c71ca29ac954692663f9db03426fb",
+ },
+
+ // get-vanilla-query
+ V4SignerSuiteCase{
+ label: "get-vanilla-query",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
+ signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ },
+
+ // get-vanilla-ut8-query
+ V4SignerSuiteCase{
+ label: "get-vanilla-ut8-query",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/?ሴ=bar",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n%E1%88%B4=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nde5065ff39c131e6c2e2bd19cd9345a794bf3b561eab20b8d97b2093fc2a979e",
+ signature: "6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=6fb359e9a05394cc7074e0feb42573a2601abc0c869a953e8c5c12e4e01f1a8c",
+ },
+
+ // get-vanilla
+ V4SignerSuiteCase{
+ label: "get-vanilla",
+ request: V4SignerSuiteCaseRequest{
+ method: "GET",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "GET\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n366b91fb121d72a00f46bbe8d395f53a102b06dfb7e79636515208ed3fa606b1",
+ signature: "b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b27ccfbfa7df52a200ff74193ca6e32d4b48b8856fab7ebf1c595d0670a7e470",
+ },
+
+ // post-header-key-case
+ V4SignerSuiteCase{
+ label: "post-header-key-case",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n05da62cee468d24ae84faff3c39f1b85540de60243c1bcaace39c0a2acc7b2c4",
+ signature: "22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
+ },
+
+ // post-header-key-sort
+ V4SignerSuiteCase{
+ label: "post-header-key-sort",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "ZOO:zoobar"},
+ },
+ canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:zoobar\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n34e1bddeb99e76ee01d63b5e28656111e210529efeec6cdfd46a48e4c734545d",
+ signature: "b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=b7a95a52518abbca0964a999a880429ab734f35ebbf1235bd79a5de87756dc4a",
+ },
+
+ // post-header-value-case
+ V4SignerSuiteCase{
+ label: "post-header-value-case",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"DATE:Mon, 09 Sep 2011 23:36:00 GMT", "zoo:ZOOBAR"},
+ },
+ canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\nzoo:ZOOBAR\n\ndate;host;zoo\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n3aae6d8274b8c03e2cc96fc7d6bda4b9bd7a0a184309344470b2c96953e124aa",
+ signature: "273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host;zoo, Signature=273313af9d0c265c531e11db70bbd653f3ba074c1009239e8559d3987039cad7",
+ },
+
+ // post-vanilla-empty-query-value
+ V4SignerSuiteCase{
+ label: "post-vanilla-empty-query-value",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/?foo=bar",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "POST\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ncd4f39132d8e60bb388831d734230460872b564871c47f5de62e62d1a68dbe1e",
+ signature: "b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
+ },
+
+ // post-vanilla-query
+ V4SignerSuiteCase{
+ label: "post-vanilla-query",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/?foo=bar",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "POST\n/\nfoo=bar\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\ncd4f39132d8e60bb388831d734230460872b564871c47f5de62e62d1a68dbe1e",
+ signature: "b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=b6e3b79003ce0743a491606ba1035a804593b0efb1e20a11cba83f8c25a57a92",
+ },
+
+ // post-vanilla
+ V4SignerSuiteCase{
+ label: "post-vanilla",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ },
+ canonicalRequest: "POST\n/\n\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ndate;host\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n05da62cee468d24ae84faff3c39f1b85540de60243c1bcaace39c0a2acc7b2c4",
+ signature: "22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=date;host, Signature=22902d79e148b64e7571c3565769328423fe276eae4b26f83afceda9e767f726",
+ },
+
+ // post-x-www-form-urlencoded-parameters
+ V4SignerSuiteCase{
+ label: "post-x-www-form-urlencoded-parameters",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"Content-Type:application/x-www-form-urlencoded; charset=utf8", "Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ body: "foo=bar",
+ },
+ canonicalRequest: "POST\n/\n\ncontent-type:application/x-www-form-urlencoded; charset=utf8\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ncontent-type;date;host\n3ba8907e7a252327488df390ed517c45b96dead033600219bdca7107d1d3f88a",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\nc4115f9e54b5cecf192b1eaa23b8e88ed8dc5391bd4fde7b3fff3d9c9fe0af1f",
+ signature: "b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=b105eb10c6d318d2294de9d49dd8b031b55e3c3fe139f2e637da70511e9e7b71",
+ },
+
+ // post-x-www-form-urlencoded
+ V4SignerSuiteCase{
+ label: "post-x-www-form-urlencoded",
+ request: V4SignerSuiteCaseRequest{
+ method: "POST",
+ host: "host.foo.com",
+ url: "/",
+ headers: []string{"Content-Type:application/x-www-form-urlencoded", "Date:Mon, 09 Sep 2011 23:36:00 GMT"},
+ body: "foo=bar",
+ },
+ canonicalRequest: "POST\n/\n\ncontent-type:application/x-www-form-urlencoded\ndate:Mon, 09 Sep 2011 23:36:00 GMT\nhost:host.foo.com\n\ncontent-type;date;host\n3ba8907e7a252327488df390ed517c45b96dead033600219bdca7107d1d3f88a",
+ stringToSign: "AWS4-HMAC-SHA256\n20110909T233600Z\n20110909/us-east-1/host/aws4_request\n4c5c6e4b52fb5fb947a8733982a8a5a61b14f04345cbfe6e739236c76dd48f74",
+ signature: "5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc",
+ authorization: "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20110909/us-east-1/host/aws4_request, SignedHeaders=content-type;date;host, Signature=5a15b22cf462f047318703b92e6f4f38884e4a7ab7b1d6426ca46a8bd1c26cbc",
+ },
+ )
+}
+
+func (s *V4SignerSuite) TestCases(c *C) {
+ signer := aws.NewV4Signer(s.auth, "host", s.region)
+
+ for _, testCase := range s.cases {
+
+ req, err := http.NewRequest(testCase.request.method, "http://"+testCase.request.host+testCase.request.url, strings.NewReader(testCase.request.body))
+ c.Assert(err, IsNil, Commentf("Testcase: %s", testCase.label))
+ for _, v := range testCase.request.headers {
+ h := strings.SplitN(v, ":", 2)
+ req.Header.Add(h[0], h[1])
+ }
+ req.Header.Set("host", req.Host)
+
+ t := signer.RequestTime(req)
+
+ canonicalRequest := signer.CanonicalRequest(req)
+ c.Check(canonicalRequest, Equals, testCase.canonicalRequest, Commentf("Testcase: %s", testCase.label))
+
+ stringToSign := signer.StringToSign(t, canonicalRequest)
+ c.Check(stringToSign, Equals, testCase.stringToSign, Commentf("Testcase: %s", testCase.label))
+
+ signature := signer.Signature(t, stringToSign)
+ c.Check(signature, Equals, testCase.signature, Commentf("Testcase: %s", testCase.label))
+
+ authorization := signer.Authorization(req.Header, t, signature)
+ c.Check(authorization, Equals, testCase.authorization, Commentf("Testcase: %s", testCase.label))
+
+ signer.Sign(req)
+ c.Check(req.Header.Get("Authorization"), Equals, testCase.authorization, Commentf("Testcase: %s", testCase.label))
+ }
+}
+
+func ExampleV4Signer() {
+ // Get auth from env vars
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ // Create a signer with the auth, name of the service, and aws region
+ signer := aws.NewV4Signer(auth, "dynamodb", aws.USEast)
+
+ // Create a request
+ req, err := http.NewRequest("POST", aws.USEast.DynamoDBEndpoint, strings.NewReader("sample_request"))
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ // Date or x-amz-date header is required to sign a request
+ req.Header.Add("Date", time.Now().UTC().Format(http.TimeFormat))
+
+ // Sign the request
+ signer.Sign(req)
+
+ // Issue signed request
+ http.DefaultClient.Do(req)
+}
diff --git a/vendor/github.com/goamz/goamz/cloudformation/cloudformation.go b/vendor/github.com/goamz/goamz/cloudformation/cloudformation.go
new file mode 100644
index 000000000..00081d0c2
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudformation/cloudformation.go
@@ -0,0 +1,837 @@
+//
+// cloudformation: This package provides types and functions to interact with the AWS CloudFormation API
+//
+// Depends on https://github.com/goamz/goamz
+//
+
+package cloudformation
+
+import (
+ "encoding/xml"
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+// The CloudFormation type encapsulates operations within a specific EC2 region.
+type CloudFormation struct {
+ aws.Auth
+ aws.Region
+}
+
+// New creates a new CloudFormation Client.
+func New(auth aws.Auth, region aws.Region) *CloudFormation {
+
+ return &CloudFormation{auth, region}
+
+}
+
+const debug = false
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+// Error encapsulates an error returned by the AWS CloudFormation API.
+//
+// See http://goo.gl/zDZbuQ for more details.
+type Error struct {
+ // HTTP status code (200, 403, ...)
+ StatusCode int
+ // Error type
+ Type string `xml:"Type"`
+ // CloudFormation error code
+ Code string `xml:"Code"`
+ // The human-oriented error message
+ Message string `xml:"Message"`
+ RequestId string `xml:"RequestID"`
+}
+
+func (err *Error) Error() string {
+ if err.Code == "" {
+ return err.Message
+ }
+
+ return fmt.Sprintf("%s (%s)", err.Message, err.Code)
+}
+
+type xmlErrors struct {
+ RequestId string `xml:"RequestId"`
+ Errors []Error `xml:"Error"`
+}
+
+func (c *CloudFormation) query(params map[string]string, resp interface{}) error {
+ params["Version"] = "2010-05-15"
+
+ data := strings.NewReader(multimap(params).Encode())
+
+ hreq, err := http.NewRequest("POST", c.Region.CloudFormationEndpoint+"/", data)
+ if err != nil {
+ return err
+ }
+
+ hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+ token := c.Auth.Token()
+ if token != "" {
+ hreq.Header.Set("X-Amz-Security-Token", token)
+ }
+
+ signer := aws.NewV4Signer(c.Auth, "cloudformation", c.Region)
+ signer.Sign(hreq)
+
+ if debug {
+ log.Printf("%v -> {\n", hreq)
+ }
+ r, err := http.DefaultClient.Do(hreq)
+
+ if err != nil {
+ log.Printf("Error calling Amazon")
+ return err
+ }
+
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("response:\n")
+ log.Printf("%v\n}\n", string(dump))
+ }
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+func buildError(r *http.Response) error {
+ var (
+ err Error
+ errors xmlErrors
+ )
+ xml.NewDecoder(r.Body).Decode(&errors)
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+
+ err.RequestId = errors.RequestId
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+// addParamsList adds params in the form of param.member.N to the params map
+func addParamsList(params map[string]string, label string, ids []string) {
+ for i, id := range ids {
+ params[label+"."+strconv.Itoa(i+1)] = id
+ }
+}
+
+// -----------------------------------------------------------------------
+// API Supported Types and Methods
+
+// SimpleResp is the basic response from most actions.
+type SimpleResp struct {
+ XMLName xml.Name
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// CancelUpdateStack cancels an update on the specified stack.
+// If the call completes successfully, the stack will roll back the update and revert
+// to the previous stack configuration.
+//
+// See http://goo.gl/ZE6fOa for more details
+func (c *CloudFormation) CancelUpdateStack(stackName string) (resp *SimpleResp, err error) {
+ params := makeParams("CancelUpdateStack")
+
+ params["StackName"] = stackName
+
+ resp = new(SimpleResp)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Parameter encapsulates the cloudstack paramter data type
+//
+// See http://goo.gl/2rg9eG for more details
+type Parameter struct {
+ ParameterKey string `xml:"ParameterKey"`
+ ParameterValue string `xml:"ParameterValue"`
+ UsePreviousValue bool `xml:"UsePreviousValue"`
+}
+
+type Tag struct {
+ Key string `xml:"Key"`
+ Value string `xml:"Value"`
+}
+
+// CreateStackParams wraps CreateStack request options
+//
+// See http://goo.gl/yDZYuV for more information
+type CreateStackParams struct {
+ Capabilities []string
+ DisableRollback bool
+ NotificationARNs []string
+ OnFailure string
+ Parameters []Parameter
+ StackName string
+ StackPolicyBody string
+ StackPolicyURL string
+ Tags []Tag
+ TemplateBody string
+ TemplateURL string
+ TimeoutInMinutes int
+}
+
+// CreateStackResponse wraps a CreateStack call response
+//
+// See http://goo.gl/yDZYuV for more details
+type CreateStackResponse struct {
+ StackId string `xml:"CreateStackResult>StackId"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// CreateStack creates a stack as specified in the template. After the call completes successfully,
+// the stack creation starts.
+//
+// Required params: StackName
+//
+// See http://goo.gl/yDZYuV for more details
+func (c *CloudFormation) CreateStack(options *CreateStackParams) (
+ resp *CreateStackResponse, err error) {
+ params := makeParams("CreateStack")
+
+ params["StackName"] = options.StackName
+
+ if options.DisableRollback {
+ params["DisableRollback"] = strconv.FormatBool(options.DisableRollback)
+ }
+ if options.OnFailure != "" {
+ params["OnFailure"] = options.OnFailure
+ }
+ if options.StackPolicyBody != "" {
+ params["StackPolicyBody"] = options.StackPolicyBody
+ }
+ if options.StackPolicyURL != "" {
+ params["StackPolicyURL"] = options.StackPolicyURL
+ }
+ if options.TemplateBody != "" {
+ params["TemplateBody"] = options.TemplateBody
+ }
+ if options.TemplateURL != "" {
+ params["TemplateURL"] = options.TemplateURL
+ }
+ if options.TimeoutInMinutes != 0 {
+ params["TimeoutInMinutes"] = strconv.Itoa(options.TimeoutInMinutes)
+ }
+ if len(options.Capabilities) > 0 {
+ addParamsList(params, "Capabilities.member", options.Capabilities)
+ }
+ if len(options.NotificationARNs) > 0 {
+ addParamsList(params, "NotificationARNs.member", options.NotificationARNs)
+ }
+ // Add any parameters
+ for i, t := range options.Parameters {
+ key := "Parameters.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
+ params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
+ params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
+ }
+ // Add any tags
+ for i, t := range options.Tags {
+ key := "Tags.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "Key")] = t.Key
+ params[fmt.Sprintf(key, index, "Value")] = t.Value
+ }
+
+ resp = new(CreateStackResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteStack deletes a specified stack.
+// Once the call completes successfully, stack deletion starts.
+//
+// See http://goo.gl/CVMpxC for more details
+func (c *CloudFormation) DeleteStack(stackName string) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteStack")
+
+ params["StackName"] = stackName
+
+ resp = new(SimpleResp)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StackEvent encapsulates the StackEvent data type
+//
+// See http://goo.gl/EHwiMf for more details
+type StackEvent struct {
+ EventId string `xml:"EventId"`
+ LogicalResourceId string `xml:"LogicalResourceId"`
+ PhysicalResourceId string `xml:"PhysicalResourceId"`
+ ResourceProperties string `xml:"ResourceProperties"`
+ ResourceStatus string `xml:"ResourceStatus"`
+ ResourceStatusReason string `xml:"ResourceStatusReason"`
+ ResourceType string `xml:"ResourceType"`
+ StackId string `xml:"StackId"`
+ StackName string `xml:"StackName"`
+ Timestamp time.Time `xml:"Timestamp"`
+}
+
+// DescribeStackEventsResponse wraps a response returned by DescribeStackEvents request
+//
+// See http://goo.gl/zqj4Bz for more details
+type DescribeStackEventsResponse struct {
+ NextToken string `xml:"DescribeStackEventsResult>NextToken"`
+ StackEvents []StackEvent `xml:"DescribeStackEventsResult>StackEvents>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeStackEvents returns all stack related events for a specified stack.
+//
+// See http://goo.gl/zqj4Bz for more details
+func (c *CloudFormation) DescribeStackEvents(stackName string, nextToken string) (
+ resp *DescribeStackEventsResponse, err error) {
+ params := makeParams("DescribeStackEvents")
+
+ if stackName != "" {
+ params["StackName"] = stackName
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ resp = new(DescribeStackEventsResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StackResourceDetail encapsulates the StackResourceDetail data type
+//
+// See http://goo.gl/flce6I for more details
+type StackResourceDetail struct {
+ Description string `xml:"Description"`
+ LastUpdatedTimestamp time.Time `xml:"LastUpdatedTimestamp"`
+ LogicalResourceId string `xml:"LogicalResourceId"`
+ Metadata string `xml:"Metadata"`
+ PhysicalResourceId string `xml:"PhysicalResourceId"`
+ ResourceStatus string `xml:"ResourceStatus"`
+ ResourceStatusReason string `xml:"ResourceStatusReason"`
+ ResourceType string `xml:"ResourceType"`
+ StackId string `xml:"StackId"`
+ StackName string `xml:"StackName"`
+}
+
+// DescribeStackResourceResponse wraps a response returned by DescribeStackResource request
+//
+// See http://goo.gl/6pfPFs for more details
+type DescribeStackResourceResponse struct {
+ StackResourceDetail StackResourceDetail `xml:"DescribeStackResourceResult>StackResourceDetail"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeStackResource returns a description of the specified resource in the specified stack.
+// For deleted stacks, DescribeStackResource returns resource information
+// for up to 90 days after the stack has been deleted.
+//
+// Required params: stackName, logicalResourceId
+//
+// See http://goo.gl/6pfPFs for more details
+func (c *CloudFormation) DescribeStackResource(stackName string, logicalResourceId string) (
+ resp *DescribeStackResourceResponse, err error) {
+ params := makeParams("DescribeStackResource")
+
+ params["StackName"] = stackName
+ params["LogicalResourceId"] = logicalResourceId
+
+ resp = new(DescribeStackResourceResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StackResource encapsulates the StackResource data type
+//
+// See http://goo.gl/j4eli5 for more details
+type StackResource struct {
+ Description string `xml:"Description"`
+ LogicalResourceId string `xml:"LogicalResourceId"`
+ PhysicalResourceId string `xml:"PhysicalResourceId"`
+ ResourceStatus string `xml:"ResourceStatus"`
+ ResourceStatusReason string `xml:"ResourceStatusReason"`
+ ResourceType string `xml:"ResourceType"`
+ StackId string `xml:"StackId"`
+ StackName string `xml:"StackName"`
+ Timestamp time.Time `xml:"Timestamp"`
+}
+
+// DescribeStackResourcesResponse wraps a response returned by DescribeStackResources request
+//
+// See http://goo.gl/YnY5rs for more details
+type DescribeStackResourcesResponse struct {
+ StackResources []StackResource `xml:"DescribeStackResourcesResult>StackResources>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeStackResources returns AWS resource descriptions for running and deleted stacks.
+// If stackName is specified, all the associated resources that are part of the stack are returned.
+// If physicalResourceId is specified, the associated resources of the stack that the resource
+// belongs to are returned.
+//
+// Only the first 100 resources will be returned. If your stack has more resources than this,
+// you should use ListStackResources instead.
+//
+// See http://goo.gl/YnY5rs for more details
+func (c *CloudFormation) DescribeStackResources(stackName, physicalResourceId, logicalResourceId string) (
+ resp *DescribeStackResourcesResponse, err error) {
+ params := makeParams("DescribeStackResources")
+
+ if stackName != "" {
+ params["StackName"] = stackName
+ }
+ if physicalResourceId != "" {
+ params["PhysicalResourceId"] = physicalResourceId
+ }
+ if logicalResourceId != "" {
+ params["LogicalResourceId"] = logicalResourceId
+ }
+
+ resp = new(DescribeStackResourcesResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Output encapsulates the Output AWS data type
+//
+// See http://goo.gl/UOn7q6 for more information
+type Output struct {
+ Description string `xml:"Description"`
+ OutputKey string `xml:"OutputKey"`
+ OutputValue string `xml:"OutputValue"`
+}
+
+// Stack encapsulates the Stack AWS data type
+//
+// See http://goo.gl/yDZYuV for more information
+type Stack struct {
+ Capabilities []string `xml:"Capabilities>member"`
+ CreationTime time.Time `xml:"CreationTime"`
+ Description string `xml:"Description"`
+ DisableRollback bool `xml:"DisableRollback"`
+ LastUpdatedTime time.Time `xml:"LastUpdatedTime"`
+ NotificationARNs []string `xml:"NotificationARNs>member"`
+ Outputs []Output `xml:"Outputs>member"`
+ Parameters []Parameter `xml:"Parameters>member"`
+ StackId string `xml:"StackId"`
+ StackName string `xml:"StackName"`
+ StackStatus string `xml:"StackStatus"`
+ StackStatusReason string `xml:"StackStatusReason"`
+ Tags []Tag `xml:"Tags>member"`
+ TimeoutInMinutes int `xml:"TimeoutInMinutes"`
+}
+
+// DescribeStacksResponse wraps a response returned by DescribeStacks request
+//
+// See http://goo.gl/UOLsXD for more information
+type DescribeStacksResponse struct {
+ NextToken string `xml:"DescribeStacksResult>NextToken"`
+ Stacks []Stack `xml:"DescribeStacksResult>Stacks>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeStacks returns the description for the specified stack;
+// If no stack name was specified, then it returns the description for all the stacks created.
+//
+// See http://goo.gl/UOLsXD for more information
+func (c *CloudFormation) DescribeStacks(stackName string, nextToken string) (
+ resp *DescribeStacksResponse, err error) {
+ params := makeParams("DescribeStacks")
+
+ if stackName != "" {
+ params["StackName"] = stackName
+ }
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ resp = new(DescribeStacksResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// EstimateTemplateCostResponse wraps a response returned by EstimateTemplateCost request
+//
+// See http://goo.gl/PD9hle for more information
+type EstimateTemplateCostResponse struct {
+ Url string `xml:"EstimateTemplateCostResult>Url"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// EstimateTemplateCost returns the estimated monthly cost of a template.
+// The return value is an AWS Simple Monthly Calculator URL with a query string that describes
+// the resources required to run the template.
+//
+// See http://goo.gl/PD9hle for more information
+func (c *CloudFormation) EstimateTemplateCost(parameters []Parameter, templateBody, templateUrl string) (
+ resp *EstimateTemplateCostResponse, err error) {
+ params := makeParams("EstimateTemplateCost")
+
+ if templateBody != "" {
+ params["TemplateBody"] = templateBody
+ }
+ if templateUrl != "" {
+ params["TemplateURL"] = templateUrl
+ }
+ // Add any parameters
+ for i, t := range parameters {
+ key := "Parameters.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
+ params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
+ params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
+ }
+
+ resp = new(EstimateTemplateCostResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// GetStackPolicyResponse wraps a response returned by GetStackPolicy request
+//
+// See http://goo.gl/iZFSgy for more information
+type GetStackPolicyResponse struct {
+ StackPolicyBody string `xml:"GetStackPolicyResult>StackPolicyBody"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// GetStackPolicy returns the stack policy for a specified stack. If a stack doesn't have a policy,
+// a null value is returned.
+//
+// See http://goo.gl/iZFSgy for more information
+func (c *CloudFormation) GetStackPolicy(stackName string) (
+ resp *GetStackPolicyResponse, err error) {
+ params := makeParams("GetStackPolicy")
+
+ params["StackName"] = stackName
+
+ resp = new(GetStackPolicyResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// GetTemplateResponse wraps a response returned by GetTemplate request
+//
+// See http://goo.gl/GU59CB for more information
+type GetTemplateResponse struct {
+ TemplateBody string `xml:"GetTemplateResult>TemplateBody"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// GetTemplate returns the template body for a specified stack.
+// You can get the template for running or deleted stacks
+//
+// Required Params: StackName - The name or the unique identifier associated with the stack,
+// which are not always interchangeable:
+// Running stacks: You can specify either the stack's name or its unique stack ID.
+// Deleted stacks: You must specify the unique stack ID.
+//
+// See http://goo.gl/GU59CB for more information
+func (c *CloudFormation) GetTemplate(stackName string) (
+ resp *GetTemplateResponse, err error) {
+ params := makeParams("GetTemplate")
+
+ params["StackName"] = stackName
+
+ resp = new(GetTemplateResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StackResourceSummary encapsulates the StackResourceSummary data type
+//
+// See http://goo.gl/Af0vcm for more details
+type StackResourceSummary struct {
+ LastUpdatedTimestamp time.Time `xml:"LastUpdatedTimestamp"`
+ LogicalResourceId string `xml:"LogicalResourceId"`
+ PhysicalResourceId string `xml:"PhysicalResourceId"`
+ ResourceStatus string `xml:"ResourceStatus"`
+ ResourceStatusReason string `xml:"ResourceStatusReason"`
+ ResourceType string `xml:"ResourceType"`
+}
+
+// ListStackResourcesResponse wraps a response returned by ListStackResources request
+//
+// See http://goo.gl/JUCgLf for more details
+type ListStackResourcesResponse struct {
+ NextToken string `xml:"ListStackResourcesResult>NextToken"`
+ StackResourceSummaries []StackResourceSummary `xml:"ListStackResourcesResult>StackResourceSummaries>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ListStackResources returns descriptions of all resources of the specified stack.
+// For deleted stacks, ListStackResources returns resource information for up to 90 days
+// after the stack has been deleted.
+//
+// Required Params: stackName - the name or the unique identifier associated with the stack,
+// which are not always interchangeable:
+// Running stacks: You can specify either the stack's name or its unique stack ID.
+// Deleted stacks: You must specify the unique stack ID.
+//
+// See http://goo.gl/JUCgLf for more details
+func (c *CloudFormation) ListStackResources(stackName, nextToken string) (
+ resp *ListStackResourcesResponse, err error) {
+ params := makeParams("ListStackResources")
+
+ params["StackName"] = stackName
+
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ resp = new(ListStackResourcesResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StackSummary encapsulates the StackSummary data type
+//
+// See http://goo.gl/35j3wf for more details
+type StackSummary struct {
+ CreationTime time.Time `xml:"CreationTime"`
+ DeletionTime time.Time `xml:"DeletionTime"`
+ LastUpdatedTime time.Time `xml:"LastUpdatedTime"`
+ StackId string `xml:"StackId"`
+ StackName string `xml:"StackName"`
+ StackStatus string `xml:"StackStatus"`
+ StackStatusReason string `xml:"StackStatusReason"`
+ TemplateDescription string `xml:"TemplateDescription"`
+}
+
+// ListStacksResponse wraps a response returned by ListStacks request
+//
+// See http://goo.gl/UWi6nm for more details
+type ListStacksResponse struct {
+ NextToken string `xml:"ListStacksResult>NextToken"`
+ StackSummaries []StackSummary `xml:"ListStacksResult>StackSummaries>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ListStacks Returns the summary information for stacks whose status matches the specified StackStatusFilter.
+// Summary information for stacks that have been deleted is kept for 90 days after the stack is deleted.
+// If no StackStatusFilter is specified, summary information for all stacks is returned
+// (including existing stacks and stacks that have been deleted).
+//
+// See http://goo.gl/UWi6nm for more details
+func (c *CloudFormation) ListStacks(stackStatusFilters []string, nextToken string) (
+ resp *ListStacksResponse, err error) {
+ params := makeParams("ListStacks")
+
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ if len(stackStatusFilters) > 0 {
+ addParamsList(params, "StackStatusFilter.member", stackStatusFilters)
+ }
+
+ resp = new(ListStacksResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// SetStackPolicy sets a stack policy for a specified stack.
+//
+// Required Params: stackName
+//
+// See http://goo.gl/iY9ohu for more information
+func (c *CloudFormation) SetStackPolicy(stackName, stackPolicyBody, stackPolicyUrl string) (
+ resp *SimpleResp, err error) {
+ params := makeParams("SetStackPolicy")
+
+ params["StackName"] = stackName
+
+ if stackPolicyBody != "" {
+ params["StackPolicyBody"] = stackPolicyBody
+ }
+ if stackPolicyUrl != "" {
+ params["StackPolicyURL"] = stackPolicyUrl
+ }
+
+ resp = new(SimpleResp)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// UpdateStackParams wraps UpdateStack request options
+//
+// See http://goo.gl/LvkhZq for more information
+type UpdateStackParams struct {
+ Capabilities []string
+ NotificationARNs []string
+ Parameters []Parameter
+ StackName string
+ StackPolicyBody string
+ StackPolicyDuringUpdateBody string
+ StackPolicyDuringUpdateURL string
+ StackPolicyURL string
+ TemplateBody string
+ TemplateURL string
+ UsePreviousTemplate bool
+}
+
+// UpdateStackResponse wraps the UpdateStack call response
+//
+// See http://goo.gl/LvkhZq for more information
+type UpdateStackResponse struct {
+ StackId string `xml:"UpdateStackResult>StackId"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// UpdateStack updates a stack as specified in the template.
+// After the call completes successfully, the stack update starts.
+// You can check the status of the stack via the DescribeStacks action.
+//
+// Required Params: options.StackName
+//
+// See http://goo.gl/LvkhZq for more information
+func (c *CloudFormation) UpdateStack(options *UpdateStackParams) (
+ resp *UpdateStackResponse, err error) {
+ params := makeParams("UpdateStack")
+
+ params["StackName"] = options.StackName
+
+ if options.StackPolicyBody != "" {
+ params["StackPolicyBody"] = options.StackPolicyBody
+ }
+ if options.StackPolicyDuringUpdateBody != "" {
+ params["StackPolicyDuringUpdateBody"] = options.StackPolicyDuringUpdateBody
+ }
+ if options.StackPolicyDuringUpdateURL != "" {
+ params["StackPolicyDuringUpdateURL"] = options.StackPolicyDuringUpdateURL
+ }
+ if options.StackPolicyURL != "" {
+ params["StackPolicyURL"] = options.StackPolicyURL
+ }
+ if options.TemplateBody != "" {
+ params["TemplateBody"] = options.TemplateBody
+ }
+ if options.TemplateURL != "" {
+ params["TemplateURL"] = options.TemplateURL
+ }
+ if options.UsePreviousTemplate {
+ params["UsePreviousTemplate"] = strconv.FormatBool(options.UsePreviousTemplate)
+ }
+
+ if len(options.Capabilities) > 0 {
+ addParamsList(params, "Capabilities.member", options.Capabilities)
+ }
+ if len(options.NotificationARNs) > 0 {
+ addParamsList(params, "NotificationARNs.member", options.NotificationARNs)
+ }
+ // Add any parameters
+ for i, t := range options.Parameters {
+ key := "Parameters.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "ParameterKey")] = t.ParameterKey
+ params[fmt.Sprintf(key, index, "ParameterValue")] = t.ParameterValue
+ params[fmt.Sprintf(key, index, "UsePreviousValue")] = strconv.FormatBool(t.UsePreviousValue)
+ }
+
+ resp = new(UpdateStackResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// TemplateParameter encapsulates the AWS TemplateParameter data type
+//
+// See http://goo.gl/OBhNzk for more information
+type TemplateParameter struct {
+ DefaultValue string `xml:"DefaultValue"`
+ Description string `xml:Description"`
+ NoEcho bool `xml:NoEcho"`
+ ParameterKey string `xml:ParameterKey"`
+}
+
+// ValidateTemplateResponse wraps the ValidateTemplate call response
+//
+// See http://goo.gl/OBhNzk for more information
+type ValidateTemplateResponse struct {
+ Capabilities []string `xml:"ValidateTemplateResult>Capabilities>member"`
+ CapabilitiesReason string `xml:"ValidateTemplateResult>CapabilitiesReason"`
+ Description string `xml:"ValidateTemplateResult>Description"`
+ Parameters []TemplateParameter `xml:"ValidateTemplateResult>Parameters>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ValidateTemplate validates a specified template.
+//
+// See http://goo.gl/OBhNzk for more information
+func (c *CloudFormation) ValidateTemplate(templateBody, templateUrl string) (
+ resp *ValidateTemplateResponse, err error) {
+ params := makeParams("ValidateTemplate")
+
+ if templateBody != "" {
+ params["TemplateBody"] = templateBody
+ }
+ if templateUrl != "" {
+ params["TemplateURL"] = templateUrl
+ }
+
+ resp = new(ValidateTemplateResponse)
+ if err := c.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
diff --git a/vendor/github.com/goamz/goamz/cloudformation/cloudformation_test.go b/vendor/github.com/goamz/goamz/cloudformation/cloudformation_test.go
new file mode 100644
index 000000000..1937e8042
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudformation/cloudformation_test.go
@@ -0,0 +1,653 @@
+package cloudformation_test
+
+import (
+ "testing"
+ "time"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/goamz/goamz/aws"
+ cf "github.com/goamz/goamz/cloudformation"
+ "github.com/goamz/goamz/testutil"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ cf *cf.CloudFormation
+}
+
+var testServer = testutil.NewHTTPServer()
+
+var mockTest bool
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.cf = cf.New(auth, aws.Region{CloudFormationEndpoint: testServer.URL})
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestCancelUpdateStack(c *C) {
+ testServer.Response(200, nil, CancelUpdateStackResponse)
+
+ resp, err := s.cf.CancelUpdateStack("foo")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "CancelUpdateStack")
+ c.Assert(values.Get("StackName"), Equals, "foo")
+ // Response test
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+}
+
+func (s *S) TestCreateStack(c *C) {
+ testServer.Response(200, nil, CreateStackResponse)
+
+ stackParams := &cf.CreateStackParams{
+ NotificationARNs: []string{"arn:aws:sns:us-east-1:1234567890:my-topic"},
+ Parameters: []cf.Parameter{
+ {
+ ParameterKey: "AvailabilityZone",
+ ParameterValue: "us-east-1a",
+ },
+ },
+ StackName: "MyStack",
+ TemplateBody: "[Template Document]",
+ }
+ resp, err := s.cf.CreateStack(stackParams)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "CreateStack")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("NotificationARNs.member.1"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic")
+ c.Assert(values.Get("TemplateBody"), Equals, "[Template Document]")
+ c.Assert(values.Get("Parameters.member.1.ParameterKey"), Equals, "AvailabilityZone")
+ c.Assert(values.Get("Parameters.member.1.ParameterValue"), Equals, "us-east-1a")
+ // Response test
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+ c.Assert(resp.StackId, Equals, "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83")
+}
+
+func (s *S) TestCreateStackWithInvalidParams(c *C) {
+ testServer.Response(400, nil, CreateStackWithInvalidParamsResponse)
+ //testServer.Response(200, nil, DeleteAutoScalingGroupResponse)
+
+ cfTemplate := `
+{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+ "Description" : "Sample template",
+ "Parameters" : {
+ "KeyName" : {
+ "Description" : "key pair",
+ "Type" : "String"
+ }
+ },
+ "Resources" : {
+ "Ec2Instance" : {
+ "Type" : "AWS::EC2::Instance",
+ "Properties" : {
+ "KeyName" : { "Ref" : "KeyName" },
+ "ImageId" : "ami-7f418316",
+ "UserData" : { "Fn::Base64" : "80" }
+ }
+ }
+ },
+ "Outputs" : {
+ "InstanceId" : {
+ "Description" : "InstanceId of the newly created EC2 instance",
+ "Value" : { "Ref" : "Ec2Instance" }
+ }
+}`
+
+ stackParams := &cf.CreateStackParams{
+ Capabilities: []string{"CAPABILITY_IAM"},
+ DisableRollback: true,
+ NotificationARNs: []string{
+ "arn:aws:sns:us-east-1:1234567890:my-topic",
+ "arn:aws:sns:us-east-1:1234567890:my-topic2",
+ },
+ OnFailure: "ROLLBACK",
+ Parameters: []cf.Parameter{
+ {
+ ParameterKey: "AvailabilityZone",
+ ParameterValue: "us-east-1a",
+ },
+ },
+ StackName: "MyStack",
+ StackPolicyBody: "{PolicyBody}",
+ StackPolicyURL: "http://stack-policy-url",
+ Tags: []cf.Tag{
+ {
+ Key: "TagKey",
+ Value: "TagValue",
+ },
+ },
+ TemplateBody: cfTemplate,
+ TemplateURL: "http://url",
+ TimeoutInMinutes: 20,
+ }
+ resp, err := s.cf.CreateStack(stackParams)
+ c.Assert(err, NotNil)
+ c.Assert(resp, IsNil)
+ values := testServer.WaitRequest().PostForm
+
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "CreateStack")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("NotificationARNs.member.1"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic")
+ c.Assert(values.Get("NotificationARNs.member.2"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic2")
+ c.Assert(values.Get("Capabilities.member.1"), Equals, "CAPABILITY_IAM")
+ c.Assert(values.Get("TemplateBody"), Equals, cfTemplate)
+ c.Assert(values.Get("TemplateURL"), Equals, "http://url")
+ c.Assert(values.Get("StackPolicyBody"), Equals, "{PolicyBody}")
+ c.Assert(values.Get("StackPolicyURL"), Equals, "http://stack-policy-url")
+ c.Assert(values.Get("OnFailure"), Equals, "ROLLBACK")
+ c.Assert(values.Get("DisableRollback"), Equals, "true")
+ c.Assert(values.Get("Tags.member.1.Key"), Equals, "TagKey")
+ c.Assert(values.Get("Tags.member.1.Value"), Equals, "TagValue")
+ c.Assert(values.Get("Parameters.member.1.ParameterKey"), Equals, "AvailabilityZone")
+ c.Assert(values.Get("Parameters.member.1.ParameterValue"), Equals, "us-east-1a")
+ c.Assert(values.Get("TimeoutInMinutes"), Equals, "20")
+
+ // Response test
+ c.Assert(err.(*cf.Error).RequestId, Equals, "70a76d42-9665-11e2-9fdf-211deEXAMPLE")
+ c.Assert(err.(*cf.Error).Message, Equals, "Either Template URL or Template Body must be specified.")
+ c.Assert(err.(*cf.Error).Type, Equals, "Sender")
+ c.Assert(err.(*cf.Error).Code, Equals, "ValidationError")
+ c.Assert(err.(*cf.Error).StatusCode, Equals, 400)
+
+}
+
+func (s *S) TestDeleteStack(c *C) {
+ testServer.Response(200, nil, DeleteStackResponse)
+
+ resp, err := s.cf.DeleteStack("foo")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "DeleteStack")
+ c.Assert(values.Get("StackName"), Equals, "foo")
+ // Response test
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+}
+
+func (s *S) TestDescribeStackEvents(c *C) {
+ testServer.Response(200, nil, DescribeStackEventsResponse)
+
+ resp, err := s.cf.DescribeStackEvents("MyStack", "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+
+ // Post request test
+ t1, _ := time.Parse(time.RFC3339, "2010-07-27T22:26:28Z")
+ t2, _ := time.Parse(time.RFC3339, "2010-07-27T22:27:28Z")
+ t3, _ := time.Parse(time.RFC3339, "2010-07-27T22:28:28Z")
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "DescribeStackEvents")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("NextToken"), Equals, "")
+
+ // Response test
+ expected := &cf.DescribeStackEventsResponse{
+ StackEvents: []cf.StackEvent{
+ {
+ EventId: "Event-1-Id",
+ StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
+ StackName: "MyStack",
+ LogicalResourceId: "MyStack",
+ PhysicalResourceId: "MyStack_One",
+ ResourceType: "AWS::CloudFormation::Stack",
+ Timestamp: t1,
+ ResourceStatus: "CREATE_IN_PROGRESS",
+ ResourceStatusReason: "User initiated",
+ },
+ {
+ EventId: "Event-2-Id",
+ StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
+ StackName: "MyStack",
+ LogicalResourceId: "MyDBInstance",
+ PhysicalResourceId: "MyStack_DB1",
+ ResourceType: "AWS::SecurityGroup",
+ Timestamp: t2,
+ ResourceStatus: "CREATE_IN_PROGRESS",
+ ResourceProperties: "{\"GroupDescription\":...}",
+ },
+ {
+ EventId: "Event-3-Id",
+ StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
+ StackName: "MyStack",
+ LogicalResourceId: "MySG1",
+ PhysicalResourceId: "MyStack_SG1",
+ ResourceType: "AWS::SecurityGroup",
+ Timestamp: t3,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ },
+ NextToken: "",
+ RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeStackResource(c *C) {
+ testServer.Response(200, nil, DescribeStackResourceResponse)
+
+ resp, err := s.cf.DescribeStackResource("MyStack", "MyDBInstance")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "DescribeStackResource")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("LogicalResourceId"), Equals, "MyDBInstance")
+ t, _ := time.Parse(time.RFC3339, "2011-07-07T22:27:28Z")
+ // Response test
+ expected := &cf.DescribeStackResourceResponse{
+ StackResourceDetail: cf.StackResourceDetail{
+ StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
+ StackName: "MyStack",
+ LogicalResourceId: "MyDBInstance",
+ PhysicalResourceId: "MyStack_DB1",
+ ResourceType: "AWS::RDS::DBInstance",
+ LastUpdatedTimestamp: t,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeStackResources(c *C) {
+ testServer.Response(200, nil, DescribeStackResourcesResponse)
+
+ resp, err := s.cf.DescribeStackResources("MyStack", "", "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+
+ // Post request test
+ t1, _ := time.Parse(time.RFC3339, "2010-07-27T22:27:28Z")
+ t2, _ := time.Parse(time.RFC3339, "2010-07-27T22:28:28Z")
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "DescribeStackResources")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("PhysicalResourceId"), Equals, "")
+ c.Assert(values.Get("LogicalResourceId"), Equals, "")
+
+ // Response test
+ expected := &cf.DescribeStackResourcesResponse{
+ StackResources: []cf.StackResource{
+ {
+ StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
+ StackName: "MyStack",
+ LogicalResourceId: "MyDBInstance",
+ PhysicalResourceId: "MyStack_DB1",
+ ResourceType: "AWS::DBInstance",
+ Timestamp: t1,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ {
+ StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
+ StackName: "MyStack",
+ LogicalResourceId: "MyAutoScalingGroup",
+ PhysicalResourceId: "MyStack_ASG1",
+ ResourceType: "AWS::AutoScalingGroup",
+ Timestamp: t2,
+ ResourceStatus: "CREATE_IN_PROGRESS",
+ },
+ },
+ RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeStacks(c *C) {
+ testServer.Response(200, nil, DescribeStacksResponse)
+
+ resp, err := s.cf.DescribeStacks("MyStack", "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+
+ // Post request test
+ t, _ := time.Parse(time.RFC3339, "2010-07-27T22:28:28Z")
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "DescribeStacks")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("NextToken"), Equals, "")
+
+ // Response test
+ expected := &cf.DescribeStacksResponse{
+ Stacks: []cf.Stack{
+ {
+ StackId: "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83",
+ StackName: "MyStack",
+ Description: "My Description",
+ Capabilities: []string{"CAPABILITY_IAM"},
+ NotificationARNs: []string{"arn:aws:sns:region-name:account-name:topic-name"},
+ Parameters: []cf.Parameter{
+ {
+ ParameterKey: "MyKey",
+ ParameterValue: "MyValue",
+ },
+ },
+ Tags: []cf.Tag{
+ {
+ Key: "MyTagKey",
+ Value: "MyTagValue",
+ },
+ },
+ CreationTime: t,
+ StackStatus: "CREATE_COMPLETE",
+ DisableRollback: false,
+ Outputs: []cf.Output{
+ {
+ Description: "ServerUrl",
+ OutputKey: "StartPage",
+ OutputValue: "http://my-load-balancer.amazonaws.com:80/index.html",
+ },
+ },
+ },
+ },
+ NextToken: "",
+ RequestId: "4af14eec-350e-11e4-b260-EXAMPLE",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestEstimateTemplateCost(c *C) {
+ testServer.Response(200, nil, EstimateTemplateCostResponse)
+
+ resp, err := s.cf.EstimateTemplateCost(nil, "", "https://s3.amazonaws.com/cloudformation-samples-us-east-1/Drupal_Simple.template")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "EstimateTemplateCost")
+ c.Assert(values.Get("TemplateBody"), Equals, "")
+ c.Assert(values.Get("TemplateURL"), Equals, "https://s3.amazonaws.com/cloudformation-samples-us-east-1/Drupal_Simple.template")
+ // Response test
+ c.Assert(resp.Url, Equals, "http://calculator.s3.amazonaws.com/calc5.html?key=cf-2e351785-e821-450c-9d58-625e1e1ebfb6")
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+}
+
+func (s *S) TestGetStackPolicy(c *C) {
+ testServer.Response(200, nil, GetStackPolicyResponse)
+
+ resp, err := s.cf.GetStackPolicy("MyStack")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "GetStackPolicy")
+
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ // Response test
+ policy := `{
+ "Statement" : [
+ {
+ "Effect" : "Deny",
+ "Action" : "Update:*",
+ "Principal" : "*",
+ "Resource" : "LogicalResourceId/ProductionDatabase"
+ },
+ {
+ "Effect" : "Allow",
+ "Action" : "Update:*",
+ "Principal" : "*",
+ "Resource" : "*"
+ }
+ ]
+ }`
+ c.Assert(resp.StackPolicyBody, Equals, policy)
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+}
+
+func (s *S) TestGetTemplate(c *C) {
+ testServer.Response(200, nil, GetTemplateResponse)
+
+ resp, err := s.cf.GetTemplate("MyStack")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "GetTemplate")
+
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ // Response test
+ templateBody := `{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+ "Description" : "Simple example",
+ "Resources" : {
+ "MySQS" : {
+ "Type" : "AWS::SQS::Queue",
+ "Properties" : {
+ }
+ }
+ }
+ }`
+ c.Assert(resp.TemplateBody, Equals, templateBody)
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+}
+
+func (s *S) TestListStackResources(c *C) {
+ testServer.Response(200, nil, ListStackResourcesResponse)
+
+ resp, err := s.cf.ListStackResources("MyStack", "4dad1-32131da-d-31")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "ListStackResources")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("NextToken"), Equals, "4dad1-32131da-d-31")
+
+ // Response test
+ t1, _ := time.Parse(time.RFC3339, "2011-06-21T20:15:58Z")
+ t2, _ := time.Parse(time.RFC3339, "2011-06-21T20:25:57Z")
+ t3, _ := time.Parse(time.RFC3339, "2011-06-21T20:26:12Z")
+ t4, _ := time.Parse(time.RFC3339, "2011-06-21T20:28:48Z")
+ t5, _ := time.Parse(time.RFC3339, "2011-06-21T20:29:06Z")
+ t6, _ := time.Parse(time.RFC3339, "2011-06-21T20:29:23Z")
+
+ expected := &cf.ListStackResourcesResponse{
+ StackResourceSummaries: []cf.StackResourceSummary{
+ {
+ LogicalResourceId: "DBSecurityGroup",
+ PhysicalResourceId: "gmarcteststack-dbsecuritygroup-1s5m0ez5lkk6w",
+ ResourceType: "AWS::RDS::DBSecurityGroup",
+ LastUpdatedTimestamp: t1,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ {
+ LogicalResourceId: "SampleDB",
+ PhysicalResourceId: "MyStack-sampledb-ycwhk1v830lx",
+ ResourceType: "AWS::RDS::DBInstance",
+ LastUpdatedTimestamp: t2,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ {
+ LogicalResourceId: "SampleApplication",
+ PhysicalResourceId: "MyStack-SampleApplication-1MKNASYR3RBQL",
+ ResourceType: "AWS::ElasticBeanstalk::Application",
+ LastUpdatedTimestamp: t3,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ {
+ LogicalResourceId: "SampleEnvironment",
+ PhysicalResourceId: "myst-Samp-1AGU6ERZX6M3Q",
+ ResourceType: "AWS::ElasticBeanstalk::Environment",
+ LastUpdatedTimestamp: t4,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ {
+ LogicalResourceId: "AlarmTopic",
+ PhysicalResourceId: "arn:aws:sns:us-east-1:803981987763:MyStack-AlarmTopic-SW4IQELG7RPJ",
+ ResourceType: "AWS::SNS::Topic",
+ LastUpdatedTimestamp: t5,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ {
+ LogicalResourceId: "CPUAlarmHigh",
+ PhysicalResourceId: "MyStack-CPUAlarmHigh-POBWQPDJA81F",
+ ResourceType: "AWS::CloudWatch::Alarm",
+ LastUpdatedTimestamp: t6,
+ ResourceStatus: "CREATE_COMPLETE",
+ },
+ },
+ NextToken: "",
+ RequestId: "2d06e36c-ac1d-11e0-a958-f9382b6eb86b",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestListStacks(c *C) {
+ testServer.Response(200, nil, ListStacksResponse)
+
+ resp, err := s.cf.ListStacks([]string{"CREATE_IN_PROGRESS", "DELETE_COMPLETE"}, "4dad1-32131da-d-31")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "ListStacks")
+ c.Assert(values.Get("StackStatusFilter.member.1"), Equals, "CREATE_IN_PROGRESS")
+ c.Assert(values.Get("StackStatusFilter.member.2"), Equals, "DELETE_COMPLETE")
+ c.Assert(values.Get("NextToken"), Equals, "4dad1-32131da-d-31")
+
+ // Response test
+ c1, _ := time.Parse(time.RFC3339, "2011-05-23T15:47:44Z")
+ c2, _ := time.Parse(time.RFC3339, "2011-03-05T19:57:58Z")
+ d2, _ := time.Parse(time.RFC3339, "2011-03-10T16:20:51Z")
+
+ expected := &cf.ListStacksResponse{
+ StackSummaries: []cf.StackSummary{
+ {
+ StackId: "arn:aws:cloudformation:us-east-1:1234567:stack/TestCreate1/aaaaa",
+ StackName: "vpc1",
+ StackStatus: "CREATE_IN_PROGRESS",
+ CreationTime: c1,
+ TemplateDescription: "Creates one EC2 instance and a load balancer.",
+ },
+ {
+ StackId: "arn:aws:cloudformation:us-east-1:1234567:stack/TestDelete2/bbbbb",
+ StackName: "WP1",
+ StackStatus: "DELETE_COMPLETE",
+ CreationTime: c2,
+ DeletionTime: d2,
+ TemplateDescription: "A simple basic Cloudformation Template.",
+ },
+ },
+ NextToken: "",
+ RequestId: "2d06e36c-ac1d-11e0-a958-f9382b6eb86b",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestSetStackPolicy(c *C) {
+ testServer.Response(200, nil, SetStackPolicyResponse)
+
+ resp, err := s.cf.SetStackPolicy("MyStack", "[Stack Policy Document]", "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "SetStackPolicy")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("StackPolicyBody"), Equals, "[Stack Policy Document]")
+ c.Assert(values.Get("StackPolicyUrl"), Equals, "")
+ // Response test
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+}
+
+func (s *S) TestUpdateStack(c *C) {
+ testServer.Response(200, nil, UpdateStackResponse)
+
+ stackParams := &cf.UpdateStackParams{
+ Capabilities: []string{"CAPABILITY_IAM"},
+ NotificationARNs: []string{"arn:aws:sns:us-east-1:1234567890:my-topic"},
+ StackPolicyBody: "{PolicyBody}",
+ StackPolicyDuringUpdateBody: "{PolicyDuringUpdateBody}",
+ Parameters: []cf.Parameter{
+ {
+ ParameterKey: "AvailabilityZone",
+ ParameterValue: "us-east-1a",
+ },
+ },
+ UsePreviousTemplate: true,
+ StackName: "MyStack",
+ TemplateBody: "[Template Document]",
+ }
+ resp, err := s.cf.UpdateStack(stackParams)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "UpdateStack")
+ c.Assert(values.Get("StackName"), Equals, "MyStack")
+ c.Assert(values.Get("NotificationARNs.member.1"), Equals, "arn:aws:sns:us-east-1:1234567890:my-topic")
+ c.Assert(values.Get("TemplateBody"), Equals, "[Template Document]")
+ c.Assert(values.Get("Parameters.member.1.ParameterKey"), Equals, "AvailabilityZone")
+ c.Assert(values.Get("Parameters.member.1.ParameterValue"), Equals, "us-east-1a")
+ c.Assert(values.Get("Capabilities.member.1"), Equals, "CAPABILITY_IAM")
+ c.Assert(values.Get("StackPolicyBody"), Equals, "{PolicyBody}")
+ c.Assert(values.Get("StackPolicyDuringUpdateBody"), Equals, "{PolicyDuringUpdateBody}")
+ c.Assert(values.Get("UsePreviousTemplate"), Equals, "true")
+
+ // Response test
+ c.Assert(resp.RequestId, Equals, "4af14eec-350e-11e4-b260-EXAMPLE")
+ c.Assert(resp.StackId, Equals, "arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83")
+}
+
+func (s *S) TestValidateTemplate(c *C) {
+ testServer.Response(200, nil, ValidateTemplateResponse)
+
+ resp, err := s.cf.ValidateTemplate("", "http://myTemplateRepository/TemplateOne.template")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2010-05-15")
+ c.Assert(values.Get("Action"), Equals, "ValidateTemplate")
+ c.Assert(values.Get("TemplateURL"), Equals, "http://myTemplateRepository/TemplateOne.template")
+ c.Assert(values.Get("TemplateBody"), Equals, "")
+
+ // Response test
+ expected := &cf.ValidateTemplateResponse{
+ Description: "Test",
+ Capabilities: []string{"CAPABILITY_IAM"},
+ Parameters: []cf.TemplateParameter{
+ {
+ NoEcho: false,
+ ParameterKey: "InstanceType",
+ Description: "Type of instance to launch",
+ DefaultValue: "m1.small",
+ },
+ {
+ NoEcho: false,
+ ParameterKey: "WebServerPort",
+ Description: "The TCP port for the Web Server",
+ DefaultValue: "8888",
+ },
+ {
+ NoEcho: false,
+ ParameterKey: "KeyName",
+ Description: "Name of an existing EC2 KeyPair to enable SSH access into the server",
+ },
+ },
+ RequestId: "0be7b6e8-e4a0-11e0-a5bd-9f8d5a7dbc91",
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
diff --git a/vendor/github.com/goamz/goamz/cloudformation/responses_test.go b/vendor/github.com/goamz/goamz/cloudformation/responses_test.go
new file mode 100644
index 000000000..705b1d976
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudformation/responses_test.go
@@ -0,0 +1,371 @@
+package cloudformation_test
+
+var CancelUpdateStackResponse = `
+<CancelUpdateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <CancelUpdateStackResult/>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</CancelUpdateStackResponse>
+`
+
+var CreateStackResponse = `
+<CreateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+<CreateStackResult>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+</CreateStackResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateStackResponse>
+`
+
+var CreateStackWithInvalidParamsResponse = `
+<ErrorResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>ValidationError</Code>
+ <Message>Either Template URL or Template Body must be specified.</Message>
+ </Error>
+ <RequestId>70a76d42-9665-11e2-9fdf-211deEXAMPLE</RequestId>
+</ErrorResponse>
+`
+
+var DeleteStackResponse = `
+<DeleteStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <DeleteStackResult/>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DeleteStackResponse>
+`
+var DescribeStackEventsResponse = `
+<DescribeStackEventsResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <DescribeStackEventsResult>
+ <StackEvents>
+ <member>
+ <EventId>Event-1-Id</EventId>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ <StackName>MyStack</StackName>
+ <LogicalResourceId>MyStack</LogicalResourceId>
+ <PhysicalResourceId>MyStack_One</PhysicalResourceId>
+ <ResourceType>AWS::CloudFormation::Stack</ResourceType>
+ <Timestamp>2010-07-27T22:26:28Z</Timestamp>
+ <ResourceStatus>CREATE_IN_PROGRESS</ResourceStatus>
+ <ResourceStatusReason>User initiated</ResourceStatusReason>
+ </member>
+ <member>
+ <EventId>Event-2-Id</EventId>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ <StackName>MyStack</StackName>
+ <LogicalResourceId>MyDBInstance</LogicalResourceId>
+ <PhysicalResourceId>MyStack_DB1</PhysicalResourceId>
+ <ResourceType>AWS::SecurityGroup</ResourceType>
+ <Timestamp>2010-07-27T22:27:28Z</Timestamp>
+ <ResourceStatus>CREATE_IN_PROGRESS</ResourceStatus>
+ <ResourceProperties>{"GroupDescription":...}</ResourceProperties>
+ </member>
+ <member>
+ <EventId>Event-3-Id</EventId>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ <StackName>MyStack</StackName>
+ <LogicalResourceId>MySG1</LogicalResourceId>
+ <PhysicalResourceId>MyStack_SG1</PhysicalResourceId>
+ <ResourceType>AWS::SecurityGroup</ResourceType>
+ <Timestamp>2010-07-27T22:28:28Z</Timestamp>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ </member>
+ </StackEvents>
+ <NextToken/>
+ </DescribeStackEventsResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeStackEventsResponse>
+`
+
+var DescribeStackResourceResponse = `
+<DescribeStackResourceResponse>
+ <DescribeStackResourceResult>
+ <StackResourceDetail>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ <StackName>MyStack</StackName>
+ <LogicalResourceId>MyDBInstance</LogicalResourceId>
+ <PhysicalResourceId>MyStack_DB1</PhysicalResourceId>
+ <ResourceType>AWS::RDS::DBInstance</ResourceType>
+ <LastUpdatedTimestamp>2011-07-07T22:27:28Z</LastUpdatedTimestamp>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ </StackResourceDetail>
+ </DescribeStackResourceResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeStackResourceResponse>
+`
+var DescribeStackResourcesResponse = `
+<DescribeStackResourcesResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <DescribeStackResourcesResult>
+ <StackResources>
+ <member>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ <StackName>MyStack</StackName>
+ <LogicalResourceId>MyDBInstance</LogicalResourceId>
+ <PhysicalResourceId>MyStack_DB1</PhysicalResourceId>
+ <ResourceType>AWS::DBInstance</ResourceType>
+ <Timestamp>2010-07-27T22:27:28Z</Timestamp>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ </member>
+ <member>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ <StackName>MyStack</StackName>
+ <LogicalResourceId>MyAutoScalingGroup</LogicalResourceId>
+ <PhysicalResourceId>MyStack_ASG1</PhysicalResourceId>
+ <ResourceType>AWS::AutoScalingGroup</ResourceType>
+ <Timestamp>2010-07-27T22:28:28Z</Timestamp>
+ <ResourceStatus>CREATE_IN_PROGRESS</ResourceStatus>
+ </member>
+ </StackResources>
+ </DescribeStackResourcesResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeStackResourcesResponse>
+`
+
+var DescribeStacksResponse = `
+<DescribeStacksResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <DescribeStacksResult>
+ <Stacks>
+ <member>
+ <StackName>MyStack</StackName>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ <StackStatusReason/>
+ <Description>My Description</Description>
+ <Capabilities>
+ <member>CAPABILITY_IAM</member>
+ </Capabilities>
+ <NotificationARNs>
+ <member>arn:aws:sns:region-name:account-name:topic-name</member>
+ </NotificationARNs>
+ <Parameters>
+ <member>
+ <ParameterValue>MyValue</ParameterValue>
+ <ParameterKey>MyKey</ParameterKey>
+ </member>
+ </Parameters>
+ <Tags>
+ <member>
+ <Key>MyTagKey</Key>
+ <Value>MyTagValue</Value>
+ </member>
+ </Tags>
+ <CreationTime>2010-07-27T22:28:28Z</CreationTime>
+ <StackStatus>CREATE_COMPLETE</StackStatus>
+ <DisableRollback>false</DisableRollback>
+ <Outputs>
+ <member>
+ <Description>ServerUrl</Description>
+ <OutputKey>StartPage</OutputKey>
+ <OutputValue>http://my-load-balancer.amazonaws.com:80/index.html</OutputValue>
+ </member>
+ </Outputs>
+ </member>
+ </Stacks>
+ <NextToken/>
+ </DescribeStacksResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeStacksResponse>
+`
+
+var EstimateTemplateCostResponse = `
+<EstimateTemplateCostResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <EstimateTemplateCostResult>
+ <Url>http://calculator.s3.amazonaws.com/calc5.html?key=cf-2e351785-e821-450c-9d58-625e1e1ebfb6</Url>
+ </EstimateTemplateCostResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</EstimateTemplateCostResponse>
+`
+
+var GetStackPolicyResponse = `
+<GetStackPolicyResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <GetStackPolicyResult>
+ <StackPolicyBody>{
+ "Statement" : [
+ {
+ "Effect" : "Deny",
+ "Action" : "Update:*",
+ "Principal" : "*",
+ "Resource" : "LogicalResourceId/ProductionDatabase"
+ },
+ {
+ "Effect" : "Allow",
+ "Action" : "Update:*",
+ "Principal" : "*",
+ "Resource" : "*"
+ }
+ ]
+ }</StackPolicyBody>
+ </GetStackPolicyResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</GetStackPolicyResponse>
+`
+
+var GetTemplateResponse = `
+<GetTemplateResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <GetTemplateResult>
+ <TemplateBody>{
+ "AWSTemplateFormatVersion" : "2010-09-09",
+ "Description" : "Simple example",
+ "Resources" : {
+ "MySQS" : {
+ "Type" : "AWS::SQS::Queue",
+ "Properties" : {
+ }
+ }
+ }
+ }</TemplateBody>
+ </GetTemplateResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</GetTemplateResponse>
+`
+
+var ListStackResourcesResponse = `
+<ListStackResourcesResponse>
+ <ListStackResourcesResult>
+ <StackResourceSummaries>
+ <member>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ <LogicalResourceId>DBSecurityGroup</LogicalResourceId>
+ <LastUpdatedTimestamp>2011-06-21T20:15:58Z</LastUpdatedTimestamp>
+ <PhysicalResourceId>gmarcteststack-dbsecuritygroup-1s5m0ez5lkk6w</PhysicalResourceId>
+ <ResourceType>AWS::RDS::DBSecurityGroup</ResourceType>
+ </member>
+ <member>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ <LogicalResourceId>SampleDB</LogicalResourceId>
+ <LastUpdatedTimestamp>2011-06-21T20:25:57Z</LastUpdatedTimestamp>
+ <PhysicalResourceId>MyStack-sampledb-ycwhk1v830lx</PhysicalResourceId>
+ <ResourceType>AWS::RDS::DBInstance</ResourceType>
+ </member>
+ <member>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ <LogicalResourceId>SampleApplication</LogicalResourceId>
+ <LastUpdatedTimestamp>2011-06-21T20:26:12Z</LastUpdatedTimestamp>
+ <PhysicalResourceId>MyStack-SampleApplication-1MKNASYR3RBQL</PhysicalResourceId>
+ <ResourceType>AWS::ElasticBeanstalk::Application</ResourceType>
+ </member>
+ <member>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ <LogicalResourceId>SampleEnvironment</LogicalResourceId>
+ <LastUpdatedTimestamp>2011-06-21T20:28:48Z</LastUpdatedTimestamp>
+ <PhysicalResourceId>myst-Samp-1AGU6ERZX6M3Q</PhysicalResourceId>
+ <ResourceType>AWS::ElasticBeanstalk::Environment</ResourceType>
+ </member>
+ <member>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ <LogicalResourceId>AlarmTopic</LogicalResourceId>
+ <LastUpdatedTimestamp>2011-06-21T20:29:06Z</LastUpdatedTimestamp>
+ <PhysicalResourceId>arn:aws:sns:us-east-1:803981987763:MyStack-AlarmTopic-SW4IQELG7RPJ</PhysicalResourceId>
+ <ResourceType>AWS::SNS::Topic</ResourceType>
+ </member>
+ <member>
+ <ResourceStatus>CREATE_COMPLETE</ResourceStatus>
+ <LogicalResourceId>CPUAlarmHigh</LogicalResourceId>
+ <LastUpdatedTimestamp>2011-06-21T20:29:23Z</LastUpdatedTimestamp>
+ <PhysicalResourceId>MyStack-CPUAlarmHigh-POBWQPDJA81F</PhysicalResourceId>
+ <ResourceType>AWS::CloudWatch::Alarm</ResourceType>
+ </member>
+ </StackResourceSummaries>
+ </ListStackResourcesResult>
+ <ResponseMetadata>
+ <RequestId>2d06e36c-ac1d-11e0-a958-f9382b6eb86b</RequestId>
+ </ResponseMetadata>
+</ListStackResourcesResponse>
+`
+
+var ListStacksResponse = `
+<ListStacksResponse>
+ <ListStacksResult>
+ <StackSummaries>
+ <member>
+ <StackId>arn:aws:cloudformation:us-east-1:1234567:stack/TestCreate1/aaaaa</StackId>
+ <StackStatus>CREATE_IN_PROGRESS</StackStatus>
+ <StackName>vpc1</StackName>
+ <CreationTime>2011-05-23T15:47:44Z</CreationTime>
+ <TemplateDescription>Creates one EC2 instance and a load balancer.</TemplateDescription>
+ </member>
+ <member>
+ <StackId>arn:aws:cloudformation:us-east-1:1234567:stack/TestDelete2/bbbbb</StackId>
+ <StackStatus>DELETE_COMPLETE</StackStatus>
+ <DeletionTime>2011-03-10T16:20:51Z</DeletionTime>
+ <StackName>WP1</StackName>
+ <CreationTime>2011-03-05T19:57:58Z</CreationTime>
+ <TemplateDescription>A simple basic Cloudformation Template.</TemplateDescription>
+ </member>
+ </StackSummaries>
+ </ListStacksResult>
+ <ResponseMetadata>
+ <RequestId>2d06e36c-ac1d-11e0-a958-f9382b6eb86b</RequestId>
+ </ResponseMetadata>
+</ListStacksResponse>
+`
+
+var SetStackPolicyResponse = `
+<SetStackPolicyResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <SetStackPolicyResponse/>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</SetStackPolicyResponse>
+`
+
+var UpdateStackResponse = `
+<UpdateStackResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <UpdateStackResult>
+ <StackId>arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83</StackId>
+ </UpdateStackResult>
+ <ResponseMetadata>
+ <RequestId>4af14eec-350e-11e4-b260-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</UpdateStackResponse>
+`
+var ValidateTemplateResponse = `
+<ValidateTemplateResponse xmlns="http://cloudformation.amazonaws.com/doc/2010-05-15/">
+ <ValidateTemplateResult>
+ <Description>Test</Description>
+ <Capabilities>
+ <member>CAPABILITY_IAM</member>
+ </Capabilities>
+ <Parameters>
+ <member>
+ <NoEcho>false</NoEcho>
+ <ParameterKey>InstanceType</ParameterKey>
+ <Description>Type of instance to launch</Description>
+ <DefaultValue>m1.small</DefaultValue>
+ </member>
+ <member>
+ <NoEcho>false</NoEcho>
+ <ParameterKey>WebServerPort</ParameterKey>
+ <Description>The TCP port for the Web Server</Description>
+ <DefaultValue>8888</DefaultValue>
+ </member>
+ <member>
+ <NoEcho>false</NoEcho>
+ <ParameterKey>KeyName</ParameterKey>
+ <Description>Name of an existing EC2 KeyPair to enable SSH access into the server</Description>
+ </member>
+ </Parameters>
+ </ValidateTemplateResult>
+ <ResponseMetadata>
+ <RequestId>0be7b6e8-e4a0-11e0-a5bd-9f8d5a7dbc91</RequestId>
+ </ResponseMetadata>
+</ValidateTemplateResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/cloudfront/cloudfront.go b/vendor/github.com/goamz/goamz/cloudfront/cloudfront.go
new file mode 100644
index 000000000..745060f1c
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudfront/cloudfront.go
@@ -0,0 +1,135 @@
+package cloudfront
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha1"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type CloudFront struct {
+ BaseURL string
+ keyPairId string
+ key *rsa.PrivateKey
+}
+
+var base64Replacer = strings.NewReplacer("=", "_", "+", "-", "/", "~")
+
+func New(baseurl string, key *rsa.PrivateKey, keyPairId string) *CloudFront {
+ return &CloudFront{
+ BaseURL: baseurl,
+ keyPairId: keyPairId,
+ key: key,
+ }
+}
+
+type epochTime struct {
+ EpochTime int64 `json:"AWS:EpochTime"`
+}
+
+type condition struct {
+ DateLessThan epochTime
+}
+
+type statement struct {
+ Resource string
+ Condition condition
+}
+
+type policy struct {
+ Statement []statement
+}
+
+func buildPolicy(resource string, expireTime time.Time) ([]byte, error) {
+ p := &policy{
+ Statement: []statement{
+ statement{
+ Resource: resource,
+ Condition: condition{
+ DateLessThan: epochTime{
+ EpochTime: expireTime.Truncate(time.Millisecond).Unix(),
+ },
+ },
+ },
+ },
+ }
+
+ return json.Marshal(p)
+}
+
+func (cf *CloudFront) generateSignature(policy []byte) (string, error) {
+ hash := sha1.New()
+ if _, err := hash.Write(policy); err != nil {
+ return "", err
+ }
+
+ hashed := hash.Sum(nil)
+
+ signed, err := rsa.SignPKCS1v15(rand.Reader, cf.key, crypto.SHA1, hashed)
+ if err != nil {
+ return "", err
+ }
+
+ encoded := base64Replacer.Replace(base64.StdEncoding.EncodeToString(signed))
+
+ return encoded, nil
+}
+
+// Creates a signed url using RSAwithSHA1 as specified by
+// http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-creating-signed-url-canned-policy.html#private-content-canned-policy-creating-signature
+func (cf *CloudFront) CannedSignedURL(path, queryString string, expires time.Time) (string, error) {
+ resource := cf.BaseURL + path
+ if queryString != "" {
+ resource = path + "?" + queryString
+ }
+
+ policy, err := buildPolicy(resource, expires)
+ if err != nil {
+ return "", err
+ }
+
+ signature, err := cf.generateSignature(policy)
+ if err != nil {
+ return "", err
+ }
+
+ // TOOD: Do this once
+ uri, err := url.Parse(cf.BaseURL)
+ if err != nil {
+ return "", err
+ }
+
+ uri.RawQuery = queryString
+ if queryString != "" {
+ uri.RawQuery += "&"
+ }
+
+ expireTime := expires.Truncate(time.Millisecond).Unix()
+
+ uri.Path = path
+ uri.RawQuery += fmt.Sprintf("Expires=%d&Signature=%s&Key-Pair-Id=%s", expireTime, signature, cf.keyPairId)
+
+ return uri.String(), nil
+}
+
+func (cloudfront *CloudFront) SignedURL(path, querystrings string, expires time.Time) string {
+ policy := `{"Statement":[{"Resource":"` + path + "?" + querystrings + `,"Condition":{"DateLessThan":{"AWS:EpochTime":` + strconv.FormatInt(expires.Truncate(time.Millisecond).Unix(), 10) + `}}}]}`
+
+ hash := sha1.New()
+ hash.Write([]byte(policy))
+ b := hash.Sum(nil)
+ he := base64.StdEncoding.EncodeToString(b)
+
+ policySha1 := he
+
+ url := cloudfront.BaseURL + path + "?" + querystrings + "&Expires=" + strconv.FormatInt(expires.Unix(), 10) + "&Signature=" + policySha1 + "&Key-Pair-Id=" + cloudfront.keyPairId
+
+ return url
+}
diff --git a/vendor/github.com/goamz/goamz/cloudfront/cloudfront_test.go b/vendor/github.com/goamz/goamz/cloudfront/cloudfront_test.go
new file mode 100644
index 000000000..63744d1cb
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudfront/cloudfront_test.go
@@ -0,0 +1,52 @@
+package cloudfront
+
+import (
+ "crypto/x509"
+ "encoding/pem"
+ "io/ioutil"
+ "net/url"
+ "testing"
+ "time"
+)
+
+func TestSignedCannedURL(t *testing.T) {
+ rawKey, err := ioutil.ReadFile("testdata/key.pem")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ pemKey, _ := pem.Decode(rawKey)
+ privateKey, err := x509.ParsePKCS1PrivateKey(pemKey.Bytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ cf := &CloudFront{
+ key: privateKey,
+ keyPairId: "test-key-pair-1231245",
+ BaseURL: "https://cloudfront.com",
+ }
+
+ expireTime, err := time.Parse(time.RFC3339, "2014-03-28T14:00:21Z")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ query := make(url.Values)
+ query.Add("test", "value")
+
+ uri, err := cf.CannedSignedURL("test", "test=value", expireTime)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ parsed, err := url.Parse(uri)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ signature := parsed.Query().Get("Signature")
+ if signature == "" {
+ t.Fatal("Encoded signature is empty")
+ }
+}
diff --git a/vendor/github.com/goamz/goamz/cloudfront/testdata/key.pem b/vendor/github.com/goamz/goamz/cloudfront/testdata/key.pem
new file mode 100644
index 000000000..96e820a2c
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudfront/testdata/key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC0yMzp9DkPAE99DhsEaGkqougLvtmDKri4bZj0fFjmGmjyyjz9
+hlrsr87LHVWzH/7igK7040HG1UqypX3ijtJa9+6BKHwBBctboU3y4GfwFwVAOumY
+9UytFpyPlgUFrffZLQAywKkT24OgcfEj0G5kiQn760wFnmSUtOuITo708QIDAQAB
+AoGAJUA6+PoZx72Io3wElSPuh5qJteHdb+mdpmLu4XG936wRc/W4G4VTtvGC6tdg
+kUhGfOWHJ26sXwwUGDuBdO146m0DkBTuIooy97afpL6hXgL5v4ELHbbuFJcf4Geg
+/UAuexvRT1HenYFQ/iXM0LlqI33i8cFRc1A+j0Gseo07gAECQQDYFCn7OUokX+Q8
+M2Cwhu7JT1obmP2HwsBtXl0CDDxtOQkuYJP/UqvtdYPz/kRn3yQjoynaCTHYrFz/
+H8oN1nNhAkEA1i9TEpo7RbanIyT4vbc1/5xfjE7Pj0lnGku0QXFp/S+8YxbqhjrQ
+4Qp7TTXIPPqvQhhEpAGGspM460K3F6h7kQJBANJCbMeFa9wRY2ohJIkiA+HoUWph
+aPNeUxkZpa+EcJhn08NJPzpIG/ypSYl3duEMhYIYF3WPVO3ea2/mYxsr/oECQFj5
+td/fdEoEk7AU1sQxDNyPwF2QC8dxbcRNuKcLD0Wfg/oB9hEm88jYytoLQpCabx3c
+6P7cp3EdmaKZx2erlRECQDYTSK2tS0+VoXSV9JbU08Pbu53j3Zhmp4l0csP+l7EU
+U+rRQzKho4X9vpR/VpRGXbw8tTIhojNpHh5ofryVfgk=
+-----END RSA PRIVATE KEY-----
diff --git a/vendor/github.com/goamz/goamz/cloudfront/testdata/key.pub b/vendor/github.com/goamz/goamz/cloudfront/testdata/key.pub
new file mode 100644
index 000000000..7d0b5b4d6
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudfront/testdata/key.pub
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC0yMzp9DkPAE99DhsEaGkqougL
+vtmDKri4bZj0fFjmGmjyyjz9hlrsr87LHVWzH/7igK7040HG1UqypX3ijtJa9+6B
+KHwBBctboU3y4GfwFwVAOumY9UytFpyPlgUFrffZLQAywKkT24OgcfEj0G5kiQn7
+60wFnmSUtOuITo708QIDAQAB
+-----END PUBLIC KEY-----
diff --git a/vendor/github.com/goamz/goamz/cloudwatch/ChangeLog b/vendor/github.com/goamz/goamz/cloudwatch/ChangeLog
new file mode 100644
index 000000000..46fea639e
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudwatch/ChangeLog
@@ -0,0 +1,7 @@
+2013-10-21 Carlos Salguero <cfsalguero@gmail.com>
+
+* Removed Namespace from the constructor as not all AWS API method needs it
+ and methods like ListMetrics you could need to call the method without a
+ Namespace to list all available metrics
+
+* Added ListMetrics method
diff --git a/vendor/github.com/goamz/goamz/cloudwatch/README.md b/vendor/github.com/goamz/goamz/cloudwatch/README.md
new file mode 100644
index 000000000..dc837b4c7
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudwatch/README.md
@@ -0,0 +1,109 @@
+#GoLang AWS Cloudwatch
+
+## Installation
+Please refer to the project's main page at [https://github.com/goamz/goamz](https://github.com/goamz/goamz) for instructions about how to install.
+
+## Available methods
+
+<table>
+ <tr>
+ <td>GetMetricStatistics</td>
+ <td>Gets statistics for the specified metric.</td>
+ </tr>
+ <tr>
+ <td>ListMetrics</td>
+ <td>Returns a list of valid metrics stored for the AWS account.</td>
+ </tr>
+ <tr>
+ <td>PutMetricData</td>
+ <td>Publishes metric data points to Amazon CloudWatch.</td>
+ </tr>
+ <tr>
+ <td>PutMetricAlarm</td>
+ <td>Creates or updates an alarm and associates it with the specified Amazon CloudWatch metric.</td>
+ </tr>
+ </table>
+
+[Please refer to AWS Cloudwatch's documentation for more info](http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_Operations.html)
+
+##Examples
+####Get Metric Statistics
+
+```
+import (
+ "fmt"
+ "time"
+ "os"
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/cloudwatch"
+)
+
+func test_get_metric_statistics() {
+ region := aws.Regions["a_region"]
+ namespace:= "AWS/ELB"
+ dimension := &cloudwatch.Dimension{
+ Name: "LoadBalancerName",
+ Value: "your_value",
+ }
+ metricName := "RequestCount"
+ now := time.Now()
+ prev := now.Add(time.Duration(600)*time.Second*-1) // 600 secs = 10 minutes
+
+ auth, err := aws.GetAuth("your_AccessKeyId", "your_SecretAccessKey", "", now)
+ if err != nil {
+ fmt.Printf("Error: %+v\n", err)
+ os.Exit(1)
+ }
+
+ cw, err := cloudwatch.NewCloudWatch(auth, region.CloudWatchServicepoint)
+ request := &cloudwatch.GetMetricStatisticsRequest {
+ Dimensions: []cloudwatch.Dimension{*dimension},
+ EndTime: now,
+ StartTime: prev,
+ MetricName: metricName,
+ Unit: "Count", // Not mandatory
+ Period: 60,
+ Statistics: []string{"Sum"},
+ Namespace: namespace,
+ }
+
+ response, err := cw.GetMetricStatistics(request)
+ if err == nil {
+ fmt.Printf("%+v\n", response)
+ } else {
+ fmt.Printf("Error: %+v\n", err)
+ }
+}
+
+```
+####List Metrics
+
+```
+import (
+ "fmt"
+ "time"
+ "os"
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/cloudwatch"
+)
+
+func test_list_metrics() {
+ region := aws.Regions["us-east-1"] // Any region here
+ now := time.Now()
+
+ auth, err := aws.GetAuth("an AccessKeyId", "a SecretAccessKey", "", now)
+ if err != nil {
+ fmt.Printf("Error: %+v\n", err)
+ os.Exit(1)
+ }
+ cw, err := cloudwatch.NewCloudWatch(auth, region.CloudWatchServicepoint)
+ request := &cloudwatch.ListMetricsRequest{Namespace: "AWS/EC2"}
+
+ response, err := cw.ListMetrics(request)
+ if err == nil {
+ fmt.Printf("%+v\n", response)
+ } else {
+ fmt.Printf("Error: %+v\n", err)
+ }
+}
+```
diff --git a/vendor/github.com/goamz/goamz/cloudwatch/cloudwatch.go b/vendor/github.com/goamz/goamz/cloudwatch/cloudwatch.go
new file mode 100644
index 000000000..461d6a102
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudwatch/cloudwatch.go
@@ -0,0 +1,404 @@
+/***** BEGIN LICENSE BLOCK *****
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# The Initial Developer of the Original Code is the Mozilla Foundation.
+# Portions created by the Initial Developer are Copyright (C) 2012
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+# Ben Bangert (bbangert@mozilla.com)
+# Logan Owen (lsowen@s1network.com)
+#
+# ***** END LICENSE BLOCK *****/
+
+package cloudwatch
+
+import (
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "github.com/feyeleanor/sets"
+ "github.com/goamz/goamz/aws"
+ "strconv"
+ "time"
+)
+
+// The CloudWatch type encapsulates all the CloudWatch operations in a region.
+type CloudWatch struct {
+ Service aws.AWSService
+}
+
+type Dimension struct {
+ Name string
+ Value string
+}
+
+type StatisticSet struct {
+ Maximum float64
+ Minimum float64
+ SampleCount float64
+ Sum float64
+}
+
+type MetricDatum struct {
+ Dimensions []Dimension
+ MetricName string
+ StatisticValues *StatisticSet
+ Timestamp time.Time
+ Unit string
+ Value float64
+}
+
+type Datapoint struct {
+ Average float64
+ Maximum float64
+ Minimum float64
+ SampleCount float64
+ Sum float64
+ Timestamp time.Time
+ Unit string
+}
+
+type GetMetricStatisticsRequest struct {
+ Dimensions []Dimension
+ EndTime time.Time
+ StartTime time.Time
+ MetricName string
+ Unit string
+ Period int
+ Statistics []string
+ Namespace string
+}
+
+type GetMetricStatisticsResult struct {
+ Datapoints []Datapoint `xml:"Datapoints>member"`
+ NextToken string `xml:"NextToken"`
+}
+
+type GetMetricStatisticsResponse struct {
+ GetMetricStatisticsResult GetMetricStatisticsResult
+ ResponseMetadata aws.ResponseMetadata
+}
+
+type Metric struct {
+ Dimensions []Dimension `xml:"Dimensions>member"`
+ MetricName string
+ Namespace string
+}
+
+type ListMetricsResult struct {
+ Metrics []Metric `xml:"Metrics>member"`
+ NextToken string
+}
+
+type ListMetricsResponse struct {
+ ListMetricsResult ListMetricsResult
+ ResponseMetadata aws.ResponseMetadata
+}
+
+type ListMetricsRequest struct {
+ Dimensions []Dimension
+ MetricName string
+ Namespace string
+ NextToken string
+}
+
+type AlarmAction struct {
+ ARN string
+}
+
+type MetricAlarm struct {
+ AlarmActions []AlarmAction
+ AlarmDescription string
+ AlarmName string
+ ComparisonOperator string
+ Dimensions []Dimension
+ EvaluationPeriods int
+ InsufficientDataActions []AlarmAction
+ MetricName string
+ Namespace string
+ OkActions []AlarmAction
+ Period int
+ Statistic string
+ Threshold float64
+ Unit string
+}
+
+var attempts = aws.AttemptStrategy{
+ Min: 5,
+ Total: 5 * time.Second,
+ Delay: 200 * time.Millisecond,
+}
+
+var validUnits = sets.SSet(
+ "Seconds",
+ "Microseconds",
+ "Milliseconds",
+ "Bytes",
+ "Kilobytes",
+ "Megabytes",
+ "Gigabytes",
+ "Terabytes",
+ "Bits",
+ "Kilobits",
+ "Megabits",
+ "Gigabits",
+ "Terabits",
+ "Percent",
+ "Count",
+ "Bytes/Second",
+ "Kilobytes/Second",
+ "Megabytes/Second",
+ "Gigabytes/Second",
+ "Terabytes/Second",
+ "Bits/Second",
+ "Kilobits/Second",
+ "Megabits/Second",
+ "Gigabits/Second",
+ "Terabits/Second",
+ "Count/Second",
+)
+
+var validMetricStatistics = sets.SSet(
+ "Average",
+ "Sum",
+ "SampleCount",
+ "Maximum",
+ "Minimum",
+)
+
+var validComparisonOperators = sets.SSet(
+ "LessThanThreshold",
+ "LessThanOrEqualToThreshold",
+ "GreaterThanThreshold",
+ "GreaterThanOrEqualToThreshold",
+)
+
+// Create a new CloudWatch object for a given namespace
+func NewCloudWatch(auth aws.Auth, region aws.ServiceInfo) (*CloudWatch, error) {
+ service, err := aws.NewService(auth, region)
+ if err != nil {
+ return nil, err
+ }
+ return &CloudWatch{
+ Service: service,
+ }, nil
+}
+
+func (c *CloudWatch) query(method, path string, params map[string]string, resp interface{}) error {
+ // Add basic Cloudwatch param
+ params["Version"] = "2010-08-01"
+
+ r, err := c.Service.Query(method, path, params)
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+
+ if r.StatusCode != 200 {
+ return c.Service.BuildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+// Get statistics for specified metric
+//
+// If the arguments are invalid or the server returns an error, the error will
+// be set and the other values undefined.
+func (c *CloudWatch) GetMetricStatistics(req *GetMetricStatisticsRequest) (result *GetMetricStatisticsResponse, err error) {
+ statisticsSet := sets.SSet(req.Statistics...)
+ // Kick out argument errors
+ switch {
+ case req.EndTime.IsZero():
+ err = errors.New("No endTime specified")
+ case req.StartTime.IsZero():
+ err = errors.New("No startTime specified")
+ case req.MetricName == "":
+ err = errors.New("No metricName specified")
+ case req.Namespace == "":
+ err = errors.New("No Namespace specified")
+ case req.Period < 60 || req.Period%60 != 0:
+ err = errors.New("Period not 60 seconds or a multiple of 60 seconds")
+ case len(req.Statistics) < 1:
+ err = errors.New("No statistics supplied")
+ case validMetricStatistics.Union(statisticsSet).Len() != validMetricStatistics.Len():
+ err = errors.New("Invalid statistic values supplied")
+ case req.Unit != "" && !validUnits.Member(req.Unit):
+ err = errors.New("Unit is not a valid value")
+ }
+ if err != nil {
+ return
+ }
+
+ // Serialize all the params
+ params := aws.MakeParams("GetMetricStatistics")
+ params["EndTime"] = req.EndTime.UTC().Format(time.RFC3339)
+ params["StartTime"] = req.StartTime.UTC().Format(time.RFC3339)
+ params["MetricName"] = req.MetricName
+ params["Namespace"] = req.Namespace
+ params["Period"] = strconv.Itoa(req.Period)
+ if req.Unit != "" {
+ params["Unit"] = req.Unit
+ }
+
+ // Serialize the lists of data
+ for i, d := range req.Dimensions {
+ prefix := "Dimensions.member." + strconv.Itoa(i+1)
+ params[prefix+".Name"] = d.Name
+ params[prefix+".Value"] = d.Value
+ }
+ for i, d := range req.Statistics {
+ prefix := "Statistics.member." + strconv.Itoa(i+1)
+ params[prefix] = d
+ }
+ result = new(GetMetricStatisticsResponse)
+ err = c.query("GET", "/", params, result)
+ return
+}
+
+// Returns a list of valid metrics stored for the AWS account owner.
+// Returned metrics can be used with GetMetricStatistics to obtain statistical data for a given metric.
+
+func (c *CloudWatch) ListMetrics(req *ListMetricsRequest) (result *ListMetricsResponse, err error) {
+
+ // Serialize all the params
+ params := aws.MakeParams("ListMetrics")
+ if req.Namespace != "" {
+ params["Namespace"] = req.Namespace
+ }
+ if len(req.Dimensions) > 0 {
+ for i, d := range req.Dimensions {
+ prefix := "Dimensions.member." + strconv.Itoa(i+1)
+ params[prefix+".Name"] = d.Name
+ params[prefix+".Value"] = d.Value
+ }
+ }
+
+ result = new(ListMetricsResponse)
+ err = c.query("GET", "/", params, &result)
+ metrics := result.ListMetricsResult.Metrics
+ if result.ListMetricsResult.NextToken != "" {
+ params = aws.MakeParams("ListMetrics")
+ params["NextToken"] = result.ListMetricsResult.NextToken
+ for result.ListMetricsResult.NextToken != "" && err == nil {
+ result = new(ListMetricsResponse)
+ err = c.query("GET", "/", params, &result)
+ if err == nil {
+ newslice := make([]Metric, len(metrics)+len(result.ListMetricsResult.Metrics))
+ copy(newslice, metrics)
+ copy(newslice[len(metrics):], result.ListMetricsResult.Metrics)
+ metrics = newslice
+ }
+ }
+ result.ListMetricsResult.Metrics = metrics
+ }
+ return
+}
+
+func (c *CloudWatch) PutMetricData(metrics []MetricDatum) (result *aws.BaseResponse, err error) {
+ return c.PutMetricDataNamespace(metrics, "")
+}
+
+func (c *CloudWatch) PutMetricDataNamespace(metrics []MetricDatum, namespace string) (result *aws.BaseResponse, err error) {
+ // Serialize the params
+ params := aws.MakeParams("PutMetricData")
+ if namespace != "" {
+ params["Namespace"] = namespace
+ }
+ for i, metric := range metrics {
+ prefix := "MetricData.member." + strconv.Itoa(i+1)
+ if metric.MetricName == "" {
+ err = fmt.Errorf("No metric name supplied for metric: %d", i)
+ return
+ }
+ params[prefix+".MetricName"] = metric.MetricName
+ if metric.Unit != "" {
+ params[prefix+".Unit"] = metric.Unit
+ }
+ params[prefix+".Value"] = strconv.FormatFloat(metric.Value, 'E', 10, 64)
+ if !metric.Timestamp.IsZero() {
+ params[prefix+".Timestamp"] = metric.Timestamp.UTC().Format(time.RFC3339)
+ }
+ for j, dim := range metric.Dimensions {
+ dimprefix := prefix + ".Dimensions.member." + strconv.Itoa(j+1)
+ params[dimprefix+".Name"] = dim.Name
+ params[dimprefix+".Value"] = dim.Value
+ }
+ if metric.StatisticValues != nil {
+ statprefix := prefix + ".StatisticValues"
+ params[statprefix+".Maximum"] = strconv.FormatFloat(metric.StatisticValues.Maximum, 'E', 10, 64)
+ params[statprefix+".Minimum"] = strconv.FormatFloat(metric.StatisticValues.Minimum, 'E', 10, 64)
+ params[statprefix+".SampleCount"] = strconv.FormatFloat(metric.StatisticValues.SampleCount, 'E', 10, 64)
+ params[statprefix+".Sum"] = strconv.FormatFloat(metric.StatisticValues.Sum, 'E', 10, 64)
+ }
+ }
+ result = new(aws.BaseResponse)
+ err = c.query("POST", "/", params, result)
+ return
+}
+
+func (c *CloudWatch) PutMetricAlarm(alarm *MetricAlarm) (result *aws.BaseResponse, err error) {
+ // Serialize the params
+ params := aws.MakeParams("PutMetricAlarm")
+
+ switch {
+ case alarm.AlarmName == "":
+ err = errors.New("No AlarmName supplied")
+ case !validComparisonOperators.Member(alarm.ComparisonOperator):
+ err = errors.New("ComparisonOperator is not valid")
+ case alarm.EvaluationPeriods == 0:
+ err = errors.New("No number of EvaluationPeriods specified")
+ case alarm.MetricName == "":
+ err = errors.New("No MetricName specified")
+ case alarm.Namespace == "":
+ err = errors.New("No Namespace specified")
+ case alarm.Period == 0:
+ err = errors.New("No Period over which statistic should apply was specified")
+ case !validMetricStatistics.Member(alarm.Statistic):
+ err = errors.New("Invalid statistic value supplied")
+ case alarm.Threshold == 0:
+ err = errors.New("No Threshold value specified")
+ case alarm.Unit != "" && !validUnits.Member(alarm.Unit):
+ err = errors.New("Unit is not a valid value")
+ }
+ if err != nil {
+ return
+ }
+
+ for i, action := range alarm.AlarmActions {
+ params["AlarmActions.member."+strconv.Itoa(i+1)] = action.ARN
+ }
+ for i, action := range alarm.InsufficientDataActions {
+ params["InsufficientDataActions.member."+strconv.Itoa(i+1)] = action.ARN
+ }
+ for i, action := range alarm.OkActions {
+ params["OKActions.member."+strconv.Itoa(i+1)] = action.ARN
+ }
+ if alarm.AlarmDescription != "" {
+ params["AlarmDescription"] = alarm.AlarmDescription
+ }
+ params["AlarmDescription"] = alarm.AlarmDescription
+ params["AlarmName"] = alarm.AlarmName
+ params["ComparisonOperator"] = alarm.ComparisonOperator
+ for i, dim := range alarm.Dimensions {
+ dimprefix := "Dimensions.member." + strconv.Itoa(i+1)
+ params[dimprefix+".Name"] = dim.Name
+ params[dimprefix+".Value"] = dim.Value
+ }
+ params["EvaluationPeriods"] = strconv.Itoa(alarm.EvaluationPeriods)
+ params["MetricName"] = alarm.MetricName
+ params["Namespace"] = alarm.Namespace
+ params["Period"] = strconv.Itoa(alarm.Period)
+ params["Statistic"] = alarm.Statistic
+ params["Threshold"] = strconv.FormatFloat(alarm.Threshold, 'E', 10, 64)
+ if alarm.Unit != "" {
+ params["Unit"] = alarm.Unit
+ }
+
+ result = new(aws.BaseResponse)
+ err = c.query("POST", "/", params, result)
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/cloudwatch/cloudwatch_test.go b/vendor/github.com/goamz/goamz/cloudwatch/cloudwatch_test.go
new file mode 100644
index 000000000..a4271f1ea
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/cloudwatch/cloudwatch_test.go
@@ -0,0 +1,132 @@
+package cloudwatch_test
+
+import (
+ "testing"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/cloudwatch"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+type S struct {
+ cw *cloudwatch.CloudWatch
+}
+
+var _ = Suite(&S{})
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.cw, _ = cloudwatch.NewCloudWatch(auth, aws.ServiceInfo{testServer.URL, aws.V2Signature})
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func getTestAlarm() *cloudwatch.MetricAlarm {
+ alarm := new(cloudwatch.MetricAlarm)
+
+ alarm.AlarmName = "TestAlarm"
+ alarm.MetricName = "TestMetric"
+ alarm.Namespace = "TestNamespace"
+ alarm.ComparisonOperator = "LessThanThreshold"
+ alarm.Threshold = 1
+ alarm.EvaluationPeriods = 5
+ alarm.Period = 60
+ alarm.Statistic = "Sum"
+
+ return alarm
+}
+
+func (s *S) TestPutAlarm(c *C) {
+ testServer.Response(200, nil, "<RequestId>123</RequestId>")
+
+ alarm := getTestAlarm()
+
+ _, err := s.cw.PutMetricAlarm(alarm)
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Form["Action"], DeepEquals, []string{"PutMetricAlarm"})
+ c.Assert(req.Form["AlarmName"], DeepEquals, []string{"TestAlarm"})
+ c.Assert(req.Form["ComparisonOperator"], DeepEquals, []string{"LessThanThreshold"})
+ c.Assert(req.Form["EvaluationPeriods"], DeepEquals, []string{"5"})
+ c.Assert(req.Form["Threshold"], DeepEquals, []string{"1.0000000000E+00"})
+ c.Assert(req.Form["Period"], DeepEquals, []string{"60"})
+ c.Assert(req.Form["Statistic"], DeepEquals, []string{"Sum"})
+}
+
+func (s *S) TestPutAlarmWithAction(c *C) {
+ testServer.Response(200, nil, "<RequestId>123</RequestId>")
+
+ alarm := getTestAlarm()
+
+ alarm.AlarmActions = []cloudwatch.AlarmAction{
+ cloudwatch.AlarmAction{
+ ARN: "123",
+ },
+ }
+
+ alarm.OkActions = []cloudwatch.AlarmAction{
+ cloudwatch.AlarmAction{
+ ARN: "456",
+ },
+ }
+
+ alarm.InsufficientDataActions = []cloudwatch.AlarmAction{
+ cloudwatch.AlarmAction{
+ ARN: "789",
+ },
+ }
+
+ _, err := s.cw.PutMetricAlarm(alarm)
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Form["Action"], DeepEquals, []string{"PutMetricAlarm"})
+ c.Assert(req.Form["AlarmActions.member.1"], DeepEquals, []string{"123"})
+ c.Assert(req.Form["OKActions.member.1"], DeepEquals, []string{"456"})
+ c.Assert(req.Form["InsufficientDataActions.member.1"], DeepEquals, []string{"789"})
+ c.Assert(req.Form["AlarmName"], DeepEquals, []string{"TestAlarm"})
+ c.Assert(req.Form["ComparisonOperator"], DeepEquals, []string{"LessThanThreshold"})
+ c.Assert(req.Form["EvaluationPeriods"], DeepEquals, []string{"5"})
+ c.Assert(req.Form["Threshold"], DeepEquals, []string{"1.0000000000E+00"})
+ c.Assert(req.Form["Period"], DeepEquals, []string{"60"})
+ c.Assert(req.Form["Statistic"], DeepEquals, []string{"Sum"})
+}
+
+func (s *S) TestPutAlarmInvalidComapirsonOperator(c *C) {
+ testServer.Response(200, nil, "<RequestId>123</RequestId>")
+
+ alarm := getTestAlarm()
+
+ alarm.ComparisonOperator = "LessThan"
+
+ _, err := s.cw.PutMetricAlarm(alarm)
+ c.Assert(err, NotNil)
+ c.Assert(err.Error(), Equals, "ComparisonOperator is not valid")
+}
+
+func (s *S) TestPutAlarmInvalidStatistic(c *C) {
+ testServer.Response(200, nil, "<RequestId>123</RequestId>")
+
+ alarm := getTestAlarm()
+
+ alarm.Statistic = "Count"
+
+ _, err := s.cw.PutMetricAlarm(alarm)
+ c.Assert(err, NotNil)
+ c.Assert(err.Error(), Equals, "Invalid statistic value supplied")
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/.gitignore b/vendor/github.com/goamz/goamz/dynamodb/.gitignore
new file mode 100644
index 000000000..2385ddf57
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/.gitignore
@@ -0,0 +1 @@
+dynamodb_local*
diff --git a/vendor/github.com/goamz/goamz/dynamodb/Makefile b/vendor/github.com/goamz/goamz/dynamodb/Makefile
new file mode 100644
index 000000000..4c02cd4b7
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/Makefile
@@ -0,0 +1,13 @@
+DYNAMODB_LOCAL_VERSION = 2013-12-12
+
+launch: DynamoDBLocal.jar
+ cd dynamodb_local_$(DYNAMODB_LOCAL_VERSION) && java -Djava.library.path=./DynamoDBLocal_lib -jar DynamoDBLocal.jar
+
+DynamoDBLocal.jar: dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz
+ [ -d dynamodb_local_$(DYNAMODB_LOCAL_VERSION) ] || tar -zxf dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz
+
+dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz:
+ curl -O https://s3-us-west-2.amazonaws.com/dynamodb-local/dynamodb_local_$(DYNAMODB_LOCAL_VERSION).tar.gz
+
+clean:
+ rm -rf dynamodb_local_$(DYNAMODB_LOCAL_VERSION)*
diff --git a/vendor/github.com/goamz/goamz/dynamodb/README.md b/vendor/github.com/goamz/goamz/dynamodb/README.md
new file mode 100644
index 000000000..5896d67b6
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/README.md
@@ -0,0 +1,27 @@
+# Running integration tests
+
+## against DynamoDB local
+
+To download and launch DynamoDB local:
+
+```sh
+$ make
+```
+
+To test:
+
+```sh
+$ go test -v -amazon
+```
+
+## against real DynamoDB server on us-east
+
+_WARNING_: Some dangerous operations such as `DeleteTable` will be performed during the tests. Please be careful.
+
+To test:
+
+```sh
+$ go test -v -amazon -local=false
+```
+
+_Note_: Running tests against real DynamoDB will take several minutes.
diff --git a/vendor/github.com/goamz/goamz/dynamodb/attribute.go b/vendor/github.com/goamz/goamz/dynamodb/attribute.go
new file mode 100755
index 000000000..38389ada2
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/attribute.go
@@ -0,0 +1,185 @@
+package dynamodb
+
+import (
+ "strconv"
+)
+
+const (
+ TYPE_STRING = "S"
+ TYPE_NUMBER = "N"
+ TYPE_BINARY = "B"
+
+ TYPE_STRING_SET = "SS"
+ TYPE_NUMBER_SET = "NS"
+ TYPE_BINARY_SET = "BS"
+
+ COMPARISON_EQUAL = "EQ"
+ COMPARISON_NOT_EQUAL = "NE"
+ COMPARISON_LESS_THAN_OR_EQUAL = "LE"
+ COMPARISON_LESS_THAN = "LT"
+ COMPARISON_GREATER_THAN_OR_EQUAL = "GE"
+ COMPARISON_GREATER_THAN = "GT"
+ COMPARISON_ATTRIBUTE_EXISTS = "NOT_NULL"
+ COMPARISON_ATTRIBUTE_DOES_NOT_EXIST = "NULL"
+ COMPARISON_CONTAINS = "CONTAINS"
+ COMPARISON_DOES_NOT_CONTAIN = "NOT_CONTAINS"
+ COMPARISON_BEGINS_WITH = "BEGINS_WITH"
+ COMPARISON_IN = "IN"
+ COMPARISON_BETWEEN = "BETWEEN"
+)
+
+type Key struct {
+ HashKey string
+ RangeKey string
+}
+
+type PrimaryKey struct {
+ KeyAttribute *Attribute
+ RangeAttribute *Attribute
+}
+
+type Attribute struct {
+ Type string
+ Name string
+ Value string
+ SetValues []string
+ Exists string // exists on dynamodb? Values: "true", "false", or ""
+}
+
+type AttributeComparison struct {
+ AttributeName string
+ ComparisonOperator string
+ AttributeValueList []Attribute // contains attributes with only types and names (value ignored)
+}
+
+func NewEqualInt64AttributeComparison(attributeName string, equalToValue int64) *AttributeComparison {
+ numeric := NewNumericAttribute(attributeName, strconv.FormatInt(equalToValue, 10))
+ return &AttributeComparison{attributeName,
+ COMPARISON_EQUAL,
+ []Attribute{*numeric},
+ }
+}
+
+func NewEqualStringAttributeComparison(attributeName string, equalToValue string) *AttributeComparison {
+ str := NewStringAttribute(attributeName, equalToValue)
+ return &AttributeComparison{attributeName,
+ COMPARISON_EQUAL,
+ []Attribute{*str},
+ }
+}
+
+func NewStringAttributeComparison(attributeName string, comparisonOperator string, value string) *AttributeComparison {
+ valueToCompare := NewStringAttribute(attributeName, value)
+ return &AttributeComparison{attributeName,
+ comparisonOperator,
+ []Attribute{*valueToCompare},
+ }
+}
+
+func NewNumericAttributeComparison(attributeName string, comparisonOperator string, value int64) *AttributeComparison {
+ valueToCompare := NewNumericAttribute(attributeName, strconv.FormatInt(value, 10))
+ return &AttributeComparison{attributeName,
+ comparisonOperator,
+ []Attribute{*valueToCompare},
+ }
+}
+
+func NewBinaryAttributeComparison(attributeName string, comparisonOperator string, value bool) *AttributeComparison {
+ valueToCompare := NewBinaryAttribute(attributeName, strconv.FormatBool(value))
+ return &AttributeComparison{attributeName,
+ comparisonOperator,
+ []Attribute{*valueToCompare},
+ }
+}
+
+func NewStringAttribute(name string, value string) *Attribute {
+ return &Attribute{
+ Type: TYPE_STRING,
+ Name: name,
+ Value: value,
+ }
+}
+
+func NewNumericAttribute(name string, value string) *Attribute {
+ return &Attribute{
+ Type: TYPE_NUMBER,
+ Name: name,
+ Value: value,
+ }
+}
+
+func NewBinaryAttribute(name string, value string) *Attribute {
+ return &Attribute{
+ Type: TYPE_BINARY,
+ Name: name,
+ Value: value,
+ }
+}
+
+func NewStringSetAttribute(name string, values []string) *Attribute {
+ return &Attribute{
+ Type: TYPE_STRING_SET,
+ Name: name,
+ SetValues: values,
+ }
+}
+
+func NewNumericSetAttribute(name string, values []string) *Attribute {
+ return &Attribute{
+ Type: TYPE_NUMBER_SET,
+ Name: name,
+ SetValues: values,
+ }
+}
+
+func NewBinarySetAttribute(name string, values []string) *Attribute {
+ return &Attribute{
+ Type: TYPE_BINARY_SET,
+ Name: name,
+ SetValues: values,
+ }
+}
+
+func (a *Attribute) SetType() bool {
+ switch a.Type {
+ case TYPE_BINARY_SET, TYPE_NUMBER_SET, TYPE_STRING_SET:
+ return true
+ }
+ return false
+}
+
+func (a *Attribute) SetExists(exists bool) *Attribute {
+ if exists {
+ a.Exists = "true"
+ } else {
+ a.Exists = "false"
+ }
+ return a
+}
+
+func (k *PrimaryKey) HasRange() bool {
+ return k.RangeAttribute != nil
+}
+
+// Useful when you may have many goroutines using a primary key, so they don't fuxor up your values.
+func (k *PrimaryKey) Clone(h string, r string) []Attribute {
+ pk := &Attribute{
+ Type: k.KeyAttribute.Type,
+ Name: k.KeyAttribute.Name,
+ Value: h,
+ }
+
+ result := []Attribute{*pk}
+
+ if k.HasRange() {
+ rk := &Attribute{
+ Type: k.RangeAttribute.Type,
+ Name: k.RangeAttribute.Name,
+ Value: r,
+ }
+
+ result = append(result, *rk)
+ }
+
+ return result
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/const.go b/vendor/github.com/goamz/goamz/dynamodb/const.go
new file mode 100644
index 000000000..b070d44cb
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/const.go
@@ -0,0 +1,11 @@
+package dynamodb
+
+type ReturnValues string
+
+const (
+ NONE ReturnValues = "NONE"
+ ALL_OLD ReturnValues = "ALL_HOLD"
+ UPDATED_OLD ReturnValues = "UPDATED_OLD"
+ ALL_NEW ReturnValues = "ALL_NEW"
+ UPDATED_NEW ReturnValues = "UPDATED_NEW"
+)
diff --git a/vendor/github.com/goamz/goamz/dynamodb/dynamodb.go b/vendor/github.com/goamz/goamz/dynamodb/dynamodb.go
new file mode 100755
index 000000000..7881e8dc1
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/dynamodb.go
@@ -0,0 +1,142 @@
+package dynamodb
+
+import simplejson "github.com/bitly/go-simplejson"
+import (
+ "errors"
+ "github.com/goamz/goamz/aws"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "strings"
+ "time"
+)
+
+type Server struct {
+ Auth aws.Auth
+ Region aws.Region
+}
+
+/*
+type Query struct {
+ Query string
+}
+*/
+
+/*
+func NewQuery(queryParts []string) *Query {
+ return &Query{
+ "{" + strings.Join(queryParts, ",") + "}",
+ }
+}
+*/
+
+const (
+ // DynamoDBAPIPrefix is the versioned prefix for DynamoDB API commands.
+ DynamoDBAPIPrefix = "DynamoDB_20120810."
+ // DynamoDBStreamsAPIPrefix is the versioned prefix for DynamoDB Streams API commands.
+ DynamoDBStreamsAPIPrefix = "DynamoDBStreams_20120810."
+)
+
+// Specific error constants
+var ErrNotFound = errors.New("Item not found")
+
+// Error represents an error in an operation with Dynamodb (following goamz/s3)
+type Error struct {
+ StatusCode int // HTTP status code (200, 403, ...)
+ Status string
+ Code string // Dynamodb error code ("MalformedQueryString", ...)
+ Message string // The human-oriented error message
+}
+
+func (e *Error) Error() string {
+ return e.Code + ": " + e.Message
+}
+
+func buildError(r *http.Response, jsonBody []byte) error {
+
+ ddbError := Error{
+ StatusCode: r.StatusCode,
+ Status: r.Status,
+ }
+ // TODO return error if Unmarshal fails?
+
+ json, err := simplejson.NewJson(jsonBody)
+ if err != nil {
+ log.Printf("Failed to parse body as JSON")
+ return err
+ }
+ ddbError.Message = json.Get("message").MustString()
+
+ // Of the form: com.amazon.coral.validate#ValidationException
+ // We only want the last part
+ codeStr := json.Get("__type").MustString()
+ hashIndex := strings.Index(codeStr, "#")
+ if hashIndex > 0 {
+ codeStr = codeStr[hashIndex+1:]
+ }
+ ddbError.Code = codeStr
+
+ return &ddbError
+}
+
+func (s *Server) queryServer(target string, query *Query) ([]byte, error) {
+ data := strings.NewReader(query.String())
+ var endpoint string
+ if isStreamsTarget(target) {
+ endpoint = s.Region.DynamoDBStreamsEndpoint
+ } else {
+ endpoint = s.Region.DynamoDBEndpoint
+ }
+ hreq, err := http.NewRequest("POST", endpoint+"/", data)
+ if err != nil {
+ return nil, err
+ }
+
+ hreq.Header.Set("Content-Type", "application/x-amz-json-1.0")
+ hreq.Header.Set("X-Amz-Date", time.Now().UTC().Format(aws.ISO8601BasicFormat))
+ hreq.Header.Set("X-Amz-Target", target)
+
+ token := s.Auth.Token()
+ if token != "" {
+ hreq.Header.Set("X-Amz-Security-Token", token)
+ }
+
+ signer := aws.NewV4Signer(s.Auth, "dynamodb", s.Region)
+ signer.Sign(hreq)
+
+ resp, err := http.DefaultClient.Do(hreq)
+
+ if err != nil {
+ log.Printf("Error calling Amazon")
+ return nil, err
+ }
+
+ defer resp.Body.Close()
+
+ body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ log.Printf("Could not read response body")
+ return nil, err
+ }
+
+ // http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ErrorHandling.html
+ // "A response code of 200 indicates the operation was successful."
+ if resp.StatusCode != 200 {
+ ddbErr := buildError(resp, body)
+ return nil, ddbErr
+ }
+
+ return body, nil
+}
+
+func target(name string) string {
+ return DynamoDBAPIPrefix + name
+}
+
+func streamsTarget(name string) string {
+ return DynamoDBStreamsAPIPrefix + name
+}
+
+func isStreamsTarget(target string) bool {
+ return strings.HasPrefix(target, DynamoDBStreamsAPIPrefix)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/dynamodb_test.go b/vendor/github.com/goamz/goamz/dynamodb/dynamodb_test.go
new file mode 100755
index 000000000..63dd03da3
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/dynamodb_test.go
@@ -0,0 +1,166 @@
+package dynamodb_test
+
+import (
+ "flag"
+ "testing"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/dynamodb"
+ . "gopkg.in/check.v1"
+)
+
+const TIMEOUT = 3 * time.Minute
+
+var amazon = flag.Bool("amazon", false, "Enable tests against dynamodb")
+var local = flag.Bool("local", true, "Use DynamoDB local on 8080 instead of real server on us-east.")
+
+var dynamodb_region aws.Region
+var dynamodb_auth aws.Auth
+
+type DynamoDBTest struct {
+ server *dynamodb.Server
+ aws.Region // Exports Region
+ TableDescriptionT dynamodb.TableDescriptionT
+ table *dynamodb.Table
+}
+
+// Delete all items in the table
+func (s *DynamoDBTest) TearDownTest(c *C) {
+ pk, err := s.TableDescriptionT.BuildPrimaryKey()
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ attrs, err := s.table.Scan(nil)
+ if err != nil {
+ c.Fatal(err)
+ }
+ for _, a := range attrs {
+ key := &dynamodb.Key{
+ HashKey: a[pk.KeyAttribute.Name].Value,
+ }
+ if pk.HasRange() {
+ key.RangeKey = a[pk.RangeAttribute.Name].Value
+ }
+ if ok, err := s.table.DeleteItem(key); !ok {
+ c.Fatal(err)
+ }
+ }
+}
+
+func (s *DynamoDBTest) TearDownSuite(c *C) {
+ // return immediately in the case of calling c.Skip() in SetUpSuite()
+ if s.server == nil {
+ return
+ }
+
+ // check whether the table exists
+ if tables, err := s.server.ListTables(); err != nil {
+ c.Fatal(err)
+ } else {
+ if !findTableByName(tables, s.TableDescriptionT.TableName) {
+ return
+ }
+ }
+
+ // Delete the table and wait
+ if _, err := s.server.DeleteTable(s.TableDescriptionT); err != nil {
+ c.Fatal(err)
+ }
+
+ done := make(chan bool)
+ timeout := time.After(TIMEOUT)
+ go func() {
+ for {
+ select {
+ case <-done:
+ return
+ default:
+ tables, err := s.server.ListTables()
+ if err != nil {
+ c.Fatal(err)
+ }
+ if findTableByName(tables, s.TableDescriptionT.TableName) {
+ time.Sleep(5 * time.Second)
+ } else {
+ done <- true
+ return
+ }
+ }
+ }
+ }()
+ select {
+ case <-done:
+ break
+ case <-timeout:
+ c.Error("Expect the table to be deleted but timed out")
+ close(done)
+ }
+}
+
+func (s *DynamoDBTest) WaitUntilStatus(c *C, status string) {
+ // We should wait until the table is in specified status because a real DynamoDB has some delay for ready
+ done := make(chan bool)
+ timeout := time.After(TIMEOUT)
+ go func() {
+ for {
+ select {
+ case <-done:
+ return
+ default:
+ desc, err := s.table.DescribeTable()
+ if err != nil {
+ c.Fatal(err)
+ }
+ if desc.TableStatus == status {
+ done <- true
+ return
+ }
+ time.Sleep(5 * time.Second)
+ }
+ }
+ }()
+ select {
+ case <-done:
+ break
+ case <-timeout:
+ c.Errorf("Expect a status to be %s, but timed out", status)
+ close(done)
+ }
+}
+
+func setUpAuth(c *C) {
+ if !*amazon {
+ c.Skip("Test against amazon not enabled.")
+ }
+ if *local {
+ c.Log("Using local server")
+ dynamodb_region = aws.Region{
+ DynamoDBEndpoint: "http://127.0.0.1:8000",
+ DynamoDBStreamsEndpoint: "http://127.0.0.1:8000",
+ }
+ dynamodb_auth = aws.Auth{AccessKey: "DUMMY_KEY", SecretKey: "DUMMY_SECRET"}
+ } else {
+ c.Log("Using REAL AMAZON SERVER")
+ dynamodb_region = aws.USEast
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ c.Fatal(err)
+ }
+ dynamodb_auth = auth
+ }
+}
+
+func findTableByName(tables []string, name string) bool {
+ for _, t := range tables {
+ if t == name {
+ return true
+ }
+ }
+ return false
+}
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/item.go b/vendor/github.com/goamz/goamz/dynamodb/item.go
new file mode 100755
index 000000000..a3814d9ad
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/item.go
@@ -0,0 +1,351 @@
+package dynamodb
+
+import simplejson "github.com/bitly/go-simplejson"
+import (
+ "errors"
+ "fmt"
+ "log"
+)
+
+type BatchGetItem struct {
+ Server *Server
+ Keys map[*Table][]Key
+}
+
+type BatchWriteItem struct {
+ Server *Server
+ ItemActions map[*Table]map[string][][]Attribute
+}
+
+func (t *Table) BatchGetItems(keys []Key) *BatchGetItem {
+ batchGetItem := &BatchGetItem{t.Server, make(map[*Table][]Key)}
+
+ batchGetItem.Keys[t] = keys
+ return batchGetItem
+}
+
+func (t *Table) BatchWriteItems(itemActions map[string][][]Attribute) *BatchWriteItem {
+ batchWriteItem := &BatchWriteItem{t.Server, make(map[*Table]map[string][][]Attribute)}
+
+ batchWriteItem.ItemActions[t] = itemActions
+ return batchWriteItem
+}
+
+func (batchGetItem *BatchGetItem) AddTable(t *Table, keys *[]Key) *BatchGetItem {
+ batchGetItem.Keys[t] = *keys
+ return batchGetItem
+}
+
+func (batchWriteItem *BatchWriteItem) AddTable(t *Table, itemActions *map[string][][]Attribute) *BatchWriteItem {
+ batchWriteItem.ItemActions[t] = *itemActions
+ return batchWriteItem
+}
+
+func (batchGetItem *BatchGetItem) Execute() (map[string][]map[string]*Attribute, error) {
+ q := NewEmptyQuery()
+ q.AddGetRequestItems(batchGetItem.Keys)
+
+ jsonResponse, err := batchGetItem.Server.queryServer("DynamoDB_20120810.BatchGetItem", q)
+ if err != nil {
+ return nil, err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+
+ if err != nil {
+ return nil, err
+ }
+
+ results := make(map[string][]map[string]*Attribute)
+
+ tables, err := json.Get("Responses").Map()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ for table, entries := range tables {
+ var tableResult []map[string]*Attribute
+
+ jsonEntriesArray, ok := entries.([]interface{})
+ if !ok {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ for _, entry := range jsonEntriesArray {
+ item, ok := entry.(map[string]interface{})
+ if !ok {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ unmarshalledItem := parseAttributes(item)
+ tableResult = append(tableResult, unmarshalledItem)
+ }
+
+ results[table] = tableResult
+ }
+
+ return results, nil
+}
+
+func (batchWriteItem *BatchWriteItem) Execute() (map[string]interface{}, error) {
+ q := NewEmptyQuery()
+ q.AddWriteRequestItems(batchWriteItem.ItemActions)
+
+ jsonResponse, err := batchWriteItem.Server.queryServer("DynamoDB_20120810.BatchWriteItem", q)
+
+ if err != nil {
+ return nil, err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+
+ if err != nil {
+ return nil, err
+ }
+
+ unprocessed, err := json.Get("UnprocessedItems").Map()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ if len(unprocessed) == 0 {
+ return nil, nil
+ } else {
+ return unprocessed, errors.New("One or more unprocessed items.")
+ }
+
+}
+
+func (t *Table) GetItem(key *Key) (map[string]*Attribute, error) {
+ return t.getItem(key, false)
+}
+
+func (t *Table) GetItemConsistent(key *Key, consistentRead bool) (map[string]*Attribute, error) {
+ return t.getItem(key, consistentRead)
+}
+
+func (t *Table) getItem(key *Key, consistentRead bool) (map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKey(t, key)
+
+ if consistentRead {
+ q.ConsistentRead(consistentRead)
+ }
+
+ jsonResponse, err := t.Server.queryServer(target("GetItem"), q)
+ if err != nil {
+ return nil, err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ itemJson, ok := json.CheckGet("Item")
+ if !ok {
+ // We got an empty from amz. The item doesn't exist.
+ return nil, ErrNotFound
+ }
+
+ item, err := itemJson.Map()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ return parseAttributes(item), nil
+
+}
+
+func (t *Table) PutItem(hashKey string, rangeKey string, attributes []Attribute) (bool, error) {
+ return t.putItem(hashKey, rangeKey, attributes, nil)
+}
+
+func (t *Table) ConditionalPutItem(hashKey, rangeKey string, attributes, expected []Attribute) (bool, error) {
+ return t.putItem(hashKey, rangeKey, attributes, expected)
+}
+
+func (t *Table) putItem(hashKey, rangeKey string, attributes, expected []Attribute) (bool, error) {
+ if len(attributes) == 0 {
+ return false, errors.New("At least one attribute is required.")
+ }
+
+ q := NewQuery(t)
+
+ keys := t.Key.Clone(hashKey, rangeKey)
+ attributes = append(attributes, keys...)
+
+ q.AddItem(attributes)
+ if expected != nil {
+ q.AddExpected(expected)
+ }
+
+ jsonResponse, err := t.Server.queryServer(target("PutItem"), q)
+
+ if err != nil {
+ return false, err
+ }
+
+ _, err = simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return false, err
+ }
+
+ return true, nil
+}
+
+func (t *Table) deleteItem(key *Key, expected []Attribute) (bool, error) {
+ q := NewQuery(t)
+ q.AddKey(t, key)
+
+ if expected != nil {
+ q.AddExpected(expected)
+ }
+
+ jsonResponse, err := t.Server.queryServer(target("DeleteItem"), q)
+
+ if err != nil {
+ return false, err
+ }
+
+ _, err = simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return false, err
+ }
+
+ return true, nil
+}
+
+func (t *Table) DeleteItem(key *Key) (bool, error) {
+ return t.deleteItem(key, nil)
+}
+
+func (t *Table) ConditionalDeleteItem(key *Key, expected []Attribute) (bool, error) {
+ return t.deleteItem(key, expected)
+}
+
+func (t *Table) AddAttributes(key *Key, attributes []Attribute) (bool, error) {
+ return t.modifyAttributes(key, attributes, nil, "ADD")
+}
+
+func (t *Table) UpdateAttributes(key *Key, attributes []Attribute) (bool, error) {
+ return t.modifyAttributes(key, attributes, nil, "PUT")
+}
+
+func (t *Table) DeleteAttributes(key *Key, attributes []Attribute) (bool, error) {
+ return t.modifyAttributes(key, attributes, nil, "DELETE")
+}
+
+func (t *Table) ConditionalAddAttributes(key *Key, attributes, expected []Attribute) (bool, error) {
+ return t.modifyAttributes(key, attributes, expected, "ADD")
+}
+
+func (t *Table) ConditionalUpdateAttributes(key *Key, attributes, expected []Attribute) (bool, error) {
+ return t.modifyAttributes(key, attributes, expected, "PUT")
+}
+
+func (t *Table) ConditionalDeleteAttributes(key *Key, attributes, expected []Attribute) (bool, error) {
+ return t.modifyAttributes(key, attributes, expected, "DELETE")
+}
+
+func (t *Table) modifyAttributes(key *Key, attributes, expected []Attribute, action string) (bool, error) {
+
+ if len(attributes) == 0 {
+ return false, errors.New("At least one attribute is required.")
+ }
+
+ q := NewQuery(t)
+ q.AddKey(t, key)
+ q.AddUpdates(attributes, action)
+
+ if expected != nil {
+ q.AddExpected(expected)
+ }
+
+ jsonResponse, err := t.Server.queryServer(target("UpdateItem"), q)
+
+ if err != nil {
+ return false, err
+ }
+
+ _, err = simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return false, err
+ }
+
+ return true, nil
+}
+
+func parseAttributes(s map[string]interface{}) map[string]*Attribute {
+ results := map[string]*Attribute{}
+
+ for key, value := range s {
+ if v, ok := value.(map[string]interface{}); ok {
+ if val, ok := v[TYPE_STRING].(string); ok {
+ results[key] = &Attribute{
+ Type: TYPE_STRING,
+ Name: key,
+ Value: val,
+ }
+ } else if val, ok := v[TYPE_NUMBER].(string); ok {
+ results[key] = &Attribute{
+ Type: TYPE_NUMBER,
+ Name: key,
+ Value: val,
+ }
+ } else if val, ok := v[TYPE_BINARY].(string); ok {
+ results[key] = &Attribute{
+ Type: TYPE_BINARY,
+ Name: key,
+ Value: val,
+ }
+ } else if vals, ok := v[TYPE_STRING_SET].([]interface{}); ok {
+ arry := make([]string, len(vals))
+ for i, ivalue := range vals {
+ if val, ok := ivalue.(string); ok {
+ arry[i] = val
+ }
+ }
+ results[key] = &Attribute{
+ Type: TYPE_STRING_SET,
+ Name: key,
+ SetValues: arry,
+ }
+ } else if vals, ok := v[TYPE_NUMBER_SET].([]interface{}); ok {
+ arry := make([]string, len(vals))
+ for i, ivalue := range vals {
+ if val, ok := ivalue.(string); ok {
+ arry[i] = val
+ }
+ }
+ results[key] = &Attribute{
+ Type: TYPE_NUMBER_SET,
+ Name: key,
+ SetValues: arry,
+ }
+ } else if vals, ok := v[TYPE_BINARY_SET].([]interface{}); ok {
+ arry := make([]string, len(vals))
+ for i, ivalue := range vals {
+ if val, ok := ivalue.(string); ok {
+ arry[i] = val
+ }
+ }
+ results[key] = &Attribute{
+ Type: TYPE_BINARY_SET,
+ Name: key,
+ SetValues: arry,
+ }
+ }
+ } else {
+ log.Printf("type assertion to map[string] interface{} failed for : %s\n ", value)
+ }
+
+ }
+
+ return results
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/item_test.go b/vendor/github.com/goamz/goamz/dynamodb/item_test.go
new file mode 100644
index 000000000..37b4b8838
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/item_test.go
@@ -0,0 +1,446 @@
+package dynamodb_test
+
+import (
+ "github.com/goamz/goamz/dynamodb"
+ . "gopkg.in/check.v1"
+)
+
+type ItemSuite struct {
+ TableDescriptionT dynamodb.TableDescriptionT
+ DynamoDBTest
+ WithRange bool
+}
+
+func (s *ItemSuite) SetUpSuite(c *C) {
+ setUpAuth(c)
+ s.DynamoDBTest.TableDescriptionT = s.TableDescriptionT
+ s.server = &dynamodb.Server{dynamodb_auth, dynamodb_region}
+ pk, err := s.TableDescriptionT.BuildPrimaryKey()
+ if err != nil {
+ c.Skip(err.Error())
+ }
+ s.table = s.server.NewTable(s.TableDescriptionT.TableName, pk)
+
+ // Cleanup
+ s.TearDownSuite(c)
+ _, err = s.server.CreateTable(s.TableDescriptionT)
+ if err != nil {
+ c.Fatal(err)
+ }
+ s.WaitUntilStatus(c, "ACTIVE")
+}
+
+var item_suite = &ItemSuite{
+ TableDescriptionT: dynamodb.TableDescriptionT{
+ TableName: "DynamoDBTestMyTable",
+ AttributeDefinitions: []dynamodb.AttributeDefinitionT{
+ dynamodb.AttributeDefinitionT{"TestHashKey", "S"},
+ dynamodb.AttributeDefinitionT{"TestRangeKey", "N"},
+ },
+ KeySchema: []dynamodb.KeySchemaT{
+ dynamodb.KeySchemaT{"TestHashKey", "HASH"},
+ dynamodb.KeySchemaT{"TestRangeKey", "RANGE"},
+ },
+ ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
+ ReadCapacityUnits: 1,
+ WriteCapacityUnits: 1,
+ },
+ },
+ WithRange: true,
+}
+
+var item_without_range_suite = &ItemSuite{
+ TableDescriptionT: dynamodb.TableDescriptionT{
+ TableName: "DynamoDBTestMyTable",
+ AttributeDefinitions: []dynamodb.AttributeDefinitionT{
+ dynamodb.AttributeDefinitionT{"TestHashKey", "S"},
+ },
+ KeySchema: []dynamodb.KeySchemaT{
+ dynamodb.KeySchemaT{"TestHashKey", "HASH"},
+ },
+ ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
+ ReadCapacityUnits: 1,
+ WriteCapacityUnits: 1,
+ },
+ },
+ WithRange: false,
+}
+
+var _ = Suite(item_suite)
+var _ = Suite(item_without_range_suite)
+
+func (s *ItemSuite) TestConditionalPutUpdateDeleteItem(c *C) {
+ if s.WithRange {
+ // No rangekey test required
+ return
+ }
+
+ attrs := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "Attr1Val"),
+ }
+ pk := &dynamodb.Key{HashKey: "NewHashKeyVal"}
+
+ // Put
+ if ok, err := s.table.PutItem("NewHashKeyVal", "", attrs); !ok {
+ c.Fatal(err)
+ }
+
+ {
+ // Put with condition failed
+ expected := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "expectedAttr1Val").SetExists(true),
+ *dynamodb.NewStringAttribute("AttrNotExists", "").SetExists(false),
+ }
+ if ok, err := s.table.ConditionalPutItem("NewHashKeyVal", "", attrs, expected); ok {
+ c.Errorf("Expect condition does not meet.")
+ } else {
+ c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
+ }
+
+ // Add attributes with condition failed
+ if ok, err := s.table.ConditionalAddAttributes(pk, attrs, expected); ok {
+ c.Errorf("Expect condition does not meet.")
+ } else {
+ c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
+ }
+
+ // Update attributes with condition failed
+ if ok, err := s.table.ConditionalUpdateAttributes(pk, attrs, expected); ok {
+ c.Errorf("Expect condition does not meet.")
+ } else {
+ c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
+ }
+
+ // Delete attributes with condition failed
+ if ok, err := s.table.ConditionalDeleteAttributes(pk, attrs, expected); ok {
+ c.Errorf("Expect condition does not meet.")
+ } else {
+ c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
+ }
+ }
+
+ {
+ expected := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "Attr1Val").SetExists(true),
+ }
+
+ // Add attributes with condition met
+ addNewAttrs := []dynamodb.Attribute{
+ *dynamodb.NewNumericAttribute("AddNewAttr1", "10"),
+ *dynamodb.NewNumericAttribute("AddNewAttr2", "20"),
+ }
+ if ok, err := s.table.ConditionalAddAttributes(pk, addNewAttrs, nil); !ok {
+ c.Errorf("Expect condition met. %s", err)
+ }
+
+ // Update attributes with condition met
+ updateAttrs := []dynamodb.Attribute{
+ *dynamodb.NewNumericAttribute("AddNewAttr1", "100"),
+ }
+ if ok, err := s.table.ConditionalUpdateAttributes(pk, updateAttrs, expected); !ok {
+ c.Errorf("Expect condition met. %s", err)
+ }
+
+ // Delete attributes with condition met
+ deleteAttrs := []dynamodb.Attribute{
+ *dynamodb.NewNumericAttribute("AddNewAttr2", ""),
+ }
+ if ok, err := s.table.ConditionalDeleteAttributes(pk, deleteAttrs, expected); !ok {
+ c.Errorf("Expect condition met. %s", err)
+ }
+
+ // Get to verify operations that condition are met
+ item, err := s.table.GetItem(pk)
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ if val, ok := item["AddNewAttr1"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("AddNewAttr1", "100"))
+ } else {
+ c.Error("Expect AddNewAttr1 attribute to be added and updated")
+ }
+
+ if _, ok := item["AddNewAttr2"]; ok {
+ c.Error("Expect AddNewAttr2 attribute to be deleted")
+ }
+ }
+
+ {
+ // Put with condition met
+ expected := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "Attr1Val").SetExists(true),
+ }
+ newattrs := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "Attr2Val"),
+ }
+ if ok, err := s.table.ConditionalPutItem("NewHashKeyVal", "", newattrs, expected); !ok {
+ c.Errorf("Expect condition met. %s", err)
+ }
+
+ // Get to verify Put operation that condition are met
+ item, err := s.table.GetItem(pk)
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ if val, ok := item["Attr1"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewStringAttribute("Attr1", "Attr2Val"))
+ } else {
+ c.Error("Expect Attr1 attribute to be updated")
+ }
+ }
+
+ {
+ // Delete with condition failed
+ expected := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "expectedAttr1Val").SetExists(true),
+ }
+ if ok, err := s.table.ConditionalDeleteItem(pk, expected); ok {
+ c.Errorf("Expect condition does not meet.")
+ } else {
+ c.Check(err.Error(), Matches, "ConditionalCheckFailedException.*")
+ }
+ }
+
+ {
+ // Delete with condition met
+ expected := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "Attr2Val").SetExists(true),
+ }
+ if ok, _ := s.table.ConditionalDeleteItem(pk, expected); !ok {
+ c.Errorf("Expect condition met.")
+ }
+
+ // Get to verify Delete operation
+ _, err := s.table.GetItem(pk)
+ c.Check(err.Error(), Matches, "Item not found")
+ }
+}
+
+func (s *ItemSuite) TestPutGetDeleteItem(c *C) {
+ attrs := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("Attr1", "Attr1Val"),
+ }
+
+ var rk string
+ if s.WithRange {
+ rk = "1"
+ }
+
+ // Put
+ if ok, err := s.table.PutItem("NewHashKeyVal", rk, attrs); !ok {
+ c.Fatal(err)
+ }
+
+ // Get to verify Put operation
+ pk := &dynamodb.Key{HashKey: "NewHashKeyVal", RangeKey: rk}
+ item, err := s.table.GetItem(pk)
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ if val, ok := item["TestHashKey"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewStringAttribute("TestHashKey", "NewHashKeyVal"))
+ } else {
+ c.Error("Expect TestHashKey to be found")
+ }
+
+ if s.WithRange {
+ if val, ok := item["TestRangeKey"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("TestRangeKey", "1"))
+ } else {
+ c.Error("Expect TestRangeKey to be found")
+ }
+ }
+
+ // Delete
+ if ok, _ := s.table.DeleteItem(pk); !ok {
+ c.Fatal(err)
+ }
+
+ // Get to verify Delete operation
+ _, err = s.table.GetItem(pk)
+ c.Check(err.Error(), Matches, "Item not found")
+}
+
+func (s *ItemSuite) TestUpdateItem(c *C) {
+ attrs := []dynamodb.Attribute{
+ *dynamodb.NewNumericAttribute("count", "0"),
+ }
+
+ var rk string
+ if s.WithRange {
+ rk = "1"
+ }
+
+ if ok, err := s.table.PutItem("NewHashKeyVal", rk, attrs); !ok {
+ c.Fatal(err)
+ }
+
+ // UpdateItem with Add
+ attrs = []dynamodb.Attribute{
+ *dynamodb.NewNumericAttribute("count", "10"),
+ }
+ pk := &dynamodb.Key{HashKey: "NewHashKeyVal", RangeKey: rk}
+ if ok, err := s.table.AddAttributes(pk, attrs); !ok {
+ c.Error(err)
+ }
+
+ // Get to verify Add operation
+ if item, err := s.table.GetItemConsistent(pk, true); err != nil {
+ c.Error(err)
+ } else {
+ if val, ok := item["count"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("count", "10"))
+ } else {
+ c.Error("Expect count to be found")
+ }
+ }
+
+ // UpdateItem with Put
+ attrs = []dynamodb.Attribute{
+ *dynamodb.NewNumericAttribute("count", "100"),
+ }
+ if ok, err := s.table.UpdateAttributes(pk, attrs); !ok {
+ c.Error(err)
+ }
+
+ // Get to verify Put operation
+ if item, err := s.table.GetItem(pk); err != nil {
+ c.Fatal(err)
+ } else {
+ if val, ok := item["count"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewNumericAttribute("count", "100"))
+ } else {
+ c.Error("Expect count to be found")
+ }
+ }
+
+ // UpdateItem with Delete
+ attrs = []dynamodb.Attribute{
+ *dynamodb.NewNumericAttribute("count", ""),
+ }
+ if ok, err := s.table.DeleteAttributes(pk, attrs); !ok {
+ c.Error(err)
+ }
+
+ // Get to verify Delete operation
+ if item, err := s.table.GetItem(pk); err != nil {
+ c.Error(err)
+ } else {
+ if _, ok := item["count"]; ok {
+ c.Error("Expect count not to be found")
+ }
+ }
+}
+
+func (s *ItemSuite) TestUpdateItemWithSet(c *C) {
+ attrs := []dynamodb.Attribute{
+ *dynamodb.NewStringSetAttribute("list", []string{"A", "B"}),
+ }
+
+ var rk string
+ if s.WithRange {
+ rk = "1"
+ }
+
+ if ok, err := s.table.PutItem("NewHashKeyVal", rk, attrs); !ok {
+ c.Error(err)
+ }
+
+ // UpdateItem with Add
+ attrs = []dynamodb.Attribute{
+ *dynamodb.NewStringSetAttribute("list", []string{"C"}),
+ }
+ pk := &dynamodb.Key{HashKey: "NewHashKeyVal", RangeKey: rk}
+ if ok, err := s.table.AddAttributes(pk, attrs); !ok {
+ c.Error(err)
+ }
+
+ // Get to verify Add operation
+ if item, err := s.table.GetItem(pk); err != nil {
+ c.Error(err)
+ } else {
+ if val, ok := item["list"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewStringSetAttribute("list", []string{"A", "B", "C"}))
+ } else {
+ c.Error("Expect count to be found")
+ }
+ }
+
+ // UpdateItem with Delete
+ attrs = []dynamodb.Attribute{
+ *dynamodb.NewStringSetAttribute("list", []string{"A"}),
+ }
+ if ok, err := s.table.DeleteAttributes(pk, attrs); !ok {
+ c.Error(err)
+ }
+
+ // Get to verify Delete operation
+ if item, err := s.table.GetItem(pk); err != nil {
+ c.Error(err)
+ } else {
+ if val, ok := item["list"]; ok {
+ c.Check(val, DeepEquals, dynamodb.NewStringSetAttribute("list", []string{"B", "C"}))
+ } else {
+ c.Error("Expect list to be remained")
+ }
+ }
+}
+
+func (s *ItemSuite) TestUpdateItem_new(c *C) {
+ attrs := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("intval", "1"),
+ }
+ var rk string
+ if s.WithRange {
+ rk = "1"
+ }
+ pk := &dynamodb.Key{HashKey: "UpdateKeyVal", RangeKey: rk}
+
+ num := func(a, b string) dynamodb.Attribute {
+ return *dynamodb.NewNumericAttribute(a, b)
+ }
+
+ checkVal := func(i string) {
+ if item, err := s.table.GetItem(pk); err != nil {
+ c.Error(err)
+ } else {
+ c.Check(item["intval"], DeepEquals, dynamodb.NewNumericAttribute("intval", i))
+ }
+ }
+
+ if ok, err := s.table.PutItem("UpdateKeyVal", rk, attrs); !ok {
+ c.Error(err)
+ }
+ checkVal("1")
+
+ // Simple Increment
+ s.table.UpdateItem(pk).UpdateExpression("SET intval = intval + :incr", num(":incr", "5")).Execute()
+ checkVal("6")
+
+ conditionalUpdate := func(check string) {
+ s.table.UpdateItem(pk).
+ ConditionExpression("intval = :check").
+ UpdateExpression("SET intval = intval + :incr").
+ ExpressionAttributes(num(":check", check), num(":incr", "4")).
+ Execute()
+ }
+ // Conditional increment should be a no-op.
+ conditionalUpdate("42")
+ checkVal("6")
+
+ // conditional increment should succeed this time
+ conditionalUpdate("6")
+ checkVal("10")
+
+ // Update with new values getting values
+ result, err := s.table.UpdateItem(pk).
+ ReturnValues(dynamodb.UPDATED_NEW).
+ UpdateExpression("SET intval = intval + :incr", num(":incr", "2")).
+ Execute()
+ c.Check(err, IsNil)
+ c.Check(result.Attributes["intval"], DeepEquals, num("intval", "12"))
+ checkVal("12")
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/marshaller.go b/vendor/github.com/goamz/goamz/dynamodb/marshaller.go
new file mode 100644
index 000000000..2898fbda9
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/marshaller.go
@@ -0,0 +1,626 @@
+package dynamodb
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "math"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "unicode"
+)
+
+func MarshalAttributes(m interface{}) ([]Attribute, error) {
+ v := reflect.ValueOf(m).Elem()
+
+ builder := &attributeBuilder{}
+ builder.buffer = []Attribute{}
+ for _, f := range cachedTypeFields(v.Type()) { // loop on each field
+ fv := fieldByIndex(v, f.index)
+ if !fv.IsValid() || isEmptyValueToOmit(fv) {
+ continue
+ }
+
+ err := builder.reflectToDynamoDBAttribute(f.name, fv)
+ if err != nil {
+ return builder.buffer, err
+ }
+ }
+
+ return builder.buffer, nil
+}
+
+func UnmarshalAttributes(attributesRef *map[string]*Attribute, m interface{}) error {
+ rv := reflect.ValueOf(m)
+ if rv.Kind() != reflect.Ptr || rv.IsNil() {
+ return fmt.Errorf("InvalidUnmarshalError reflect.ValueOf(v): %#v, m interface{}: %#v", rv, reflect.TypeOf(m))
+ }
+
+ v := reflect.ValueOf(m).Elem()
+
+ attributes := *attributesRef
+ for _, f := range cachedTypeFields(v.Type()) { // loop on each field
+ fv := fieldByIndex(v, f.index)
+ correlatedAttribute := attributes[f.name]
+ if correlatedAttribute == nil {
+ continue
+ }
+ err := unmarshallAttribute(correlatedAttribute, fv)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+type attributeBuilder struct {
+ buffer []Attribute
+}
+
+func (builder *attributeBuilder) Push(attribute *Attribute) {
+ builder.buffer = append(builder.buffer, *attribute)
+}
+
+func unmarshallAttribute(a *Attribute, v reflect.Value) error {
+ switch v.Kind() {
+ case reflect.Bool:
+ n, err := strconv.ParseInt(a.Value, 10, 64)
+ if err != nil {
+ return fmt.Errorf("UnmarshalTypeError (bool) %#v: %#v", a.Value, err)
+ }
+ v.SetBool(n != 0)
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ n, err := strconv.ParseInt(a.Value, 10, 64)
+ if err != nil || v.OverflowInt(n) {
+ return fmt.Errorf("UnmarshalTypeError (number) %#v: %#v", a.Value, err)
+ }
+ v.SetInt(n)
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ n, err := strconv.ParseUint(a.Value, 10, 64)
+ if err != nil || v.OverflowUint(n) {
+ return fmt.Errorf("UnmarshalTypeError (number) %#v: %#v", a.Value, err)
+ }
+ v.SetUint(n)
+
+ case reflect.Float32, reflect.Float64:
+ n, err := strconv.ParseFloat(a.Value, v.Type().Bits())
+ if err != nil || v.OverflowFloat(n) {
+ return fmt.Errorf("UnmarshalTypeError (number) %#v: %#v", a.Value, err)
+ }
+ v.SetFloat(n)
+
+ case reflect.String:
+ v.SetString(a.Value)
+
+ case reflect.Slice:
+ if v.Type().Elem().Kind() == reflect.Uint8 { // byte arrays are a special case
+ b := make([]byte, base64.StdEncoding.DecodedLen(len(a.Value)))
+ n, err := base64.StdEncoding.Decode(b, []byte(a.Value))
+ if err != nil {
+ return fmt.Errorf("UnmarshalTypeError (byte) %#v: %#v", a.Value, err)
+ }
+ v.Set(reflect.ValueOf(b[0:n]))
+ break
+ }
+
+ if a.SetType() { // Special NS and SS types should be correctly handled
+ nativeSetCreated := false
+ switch v.Type().Elem().Kind() {
+ case reflect.Bool:
+ nativeSetCreated = true
+ arry := reflect.MakeSlice(v.Type(), len(a.SetValues), len(a.SetValues))
+ for i, aval := range a.SetValues {
+ n, err := strconv.ParseInt(aval, 10, 64)
+ if err != nil {
+ return fmt.Errorf("UnmarshalSetTypeError (bool) %#v: %#v", aval, err)
+ }
+ arry.Index(i).SetBool(n != 0)
+ }
+ v.Set(arry)
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ nativeSetCreated = true
+ arry := reflect.MakeSlice(v.Type(), len(a.SetValues), len(a.SetValues))
+ for i, aval := range a.SetValues {
+ n, err := strconv.ParseInt(aval, 10, 64)
+ if err != nil || arry.Index(i).OverflowInt(n) {
+ return fmt.Errorf("UnmarshalSetTypeError (number) %#v: %#v", aval, err)
+ }
+ arry.Index(i).SetInt(n)
+ }
+ v.Set(arry)
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ nativeSetCreated = true
+ arry := reflect.MakeSlice(v.Type(), len(a.SetValues), len(a.SetValues))
+ for i, aval := range a.SetValues {
+ n, err := strconv.ParseUint(aval, 10, 64)
+ if err != nil || arry.Index(i).OverflowUint(n) {
+ return fmt.Errorf("UnmarshalSetTypeError (number) %#v: %#v", aval, err)
+ }
+ arry.Index(i).SetUint(n)
+ }
+ v.Set(arry)
+
+ case reflect.Float32, reflect.Float64:
+ nativeSetCreated = true
+ arry := reflect.MakeSlice(v.Type(), len(a.SetValues), len(a.SetValues))
+ for i, aval := range a.SetValues {
+ n, err := strconv.ParseFloat(aval, arry.Index(i).Type().Bits())
+ if err != nil || arry.Index(i).OverflowFloat(n) {
+ return fmt.Errorf("UnmarshalSetTypeError (number) %#v: %#v", aval, err)
+ }
+ arry.Index(i).SetFloat(n)
+ }
+ v.Set(arry)
+
+ case reflect.String:
+ nativeSetCreated = true
+ arry := reflect.MakeSlice(v.Type(), len(a.SetValues), len(a.SetValues))
+ for i, aval := range a.SetValues {
+ arry.Index(i).SetString(aval)
+ }
+ v.Set(arry)
+ }
+
+ if nativeSetCreated {
+ break
+ }
+ }
+
+ // Slices can be marshalled as nil, but otherwise are handled
+ // as arrays.
+ fallthrough
+ case reflect.Array, reflect.Struct, reflect.Map, reflect.Interface, reflect.Ptr:
+ unmarshalled := reflect.New(v.Type())
+ err := json.Unmarshal([]byte(a.Value), unmarshalled.Interface())
+ if err != nil {
+ return err
+ }
+ v.Set(unmarshalled.Elem())
+
+ default:
+ return fmt.Errorf("UnsupportedTypeError %#v", v.Type())
+ }
+
+ return nil
+}
+
+// reflectValueQuoted writes the value in v to the output.
+// If quoted is true, the serialization is wrapped in a JSON string.
+func (e *attributeBuilder) reflectToDynamoDBAttribute(name string, v reflect.Value) error {
+ if !v.IsValid() {
+ return nil
+ } // don't build
+
+ switch v.Kind() {
+ case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
+ rv, err := numericReflectedValueString(v)
+ if err != nil {
+ return err
+ }
+ e.Push(NewNumericAttribute(name, rv))
+
+ case reflect.String:
+ e.Push(NewStringAttribute(name, v.String()))
+
+ case reflect.Slice:
+ if v.IsNil() {
+ break
+ }
+ if v.Type().Elem().Kind() == reflect.Uint8 {
+ // Byte slices are treated as errors
+ s := v.Bytes()
+ dst := make([]byte, base64.StdEncoding.EncodedLen(len(s)))
+ base64.StdEncoding.Encode(dst, s)
+ e.Push(NewStringAttribute(name, string(dst)))
+ break
+ }
+
+ // Special NS and SS types should be correctly handled
+ nativeSetCreated := false
+ switch v.Type().Elem().Kind() {
+ case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
+ nativeSetCreated = true
+ arrystrings := make([]string, v.Len())
+ for i, _ := range arrystrings {
+ var err error
+ arrystrings[i], err = numericReflectedValueString(v.Index(i))
+ if err != nil {
+ return err
+ }
+ }
+ e.Push(NewNumericSetAttribute(name, arrystrings))
+ case reflect.String: // simple copy will suffice
+ nativeSetCreated = true
+ arrystrings := make([]string, v.Len())
+ for i, _ := range arrystrings {
+ arrystrings[i] = v.Index(i).String()
+ }
+ e.Push(NewStringSetAttribute(name, arrystrings))
+ }
+
+ if nativeSetCreated {
+ break
+ }
+
+ // Slices can be marshalled as nil, but otherwise are handled
+ // as arrays.
+ fallthrough
+ case reflect.Array, reflect.Struct, reflect.Map, reflect.Interface, reflect.Ptr:
+ jsonVersion, err := json.Marshal(v.Interface())
+ if err != nil {
+ return err
+ }
+ escapedJson := `"` + string(jsonVersion) + `"` // strconv.Quote not required because the entire string is escaped from json Marshall
+ e.Push(NewStringAttribute(name, escapedJson[1:len(escapedJson)-1]))
+
+ default:
+ return fmt.Errorf("UnsupportedTypeError %#v", v.Type())
+ }
+ return nil
+}
+
+func numericReflectedValueString(v reflect.Value) (string, error) {
+ switch v.Kind() {
+ case reflect.Bool:
+ x := v.Bool()
+ if x {
+ return "1", nil
+ } else {
+ return "0", nil
+ }
+
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return strconv.FormatInt(v.Int(), 10), nil
+
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return strconv.FormatUint(v.Uint(), 10), nil
+
+ case reflect.Float32, reflect.Float64:
+ f := v.Float()
+ if math.IsInf(f, 0) || math.IsNaN(f) {
+ return "", fmt.Errorf("UnsupportedValueError %#v (formatted float: %s)", v, strconv.FormatFloat(f, 'g', -1, v.Type().Bits()))
+ }
+ return strconv.FormatFloat(f, 'g', -1, v.Type().Bits()), nil
+ }
+ return "", fmt.Errorf("UnsupportedNumericValueError %#v", v.Type())
+}
+
+// In DynamoDB we should omit empty value in some type
+// See http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html
+func isEmptyValueToOmit(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String, reflect.Interface, reflect.Ptr:
+ // should omit if empty value
+ return isEmptyValue(v)
+ }
+ // otherwise should not omit
+ return false
+}
+
+// ---------------- Below are copied handy functions from http://golang.org/src/pkg/encoding/json/encode.go --------------------------------
+func isEmptyValue(v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
+ return v.Len() == 0
+ case reflect.Bool:
+ return !v.Bool()
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ return v.Int() == 0
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+ return v.Uint() == 0
+ case reflect.Float32, reflect.Float64:
+ return v.Float() == 0
+ case reflect.Interface, reflect.Ptr:
+ return v.IsNil()
+ }
+ return false
+}
+
+func fieldByIndex(v reflect.Value, index []int) reflect.Value {
+ for _, i := range index {
+ if v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ return reflect.Value{}
+ }
+ v = v.Elem()
+ }
+ v = v.Field(i)
+ }
+ return v
+}
+
+// A field represents a single field found in a struct.
+type field struct {
+ name string
+ tag bool
+ index []int
+ typ reflect.Type
+ omitEmpty bool
+ quoted bool
+}
+
+// byName sorts field by name, breaking ties with depth,
+// then breaking ties with "name came from json tag", then
+// breaking ties with index sequence.
+type byName []field
+
+func (x byName) Len() int { return len(x) }
+
+func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+func (x byName) Less(i, j int) bool {
+ if x[i].name != x[j].name {
+ return x[i].name < x[j].name
+ }
+ if len(x[i].index) != len(x[j].index) {
+ return len(x[i].index) < len(x[j].index)
+ }
+ if x[i].tag != x[j].tag {
+ return x[i].tag
+ }
+ return byIndex(x).Less(i, j)
+}
+
+// byIndex sorts field by index sequence.
+type byIndex []field
+
+func (x byIndex) Len() int { return len(x) }
+
+func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+
+func (x byIndex) Less(i, j int) bool {
+ for k, xik := range x[i].index {
+ if k >= len(x[j].index) {
+ return false
+ }
+ if xik != x[j].index[k] {
+ return xik < x[j].index[k]
+ }
+ }
+ return len(x[i].index) < len(x[j].index)
+}
+
+func isValidTag(s string) bool {
+ if s == "" {
+ return false
+ }
+ for _, c := range s {
+ switch {
+ case strings.ContainsRune("!#$%&()*+-./:<=>?@[]^_{|}~ ", c):
+ // Backslash and quote chars are reserved, but
+ // otherwise any punctuation chars are allowed
+ // in a tag name.
+ default:
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// tagOptions is the string following a comma in a struct field's "json"
+// tag, or the empty string. It does not include the leading comma.
+type tagOptions string
+
+// Contains returns whether checks that a comma-separated list of options
+// contains a particular substr flag. substr must be surrounded by a
+// string boundary or commas.
+func (o tagOptions) Contains(optionName string) bool {
+ if len(o) == 0 {
+ return false
+ }
+ s := string(o)
+ for s != "" {
+ var next string
+ i := strings.Index(s, ",")
+ if i >= 0 {
+ s, next = s[:i], s[i+1:]
+ }
+ if s == optionName {
+ return true
+ }
+ s = next
+ }
+ return false
+}
+
+// parseTag splits a struct field's json tag into its name and
+// comma-separated options.
+func parseTag(tag string) (string, tagOptions) {
+ if idx := strings.Index(tag, ","); idx != -1 {
+ return tag[:idx], tagOptions(tag[idx+1:])
+ }
+ return tag, tagOptions("")
+}
+
+// typeFields returns a list of fields that JSON should recognize for the given type.
+// The algorithm is breadth-first search over the set of structs to include - the top struct
+// and then any reachable anonymous structs.
+func typeFields(t reflect.Type) []field {
+ // Anonymous fields to explore at the current level and the next.
+ current := []field{}
+ next := []field{{typ: t}}
+
+ // Count of queued names for current level and the next.
+ count := map[reflect.Type]int{}
+ nextCount := map[reflect.Type]int{}
+
+ // Types already visited at an earlier level.
+ visited := map[reflect.Type]bool{}
+
+ // Fields found.
+ var fields []field
+
+ for len(next) > 0 {
+ current, next = next, current[:0]
+ count, nextCount = nextCount, map[reflect.Type]int{}
+
+ for _, f := range current {
+ if visited[f.typ] {
+ continue
+ }
+ visited[f.typ] = true
+
+ // Scan f.typ for fields to include.
+ for i := 0; i < f.typ.NumField(); i++ {
+ sf := f.typ.Field(i)
+ if sf.PkgPath != "" { // unexported
+ continue
+ }
+ tag := sf.Tag.Get("json")
+ if tag == "-" {
+ continue
+ }
+ name, opts := parseTag(tag)
+ if !isValidTag(name) {
+ name = ""
+ }
+ index := make([]int, len(f.index)+1)
+ copy(index, f.index)
+ index[len(f.index)] = i
+
+ ft := sf.Type
+ if ft.Name() == "" && ft.Kind() == reflect.Ptr {
+ // Follow pointer.
+ ft = ft.Elem()
+ }
+
+ // Record found field and index sequence.
+ if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
+ tagged := name != ""
+ if name == "" {
+ name = sf.Name
+ }
+ fields = append(fields, field{name, tagged, index, ft,
+ opts.Contains("omitempty"), opts.Contains("string")})
+ if count[f.typ] > 1 {
+ // If there were multiple instances, add a second,
+ // so that the annihilation code will see a duplicate.
+ // It only cares about the distinction between 1 or 2,
+ // so don't bother generating any more copies.
+ fields = append(fields, fields[len(fields)-1])
+ }
+ continue
+ }
+
+ // Record new anonymous struct to explore in next round.
+ nextCount[ft]++
+ if nextCount[ft] == 1 {
+ next = append(next, field{name: ft.Name(), index: index, typ: ft})
+ }
+ }
+ }
+ }
+
+ sort.Sort(byName(fields))
+
+ // Delete all fields that are hidden by the Go rules for embedded fields,
+ // except that fields with JSON tags are promoted.
+
+ // The fields are sorted in primary order of name, secondary order
+ // of field index length. Loop over names; for each name, delete
+ // hidden fields by choosing the one dominant field that survives.
+ out := fields[:0]
+ for advance, i := 0, 0; i < len(fields); i += advance {
+ // One iteration per name.
+ // Find the sequence of fields with the name of this first field.
+ fi := fields[i]
+ name := fi.name
+ for advance = 1; i+advance < len(fields); advance++ {
+ fj := fields[i+advance]
+ if fj.name != name {
+ break
+ }
+ }
+ if advance == 1 { // Only one field with this name
+ out = append(out, fi)
+ continue
+ }
+ dominant, ok := dominantField(fields[i : i+advance])
+ if ok {
+ out = append(out, dominant)
+ }
+ }
+
+ fields = out
+ sort.Sort(byIndex(fields))
+
+ return fields
+}
+
+// dominantField looks through the fields, all of which are known to
+// have the same name, to find the single field that dominates the
+// others using Go's embedding rules, modified by the presence of
+// JSON tags. If there are multiple top-level fields, the boolean
+// will be false: This condition is an error in Go and we skip all
+// the fields.
+func dominantField(fields []field) (field, bool) {
+ // The fields are sorted in increasing index-length order. The winner
+ // must therefore be one with the shortest index length. Drop all
+ // longer entries, which is easy: just truncate the slice.
+ length := len(fields[0].index)
+ tagged := -1 // Index of first tagged field.
+ for i, f := range fields {
+ if len(f.index) > length {
+ fields = fields[:i]
+ break
+ }
+ if f.tag {
+ if tagged >= 0 {
+ // Multiple tagged fields at the same level: conflict.
+ // Return no field.
+ return field{}, false
+ }
+ tagged = i
+ }
+ }
+ if tagged >= 0 {
+ return fields[tagged], true
+ }
+ // All remaining fields have the same length. If there's more than one,
+ // we have a conflict (two fields named "X" at the same level) and we
+ // return no field.
+ if len(fields) > 1 {
+ return field{}, false
+ }
+ return fields[0], true
+}
+
+var fieldCache struct {
+ sync.RWMutex
+ m map[reflect.Type][]field
+}
+
+// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
+func cachedTypeFields(t reflect.Type) []field {
+ fieldCache.RLock()
+ f := fieldCache.m[t]
+ fieldCache.RUnlock()
+ if f != nil {
+ return f
+ }
+
+ // Compute fields without lock.
+ // Might duplicate effort but won't hold other computations back.
+ f = typeFields(t)
+ if f == nil {
+ f = []field{}
+ }
+
+ fieldCache.Lock()
+ if fieldCache.m == nil {
+ fieldCache.m = map[reflect.Type][]field{}
+ }
+ fieldCache.m[t] = f
+ fieldCache.Unlock()
+ return f
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/marshaller_test.go b/vendor/github.com/goamz/goamz/dynamodb/marshaller_test.go
new file mode 100644
index 000000000..8b9d2fc08
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/marshaller_test.go
@@ -0,0 +1,283 @@
+package dynamodb_test
+
+import (
+ "time"
+
+ "github.com/goamz/goamz/dynamodb"
+ . "gopkg.in/check.v1"
+)
+
+type TestSubStruct struct {
+ SubBool bool
+ SubInt int
+ SubString string
+ SubStringArray []string
+}
+
+type TestStruct struct {
+ TestBool bool
+ TestInt int
+ TestInt32 int32
+ TestInt64 int64
+ TestUint uint
+ TestFloat32 float32
+ TestFloat64 float64
+ TestString string
+ TestByteArray []byte
+ TestStringArray []string
+ TestIntArray []int
+ TestInt8Array []int8
+ TestFloatArray []float64
+ TestSub TestSubStruct
+}
+
+type TestStructTime struct {
+ TestTime time.Time
+}
+
+func testObject() *TestStruct {
+ return &TestStruct{
+ TestBool: true,
+ TestInt: -99,
+ TestInt32: 999,
+ TestInt64: 9999,
+ TestUint: 99,
+ TestFloat32: 9.9999,
+ TestFloat64: 99.999999,
+ TestString: "test",
+ TestByteArray: []byte("bytes"),
+ TestStringArray: []string{"test1", "test2", "test3", "test4"},
+ TestIntArray: []int{0, 1, 12, 123, 1234, 12345},
+ TestInt8Array: []int8{0, 1, 12, 123},
+ TestFloatArray: []float64{0.1, 1.1, 1.2, 1.23, 1.234, 1.2345},
+ TestSub: TestSubStruct{
+ SubBool: true,
+ SubInt: 2,
+ SubString: "subtest",
+ SubStringArray: []string{"sub1", "sub2", "sub3"},
+ },
+ }
+}
+
+func testObjectTime() *TestStructTime {
+ t, _ := time.Parse("Jan 2, 2006 at 3:04pm", "Mar 3, 2003 at 5:03pm")
+ return &TestStructTime{
+ TestTime: t,
+ }
+}
+
+func testObjectWithZeroValues() *TestStruct {
+ return &TestStruct{}
+}
+
+func testObjectWithNilSets() *TestStruct {
+ return &TestStruct{
+ TestBool: true,
+ TestInt: -99,
+ TestInt32: 999,
+ TestInt64: 9999,
+ TestUint: 99,
+ TestFloat32: 9.9999,
+ TestFloat64: 99.999999,
+ TestString: "test",
+ TestByteArray: []byte("bytes"),
+ TestStringArray: []string(nil),
+ TestIntArray: []int(nil),
+ TestFloatArray: []float64(nil),
+ TestSub: TestSubStruct{
+ SubBool: true,
+ SubInt: 2,
+ SubString: "subtest",
+ SubStringArray: []string{"sub1", "sub2", "sub3"},
+ },
+ }
+}
+func testObjectWithEmptySets() *TestStruct {
+ return &TestStruct{
+ TestBool: true,
+ TestInt: -99,
+ TestInt32: 999,
+ TestInt64: 9999,
+ TestUint: 99,
+ TestFloat32: 9.9999,
+ TestFloat64: 99.999999,
+ TestString: "test",
+ TestByteArray: []byte("bytes"),
+ TestStringArray: []string{},
+ TestIntArray: []int{},
+ TestFloatArray: []float64{},
+ TestSub: TestSubStruct{
+ SubBool: true,
+ SubInt: 2,
+ SubString: "subtest",
+ SubStringArray: []string{"sub1", "sub2", "sub3"},
+ },
+ }
+}
+
+func testAttrs() []dynamodb.Attribute {
+ return []dynamodb.Attribute{
+ dynamodb.Attribute{Type: "N", Name: "TestBool", Value: "1", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt", Value: "-99", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt32", Value: "999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt64", Value: "9999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestUint", Value: "99", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestFloat32", Value: "9.9999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestFloat64", Value: "99.999999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "S", Name: "TestString", Value: "test", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "S", Name: "TestByteArray", Value: "Ynl0ZXM=", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "SS", Name: "TestStringArray", Value: "", SetValues: []string{"test1", "test2", "test3", "test4"}},
+ dynamodb.Attribute{Type: "NS", Name: "TestIntArray", Value: "", SetValues: []string{"0", "1", "12", "123", "1234", "12345"}},
+ dynamodb.Attribute{Type: "NS", Name: "TestInt8Array", Value: "", SetValues: []string{"0", "1", "12", "123"}},
+ dynamodb.Attribute{Type: "NS", Name: "TestFloatArray", Value: "", SetValues: []string{"0.1", "1.1", "1.2", "1.23", "1.234", "1.2345"}},
+ dynamodb.Attribute{Type: "S", Name: "TestSub", Value: `{"SubBool":true,"SubInt":2,"SubString":"subtest","SubStringArray":["sub1","sub2","sub3"]}`, SetValues: []string(nil)},
+ }
+}
+
+func testAttrsTime() []dynamodb.Attribute {
+ return []dynamodb.Attribute{
+ dynamodb.Attribute{Type: "S", Name: "TestTime", Value: "\"2003-03-03T17:03:00Z\"", SetValues: []string(nil)},
+ }
+}
+
+func testAttrsWithZeroValues() []dynamodb.Attribute {
+ return []dynamodb.Attribute{
+ dynamodb.Attribute{Type: "N", Name: "TestBool", Value: "0", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt", Value: "0", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt32", Value: "0", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt64", Value: "0", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestUint", Value: "0", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestFloat32", Value: "0", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestFloat64", Value: "0", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "S", Name: "TestSub", Value: `{"SubBool":false,"SubInt":0,"SubString":"","SubStringArray":null}`, SetValues: []string(nil)},
+ }
+}
+
+func testAttrsWithNilSets() []dynamodb.Attribute {
+ return []dynamodb.Attribute{
+ dynamodb.Attribute{Type: "N", Name: "TestBool", Value: "1", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt", Value: "-99", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt32", Value: "999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestInt64", Value: "9999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestUint", Value: "99", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestFloat32", Value: "9.9999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "N", Name: "TestFloat64", Value: "99.999999", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "S", Name: "TestString", Value: "test", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "S", Name: "TestByteArray", Value: "Ynl0ZXM=", SetValues: []string(nil)},
+ dynamodb.Attribute{Type: "S", Name: "TestSub", Value: `{"SubBool":true,"SubInt":2,"SubString":"subtest","SubStringArray":["sub1","sub2","sub3"]}`, SetValues: []string(nil)},
+ }
+}
+
+type MarshallerSuite struct {
+}
+
+var _ = Suite(&MarshallerSuite{})
+
+func (s *MarshallerSuite) TestMarshal(c *C) {
+ testObj := testObject()
+ attrs, err := dynamodb.MarshalAttributes(testObj)
+ if err != nil {
+ c.Errorf("Error from dynamodb.MarshalAttributes: %#v", err)
+ }
+
+ expected := testAttrs()
+ c.Check(attrs, DeepEquals, expected)
+}
+
+func (s *MarshallerSuite) TestUnmarshal(c *C) {
+ testObj := &TestStruct{}
+
+ attrMap := map[string]*dynamodb.Attribute{}
+ attrs := testAttrs()
+ for i, _ := range attrs {
+ attrMap[attrs[i].Name] = &attrs[i]
+ }
+
+ err := dynamodb.UnmarshalAttributes(&attrMap, testObj)
+ if err != nil {
+ c.Fatalf("Error from dynamodb.UnmarshalAttributes: %#v (Built: %#v)", err, testObj)
+ }
+
+ expected := testObject()
+ c.Check(testObj, DeepEquals, expected)
+}
+
+func (s *MarshallerSuite) TestMarshalTime(c *C) {
+ testObj := testObjectTime()
+ attrs, err := dynamodb.MarshalAttributes(testObj)
+ if err != nil {
+ c.Errorf("Error from dynamodb.MarshalAttributes: %#v", err)
+ }
+
+ expected := testAttrsTime()
+ c.Check(attrs, DeepEquals, expected)
+}
+
+func (s *MarshallerSuite) TestUnmarshalTime(c *C) {
+ testObj := &TestStructTime{}
+
+ attrMap := map[string]*dynamodb.Attribute{}
+ attrs := testAttrsTime()
+ for i, _ := range attrs {
+ attrMap[attrs[i].Name] = &attrs[i]
+ }
+
+ err := dynamodb.UnmarshalAttributes(&attrMap, testObj)
+ if err != nil {
+ c.Fatalf("Error from dynamodb.UnmarshalAttributes: %#v (Built: %#v)", err, testObj)
+ }
+
+ expected := testObjectTime()
+ c.Check(testObj, DeepEquals, expected)
+}
+
+func (s *MarshallerSuite) TestMarshalNilSets(c *C) {
+ testObj := testObjectWithNilSets()
+ attrs, err := dynamodb.MarshalAttributes(testObj)
+ if err != nil {
+ c.Errorf("Error from dynamodb.MarshalAttributes: %#v", err)
+ }
+
+ expected := testAttrsWithNilSets()
+ c.Check(attrs, DeepEquals, expected)
+}
+
+func (s *MarshallerSuite) TestMarshalZeroValues(c *C) {
+ testObj := testObjectWithZeroValues()
+ attrs, err := dynamodb.MarshalAttributes(testObj)
+ if err != nil {
+ c.Errorf("Error from dynamodb.MarshalAttributes: %#v", err)
+ }
+
+ expected := testAttrsWithZeroValues()
+ c.Check(attrs, DeepEquals, expected)
+}
+
+func (s *MarshallerSuite) TestMarshalEmptySets(c *C) {
+ testObj := testObjectWithEmptySets()
+ attrs, err := dynamodb.MarshalAttributes(testObj)
+ if err != nil {
+ c.Errorf("Error from dynamodb.MarshalAttributes: %#v", err)
+ }
+
+ expected := testAttrsWithNilSets()
+ c.Check(attrs, DeepEquals, expected)
+}
+
+func (s *MarshallerSuite) TestUnmarshalEmptySets(c *C) {
+ testObj := &TestStruct{}
+
+ attrMap := map[string]*dynamodb.Attribute{}
+ attrs := testAttrsWithNilSets()
+ for i, _ := range attrs {
+ attrMap[attrs[i].Name] = &attrs[i]
+ }
+
+ err := dynamodb.UnmarshalAttributes(&attrMap, testObj)
+ if err != nil {
+ c.Fatalf("Error from dynamodb.UnmarshalAttributes: %#v (Built: %#v)", err, testObj)
+ }
+
+ expected := testObjectWithNilSets()
+ c.Check(testObj, DeepEquals, expected)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/query.go b/vendor/github.com/goamz/goamz/dynamodb/query.go
new file mode 100644
index 000000000..453e38733
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/query.go
@@ -0,0 +1,111 @@
+package dynamodb
+
+import (
+ "errors"
+ "fmt"
+ simplejson "github.com/bitly/go-simplejson"
+)
+
+func (t *Table) Query(attributeComparisons []AttributeComparison) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ return runQuery(q, t)
+}
+
+func (t *Table) QueryOnIndex(attributeComparisons []AttributeComparison, indexName string) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ q.AddIndex(indexName)
+ return runQuery(q, t)
+}
+
+func (t *Table) QueryOnIndexDescending(attributeComparisons []AttributeComparison, indexName string) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ q.AddIndex(indexName)
+ q.ScanIndexDescending()
+ return runQuery(q, t)
+}
+
+func (t *Table) LimitedQuery(attributeComparisons []AttributeComparison, limit int64) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ q.AddLimit(limit)
+ return runQuery(q, t)
+}
+
+func (t *Table) LimitedQueryOnIndex(attributeComparisons []AttributeComparison, indexName string, limit int64) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ q.AddIndex(indexName)
+ q.AddLimit(limit)
+ return runQuery(q, t)
+}
+
+func (t *Table) LimitedQueryDescending(attributeComparisons []AttributeComparison, limit int64) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ q.AddLimit(limit)
+ q.ScanIndexDescending()
+ return runQuery(q, t)
+}
+
+func (t *Table) LimitedQueryOnIndexDescending(attributeComparisons []AttributeComparison, indexName string, limit int64) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ q.AddIndex(indexName)
+ q.AddLimit(limit)
+ q.ScanIndexDescending()
+ return runQuery(q, t)
+}
+
+func (t *Table) CountQuery(attributeComparisons []AttributeComparison) (int64, error) {
+ q := NewQuery(t)
+ q.AddKeyConditions(attributeComparisons)
+ q.AddSelect("COUNT")
+ jsonResponse, err := t.Server.queryServer("DynamoDB_20120810.Query", q)
+ if err != nil {
+ return 0, err
+ }
+ json, err := simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return 0, err
+ }
+
+ itemCount, err := json.Get("Count").Int64()
+ if err != nil {
+ return 0, err
+ }
+
+ return itemCount, nil
+}
+
+func runQuery(q *Query, t *Table) ([]map[string]*Attribute, error) {
+ jsonResponse, err := t.Server.queryServer("DynamoDB_20120810.Query", q)
+ if err != nil {
+ return nil, err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ itemCount, err := json.Get("Count").Int()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ results := make([]map[string]*Attribute, itemCount)
+
+ for i, _ := range results {
+ item, err := json.Get("Items").GetIndex(i).Map()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+ results[i] = parseAttributes(item)
+ }
+ return results, nil
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/query_builder.go b/vendor/github.com/goamz/goamz/dynamodb/query_builder.go
new file mode 100644
index 000000000..47a90bb1c
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/query_builder.go
@@ -0,0 +1,362 @@
+package dynamodb
+
+import (
+ "encoding/json"
+ "sort"
+)
+
+type msi map[string]interface{}
+type Query struct {
+ buffer msi
+}
+
+func NewEmptyQuery() *Query {
+ return &Query{msi{}}
+}
+
+func NewQuery(t *Table) *Query {
+ q := &Query{msi{}}
+ q.addTable(t)
+ return q
+}
+
+// This way of specifing the key is used when doing a Get.
+// If rangeKey is "", it is assumed to not want to be used
+func (q *Query) AddKey(t *Table, key *Key) {
+ k := t.Key
+ keymap := msi{
+ k.KeyAttribute.Name: msi{
+ k.KeyAttribute.Type: key.HashKey},
+ }
+ if k.HasRange() {
+ keymap[k.RangeAttribute.Name] = msi{k.RangeAttribute.Type: key.RangeKey}
+ }
+
+ q.buffer["Key"] = keymap
+}
+
+func keyAttributes(t *Table, key *Key) msi {
+ k := t.Key
+
+ out := msi{}
+ out[k.KeyAttribute.Name] = msi{k.KeyAttribute.Type: key.HashKey}
+ if k.HasRange() {
+ out[k.RangeAttribute.Name] = msi{k.RangeAttribute.Type: key.RangeKey}
+ }
+ return out
+}
+
+func (q *Query) AddAttributesToGet(attributes []string) {
+ if len(attributes) == 0 {
+ return
+ }
+
+ q.buffer["AttributesToGet"] = attributes
+}
+
+func (q *Query) ConsistentRead(c bool) {
+ if c == true {
+ q.buffer["ConsistentRead"] = "true" //String "true", not bool true
+ }
+}
+
+func (q *Query) AddGetRequestItems(tableKeys map[*Table][]Key) {
+ requestitems := msi{}
+ for table, keys := range tableKeys {
+ keyslist := []msi{}
+ for _, key := range keys {
+ keyslist = append(keyslist, keyAttributes(table, &key))
+ }
+ requestitems[table.Name] = msi{"Keys": keyslist}
+ }
+ q.buffer["RequestItems"] = requestitems
+}
+
+func (q *Query) AddWriteRequestItems(tableItems map[*Table]map[string][][]Attribute) {
+ b := q.buffer
+
+ b["RequestItems"] = func() msi {
+ out := msi{}
+ for table, itemActions := range tableItems {
+ out[table.Name] = func() interface{} {
+ out2 := []interface{}{}
+
+ // here breaks an order of array....
+ // For now, we iterate over sorted key by action for stable testing
+ keys := []string{}
+ for k := range itemActions {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+
+ for ki := range keys {
+ action := keys[ki]
+ items := itemActions[action]
+ for _, attributes := range items {
+ Item_or_Key := map[bool]string{true: "Item", false: "Key"}[action == "Put"]
+ out2 = append(out2, msi{action + "Request": msi{Item_or_Key: attributeList(attributes)}})
+ }
+ }
+ return out2
+ }()
+ }
+ return out
+ }()
+}
+
+func (q *Query) AddCreateRequestTable(description TableDescriptionT) {
+ b := q.buffer
+
+ attDefs := []interface{}{}
+ for _, attr := range description.AttributeDefinitions {
+ attDefs = append(attDefs, msi{
+ "AttributeName": attr.Name,
+ "AttributeType": attr.Type,
+ })
+ }
+ b["AttributeDefinitions"] = attDefs
+ b["KeySchema"] = description.KeySchema
+ b["TableName"] = description.TableName
+ b["ProvisionedThroughput"] = msi{
+ "ReadCapacityUnits": int(description.ProvisionedThroughput.ReadCapacityUnits),
+ "WriteCapacityUnits": int(description.ProvisionedThroughput.WriteCapacityUnits),
+ }
+
+ if description.StreamSpecification.StreamEnabled {
+ b["StreamSpecification"] = msi{
+ "StreamEnabled": "true",
+ "StreamViewType": description.StreamSpecification.StreamViewType,
+ }
+ }
+
+ localSecondaryIndexes := []interface{}{}
+
+ for _, ind := range description.LocalSecondaryIndexes {
+ localSecondaryIndexes = append(localSecondaryIndexes, msi{
+ "IndexName": ind.IndexName,
+ "KeySchema": ind.KeySchema,
+ "Projection": ind.Projection,
+ })
+ }
+
+ globalSecondaryIndexes := []interface{}{}
+ intmax := func(x, y int64) int64 {
+ if x > y {
+ return x
+ }
+ return y
+ }
+ for _, ind := range description.GlobalSecondaryIndexes {
+ rec := msi{
+ "IndexName": ind.IndexName,
+ "KeySchema": ind.KeySchema,
+ "Projection": ind.Projection,
+ }
+ // need at least one unit, and since go's max() is float based.
+ rec["ProvisionedThroughput"] = msi{
+ "ReadCapacityUnits": intmax(1, ind.ProvisionedThroughput.ReadCapacityUnits),
+ "WriteCapacityUnits": intmax(1, ind.ProvisionedThroughput.WriteCapacityUnits),
+ }
+ globalSecondaryIndexes = append(globalSecondaryIndexes, rec)
+ }
+
+ if len(localSecondaryIndexes) > 0 {
+ b["LocalSecondaryIndexes"] = localSecondaryIndexes
+ }
+
+ if len(globalSecondaryIndexes) > 0 {
+ b["GlobalSecondaryIndexes"] = globalSecondaryIndexes
+ }
+}
+
+func (q *Query) AddDeleteRequestTable(description TableDescriptionT) {
+ b := q.buffer
+ b["TableName"] = description.TableName
+}
+
+func (q *Query) AddUpdateRequestTable(description TableDescriptionT) {
+ b := q.buffer
+
+ attDefs := []interface{}{}
+ for _, attr := range description.AttributeDefinitions {
+ attDefs = append(attDefs, msi{
+ "AttributeName": attr.Name,
+ "AttributeType": attr.Type,
+ })
+ }
+ if len(attDefs) > 0 {
+ b["AttributeDefinitions"] = attDefs
+ }
+ b["TableName"] = description.TableName
+ b["ProvisionedThroughput"] = msi{
+ "ReadCapacityUnits": int(description.ProvisionedThroughput.ReadCapacityUnits),
+ "WriteCapacityUnits": int(description.ProvisionedThroughput.WriteCapacityUnits),
+ }
+
+}
+
+func (q *Query) AddKeyConditions(comparisons []AttributeComparison) {
+ q.buffer["KeyConditions"] = buildComparisons(comparisons)
+}
+
+func (q *Query) AddLimit(limit int64) {
+ q.buffer["Limit"] = limit
+}
+func (q *Query) AddSelect(value string) {
+ q.buffer["Select"] = value
+}
+
+func (q *Query) AddIndex(value string) {
+ q.buffer["IndexName"] = value
+}
+
+func (q *Query) ScanIndexDescending() {
+ q.buffer["ScanIndexForward"] = "false"
+}
+
+/*
+ "ScanFilter":{
+ "AttributeName1":{"AttributeValueList":[{"S":"AttributeValue"}],"ComparisonOperator":"EQ"}
+ },
+*/
+func (q *Query) AddScanFilter(comparisons []AttributeComparison) {
+ q.buffer["ScanFilter"] = buildComparisons(comparisons)
+}
+
+func (q *Query) AddParallelScanConfiguration(segment int, totalSegments int) {
+ q.buffer["Segment"] = segment
+ q.buffer["TotalSegments"] = totalSegments
+}
+
+func buildComparisons(comparisons []AttributeComparison) msi {
+ out := msi{}
+
+ for _, c := range comparisons {
+ avlist := []interface{}{}
+ for _, attributeValue := range c.AttributeValueList {
+ avlist = append(avlist, msi{attributeValue.Type: attributeValue.Value})
+ }
+ out[c.AttributeName] = msi{
+ "AttributeValueList": avlist,
+ "ComparisonOperator": c.ComparisonOperator,
+ }
+ }
+
+ return out
+}
+
+// The primary key must be included in attributes.
+func (q *Query) AddItem(attributes []Attribute) {
+ q.buffer["Item"] = attributeList(attributes)
+}
+
+func (q *Query) AddUpdates(attributes []Attribute, action string) {
+ updates := msi{}
+ for _, a := range attributes {
+ au := msi{
+ "Value": msi{
+ a.Type: map[bool]interface{}{true: a.SetValues, false: a.Value}[a.SetType()],
+ },
+ "Action": action,
+ }
+ // Delete 'Value' from AttributeUpdates if Type is not Set
+ if action == "DELETE" && !a.SetType() {
+ delete(au, "Value")
+ }
+ updates[a.Name] = au
+ }
+
+ q.buffer["AttributeUpdates"] = updates
+}
+
+func (q *Query) AddExpected(attributes []Attribute) {
+ expected := msi{}
+ for _, a := range attributes {
+ value := msi{}
+ if a.Exists != "" {
+ value["Exists"] = a.Exists
+ }
+ // If set Exists to false, we must remove Value
+ if value["Exists"] != "false" {
+ value["Value"] = msi{a.Type: map[bool]interface{}{true: a.SetValues, false: a.Value}[a.SetType()]}
+ }
+ expected[a.Name] = value
+ }
+ q.buffer["Expected"] = expected
+}
+
+// Add the ReturnValues parameter, used in UpdateItem queries.
+func (q *Query) AddReturnValues(returnValues ReturnValues) {
+ q.buffer["ReturnValues"] = string(returnValues)
+}
+
+// Add the UpdateExpression parameter, used in UpdateItem queries.
+func (q *Query) AddUpdateExpression(expression string) {
+ q.buffer["UpdateExpression"] = expression
+}
+
+// Add the ConditionExpression parameter, used in UpdateItem queries.
+func (q *Query) AddConditionExpression(expression string) {
+ q.buffer["ConditionExpression"] = expression
+}
+
+func (q *Query) AddExpressionAttributes(attributes []Attribute) {
+ existing, ok := q.buffer["ExpressionAttributes"].(msi)
+ if !ok {
+ existing = msi{}
+ q.buffer["ExpressionAttributes"] = existing
+ }
+ for key, val := range attributeList(attributes) {
+ existing[key] = val
+ }
+}
+
+func (q *Query) AddExclusiveStartStreamArn(arn string) {
+ q.buffer["ExclusiveStartStreamArn"] = arn
+}
+
+func (q *Query) AddStreamArn(arn string) {
+ q.buffer["StreamArn"] = arn
+}
+
+func (q *Query) AddExclusiveStartShardId(shardId string) {
+ q.buffer["ExclusiveStartShardId"] = shardId
+}
+
+func (q *Query) AddShardId(shardId string) {
+ q.buffer["ShardId"] = shardId
+}
+
+func (q *Query) AddShardIteratorType(shardIteratorType string) {
+ q.buffer["ShardIteratorType"] = shardIteratorType
+}
+
+func (q *Query) AddSequenceNumber(sequenceNumber string) {
+ q.buffer["SequenceNumber"] = sequenceNumber
+}
+
+func (q *Query) AddShardIterator(shardIterator string) {
+ q.buffer["ShardIterator"] = shardIterator
+}
+
+func attributeList(attributes []Attribute) msi {
+ b := msi{}
+ for _, a := range attributes {
+ //UGH!! (I miss the query operator)
+ b[a.Name] = msi{a.Type: map[bool]interface{}{true: a.SetValues, false: a.Value}[a.SetType()]}
+ }
+ return b
+}
+
+func (q *Query) addTable(t *Table) {
+ q.addTableByName(t.Name)
+}
+
+func (q *Query) addTableByName(tableName string) {
+ q.buffer["TableName"] = tableName
+}
+
+func (q *Query) String() string {
+ bytes, _ := json.Marshal(q.buffer)
+ return string(bytes)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/query_builder_test.go b/vendor/github.com/goamz/goamz/dynamodb/query_builder_test.go
new file mode 100755
index 000000000..9a1f6f2c5
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/query_builder_test.go
@@ -0,0 +1,380 @@
+package dynamodb_test
+
+import (
+ simplejson "github.com/bitly/go-simplejson"
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/dynamodb"
+ . "gopkg.in/check.v1"
+)
+
+type QueryBuilderSuite struct {
+ server *dynamodb.Server
+}
+
+var _ = Suite(&QueryBuilderSuite{})
+
+func (s *QueryBuilderSuite) SetUpSuite(c *C) {
+ auth := &aws.Auth{AccessKey: "", SecretKey: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"}
+ s.server = &dynamodb.Server{*auth, aws.USEast}
+}
+
+func (s *QueryBuilderSuite) TestEmptyQuery(c *C) {
+ q := dynamodb.NewEmptyQuery()
+ queryString := q.String()
+ expectedString := "{}"
+ c.Check(queryString, Equals, expectedString)
+
+ if expectedString != queryString {
+ c.Fatalf("Unexpected Query String : %s\n", queryString)
+ }
+}
+
+func (s *QueryBuilderSuite) TestAddWriteRequestItems(c *C) {
+ primary := dynamodb.NewStringAttribute("WidgetFoo", "")
+ secondary := dynamodb.NewNumericAttribute("Created", "")
+ key := dynamodb.PrimaryKey{primary, secondary}
+ table := s.server.NewTable("FooData", key)
+
+ primary2 := dynamodb.NewStringAttribute("TestHashKey", "")
+ secondary2 := dynamodb.NewNumericAttribute("TestRangeKey", "")
+ key2 := dynamodb.PrimaryKey{primary2, secondary2}
+ table2 := s.server.NewTable("TestTable", key2)
+
+ q := dynamodb.NewEmptyQuery()
+
+ attribute1 := dynamodb.NewNumericAttribute("testing", "4")
+ attribute2 := dynamodb.NewNumericAttribute("testingbatch", "2111")
+ attribute3 := dynamodb.NewStringAttribute("testingstrbatch", "mystr")
+ item1 := []dynamodb.Attribute{*attribute1, *attribute2, *attribute3}
+
+ attribute4 := dynamodb.NewNumericAttribute("testing", "444")
+ attribute5 := dynamodb.NewNumericAttribute("testingbatch", "93748249272")
+ attribute6 := dynamodb.NewStringAttribute("testingstrbatch", "myotherstr")
+ item2 := []dynamodb.Attribute{*attribute4, *attribute5, *attribute6}
+
+ attributeDel1 := dynamodb.NewStringAttribute("TestHashKeyDel", "DelKey")
+ attributeDel2 := dynamodb.NewNumericAttribute("TestRangeKeyDel", "7777777")
+ itemDel := []dynamodb.Attribute{*attributeDel1, *attributeDel2}
+
+ attributeTest1 := dynamodb.NewStringAttribute("TestHashKey", "MyKey")
+ attributeTest2 := dynamodb.NewNumericAttribute("TestRangeKey", "0193820384293")
+ itemTest := []dynamodb.Attribute{*attributeTest1, *attributeTest2}
+
+ tableItems := map[*dynamodb.Table]map[string][][]dynamodb.Attribute{}
+ actionItems := make(map[string][][]dynamodb.Attribute)
+ actionItems["Put"] = [][]dynamodb.Attribute{item1, item2}
+ actionItems["Delete"] = [][]dynamodb.Attribute{itemDel}
+ tableItems[table] = actionItems
+
+ actionItems2 := make(map[string][][]dynamodb.Attribute)
+ actionItems2["Put"] = [][]dynamodb.Attribute{itemTest}
+ tableItems[table2] = actionItems2
+
+ q.AddWriteRequestItems(tableItems)
+
+ queryJson, err := simplejson.NewJson([]byte(q.String()))
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ expectedJson, err := simplejson.NewJson([]byte(`
+{
+ "RequestItems": {
+ "TestTable": [
+ {
+ "PutRequest": {
+ "Item": {
+ "TestRangeKey": {
+ "N": "0193820384293"
+ },
+ "TestHashKey": {
+ "S": "MyKey"
+ }
+ }
+ }
+ }
+ ],
+ "FooData": [
+ {
+ "DeleteRequest": {
+ "Key": {
+ "TestRangeKeyDel": {
+ "N": "7777777"
+ },
+ "TestHashKeyDel": {
+ "S": "DelKey"
+ }
+ }
+ }
+ },
+ {
+ "PutRequest": {
+ "Item": {
+ "testingstrbatch": {
+ "S": "mystr"
+ },
+ "testingbatch": {
+ "N": "2111"
+ },
+ "testing": {
+ "N": "4"
+ }
+ }
+ }
+ },
+ {
+ "PutRequest": {
+ "Item": {
+ "testingstrbatch": {
+ "S": "myotherstr"
+ },
+ "testingbatch": {
+ "N": "93748249272"
+ },
+ "testing": {
+ "N": "444"
+ }
+ }
+ }
+ }
+ ]
+ }
+}
+ `))
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(queryJson, DeepEquals, expectedJson)
+}
+
+func (s *QueryBuilderSuite) TestAddExpectedQuery(c *C) {
+ primary := dynamodb.NewStringAttribute("domain", "")
+ key := dynamodb.PrimaryKey{primary, nil}
+ table := s.server.NewTable("sites", key)
+
+ q := dynamodb.NewQuery(table)
+ q.AddKey(table, &dynamodb.Key{HashKey: "test"})
+
+ expected := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("domain", "expectedTest").SetExists(true),
+ *dynamodb.NewStringAttribute("testKey", "").SetExists(false),
+ }
+ q.AddExpected(expected)
+
+ queryJson, err := simplejson.NewJson([]byte(q.String()))
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ expectedJson, err := simplejson.NewJson([]byte(`
+ {
+ "Expected": {
+ "domain": {
+ "Exists": "true",
+ "Value": {
+ "S": "expectedTest"
+ }
+ },
+ "testKey": {
+ "Exists": "false"
+ }
+ },
+ "Key": {
+ "domain": {
+ "S": "test"
+ }
+ },
+ "TableName": "sites"
+ }
+ `))
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(queryJson, DeepEquals, expectedJson)
+}
+
+func (s *QueryBuilderSuite) TestGetItemQuery(c *C) {
+ primary := dynamodb.NewStringAttribute("domain", "")
+ key := dynamodb.PrimaryKey{primary, nil}
+ table := s.server.NewTable("sites", key)
+
+ q := dynamodb.NewQuery(table)
+ q.AddKey(table, &dynamodb.Key{HashKey: "test"})
+
+ {
+ queryJson, err := simplejson.NewJson([]byte(q.String()))
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ expectedJson, err := simplejson.NewJson([]byte(`
+ {
+ "Key": {
+ "domain": {
+ "S": "test"
+ }
+ },
+ "TableName": "sites"
+ }
+ `))
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(queryJson, DeepEquals, expectedJson)
+ }
+
+ // Use ConsistentRead
+ {
+ q.ConsistentRead(true)
+ queryJson, err := simplejson.NewJson([]byte(q.String()))
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ expectedJson, err := simplejson.NewJson([]byte(`
+ {
+ "ConsistentRead": "true",
+ "Key": {
+ "domain": {
+ "S": "test"
+ }
+ },
+ "TableName": "sites"
+ }
+ `))
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(queryJson, DeepEquals, expectedJson)
+ }
+}
+
+func (s *QueryBuilderSuite) TestUpdateQuery(c *C) {
+ primary := dynamodb.NewStringAttribute("domain", "")
+ rangek := dynamodb.NewNumericAttribute("time", "")
+ key := dynamodb.PrimaryKey{primary, rangek}
+ table := s.server.NewTable("sites", key)
+
+ countAttribute := dynamodb.NewNumericAttribute("count", "4")
+ attributes := []dynamodb.Attribute{*countAttribute}
+
+ q := dynamodb.NewQuery(table)
+ q.AddKey(table, &dynamodb.Key{HashKey: "test", RangeKey: "1234"})
+ q.AddUpdates(attributes, "ADD")
+
+ queryJson, err := simplejson.NewJson([]byte(q.String()))
+ if err != nil {
+ c.Fatal(err)
+ }
+ expectedJson, err := simplejson.NewJson([]byte(`
+{
+ "AttributeUpdates": {
+ "count": {
+ "Action": "ADD",
+ "Value": {
+ "N": "4"
+ }
+ }
+ },
+ "Key": {
+ "domain": {
+ "S": "test"
+ },
+ "time": {
+ "N": "1234"
+ }
+ },
+ "TableName": "sites"
+}
+ `))
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(queryJson, DeepEquals, expectedJson)
+}
+
+func (s *QueryBuilderSuite) TestAddUpdates(c *C) {
+ primary := dynamodb.NewStringAttribute("domain", "")
+ key := dynamodb.PrimaryKey{primary, nil}
+ table := s.server.NewTable("sites", key)
+
+ q := dynamodb.NewQuery(table)
+ q.AddKey(table, &dynamodb.Key{HashKey: "test"})
+
+ attr := dynamodb.NewStringSetAttribute("StringSet", []string{"str", "str2"})
+
+ q.AddUpdates([]dynamodb.Attribute{*attr}, "ADD")
+
+ queryJson, err := simplejson.NewJson([]byte(q.String()))
+ if err != nil {
+ c.Fatal(err)
+ }
+ expectedJson, err := simplejson.NewJson([]byte(`
+{
+ "AttributeUpdates": {
+ "StringSet": {
+ "Action": "ADD",
+ "Value": {
+ "SS": ["str", "str2"]
+ }
+ }
+ },
+ "Key": {
+ "domain": {
+ "S": "test"
+ }
+ },
+ "TableName": "sites"
+}
+ `))
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(queryJson, DeepEquals, expectedJson)
+}
+
+func (s *QueryBuilderSuite) TestAddKeyConditions(c *C) {
+ primary := dynamodb.NewStringAttribute("domain", "")
+ key := dynamodb.PrimaryKey{primary, nil}
+ table := s.server.NewTable("sites", key)
+
+ q := dynamodb.NewQuery(table)
+ acs := []dynamodb.AttributeComparison{
+ *dynamodb.NewStringAttributeComparison("domain", "EQ", "example.com"),
+ *dynamodb.NewStringAttributeComparison("path", "EQ", "/"),
+ }
+ q.AddKeyConditions(acs)
+ queryJson, err := simplejson.NewJson([]byte(q.String()))
+
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ expectedJson, err := simplejson.NewJson([]byte(`
+{
+ "KeyConditions": {
+ "domain": {
+ "AttributeValueList": [
+ {
+ "S": "example.com"
+ }
+ ],
+ "ComparisonOperator": "EQ"
+ },
+ "path": {
+ "AttributeValueList": [
+ {
+ "S": "/"
+ }
+ ],
+ "ComparisonOperator": "EQ"
+ }
+ },
+ "TableName": "sites"
+}
+ `))
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(queryJson, DeepEquals, expectedJson)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/scan.go b/vendor/github.com/goamz/goamz/dynamodb/scan.go
new file mode 100644
index 000000000..e8ed62363
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/scan.go
@@ -0,0 +1,51 @@
+package dynamodb
+
+import (
+ "errors"
+ "fmt"
+ simplejson "github.com/bitly/go-simplejson"
+)
+
+func (t *Table) FetchResults(query *Query) ([]map[string]*Attribute, error) {
+ jsonResponse, err := t.Server.queryServer(target("Scan"), query)
+ if err != nil {
+ return nil, err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return nil, err
+ }
+
+ itemCount, err := json.Get("Count").Int()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ results := make([]map[string]*Attribute, itemCount)
+
+ for i, _ := range results {
+ item, err := json.Get("Items").GetIndex(i).Map()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+ results[i] = parseAttributes(item)
+ }
+ return results, nil
+
+}
+
+func (t *Table) Scan(attributeComparisons []AttributeComparison) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddScanFilter(attributeComparisons)
+ return t.FetchResults(q)
+}
+
+func (t *Table) ParallelScan(attributeComparisons []AttributeComparison, segment int, totalSegments int) ([]map[string]*Attribute, error) {
+ q := NewQuery(t)
+ q.AddScanFilter(attributeComparisons)
+ q.AddParallelScanConfiguration(segment, totalSegments)
+ return t.FetchResults(q)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/stream.go b/vendor/github.com/goamz/goamz/dynamodb/stream.go
new file mode 100644
index 000000000..57f3a145f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/stream.go
@@ -0,0 +1,307 @@
+package dynamodb
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "reflect"
+
+ simplejson "github.com/bitly/go-simplejson"
+)
+
+type Stream struct {
+ Server *Server
+ Arn string
+}
+
+type StreamListItemT struct {
+ StreamArn string
+ StreamLabel string
+ TableName string
+}
+
+type SequenceNumberRangeT struct {
+ EndingSequenceNumber string
+ StartingSequenceNumber string
+}
+
+type ShardT struct {
+ ParentShardId string
+ SequenceNumberRange SequenceNumberRangeT
+ ShardId string
+}
+
+type StreamDescriptionT struct {
+ CreationDateTime float64
+ KeySchema []KeySchemaT
+ LastEvaluatedShardId string
+ Shards []ShardT
+ StreamArn string
+ StreamLabel string
+ StreamStatus string
+ StreamViewType string
+ TableName string
+}
+
+type RecordT struct {
+ AwsRegion string
+ EventID string
+ EventName string
+ EventSource string
+ EventVersion string
+ StreamRecord *StreamRecordT
+}
+
+type StreamRecordT struct {
+ Keys map[string]*Attribute
+ NewImage map[string]*Attribute
+ OldImage map[string]*Attribute
+ SequenceNumber string
+ StreamViewType string
+ SizeBytes int64
+}
+
+type listStreamsResponse struct {
+ Streams []StreamListItemT
+}
+
+type describeStreamResponse struct {
+ StreamDescription StreamDescriptionT
+}
+
+var ErrNoRecords = errors.New("No records")
+
+func (s *Server) ListStreams(startArn string) ([]StreamListItemT, error) {
+ return s.LimitedListTableStreams("", startArn, 0)
+}
+
+func (s *Server) LimitedListStreams(startArn string, limit int64) ([]StreamListItemT, error) {
+ return s.LimitedListTableStreams("", startArn, limit)
+}
+
+func (s *Server) ListTableStreams(table, startArn string) ([]StreamListItemT, error) {
+ return s.LimitedListTableStreams(table, startArn, 0)
+}
+
+func (s *Server) LimitedListTableStreams(table, startArn string, limit int64) ([]StreamListItemT, error) {
+ query := NewEmptyQuery()
+
+ if len(table) != 0 {
+ query.addTableByName(table)
+ }
+
+ if len(startArn) != 0 {
+ query.AddExclusiveStartStreamArn(startArn)
+ }
+
+ if limit > 0 {
+ query.AddLimit(limit)
+ }
+
+ jsonResponse, err := s.queryServer(streamsTarget("ListStreams"), query)
+ if err != nil {
+ return nil, err
+ }
+
+ var r listStreamsResponse
+ err = json.Unmarshal(jsonResponse, &r)
+ if err != nil {
+ return nil, err
+ }
+
+ return r.Streams, nil
+}
+
+func (s *Server) DescribeStream(arn, startShardId string) (*StreamDescriptionT, error) {
+ return s.LimitedDescribeStream(arn, startShardId, 0)
+}
+
+func (s *Server) LimitedDescribeStream(arn, startShardId string, limit int64) (*StreamDescriptionT, error) {
+ query := NewEmptyQuery()
+ query.AddStreamArn(arn)
+
+ if len(startShardId) != 0 {
+ query.AddExclusiveStartShardId(startShardId)
+ }
+
+ if limit > 0 {
+ query.AddLimit(limit)
+ }
+
+ jsonResponse, err := s.queryServer(streamsTarget("DescribeStream"), query)
+ if err != nil {
+ return nil, err
+ }
+
+ var r describeStreamResponse
+ err = json.Unmarshal(jsonResponse, &r)
+ if err != nil {
+ return nil, err
+ }
+
+ return &r.StreamDescription, nil
+}
+
+func (s *Server) NewStream(streamArn string) *Stream {
+ return &Stream{s, streamArn}
+}
+
+func (s *Stream) DescribeStream(startShardId string) (*StreamDescriptionT, error) {
+ return s.Server.DescribeStream(s.Arn, startShardId)
+}
+
+func (s *Stream) LimitedDescribeStream(startShardId string, limit int64) (*StreamDescriptionT, error) {
+ return s.Server.LimitedDescribeStream(s.Arn, startShardId, limit)
+}
+
+func (s *Server) GetShardIterator(streamArn, shardId, shardIteratorType, sequenceNumber string) (string, error) {
+ query := NewEmptyQuery()
+ query.AddStreamArn(streamArn)
+ query.AddShardId(shardId)
+ query.AddShardIteratorType(shardIteratorType)
+
+ if len(sequenceNumber) != 0 {
+ query.AddSequenceNumber(sequenceNumber)
+ }
+
+ jsonResponse, err := s.queryServer(streamsTarget("GetShardIterator"), query)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ return json.Get("ShardIterator").MustString(), nil
+}
+
+func (s *Stream) GetShardIterator(shardId, shardIteratorType, sequenceNumber string) (string, error) {
+ return s.Server.GetShardIterator(s.Arn, shardId, shardIteratorType, sequenceNumber)
+}
+
+func (s *Server) GetRecords(shardIterator string) (string, []*RecordT, error) {
+ return s.LimitedGetRecords(shardIterator, 0)
+}
+
+func (s *Server) LimitedGetRecords(shardIterator string, limit int64) (string, []*RecordT, error) {
+ query := NewEmptyQuery()
+ query.AddShardIterator(shardIterator)
+
+ if limit > 0 {
+ query.AddLimit(limit)
+ }
+
+ jsonResponse, err := s.queryServer(streamsTarget("GetRecords"), query)
+ if err != nil {
+ return "", nil, err
+ }
+
+ jsonParsed, err := simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return "", nil, err
+ }
+
+ nextShardIt := ""
+ nextShardItJson, ok := jsonParsed.CheckGet("NextShardIterator")
+ if ok {
+ nextShardIt, err = nextShardItJson.String()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return "", nil, errors.New(message)
+ }
+ }
+
+ recordsJson, ok := jsonParsed.CheckGet("Records")
+ if !ok {
+ return nextShardIt, nil, ErrNoRecords
+ }
+
+ recordsArray, err := recordsJson.Array()
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nextShardIt, nil, errors.New(message)
+ }
+
+ var records []*RecordT
+ for _, record := range recordsArray {
+ if recordMap, ok := record.(map[string]interface{}); ok {
+ r := parseRecord(recordMap)
+ records = append(records, r)
+ }
+ }
+
+ return nextShardIt, records, nil
+}
+
+func (s *Stream) GetRecords(shardIterator string) (string, []*RecordT, error) {
+ return s.Server.GetRecords(shardIterator)
+}
+
+func (s *Stream) LimitedGetRecords(shardIterator string, limit int64) (string, []*RecordT, error) {
+ return s.Server.LimitedGetRecords(shardIterator, limit)
+}
+
+func parseRecord(r map[string]interface{}) *RecordT {
+ record := RecordT{}
+ rValue := reflect.ValueOf(&record)
+
+ keys := []string{"awsRegion", "eventID", "eventName", "eventSource", "eventVersion"}
+ for i, key := range keys {
+ if value, ok := r[key]; ok {
+ if valueStr, ok := value.(string); ok {
+ rValue.Elem().Field(i).SetString(valueStr)
+ }
+ }
+ }
+
+ if streamRecord, ok := r["dynamodb"]; ok {
+ if streamRecordMap, ok := streamRecord.(map[string]interface{}); ok {
+ record.StreamRecord = parseStreamRecord(streamRecordMap)
+ }
+ }
+
+ return &record
+}
+
+func parseStreamRecord(s map[string]interface{}) *StreamRecordT {
+ sr := StreamRecordT{}
+ rValue := reflect.ValueOf(&sr)
+
+ attrKeys := []string{"Keys", "NewImage", "OldImage"}
+ numAttrKeys := len(attrKeys)
+ for i, key := range attrKeys {
+ if value, ok := s[key]; ok {
+ if valueMap, ok := value.(map[string]interface{}); ok {
+ attrs := parseAttributes(valueMap)
+ rValue.Elem().Field(i).Set(reflect.ValueOf(attrs))
+ }
+ }
+ }
+
+ strKeys := []string{"SequenceNumber", "StreamViewType"}
+ numStrKeys := len(strKeys)
+ for i, key := range strKeys {
+ if value, ok := s[key]; ok {
+ if valueStr, ok := value.(string); ok {
+ rValue.Elem().Field(i + numAttrKeys).SetString(valueStr)
+ }
+ }
+ }
+
+ intKeys := []string{"SizeBytes"}
+ for i, key := range intKeys {
+ if value, ok := s[key]; ok {
+ if valueNumber, ok := value.(json.Number); ok {
+ if valueInt, err := valueNumber.Int64(); err == nil {
+ rValue.Elem().Field(i + numAttrKeys + numStrKeys).SetInt(valueInt)
+ }
+ }
+ }
+ }
+
+ return &sr
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/stream_test.go b/vendor/github.com/goamz/goamz/dynamodb/stream_test.go
new file mode 100755
index 000000000..a982ffa65
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/stream_test.go
@@ -0,0 +1,198 @@
+package dynamodb_test
+
+import (
+ "strconv"
+
+ "github.com/goamz/goamz/dynamodb"
+ . "gopkg.in/check.v1"
+)
+
+type StreamSuite struct {
+ TableDescriptionT dynamodb.TableDescriptionT
+ DynamoDBTest
+}
+
+func (s *StreamSuite) SetUpSuite(c *C) {
+ setUpAuth(c)
+ s.DynamoDBTest.TableDescriptionT = s.TableDescriptionT
+ s.server = &dynamodb.Server{dynamodb_auth, dynamodb_region}
+ pk, err := s.TableDescriptionT.BuildPrimaryKey()
+ if err != nil {
+ c.Skip(err.Error())
+ }
+ s.table = s.server.NewTable(s.TableDescriptionT.TableName, pk)
+
+ // Cleanup
+ s.TearDownSuite(c)
+ _, err = s.server.CreateTable(s.TableDescriptionT)
+ if err != nil {
+ c.Fatal(err)
+ }
+ s.WaitUntilStatus(c, "ACTIVE")
+}
+
+var stream_suite_keys_only = &StreamSuite{
+ TableDescriptionT: dynamodb.TableDescriptionT{
+ TableName: "StreamTable",
+ AttributeDefinitions: []dynamodb.AttributeDefinitionT{
+ dynamodb.AttributeDefinitionT{"TestHashKey", "S"},
+ dynamodb.AttributeDefinitionT{"TestRangeKey", "N"},
+ },
+ KeySchema: []dynamodb.KeySchemaT{
+ dynamodb.KeySchemaT{"TestHashKey", "HASH"},
+ dynamodb.KeySchemaT{"TestRangeKey", "RANGE"},
+ },
+ ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
+ ReadCapacityUnits: 1,
+ WriteCapacityUnits: 1,
+ },
+ StreamSpecification: dynamodb.StreamSpecificationT{
+ StreamEnabled: true,
+ StreamViewType: "KEYS_ONLY",
+ },
+ },
+}
+
+var stream_suite_new_image = &StreamSuite{
+ TableDescriptionT: dynamodb.TableDescriptionT{
+ TableName: "StreamTable",
+ AttributeDefinitions: []dynamodb.AttributeDefinitionT{
+ dynamodb.AttributeDefinitionT{"TestHashKey", "S"},
+ dynamodb.AttributeDefinitionT{"TestRangeKey", "N"},
+ },
+ KeySchema: []dynamodb.KeySchemaT{
+ dynamodb.KeySchemaT{"TestHashKey", "HASH"},
+ dynamodb.KeySchemaT{"TestRangeKey", "RANGE"},
+ },
+ ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
+ ReadCapacityUnits: 1,
+ WriteCapacityUnits: 1,
+ },
+ StreamSpecification: dynamodb.StreamSpecificationT{
+ StreamEnabled: true,
+ StreamViewType: "NEW_IMAGE",
+ },
+ },
+}
+
+var _ = Suite(stream_suite_keys_only)
+var _ = Suite(stream_suite_new_image)
+
+func (s *StreamSuite) TestStream(c *C) {
+ checkStream(s.table, c)
+}
+
+func checkStream(table *dynamodb.Table, c *C) {
+ // list the table's streams
+ streams, err := table.ListStreams("")
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(len(streams), Not(Equals), 0)
+ c.Check(streams[0].TableName, Equals, table.Name)
+
+ // stick a couple of items in the table
+ attrs := []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("TestAttr", "0"),
+ }
+ if ok, err := table.PutItem("0", "0", attrs); !ok {
+ c.Fatal(err)
+ }
+ attrs = []dynamodb.Attribute{
+ *dynamodb.NewStringAttribute("TestAttr", "1"),
+ }
+ if ok, err := table.PutItem("1", "1", attrs); !ok {
+ c.Fatal(err)
+ }
+
+ // create a stream object
+ stream := table.Server.NewStream(streams[0].StreamArn)
+
+ // describe the steam
+ desc, err := stream.DescribeStream("")
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ tableDesc, err := table.DescribeTable()
+ if err != nil {
+ c.Fatal(err)
+ }
+
+ c.Check(desc.KeySchema[0], Equals, tableDesc.KeySchema[0])
+ c.Check(desc.StreamArn, Equals, streams[0].StreamArn)
+ c.Check(desc.StreamStatus, Equals, "ENABLED")
+ c.Check(desc.StreamViewType, Equals, tableDesc.StreamSpecification.StreamViewType)
+ c.Check(desc.TableName, Equals, table.Name)
+ c.Check(len(desc.Shards), Equals, 1)
+
+ // get a shard iterator
+ shardIt, err := stream.GetShardIterator(desc.Shards[0].ShardId, "TRIM_HORIZON", "")
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(len(shardIt), Not(Equals), 0)
+
+ // poll for records
+ nextIt, records, err := stream.GetRecords(shardIt)
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(len(nextIt), Not(Equals), 0)
+ c.Check(len(records), Equals, 2)
+
+ for index, record := range records {
+ c.Check(record.EventSource, Equals, "aws:dynamodb")
+ c.Check(record.EventName, Equals, "INSERT")
+ c.Check(len(record.EventID), Not(Equals), 0)
+
+ // look at the actual record
+ streamRec := record.StreamRecord
+ c.Check(streamRec.StreamViewType, Equals, desc.StreamViewType)
+ c.Check(len(streamRec.SequenceNumber), Not(Equals), 0)
+ if streamRec.SizeBytes <= 0 {
+ c.Errorf("Expected greater-than-zero size, got: %d", streamRec.SizeBytes)
+ }
+ // check the keys
+ if streamRec.StreamViewType == "KEYS_ONLY" {
+ checkKeys(streamRec.Keys, index, c)
+ }
+ // check the image
+ if streamRec.StreamViewType == "NEW_IMAGE" {
+ checkNewImage(streamRec.NewImage, index, c)
+ }
+ }
+}
+
+func checkKeys(keys map[string]*dynamodb.Attribute, expect int, c *C) {
+ c.Check(len(keys), Equals, 2)
+ value, err := strconv.Atoi(keys["TestHashKey"].Value)
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(value, Equals, expect)
+ value, err = strconv.Atoi(keys["TestRangeKey"].Value)
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(value, Equals, expect)
+}
+
+func checkNewImage(image map[string]*dynamodb.Attribute, expect int, c *C) {
+ c.Check(len(image), Equals, 3)
+ value, err := strconv.Atoi(image["TestHashKey"].Value)
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(value, Equals, expect)
+ value, err = strconv.Atoi(image["TestRangeKey"].Value)
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(value, Equals, expect)
+ value, err = strconv.Atoi(image["TestAttr"].Value)
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(value, Equals, expect)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/table.go b/vendor/github.com/goamz/goamz/dynamodb/table.go
new file mode 100755
index 000000000..541433c13
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/table.go
@@ -0,0 +1,259 @@
+package dynamodb
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ simplejson "github.com/bitly/go-simplejson"
+)
+
+type Table struct {
+ Server *Server
+ Name string
+ Key PrimaryKey
+}
+
+type AttributeDefinitionT struct {
+ Name string `json:"AttributeName"`
+ Type string `json:"AttributeType"`
+}
+
+type KeySchemaT struct {
+ AttributeName string
+ KeyType string
+}
+
+type ProjectionT struct {
+ ProjectionType string
+}
+
+type GlobalSecondaryIndexT struct {
+ IndexName string
+ IndexSizeBytes int64
+ ItemCount int64
+ KeySchema []KeySchemaT
+ Projection ProjectionT
+ ProvisionedThroughput ProvisionedThroughputT
+}
+
+type LocalSecondaryIndexT struct {
+ IndexName string
+ IndexSizeBytes int64
+ ItemCount int64
+ KeySchema []KeySchemaT
+ Projection ProjectionT
+}
+
+type ProvisionedThroughputT struct {
+ NumberOfDecreasesToday int64
+ ReadCapacityUnits int64
+ WriteCapacityUnits int64
+}
+
+type StreamSpecificationT struct {
+ StreamEnabled bool
+ StreamViewType string
+}
+
+type TableDescriptionT struct {
+ AttributeDefinitions []AttributeDefinitionT
+ CreationDateTime float64
+ ItemCount int64
+ KeySchema []KeySchemaT
+ GlobalSecondaryIndexes []GlobalSecondaryIndexT
+ LocalSecondaryIndexes []LocalSecondaryIndexT
+ ProvisionedThroughput ProvisionedThroughputT
+ StreamSpecification StreamSpecificationT
+ TableName string
+ TableSizeBytes int64
+ TableStatus string
+ LatestStreamArn string
+ LatestStreamLabel string
+}
+
+type describeTableResponse struct {
+ Table TableDescriptionT
+}
+
+func findAttributeDefinitionByName(ads []AttributeDefinitionT, name string) *AttributeDefinitionT {
+ for _, a := range ads {
+ if a.Name == name {
+ return &a
+ }
+ }
+ return nil
+}
+
+func (a *AttributeDefinitionT) GetEmptyAttribute() *Attribute {
+ switch a.Type {
+ case "S":
+ return NewStringAttribute(a.Name, "")
+ case "N":
+ return NewNumericAttribute(a.Name, "")
+ case "B":
+ return NewBinaryAttribute(a.Name, "")
+ default:
+ return nil
+ }
+}
+
+func (t *TableDescriptionT) BuildPrimaryKey() (pk PrimaryKey, err error) {
+ for _, k := range t.KeySchema {
+ var attr *Attribute
+ ad := findAttributeDefinitionByName(t.AttributeDefinitions, k.AttributeName)
+ if ad == nil {
+ return pk, errors.New("An inconsistency found in TableDescriptionT")
+ }
+ attr = ad.GetEmptyAttribute()
+ if attr == nil {
+ return pk, errors.New("An inconsistency found in TableDescriptionT")
+ }
+
+ switch k.KeyType {
+ case "HASH":
+ pk.KeyAttribute = attr
+ case "RANGE":
+ pk.RangeAttribute = attr
+ }
+ }
+ return
+}
+
+func (s *Server) NewTable(name string, key PrimaryKey) *Table {
+ return &Table{s, name, key}
+}
+
+func (s *Server) ListTables() ([]string, error) {
+ var tables []string
+
+ query := NewEmptyQuery()
+
+ jsonResponse, err := s.queryServer(target("ListTables"), query)
+
+ if err != nil {
+ return nil, err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+
+ if err != nil {
+ return nil, err
+ }
+
+ response, err := json.Get("TableNames").Array()
+
+ if err != nil {
+ message := fmt.Sprintf("Unexpected response %s", jsonResponse)
+ return nil, errors.New(message)
+ }
+
+ for _, value := range response {
+ if t, ok := (value).(string); ok {
+ tables = append(tables, t)
+ }
+ }
+
+ return tables, nil
+}
+
+func (s *Server) CreateTable(tableDescription TableDescriptionT) (string, error) {
+ query := NewEmptyQuery()
+ query.AddCreateRequestTable(tableDescription)
+
+ jsonResponse, err := s.queryServer(target("CreateTable"), query)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ return json.Get("TableDescription").Get("TableStatus").MustString(), nil
+}
+
+func (s *Server) DeleteTable(tableDescription TableDescriptionT) (string, error) {
+ query := NewEmptyQuery()
+ query.AddDeleteRequestTable(tableDescription)
+
+ jsonResponse, err := s.queryServer(target("DeleteTable"), query)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ return json.Get("TableDescription").Get("TableStatus").MustString(), nil
+}
+
+func (t *Table) DescribeTable() (*TableDescriptionT, error) {
+ return t.Server.DescribeTable(t.Name)
+}
+
+func (s *Server) DescribeTable(name string) (*TableDescriptionT, error) {
+ q := NewEmptyQuery()
+ q.addTableByName(name)
+
+ jsonResponse, err := s.queryServer(target("DescribeTable"), q)
+ if err != nil {
+ return nil, err
+ }
+
+ var r describeTableResponse
+ err = json.Unmarshal(jsonResponse, &r)
+ if err != nil {
+ return nil, err
+ }
+
+ return &r.Table, nil
+}
+
+func (s *Server) UpdateTable(tableDescription TableDescriptionT) (string, error) {
+ query := NewEmptyQuery()
+ query.AddUpdateRequestTable(tableDescription)
+
+ jsonResponse, err := s.queryServer(target("UpdateTable"), query)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ json, err := simplejson.NewJson(jsonResponse)
+
+ if err != nil {
+ return "unknown", err
+ }
+
+ return json.Get("TableDescription").Get("TableStatus").MustString(), nil
+}
+
+func (t *Table) ListStreams(startArn string) ([]StreamListItemT, error) {
+ return t.Server.ListTableStreams(t.Name, startArn)
+}
+
+func (t *Table) LimitedListStreams(startArn string, limit int64) ([]StreamListItemT, error) {
+ return t.Server.LimitedListTableStreams(t.Name, startArn, limit)
+}
+
+func keyParam(k *PrimaryKey, hashKey string, rangeKey string) string {
+ value := fmt.Sprintf("{\"HashKeyElement\":{%s}", keyValue(k.KeyAttribute.Type, hashKey))
+
+ if k.RangeAttribute != nil {
+ value = fmt.Sprintf("%s,\"RangeKeyElement\":{%s}", value,
+ keyValue(k.RangeAttribute.Type, rangeKey))
+ }
+
+ return fmt.Sprintf("\"Key\":%s}", value)
+}
+
+func keyValue(key string, value string) string {
+ return fmt.Sprintf("\"%s\":\"%s\"", key, value)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/table_test.go b/vendor/github.com/goamz/goamz/dynamodb/table_test.go
new file mode 100755
index 000000000..8925bdc1b
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/table_test.go
@@ -0,0 +1,79 @@
+package dynamodb_test
+
+import (
+ "github.com/goamz/goamz/dynamodb"
+ . "gopkg.in/check.v1"
+)
+
+type TableSuite struct {
+ TableDescriptionT dynamodb.TableDescriptionT
+ DynamoDBTest
+}
+
+func (s *TableSuite) SetUpSuite(c *C) {
+ setUpAuth(c)
+ s.DynamoDBTest.TableDescriptionT = s.TableDescriptionT
+ s.server = &dynamodb.Server{dynamodb_auth, dynamodb_region}
+ pk, err := s.TableDescriptionT.BuildPrimaryKey()
+ if err != nil {
+ c.Skip(err.Error())
+ }
+ s.table = s.server.NewTable(s.TableDescriptionT.TableName, pk)
+
+ // Cleanup
+ s.TearDownSuite(c)
+}
+
+var table_suite = &TableSuite{
+ TableDescriptionT: dynamodb.TableDescriptionT{
+ TableName: "DynamoDBTestMyTable",
+ AttributeDefinitions: []dynamodb.AttributeDefinitionT{
+ dynamodb.AttributeDefinitionT{"TestHashKey", "S"},
+ dynamodb.AttributeDefinitionT{"TestRangeKey", "N"},
+ dynamodb.AttributeDefinitionT{"TestSecKey", "N"},
+ },
+ KeySchema: []dynamodb.KeySchemaT{
+ dynamodb.KeySchemaT{"TestHashKey", "HASH"},
+ dynamodb.KeySchemaT{"TestRangeKey", "RANGE"},
+ },
+ GlobalSecondaryIndexes: []dynamodb.GlobalSecondaryIndexT{
+ dynamodb.GlobalSecondaryIndexT{
+ IndexName: "gsiTest",
+ KeySchema: []dynamodb.KeySchemaT{
+ dynamodb.KeySchemaT{"TestHashKey", "HASH"},
+ dynamodb.KeySchemaT{"TestSecKey", "RANGE"},
+ },
+ Projection: dynamodb.ProjectionT{"ALL"},
+ ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
+ ReadCapacityUnits: 1,
+ WriteCapacityUnits: 1,
+ },
+ },
+ },
+ ProvisionedThroughput: dynamodb.ProvisionedThroughputT{
+ ReadCapacityUnits: 1,
+ WriteCapacityUnits: 1,
+ },
+ },
+}
+
+var _ = Suite(table_suite)
+
+func (s *TableSuite) TestCreateListTable(c *C) {
+ status, err := s.server.CreateTable(s.TableDescriptionT)
+ if err != nil {
+ c.Fatal(err)
+ }
+ if status != "ACTIVE" && status != "CREATING" {
+ c.Error("Expect status to be ACTIVE or CREATING")
+ }
+
+ s.WaitUntilStatus(c, "ACTIVE")
+
+ tables, err := s.server.ListTables()
+ if err != nil {
+ c.Fatal(err)
+ }
+ c.Check(len(tables), Not(Equals), 0)
+ c.Check(findTableByName(tables, s.TableDescriptionT.TableName), Equals, true)
+}
diff --git a/vendor/github.com/goamz/goamz/dynamodb/update_item.go b/vendor/github.com/goamz/goamz/dynamodb/update_item.go
new file mode 100644
index 000000000..280eb4bed
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/dynamodb/update_item.go
@@ -0,0 +1,94 @@
+package dynamodb
+
+import simplejson "github.com/bitly/go-simplejson"
+
+/*
+Construct an update item query.
+
+The query can be composed via chaining and then executed via Execute()
+
+Usage:
+ update := table.UpdateItem(key)
+ .ReturnValues(dynamodb.UPDATED_NEW)
+ .UpdateExpression("SET Counter = Counter + :incr")
+ .UpdateCondition("Counter < :checkVal")
+ .ExpressionAttributes(NewNumberAttribute(":incr", "1"), NewNumberAttribute(":checkVal", 42))
+ result, err := update.Execute()
+ if err == nil {
+ log.Printf("Counter is now %v", result.Attributes["Counter"].Value)
+ }
+
+*/
+func (t *Table) UpdateItem(key *Key) *UpdateItem {
+ q := NewQuery(t)
+ q.AddKey(t, key)
+ return &UpdateItem{table: t, query: q}
+}
+
+type UpdateItem struct {
+ table *Table
+ query *Query
+ hasReturnValues bool
+}
+
+// Specify how return values are to be provided.
+func (u *UpdateItem) ReturnValues(returnValues ReturnValues) *UpdateItem {
+ u.hasReturnValues = (returnValues != NONE)
+ u.query.AddReturnValues(returnValues)
+ return u
+}
+
+/*
+Specify an update expression and optional attribute settings at the same time.
+
+ update.UpdateExpression("SET Foo = Foo + :incr", dynamodb.NewNumberAttribute(":incr", "7"))
+
+is equivalent to
+
+ update.UpdateExpression("SET Foo = Foo + :incr")
+ .ExpressionAttributes(NewNumberAttribute(":incr", "7"))
+
+*/
+func (u *UpdateItem) UpdateExpression(expression string, attributes ...Attribute) *UpdateItem {
+ u.query.AddUpdateExpression(expression)
+ u.ExpressionAttributes(attributes...)
+ return u
+}
+
+// Specify attribute substitutions to be used in expressions.
+func (u *UpdateItem) ExpressionAttributes(attributes ...Attribute) *UpdateItem {
+ u.query.AddExpressionAttributes(attributes)
+ return u
+}
+
+// Specify a check condition for conditional updates.
+func (u *UpdateItem) ConditionExpression(expression string) *UpdateItem {
+ u.query.AddConditionExpression(expression)
+ return u
+}
+
+// Execute this query.
+func (u *UpdateItem) Execute() (*UpdateResult, error) {
+ jsonResponse, err := u.table.Server.queryServer(target("UpdateItem"), u.query)
+
+ if err != nil {
+ return nil, err
+ }
+
+ if u.hasReturnValues {
+ resp, err := simplejson.NewJson(jsonResponse)
+ if err != nil {
+ return nil, err
+ }
+ attrib, err := resp.Get("Attributes").Map()
+ if err != nil {
+ return nil, err
+ }
+ return &UpdateResult{parseAttributes(attrib)}, nil
+ }
+ return nil, nil
+}
+
+type UpdateResult struct {
+ Attributes map[string]*Attribute
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/ec2.go b/vendor/github.com/goamz/goamz/ec2/ec2.go
new file mode 100644
index 000000000..e6ec612cf
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/ec2.go
@@ -0,0 +1,2267 @@
+//
+// goamz - Go packages to interact with the Amazon Web Services.
+//
+// https://wiki.ubuntu.com/goamz
+//
+// Copyright (c) 2011 Canonical Ltd.
+//
+// Written by Gustavo Niemeyer <gustavo.niemeyer@canonical.com>
+//
+
+package ec2
+
+import (
+ "crypto/rand"
+ "encoding/hex"
+ "encoding/xml"
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+const debug = false
+
+// The EC2 type encapsulates operations with a specific EC2 region.
+type EC2 struct {
+ aws.Auth
+ aws.Region
+ httpClient *http.Client
+ private byte // Reserve the right of using private data.
+}
+
+// NewWithClient creates a new EC2 with a custom http client
+func NewWithClient(auth aws.Auth, region aws.Region, client *http.Client) *EC2 {
+ return &EC2{auth, region, client, 0}
+}
+
+// New creates a new EC2.
+func New(auth aws.Auth, region aws.Region) *EC2 {
+ return NewWithClient(auth, region, aws.RetryingClient)
+}
+
+// ----------------------------------------------------------------------------
+// Filtering helper.
+
+// Filter builds filtering parameters to be used in an EC2 query which supports
+// filtering. For example:
+//
+// filter := NewFilter()
+// filter.Add("architecture", "i386")
+// filter.Add("launch-index", "0")
+// resp, err := ec2.Instances(nil, filter)
+//
+type Filter struct {
+ m map[string][]string
+}
+
+// NewFilter creates a new Filter.
+func NewFilter() *Filter {
+ return &Filter{make(map[string][]string)}
+}
+
+// Add appends a filtering parameter with the given name and value(s).
+func (f *Filter) Add(name string, value ...string) {
+ f.m[name] = append(f.m[name], value...)
+}
+
+func (f *Filter) addParams(params map[string]string) {
+ if f != nil {
+ a := make([]string, len(f.m))
+ i := 0
+ for k := range f.m {
+ a[i] = k
+ i++
+ }
+ sort.StringSlice(a).Sort()
+ for i, k := range a {
+ prefix := "Filter." + strconv.Itoa(i+1)
+ params[prefix+".Name"] = k
+ for j, v := range f.m[k] {
+ params[prefix+".Value."+strconv.Itoa(j+1)] = v
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+// Error encapsulates an error returned by EC2.
+//
+// See http://goo.gl/VZGuC for more details.
+type Error struct {
+ // HTTP status code (200, 403, ...)
+ StatusCode int
+ // EC2 error code ("UnsupportedOperation", ...)
+ Code string
+ // The human-oriented error message
+ Message string
+ RequestId string `xml:"RequestID"`
+}
+
+func (err *Error) Error() string {
+ if err.Code == "" {
+ return err.Message
+ }
+
+ return fmt.Sprintf("%s (%s)", err.Message, err.Code)
+}
+
+// For now a single error inst is being exposed. In the future it may be useful
+// to provide access to all of them, but rather than doing it as an array/slice,
+// use a *next pointer, so that it's backward compatible and it continues to be
+// easy to handle the first error, which is what most people will want.
+type xmlErrors struct {
+ RequestId string `xml:"RequestID"`
+ Errors []Error `xml:"Errors>Error"`
+}
+
+var timeNow = time.Now
+
+func (ec2 *EC2) query(params map[string]string, resp interface{}) error {
+ params["Version"] = "2014-02-01"
+ params["Timestamp"] = timeNow().In(time.UTC).Format(time.RFC3339)
+ endpoint, err := url.Parse(ec2.Region.EC2Endpoint)
+ if err != nil {
+ return err
+ }
+ if endpoint.Path == "" {
+ endpoint.Path = "/"
+ }
+ sign(ec2.Auth, "GET", endpoint.Path, params, endpoint.Host)
+ endpoint.RawQuery = multimap(params).Encode()
+ if debug {
+ log.Printf("get { %v } -> {\n", endpoint.String())
+ }
+ r, err := ec2.httpClient.Get(endpoint.String())
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("response:\n")
+ log.Printf("%v\n}\n", string(dump))
+ }
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+func buildError(r *http.Response) error {
+ errors := xmlErrors{}
+ xml.NewDecoder(r.Body).Decode(&errors)
+ var err Error
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+ err.RequestId = errors.RequestId
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+func addParamsList(params map[string]string, label string, ids []string) {
+ for i, id := range ids {
+ params[label+"."+strconv.Itoa(i+1)] = id
+ }
+}
+
+func addBlockDeviceParams(prename string, params map[string]string, blockdevices []BlockDeviceMapping) {
+ for i, k := range blockdevices {
+ // Fixup index since Amazon counts these from 1
+ prefix := prename + "BlockDeviceMapping." + strconv.Itoa(i+1) + "."
+
+ if k.DeviceName != "" {
+ params[prefix+"DeviceName"] = k.DeviceName
+ }
+ if k.VirtualName != "" {
+ params[prefix+"VirtualName"] = k.VirtualName
+ }
+ if k.SnapshotId != "" {
+ params[prefix+"Ebs.SnapshotId"] = k.SnapshotId
+ }
+ if k.VolumeType != "" {
+ params[prefix+"Ebs.VolumeType"] = k.VolumeType
+ }
+ if k.IOPS != 0 {
+ params[prefix+"Ebs.Iops"] = strconv.FormatInt(k.IOPS, 10)
+ }
+ if k.VolumeSize != 0 {
+ params[prefix+"Ebs.VolumeSize"] = strconv.FormatInt(k.VolumeSize, 10)
+ }
+ if k.DeleteOnTermination {
+ params[prefix+"Ebs.DeleteOnTermination"] = "true"
+ }
+ if k.NoDevice {
+ params[prefix+"NoDevice"] = "true"
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Instance management functions and types.
+
+// RunInstancesOptions encapsulates options for the respective request in EC2.
+//
+// See http://goo.gl/Mcm3b for more details.
+type RunInstancesOptions struct {
+ ImageId string
+ MinCount int
+ MaxCount int
+ KeyName string
+ InstanceType string
+ SecurityGroups []SecurityGroup
+ KernelId string
+ RamdiskId string
+ UserData []byte
+ AvailabilityZone string
+ PlacementGroupName string
+ Tenancy string
+ Monitoring bool
+ SubnetId string
+ DisableAPITermination bool
+ ShutdownBehavior string
+ PrivateIPAddress string
+ IamInstanceProfile IamInstanceProfile
+ BlockDevices []BlockDeviceMapping
+ EbsOptimized bool
+ AssociatePublicIpAddress bool
+}
+
+// Response to a RunInstances request.
+//
+// See http://goo.gl/Mcm3b for more details.
+type RunInstancesResp struct {
+ RequestId string `xml:"requestId"`
+ ReservationId string `xml:"reservationId"`
+ OwnerId string `xml:"ownerId"`
+ SecurityGroups []SecurityGroup `xml:"groupSet>item"`
+ Instances []Instance `xml:"instancesSet>item"`
+}
+
+// Instance encapsulates a running instance in EC2.
+//
+// See http://goo.gl/OCH8a for more details.
+type Instance struct {
+
+ // General instance information
+ InstanceId string `xml:"instanceId"` // The ID of the instance launched
+ InstanceType string `xml:"instanceType"` // The instance type eg. m1.small | m1.medium | m1.large etc
+ AvailabilityZone string `xml:"placement>availabilityZone"` // The Availability Zone the instance is located in
+ Tags []Tag `xml:"tagSet>item"` // Any tags assigned to the resource
+ State InstanceState `xml:"instanceState"` // The current state of the instance
+ Reason string `xml:"reason"` // The reason for the most recent state transition. This might be an empty string
+ StateReason InstanceStateReason `xml:"stateReason"` // The reason for the most recent state transition
+ ImageId string `xml:"imageId"` // The ID of the AMI used to launch the instance
+ KeyName string `xml:"keyName"` // The key pair name, if this instance was launched with an associated key pair
+ Monitoring string `xml:"monitoring>state"` // Valid values: disabled | enabled | pending
+ IamInstanceProfile IamInstanceProfile `xml:"iamInstanceProfile"` // The IAM instance profile associated with the instance
+ LaunchTime string `xml:"launchTime"` // The time the instance was launched
+ OwnerId string // This isn't currently returned in the response, and is taken from the parent reservation
+
+ // More specific information
+ Architecture string `xml:"architecture"` // Valid values: i386 | x86_64
+ Hypervisor string `xml:"hypervisor"` // Valid values: ovm | xen
+ KernelId string `xml:"kernelId"` // The kernel associated with this instance
+ RamDiskId string `xml:"ramdiskId"` // The RAM disk associated with this instance
+ Platform string `xml:"platform"` // The value is Windows for Windows AMIs; otherwise blank
+ VirtualizationType string `xml:"virtualizationType"` // Valid values: paravirtual | hvm
+ AMILaunchIndex int `xml:"amiLaunchIndex"` // The AMI launch index, which can be used to find this instance in the launch group
+ PlacementGroupName string `xml:"placement>groupName"` // The name of the placement group the instance is in (for cluster compute instances)
+ Tenancy string `xml:"placement>tenancy"` // (VPC only) Valid values: default | dedicated
+ InstanceLifecycle string `xml:"instanceLifecycle"` // Spot instance? Valid values: "spot" or blank
+ SpotInstanceRequestId string `xml:"spotInstanceRequestId"` // The ID of the Spot Instance request
+ ClientToken string `xml:"clientToken"` // The idempotency token you provided when you launched the instance
+ ProductCodes []ProductCode `xml:"productCodes>item"` // The product codes attached to this instance
+
+ // Storage
+ RootDeviceType string `xml:"rootDeviceType"` // Valid values: ebs | instance-store
+ RootDeviceName string `xml:"rootDeviceName"` // The root device name (for example, /dev/sda1)
+ BlockDevices []BlockDevice `xml:"blockDeviceMapping>item"` // Any block device mapping entries for the instance
+ EbsOptimized bool `xml:"ebsOptimized"` // Indicates whether the instance is optimized for Amazon EBS I/O
+
+ // Network
+ DNSName string `xml:"dnsName"` // The public DNS name assigned to the instance. This element remains empty until the instance enters the running state
+ PrivateDNSName string `xml:"privateDnsName"` // The private DNS name assigned to the instance. This DNS name can only be used inside the Amazon EC2 network. This element remains empty until the instance enters the running state
+ IPAddress string `xml:"ipAddress"` // The public IP address assigned to the instance
+ PrivateIPAddress string `xml:"privateIpAddress"` // The private IP address assigned to the instance
+ SubnetId string `xml:"subnetId"` // The ID of the subnet in which the instance is running
+ VpcId string `xml:"vpcId"` // The ID of the VPC in which the instance is running
+ SecurityGroups []SecurityGroup `xml:"groupSet>item"` // A list of the security groups for the instance
+
+ // Advanced Networking
+ NetworkInterfaces []InstanceNetworkInterface `xml:"networkInterfaceSet>item"` // (VPC) One or more network interfaces for the instance
+ SourceDestCheck bool `xml:"sourceDestCheck"` // Controls whether source/destination checking is enabled on the instance
+ SriovNetSupport string `xml:"sriovNetSupport"` // Specifies whether enhanced networking is enabled. Valid values: simple
+}
+
+// isSpotInstance returns if the instance is a spot instance
+func (i Instance) IsSpotInstance() bool {
+ if i.InstanceLifecycle == "spot" {
+ return true
+ }
+ return false
+}
+
+type BlockDevice struct {
+ DeviceName string `xml:"deviceName"`
+ EBS EBS `xml:"ebs"`
+}
+
+type EBS struct {
+ VolumeId string `xml:"volumeId"`
+ Status string `xml:"status"`
+ AttachTime string `xml:"attachTime"`
+ DeleteOnTermination bool `xml:"deleteOnTermination"`
+}
+
+// ProductCode represents a product code
+// See http://goo.gl/hswmQm for more details.
+type ProductCode struct {
+ ProductCode string `xml:"productCode"` // The product code
+ Type string `xml:"type"` // Valid values: devpay | marketplace
+}
+
+// InstanceNetworkInterface represents a network interface attached to an instance
+// See http://goo.gl/9eW02N for more details.
+type InstanceNetworkInterface struct {
+ Id string `xml:"networkInterfaceId"`
+ Description string `xml:"description"`
+ SubnetId string `xml:"subnetId"`
+ VpcId string `xml:"vpcId"`
+ OwnerId string `xml:"ownerId"` // The ID of the AWS account that created the network interface.
+ Status string `xml:"status"` // Valid values: available | attaching | in-use | detaching
+ MacAddress string `xml:"macAddress"`
+ PrivateIPAddress string `xml:"privateIpAddress"`
+ PrivateDNSName string `xml:"privateDnsName"`
+ SourceDestCheck bool `xml:"sourceDestCheck"`
+ SecurityGroups []SecurityGroup `xml:"groupSet>item"`
+ Attachment InstanceNetworkInterfaceAttachment `xml:"attachment"`
+ Association InstanceNetworkInterfaceAssociation `xml:"association"`
+ PrivateIPAddresses []InstancePrivateIpAddress `xml:"privateIpAddressesSet>item"`
+}
+
+// InstanceNetworkInterfaceAttachment describes a network interface attachment to an instance
+// See http://goo.gl/0ql0Cg for more details
+type InstanceNetworkInterfaceAttachment struct {
+ AttachmentID string `xml:"attachmentID"` // The ID of the network interface attachment.
+ DeviceIndex int32 `xml:"deviceIndex"` // The index of the device on the instance for the network interface attachment.
+ Status string `xml:"status"` // Valid values: attaching | attached | detaching | detached
+ AttachTime string `xml:"attachTime"` // Time attached, as a Datetime
+ DeleteOnTermination bool `xml:"deleteOnTermination"` // Indicates whether the network interface is deleted when the instance is terminated.
+}
+
+// Describes association information for an Elastic IP address.
+// See http://goo.gl/YCDdMe for more details
+type InstanceNetworkInterfaceAssociation struct {
+ PublicIP string `xml:"publicIp"` // The address of the Elastic IP address bound to the network interface
+ PublicDNSName string `xml:"publicDnsName"` // The public DNS name
+ IPOwnerId string `xml:"ipOwnerId"` // The ID of the owner of the Elastic IP address
+}
+
+// InstancePrivateIpAddress describes a private IP address
+// See http://goo.gl/irN646 for more details
+type InstancePrivateIpAddress struct {
+ PrivateIPAddress string `xml:"privateIpAddress"` // The private IP address of the network interface
+ PrivateDNSName string `xml:"privateDnsName"` // The private DNS name
+ Primary bool `xml:"primary"` // Indicates whether this IP address is the primary private IP address of the network interface
+ Association InstanceNetworkInterfaceAssociation `xml:"association"` // The association information for an Elastic IP address for the network interface
+}
+
+// IamInstanceProfile
+// See http://goo.gl/PjyijL for more details
+type IamInstanceProfile struct {
+ ARN string `xml:"arn"`
+ Id string `xml:"id"`
+ Name string `xml:"name"`
+}
+
+// RunInstances starts new instances in EC2.
+// If options.MinCount and options.MaxCount are both zero, a single instance
+// will be started; otherwise if options.MaxCount is zero, options.MinCount
+// will be used instead.
+//
+// See http://goo.gl/Mcm3b for more details.
+func (ec2 *EC2) RunInstances(options *RunInstancesOptions) (resp *RunInstancesResp, err error) {
+ params := makeParams("RunInstances")
+ params["ImageId"] = options.ImageId
+ params["InstanceType"] = options.InstanceType
+ var min, max int
+ if options.MinCount == 0 && options.MaxCount == 0 {
+ min = 1
+ max = 1
+ } else if options.MaxCount == 0 {
+ min = options.MinCount
+ max = min
+ } else {
+ min = options.MinCount
+ max = options.MaxCount
+ }
+ params["MinCount"] = strconv.Itoa(min)
+ params["MaxCount"] = strconv.Itoa(max)
+ token, err := clientToken()
+ if err != nil {
+ return nil, err
+ }
+ params["ClientToken"] = token
+
+ if options.KeyName != "" {
+ params["KeyName"] = options.KeyName
+ }
+ if options.KernelId != "" {
+ params["KernelId"] = options.KernelId
+ }
+ if options.RamdiskId != "" {
+ params["RamdiskId"] = options.RamdiskId
+ }
+ if options.UserData != nil {
+ userData := make([]byte, b64.EncodedLen(len(options.UserData)))
+ b64.Encode(userData, options.UserData)
+ params["UserData"] = string(userData)
+ }
+ if options.AvailabilityZone != "" {
+ params["Placement.AvailabilityZone"] = options.AvailabilityZone
+ }
+ if options.PlacementGroupName != "" {
+ params["Placement.GroupName"] = options.PlacementGroupName
+ }
+ if options.Tenancy != "" {
+ params["Placement.Tenancy"] = options.Tenancy
+ }
+ if options.Monitoring {
+ params["Monitoring.Enabled"] = "true"
+ }
+ if options.SubnetId != "" && options.AssociatePublicIpAddress {
+ // If we have a non-default VPC / Subnet specified, we can flag
+ // AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
+ // You cannot specify both SubnetId and the NetworkInterface.0.* parameters though, otherwise
+ // you get: Network interfaces and an instance-level subnet ID may not be specified on the same request
+ // You also need to attach Security Groups to the NetworkInterface instead of the instance,
+ // to avoid: Network interfaces and an instance-level security groups may not be specified on
+ // the same request
+ params["NetworkInterface.0.DeviceIndex"] = "0"
+ params["NetworkInterface.0.AssociatePublicIpAddress"] = "true"
+ params["NetworkInterface.0.SubnetId"] = options.SubnetId
+
+ i := 1
+ for _, g := range options.SecurityGroups {
+ // We only have SecurityGroupId's on NetworkInterface's, no SecurityGroup params.
+ if g.Id != "" {
+ params["NetworkInterface.0.SecurityGroupId."+strconv.Itoa(i)] = g.Id
+ i++
+ }
+ }
+ } else {
+ if options.SubnetId != "" {
+ params["SubnetId"] = options.SubnetId
+ }
+
+ i, j := 1, 1
+ for _, g := range options.SecurityGroups {
+ if g.Id != "" {
+ params["SecurityGroupId."+strconv.Itoa(i)] = g.Id
+ i++
+ } else {
+ params["SecurityGroup."+strconv.Itoa(j)] = g.Name
+ j++
+ }
+ }
+ }
+ if options.IamInstanceProfile.ARN != "" {
+ params["IamInstanceProfile.Arn"] = options.IamInstanceProfile.ARN
+ }
+ if options.IamInstanceProfile.Name != "" {
+ params["IamInstanceProfile.Name"] = options.IamInstanceProfile.Name
+ }
+ if options.DisableAPITermination {
+ params["DisableApiTermination"] = "true"
+ }
+ if options.ShutdownBehavior != "" {
+ params["InstanceInitiatedShutdownBehavior"] = options.ShutdownBehavior
+ }
+ if options.PrivateIPAddress != "" {
+ params["PrivateIpAddress"] = options.PrivateIPAddress
+ }
+ if options.EbsOptimized {
+ params["EbsOptimized"] = "true"
+ }
+
+ addBlockDeviceParams("", params, options.BlockDevices)
+
+ resp = &RunInstancesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+func clientToken() (string, error) {
+ // Maximum EC2 client token size is 64 bytes.
+ // Each byte expands to two when hex encoded.
+ buf := make([]byte, 32)
+ _, err := rand.Read(buf)
+ if err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(buf), nil
+}
+
+// ----------------------------------------------------------------------------
+// Spot Instance management functions and types.
+
+// The RequestSpotInstances type encapsulates options for the respective request in EC2.
+//
+// See http://goo.gl/GRZgCD for more details.
+type RequestSpotInstances struct {
+ SpotPrice string
+ InstanceCount int
+ Type string
+ ImageId string
+ KeyName string
+ InstanceType string
+ SecurityGroups []SecurityGroup
+ IamInstanceProfile string
+ KernelId string
+ RamdiskId string
+ UserData []byte
+ AvailZone string
+ PlacementGroupName string
+ Monitoring bool
+ SubnetId string
+ AssociatePublicIpAddress bool
+ PrivateIPAddress string
+ BlockDevices []BlockDeviceMapping
+}
+
+type SpotInstanceSpec struct {
+ ImageId string
+ KeyName string
+ InstanceType string
+ SecurityGroups []SecurityGroup
+ IamInstanceProfile string
+ KernelId string
+ RamdiskId string
+ UserData []byte
+ AvailZone string
+ PlacementGroupName string
+ Monitoring bool
+ SubnetId string
+ AssociatePublicIpAddress bool
+ PrivateIPAddress string
+ BlockDevices []BlockDeviceMapping
+}
+
+type SpotLaunchSpec struct {
+ ImageId string `xml:"imageId"`
+ KeyName string `xml:"keyName"`
+ InstanceType string `xml:"instanceType"`
+ SecurityGroups []SecurityGroup `xml:"groupSet>item"`
+ IamInstanceProfile string `xml:"iamInstanceProfile"`
+ KernelId string `xml:"kernelId"`
+ RamdiskId string `xml:"ramdiskId"`
+ PlacementGroupName string `xml:"placement>groupName"`
+ Monitoring bool `xml:"monitoring>enabled"`
+ SubnetId string `xml:"subnetId"`
+ BlockDevices []BlockDeviceMapping `xml:"blockDeviceMapping>item"`
+}
+
+type SpotRequestResult struct {
+ SpotRequestId string `xml:"spotInstanceRequestId"`
+ SpotPrice string `xml:"spotPrice"`
+ Type string `xml:"type"`
+ AvailZone string `xml:"launchedAvailabilityZone"`
+ InstanceId string `xml:"instanceId"`
+ State string `xml:"state"`
+ SpotLaunchSpec SpotLaunchSpec `xml:"launchSpecification"`
+ CreateTime string `xml:"createTime"`
+ Tags []Tag `xml:"tagSet>item"`
+}
+
+// Response to a RequestSpotInstances request.
+//
+// See http://goo.gl/GRZgCD for more details.
+type RequestSpotInstancesResp struct {
+ RequestId string `xml:"requestId"`
+ SpotRequestResults []SpotRequestResult `xml:"spotInstanceRequestSet>item"`
+}
+
+// RequestSpotInstances requests a new spot instances in EC2.
+func (ec2 *EC2) RequestSpotInstances(options *RequestSpotInstances) (resp *RequestSpotInstancesResp, err error) {
+ params := makeParams("RequestSpotInstances")
+ prefix := "LaunchSpecification" + "."
+
+ params["SpotPrice"] = options.SpotPrice
+ params[prefix+"ImageId"] = options.ImageId
+ params[prefix+"InstanceType"] = options.InstanceType
+
+ if options.InstanceCount != 0 {
+ params["InstanceCount"] = strconv.Itoa(options.InstanceCount)
+ }
+ if options.KeyName != "" {
+ params[prefix+"KeyName"] = options.KeyName
+ }
+ if options.KernelId != "" {
+ params[prefix+"KernelId"] = options.KernelId
+ }
+ if options.RamdiskId != "" {
+ params[prefix+"RamdiskId"] = options.RamdiskId
+ }
+ if options.UserData != nil {
+ userData := make([]byte, b64.EncodedLen(len(options.UserData)))
+ b64.Encode(userData, options.UserData)
+ params[prefix+"UserData"] = string(userData)
+ }
+ if options.AvailZone != "" {
+ params[prefix+"Placement.AvailabilityZone"] = options.AvailZone
+ }
+ if options.PlacementGroupName != "" {
+ params[prefix+"Placement.GroupName"] = options.PlacementGroupName
+ }
+ if options.Monitoring {
+ params[prefix+"Monitoring.Enabled"] = "true"
+ }
+ if options.SubnetId != "" && options.AssociatePublicIpAddress {
+ // If we have a non-default VPC / Subnet specified, we can flag
+ // AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
+ // You cannot specify both SubnetId and the NetworkInterface.0.* parameters though, otherwise
+ // you get: Network interfaces and an instance-level subnet ID may not be specified on the same request
+ // You also need to attach Security Groups to the NetworkInterface instead of the instance,
+ // to avoid: Network interfaces and an instance-level security groups may not be specified on
+ // the same request
+ params[prefix+"NetworkInterface.0.DeviceIndex"] = "0"
+ params[prefix+"NetworkInterface.0.AssociatePublicIpAddress"] = "true"
+ params[prefix+"NetworkInterface.0.SubnetId"] = options.SubnetId
+
+ i := 1
+ for _, g := range options.SecurityGroups {
+ // We only have SecurityGroupId's on NetworkInterface's, no SecurityGroup params.
+ if g.Id != "" {
+ params[prefix+"NetworkInterface.0.SecurityGroupId."+strconv.Itoa(i)] = g.Id
+ i++
+ }
+ }
+ } else {
+ if options.SubnetId != "" {
+ params[prefix+"SubnetId"] = options.SubnetId
+ }
+
+ i, j := 1, 1
+ for _, g := range options.SecurityGroups {
+ if g.Id != "" {
+ params[prefix+"SecurityGroupId."+strconv.Itoa(i)] = g.Id
+ i++
+ } else {
+ params[prefix+"SecurityGroup."+strconv.Itoa(j)] = g.Name
+ j++
+ }
+ }
+ }
+ if options.IamInstanceProfile != "" {
+ params[prefix+"IamInstanceProfile.Name"] = options.IamInstanceProfile
+ }
+ if options.PrivateIPAddress != "" {
+ params[prefix+"PrivateIpAddress"] = options.PrivateIPAddress
+ }
+ addBlockDeviceParams(prefix, params, options.BlockDevices)
+
+ resp = &RequestSpotInstancesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Response to a DescribeSpotInstanceRequests request.
+//
+// See http://goo.gl/KsKJJk for more details.
+type SpotRequestsResp struct {
+ RequestId string `xml:"requestId"`
+ SpotRequestResults []SpotRequestResult `xml:"spotInstanceRequestSet>item"`
+}
+
+// DescribeSpotInstanceRequests returns details about spot requests in EC2. Both parameters
+// are optional, and if provided will limit the spot requests returned to those
+// matching the given spot request ids or filtering rules.
+//
+// See http://goo.gl/KsKJJk for more details.
+func (ec2 *EC2) DescribeSpotRequests(spotrequestIds []string, filter *Filter) (resp *SpotRequestsResp, err error) {
+ params := makeParams("DescribeSpotInstanceRequests")
+ addParamsList(params, "SpotInstanceRequestId", spotrequestIds)
+ filter.addParams(params)
+ resp = &SpotRequestsResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Response to a CancelSpotInstanceRequests request.
+//
+// See http://goo.gl/3BKHj for more details.
+type CancelSpotRequestResult struct {
+ SpotRequestId string `xml:"spotInstanceRequestId"`
+ State string `xml:"state"`
+}
+type CancelSpotRequestsResp struct {
+ RequestId string `xml:"requestId"`
+ CancelSpotRequestResults []CancelSpotRequestResult `xml:"spotInstanceRequestSet>item"`
+}
+
+// CancelSpotRequests requests the cancellation of spot requests when the given ids.
+//
+// See http://goo.gl/3BKHj for more details.
+func (ec2 *EC2) CancelSpotRequests(spotrequestIds []string) (resp *CancelSpotRequestsResp, err error) {
+ params := makeParams("CancelSpotInstanceRequests")
+ addParamsList(params, "SpotInstanceRequestId", spotrequestIds)
+ resp = &CancelSpotRequestsResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Response to a TerminateInstances request.
+//
+// See http://goo.gl/3BKHj for more details.
+type TerminateInstancesResp struct {
+ RequestId string `xml:"requestId"`
+ StateChanges []InstanceStateChange `xml:"instancesSet>item"`
+}
+
+// InstanceState encapsulates the state of an instance in EC2.
+//
+// See http://goo.gl/y3ZBq for more details.
+type InstanceState struct {
+ Code int `xml:"code"` // Watch out, bits 15-8 have unpublished meaning.
+ Name string `xml:"name"`
+}
+
+// InstanceStateChange informs of the previous and current states
+// for an instance when a state change is requested.
+type InstanceStateChange struct {
+ InstanceId string `xml:"instanceId"`
+ CurrentState InstanceState `xml:"currentState"`
+ PreviousState InstanceState `xml:"previousState"`
+}
+
+// InstanceStateReason describes a state change for an instance in EC2
+//
+// See http://goo.gl/KZkbXi for more details
+type InstanceStateReason struct {
+ Code string `xml:"code"`
+ Message string `xml:"message"`
+}
+
+// TerminateInstances requests the termination of instances when the given ids.
+//
+// See http://goo.gl/3BKHj for more details.
+func (ec2 *EC2) TerminateInstances(instIds []string) (resp *TerminateInstancesResp, err error) {
+ params := makeParams("TerminateInstances")
+ addParamsList(params, "InstanceId", instIds)
+ resp = &TerminateInstancesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Response to a DescribeInstances request.
+//
+// See http://goo.gl/mLbmw for more details.
+type DescribeInstancesResp struct {
+ RequestId string `xml:"requestId"`
+ Reservations []Reservation `xml:"reservationSet>item"`
+}
+
+// Reservation represents details about a reservation in EC2.
+//
+// See http://goo.gl/0ItPT for more details.
+type Reservation struct {
+ ReservationId string `xml:"reservationId"`
+ OwnerId string `xml:"ownerId"`
+ RequesterId string `xml:"requesterId"`
+ SecurityGroups []SecurityGroup `xml:"groupSet>item"`
+ Instances []Instance `xml:"instancesSet>item"`
+}
+
+// Instances returns details about instances in EC2. Both parameters
+// are optional, and if provided will limit the instances returned to those
+// matching the given instance ids or filtering rules.
+//
+// See http://goo.gl/4No7c for more details.
+func (ec2 *EC2) DescribeInstances(instIds []string, filter *Filter) (resp *DescribeInstancesResp, err error) {
+ params := makeParams("DescribeInstances")
+ addParamsList(params, "InstanceId", instIds)
+ filter.addParams(params)
+ resp = &DescribeInstancesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ // Add additional parameters to instances which aren't available in the response
+ for i, rsv := range resp.Reservations {
+ ownerId := rsv.OwnerId
+ for j, inst := range rsv.Instances {
+ inst.OwnerId = ownerId
+ resp.Reservations[i].Instances[j] = inst
+ }
+ }
+
+ return
+}
+
+// DescribeInstanceStatusOptions encapsulates the query parameters for the corresponding action.
+//
+// See http:////goo.gl/2FBTdS for more details.
+type DescribeInstanceStatusOptions struct {
+ InstanceIds []string // If non-empty, limit the query to this subset of instances. Maximum length of 100.
+ IncludeAllInstances bool // If true, describe all instances, instead of just running instances (the default).
+ MaxResults int // Maximum number of results to return. Minimum of 5. Maximum of 1000.
+ NextToken string // The token for the next set of items to return. (You received this token from a prior call.)
+}
+
+// Response to a DescribeInstanceStatus request.
+//
+// See http://goo.gl/2FBTdS for more details.
+type DescribeInstanceStatusResp struct {
+ RequestId string `xml:"requestId"`
+ InstanceStatusSet []InstanceStatusItem `xml:"instanceStatusSet>item"`
+ NextToken string `xml:"nextToken"`
+}
+
+// InstanceStatusItem describes the instance status, cause, details, and potential actions to take in response.
+//
+// See http://goo.gl/oImFZZ for more details.
+type InstanceStatusItem struct {
+ InstanceId string `xml:"instanceId"`
+ AvailabilityZone string `xml:"availabilityZone"`
+ Events []InstanceStatusEvent `xml:"eventsSet>item"` // Extra information regarding events associated with the instance.
+ InstanceState InstanceState `xml:"instanceState"` // The intended state of the instance. Calls to DescribeInstanceStatus require that an instance be in the running state.
+ SystemStatus InstanceStatus `xml:"systemStatus"`
+ InstanceStatus InstanceStatus `xml:"instanceStatus"`
+}
+
+// InstanceStatusEvent describes an instance event.
+//
+// See http://goo.gl/PXsDTn for more details.
+type InstanceStatusEvent struct {
+ Code string `xml:"code"` // The associated code of the event.
+ Description string `xml:"description"` // A description of the event.
+ NotBefore string `xml:"notBefore"` // The earliest scheduled start time for the event.
+ NotAfter string `xml:"notAfter"` // The latest scheduled end time for the event.
+}
+
+// InstanceStatus describes the status of an instance with details.
+//
+// See http://goo.gl/eFch4S for more details.
+type InstanceStatus struct {
+ Status string `xml:"status"` // The instance status.
+ Details InstanceStatusDetails `xml:"details"` // The system instance health or application instance health.
+}
+
+// InstanceStatusDetails describes the instance status with the cause and more detail.
+//
+// See http://goo.gl/3qoMC4 for more details.
+type InstanceStatusDetails struct {
+ Name string `xml:"name"` // The type of instance status.
+ Status string `xml:"status"` // The status.
+ ImpairedSince string `xml:"impairedSince"` // The time when a status check failed. For an instance that was launched and impaired, this is the time when the instance was launched.
+}
+
+// DescribeInstanceStatus returns instance status information about instances in EC2.
+// instIds and filter are optional, and if provided will limit the instances returned to those
+// matching the given instance ids or filtering rules.
+// all determines whether to report all matching instances or only those in the running state
+//
+// See http://goo.gl/2FBTdS for more details.
+func (ec2 *EC2) DescribeInstanceStatus(options *DescribeInstanceStatusOptions, filter *Filter) (resp *DescribeInstanceStatusResp, err error) {
+ params := makeParams("DescribeInstanceStatus")
+ if len(options.InstanceIds) > 0 {
+ addParamsList(params, "InstanceId", options.InstanceIds)
+ }
+ if options.IncludeAllInstances {
+ params["IncludeAllInstances"] = "true"
+ }
+ if options.MaxResults != 0 {
+ params["MaxResults"] = strconv.Itoa(options.MaxResults)
+ }
+ if options.NextToken != "" {
+ params["NextToken"] = options.NextToken
+ }
+ filter.addParams(params)
+ resp = &DescribeInstanceStatusResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// KeyPair management functions and types.
+
+type CreateKeyPairResp struct {
+ RequestId string `xml:"requestId"`
+ KeyName string `xml:"keyName"`
+ KeyFingerprint string `xml:"keyFingerprint"`
+ KeyMaterial string `xml:"keyMaterial"`
+}
+
+// CreateKeyPair creates a new key pair and returns the private key contents.
+//
+// See http://goo.gl/0S6hV
+func (ec2 *EC2) CreateKeyPair(keyName string) (resp *CreateKeyPairResp, err error) {
+ params := makeParams("CreateKeyPair")
+ params["KeyName"] = keyName
+
+ resp = &CreateKeyPairResp{}
+ err = ec2.query(params, resp)
+ if err == nil {
+ resp.KeyFingerprint = strings.TrimSpace(resp.KeyFingerprint)
+ }
+ return
+}
+
+// DeleteKeyPair deletes a key pair.
+//
+// See http://goo.gl/0bqok
+func (ec2 *EC2) DeleteKeyPair(name string) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteKeyPair")
+ params["KeyName"] = name
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ return
+}
+
+type ImportKeyPairOptions struct {
+ KeyName string
+ PublicKeyMaterial string
+}
+
+type ImportKeyPairResp struct {
+ RequestId string `xml:"requestId"`
+ KeyName string `xml:"keyName"`
+ KeyFingerprint string `xml:"keyFingerprint"`
+}
+
+// ImportKeyPair import a key pair.
+//
+// See http://goo.gl/xpTccS
+func (ec2 *EC2) ImportKeyPair(options *ImportKeyPairOptions) (resp *ImportKeyPairResp, err error) {
+ params := makeParams("ImportKeyPair")
+ params["KeyName"] = options.KeyName
+ params["PublicKeyMaterial"] = options.PublicKeyMaterial
+
+ resp = &ImportKeyPairResp{}
+ err = ec2.query(params, resp)
+ return
+}
+
+// ResourceTag represents key-value metadata used to classify and organize
+// EC2 instances.
+//
+// See http://goo.gl/bncl3 for more details
+type Tag struct {
+ Key string `xml:"key"`
+ Value string `xml:"value"`
+}
+
+// CreateTags adds or overwrites one or more tags for the specified taggable resources.
+// For a list of tagable resources, see: http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/Using_Tags.html
+//
+// See http://goo.gl/Vmkqc for more details
+func (ec2 *EC2) CreateTags(resourceIds []string, tags []Tag) (resp *SimpleResp, err error) {
+ params := makeParams("CreateTags")
+ addParamsList(params, "ResourceId", resourceIds)
+
+ for j, tag := range tags {
+ params["Tag."+strconv.Itoa(j+1)+".Key"] = tag.Key
+ params["Tag."+strconv.Itoa(j+1)+".Value"] = tag.Value
+ }
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a StartInstances request.
+//
+// See http://goo.gl/awKeF for more details.
+type StartInstanceResp struct {
+ RequestId string `xml:"requestId"`
+ StateChanges []InstanceStateChange `xml:"instancesSet>item"`
+}
+
+// Response to a StopInstances request.
+//
+// See http://goo.gl/436dJ for more details.
+type StopInstanceResp struct {
+ RequestId string `xml:"requestId"`
+ StateChanges []InstanceStateChange `xml:"instancesSet>item"`
+}
+
+// StartInstances starts an Amazon EBS-backed AMI that you've previously stopped.
+//
+// See http://goo.gl/awKeF for more details.
+func (ec2 *EC2) StartInstances(ids ...string) (resp *StartInstanceResp, err error) {
+ params := makeParams("StartInstances")
+ addParamsList(params, "InstanceId", ids)
+ resp = &StartInstanceResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StopInstances requests stopping one or more Amazon EBS-backed instances.
+//
+// See http://goo.gl/436dJ for more details.
+func (ec2 *EC2) StopInstances(ids ...string) (resp *StopInstanceResp, err error) {
+ params := makeParams("StopInstances")
+ addParamsList(params, "InstanceId", ids)
+ resp = &StopInstanceResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// RebootInstance requests a reboot of one or more instances. This operation is asynchronous;
+// it only queues a request to reboot the specified instance(s). The operation will succeed
+// if the instances are valid and belong to you.
+//
+// Requests to reboot terminated instances are ignored.
+//
+// See http://goo.gl/baoUf for more details.
+func (ec2 *EC2) RebootInstances(ids ...string) (resp *SimpleResp, err error) {
+ params := makeParams("RebootInstances")
+ addParamsList(params, "InstanceId", ids)
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// The ModifyInstanceAttribute request parameters.
+type ModifyInstance struct {
+ InstanceType string
+ BlockDevices []BlockDeviceMapping
+ DisableAPITermination bool
+ EbsOptimized bool
+ SecurityGroups []SecurityGroup
+ ShutdownBehavior string
+ KernelId string
+ RamdiskId string
+ SourceDestCheck bool
+ SriovNetSupport bool
+ UserData []byte
+}
+
+// Response to a ModifyInstanceAttribute request.
+//
+// http://goo.gl/icuXh5 for more details.
+type ModifyInstanceResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
+// ModifyImageAttribute modifies the specified attribute of the specified instance.
+// You can specify only one attribute at a time. To modify some attributes, the
+// instance must be stopped.
+//
+// See http://goo.gl/icuXh5 for more details.
+func (ec2 *EC2) ModifyInstance(instId string, options *ModifyInstance) (resp *ModifyInstanceResp, err error) {
+ params := makeParams("ModifyInstanceAttribute")
+ params["InstanceId"] = instId
+ addBlockDeviceParams("", params, options.BlockDevices)
+
+ if options.InstanceType != "" {
+ params["InstanceType.Value"] = options.InstanceType
+ }
+
+ if options.DisableAPITermination {
+ params["DisableApiTermination.Value"] = "true"
+ }
+
+ if options.EbsOptimized {
+ params["EbsOptimized"] = "true"
+ }
+
+ if options.ShutdownBehavior != "" {
+ params["InstanceInitiatedShutdownBehavior.Value"] = options.ShutdownBehavior
+ }
+
+ if options.KernelId != "" {
+ params["Kernel.Value"] = options.KernelId
+ }
+
+ if options.RamdiskId != "" {
+ params["Ramdisk.Value"] = options.RamdiskId
+ }
+
+ if options.SourceDestCheck {
+ params["SourceDestCheck.Value"] = "true"
+ }
+
+ if options.SriovNetSupport {
+ params["SriovNetSupport.Value"] = "simple"
+ }
+
+ if options.UserData != nil {
+ userData := make([]byte, b64.EncodedLen(len(options.UserData)))
+ b64.Encode(userData, options.UserData)
+ params["UserData"] = string(userData)
+ }
+
+ i := 1
+ for _, g := range options.SecurityGroups {
+ if g.Id != "" {
+ params["GroupId."+strconv.Itoa(i)] = g.Id
+ i++
+ }
+ }
+
+ resp = &ModifyInstanceResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ resp = nil
+ }
+ return
+}
+
+// Reserved Instances
+
+// Structures
+
+// DescribeReservedInstancesResponse structure returned from a DescribeReservedInstances request.
+//
+// See
+type DescribeReservedInstancesResponse struct {
+ RequestId string `xml:"requestId"`
+ ReservedInstances []ReservedInstancesResponseItem `xml:"reservedInstancesSet>item"`
+}
+
+//
+//
+// See
+type ReservedInstancesResponseItem struct {
+ ReservedInstanceId string `xml:"reservedInstancesId"`
+ InstanceType string `xml:"instanceType"`
+ AvailabilityZone string `xml:"availabilityZone"`
+ Start string `xml:"start"`
+ Duration uint64 `xml:"duration"`
+ End string `xml:"end"`
+ FixedPrice float32 `xml:"fixedPrice"`
+ UsagePrice float32 `xml:"usagePrice"`
+ InstanceCount int `xml:"instanceCount"`
+ ProductDescription string `xml:"productDescription"`
+ State string `xml:"state"`
+ Tags []Tag `xml:"tagSet->item"`
+ InstanceTenancy string `xml:"instanceTenancy"`
+ CurrencyCode string `xml:"currencyCode"`
+ OfferingType string `xml:"offeringType"`
+ RecurringCharges []RecurringCharge `xml:"recurringCharges>item"`
+}
+
+//
+//
+// See
+type RecurringCharge struct {
+ Frequency string `xml:"frequency"`
+ Amount float32 `xml:"amount"`
+}
+
+// functions
+// DescribeReservedInstances
+//
+// See
+func (ec2 *EC2) DescribeReservedInstances(instIds []string, filter *Filter) (resp *DescribeReservedInstancesResponse, err error) {
+ params := makeParams("DescribeReservedInstances")
+
+ for i, id := range instIds {
+ params["ReservedInstancesId."+strconv.Itoa(i+1)] = id
+ }
+ filter.addParams(params)
+
+ resp = &DescribeReservedInstancesResponse{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ----------------------------------------------------------------------------
+// Image and snapshot management functions and types.
+
+// The CreateImage request parameters.
+//
+// See http://goo.gl/cxU41 for more details.
+type CreateImage struct {
+ InstanceId string
+ Name string
+ Description string
+ NoReboot bool
+ BlockDevices []BlockDeviceMapping
+}
+
+// Response to a CreateImage request.
+//
+// See http://goo.gl/cxU41 for more details.
+type CreateImageResp struct {
+ RequestId string `xml:"requestId"`
+ ImageId string `xml:"imageId"`
+}
+
+// Response to a DescribeImages request.
+//
+// See http://goo.gl/hLnyg for more details.
+type ImagesResp struct {
+ RequestId string `xml:"requestId"`
+ Images []Image `xml:"imagesSet>item"`
+}
+
+// Response to a DescribeImageAttribute request.
+//
+// See http://goo.gl/bHO3zT for more details.
+type ImageAttributeResp struct {
+ RequestId string `xml:"requestId"`
+ ImageId string `xml:"imageId"`
+ Kernel string `xml:"kernel>value"`
+ RamDisk string `xml:"ramdisk>value"`
+ Description string `xml:"description>value"`
+ Group string `xml:"launchPermission>item>group"`
+ UserIds []string `xml:"launchPermission>item>userId"`
+ ProductCodes []string `xml:"productCodes>item>productCode"`
+ BlockDevices []BlockDeviceMapping `xml:"blockDeviceMapping>item"`
+}
+
+// The RegisterImage request parameters.
+type RegisterImage struct {
+ ImageLocation string
+ Name string
+ Description string
+ Architecture string
+ KernelId string
+ RamdiskId string
+ RootDeviceName string
+ VirtType string
+ BlockDevices []BlockDeviceMapping
+}
+
+// Response to a RegisterImage request.
+type RegisterImageResp struct {
+ RequestId string `xml:"requestId"`
+ ImageId string `xml:"imageId"`
+}
+
+// Response to a DegisterImage request.
+//
+// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DeregisterImage.html
+type DeregisterImageResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
+// BlockDeviceMapping represents the association of a block device with an image.
+//
+// See http://goo.gl/wnDBf for more details.
+type BlockDeviceMapping struct {
+ DeviceName string `xml:"deviceName"`
+ VirtualName string `xml:"virtualName"`
+ SnapshotId string `xml:"ebs>snapshotId"`
+ VolumeType string `xml:"ebs>volumeType"`
+ VolumeSize int64 `xml:"ebs>volumeSize"`
+ DeleteOnTermination bool `xml:"ebs>deleteOnTermination"`
+ NoDevice bool `xml:"noDevice"`
+
+ // The number of I/O operations per second (IOPS) that the volume supports.
+ IOPS int64 `xml:"ebs>iops"`
+}
+
+// Image represents details about an image.
+//
+// See http://goo.gl/iSqJG for more details.
+type Image struct {
+ Id string `xml:"imageId"`
+ Name string `xml:"name"`
+ Description string `xml:"description"`
+ Type string `xml:"imageType"`
+ State string `xml:"imageState"`
+ Location string `xml:"imageLocation"`
+ Public bool `xml:"isPublic"`
+ Architecture string `xml:"architecture"`
+ Platform string `xml:"platform"`
+ ProductCodes []string `xml:"productCode>item>productCode"`
+ KernelId string `xml:"kernelId"`
+ RamdiskId string `xml:"ramdiskId"`
+ StateReason string `xml:"stateReason"`
+ OwnerId string `xml:"imageOwnerId"`
+ OwnerAlias string `xml:"imageOwnerAlias"`
+ RootDeviceType string `xml:"rootDeviceType"`
+ RootDeviceName string `xml:"rootDeviceName"`
+ VirtualizationType string `xml:"virtualizationType"`
+ Hypervisor string `xml:"hypervisor"`
+ BlockDevices []BlockDeviceMapping `xml:"blockDeviceMapping>item"`
+ Tags []Tag `xml:"tagSet>item"`
+}
+
+// The ModifyImageAttribute request parameters.
+type ModifyImageAttribute struct {
+ AddUsers []string
+ RemoveUsers []string
+ AddGroups []string
+ RemoveGroups []string
+ ProductCodes []string
+ Description string
+}
+
+// The CopyImage request parameters.
+//
+// See http://goo.gl/hQwPCK for more details.
+type CopyImage struct {
+ SourceRegion string
+ SourceImageId string
+ Name string
+ Description string
+ ClientToken string
+}
+
+// Response to a CopyImage request.
+//
+// See http://goo.gl/hQwPCK for more details.
+type CopyImageResp struct {
+ RequestId string `xml:"requestId"`
+ ImageId string `xml:"imageId"`
+}
+
+// Creates an Amazon EBS-backed AMI from an Amazon EBS-backed instance
+// that is either running or stopped.
+//
+// See http://goo.gl/cxU41 for more details.
+func (ec2 *EC2) CreateImage(options *CreateImage) (resp *CreateImageResp, err error) {
+ params := makeParams("CreateImage")
+ params["InstanceId"] = options.InstanceId
+ params["Name"] = options.Name
+ if options.Description != "" {
+ params["Description"] = options.Description
+ }
+ if options.NoReboot {
+ params["NoReboot"] = "true"
+ }
+ addBlockDeviceParams("", params, options.BlockDevices)
+
+ resp = &CreateImageResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// Images returns details about available images.
+// The ids and filter parameters, if provided, will limit the images returned.
+// For example, to get all the private images associated with this account set
+// the boolean filter "is-public" to 0.
+// For list of filters: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html
+//
+// Note: calling this function with nil ids and filter parameters will result in
+// a very large number of images being returned.
+//
+// See http://goo.gl/SRBhW for more details.
+func (ec2 *EC2) Images(ids []string, filter *Filter) (resp *ImagesResp, err error) {
+ params := makeParams("DescribeImages")
+ for i, id := range ids {
+ params["ImageId."+strconv.Itoa(i+1)] = id
+ }
+ filter.addParams(params)
+
+ resp = &ImagesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ImagesByOwners returns details about available images.
+// The ids, owners, and filter parameters, if provided, will limit the images returned.
+// For example, to get all the private images associated with this account set
+// the boolean filter "is-public" to 0.
+// For list of filters: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html
+//
+// Note: calling this function with nil ids and filter parameters will result in
+// a very large number of images being returned.
+//
+// See http://goo.gl/SRBhW for more details.
+func (ec2 *EC2) ImagesByOwners(ids []string, owners []string, filter *Filter) (resp *ImagesResp, err error) {
+ params := makeParams("DescribeImages")
+ for i, id := range ids {
+ params["ImageId."+strconv.Itoa(i+1)] = id
+ }
+ for i, owner := range owners {
+ params[fmt.Sprintf("Owner.%d", i+1)] = owner
+ }
+
+ filter.addParams(params)
+
+ resp = &ImagesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ImageAttribute describes an attribute of an AMI.
+// You can specify only one attribute at a time.
+// Valid attributes are:
+// description | kernel | ramdisk | launchPermission | productCodes | blockDeviceMapping
+//
+// See http://goo.gl/bHO3zT for more details.
+func (ec2 *EC2) ImageAttribute(imageId, attribute string) (resp *ImageAttributeResp, err error) {
+ params := makeParams("DescribeImageAttribute")
+ params["ImageId"] = imageId
+ params["Attribute"] = attribute
+
+ resp = &ImageAttributeResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ModifyImageAttribute sets attributes for an image.
+//
+// See http://goo.gl/YUjO4G for more details.
+func (ec2 *EC2) ModifyImageAttribute(imageId string, options *ModifyImageAttribute) (resp *SimpleResp, err error) {
+ params := makeParams("ModifyImageAttribute")
+ params["ImageId"] = imageId
+ if options.Description != "" {
+ params["Description.Value"] = options.Description
+ }
+
+ if options.AddUsers != nil {
+ for i, user := range options.AddUsers {
+ p := fmt.Sprintf("LaunchPermission.Add.%d.UserId", i+1)
+ params[p] = user
+ }
+ }
+
+ if options.RemoveUsers != nil {
+ for i, user := range options.RemoveUsers {
+ p := fmt.Sprintf("LaunchPermission.Remove.%d.UserId", i+1)
+ params[p] = user
+ }
+ }
+
+ if options.AddGroups != nil {
+ for i, group := range options.AddGroups {
+ p := fmt.Sprintf("LaunchPermission.Add.%d.Group", i+1)
+ params[p] = group
+ }
+ }
+
+ if options.RemoveGroups != nil {
+ for i, group := range options.RemoveGroups {
+ p := fmt.Sprintf("LaunchPermission.Remove.%d.Group", i+1)
+ params[p] = group
+ }
+ }
+
+ if options.ProductCodes != nil {
+ addParamsList(params, "ProductCode", options.ProductCodes)
+ }
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ resp = nil
+ }
+
+ return
+}
+
+// Registers a new AMI with EC2.
+//
+// See: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-RegisterImage.html
+func (ec2 *EC2) RegisterImage(options *RegisterImage) (resp *RegisterImageResp, err error) {
+ params := makeParams("RegisterImage")
+ params["Name"] = options.Name
+ if options.ImageLocation != "" {
+ params["ImageLocation"] = options.ImageLocation
+ }
+
+ if options.Description != "" {
+ params["Description"] = options.Description
+ }
+
+ if options.Architecture != "" {
+ params["Architecture"] = options.Architecture
+ }
+
+ if options.KernelId != "" {
+ params["KernelId"] = options.KernelId
+ }
+
+ if options.RamdiskId != "" {
+ params["RamdiskId"] = options.RamdiskId
+ }
+
+ if options.RootDeviceName != "" {
+ params["RootDeviceName"] = options.RootDeviceName
+ }
+
+ if options.VirtType != "" {
+ params["VirtualizationType"] = options.VirtType
+ }
+
+ addBlockDeviceParams("", params, options.BlockDevices)
+
+ resp = &RegisterImageResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// Degisters an image. Note that this does not delete the backing stores of the AMI.
+//
+// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DeregisterImage.html
+func (ec2 *EC2) DeregisterImage(imageId string) (resp *DeregisterImageResp, err error) {
+ params := makeParams("DeregisterImage")
+ params["ImageId"] = imageId
+
+ resp = &DeregisterImageResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// Copy and Image from one region to another.
+//
+// See http://goo.gl/hQwPCK for more details.
+func (ec2 *EC2) CopyImage(options *CopyImage) (resp *CopyImageResp, err error) {
+ params := makeParams("CopyImage")
+
+ if options.SourceRegion != "" {
+ params["SourceRegion"] = options.SourceRegion
+ }
+
+ if options.SourceImageId != "" {
+ params["SourceImageId"] = options.SourceImageId
+ }
+
+ if options.Name != "" {
+ params["Name"] = options.Name
+ }
+
+ if options.Description != "" {
+ params["Description"] = options.Description
+ }
+
+ if options.ClientToken != "" {
+ params["ClientToken"] = options.ClientToken
+ }
+
+ resp = &CopyImageResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// Response to a CreateSnapshot request.
+//
+// See http://goo.gl/ttcda for more details.
+type CreateSnapshotResp struct {
+ RequestId string `xml:"requestId"`
+ Snapshot
+}
+
+// CreateSnapshot creates a volume snapshot and stores it in S3.
+//
+// See http://goo.gl/ttcda for more details.
+func (ec2 *EC2) CreateSnapshot(volumeId, description string) (resp *CreateSnapshotResp, err error) {
+ params := makeParams("CreateSnapshot")
+ params["VolumeId"] = volumeId
+ params["Description"] = description
+
+ resp = &CreateSnapshotResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// DeleteSnapshots deletes the volume snapshots with the given ids.
+//
+// Note: If you make periodic snapshots of a volume, the snapshots are
+// incremental so that only the blocks on the device that have changed
+// since your last snapshot are incrementally saved in the new snapshot.
+// Even though snapshots are saved incrementally, the snapshot deletion
+// process is designed so that you need to retain only the most recent
+// snapshot in order to restore the volume.
+//
+// See http://goo.gl/vwU1y for more details.
+func (ec2 *EC2) DeleteSnapshots(ids []string) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteSnapshot")
+ for i, id := range ids {
+ params["SnapshotId."+strconv.Itoa(i+1)] = id
+ }
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// Response to a DescribeSnapshots request.
+//
+// See http://goo.gl/nClDT for more details.
+type SnapshotsResp struct {
+ RequestId string `xml:"requestId"`
+ Snapshots []Snapshot `xml:"snapshotSet>item"`
+}
+
+// Snapshot represents details about a volume snapshot.
+//
+// See http://goo.gl/nkovs for more details.
+type Snapshot struct {
+ Id string `xml:"snapshotId"`
+ VolumeId string `xml:"volumeId"`
+ VolumeSize string `xml:"volumeSize"`
+ Status string `xml:"status"`
+ StartTime string `xml:"startTime"`
+ Description string `xml:"description"`
+ Progress string `xml:"progress"`
+ OwnerId string `xml:"ownerId"`
+ OwnerAlias string `xml:"ownerAlias"`
+ Tags []Tag `xml:"tagSet>item"`
+}
+
+// Snapshots returns details about volume snapshots available to the user.
+// The ids and filter parameters, if provided, limit the snapshots returned.
+//
+// See http://goo.gl/ogJL4 for more details.
+func (ec2 *EC2) Snapshots(ids []string, filter *Filter) (resp *SnapshotsResp, err error) {
+ params := makeParams("DescribeSnapshots")
+ for i, id := range ids {
+ params["SnapshotId."+strconv.Itoa(i+1)] = id
+ }
+ filter.addParams(params)
+
+ resp = &SnapshotsResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Volume management
+
+// The CreateVolume request parameters
+//
+// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-CreateVolume.html
+type CreateVolume struct {
+ AvailZone string
+ Size int64
+ SnapshotId string
+ VolumeType string
+ IOPS int64
+}
+
+// Response to an AttachVolume request
+type AttachVolumeResp struct {
+ RequestId string `xml:"requestId"`
+ VolumeId string `xml:"volumeId"`
+ InstanceId string `xml:"instanceId"`
+ Device string `xml:"device"`
+ Status string `xml:"status"`
+ AttachTime string `xml:"attachTime"`
+}
+
+// Response to a CreateVolume request
+type CreateVolumeResp struct {
+ RequestId string `xml:"requestId"`
+ VolumeId string `xml:"volumeId"`
+ Size int64 `xml:"size"`
+ SnapshotId string `xml:"snapshotId"`
+ AvailZone string `xml:"availabilityZone"`
+ Status string `xml:"status"`
+ CreateTime string `xml:"createTime"`
+ VolumeType string `xml:"volumeType"`
+ IOPS int64 `xml:"iops"`
+}
+
+// Volume is a single volume.
+type Volume struct {
+ VolumeId string `xml:"volumeId"`
+ Size string `xml:"size"`
+ SnapshotId string `xml:"snapshotId"`
+ AvailZone string `xml:"availabilityZone"`
+ Status string `xml:"status"`
+ Attachments []VolumeAttachment `xml:"attachmentSet>item"`
+ VolumeType string `xml:"volumeType"`
+ IOPS int64 `xml:"iops"`
+ Tags []Tag `xml:"tagSet>item"`
+}
+
+type VolumeAttachment struct {
+ VolumeId string `xml:"volumeId"`
+ InstanceId string `xml:"instanceId"`
+ Device string `xml:"device"`
+ Status string `xml:"status"`
+}
+
+// Response to a DescribeVolumes request
+type VolumesResp struct {
+ RequestId string `xml:"requestId"`
+ Volumes []Volume `xml:"volumeSet>item"`
+}
+
+// Attach a volume.
+func (ec2 *EC2) AttachVolume(volumeId string, instanceId string, device string) (resp *AttachVolumeResp, err error) {
+ params := makeParams("AttachVolume")
+ params["VolumeId"] = volumeId
+ params["InstanceId"] = instanceId
+ params["Device"] = device
+
+ resp = &AttachVolumeResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
+// Create a new volume.
+func (ec2 *EC2) CreateVolume(options *CreateVolume) (resp *CreateVolumeResp, err error) {
+ params := makeParams("CreateVolume")
+ params["AvailabilityZone"] = options.AvailZone
+ if options.Size > 0 {
+ params["Size"] = strconv.FormatInt(options.Size, 10)
+ }
+
+ if options.SnapshotId != "" {
+ params["SnapshotId"] = options.SnapshotId
+ }
+
+ if options.VolumeType != "" {
+ params["VolumeType"] = options.VolumeType
+ }
+
+ if options.IOPS > 0 {
+ params["Iops"] = strconv.FormatInt(options.IOPS, 10)
+ }
+
+ resp = &CreateVolumeResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Delete an EBS volume.
+func (ec2 *EC2) DeleteVolume(id string) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteVolume")
+ params["VolumeId"] = id
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Detaches an EBS volume.
+func (ec2 *EC2) DetachVolume(id string) (resp *SimpleResp, err error) {
+ params := makeParams("DetachVolume")
+ params["VolumeId"] = id
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Finds or lists all volumes.
+func (ec2 *EC2) Volumes(volIds []string, filter *Filter) (resp *VolumesResp, err error) {
+ params := makeParams("DescribeVolumes")
+ addParamsList(params, "VolumeId", volIds)
+ filter.addParams(params)
+ resp = &VolumesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Security group management functions and types.
+
+// SimpleResp represents a response to an EC2 request which on success will
+// return no other information besides a request id.
+type SimpleResp struct {
+ XMLName xml.Name
+ RequestId string `xml:"requestId"`
+}
+
+// CreateSecurityGroupResp represents a response to a CreateSecurityGroup request.
+type CreateSecurityGroupResp struct {
+ SecurityGroup
+ RequestId string `xml:"requestId"`
+}
+
+// CreateSecurityGroup run a CreateSecurityGroup request in EC2, with the provided
+// name and description.
+//
+// See http://goo.gl/Eo7Yl for more details.
+func (ec2 *EC2) CreateSecurityGroup(group SecurityGroup) (resp *CreateSecurityGroupResp, err error) {
+ params := makeParams("CreateSecurityGroup")
+ params["GroupName"] = group.Name
+ params["GroupDescription"] = group.Description
+ if group.VpcId != "" {
+ params["VpcId"] = group.VpcId
+ }
+
+ resp = &CreateSecurityGroupResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ resp.Name = group.Name
+ return resp, nil
+}
+
+// SecurityGroupsResp represents a response to a DescribeSecurityGroups
+// request in EC2.
+//
+// See http://goo.gl/k12Uy for more details.
+type SecurityGroupsResp struct {
+ RequestId string `xml:"requestId"`
+ Groups []SecurityGroupInfo `xml:"securityGroupInfo>item"`
+}
+
+// SecurityGroup encapsulates details for a security group in EC2.
+//
+// See http://goo.gl/CIdyP for more details.
+type SecurityGroupInfo struct {
+ SecurityGroup
+ OwnerId string `xml:"ownerId"`
+ Description string `xml:"groupDescription"`
+ IPPerms []IPPerm `xml:"ipPermissions>item"`
+ IPPermsEgress []IPPerm `xml:"ipPermissionsEgress>item"`
+}
+
+// IPPerm represents an allowance within an EC2 security group.
+//
+// See http://goo.gl/4oTxv for more details.
+type IPPerm struct {
+ Protocol string `xml:"ipProtocol"`
+ FromPort int `xml:"fromPort"`
+ ToPort int `xml:"toPort"`
+ SourceIPs []string `xml:"ipRanges>item>cidrIp"`
+ SourceGroups []UserSecurityGroup `xml:"groups>item"`
+}
+
+// UserSecurityGroup holds a security group and the owner
+// of that group.
+type UserSecurityGroup struct {
+ Id string `xml:"groupId"`
+ Name string `xml:"groupName"`
+ OwnerId string `xml:"userId"`
+}
+
+// SecurityGroup represents an EC2 security group.
+// If SecurityGroup is used as a parameter, then one of Id or Name
+// may be empty. If both are set, then Id is used.
+type SecurityGroup struct {
+ Id string `xml:"groupId"`
+ Name string `xml:"groupName"`
+ Description string `xml:"groupDescription"`
+ VpcId string `xml:"vpcId"`
+}
+
+// SecurityGroupNames is a convenience function that
+// returns a slice of security groups with the given names.
+func SecurityGroupNames(names ...string) []SecurityGroup {
+ g := make([]SecurityGroup, len(names))
+ for i, name := range names {
+ g[i] = SecurityGroup{Name: name}
+ }
+ return g
+}
+
+// SecurityGroupNames is a convenience function that
+// returns a slice of security groups with the given ids.
+func SecurityGroupIds(ids ...string) []SecurityGroup {
+ g := make([]SecurityGroup, len(ids))
+ for i, id := range ids {
+ g[i] = SecurityGroup{Id: id}
+ }
+ return g
+}
+
+// SecurityGroups returns details about security groups in EC2. Both parameters
+// are optional, and if provided will limit the security groups returned to those
+// matching the given groups or filtering rules.
+//
+// See http://goo.gl/k12Uy for more details.
+func (ec2 *EC2) SecurityGroups(groups []SecurityGroup, filter *Filter) (resp *SecurityGroupsResp, err error) {
+ params := makeParams("DescribeSecurityGroups")
+ i, j := 1, 1
+ for _, g := range groups {
+ if g.Id != "" {
+ params["GroupId."+strconv.Itoa(i)] = g.Id
+ i++
+ } else {
+ params["GroupName."+strconv.Itoa(j)] = g.Name
+ j++
+ }
+ }
+ filter.addParams(params)
+
+ resp = &SecurityGroupsResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteSecurityGroup removes the given security group in EC2.
+//
+// See http://goo.gl/QJJDO for more details.
+func (ec2 *EC2) DeleteSecurityGroup(group SecurityGroup) (resp *SimpleResp, err error) {
+ params := makeParams("DeleteSecurityGroup")
+ if group.Id != "" {
+ params["GroupId"] = group.Id
+ } else {
+ params["GroupName"] = group.Name
+ }
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// AuthorizeSecurityGroup creates an allowance for clients matching the provided
+// rules to access instances within the given security group.
+//
+// See http://goo.gl/u2sDJ for more details.
+func (ec2 *EC2) AuthorizeSecurityGroup(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
+ return ec2.authOrRevoke("AuthorizeSecurityGroupIngress", group, perms)
+}
+
+// RevokeSecurityGroup revokes permissions from a group.
+//
+// See http://goo.gl/ZgdxA for more details.
+func (ec2 *EC2) RevokeSecurityGroup(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
+ return ec2.authOrRevoke("RevokeSecurityGroupIngress", group, perms)
+}
+
+// AuthorizeSecurityGroupEgress creates an allowance for instances within the
+// given security group to access servers matching the provided rules.
+//
+// See http://goo.gl/R91LXY for more details.
+func (ec2 *EC2) AuthorizeSecurityGroupEgress(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
+ return ec2.authOrRevoke("AuthorizeSecurityGroupEgress", group, perms)
+}
+
+// RevokeSecurityGroupEgress revokes egress permissions from a group
+//
+// see http://goo.gl/Zv4wh8
+func (ec2 *EC2) RevokeSecurityGroupEgress(group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
+ return ec2.authOrRevoke("RevokeSecurityGroupEgress", group, perms)
+}
+
+func (ec2 *EC2) authOrRevoke(op string, group SecurityGroup, perms []IPPerm) (resp *SimpleResp, err error) {
+ params := makeParams(op)
+ if group.Id != "" {
+ params["GroupId"] = group.Id
+ } else {
+ params["GroupName"] = group.Name
+ }
+
+ for i, perm := range perms {
+ prefix := "IpPermissions." + strconv.Itoa(i+1)
+ params[prefix+".IpProtocol"] = perm.Protocol
+ params[prefix+".FromPort"] = strconv.Itoa(perm.FromPort)
+ params[prefix+".ToPort"] = strconv.Itoa(perm.ToPort)
+ for j, ip := range perm.SourceIPs {
+ params[prefix+".IpRanges."+strconv.Itoa(j+1)+".CidrIp"] = ip
+ }
+ for j, g := range perm.SourceGroups {
+ subprefix := prefix + ".Groups." + strconv.Itoa(j+1)
+ if g.OwnerId != "" {
+ params[subprefix+".UserId"] = g.OwnerId
+ }
+ if g.Id != "" {
+ params[subprefix+".GroupId"] = g.Id
+ } else {
+ params[subprefix+".GroupName"] = g.Name
+ }
+ }
+ }
+
+ resp = &SimpleResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ----------------------------------------------------------------------------
+// Elastic IP management functions and types.
+
+// Response to a DescribeAddresses request.
+//
+// See http://goo.gl/zW7J4p for more details.
+type DescribeAddressesResp struct {
+ RequestId string `xml:"requestId"`
+ Addresses []Address `xml:"addressesSet>item"`
+}
+
+// Address represents an Elastic IP Address
+// See http://goo.gl/uxCjp7 for more details
+type Address struct {
+ PublicIp string `xml:"publicIp"`
+ AllocationId string `xml:"allocationId"`
+ Domain string `xml:"domain"`
+ InstanceId string `xml:"instanceId"`
+ AssociationId string `xml:"associationId"`
+ NetworkInterfaceId string `xml:"networkInterfaceId"`
+ NetworkInterfaceOwnerId string `xml:"networkInterfaceOwnerId"`
+ PrivateIpAddress string `xml:"privateIpAddress"`
+}
+
+// DescribeAddresses returns details about one or more
+// Elastic IP Addresses. Returned addresses can be
+// filtered by Public IP, Allocation ID or multiple filters
+//
+// See http://goo.gl/zW7J4p for more details.
+func (ec2 *EC2) DescribeAddresses(publicIps []string, allocationIds []string, filter *Filter) (resp *DescribeAddressesResp, err error) {
+ params := makeParams("DescribeAddresses")
+ addParamsList(params, "PublicIp", publicIps)
+ addParamsList(params, "AllocationId", allocationIds)
+ filter.addParams(params)
+ resp = &DescribeAddressesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// AllocateAddressOptions are request parameters for allocating an Elastic IP Address
+//
+// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-AllocateAddress.html
+type AllocateAddressOptions struct {
+ Domain string
+}
+
+// Response to an AllocateAddress request
+//
+// See http://goo.gl/aLPmbm for more details
+type AllocateAddressResp struct {
+ RequestId string `xml:"requestId"`
+ PublicIp string `xml:"publicIp"`
+ Domain string `xml:"domain"`
+ AllocationId string `xml:"allocationId"`
+}
+
+// Allocates a new Elastic IP address.
+// The domain parameter is optional and is used for provisioning an ip address
+// in EC2 or in VPC respectively
+//
+// See http://goo.gl/aLPmbm for more details
+func (ec2 *EC2) AllocateAddress(options *AllocateAddressOptions) (resp *AllocateAddressResp, err error) {
+ params := makeParams("AllocateAddress")
+ params["Domain"] = options.Domain
+ resp = &AllocateAddressResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a ReleaseAddress request
+//
+// See http://goo.gl/Ciw2Z8 for more details
+type ReleaseAddressResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
+// Release existing elastic ip address from the account
+// PublicIp = Required for EC2
+// AllocationId = Required for VPC
+//
+// See http://goo.gl/Ciw2Z8 for more details
+func (ec2 *EC2) ReleaseAddress(publicIp, allocationId string) (resp *ReleaseAddressResp, err error) {
+ params := makeParams("ReleaseAddress")
+
+ if publicIp != "" {
+ params["PublicIp"] = publicIp
+
+ }
+ if allocationId != "" {
+ params["AllocationId"] = allocationId
+ }
+
+ resp = &ReleaseAddressResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Options set for AssociateAddress
+//
+// See http://goo.gl/hhj4z7 for more details
+type AssociateAddressOptions struct {
+ PublicIp string
+ InstanceId string
+ AllocationId string
+ NetworkInterfaceId string
+ PrivateIpAddress string
+ AllowReassociation bool
+}
+
+// Response to an AssociateAddress request
+//
+// See http://goo.gl/hhj4z7 for more details
+type AssociateAddressResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+ AssociationId string `xml:"associationId"`
+}
+
+// Associate an Elastic ip address to an instance id or a network interface
+//
+// See http://goo.gl/hhj4z7 for more details
+func (ec2 *EC2) AssociateAddress(options *AssociateAddressOptions) (resp *AssociateAddressResp, err error) {
+ params := makeParams("AssociateAddress")
+ params["InstanceId"] = options.InstanceId
+ if options.PublicIp != "" {
+ params["PublicIp"] = options.PublicIp
+ }
+ if options.AllocationId != "" {
+ params["AllocationId"] = options.AllocationId
+ }
+ if options.NetworkInterfaceId != "" {
+ params["NetworkInterfaceId"] = options.NetworkInterfaceId
+ }
+ if options.PrivateIpAddress != "" {
+ params["PrivateIpAddress"] = options.PrivateIpAddress
+ }
+ if options.AllowReassociation {
+ params["AllowReassociation"] = "true"
+ }
+
+ resp = &AssociateAddressResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a Disassociate Address request
+//
+// See http://goo.gl/Dapkuzfor more details
+type DisassociateAddressResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+}
+
+// Disassociate an elastic ip address from an instance
+// PublicIp - Required for EC2
+// AssociationId - Required for VPC
+// See http://goo.gl/Dapkuz for more details
+func (ec2 *EC2) DisassociateAddress(publicIp, associationId string) (resp *DisassociateAddressResp, err error) {
+ params := makeParams("DisassociateAddress")
+ if publicIp != "" {
+ params["PublicIp"] = publicIp
+ }
+ if associationId != "" {
+ params["AssociationId"] = associationId
+ }
+
+ resp = &DisassociateAddressResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/ec2_test.go b/vendor/github.com/goamz/goamz/ec2/ec2_test.go
new file mode 100644
index 000000000..3ca3a220d
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/ec2_test.go
@@ -0,0 +1,1280 @@
+package ec2_test
+
+import (
+ "testing"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/ec2"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ ec2 *ec2.EC2
+}
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.ec2 = ec2.NewWithClient(
+ auth,
+ aws.Region{EC2Endpoint: testServer.URL},
+ testutil.DefaultClient,
+ )
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestRunInstancesErrorDump(c *C) {
+ testServer.Response(400, nil, ErrorDump)
+
+ options := ec2.RunInstancesOptions{
+ ImageId: "ami-a6f504cf", // Ubuntu Maverick, i386, instance store
+ InstanceType: "t1.micro", // Doesn't work with micro, results in 400.
+ }
+
+ msg := `AMIs with an instance-store root device are not supported for the instance type 't1\.micro'\.`
+
+ resp, err := s.ec2.RunInstances(&options)
+
+ testServer.WaitRequest()
+
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, msg+` \(UnsupportedOperation\)`)
+
+ ec2err, ok := err.(*ec2.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(ec2err.StatusCode, Equals, 400)
+ c.Assert(ec2err.Code, Equals, "UnsupportedOperation")
+ c.Assert(ec2err.Message, Matches, msg)
+ c.Assert(ec2err.RequestId, Equals, "0503f4e9-bbd6-483c-b54f-c4ae9f3b30f4")
+}
+
+func (s *S) TestRequestSpotInstancesErrorDump(c *C) {
+ testServer.Response(400, nil, ErrorDump)
+
+ options := ec2.RequestSpotInstances{
+ SpotPrice: "0.01",
+ ImageId: "ami-a6f504cf", // Ubuntu Maverick, i386, instance store
+ InstanceType: "t1.micro", // Doesn't work with micro, results in 400.
+ }
+
+ msg := `AMIs with an instance-store root device are not supported for the instance type 't1\.micro'\.`
+
+ resp, err := s.ec2.RequestSpotInstances(&options)
+
+ testServer.WaitRequest()
+
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, msg+` \(UnsupportedOperation\)`)
+
+ ec2err, ok := err.(*ec2.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(ec2err.StatusCode, Equals, 400)
+ c.Assert(ec2err.Code, Equals, "UnsupportedOperation")
+ c.Assert(ec2err.Message, Matches, msg)
+ c.Assert(ec2err.RequestId, Equals, "0503f4e9-bbd6-483c-b54f-c4ae9f3b30f4")
+}
+
+func (s *S) TestRunInstancesErrorWithoutXML(c *C) {
+ testServer.Responses(5, 500, nil, "")
+ options := ec2.RunInstancesOptions{ImageId: "image-id"}
+
+ resp, err := s.ec2.RunInstances(&options)
+
+ testServer.WaitRequest()
+
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, "500 Internal Server Error")
+
+ ec2err, ok := err.(*ec2.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(ec2err.StatusCode, Equals, 500)
+ c.Assert(ec2err.Code, Equals, "")
+ c.Assert(ec2err.Message, Equals, "500 Internal Server Error")
+ c.Assert(ec2err.RequestId, Equals, "")
+}
+
+func (s *S) TestRequestSpotInstancesErrorWithoutXML(c *C) {
+ testServer.Responses(5, 500, nil, "")
+ options := ec2.RequestSpotInstances{SpotPrice: "spot-price", ImageId: "image-id"}
+
+ resp, err := s.ec2.RequestSpotInstances(&options)
+
+ testServer.WaitRequest()
+
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, "500 Internal Server Error")
+
+ ec2err, ok := err.(*ec2.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(ec2err.StatusCode, Equals, 500)
+ c.Assert(ec2err.Code, Equals, "")
+ c.Assert(ec2err.Message, Equals, "500 Internal Server Error")
+ c.Assert(ec2err.RequestId, Equals, "")
+}
+
+func (s *S) TestRunInstancesExample(c *C) {
+ testServer.Response(200, nil, RunInstancesExample)
+
+ options := ec2.RunInstancesOptions{
+ KeyName: "my-keys",
+ ImageId: "image-id",
+ InstanceType: "inst-type",
+ SecurityGroups: []ec2.SecurityGroup{{Name: "g1"}, {Id: "g2"}, {Name: "g3"}, {Id: "g4"}},
+ UserData: []byte("1234"),
+ KernelId: "kernel-id",
+ RamdiskId: "ramdisk-id",
+ AvailabilityZone: "zone",
+ PlacementGroupName: "group",
+ Monitoring: true,
+ SubnetId: "subnet-id",
+ DisableAPITermination: true,
+ ShutdownBehavior: "terminate",
+ PrivateIPAddress: "10.0.0.25",
+ BlockDevices: []ec2.BlockDeviceMapping{
+ {DeviceName: "/dev/sdb", VirtualName: "ephemeral0"},
+ {DeviceName: "/dev/sdc", SnapshotId: "snap-a08912c9", DeleteOnTermination: true},
+ },
+ }
+ resp, err := s.ec2.RunInstances(&options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"RunInstances"})
+ c.Assert(req.Form["ImageId"], DeepEquals, []string{"image-id"})
+ c.Assert(req.Form["MinCount"], DeepEquals, []string{"1"})
+ c.Assert(req.Form["MaxCount"], DeepEquals, []string{"1"})
+ c.Assert(req.Form["KeyName"], DeepEquals, []string{"my-keys"})
+ c.Assert(req.Form["InstanceType"], DeepEquals, []string{"inst-type"})
+ c.Assert(req.Form["SecurityGroup.1"], DeepEquals, []string{"g1"})
+ c.Assert(req.Form["SecurityGroup.2"], DeepEquals, []string{"g3"})
+ c.Assert(req.Form["SecurityGroupId.1"], DeepEquals, []string{"g2"})
+ c.Assert(req.Form["SecurityGroupId.2"], DeepEquals, []string{"g4"})
+ c.Assert(req.Form["UserData"], DeepEquals, []string{"MTIzNA=="})
+ c.Assert(req.Form["KernelId"], DeepEquals, []string{"kernel-id"})
+ c.Assert(req.Form["RamdiskId"], DeepEquals, []string{"ramdisk-id"})
+ c.Assert(req.Form["Placement.AvailabilityZone"], DeepEquals, []string{"zone"})
+ c.Assert(req.Form["Placement.GroupName"], DeepEquals, []string{"group"})
+ c.Assert(req.Form["Monitoring.Enabled"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["SubnetId"], DeepEquals, []string{"subnet-id"})
+ c.Assert(req.Form["DisableApiTermination"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["InstanceInitiatedShutdownBehavior"], DeepEquals, []string{"terminate"})
+ c.Assert(req.Form["PrivateIpAddress"], DeepEquals, []string{"10.0.0.25"})
+ c.Assert(req.Form["BlockDeviceMapping.1.DeviceName"], DeepEquals, []string{"/dev/sdb"})
+ c.Assert(req.Form["BlockDeviceMapping.1.VirtualName"], DeepEquals, []string{"ephemeral0"})
+ c.Assert(req.Form["BlockDeviceMapping.2.Ebs.SnapshotId"], DeepEquals, []string{"snap-a08912c9"})
+ c.Assert(req.Form["BlockDeviceMapping.2.Ebs.DeleteOnTermination"], DeepEquals, []string{"true"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.ReservationId, Equals, "r-47a5402e")
+ c.Assert(resp.OwnerId, Equals, "999988887777")
+ c.Assert(resp.SecurityGroups, DeepEquals, []ec2.SecurityGroup{{Name: "default", Id: "sg-67ad940e"}})
+ c.Assert(resp.Instances, HasLen, 3)
+
+ i0 := resp.Instances[0]
+ c.Assert(i0.InstanceId, Equals, "i-2ba64342")
+ c.Assert(i0.InstanceType, Equals, "m1.small")
+ c.Assert(i0.ImageId, Equals, "ami-60a54009")
+ c.Assert(i0.Monitoring, Equals, "enabled")
+ c.Assert(i0.KeyName, Equals, "example-key-name")
+ c.Assert(i0.AMILaunchIndex, Equals, 0)
+ c.Assert(i0.VirtualizationType, Equals, "paravirtual")
+ c.Assert(i0.Hypervisor, Equals, "xen")
+
+ i1 := resp.Instances[1]
+ c.Assert(i1.InstanceId, Equals, "i-2bc64242")
+ c.Assert(i1.InstanceType, Equals, "m1.small")
+ c.Assert(i1.ImageId, Equals, "ami-60a54009")
+ c.Assert(i1.Monitoring, Equals, "enabled")
+ c.Assert(i1.KeyName, Equals, "example-key-name")
+ c.Assert(i1.AMILaunchIndex, Equals, 1)
+ c.Assert(i1.VirtualizationType, Equals, "paravirtual")
+ c.Assert(i1.Hypervisor, Equals, "xen")
+
+ i2 := resp.Instances[2]
+ c.Assert(i2.InstanceId, Equals, "i-2be64332")
+ c.Assert(i2.InstanceType, Equals, "m1.small")
+ c.Assert(i2.ImageId, Equals, "ami-60a54009")
+ c.Assert(i2.Monitoring, Equals, "enabled")
+ c.Assert(i2.KeyName, Equals, "example-key-name")
+ c.Assert(i2.AMILaunchIndex, Equals, 2)
+ c.Assert(i2.VirtualizationType, Equals, "paravirtual")
+ c.Assert(i2.Hypervisor, Equals, "xen")
+}
+
+func (s *S) TestRequestSpotInstancesExample(c *C) {
+ testServer.Response(200, nil, RequestSpotInstancesExample)
+
+ options := ec2.RequestSpotInstances{
+ SpotPrice: "0.5",
+ KeyName: "my-keys",
+ ImageId: "image-id",
+ InstanceType: "inst-type",
+ SecurityGroups: []ec2.SecurityGroup{{Name: "g1"}, {Id: "g2"}, {Name: "g3"}, {Id: "g4"}},
+ UserData: []byte("1234"),
+ KernelId: "kernel-id",
+ RamdiskId: "ramdisk-id",
+ AvailZone: "zone",
+ PlacementGroupName: "group",
+ Monitoring: true,
+ SubnetId: "subnet-id",
+ PrivateIPAddress: "10.0.0.25",
+ BlockDevices: []ec2.BlockDeviceMapping{
+ {DeviceName: "/dev/sdb", VirtualName: "ephemeral0"},
+ {DeviceName: "/dev/sdc", SnapshotId: "snap-a08912c9", DeleteOnTermination: true},
+ },
+ }
+ resp, err := s.ec2.RequestSpotInstances(&options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"RequestSpotInstances"})
+ c.Assert(req.Form["SpotPrice"], DeepEquals, []string{"0.5"})
+ c.Assert(req.Form["LaunchSpecification.ImageId"], DeepEquals, []string{"image-id"})
+ c.Assert(req.Form["LaunchSpecification.KeyName"], DeepEquals, []string{"my-keys"})
+ c.Assert(req.Form["LaunchSpecification.InstanceType"], DeepEquals, []string{"inst-type"})
+ c.Assert(req.Form["LaunchSpecification.SecurityGroup.1"], DeepEquals, []string{"g1"})
+ c.Assert(req.Form["LaunchSpecification.SecurityGroup.2"], DeepEquals, []string{"g3"})
+ c.Assert(req.Form["LaunchSpecification.SecurityGroupId.1"], DeepEquals, []string{"g2"})
+ c.Assert(req.Form["LaunchSpecification.SecurityGroupId.2"], DeepEquals, []string{"g4"})
+ c.Assert(req.Form["LaunchSpecification.UserData"], DeepEquals, []string{"MTIzNA=="})
+ c.Assert(req.Form["LaunchSpecification.KernelId"], DeepEquals, []string{"kernel-id"})
+ c.Assert(req.Form["LaunchSpecification.RamdiskId"], DeepEquals, []string{"ramdisk-id"})
+ c.Assert(req.Form["LaunchSpecification.Placement.AvailabilityZone"], DeepEquals, []string{"zone"})
+ c.Assert(req.Form["LaunchSpecification.Placement.GroupName"], DeepEquals, []string{"group"})
+ c.Assert(req.Form["LaunchSpecification.Monitoring.Enabled"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["LaunchSpecification.SubnetId"], DeepEquals, []string{"subnet-id"})
+ c.Assert(req.Form["LaunchSpecification.PrivateIpAddress"], DeepEquals, []string{"10.0.0.25"})
+ c.Assert(req.Form["LaunchSpecification.BlockDeviceMapping.1.DeviceName"], DeepEquals, []string{"/dev/sdb"})
+ c.Assert(req.Form["LaunchSpecification.BlockDeviceMapping.1.VirtualName"], DeepEquals, []string{"ephemeral0"})
+ c.Assert(req.Form["LaunchSpecification.BlockDeviceMapping.2.Ebs.SnapshotId"], DeepEquals, []string{"snap-a08912c9"})
+ c.Assert(req.Form["LaunchSpecification.BlockDeviceMapping.2.Ebs.DeleteOnTermination"], DeepEquals, []string{"true"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.SpotRequestResults[0].SpotRequestId, Equals, "sir-1a2b3c4d")
+ c.Assert(resp.SpotRequestResults[0].SpotPrice, Equals, "0.5")
+ c.Assert(resp.SpotRequestResults[0].State, Equals, "open")
+ c.Assert(resp.SpotRequestResults[0].SpotLaunchSpec.ImageId, Equals, "ami-1a2b3c4d")
+}
+
+func (s *S) TestCancelSpotRequestsExample(c *C) {
+ testServer.Response(200, nil, CancelSpotRequestsExample)
+
+ resp, err := s.ec2.CancelSpotRequests([]string{"s-1", "s-2"})
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CancelSpotInstanceRequests"})
+ c.Assert(req.Form["SpotInstanceRequestId.1"], DeepEquals, []string{"s-1"})
+ c.Assert(req.Form["SpotInstanceRequestId.2"], DeepEquals, []string{"s-2"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.CancelSpotRequestResults[0].SpotRequestId, Equals, "sir-1a2b3c4d")
+ c.Assert(resp.CancelSpotRequestResults[0].State, Equals, "cancelled")
+}
+
+func (s *S) TestTerminateInstancesExample(c *C) {
+ testServer.Response(200, nil, TerminateInstancesExample)
+
+ resp, err := s.ec2.TerminateInstances([]string{"i-1", "i-2"})
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"TerminateInstances"})
+ c.Assert(req.Form["InstanceId.1"], DeepEquals, []string{"i-1"})
+ c.Assert(req.Form["InstanceId.2"], DeepEquals, []string{"i-2"})
+ c.Assert(req.Form["UserData"], IsNil)
+ c.Assert(req.Form["KernelId"], IsNil)
+ c.Assert(req.Form["RamdiskId"], IsNil)
+ c.Assert(req.Form["Placement.AvailabilityZone"], IsNil)
+ c.Assert(req.Form["Placement.GroupName"], IsNil)
+ c.Assert(req.Form["Monitoring.Enabled"], IsNil)
+ c.Assert(req.Form["SubnetId"], IsNil)
+ c.Assert(req.Form["DisableApiTermination"], IsNil)
+ c.Assert(req.Form["InstanceInitiatedShutdownBehavior"], IsNil)
+ c.Assert(req.Form["PrivateIpAddress"], IsNil)
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.StateChanges, HasLen, 1)
+ c.Assert(resp.StateChanges[0].InstanceId, Equals, "i-3ea74257")
+ c.Assert(resp.StateChanges[0].CurrentState.Code, Equals, 32)
+ c.Assert(resp.StateChanges[0].CurrentState.Name, Equals, "shutting-down")
+ c.Assert(resp.StateChanges[0].PreviousState.Code, Equals, 16)
+ c.Assert(resp.StateChanges[0].PreviousState.Name, Equals, "running")
+}
+
+func (s *S) TestDescribeSpotRequestsExample(c *C) {
+ testServer.Response(200, nil, DescribeSpotRequestsExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.DescribeSpotRequests([]string{"s-1", "s-2"}, filter)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeSpotInstanceRequests"})
+ c.Assert(req.Form["SpotInstanceRequestId.1"], DeepEquals, []string{"s-1"})
+ c.Assert(req.Form["SpotInstanceRequestId.2"], DeepEquals, []string{"s-2"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "b1719f2a-5334-4479-b2f1-26926EXAMPLE")
+ c.Assert(resp.SpotRequestResults[0].SpotRequestId, Equals, "sir-1a2b3c4d")
+ c.Assert(resp.SpotRequestResults[0].State, Equals, "active")
+ c.Assert(resp.SpotRequestResults[0].SpotPrice, Equals, "0.5")
+ c.Assert(resp.SpotRequestResults[0].SpotLaunchSpec.ImageId, Equals, "ami-1a2b3c4d")
+}
+
+func (s *S) TestDescribeInstancesExample1(c *C) {
+ testServer.Response(200, nil, DescribeInstancesExample1)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.DescribeInstances([]string{"i-1", "i-2"}, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeInstances"})
+ c.Assert(req.Form["InstanceId.1"], DeepEquals, []string{"i-1"})
+ c.Assert(req.Form["InstanceId.2"], DeepEquals, []string{"i-2"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "98e3c9a4-848c-4d6d-8e8a-b1bdEXAMPLE")
+ c.Assert(resp.Reservations, HasLen, 2)
+
+ r0 := resp.Reservations[0]
+ c.Assert(r0.ReservationId, Equals, "r-b27e30d9")
+ c.Assert(r0.OwnerId, Equals, "999988887777")
+ c.Assert(r0.RequesterId, Equals, "854251627541")
+ c.Assert(r0.SecurityGroups, DeepEquals, []ec2.SecurityGroup{{Name: "default", Id: "sg-67ad940e"}})
+ c.Assert(r0.Instances, HasLen, 1)
+
+ r0i := r0.Instances[0]
+ c.Assert(r0i.InstanceId, Equals, "i-c5cd56af")
+ c.Assert(r0i.PrivateDNSName, Equals, "domU-12-31-39-10-56-34.compute-1.internal")
+ c.Assert(r0i.DNSName, Equals, "ec2-174-129-165-232.compute-1.amazonaws.com")
+ c.Assert(r0i.AvailabilityZone, Equals, "us-east-1b")
+ c.Assert(r0i.IPAddress, Equals, "174.129.165.232")
+ c.Assert(r0i.PrivateIPAddress, Equals, "10.198.85.190")
+}
+
+func (s *S) TestDescribeInstancesExample2(c *C) {
+ testServer.Response(200, nil, DescribeInstancesExample2)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.DescribeInstances([]string{"i-1", "i-2"}, filter)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeInstances"})
+ c.Assert(req.Form["InstanceId.1"], DeepEquals, []string{"i-1"})
+ c.Assert(req.Form["InstanceId.2"], DeepEquals, []string{"i-2"})
+ c.Assert(req.Form["Filter.1.Name"], DeepEquals, []string{"key1"})
+ c.Assert(req.Form["Filter.1.Value.1"], DeepEquals, []string{"value1"})
+ c.Assert(req.Form["Filter.1.Value.2"], IsNil)
+ c.Assert(req.Form["Filter.2.Name"], DeepEquals, []string{"key2"})
+ c.Assert(req.Form["Filter.2.Value.1"], DeepEquals, []string{"value2"})
+ c.Assert(req.Form["Filter.2.Value.2"], DeepEquals, []string{"value3"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Reservations, HasLen, 1)
+
+ r0 := resp.Reservations[0]
+ r0i := r0.Instances[0]
+ c.Assert(r0i.State.Code, Equals, 16)
+ c.Assert(r0i.State.Name, Equals, "running")
+
+ r0t0 := r0i.Tags[0]
+ r0t1 := r0i.Tags[1]
+ c.Assert(r0t0.Key, Equals, "webserver")
+ c.Assert(r0t0.Value, Equals, "")
+ c.Assert(r0t1.Key, Equals, "stack")
+ c.Assert(r0t1.Value, Equals, "Production")
+}
+
+func (s *S) TestDescribeInstanceStatusExample(c *C) {
+ testServer.Response(200, nil, DescribeInstanceStatusExample)
+
+ resp, err := s.ec2.DescribeInstanceStatus(&ec2.DescribeInstanceStatusOptions{}, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeInstanceStatus"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.InstanceStatusSet, HasLen, 1)
+ c.Assert(resp.NextToken, Equals, "exampleToken")
+
+ i0 := resp.InstanceStatusSet[0]
+ c.Assert(i0.InstanceId, Equals, "i-c7cd56ad")
+ c.Assert(i0.AvailabilityZone, Equals, "us-east-1b")
+ c.Assert(i0.Events, HasLen, 1)
+
+ e0 := i0.Events[0]
+ c.Assert(e0.Code, Equals, "instance-reboot")
+ c.Assert(e0.Description, Equals, "example description")
+ c.Assert(e0.NotBefore, Equals, "2010-08-17T01:15:18.000Z")
+ c.Assert(e0.NotAfter, Equals, "2010-08-17T01:15:18.000Z")
+
+ c.Assert(i0.InstanceState.Code, Equals, 16)
+ c.Assert(i0.InstanceState.Name, Equals, "running")
+ c.Assert(i0.SystemStatus.Status, Equals, "ok")
+ c.Assert(i0.SystemStatus.Details.Name, Equals, "reachability")
+ c.Assert(i0.SystemStatus.Details.Status, Equals, "passed")
+ c.Assert(i0.SystemStatus.Details.ImpairedSince, Equals, "2010-08-17T01:15:18.000Z")
+ c.Assert(i0.InstanceStatus.Status, Equals, "ok")
+ c.Assert(i0.InstanceStatus.Details.Name, Equals, "reachability")
+ c.Assert(i0.InstanceStatus.Details.Status, Equals, "passed")
+ c.Assert(i0.InstanceStatus.Details.ImpairedSince, Equals, "2010-08-17T01:15:18.000Z")
+}
+
+func (s *S) TestDescribeAddressesPublicIPExample(c *C) {
+ testServer.Response(200, nil, DescribeAddressesExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.DescribeAddresses([]string{"192.0.2.1", "198.51.100.2", "203.0.113.41"}, []string{}, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeAddresses"})
+ c.Assert(req.Form["PublicIp.1"], DeepEquals, []string{"192.0.2.1"})
+ c.Assert(req.Form["PublicIp.2"], DeepEquals, []string{"198.51.100.2"})
+ c.Assert(req.Form["PublicIp.3"], DeepEquals, []string{"203.0.113.41"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Addresses, HasLen, 3)
+
+ r0 := resp.Addresses[0]
+ c.Assert(r0.PublicIp, Equals, "192.0.2.1")
+ c.Assert(r0.Domain, Equals, "standard")
+ c.Assert(r0.InstanceId, Equals, "i-f15ebb98")
+
+ r0i := resp.Addresses[1]
+ c.Assert(r0i.PublicIp, Equals, "198.51.100.2")
+ c.Assert(r0i.Domain, Equals, "standard")
+ c.Assert(r0i.InstanceId, Equals, "")
+
+ r0ii := resp.Addresses[2]
+ c.Assert(r0ii.PublicIp, Equals, "203.0.113.41")
+ c.Assert(r0ii.Domain, Equals, "vpc")
+ c.Assert(r0ii.InstanceId, Equals, "i-64600030")
+ c.Assert(r0ii.AssociationId, Equals, "eipassoc-f0229899")
+ c.Assert(r0ii.AllocationId, Equals, "eipalloc-08229861")
+ c.Assert(r0ii.NetworkInterfaceOwnerId, Equals, "053230519467")
+ c.Assert(r0ii.NetworkInterfaceId, Equals, "eni-ef229886")
+ c.Assert(r0ii.PrivateIpAddress, Equals, "10.0.0.228")
+}
+
+func (s *S) TestDescribeAddressesAllocationIDExample(c *C) {
+ testServer.Response(200, nil, DescribeAddressesAllocationIdExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.DescribeAddresses([]string{}, []string{"eipalloc-08229861", "eipalloc-08364752"}, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeAddresses"})
+ c.Assert(req.Form["AllocationId.1"], DeepEquals, []string{"eipalloc-08229861"})
+ c.Assert(req.Form["AllocationId.2"], DeepEquals, []string{"eipalloc-08364752"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Addresses, HasLen, 2)
+
+ r0 := resp.Addresses[0]
+ c.Assert(r0.PublicIp, Equals, "203.0.113.41")
+ c.Assert(r0.AllocationId, Equals, "eipalloc-08229861")
+ c.Assert(r0.Domain, Equals, "vpc")
+ c.Assert(r0.InstanceId, Equals, "i-64600030")
+ c.Assert(r0.AssociationId, Equals, "eipassoc-f0229899")
+ c.Assert(r0.NetworkInterfaceId, Equals, "eni-ef229886")
+ c.Assert(r0.NetworkInterfaceOwnerId, Equals, "053230519467")
+ c.Assert(r0.PrivateIpAddress, Equals, "10.0.0.228")
+
+ r1 := resp.Addresses[1]
+ c.Assert(r1.PublicIp, Equals, "146.54.2.230")
+ c.Assert(r1.AllocationId, Equals, "eipalloc-08364752")
+ c.Assert(r1.Domain, Equals, "vpc")
+ c.Assert(r1.InstanceId, Equals, "i-64693456")
+ c.Assert(r1.AssociationId, Equals, "eipassoc-f0348693")
+ c.Assert(r1.NetworkInterfaceId, Equals, "eni-da764039")
+ c.Assert(r1.NetworkInterfaceOwnerId, Equals, "053230519467")
+ c.Assert(r1.PrivateIpAddress, Equals, "10.0.0.102")
+}
+
+func (s *S) TestCreateImageExample(c *C) {
+ testServer.Response(200, nil, CreateImageExample)
+
+ options := &ec2.CreateImage{
+ InstanceId: "i-123456",
+ Name: "foo",
+ Description: "Test CreateImage",
+ NoReboot: true,
+ BlockDevices: []ec2.BlockDeviceMapping{
+ {DeviceName: "/dev/sdb", VirtualName: "ephemeral0"},
+ {DeviceName: "/dev/sdc", SnapshotId: "snap-a08912c9", DeleteOnTermination: true},
+ },
+ }
+
+ resp, err := s.ec2.CreateImage(options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CreateImage"})
+ c.Assert(req.Form["InstanceId"], DeepEquals, []string{options.InstanceId})
+ c.Assert(req.Form["Name"], DeepEquals, []string{options.Name})
+ c.Assert(req.Form["Description"], DeepEquals, []string{options.Description})
+ c.Assert(req.Form["NoReboot"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["BlockDeviceMapping.1.DeviceName"], DeepEquals, []string{"/dev/sdb"})
+ c.Assert(req.Form["BlockDeviceMapping.1.VirtualName"], DeepEquals, []string{"ephemeral0"})
+ c.Assert(req.Form["BlockDeviceMapping.2.DeviceName"], DeepEquals, []string{"/dev/sdc"})
+ c.Assert(req.Form["BlockDeviceMapping.2.Ebs.SnapshotId"], DeepEquals, []string{"snap-a08912c9"})
+ c.Assert(req.Form["BlockDeviceMapping.2.Ebs.DeleteOnTermination"], DeepEquals, []string{"true"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.ImageId, Equals, "ami-4fa54026")
+}
+
+func (s *S) TestDescribeImagesExample(c *C) {
+ testServer.Response(200, nil, DescribeImagesExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.Images([]string{"ami-1", "ami-2"}, filter)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeImages"})
+ c.Assert(req.Form["ImageId.1"], DeepEquals, []string{"ami-1"})
+ c.Assert(req.Form["ImageId.2"], DeepEquals, []string{"ami-2"})
+ c.Assert(req.Form["Filter.1.Name"], DeepEquals, []string{"key1"})
+ c.Assert(req.Form["Filter.1.Value.1"], DeepEquals, []string{"value1"})
+ c.Assert(req.Form["Filter.1.Value.2"], IsNil)
+ c.Assert(req.Form["Filter.2.Name"], DeepEquals, []string{"key2"})
+ c.Assert(req.Form["Filter.2.Value.1"], DeepEquals, []string{"value2"})
+ c.Assert(req.Form["Filter.2.Value.2"], DeepEquals, []string{"value3"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "4a4a27a2-2e7c-475d-b35b-ca822EXAMPLE")
+ c.Assert(resp.Images, HasLen, 1)
+
+ i0 := resp.Images[0]
+ c.Assert(i0.Id, Equals, "ami-a2469acf")
+ c.Assert(i0.Type, Equals, "machine")
+ c.Assert(i0.Name, Equals, "example-marketplace-amzn-ami.1")
+ c.Assert(i0.Description, Equals, "Amazon Linux AMI i386 EBS")
+ c.Assert(i0.Location, Equals, "aws-marketplace/example-marketplace-amzn-ami.1")
+ c.Assert(i0.State, Equals, "available")
+ c.Assert(i0.Public, Equals, true)
+ c.Assert(i0.OwnerId, Equals, "123456789999")
+ c.Assert(i0.OwnerAlias, Equals, "aws-marketplace")
+ c.Assert(i0.Architecture, Equals, "i386")
+ c.Assert(i0.KernelId, Equals, "aki-805ea7e9")
+ c.Assert(i0.RootDeviceType, Equals, "ebs")
+ c.Assert(i0.RootDeviceName, Equals, "/dev/sda1")
+ c.Assert(i0.VirtualizationType, Equals, "paravirtual")
+ c.Assert(i0.Hypervisor, Equals, "xen")
+
+ c.Assert(i0.Tags, HasLen, 1)
+ c.Assert(i0.Tags[0].Key, Equals, "Purpose")
+ c.Assert(i0.Tags[0].Value, Equals, "EXAMPLE")
+
+ c.Assert(i0.BlockDevices, HasLen, 1)
+ c.Assert(i0.BlockDevices[0].DeviceName, Equals, "/dev/sda1")
+ c.Assert(i0.BlockDevices[0].SnapshotId, Equals, "snap-787e9403")
+ c.Assert(i0.BlockDevices[0].VolumeSize, Equals, int64(8))
+ c.Assert(i0.BlockDevices[0].DeleteOnTermination, Equals, true)
+
+ testServer.Response(200, nil, DescribeImagesExample)
+ resp2, err := s.ec2.ImagesByOwners([]string{"ami-1", "ami-2"}, []string{"123456789999", "id2"}, filter)
+
+ req2 := testServer.WaitRequest()
+ c.Assert(req2.Form["Action"], DeepEquals, []string{"DescribeImages"})
+ c.Assert(req2.Form["ImageId.1"], DeepEquals, []string{"ami-1"})
+ c.Assert(req2.Form["ImageId.2"], DeepEquals, []string{"ami-2"})
+ c.Assert(req2.Form["Owner.1"], DeepEquals, []string{"123456789999"})
+ c.Assert(req2.Form["Owner.2"], DeepEquals, []string{"id2"})
+ c.Assert(req2.Form["Filter.1.Name"], DeepEquals, []string{"key1"})
+ c.Assert(req2.Form["Filter.1.Value.1"], DeepEquals, []string{"value1"})
+ c.Assert(req2.Form["Filter.1.Value.2"], IsNil)
+ c.Assert(req2.Form["Filter.2.Name"], DeepEquals, []string{"key2"})
+ c.Assert(req2.Form["Filter.2.Value.1"], DeepEquals, []string{"value2"})
+ c.Assert(req2.Form["Filter.2.Value.2"], DeepEquals, []string{"value3"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp2.RequestId, Equals, "4a4a27a2-2e7c-475d-b35b-ca822EXAMPLE")
+ c.Assert(resp2.Images, HasLen, 1)
+
+ i1 := resp2.Images[0]
+ c.Assert(i1.Id, Equals, "ami-a2469acf")
+ c.Assert(i1.Type, Equals, "machine")
+ c.Assert(i1.Name, Equals, "example-marketplace-amzn-ami.1")
+ c.Assert(i1.Description, Equals, "Amazon Linux AMI i386 EBS")
+ c.Assert(i1.Location, Equals, "aws-marketplace/example-marketplace-amzn-ami.1")
+ c.Assert(i1.State, Equals, "available")
+ c.Assert(i1.Public, Equals, true)
+ c.Assert(i1.OwnerId, Equals, "123456789999")
+ c.Assert(i1.OwnerAlias, Equals, "aws-marketplace")
+ c.Assert(i1.Architecture, Equals, "i386")
+ c.Assert(i1.KernelId, Equals, "aki-805ea7e9")
+ c.Assert(i1.RootDeviceType, Equals, "ebs")
+ c.Assert(i1.RootDeviceName, Equals, "/dev/sda1")
+ c.Assert(i1.VirtualizationType, Equals, "paravirtual")
+ c.Assert(i1.Hypervisor, Equals, "xen")
+
+ c.Assert(i1.BlockDevices, HasLen, 1)
+ c.Assert(i1.BlockDevices[0].DeviceName, Equals, "/dev/sda1")
+ c.Assert(i1.BlockDevices[0].SnapshotId, Equals, "snap-787e9403")
+ c.Assert(i1.BlockDevices[0].VolumeSize, Equals, int64(8))
+ c.Assert(i1.BlockDevices[0].DeleteOnTermination, Equals, true)
+}
+
+func (s *S) TestImageAttributeExample(c *C) {
+ testServer.Response(200, nil, ImageAttributeExample)
+
+ resp, err := s.ec2.ImageAttribute("ami-61a54008", "launchPermission")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeImageAttribute"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.ImageId, Equals, "ami-61a54008")
+ c.Assert(resp.Group, Equals, "all")
+ c.Assert(resp.UserIds[0], Equals, "495219933132")
+}
+
+func (s *S) TestCreateSnapshotExample(c *C) {
+ testServer.Response(200, nil, CreateSnapshotExample)
+
+ resp, err := s.ec2.CreateSnapshot("vol-4d826724", "Daily Backup")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CreateSnapshot"})
+ c.Assert(req.Form["VolumeId"], DeepEquals, []string{"vol-4d826724"})
+ c.Assert(req.Form["Description"], DeepEquals, []string{"Daily Backup"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Snapshot.Id, Equals, "snap-78a54011")
+ c.Assert(resp.Snapshot.VolumeId, Equals, "vol-4d826724")
+ c.Assert(resp.Snapshot.Status, Equals, "pending")
+ c.Assert(resp.Snapshot.StartTime, Equals, "2008-05-07T12:51:50.000Z")
+ c.Assert(resp.Snapshot.Progress, Equals, "60%")
+ c.Assert(resp.Snapshot.OwnerId, Equals, "111122223333")
+ c.Assert(resp.Snapshot.VolumeSize, Equals, "10")
+ c.Assert(resp.Snapshot.Description, Equals, "Daily Backup")
+}
+
+func (s *S) TestDeleteSnapshotsExample(c *C) {
+ testServer.Response(200, nil, DeleteSnapshotExample)
+
+ resp, err := s.ec2.DeleteSnapshots([]string{"snap-78a54011"})
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DeleteSnapshot"})
+ c.Assert(req.Form["SnapshotId.1"], DeepEquals, []string{"snap-78a54011"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestDescribeSnapshotsExample(c *C) {
+ testServer.Response(200, nil, DescribeSnapshotsExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.Snapshots([]string{"snap-1", "snap-2"}, filter)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeSnapshots"})
+ c.Assert(req.Form["SnapshotId.1"], DeepEquals, []string{"snap-1"})
+ c.Assert(req.Form["SnapshotId.2"], DeepEquals, []string{"snap-2"})
+ c.Assert(req.Form["Filter.1.Name"], DeepEquals, []string{"key1"})
+ c.Assert(req.Form["Filter.1.Value.1"], DeepEquals, []string{"value1"})
+ c.Assert(req.Form["Filter.1.Value.2"], IsNil)
+ c.Assert(req.Form["Filter.2.Name"], DeepEquals, []string{"key2"})
+ c.Assert(req.Form["Filter.2.Value.1"], DeepEquals, []string{"value2"})
+ c.Assert(req.Form["Filter.2.Value.2"], DeepEquals, []string{"value3"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Snapshots, HasLen, 1)
+
+ s0 := resp.Snapshots[0]
+ c.Assert(s0.Id, Equals, "snap-1a2b3c4d")
+ c.Assert(s0.VolumeId, Equals, "vol-8875daef")
+ c.Assert(s0.VolumeSize, Equals, "15")
+ c.Assert(s0.Status, Equals, "pending")
+ c.Assert(s0.StartTime, Equals, "2010-07-29T04:12:01.000Z")
+ c.Assert(s0.Progress, Equals, "30%")
+ c.Assert(s0.OwnerId, Equals, "111122223333")
+ c.Assert(s0.Description, Equals, "Daily Backup")
+
+ c.Assert(s0.Tags, HasLen, 1)
+ c.Assert(s0.Tags[0].Key, Equals, "Purpose")
+ c.Assert(s0.Tags[0].Value, Equals, "demo_db_14_backup")
+}
+
+func (s *S) TestModifyImageAttributeExample(c *C) {
+ testServer.Response(200, nil, ModifyImageAttributeExample)
+
+ options := ec2.ModifyImageAttribute{
+ Description: "Test Description",
+ }
+
+ resp, err := s.ec2.ModifyImageAttribute("ami-4fa54026", &options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"ModifyImageAttribute"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestModifyImageAttributeExample_complex(c *C) {
+ testServer.Response(200, nil, ModifyImageAttributeExample)
+
+ options := ec2.ModifyImageAttribute{
+ AddUsers: []string{"u1", "u2"},
+ RemoveUsers: []string{"u3"},
+ AddGroups: []string{"g1", "g3"},
+ RemoveGroups: []string{"g2"},
+ Description: "Test Description",
+ }
+
+ resp, err := s.ec2.ModifyImageAttribute("ami-4fa54026", &options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"ModifyImageAttribute"})
+ c.Assert(req.Form["LaunchPermission.Add.1.UserId"], DeepEquals, []string{"u1"})
+ c.Assert(req.Form["LaunchPermission.Add.2.UserId"], DeepEquals, []string{"u2"})
+ c.Assert(req.Form["LaunchPermission.Remove.1.UserId"], DeepEquals, []string{"u3"})
+ c.Assert(req.Form["LaunchPermission.Add.1.Group"], DeepEquals, []string{"g1"})
+ c.Assert(req.Form["LaunchPermission.Add.2.Group"], DeepEquals, []string{"g3"})
+ c.Assert(req.Form["LaunchPermission.Remove.1.Group"], DeepEquals, []string{"g2"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestCopyImageExample(c *C) {
+ testServer.Response(200, nil, CopyImageExample)
+
+ options := ec2.CopyImage{
+ SourceRegion: "us-west-2",
+ SourceImageId: "ami-1a2b3c4d",
+ Description: "Test Description",
+ }
+
+ resp, err := s.ec2.CopyImage(&options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CopyImage"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "60bc441d-fa2c-494d-b155-5d6a3EXAMPLE")
+}
+
+func (s *S) TestCreateKeyPairExample(c *C) {
+ testServer.Response(200, nil, CreateKeyPairExample)
+
+ resp, err := s.ec2.CreateKeyPair("foo")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CreateKeyPair"})
+ c.Assert(req.Form["KeyName"], DeepEquals, []string{"foo"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.KeyName, Equals, "foo")
+ c.Assert(resp.KeyFingerprint, Equals, "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00")
+}
+
+func (s *S) TestDeleteKeyPairExample(c *C) {
+ testServer.Response(200, nil, DeleteKeyPairExample)
+
+ resp, err := s.ec2.DeleteKeyPair("foo")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DeleteKeyPair"})
+ c.Assert(req.Form["KeyName"], DeepEquals, []string{"foo"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestCreateSecurityGroupExample(c *C) {
+ testServer.Response(200, nil, CreateSecurityGroupExample)
+
+ resp, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: "websrv", Description: "Web Servers"})
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CreateSecurityGroup"})
+ c.Assert(req.Form["GroupName"], DeepEquals, []string{"websrv"})
+ c.Assert(req.Form["GroupDescription"], DeepEquals, []string{"Web Servers"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Name, Equals, "websrv")
+ c.Assert(resp.Id, Equals, "sg-67ad940e")
+}
+
+func (s *S) TestDescribeSecurityGroupsExample(c *C) {
+ testServer.Response(200, nil, DescribeSecurityGroupsExample)
+
+ resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{{Name: "WebServers"}, {Name: "RangedPortsBySource"}}, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeSecurityGroups"})
+ c.Assert(req.Form["GroupName.1"], DeepEquals, []string{"WebServers"})
+ c.Assert(req.Form["GroupName.2"], DeepEquals, []string{"RangedPortsBySource"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Groups, HasLen, 2)
+
+ g0 := resp.Groups[0]
+ c.Assert(g0.OwnerId, Equals, "999988887777")
+ c.Assert(g0.Name, Equals, "WebServers")
+ c.Assert(g0.Id, Equals, "sg-67ad940e")
+ c.Assert(g0.Description, Equals, "Web Servers")
+ c.Assert(g0.IPPerms, HasLen, 1)
+ c.Assert(g0.IPPermsEgress, HasLen, 1)
+
+ g0ipp := g0.IPPerms[0]
+ c.Assert(g0ipp.Protocol, Equals, "tcp")
+ c.Assert(g0ipp.FromPort, Equals, 80)
+ c.Assert(g0ipp.ToPort, Equals, 80)
+ c.Assert(g0ipp.SourceIPs, DeepEquals, []string{"0.0.0.0/0"})
+
+ g0ippe := g0.IPPermsEgress[0]
+ c.Assert(g0ippe.Protocol, Equals, "tcp")
+ c.Assert(g0ippe.FromPort, Equals, 80)
+ c.Assert(g0ippe.ToPort, Equals, 80)
+ c.Assert(g0ippe.SourceIPs, DeepEquals, []string{"0.0.0.0/0"})
+
+ g1 := resp.Groups[1]
+ c.Assert(g1.OwnerId, Equals, "999988887777")
+ c.Assert(g1.Name, Equals, "RangedPortsBySource")
+ c.Assert(g1.Id, Equals, "sg-76abc467")
+ c.Assert(g1.Description, Equals, "Group A")
+ c.Assert(g1.IPPerms, HasLen, 1)
+
+ g1ipp := g1.IPPerms[0]
+ c.Assert(g1ipp.Protocol, Equals, "tcp")
+ c.Assert(g1ipp.FromPort, Equals, 6000)
+ c.Assert(g1ipp.ToPort, Equals, 7000)
+ c.Assert(g1ipp.SourceIPs, IsNil)
+}
+
+func (s *S) TestDescribeSecurityGroupsExampleWithFilter(c *C) {
+ testServer.Response(200, nil, DescribeSecurityGroupsExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("ip-permission.protocol", "tcp")
+ filter.Add("ip-permission.from-port", "22")
+ filter.Add("ip-permission.to-port", "22")
+ filter.Add("ip-permission.group-name", "app_server_group", "database_group")
+
+ _, err := s.ec2.SecurityGroups(nil, filter)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeSecurityGroups"})
+ c.Assert(req.Form["Filter.1.Name"], DeepEquals, []string{"ip-permission.from-port"})
+ c.Assert(req.Form["Filter.1.Value.1"], DeepEquals, []string{"22"})
+ c.Assert(req.Form["Filter.2.Name"], DeepEquals, []string{"ip-permission.group-name"})
+ c.Assert(req.Form["Filter.2.Value.1"], DeepEquals, []string{"app_server_group"})
+ c.Assert(req.Form["Filter.2.Value.2"], DeepEquals, []string{"database_group"})
+ c.Assert(req.Form["Filter.3.Name"], DeepEquals, []string{"ip-permission.protocol"})
+ c.Assert(req.Form["Filter.3.Value.1"], DeepEquals, []string{"tcp"})
+ c.Assert(req.Form["Filter.4.Name"], DeepEquals, []string{"ip-permission.to-port"})
+ c.Assert(req.Form["Filter.4.Value.1"], DeepEquals, []string{"22"})
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestDescribeSecurityGroupsDumpWithGroup(c *C) {
+ testServer.Response(200, nil, DescribeSecurityGroupsDump)
+
+ resp, err := s.ec2.SecurityGroups(nil, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeSecurityGroups"})
+ c.Assert(err, IsNil)
+ c.Check(resp.Groups, HasLen, 1)
+ c.Check(resp.Groups[0].IPPerms, HasLen, 2)
+
+ ipp0 := resp.Groups[0].IPPerms[0]
+ c.Assert(ipp0.SourceIPs, IsNil)
+ c.Check(ipp0.Protocol, Equals, "icmp")
+ c.Assert(ipp0.SourceGroups, HasLen, 1)
+ c.Check(ipp0.SourceGroups[0].OwnerId, Equals, "12345")
+ c.Check(ipp0.SourceGroups[0].Name, Equals, "default")
+ c.Check(ipp0.SourceGroups[0].Id, Equals, "sg-67ad940e")
+
+ ipp1 := resp.Groups[0].IPPerms[1]
+ c.Check(ipp1.Protocol, Equals, "tcp")
+ c.Assert(ipp0.SourceIPs, IsNil)
+ c.Assert(ipp0.SourceGroups, HasLen, 1)
+ c.Check(ipp1.SourceGroups[0].Id, Equals, "sg-76abc467")
+ c.Check(ipp1.SourceGroups[0].OwnerId, Equals, "12345")
+ c.Check(ipp1.SourceGroups[0].Name, Equals, "other")
+}
+
+func (s *S) TestDeleteSecurityGroupExample(c *C) {
+ testServer.Response(200, nil, DeleteSecurityGroupExample)
+
+ resp, err := s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: "websrv"})
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DeleteSecurityGroup"})
+ c.Assert(req.Form["GroupName"], DeepEquals, []string{"websrv"})
+ c.Assert(req.Form["GroupId"], IsNil)
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestDeleteSecurityGroupExampleWithId(c *C) {
+ testServer.Response(200, nil, DeleteSecurityGroupExample)
+
+ // ignore return and error - we're only want to check the parameter handling.
+ s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Id: "sg-67ad940e", Name: "ignored"})
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["GroupName"], IsNil)
+ c.Assert(req.Form["GroupId"], DeepEquals, []string{"sg-67ad940e"})
+}
+
+func (s *S) TestAuthorizeSecurityGroupExample1(c *C) {
+ testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
+
+ perms := []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 80,
+ ToPort: 80,
+ SourceIPs: []string{"205.192.0.0/16", "205.159.0.0/16"},
+ }}
+ resp, err := s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: "websrv"}, perms)
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"AuthorizeSecurityGroupIngress"})
+ c.Assert(req.Form["GroupName"], DeepEquals, []string{"websrv"})
+ c.Assert(req.Form["IpPermissions.1.IpProtocol"], DeepEquals, []string{"tcp"})
+ c.Assert(req.Form["IpPermissions.1.FromPort"], DeepEquals, []string{"80"})
+ c.Assert(req.Form["IpPermissions.1.ToPort"], DeepEquals, []string{"80"})
+ c.Assert(req.Form["IpPermissions.1.IpRanges.1.CidrIp"], DeepEquals, []string{"205.192.0.0/16"})
+ c.Assert(req.Form["IpPermissions.1.IpRanges.2.CidrIp"], DeepEquals, []string{"205.159.0.0/16"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestAuthorizeSecurityGroupExample1WithId(c *C) {
+ testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
+
+ perms := []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 80,
+ ToPort: 80,
+ SourceIPs: []string{"205.192.0.0/16", "205.159.0.0/16"},
+ }}
+ // ignore return and error - we're only want to check the parameter handling.
+ s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Id: "sg-67ad940e", Name: "ignored"}, perms)
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["GroupName"], IsNil)
+ c.Assert(req.Form["GroupId"], DeepEquals, []string{"sg-67ad940e"})
+}
+
+func (s *S) TestAuthorizeSecurityGroupExample2(c *C) {
+ testServer.Response(200, nil, AuthorizeSecurityGroupIngressExample)
+
+ perms := []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 80,
+ ToPort: 81,
+ SourceGroups: []ec2.UserSecurityGroup{
+ {OwnerId: "999988887777", Name: "OtherAccountGroup"},
+ {Id: "sg-67ad940e"},
+ },
+ }}
+ resp, err := s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: "websrv"}, perms)
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"AuthorizeSecurityGroupIngress"})
+ c.Assert(req.Form["GroupName"], DeepEquals, []string{"websrv"})
+ c.Assert(req.Form["IpPermissions.1.IpProtocol"], DeepEquals, []string{"tcp"})
+ c.Assert(req.Form["IpPermissions.1.FromPort"], DeepEquals, []string{"80"})
+ c.Assert(req.Form["IpPermissions.1.ToPort"], DeepEquals, []string{"81"})
+ c.Assert(req.Form["IpPermissions.1.Groups.1.UserId"], DeepEquals, []string{"999988887777"})
+ c.Assert(req.Form["IpPermissions.1.Groups.1.GroupName"], DeepEquals, []string{"OtherAccountGroup"})
+ c.Assert(req.Form["IpPermissions.1.Groups.2.UserId"], IsNil)
+ c.Assert(req.Form["IpPermissions.1.Groups.2.GroupName"], IsNil)
+ c.Assert(req.Form["IpPermissions.1.Groups.2.GroupId"], DeepEquals, []string{"sg-67ad940e"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestRevokeSecurityGroupExample(c *C) {
+ // RevokeSecurityGroup is implemented by the same code as AuthorizeSecurityGroup
+ // so there's no need to duplicate all the tests.
+ testServer.Response(200, nil, RevokeSecurityGroupIngressExample)
+
+ resp, err := s.ec2.RevokeSecurityGroup(ec2.SecurityGroup{Name: "websrv"}, nil)
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"RevokeSecurityGroupIngress"})
+ c.Assert(req.Form["GroupName"], DeepEquals, []string{"websrv"})
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestCreateTags(c *C) {
+ testServer.Response(200, nil, CreateTagsExample)
+
+ resp, err := s.ec2.CreateTags([]string{"ami-1a2b3c4d", "i-7f4d3a2b"}, []ec2.Tag{{"webserver", ""}, {"stack", "Production"}})
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["ResourceId.1"], DeepEquals, []string{"ami-1a2b3c4d"})
+ c.Assert(req.Form["ResourceId.2"], DeepEquals, []string{"i-7f4d3a2b"})
+ c.Assert(req.Form["Tag.1.Key"], DeepEquals, []string{"webserver"})
+ c.Assert(req.Form["Tag.1.Value"], DeepEquals, []string{""})
+ c.Assert(req.Form["Tag.2.Key"], DeepEquals, []string{"stack"})
+ c.Assert(req.Form["Tag.2.Value"], DeepEquals, []string{"Production"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestStartInstances(c *C) {
+ testServer.Response(200, nil, StartInstancesExample)
+
+ resp, err := s.ec2.StartInstances("i-10a64379")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"StartInstances"})
+ c.Assert(req.Form["InstanceId.1"], DeepEquals, []string{"i-10a64379"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+
+ s0 := resp.StateChanges[0]
+ c.Assert(s0.InstanceId, Equals, "i-10a64379")
+ c.Assert(s0.CurrentState.Code, Equals, 0)
+ c.Assert(s0.CurrentState.Name, Equals, "pending")
+ c.Assert(s0.PreviousState.Code, Equals, 80)
+ c.Assert(s0.PreviousState.Name, Equals, "stopped")
+}
+
+func (s *S) TestStopInstances(c *C) {
+ testServer.Response(200, nil, StopInstancesExample)
+
+ resp, err := s.ec2.StopInstances("i-10a64379")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"StopInstances"})
+ c.Assert(req.Form["InstanceId.1"], DeepEquals, []string{"i-10a64379"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+
+ s0 := resp.StateChanges[0]
+ c.Assert(s0.InstanceId, Equals, "i-10a64379")
+ c.Assert(s0.CurrentState.Code, Equals, 64)
+ c.Assert(s0.CurrentState.Name, Equals, "stopping")
+ c.Assert(s0.PreviousState.Code, Equals, 16)
+ c.Assert(s0.PreviousState.Name, Equals, "running")
+}
+
+func (s *S) TestRebootInstances(c *C) {
+ testServer.Response(200, nil, RebootInstancesExample)
+
+ resp, err := s.ec2.RebootInstances("i-10a64379")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"RebootInstances"})
+ c.Assert(req.Form["InstanceId.1"], DeepEquals, []string{"i-10a64379"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestSignatureWithEndpointPath(c *C) {
+ ec2.FakeTime(true)
+ defer ec2.FakeTime(false)
+
+ testServer.Response(200, nil, RebootInstancesExample)
+
+ // https://bugs.launchpad.net/goamz/+bug/1022749
+ ec2 := ec2.NewWithClient(s.ec2.Auth, aws.Region{EC2Endpoint: testServer.URL + "/services/Cloud"}, testutil.DefaultClient)
+
+ _, err := ec2.RebootInstances("i-10a64379")
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Signature"], DeepEquals, []string{"VVoC6Y6xfES+KvZo+789thP8+tye4F6fOKBiKmXk4S4="})
+}
+
+func (s *S) TestAllocateAddressExample(c *C) {
+ testServer.Response(200, nil, AllocateAddressExample)
+
+ options := &ec2.AllocateAddressOptions{
+ Domain: "vpc",
+ }
+
+ resp, err := s.ec2.AllocateAddress(options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"AllocateAddress"})
+ c.Assert(req.Form["Domain"], DeepEquals, []string{"vpc"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.PublicIp, Equals, "198.51.100.1")
+ c.Assert(resp.Domain, Equals, "vpc")
+ c.Assert(resp.AllocationId, Equals, "eipalloc-5723d13e")
+}
+
+func (s *S) TestReleaseAddressExample(c *C) {
+ testServer.Response(200, nil, ReleaseAddressExample)
+
+ resp, err := s.ec2.ReleaseAddress("192.0.2.1", "eipalloc-5723d13e")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"ReleaseAddress"})
+ c.Assert(req.Form["PublicIp"], DeepEquals, []string{"192.0.2.1"})
+ c.Assert(req.Form["AllocationId"], DeepEquals, []string{"eipalloc-5723d13e"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Return, Equals, true)
+}
+
+func (s *S) TestAssociateAddressExample(c *C) {
+ testServer.Response(200, nil, AssociateAddressExample)
+
+ options := &ec2.AssociateAddressOptions{
+ PublicIp: "192.0.2.1",
+ InstanceId: "i-4fd2431a",
+ AllocationId: "eipalloc-5723d13e",
+ AllowReassociation: true,
+ }
+
+ resp, err := s.ec2.AssociateAddress(options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"AssociateAddress"})
+ c.Assert(req.Form["PublicIp"], DeepEquals, []string{"192.0.2.1"})
+ c.Assert(req.Form["InstanceId"], DeepEquals, []string{"i-4fd2431a"})
+ c.Assert(req.Form["AllocationId"], DeepEquals, []string{"eipalloc-5723d13e"})
+ c.Assert(req.Form["AllowReassociation"], DeepEquals, []string{"true"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.AssociationId, Equals, "eipassoc-fc5ca095")
+ c.Assert(resp.Return, Equals, true)
+}
+
+func (s *S) TestDisassociateAddressExample(c *C) {
+ testServer.Response(200, nil, DisassociateAddressExample)
+
+ resp, err := s.ec2.DisassociateAddress("192.0.2.1", "eipassoc-aa7486c3")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DisassociateAddress"})
+ c.Assert(req.Form["PublicIp"], DeepEquals, []string{"192.0.2.1"})
+ c.Assert(req.Form["AssociationId"], DeepEquals, []string{"eipassoc-aa7486c3"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Return, Equals, true)
+}
+
+func (s *S) TestModifyInstance(c *C) {
+ testServer.Response(200, nil, ModifyInstanceExample)
+
+ options := ec2.ModifyInstance{
+ InstanceType: "m1.small",
+ DisableAPITermination: true,
+ EbsOptimized: true,
+ SecurityGroups: []ec2.SecurityGroup{{Id: "g1"}, {Id: "g2"}},
+ ShutdownBehavior: "terminate",
+ KernelId: "kernel-id",
+ RamdiskId: "ramdisk-id",
+ SourceDestCheck: true,
+ SriovNetSupport: true,
+ UserData: []byte("1234"),
+ BlockDevices: []ec2.BlockDeviceMapping{
+ {DeviceName: "/dev/sda1", SnapshotId: "snap-a08912c9", DeleteOnTermination: true},
+ },
+ }
+
+ resp, err := s.ec2.ModifyInstance("i-2ba64342", &options)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Form["Action"], DeepEquals, []string{"ModifyInstanceAttribute"})
+ c.Assert(req.Form["InstanceId"], DeepEquals, []string{"i-2ba64342"})
+ c.Assert(req.Form["InstanceType.Value"], DeepEquals, []string{"m1.small"})
+ c.Assert(req.Form["BlockDeviceMapping.1.DeviceName"], DeepEquals, []string{"/dev/sda1"})
+ c.Assert(req.Form["BlockDeviceMapping.1.Ebs.SnapshotId"], DeepEquals, []string{"snap-a08912c9"})
+ c.Assert(req.Form["BlockDeviceMapping.1.Ebs.DeleteOnTermination"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["DisableApiTermination.Value"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["EbsOptimized"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["GroupId.1"], DeepEquals, []string{"g1"})
+ c.Assert(req.Form["GroupId.2"], DeepEquals, []string{"g2"})
+ c.Assert(req.Form["InstanceInitiatedShutdownBehavior.Value"], DeepEquals, []string{"terminate"})
+ c.Assert(req.Form["Kernel.Value"], DeepEquals, []string{"kernel-id"})
+ c.Assert(req.Form["Ramdisk.Value"], DeepEquals, []string{"ramdisk-id"})
+ c.Assert(req.Form["SourceDestCheck.Value"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["SriovNetSupport.Value"], DeepEquals, []string{"simple"})
+ c.Assert(req.Form["UserData"], DeepEquals, []string{"MTIzNA=="})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+}
+
+func (s *S) TestDescribeReservedInstancesExample(c *C) {
+ testServer.Response(200, nil, DescribeReservedInstancesExample)
+
+ resp, err := s.ec2.DescribeReservedInstances([]string{"i-1", "i-2"}, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeReservedInstances"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.ReservedInstances, HasLen, 1)
+
+ r0 := resp.ReservedInstances[0]
+ c.Assert(r0.ReservedInstanceId, Equals, "e5a2ff3b-7d14-494f-90af-0b5d0EXAMPLE")
+
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/ec2i_test.go b/vendor/github.com/goamz/goamz/ec2/ec2i_test.go
new file mode 100644
index 000000000..e8656f19f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/ec2i_test.go
@@ -0,0 +1,204 @@
+package ec2_test
+
+import (
+ "crypto/rand"
+ "fmt"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/ec2"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+// AmazonServer represents an Amazon EC2 server.
+type AmazonServer struct {
+ auth aws.Auth
+}
+
+func (s *AmazonServer) SetUp(c *C) {
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ c.Fatal(err.Error())
+ }
+ s.auth = auth
+}
+
+// Suite cost per run: 0.02 USD
+var _ = Suite(&AmazonClientSuite{})
+
+// AmazonClientSuite tests the client against a live EC2 server.
+type AmazonClientSuite struct {
+ srv AmazonServer
+ ClientTests
+}
+
+func (s *AmazonClientSuite) SetUpSuite(c *C) {
+ if !testutil.Amazon {
+ c.Skip("AmazonClientSuite tests not enabled")
+ }
+ s.srv.SetUp(c)
+ s.ec2 = ec2.NewWithClient(s.srv.auth, aws.USEast, testutil.DefaultClient)
+}
+
+// ClientTests defines integration tests designed to test the client.
+// It is not used as a test suite in itself, but embedded within
+// another type.
+type ClientTests struct {
+ ec2 *ec2.EC2
+}
+
+var imageId = "ami-ccf405a5" // Ubuntu Maverick, i386, EBS store
+
+// Cost: 0.00 USD
+func (s *ClientTests) TestRunInstancesError(c *C) {
+ options := ec2.RunInstancesOptions{
+ ImageId: "ami-a6f504cf", // Ubuntu Maverick, i386, instance store
+ InstanceType: "t1.micro", // Doesn't work with micro, results in 400.
+ }
+
+ resp, err := s.ec2.RunInstances(&options)
+
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, "AMI.*root device.*not supported.*")
+
+ ec2err, ok := err.(*ec2.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(ec2err.StatusCode, Equals, 400)
+ c.Assert(ec2err.Code, Equals, "UnsupportedOperation")
+ c.Assert(ec2err.Message, Matches, "AMI.*root device.*not supported.*")
+ c.Assert(ec2err.RequestId, Matches, ".+")
+}
+
+// Cost: 0.02 USD
+func (s *ClientTests) TestRunAndTerminate(c *C) {
+ options := ec2.RunInstancesOptions{
+ ImageId: imageId,
+ InstanceType: "t1.micro",
+ }
+ resp1, err := s.ec2.RunInstances(&options)
+ c.Assert(err, IsNil)
+ c.Check(resp1.ReservationId, Matches, "r-[0-9a-f]*")
+ c.Check(resp1.OwnerId, Matches, "[0-9]+")
+ c.Check(resp1.Instances, HasLen, 1)
+ c.Check(resp1.Instances[0].InstanceType, Equals, "t1.micro")
+
+ instId := resp1.Instances[0].InstanceId
+
+ resp2, err := s.ec2.DescribeInstances([]string{instId}, nil)
+ c.Assert(err, IsNil)
+ if c.Check(resp2.Reservations, HasLen, 1) && c.Check(len(resp2.Reservations[0].Instances), Equals, 1) {
+ inst := resp2.Reservations[0].Instances[0]
+ c.Check(inst.InstanceId, Equals, instId)
+ }
+
+ resp3, err := s.ec2.TerminateInstances([]string{instId})
+ c.Assert(err, IsNil)
+ c.Check(resp3.StateChanges, HasLen, 1)
+ c.Check(resp3.StateChanges[0].InstanceId, Equals, instId)
+ c.Check(resp3.StateChanges[0].CurrentState.Name, Equals, "shutting-down")
+ c.Check(resp3.StateChanges[0].CurrentState.Code, Equals, 32)
+}
+
+// Cost: 0.00 USD
+func (s *ClientTests) TestSecurityGroups(c *C) {
+ name := "goamz-test"
+ descr := "goamz security group for tests"
+
+ // Clean it up, if a previous test left it around and avoid leaving it around.
+ s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
+ defer s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
+
+ resp1, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: name, Description: descr})
+ c.Assert(err, IsNil)
+ c.Assert(resp1.RequestId, Matches, ".+")
+ c.Assert(resp1.Name, Equals, name)
+ c.Assert(resp1.Id, Matches, ".+")
+
+ resp1, err = s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: name, Description: descr})
+ ec2err, _ := err.(*ec2.Error)
+ c.Assert(resp1, IsNil)
+ c.Assert(ec2err, NotNil)
+ c.Assert(ec2err.Code, Equals, "InvalidGroup.Duplicate")
+
+ perms := []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 0,
+ ToPort: 1024,
+ SourceIPs: []string{"127.0.0.1/24"},
+ }}
+
+ resp2, err := s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: name}, perms)
+ c.Assert(err, IsNil)
+ c.Assert(resp2.RequestId, Matches, ".+")
+
+ resp3, err := s.ec2.SecurityGroups(ec2.SecurityGroupNames(name), nil)
+ c.Assert(err, IsNil)
+ c.Assert(resp3.RequestId, Matches, ".+")
+ c.Assert(resp3.Groups, HasLen, 1)
+
+ g0 := resp3.Groups[0]
+ c.Assert(g0.Name, Equals, name)
+ c.Assert(g0.Description, Equals, descr)
+ c.Assert(g0.IPPerms, HasLen, 1)
+ c.Assert(g0.IPPerms[0].Protocol, Equals, "tcp")
+ c.Assert(g0.IPPerms[0].FromPort, Equals, 0)
+ c.Assert(g0.IPPerms[0].ToPort, Equals, 1024)
+ c.Assert(g0.IPPerms[0].SourceIPs, DeepEquals, []string{"127.0.0.1/24"})
+
+ resp2, err = s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
+ c.Assert(err, IsNil)
+ c.Assert(resp2.RequestId, Matches, ".+")
+}
+
+var sessionId = func() string {
+ buf := make([]byte, 8)
+ // if we have no randomness, we'll just make do, so ignore the error.
+ rand.Read(buf)
+ return fmt.Sprintf("%x", buf)
+}()
+
+// sessionName reutrns a name that is probably
+// unique to this test session.
+func sessionName(prefix string) string {
+ return prefix + "-" + sessionId
+}
+
+var allRegions = []aws.Region{
+ aws.USEast,
+ aws.USWest,
+ aws.EUWest,
+ aws.APSoutheast,
+ aws.APNortheast,
+}
+
+// Communicate with all EC2 endpoints to see if they are alive.
+func (s *ClientTests) TestRegions(c *C) {
+ name := sessionName("goamz-region-test")
+ perms := []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 80,
+ ToPort: 80,
+ SourceIPs: []string{"127.0.0.1/32"},
+ }}
+ errs := make(chan error, len(allRegions))
+ for _, region := range allRegions {
+ go func(r aws.Region) {
+ e := ec2.NewWithClient(s.ec2.Auth, r, testutil.DefaultClient)
+ _, err := e.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: name}, perms)
+ errs <- err
+ }(region)
+ }
+ for _ = range allRegions {
+ err := <-errs
+ if err != nil {
+ ec2_err, ok := err.(*ec2.Error)
+ if ok {
+ c.Check(ec2_err.Code, Matches, "InvalidGroup.NotFound")
+ } else {
+ c.Errorf("Non-EC2 error: %s", err)
+ }
+ } else {
+ c.Errorf("Test should have errored but it seems to have succeeded")
+ }
+ }
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/ec2t_test.go b/vendor/github.com/goamz/goamz/ec2/ec2t_test.go
new file mode 100644
index 000000000..37c2e7eb7
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/ec2t_test.go
@@ -0,0 +1,581 @@
+package ec2_test
+
+import (
+ "fmt"
+ "regexp"
+ "sort"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/ec2"
+ "github.com/goamz/goamz/ec2/ec2test"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+// LocalServer represents a local ec2test fake server.
+type LocalServer struct {
+ auth aws.Auth
+ region aws.Region
+ srv *ec2test.Server
+}
+
+func (s *LocalServer) SetUp(c *C) {
+ srv, err := ec2test.NewServer()
+ c.Assert(err, IsNil)
+ c.Assert(srv, NotNil)
+
+ s.srv = srv
+ s.region = aws.Region{EC2Endpoint: srv.URL()}
+}
+
+// LocalServerSuite defines tests that will run
+// against the local ec2test server. It includes
+// selected tests from ClientTests;
+// when the ec2test functionality is sufficient, it should
+// include all of them, and ClientTests can be simply embedded.
+type LocalServerSuite struct {
+ srv LocalServer
+ ServerTests
+ clientTests ClientTests
+}
+
+var _ = Suite(&LocalServerSuite{})
+
+func (s *LocalServerSuite) SetUpSuite(c *C) {
+ s.srv.SetUp(c)
+ s.ServerTests.ec2 = ec2.NewWithClient(s.srv.auth, s.srv.region, testutil.DefaultClient)
+ s.clientTests.ec2 = ec2.NewWithClient(s.srv.auth, s.srv.region, testutil.DefaultClient)
+}
+
+func (s *LocalServerSuite) TestRunAndTerminate(c *C) {
+ s.clientTests.TestRunAndTerminate(c)
+}
+
+func (s *LocalServerSuite) TestSecurityGroups(c *C) {
+ s.clientTests.TestSecurityGroups(c)
+}
+
+// TestUserData is not defined on ServerTests because it
+// requires the ec2test server to function.
+func (s *LocalServerSuite) TestUserData(c *C) {
+ data := make([]byte, 256)
+ for i := range data {
+ data[i] = byte(i)
+ }
+ inst, err := s.ec2.RunInstances(&ec2.RunInstancesOptions{
+ ImageId: imageId,
+ InstanceType: "t1.micro",
+ UserData: data,
+ })
+ c.Assert(err, IsNil)
+ c.Assert(inst, NotNil)
+ c.Assert(inst.Instances[0].DNSName, Equals, inst.Instances[0].InstanceId+".example.com")
+
+ id := inst.Instances[0].InstanceId
+
+ defer s.ec2.TerminateInstances([]string{id})
+
+ tinst := s.srv.srv.Instance(id)
+ c.Assert(tinst, NotNil)
+ c.Assert(tinst.UserData, DeepEquals, data)
+}
+
+// AmazonServerSuite runs the ec2test server tests against a live EC2 server.
+// It will only be activated if the -all flag is specified.
+type AmazonServerSuite struct {
+ srv AmazonServer
+ ServerTests
+}
+
+var _ = Suite(&AmazonServerSuite{})
+
+func (s *AmazonServerSuite) SetUpSuite(c *C) {
+ if !testutil.Amazon {
+ c.Skip("AmazonServerSuite tests not enabled")
+ }
+ s.srv.SetUp(c)
+ s.ServerTests.ec2 = ec2.NewWithClient(s.srv.auth, aws.USEast, testutil.DefaultClient)
+}
+
+// ServerTests defines a set of tests designed to test
+// the ec2test local fake ec2 server.
+// It is not used as a test suite in itself, but embedded within
+// another type.
+type ServerTests struct {
+ ec2 *ec2.EC2
+}
+
+func terminateInstances(c *C, e *ec2.EC2, insts []*ec2.Instance) {
+ var ids []string
+ for _, inst := range insts {
+ if inst != nil {
+ ids = append(ids, inst.InstanceId)
+ }
+ }
+ _, err := e.TerminateInstances(ids)
+ c.Check(err, IsNil, Commentf("%d INSTANCES LEFT RUNNING!!!", len(ids)))
+}
+
+func (s *ServerTests) makeTestGroup(c *C, name, descr string) ec2.SecurityGroup {
+ // Clean it up if a previous test left it around.
+ _, err := s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
+ if err != nil && err.(*ec2.Error).Code != "InvalidGroup.NotFound" {
+ c.Fatalf("delete security group: %v", err)
+ }
+
+ resp, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: name, Description: descr})
+ c.Assert(err, IsNil)
+ c.Assert(resp.Name, Equals, name)
+ return resp.SecurityGroup
+}
+
+func (s *ServerTests) TestIPPerms(c *C) {
+ g0 := s.makeTestGroup(c, "goamz-test0", "ec2test group 0")
+ defer s.ec2.DeleteSecurityGroup(g0)
+
+ g1 := s.makeTestGroup(c, "goamz-test1", "ec2test group 1")
+ defer s.ec2.DeleteSecurityGroup(g1)
+
+ resp, err := s.ec2.SecurityGroups([]ec2.SecurityGroup{g0, g1}, nil)
+ c.Assert(err, IsNil)
+ c.Assert(resp.Groups, HasLen, 2)
+ c.Assert(resp.Groups[0].IPPerms, HasLen, 0)
+ c.Assert(resp.Groups[1].IPPerms, HasLen, 0)
+
+ ownerId := resp.Groups[0].OwnerId
+
+ // test some invalid parameters
+ // TODO more
+ _, err = s.ec2.AuthorizeSecurityGroup(g0, []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 0,
+ ToPort: 1024,
+ SourceIPs: []string{"z127.0.0.1/24"},
+ }})
+ c.Assert(err, NotNil)
+ c.Check(err.(*ec2.Error).Code, Equals, "InvalidPermission.Malformed")
+
+ // Check that AuthorizeSecurityGroup adds the correct authorizations.
+ _, err = s.ec2.AuthorizeSecurityGroup(g0, []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 2000,
+ ToPort: 2001,
+ SourceIPs: []string{"127.0.0.0/24"},
+ SourceGroups: []ec2.UserSecurityGroup{{
+ Name: g1.Name,
+ }, {
+ Id: g0.Id,
+ }},
+ }, {
+ Protocol: "tcp",
+ FromPort: 2000,
+ ToPort: 2001,
+ SourceIPs: []string{"200.1.1.34/32"},
+ }})
+ c.Assert(err, IsNil)
+
+ resp, err = s.ec2.SecurityGroups([]ec2.SecurityGroup{g0}, nil)
+ c.Assert(err, IsNil)
+ c.Assert(resp.Groups, HasLen, 1)
+ c.Assert(resp.Groups[0].IPPerms, HasLen, 1)
+
+ perm := resp.Groups[0].IPPerms[0]
+ srcg := perm.SourceGroups
+ c.Assert(srcg, HasLen, 2)
+
+ // Normalize so we don't care about returned order.
+ if srcg[0].Name == g1.Name {
+ srcg[0], srcg[1] = srcg[1], srcg[0]
+ }
+ c.Check(srcg[0].Name, Equals, g0.Name)
+ c.Check(srcg[0].Id, Equals, g0.Id)
+ c.Check(srcg[0].OwnerId, Equals, ownerId)
+ c.Check(srcg[1].Name, Equals, g1.Name)
+ c.Check(srcg[1].Id, Equals, g1.Id)
+ c.Check(srcg[1].OwnerId, Equals, ownerId)
+
+ sort.Strings(perm.SourceIPs)
+ c.Check(perm.SourceIPs, DeepEquals, []string{"127.0.0.0/24", "200.1.1.34/32"})
+
+ // Check that we can't delete g1 (because g0 is using it)
+ _, err = s.ec2.DeleteSecurityGroup(g1)
+ c.Assert(err, NotNil)
+ c.Check(err.(*ec2.Error).Code, Equals, "InvalidGroup.InUse")
+
+ _, err = s.ec2.RevokeSecurityGroup(g0, []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 2000,
+ ToPort: 2001,
+ SourceGroups: []ec2.UserSecurityGroup{{Id: g1.Id}},
+ }, {
+ Protocol: "tcp",
+ FromPort: 2000,
+ ToPort: 2001,
+ SourceIPs: []string{"200.1.1.34/32"},
+ }})
+ c.Assert(err, IsNil)
+
+ resp, err = s.ec2.SecurityGroups([]ec2.SecurityGroup{g0}, nil)
+ c.Assert(err, IsNil)
+ c.Assert(resp.Groups, HasLen, 1)
+ c.Assert(resp.Groups[0].IPPerms, HasLen, 1)
+
+ perm = resp.Groups[0].IPPerms[0]
+ srcg = perm.SourceGroups
+ c.Assert(srcg, HasLen, 1)
+ c.Check(srcg[0].Name, Equals, g0.Name)
+ c.Check(srcg[0].Id, Equals, g0.Id)
+ c.Check(srcg[0].OwnerId, Equals, ownerId)
+
+ c.Check(perm.SourceIPs, DeepEquals, []string{"127.0.0.0/24"})
+
+ // We should be able to delete g1 now because we've removed its only use.
+ _, err = s.ec2.DeleteSecurityGroup(g1)
+ c.Assert(err, IsNil)
+
+ _, err = s.ec2.DeleteSecurityGroup(g0)
+ c.Assert(err, IsNil)
+
+ f := ec2.NewFilter()
+ f.Add("group-id", g0.Id, g1.Id)
+ resp, err = s.ec2.SecurityGroups(nil, f)
+ c.Assert(err, IsNil)
+ c.Assert(resp.Groups, HasLen, 0)
+}
+
+func (s *ServerTests) TestDuplicateIPPerm(c *C) {
+ name := "goamz-test"
+ descr := "goamz security group for tests"
+
+ // Clean it up, if a previous test left it around and avoid leaving it around.
+ s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
+ defer s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name})
+
+ resp1, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: name, Description: descr})
+ c.Assert(err, IsNil)
+ c.Assert(resp1.Name, Equals, name)
+
+ perms := []ec2.IPPerm{{
+ Protocol: "tcp",
+ FromPort: 200,
+ ToPort: 1024,
+ SourceIPs: []string{"127.0.0.1/24"},
+ }, {
+ Protocol: "tcp",
+ FromPort: 0,
+ ToPort: 100,
+ SourceIPs: []string{"127.0.0.1/24"},
+ }}
+
+ _, err = s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: name}, perms[0:1])
+ c.Assert(err, IsNil)
+
+ _, err = s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: name}, perms[0:2])
+ c.Assert(err, ErrorMatches, `.*\(InvalidPermission.Duplicate\)`)
+}
+
+type filterSpec struct {
+ name string
+ values []string
+}
+
+func (s *ServerTests) TestInstanceFiltering(c *C) {
+ groupResp, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: sessionName("testgroup1"), Description: "testgroup one description"})
+ c.Assert(err, IsNil)
+ group1 := groupResp.SecurityGroup
+ defer s.ec2.DeleteSecurityGroup(group1)
+
+ groupResp, err = s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: sessionName("testgroup2"), Description: "testgroup two description"})
+ c.Assert(err, IsNil)
+ group2 := groupResp.SecurityGroup
+ defer s.ec2.DeleteSecurityGroup(group2)
+
+ insts := make([]*ec2.Instance, 3)
+ inst, err := s.ec2.RunInstances(&ec2.RunInstancesOptions{
+ MinCount: 2,
+ ImageId: imageId,
+ InstanceType: "t1.micro",
+ SecurityGroups: []ec2.SecurityGroup{group1},
+ })
+ c.Assert(err, IsNil)
+ insts[0] = &inst.Instances[0]
+ insts[1] = &inst.Instances[1]
+ defer terminateInstances(c, s.ec2, insts)
+
+ imageId2 := "ami-e358958a" // Natty server, i386, EBS store
+ inst, err = s.ec2.RunInstances(&ec2.RunInstancesOptions{
+ ImageId: imageId2,
+ InstanceType: "t1.micro",
+ SecurityGroups: []ec2.SecurityGroup{group2},
+ })
+ c.Assert(err, IsNil)
+ insts[2] = &inst.Instances[0]
+
+ ids := func(indices ...int) (instIds []string) {
+ for _, index := range indices {
+ instIds = append(instIds, insts[index].InstanceId)
+ }
+ return
+ }
+
+ tests := []struct {
+ about string
+ instanceIds []string // instanceIds argument to Instances method.
+ filters []filterSpec // filters argument to Instances method.
+ resultIds []string // set of instance ids of expected results.
+ allowExtra bool // resultIds may be incomplete.
+ err string // expected error.
+ }{
+ {
+ about: "check that Instances returns all instances",
+ resultIds: ids(0, 1, 2),
+ allowExtra: true,
+ }, {
+ about: "check that specifying two instance ids returns them",
+ instanceIds: ids(0, 2),
+ resultIds: ids(0, 2),
+ }, {
+ about: "check that specifying a non-existent instance id gives an error",
+ instanceIds: append(ids(0), "i-deadbeef"),
+ err: `.*\(InvalidInstanceID\.NotFound\)`,
+ }, {
+ about: "check that a filter allowed both instances returns both of them",
+ filters: []filterSpec{
+ {"instance-id", ids(0, 2)},
+ },
+ resultIds: ids(0, 2),
+ }, {
+ about: "check that a filter allowing only one instance returns it",
+ filters: []filterSpec{
+ {"instance-id", ids(1)},
+ },
+ resultIds: ids(1),
+ }, {
+ about: "check that a filter allowing no instances returns none",
+ filters: []filterSpec{
+ {"instance-id", []string{"i-deadbeef12345"}},
+ },
+ }, {
+ about: "check that filtering on group id works",
+ filters: []filterSpec{
+ {"group-id", []string{group1.Id}},
+ },
+ resultIds: ids(0, 1),
+ }, {
+ about: "check that filtering on group name works",
+ filters: []filterSpec{
+ {"group-name", []string{group1.Name}},
+ },
+ resultIds: ids(0, 1),
+ }, {
+ about: "check that filtering on image id works",
+ filters: []filterSpec{
+ {"image-id", []string{imageId}},
+ },
+ resultIds: ids(0, 1),
+ allowExtra: true,
+ }, {
+ about: "combination filters 1",
+ filters: []filterSpec{
+ {"image-id", []string{imageId, imageId2}},
+ {"group-name", []string{group1.Name}},
+ },
+ resultIds: ids(0, 1),
+ }, {
+ about: "combination filters 2",
+ filters: []filterSpec{
+ {"image-id", []string{imageId2}},
+ {"group-name", []string{group1.Name}},
+ },
+ },
+ }
+ for i, t := range tests {
+ c.Logf("%d. %s", i, t.about)
+ var f *ec2.Filter
+ if t.filters != nil {
+ f = ec2.NewFilter()
+ for _, spec := range t.filters {
+ f.Add(spec.name, spec.values...)
+ }
+ }
+ resp, err := s.ec2.DescribeInstances(t.instanceIds, f)
+ if t.err != "" {
+ c.Check(err, ErrorMatches, t.err)
+ continue
+ }
+ c.Assert(err, IsNil)
+ insts := make(map[string]*ec2.Instance)
+ for _, r := range resp.Reservations {
+ for j := range r.Instances {
+ inst := &r.Instances[j]
+ c.Check(insts[inst.InstanceId], IsNil, Commentf("duplicate instance id: %q", inst.InstanceId))
+ insts[inst.InstanceId] = inst
+ }
+ }
+ if !t.allowExtra {
+ c.Check(insts, HasLen, len(t.resultIds), Commentf("expected %d instances got %#v", len(t.resultIds), insts))
+ }
+ for j, id := range t.resultIds {
+ c.Check(insts[id], NotNil, Commentf("instance id %d (%q) not found; got %#v", j, id, insts))
+ }
+ }
+}
+
+func idsOnly(gs []ec2.SecurityGroup) []ec2.SecurityGroup {
+ for i := range gs {
+ gs[i].Name = ""
+ }
+ return gs
+}
+
+func namesOnly(gs []ec2.SecurityGroup) []ec2.SecurityGroup {
+ for i := range gs {
+ gs[i].Id = ""
+ }
+ return gs
+}
+
+func (s *ServerTests) TestGroupFiltering(c *C) {
+ g := make([]ec2.SecurityGroup, 4)
+ for i := range g {
+ resp, err := s.ec2.CreateSecurityGroup(ec2.SecurityGroup{Name: sessionName(fmt.Sprintf("testgroup%d", i)), Description: fmt.Sprintf("testdescription%d", i)})
+ c.Assert(err, IsNil)
+ g[i] = resp.SecurityGroup
+ c.Logf("group %d: %v", i, g[i])
+ defer s.ec2.DeleteSecurityGroup(g[i])
+ }
+
+ perms := [][]ec2.IPPerm{
+ {{
+ Protocol: "tcp",
+ FromPort: 100,
+ ToPort: 200,
+ SourceIPs: []string{"1.2.3.4/32"},
+ }},
+ {{
+ Protocol: "tcp",
+ FromPort: 200,
+ ToPort: 300,
+ SourceGroups: []ec2.UserSecurityGroup{{Id: g[1].Id}},
+ }},
+ {{
+ Protocol: "udp",
+ FromPort: 200,
+ ToPort: 400,
+ SourceGroups: []ec2.UserSecurityGroup{{Id: g[1].Id}},
+ }},
+ }
+ for i, ps := range perms {
+ _, err := s.ec2.AuthorizeSecurityGroup(g[i], ps)
+ c.Assert(err, IsNil)
+ }
+
+ groups := func(indices ...int) (gs []ec2.SecurityGroup) {
+ for _, index := range indices {
+ gs = append(gs, g[index])
+ }
+ return
+ }
+
+ type groupTest struct {
+ about string
+ groups []ec2.SecurityGroup // groupIds argument to SecurityGroups method.
+ filters []filterSpec // filters argument to SecurityGroups method.
+ results []ec2.SecurityGroup // set of expected result groups.
+ allowExtra bool // specified results may be incomplete.
+ err string // expected error.
+ }
+ filterCheck := func(name, val string, gs []ec2.SecurityGroup) groupTest {
+ return groupTest{
+ about: "filter check " + name,
+ filters: []filterSpec{{name, []string{val}}},
+ results: gs,
+ allowExtra: true,
+ }
+ }
+ tests := []groupTest{
+ {
+ about: "check that SecurityGroups returns all groups",
+ results: groups(0, 1, 2, 3),
+ allowExtra: true,
+ }, {
+ about: "check that specifying two group ids returns them",
+ groups: idsOnly(groups(0, 2)),
+ results: groups(0, 2),
+ }, {
+ about: "check that specifying names only works",
+ groups: namesOnly(groups(0, 2)),
+ results: groups(0, 2),
+ }, {
+ about: "check that specifying a non-existent group id gives an error",
+ groups: append(groups(0), ec2.SecurityGroup{Id: "sg-eeeeeeeee"}),
+ err: `.*\(InvalidGroup\.NotFound\)`,
+ }, {
+ about: "check that a filter allowed two groups returns both of them",
+ filters: []filterSpec{
+ {"group-id", []string{g[0].Id, g[2].Id}},
+ },
+ results: groups(0, 2),
+ },
+ {
+ about: "check that the previous filter works when specifying a list of ids",
+ groups: groups(1, 2),
+ filters: []filterSpec{
+ {"group-id", []string{g[0].Id, g[2].Id}},
+ },
+ results: groups(2),
+ }, {
+ about: "check that a filter allowing no groups returns none",
+ filters: []filterSpec{
+ {"group-id", []string{"sg-eeeeeeeee"}},
+ },
+ },
+ filterCheck("description", "testdescription1", groups(1)),
+ filterCheck("group-name", g[2].Name, groups(2)),
+ filterCheck("ip-permission.cidr", "1.2.3.4/32", groups(0)),
+ filterCheck("ip-permission.group-name", g[1].Name, groups(1, 2)),
+ filterCheck("ip-permission.protocol", "udp", groups(2)),
+ filterCheck("ip-permission.from-port", "200", groups(1, 2)),
+ filterCheck("ip-permission.to-port", "200", groups(0)),
+ // TODO owner-id
+ }
+ for i, t := range tests {
+ c.Logf("%d. %s", i, t.about)
+ var f *ec2.Filter
+ if t.filters != nil {
+ f = ec2.NewFilter()
+ for _, spec := range t.filters {
+ f.Add(spec.name, spec.values...)
+ }
+ }
+ resp, err := s.ec2.SecurityGroups(t.groups, f)
+ if t.err != "" {
+ c.Check(err, ErrorMatches, t.err)
+ continue
+ }
+ c.Assert(err, IsNil)
+ groups := make(map[string]*ec2.SecurityGroup)
+ for j := range resp.Groups {
+ group := &resp.Groups[j].SecurityGroup
+ c.Check(groups[group.Id], IsNil, Commentf("duplicate group id: %q", group.Id))
+
+ groups[group.Id] = group
+ }
+ // If extra groups may be returned, eliminate all groups that
+ // we did not create in this session apart from the default group.
+ if t.allowExtra {
+ namePat := regexp.MustCompile(sessionName("testgroup[0-9]"))
+ for id, g := range groups {
+ if !namePat.MatchString(g.Name) {
+ delete(groups, id)
+ }
+ }
+ }
+ c.Check(groups, HasLen, len(t.results))
+ for j, g := range t.results {
+ rg := groups[g.Id]
+ c.Assert(rg, NotNil, Commentf("group %d (%v) not found; got %#v", j, g, groups))
+ c.Check(rg.Name, Equals, g.Name, Commentf("group %d (%v)", j, g))
+ }
+ }
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/ec2test/filter.go b/vendor/github.com/goamz/goamz/ec2/ec2test/filter.go
new file mode 100644
index 000000000..1a0c04619
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/ec2test/filter.go
@@ -0,0 +1,84 @@
+package ec2test
+
+import (
+ "fmt"
+ "net/url"
+ "strings"
+)
+
+// filter holds an ec2 filter. A filter maps an attribute to a set of
+// possible values for that attribute. For an item to pass through the
+// filter, every attribute of the item mentioned in the filter must match
+// at least one of its given values.
+type filter map[string][]string
+
+// newFilter creates a new filter from the Filter fields in the url form.
+//
+// The filtering is specified through a map of name=>values, where the
+// name is a well-defined key identifying the data to be matched,
+// and the list of values holds the possible values the filtered
+// item can take for the key to be included in the
+// result set. For example:
+//
+// Filter.1.Name=instance-type
+// Filter.1.Value.1=m1.small
+// Filter.1.Value.2=m1.large
+//
+func newFilter(form url.Values) filter {
+ // TODO return an error if the fields are not well formed?
+ names := make(map[int]string)
+ values := make(map[int][]string)
+ maxId := 0
+ for name, fvalues := range form {
+ var rest string
+ var id int
+ if x, _ := fmt.Sscanf(name, "Filter.%d.%s", &id, &rest); x != 2 {
+ continue
+ }
+ if id > maxId {
+ maxId = id
+ }
+ if rest == "Name" {
+ names[id] = fvalues[0]
+ continue
+ }
+ if !strings.HasPrefix(rest, "Value.") {
+ continue
+ }
+ values[id] = append(values[id], fvalues[0])
+ }
+
+ f := make(filter)
+ for id, name := range names {
+ f[name] = values[id]
+ }
+ return f
+}
+
+func notDigit(r rune) bool {
+ return r < '0' || r > '9'
+}
+
+// filterable represents an object that can be passed through a filter.
+type filterable interface {
+ // matchAttr returns true if given attribute of the
+ // object matches value. It returns an error if the
+ // attribute is not recognised or the value is malformed.
+ matchAttr(attr, value string) (bool, error)
+}
+
+// ok returns true if x passes through the filter.
+func (f filter) ok(x filterable) (bool, error) {
+next:
+ for a, vs := range f {
+ for _, v := range vs {
+ if ok, err := x.matchAttr(a, v); ok {
+ continue next
+ } else if err != nil {
+ return false, fmt.Errorf("bad attribute or value %q=%q for type %T: %v", a, v, x, err)
+ }
+ }
+ return false, nil
+ }
+ return true, nil
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/ec2test/server.go b/vendor/github.com/goamz/goamz/ec2/ec2test/server.go
new file mode 100644
index 000000000..e25d4ea20
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/ec2test/server.go
@@ -0,0 +1,993 @@
+// The ec2test package implements a fake EC2 provider with
+// the capability of inducing errors on any given operation,
+// and retrospectively determining what operations have been
+// carried out.
+package ec2test
+
+import (
+ "encoding/base64"
+ "encoding/xml"
+ "fmt"
+ "github.com/goamz/goamz/ec2"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+var b64 = base64.StdEncoding
+
+// Action represents a request that changes the ec2 state.
+type Action struct {
+ RequestId string
+
+ // Request holds the requested action as a url.Values instance
+ Request url.Values
+
+ // If the action succeeded, Response holds the value that
+ // was marshalled to build the XML response for the request.
+ Response interface{}
+
+ // If the action failed, Err holds an error giving details of the failure.
+ Err *ec2.Error
+}
+
+// TODO possible other things:
+// - some virtual time stamp interface, so a client
+// can ask for all actions after a certain virtual time.
+
+// Server implements an EC2 simulator for use in testing.
+type Server struct {
+ url string
+ listener net.Listener
+ mu sync.Mutex
+ reqs []*Action
+
+ instances map[string]*Instance // id -> instance
+ reservations map[string]*reservation // id -> reservation
+ groups map[string]*securityGroup // id -> group
+ maxId counter
+ reqId counter
+ reservationId counter
+ groupId counter
+ initialInstanceState ec2.InstanceState
+}
+
+// reservation holds a simulated ec2 reservation.
+type reservation struct {
+ id string
+ instances map[string]*Instance
+ groups []*securityGroup
+}
+
+// instance holds a simulated ec2 instance
+type Instance struct {
+ // UserData holds the data that was passed to the RunInstances request
+ // when the instance was started.
+ UserData []byte
+ id string
+ imageId string
+ reservation *reservation
+ instType string
+ state ec2.InstanceState
+}
+
+// permKey represents permission for a given security
+// group or IP address (but not both) to access a given range of
+// ports. Equality of permKeys is used in the implementation of
+// permission sets, relying on the uniqueness of securityGroup
+// instances.
+type permKey struct {
+ protocol string
+ fromPort int
+ toPort int
+ group *securityGroup
+ ipAddr string
+}
+
+// securityGroup holds a simulated ec2 security group.
+// Instances of securityGroup should only be created through
+// Server.createSecurityGroup to ensure that groups can be
+// compared by pointer value.
+type securityGroup struct {
+ id string
+ name string
+ description string
+
+ perms map[permKey]bool
+}
+
+func (g *securityGroup) ec2SecurityGroup() ec2.SecurityGroup {
+ return ec2.SecurityGroup{
+ Name: g.name,
+ Id: g.id,
+ }
+}
+
+func (g *securityGroup) matchAttr(attr, value string) (ok bool, err error) {
+ switch attr {
+ case "description":
+ return g.description == value, nil
+ case "group-id":
+ return g.id == value, nil
+ case "group-name":
+ return g.name == value, nil
+ case "ip-permission.cidr":
+ return g.hasPerm(func(k permKey) bool { return k.ipAddr == value }), nil
+ case "ip-permission.group-name":
+ return g.hasPerm(func(k permKey) bool {
+ return k.group != nil && k.group.name == value
+ }), nil
+ case "ip-permission.from-port":
+ port, err := strconv.Atoi(value)
+ if err != nil {
+ return false, err
+ }
+ return g.hasPerm(func(k permKey) bool { return k.fromPort == port }), nil
+ case "ip-permission.to-port":
+ port, err := strconv.Atoi(value)
+ if err != nil {
+ return false, err
+ }
+ return g.hasPerm(func(k permKey) bool { return k.toPort == port }), nil
+ case "ip-permission.protocol":
+ return g.hasPerm(func(k permKey) bool { return k.protocol == value }), nil
+ case "owner-id":
+ return value == ownerId, nil
+ }
+ return false, fmt.Errorf("unknown attribute %q", attr)
+}
+
+func (g *securityGroup) hasPerm(test func(k permKey) bool) bool {
+ for k := range g.perms {
+ if test(k) {
+ return true
+ }
+ }
+ return false
+}
+
+// ec2Perms returns the list of EC2 permissions granted
+// to g. It groups permissions by port range and protocol.
+func (g *securityGroup) ec2Perms() (perms []ec2.IPPerm) {
+ // The grouping is held in result. We use permKey for convenience,
+ // (ensuring that the group and ipAddr of each key is zero). For
+ // each protocol/port range combination, we build up the permission
+ // set in the associated value.
+ result := make(map[permKey]*ec2.IPPerm)
+ for k := range g.perms {
+ groupKey := k
+ groupKey.group = nil
+ groupKey.ipAddr = ""
+
+ ec2p := result[groupKey]
+ if ec2p == nil {
+ ec2p = &ec2.IPPerm{
+ Protocol: k.protocol,
+ FromPort: k.fromPort,
+ ToPort: k.toPort,
+ }
+ result[groupKey] = ec2p
+ }
+ if k.group != nil {
+ ec2p.SourceGroups = append(ec2p.SourceGroups,
+ ec2.UserSecurityGroup{
+ Id: k.group.id,
+ Name: k.group.name,
+ OwnerId: ownerId,
+ })
+ } else {
+ ec2p.SourceIPs = append(ec2p.SourceIPs, k.ipAddr)
+ }
+ }
+ for _, ec2p := range result {
+ perms = append(perms, *ec2p)
+ }
+ return
+}
+
+var actions = map[string]func(*Server, http.ResponseWriter, *http.Request, string) interface{}{
+ "RunInstances": (*Server).runInstances,
+ "TerminateInstances": (*Server).terminateInstances,
+ "DescribeInstances": (*Server).describeInstances,
+ "CreateSecurityGroup": (*Server).createSecurityGroup,
+ "DescribeSecurityGroups": (*Server).describeSecurityGroups,
+ "DeleteSecurityGroup": (*Server).deleteSecurityGroup,
+ "AuthorizeSecurityGroupIngress": (*Server).authorizeSecurityGroupIngress,
+ "RevokeSecurityGroupIngress": (*Server).revokeSecurityGroupIngress,
+}
+
+const ownerId = "9876"
+
+// newAction allocates a new action and adds it to the
+// recorded list of server actions.
+func (srv *Server) newAction() *Action {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+
+ a := new(Action)
+ srv.reqs = append(srv.reqs, a)
+ return a
+}
+
+// NewServer returns a new server.
+func NewServer() (*Server, error) {
+ srv := &Server{
+ instances: make(map[string]*Instance),
+ groups: make(map[string]*securityGroup),
+ reservations: make(map[string]*reservation),
+ initialInstanceState: Pending,
+ }
+
+ // Add default security group.
+ g := &securityGroup{
+ name: "default",
+ description: "default group",
+ id: fmt.Sprintf("sg-%d", srv.groupId.next()),
+ }
+ g.perms = map[permKey]bool{
+ permKey{
+ protocol: "icmp",
+ fromPort: -1,
+ toPort: -1,
+ group: g,
+ }: true,
+ permKey{
+ protocol: "tcp",
+ fromPort: 0,
+ toPort: 65535,
+ group: g,
+ }: true,
+ permKey{
+ protocol: "udp",
+ fromPort: 0,
+ toPort: 65535,
+ group: g,
+ }: true,
+ }
+ srv.groups[g.id] = g
+
+ l, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ return nil, fmt.Errorf("cannot listen on localhost: %v", err)
+ }
+ srv.listener = l
+
+ srv.url = "http://" + l.Addr().String()
+
+ // we use HandlerFunc rather than *Server directly so that we
+ // can avoid exporting HandlerFunc from *Server.
+ go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ srv.serveHTTP(w, req)
+ }))
+ return srv, nil
+}
+
+// Quit closes down the server.
+func (srv *Server) Quit() {
+ srv.listener.Close()
+}
+
+// SetInitialInstanceState sets the state that any new instances will be started in.
+func (srv *Server) SetInitialInstanceState(state ec2.InstanceState) {
+ srv.mu.Lock()
+ srv.initialInstanceState = state
+ srv.mu.Unlock()
+}
+
+// URL returns the URL of the server.
+func (srv *Server) URL() string {
+ return srv.url
+}
+
+// serveHTTP serves the EC2 protocol.
+func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) {
+ req.ParseForm()
+
+ a := srv.newAction()
+ a.RequestId = fmt.Sprintf("req%d", srv.reqId.next())
+ a.Request = req.Form
+
+ // Methods on Server that deal with parsing user data
+ // may fail. To save on error handling code, we allow these
+ // methods to call fatalf, which will panic with an *ec2.Error
+ // which will be caught here and returned
+ // to the client as a properly formed EC2 error.
+ defer func() {
+ switch err := recover().(type) {
+ case *ec2.Error:
+ a.Err = err
+ err.RequestId = a.RequestId
+ writeError(w, err)
+ case nil:
+ default:
+ panic(err)
+ }
+ }()
+
+ f := actions[req.Form.Get("Action")]
+ if f == nil {
+ fatalf(400, "InvalidParameterValue", "Unrecognized Action")
+ }
+
+ response := f(srv, w, req, a.RequestId)
+ a.Response = response
+
+ w.Header().Set("Content-Type", `xml version="1.0" encoding="UTF-8"`)
+ xmlMarshal(w, response)
+}
+
+// Instance returns the instance for the given instance id.
+// It returns nil if there is no such instance.
+func (srv *Server) Instance(id string) *Instance {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ return srv.instances[id]
+}
+
+// writeError writes an appropriate error response.
+// TODO how should we deal with errors when the
+// error itself is potentially generated by backend-agnostic
+// code?
+func writeError(w http.ResponseWriter, err *ec2.Error) {
+ // Error encapsulates an error returned by EC2.
+ // TODO merge with ec2.Error when xml supports ignoring a field.
+ type ec2error struct {
+ Code string // EC2 error code ("UnsupportedOperation", ...)
+ Message string // The human-oriented error message
+ RequestId string
+ }
+
+ type Response struct {
+ RequestId string
+ Errors []ec2error `xml:"Errors>Error"`
+ }
+
+ w.Header().Set("Content-Type", `xml version="1.0" encoding="UTF-8"`)
+ w.WriteHeader(err.StatusCode)
+ xmlMarshal(w, Response{
+ RequestId: err.RequestId,
+ Errors: []ec2error{{
+ Code: err.Code,
+ Message: err.Message,
+ }},
+ })
+}
+
+// xmlMarshal is the same as xml.Marshal except that
+// it panics on error. The marshalling should not fail,
+// but we want to know if it does.
+func xmlMarshal(w io.Writer, x interface{}) {
+ if err := xml.NewEncoder(w).Encode(x); err != nil {
+ panic(fmt.Errorf("error marshalling %#v: %v", x, err))
+ }
+}
+
+// formToGroups parses a set of SecurityGroup form values
+// as found in a RunInstances request, and returns the resulting
+// slice of security groups.
+// It calls fatalf if a group is not found.
+func (srv *Server) formToGroups(form url.Values) []*securityGroup {
+ var groups []*securityGroup
+ for name, values := range form {
+ switch {
+ case strings.HasPrefix(name, "SecurityGroupId."):
+ if g := srv.groups[values[0]]; g != nil {
+ groups = append(groups, g)
+ } else {
+ fatalf(400, "InvalidGroup.NotFound", "unknown group id %q", values[0])
+ }
+ case strings.HasPrefix(name, "SecurityGroup."):
+ var found *securityGroup
+ for _, g := range srv.groups {
+ if g.name == values[0] {
+ found = g
+ }
+ }
+ if found == nil {
+ fatalf(400, "InvalidGroup.NotFound", "unknown group name %q", values[0])
+ }
+ groups = append(groups, found)
+ }
+ }
+ return groups
+}
+
+// runInstances implements the EC2 RunInstances entry point.
+func (srv *Server) runInstances(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ min := atoi(req.Form.Get("MinCount"))
+ max := atoi(req.Form.Get("MaxCount"))
+ if min < 0 || max < 1 {
+ fatalf(400, "InvalidParameterValue", "bad values for MinCount or MaxCount")
+ }
+ if min > max {
+ fatalf(400, "InvalidParameterCombination", "MinCount is greater than MaxCount")
+ }
+ var userData []byte
+ if data := req.Form.Get("UserData"); data != "" {
+ var err error
+ userData, err = b64.DecodeString(data)
+ if err != nil {
+ fatalf(400, "InvalidParameterValue", "bad UserData value: %v", err)
+ }
+ }
+
+ // TODO attributes still to consider:
+ // ImageId: accept anything, we can verify later
+ // KeyName ?
+ // InstanceType ?
+ // KernelId ?
+ // RamdiskId ?
+ // AvailabilityZone ?
+ // GroupName tag
+ // Monitoring ignore?
+ // SubnetId ?
+ // DisableAPITermination bool
+ // ShutdownBehavior string
+ // PrivateIPAddress string
+
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+
+ // make sure that form fields are correct before creating the reservation.
+ instType := req.Form.Get("InstanceType")
+ imageId := req.Form.Get("ImageId")
+
+ r := srv.newReservation(srv.formToGroups(req.Form))
+
+ var resp ec2.RunInstancesResp
+ resp.RequestId = reqId
+ resp.ReservationId = r.id
+ resp.OwnerId = ownerId
+
+ for i := 0; i < max; i++ {
+ inst := srv.newInstance(r, instType, imageId, srv.initialInstanceState)
+ inst.UserData = userData
+ resp.Instances = append(resp.Instances, inst.ec2instance())
+ }
+ return &resp
+}
+
+func (srv *Server) group(group ec2.SecurityGroup) *securityGroup {
+ if group.Id != "" {
+ return srv.groups[group.Id]
+ }
+ for _, g := range srv.groups {
+ if g.name == group.Name {
+ return g
+ }
+ }
+ return nil
+}
+
+// NewInstances creates n new instances in srv with the given instance type,
+// image ID, initial state and security groups. If any group does not already
+// exist, it will be created. NewInstances returns the ids of the new instances.
+func (srv *Server) NewInstances(n int, instType string, imageId string, state ec2.InstanceState, groups []ec2.SecurityGroup) []string {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+
+ rgroups := make([]*securityGroup, len(groups))
+ for i, group := range groups {
+ g := srv.group(group)
+ if g == nil {
+ fatalf(400, "InvalidGroup.NotFound", "no such group %v", g)
+ }
+ rgroups[i] = g
+ }
+ r := srv.newReservation(rgroups)
+
+ ids := make([]string, n)
+ for i := 0; i < n; i++ {
+ inst := srv.newInstance(r, instType, imageId, state)
+ ids[i] = inst.id
+ }
+ return ids
+}
+
+func (srv *Server) newInstance(r *reservation, instType string, imageId string, state ec2.InstanceState) *Instance {
+ inst := &Instance{
+ id: fmt.Sprintf("i-%d", srv.maxId.next()),
+ instType: instType,
+ imageId: imageId,
+ state: state,
+ reservation: r,
+ }
+ srv.instances[inst.id] = inst
+ r.instances[inst.id] = inst
+ return inst
+}
+
+func (srv *Server) newReservation(groups []*securityGroup) *reservation {
+ r := &reservation{
+ id: fmt.Sprintf("r-%d", srv.reservationId.next()),
+ instances: make(map[string]*Instance),
+ groups: groups,
+ }
+
+ srv.reservations[r.id] = r
+ return r
+}
+
+func (srv *Server) terminateInstances(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ var resp ec2.TerminateInstancesResp
+ resp.RequestId = reqId
+ var insts []*Instance
+ for attr, vals := range req.Form {
+ if strings.HasPrefix(attr, "InstanceId.") {
+ id := vals[0]
+ inst := srv.instances[id]
+ if inst == nil {
+ fatalf(400, "InvalidInstanceID.NotFound", "no such instance id %q", id)
+ }
+ insts = append(insts, inst)
+ }
+ }
+ for _, inst := range insts {
+ resp.StateChanges = append(resp.StateChanges, inst.terminate())
+ }
+ return &resp
+}
+
+func (inst *Instance) terminate() (d ec2.InstanceStateChange) {
+ d.PreviousState = inst.state
+ inst.state = ShuttingDown
+ d.CurrentState = inst.state
+ d.InstanceId = inst.id
+ return d
+}
+
+func (inst *Instance) ec2instance() ec2.Instance {
+ return ec2.Instance{
+ InstanceId: inst.id,
+ InstanceType: inst.instType,
+ ImageId: inst.imageId,
+ DNSName: fmt.Sprintf("%s.example.com", inst.id),
+ // TODO the rest
+ }
+}
+
+func (inst *Instance) matchAttr(attr, value string) (ok bool, err error) {
+ switch attr {
+ case "architecture":
+ return value == "i386", nil
+ case "instance-id":
+ return inst.id == value, nil
+ case "group-id":
+ for _, g := range inst.reservation.groups {
+ if g.id == value {
+ return true, nil
+ }
+ }
+ return false, nil
+ case "group-name":
+ for _, g := range inst.reservation.groups {
+ if g.name == value {
+ return true, nil
+ }
+ }
+ return false, nil
+ case "image-id":
+ return value == inst.imageId, nil
+ case "instance-state-code":
+ code, err := strconv.Atoi(value)
+ if err != nil {
+ return false, err
+ }
+ return code&0xff == inst.state.Code, nil
+ case "instance-state-name":
+ return value == inst.state.Name, nil
+ }
+ return false, fmt.Errorf("unknown attribute %q", attr)
+}
+
+var (
+ Pending = ec2.InstanceState{0, "pending"}
+ Running = ec2.InstanceState{16, "running"}
+ ShuttingDown = ec2.InstanceState{32, "shutting-down"}
+ Terminated = ec2.InstanceState{16, "terminated"}
+ Stopped = ec2.InstanceState{16, "stopped"}
+)
+
+func (srv *Server) createSecurityGroup(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ name := req.Form.Get("GroupName")
+ if name == "" {
+ fatalf(400, "InvalidParameterValue", "empty security group name")
+ }
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ if srv.group(ec2.SecurityGroup{Name: name}) != nil {
+ fatalf(400, "InvalidGroup.Duplicate", "group %q already exists", name)
+ }
+ g := &securityGroup{
+ name: name,
+ description: req.Form.Get("GroupDescription"),
+ id: fmt.Sprintf("sg-%d", srv.groupId.next()),
+ perms: make(map[permKey]bool),
+ }
+ srv.groups[g.id] = g
+ // we define a local type for this because ec2.CreateSecurityGroupResp
+ // contains SecurityGroup, but the response to this request
+ // should not contain the security group name.
+ type CreateSecurityGroupResponse struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"`
+ GroupId string `xml:"groupId"`
+ }
+ r := &CreateSecurityGroupResponse{
+ RequestId: reqId,
+ Return: true,
+ GroupId: g.id,
+ }
+ return r
+}
+
+func (srv *Server) notImplemented(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ fatalf(500, "InternalError", "not implemented")
+ panic("not reached")
+}
+
+func (srv *Server) describeInstances(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ insts := make(map[*Instance]bool)
+ for name, vals := range req.Form {
+ if !strings.HasPrefix(name, "InstanceId.") {
+ continue
+ }
+ inst := srv.instances[vals[0]]
+ if inst == nil {
+ fatalf(400, "InvalidInstanceID.NotFound", "instance %q not found", vals[0])
+ }
+ insts[inst] = true
+ }
+
+ f := newFilter(req.Form)
+
+ var resp ec2.DescribeInstancesResp
+ resp.RequestId = reqId
+ for _, r := range srv.reservations {
+ var instances []ec2.Instance
+ for _, inst := range r.instances {
+ if len(insts) > 0 && !insts[inst] {
+ continue
+ }
+ ok, err := f.ok(inst)
+ if ok {
+ instances = append(instances, inst.ec2instance())
+ } else if err != nil {
+ fatalf(400, "InvalidParameterValue", "describe instances: %v", err)
+ }
+ }
+ if len(instances) > 0 {
+ var groups []ec2.SecurityGroup
+ for _, g := range r.groups {
+ groups = append(groups, g.ec2SecurityGroup())
+ }
+ resp.Reservations = append(resp.Reservations, ec2.Reservation{
+ ReservationId: r.id,
+ OwnerId: ownerId,
+ Instances: instances,
+ SecurityGroups: groups,
+ })
+ }
+ }
+ return &resp
+}
+
+func (srv *Server) describeSecurityGroups(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ // BUG similar bug to describeInstances, but for GroupName and GroupId
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+
+ var groups []*securityGroup
+ for name, vals := range req.Form {
+ var g ec2.SecurityGroup
+ switch {
+ case strings.HasPrefix(name, "GroupName."):
+ g.Name = vals[0]
+ case strings.HasPrefix(name, "GroupId."):
+ g.Id = vals[0]
+ default:
+ continue
+ }
+ sg := srv.group(g)
+ if sg == nil {
+ fatalf(400, "InvalidGroup.NotFound", "no such group %v", g)
+ }
+ groups = append(groups, sg)
+ }
+ if len(groups) == 0 {
+ for _, g := range srv.groups {
+ groups = append(groups, g)
+ }
+ }
+
+ f := newFilter(req.Form)
+ var resp ec2.SecurityGroupsResp
+ resp.RequestId = reqId
+ for _, group := range groups {
+ ok, err := f.ok(group)
+ if ok {
+ resp.Groups = append(resp.Groups, ec2.SecurityGroupInfo{
+ OwnerId: ownerId,
+ SecurityGroup: group.ec2SecurityGroup(),
+ Description: group.description,
+ IPPerms: group.ec2Perms(),
+ })
+ } else if err != nil {
+ fatalf(400, "InvalidParameterValue", "describe security groups: %v", err)
+ }
+ }
+ return &resp
+}
+
+func (srv *Server) authorizeSecurityGroupIngress(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ g := srv.group(ec2.SecurityGroup{
+ Name: req.Form.Get("GroupName"),
+ Id: req.Form.Get("GroupId"),
+ })
+ if g == nil {
+ fatalf(400, "InvalidGroup.NotFound", "group not found")
+ }
+ perms := srv.parsePerms(req)
+
+ for _, p := range perms {
+ if g.perms[p] {
+ fatalf(400, "InvalidPermission.Duplicate", "Permission has already been authorized on the specified group")
+ }
+ }
+ for _, p := range perms {
+ g.perms[p] = true
+ }
+ return &ec2.SimpleResp{
+ XMLName: xml.Name{"", "AuthorizeSecurityGroupIngressResponse"},
+ RequestId: reqId,
+ }
+}
+
+func (srv *Server) revokeSecurityGroupIngress(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ g := srv.group(ec2.SecurityGroup{
+ Name: req.Form.Get("GroupName"),
+ Id: req.Form.Get("GroupId"),
+ })
+ if g == nil {
+ fatalf(400, "InvalidGroup.NotFound", "group not found")
+ }
+ perms := srv.parsePerms(req)
+
+ // Note EC2 does not give an error if asked to revoke an authorization
+ // that does not exist.
+ for _, p := range perms {
+ delete(g.perms, p)
+ }
+ return &ec2.SimpleResp{
+ XMLName: xml.Name{"", "RevokeSecurityGroupIngressResponse"},
+ RequestId: reqId,
+ }
+}
+
+var secGroupPat = regexp.MustCompile(`^sg-[a-z0-9]+$`)
+var ipPat = regexp.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$`)
+var ownerIdPat = regexp.MustCompile(`^[0-9]+$`)
+
+// parsePerms returns a slice of permKey values extracted
+// from the permission fields in req.
+func (srv *Server) parsePerms(req *http.Request) []permKey {
+ // perms maps an index found in the form to its associated
+ // IPPerm. For instance, the form value with key
+ // "IpPermissions.3.FromPort" will be stored in perms[3].FromPort
+ perms := make(map[int]ec2.IPPerm)
+
+ type subgroupKey struct {
+ id1, id2 int
+ }
+ // Each IPPerm can have many source security groups. The form key
+ // for a source security group contains two indices: the index
+ // of the IPPerm and the sub-index of the security group. The
+ // sourceGroups map maps from a subgroupKey containing these
+ // two indices to the associated security group. For instance,
+ // the form value with key "IPPermissions.3.Groups.2.GroupName"
+ // will be stored in sourceGroups[subgroupKey{3, 2}].Name.
+ sourceGroups := make(map[subgroupKey]ec2.UserSecurityGroup)
+
+ // For each value in the form we store its associated information in the
+ // above maps. The maps are necessary because the form keys may
+ // arrive in any order, and the indices are not
+ // necessarily sequential or even small.
+ for name, vals := range req.Form {
+ val := vals[0]
+ var id1 int
+ var rest string
+ if x, _ := fmt.Sscanf(name, "IpPermissions.%d.%s", &id1, &rest); x != 2 {
+ continue
+ }
+ ec2p := perms[id1]
+ switch {
+ case rest == "FromPort":
+ ec2p.FromPort = atoi(val)
+ case rest == "ToPort":
+ ec2p.ToPort = atoi(val)
+ case rest == "IpProtocol":
+ switch val {
+ case "tcp", "udp", "icmp":
+ ec2p.Protocol = val
+ default:
+ // check it's a well formed number
+ atoi(val)
+ ec2p.Protocol = val
+ }
+ case strings.HasPrefix(rest, "Groups."):
+ k := subgroupKey{id1: id1}
+ if x, _ := fmt.Sscanf(rest[len("Groups."):], "%d.%s", &k.id2, &rest); x != 2 {
+ continue
+ }
+ g := sourceGroups[k]
+ switch rest {
+ case "UserId":
+ // BUG if the user id is blank, this does not conform to the
+ // way that EC2 handles it - a specified but blank owner id
+ // can cause RevokeSecurityGroupIngress to fail with
+ // "group not found" even if the security group id has been
+ // correctly specified.
+ // By failing here, we ensure that we fail early in this case.
+ if !ownerIdPat.MatchString(val) {
+ fatalf(400, "InvalidUserID.Malformed", "Invalid user ID: %q", val)
+ }
+ g.OwnerId = val
+ case "GroupName":
+ g.Name = val
+ case "GroupId":
+ if !secGroupPat.MatchString(val) {
+ fatalf(400, "InvalidGroupId.Malformed", "Invalid group ID: %q", val)
+ }
+ g.Id = val
+ default:
+ fatalf(400, "UnknownParameter", "unknown parameter %q", name)
+ }
+ sourceGroups[k] = g
+ case strings.HasPrefix(rest, "IpRanges."):
+ var id2 int
+ if x, _ := fmt.Sscanf(rest[len("IpRanges."):], "%d.%s", &id2, &rest); x != 2 {
+ continue
+ }
+ switch rest {
+ case "CidrIp":
+ if !ipPat.MatchString(val) {
+ fatalf(400, "InvalidPermission.Malformed", "Invalid IP range: %q", val)
+ }
+ ec2p.SourceIPs = append(ec2p.SourceIPs, val)
+ default:
+ fatalf(400, "UnknownParameter", "unknown parameter %q", name)
+ }
+ default:
+ fatalf(400, "UnknownParameter", "unknown parameter %q", name)
+ }
+ perms[id1] = ec2p
+ }
+ // Associate each set of source groups with its IPPerm.
+ for k, g := range sourceGroups {
+ p := perms[k.id1]
+ p.SourceGroups = append(p.SourceGroups, g)
+ perms[k.id1] = p
+ }
+
+ // Now that we have built up the IPPerms we need, we check for
+ // parameter errors and build up a permKey for each permission,
+ // looking up security groups from srv as we do so.
+ var result []permKey
+ for _, p := range perms {
+ if p.FromPort > p.ToPort {
+ fatalf(400, "InvalidParameterValue", "invalid port range")
+ }
+ k := permKey{
+ protocol: p.Protocol,
+ fromPort: p.FromPort,
+ toPort: p.ToPort,
+ }
+ for _, g := range p.SourceGroups {
+ if g.OwnerId != "" && g.OwnerId != ownerId {
+ fatalf(400, "InvalidGroup.NotFound", "group %q not found", g.Name)
+ }
+ var ec2g ec2.SecurityGroup
+ switch {
+ case g.Id != "":
+ ec2g.Id = g.Id
+ case g.Name != "":
+ ec2g.Name = g.Name
+ }
+ k.group = srv.group(ec2g)
+ if k.group == nil {
+ fatalf(400, "InvalidGroup.NotFound", "group %v not found", g)
+ }
+ result = append(result, k)
+ }
+ k.group = nil
+ for _, ip := range p.SourceIPs {
+ k.ipAddr = ip
+ result = append(result, k)
+ }
+ }
+ return result
+}
+
+func (srv *Server) deleteSecurityGroup(w http.ResponseWriter, req *http.Request, reqId string) interface{} {
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+ g := srv.group(ec2.SecurityGroup{
+ Name: req.Form.Get("GroupName"),
+ Id: req.Form.Get("GroupId"),
+ })
+ if g == nil {
+ fatalf(400, "InvalidGroup.NotFound", "group not found")
+ }
+ for _, r := range srv.reservations {
+ for _, h := range r.groups {
+ if h == g && r.hasRunningMachine() {
+ fatalf(500, "InvalidGroup.InUse", "group is currently in use by a running instance")
+ }
+ }
+ }
+ for _, sg := range srv.groups {
+ // If a group refers to itself, it's ok to delete it.
+ if sg == g {
+ continue
+ }
+ for k := range sg.perms {
+ if k.group == g {
+ fatalf(500, "InvalidGroup.InUse", "group is currently in use by group %q", sg.id)
+ }
+ }
+ }
+
+ delete(srv.groups, g.id)
+ return &ec2.SimpleResp{
+ XMLName: xml.Name{"", "DeleteSecurityGroupResponse"},
+ RequestId: reqId,
+ }
+}
+
+func (r *reservation) hasRunningMachine() bool {
+ for _, inst := range r.instances {
+ if inst.state.Code != ShuttingDown.Code && inst.state.Code != Terminated.Code {
+ return true
+ }
+ }
+ return false
+}
+
+type counter int
+
+func (c *counter) next() (i int) {
+ i = int(*c)
+ (*c)++
+ return
+}
+
+// atoi is like strconv.Atoi but is fatal if the
+// string is not well formed.
+func atoi(s string) int {
+ i, err := strconv.Atoi(s)
+ if err != nil {
+ fatalf(400, "InvalidParameterValue", "bad number: %v", err)
+ }
+ return i
+}
+
+func fatalf(statusCode int, code string, f string, a ...interface{}) {
+ panic(&ec2.Error{
+ StatusCode: statusCode,
+ Code: code,
+ Message: fmt.Sprintf(f, a...),
+ })
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/export_test.go b/vendor/github.com/goamz/goamz/ec2/export_test.go
new file mode 100644
index 000000000..78da91a07
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/export_test.go
@@ -0,0 +1,22 @@
+package ec2
+
+import (
+ "github.com/goamz/goamz/aws"
+ "time"
+)
+
+func Sign(auth aws.Auth, method, path string, params map[string]string, host string) {
+ sign(auth, method, path, params, host)
+}
+
+func fixedTime() time.Time {
+ return time.Date(2012, 1, 1, 0, 0, 0, 0, time.UTC)
+}
+
+func FakeTime(fakeIt bool) {
+ if fakeIt {
+ timeNow = fixedTime
+ } else {
+ timeNow = time.Now
+ }
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/responses_test.go b/vendor/github.com/goamz/goamz/ec2/responses_test.go
new file mode 100644
index 000000000..84186c1be
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/responses_test.go
@@ -0,0 +1,1084 @@
+package ec2_test
+
+var ErrorDump = `
+<?xml version="1.0" encoding="UTF-8"?>
+<Response><Errors><Error><Code>UnsupportedOperation</Code>
+<Message>AMIs with an instance-store root device are not supported for the instance type 't1.micro'.</Message>
+</Error></Errors><RequestID>0503f4e9-bbd6-483c-b54f-c4ae9f3b30f4</RequestID></Response>
+`
+
+// http://goo.gl/Mcm3b
+var RunInstancesExample = `
+<RunInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <reservationId>r-47a5402e</reservationId>
+ <ownerId>999988887777</ownerId>
+ <groupSet>
+ <item>
+ <groupId>sg-67ad940e</groupId>
+ <groupName>default</groupName>
+ </item>
+ </groupSet>
+ <instancesSet>
+ <item>
+ <instanceId>i-2ba64342</instanceId>
+ <imageId>ami-60a54009</imageId>
+ <instanceState>
+ <code>0</code>
+ <name>pending</name>
+ </instanceState>
+ <privateDnsName></privateDnsName>
+ <dnsName></dnsName>
+ <keyName>example-key-name</keyName>
+ <amiLaunchIndex>0</amiLaunchIndex>
+ <instanceType>m1.small</instanceType>
+ <launchTime>2007-08-07T11:51:50.000Z</launchTime>
+ <placement>
+ <availabilityZone>us-east-1b</availabilityZone>
+ </placement>
+ <monitoring>
+ <state>enabled</state>
+ </monitoring>
+ <virtualizationType>paravirtual</virtualizationType>
+ <clientToken/>
+ <tagSet/>
+ <hypervisor>xen</hypervisor>
+ </item>
+ <item>
+ <instanceId>i-2bc64242</instanceId>
+ <imageId>ami-60a54009</imageId>
+ <instanceState>
+ <code>0</code>
+ <name>pending</name>
+ </instanceState>
+ <privateDnsName></privateDnsName>
+ <dnsName></dnsName>
+ <keyName>example-key-name</keyName>
+ <amiLaunchIndex>1</amiLaunchIndex>
+ <instanceType>m1.small</instanceType>
+ <launchTime>2007-08-07T11:51:50.000Z</launchTime>
+ <placement>
+ <availabilityZone>us-east-1b</availabilityZone>
+ </placement>
+ <monitoring>
+ <state>enabled</state>
+ </monitoring>
+ <virtualizationType>paravirtual</virtualizationType>
+ <clientToken/>
+ <tagSet/>
+ <hypervisor>xen</hypervisor>
+ </item>
+ <item>
+ <instanceId>i-2be64332</instanceId>
+ <imageId>ami-60a54009</imageId>
+ <instanceState>
+ <code>0</code>
+ <name>pending</name>
+ </instanceState>
+ <privateDnsName></privateDnsName>
+ <dnsName></dnsName>
+ <keyName>example-key-name</keyName>
+ <amiLaunchIndex>2</amiLaunchIndex>
+ <instanceType>m1.small</instanceType>
+ <launchTime>2007-08-07T11:51:50.000Z</launchTime>
+ <placement>
+ <availabilityZone>us-east-1b</availabilityZone>
+ </placement>
+ <monitoring>
+ <state>enabled</state>
+ </monitoring>
+ <virtualizationType>paravirtual</virtualizationType>
+ <clientToken/>
+ <tagSet/>
+ <hypervisor>xen</hypervisor>
+ </item>
+ </instancesSet>
+</RunInstancesResponse>
+`
+
+// http://goo.gl/GRZgCD
+var RequestSpotInstancesExample = `
+<RequestSpotInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <spotInstanceRequestSet>
+ <item>
+ <spotInstanceRequestId>sir-1a2b3c4d</spotInstanceRequestId>
+ <spotPrice>0.5</spotPrice>
+ <type>one-time</type>
+ <state>open</state>
+ <status>
+ <code>pending-evaluation</code>
+ <updateTime>YYYY-MM-DDTHH:MM:SS.000Z</updateTime>
+ <message>Your Spot request has been submitted for review, and is pending evaluation.</message>
+ </status>
+ <availabilityZoneGroup>MyAzGroup</availabilityZoneGroup>
+ <launchSpecification>
+ <imageId>ami-1a2b3c4d</imageId>
+ <keyName>gsg-keypair</keyName>
+ <groupSet>
+ <item>
+ <groupId>sg-1a2b3c4d</groupId>
+ <groupName>websrv</groupName>
+ </item>
+ </groupSet>
+ <instanceType>m1.small</instanceType>
+ <blockDeviceMapping/>
+ <monitoring>
+ <enabled>false</enabled>
+ </monitoring>
+ <ebsOptimized>false</ebsOptimized>
+ </launchSpecification>
+ <createTime>YYYY-MM-DDTHH:MM:SS.000Z</createTime>
+ <productDescription>Linux/UNIX</productDescription>
+ </item>
+ </spotInstanceRequestSet>
+</RequestSpotInstancesResponse>
+`
+
+// http://goo.gl/KsKJJk
+var DescribeSpotRequestsExample = `
+<DescribeSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>b1719f2a-5334-4479-b2f1-26926EXAMPLE</requestId>
+ <spotInstanceRequestSet>
+ <item>
+ <spotInstanceRequestId>sir-1a2b3c4d</spotInstanceRequestId>
+ <spotPrice>0.5</spotPrice>
+ <type>one-time</type>
+ <state>active</state>
+ <status>
+ <code>fulfilled</code>
+ <updateTime>YYYY-MM-DDTHH:MM:SS.000Z</updateTime>
+ <message>Your Spot request is fulfilled.</message>
+ </status>
+ <launchSpecification>
+ <imageId>ami-1a2b3c4d</imageId>
+ <keyName>gsg-keypair</keyName>
+ <groupSet>
+ <item>
+ <groupId>sg-1a2b3c4d</groupId>
+ <groupName>websrv</groupName>
+ </item>
+ </groupSet>
+ <instanceType>m1.small</instanceType>
+ <monitoring>
+ <enabled>false</enabled>
+ </monitoring>
+ <ebsOptimized>false</ebsOptimized>
+ </launchSpecification>
+ <instanceId>i-1a2b3c4d</instanceId>
+ <createTime>YYYY-MM-DDTHH:MM:SS.000Z</createTime>
+ <productDescription>Linux/UNIX</productDescription>
+ <launchedAvailabilityZone>us-east-1a</launchedAvailabilityZone>
+ </item>
+ </spotInstanceRequestSet>
+</DescribeSpotInstanceRequestsResponse>
+`
+
+// http://goo.gl/DcfFgJ
+var CancelSpotRequestsExample = `
+<CancelSpotInstanceRequestsResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <spotInstanceRequestSet>
+ <item>
+ <spotInstanceRequestId>sir-1a2b3c4d</spotInstanceRequestId>
+ <state>cancelled</state>
+ </item>
+ </spotInstanceRequestSet>
+</CancelSpotInstanceRequestsResponse>
+`
+
+// http://goo.gl/3BKHj
+var TerminateInstancesExample = `
+<TerminateInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <instancesSet>
+ <item>
+ <instanceId>i-3ea74257</instanceId>
+ <currentState>
+ <code>32</code>
+ <name>shutting-down</name>
+ </currentState>
+ <previousState>
+ <code>16</code>
+ <name>running</name>
+ </previousState>
+ </item>
+ </instancesSet>
+</TerminateInstancesResponse>
+`
+
+// http://goo.gl/mLbmw
+var DescribeInstancesExample1 = `
+<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>98e3c9a4-848c-4d6d-8e8a-b1bdEXAMPLE</requestId>
+ <reservationSet>
+ <item>
+ <reservationId>r-b27e30d9</reservationId>
+ <ownerId>999988887777</ownerId>
+ <groupSet>
+ <item>
+ <groupId>sg-67ad940e</groupId>
+ <groupName>default</groupName>
+ </item>
+ </groupSet>
+ <instancesSet>
+ <item>
+ <instanceId>i-c5cd56af</instanceId>
+ <imageId>ami-1a2b3c4d</imageId>
+ <instanceState>
+ <code>16</code>
+ <name>running</name>
+ </instanceState>
+ <privateDnsName>domU-12-31-39-10-56-34.compute-1.internal</privateDnsName>
+ <dnsName>ec2-174-129-165-232.compute-1.amazonaws.com</dnsName>
+ <reason/>
+ <keyName>GSG_Keypair</keyName>
+ <amiLaunchIndex>0</amiLaunchIndex>
+ <productCodes/>
+ <instanceType>m1.small</instanceType>
+ <launchTime>2010-08-17T01:15:18.000Z</launchTime>
+ <placement>
+ <availabilityZone>us-east-1b</availabilityZone>
+ <groupName/>
+ </placement>
+ <kernelId>aki-94c527fd</kernelId>
+ <ramdiskId>ari-96c527ff</ramdiskId>
+ <monitoring>
+ <state>disabled</state>
+ </monitoring>
+ <privateIpAddress>10.198.85.190</privateIpAddress>
+ <ipAddress>174.129.165.232</ipAddress>
+ <architecture>i386</architecture>
+ <rootDeviceType>ebs</rootDeviceType>
+ <rootDeviceName>/dev/sda1</rootDeviceName>
+ <blockDeviceMapping>
+ <item>
+ <deviceName>/dev/sda1</deviceName>
+ <ebs>
+ <volumeId>vol-a082c1c9</volumeId>
+ <status>attached</status>
+ <attachTime>2010-08-17T01:15:21.000Z</attachTime>
+ <deleteOnTermination>false</deleteOnTermination>
+ </ebs>
+ </item>
+ </blockDeviceMapping>
+ <instanceLifecycle>spot</instanceLifecycle>
+ <spotInstanceRequestId>sir-7a688402</spotInstanceRequestId>
+ <virtualizationType>paravirtual</virtualizationType>
+ <clientToken/>
+ <tagSet/>
+ <hypervisor>xen</hypervisor>
+ </item>
+ </instancesSet>
+ <requesterId>854251627541</requesterId>
+ </item>
+ <item>
+ <reservationId>r-b67e30dd</reservationId>
+ <ownerId>999988887777</ownerId>
+ <groupSet>
+ <item>
+ <groupId>sg-67ad940e</groupId>
+ <groupName>default</groupName>
+ </item>
+ </groupSet>
+ <instancesSet>
+ <item>
+ <instanceId>i-d9cd56b3</instanceId>
+ <imageId>ami-1a2b3c4d</imageId>
+ <instanceState>
+ <code>16</code>
+ <name>running</name>
+ </instanceState>
+ <privateDnsName>domU-12-31-39-10-54-E5.compute-1.internal</privateDnsName>
+ <dnsName>ec2-184-73-58-78.compute-1.amazonaws.com</dnsName>
+ <reason/>
+ <keyName>GSG_Keypair</keyName>
+ <amiLaunchIndex>0</amiLaunchIndex>
+ <productCodes/>
+ <instanceType>m1.large</instanceType>
+ <launchTime>2010-08-17T01:15:19.000Z</launchTime>
+ <placement>
+ <availabilityZone>us-east-1b</availabilityZone>
+ <groupName/>
+ </placement>
+ <kernelId>aki-94c527fd</kernelId>
+ <ramdiskId>ari-96c527ff</ramdiskId>
+ <monitoring>
+ <state>disabled</state>
+ </monitoring>
+ <privateIpAddress>10.198.87.19</privateIpAddress>
+ <ipAddress>184.73.58.78</ipAddress>
+ <architecture>i386</architecture>
+ <rootDeviceType>ebs</rootDeviceType>
+ <rootDeviceName>/dev/sda1</rootDeviceName>
+ <blockDeviceMapping>
+ <item>
+ <deviceName>/dev/sda1</deviceName>
+ <ebs>
+ <volumeId>vol-a282c1cb</volumeId>
+ <status>attached</status>
+ <attachTime>2010-08-17T01:15:23.000Z</attachTime>
+ <deleteOnTermination>false</deleteOnTermination>
+ </ebs>
+ </item>
+ </blockDeviceMapping>
+ <instanceLifecycle>spot</instanceLifecycle>
+ <spotInstanceRequestId>sir-55a3aa02</spotInstanceRequestId>
+ <virtualizationType>paravirtual</virtualizationType>
+ <clientToken/>
+ <tagSet/>
+ <hypervisor>xen</hypervisor>
+ </item>
+ </instancesSet>
+ <requesterId>854251627541</requesterId>
+ </item>
+ </reservationSet>
+</DescribeInstancesResponse>
+`
+
+// http://goo.gl/mLbmw
+var DescribeInstancesExample2 = `
+<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <reservationSet>
+ <item>
+ <reservationId>r-bc7e30d7</reservationId>
+ <ownerId>999988887777</ownerId>
+ <groupSet>
+ <item>
+ <groupId>sg-67ad940e</groupId>
+ <groupName>default</groupName>
+ </item>
+ </groupSet>
+ <instancesSet>
+ <item>
+ <instanceId>i-c7cd56ad</instanceId>
+ <imageId>ami-b232d0db</imageId>
+ <instanceState>
+ <code>16</code>
+ <name>running</name>
+ </instanceState>
+ <privateDnsName>domU-12-31-39-01-76-06.compute-1.internal</privateDnsName>
+ <dnsName>ec2-72-44-52-124.compute-1.amazonaws.com</dnsName>
+ <keyName>GSG_Keypair</keyName>
+ <amiLaunchIndex>0</amiLaunchIndex>
+ <productCodes/>
+ <instanceType>m1.small</instanceType>
+ <launchTime>2010-08-17T01:15:16.000Z</launchTime>
+ <placement>
+ <availabilityZone>us-east-1b</availabilityZone>
+ </placement>
+ <kernelId>aki-94c527fd</kernelId>
+ <ramdiskId>ari-96c527ff</ramdiskId>
+ <monitoring>
+ <state>disabled</state>
+ </monitoring>
+ <privateIpAddress>10.255.121.240</privateIpAddress>
+ <ipAddress>72.44.52.124</ipAddress>
+ <architecture>i386</architecture>
+ <rootDeviceType>ebs</rootDeviceType>
+ <rootDeviceName>/dev/sda1</rootDeviceName>
+ <blockDeviceMapping>
+ <item>
+ <deviceName>/dev/sda1</deviceName>
+ <ebs>
+ <volumeId>vol-a482c1cd</volumeId>
+ <status>attached</status>
+ <attachTime>2010-08-17T01:15:26.000Z</attachTime>
+ <deleteOnTermination>true</deleteOnTermination>
+ </ebs>
+ </item>
+ </blockDeviceMapping>
+ <virtualizationType>paravirtual</virtualizationType>
+ <clientToken/>
+ <tagSet>
+ <item>
+ <key>webserver</key>
+ <value></value>
+ </item>
+ <item>
+ <key>stack</key>
+ <value>Production</value>
+ </item>
+ </tagSet>
+ <hypervisor>xen</hypervisor>
+ </item>
+ </instancesSet>
+ </item>
+ </reservationSet>
+</DescribeInstancesResponse>
+`
+
+// http://goo.gl/2FBTdS
+var DescribeInstanceStatusExample = `
+<DescribeInstanceStatusResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <instanceStatusSet>
+ <item>
+ <instanceId>i-c7cd56ad</instanceId>
+ <availabilityZone>us-east-1b</availabilityZone>
+ <eventsSet>
+ <item>
+ <code>instance-reboot</code>
+ <description>example description</description>
+ <notBefore>2010-08-17T01:15:18.000Z</notBefore>
+ <notAfter>2010-08-17T01:15:18.000Z</notAfter>
+ </item>
+ </eventsSet>
+ <instanceState>
+ <code>16</code>
+ <name>running</name>
+ </instanceState>
+ <systemStatus>
+ <status>ok</status>
+ <details>
+ <name>reachability</name>
+ <status>passed</status>
+ <impairedSince>2010-08-17T01:15:18.000Z</impairedSince>
+ </details>
+ </systemStatus>
+ <instanceStatus>
+ <status>ok</status>
+ <details>
+ <name>reachability</name>
+ <status>passed</status>
+ <impairedSince>2010-08-17T01:15:18.000Z</impairedSince>
+ </details>
+ </instanceStatus>
+ </item>
+ </instanceStatusSet>
+ <nextToken>exampleToken</nextToken>
+</DescribeInstanceStatusResponse>
+`
+
+// http://goo.gl/icuXh5
+var ModifyInstanceExample = `
+<ModifyImageAttributeResponse xmlns="http://ec2.amazonaws.com/doc/2013-06-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</ModifyImageAttributeResponse>
+`
+
+// http://goo.gl/9rprDN
+var AllocateAddressExample = `
+<AllocateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <publicIp>198.51.100.1</publicIp>
+ <domain>vpc</domain>
+ <allocationId>eipalloc-5723d13e</allocationId>
+</AllocateAddressResponse>
+`
+
+// http://goo.gl/3Q0oCc
+var ReleaseAddressExample = `
+<ReleaseAddressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</ReleaseAddressResponse>
+`
+
+// http://goo.gl/uOSQE
+var AssociateAddressExample = `
+<AssociateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+ <associationId>eipassoc-fc5ca095</associationId>
+</AssociateAddressResponse>
+`
+
+// http://goo.gl/LrOa0
+var DisassociateAddressExample = `
+<DisassociateAddressResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</DisassociateAddressResponse>
+`
+
+//http://goo.gl/zW7J4p
+var DescribeAddressesExample = `
+<DescribeAddressesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <addressesSet>
+ <item>
+ <publicIp>192.0.2.1</publicIp>
+ <domain>standard</domain>
+ <instanceId>i-f15ebb98</instanceId>
+ </item>
+ <item>
+ <publicIp>198.51.100.2</publicIp>
+ <domain>standard</domain>
+ <instanceId/>
+ </item>
+ <item>
+ <publicIp>203.0.113.41</publicIp>
+ <allocationId>eipalloc-08229861</allocationId>
+ <domain>vpc</domain>
+ <instanceId>i-64600030</instanceId>
+ <associationId>eipassoc-f0229899</associationId>
+ <networkInterfaceId>eni-ef229886</networkInterfaceId>
+ <networkInterfaceOwnerId>053230519467</networkInterfaceOwnerId>
+ <privateIpAddress>10.0.0.228</privateIpAddress>
+ </item>
+ </addressesSet>
+</DescribeAddressesResponse>
+`
+
+var DescribeAddressesAllocationIdExample = `
+<DescribeAddressesResponse xmlns="http://ec2.amazonaws.com/doc/2013-10-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <addressesSet>
+ <item>
+ <publicIp>203.0.113.41</publicIp>
+ <allocationId>eipalloc-08229861</allocationId>
+ <domain>vpc</domain>
+ <instanceId>i-64600030</instanceId>
+ <associationId>eipassoc-f0229899</associationId>
+ <networkInterfaceId>eni-ef229886</networkInterfaceId>
+ <networkInterfaceOwnerId>053230519467</networkInterfaceOwnerId>
+ <privateIpAddress>10.0.0.228</privateIpAddress>
+ </item>
+ <item>
+ <publicIp>146.54.2.230</publicIp>
+ <allocationId>eipalloc-08364752</allocationId>
+ <domain>vpc</domain>
+ <instanceId>i-64693456</instanceId>
+ <associationId>eipassoc-f0348693</associationId>
+ <networkInterfaceId>eni-da764039</networkInterfaceId>
+ <networkInterfaceOwnerId>053230519467</networkInterfaceOwnerId>
+ <privateIpAddress>10.0.0.102</privateIpAddress>
+ </item>
+ </addressesSet>
+</DescribeAddressesResponse>
+`
+
+// http://goo.gl/cxU41
+var CreateImageExample = `
+<CreateImageResponse xmlns="http://ec2.amazonaws.com/doc/2013-02-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <imageId>ami-4fa54026</imageId>
+</CreateImageResponse>
+`
+
+// http://goo.gl/V0U25
+var DescribeImagesExample = `
+<DescribeImagesResponse xmlns="http://ec2.amazonaws.com/doc/2012-08-15/">
+ <requestId>4a4a27a2-2e7c-475d-b35b-ca822EXAMPLE</requestId>
+ <imagesSet>
+ <item>
+ <imageId>ami-a2469acf</imageId>
+ <imageLocation>aws-marketplace/example-marketplace-amzn-ami.1</imageLocation>
+ <imageState>available</imageState>
+ <imageOwnerId>123456789999</imageOwnerId>
+ <isPublic>true</isPublic>
+ <productCodes>
+ <item>
+ <productCode>a1b2c3d4e5f6g7h8i9j10k11</productCode>
+ <type>marketplace</type>
+ </item>
+ </productCodes>
+ <architecture>i386</architecture>
+ <imageType>machine</imageType>
+ <kernelId>aki-805ea7e9</kernelId>
+ <imageOwnerAlias>aws-marketplace</imageOwnerAlias>
+ <name>example-marketplace-amzn-ami.1</name>
+ <description>Amazon Linux AMI i386 EBS</description>
+ <rootDeviceType>ebs</rootDeviceType>
+ <rootDeviceName>/dev/sda1</rootDeviceName>
+ <blockDeviceMapping>
+ <item>
+ <deviceName>/dev/sda1</deviceName>
+ <ebs>
+ <snapshotId>snap-787e9403</snapshotId>
+ <volumeSize>8</volumeSize>
+ <deleteOnTermination>true</deleteOnTermination>
+ </ebs>
+ </item>
+ </blockDeviceMapping>
+ <virtualizationType>paravirtual</virtualizationType>
+ <tagSet>
+ <item>
+ <key>Purpose</key>
+ <value>EXAMPLE</value>
+ </item>
+ </tagSet>
+ <hypervisor>xen</hypervisor>
+ </item>
+ </imagesSet>
+</DescribeImagesResponse>
+`
+
+// http://goo.gl/bHO3z
+var ImageAttributeExample = `
+<DescribeImageAttributeResponse xmlns="http://ec2.amazonaws.com/doc/2013-07-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <imageId>ami-61a54008</imageId>
+ <launchPermission>
+ <item>
+ <group>all</group>
+ </item>
+ <item>
+ <userId>495219933132</userId>
+ </item>
+ </launchPermission>
+</DescribeImageAttributeResponse>
+`
+
+// http://goo.gl/ttcda
+var CreateSnapshotExample = `
+<CreateSnapshotResponse xmlns="http://ec2.amazonaws.com/doc/2012-10-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <snapshotId>snap-78a54011</snapshotId>
+ <volumeId>vol-4d826724</volumeId>
+ <status>pending</status>
+ <startTime>2008-05-07T12:51:50.000Z</startTime>
+ <progress>60%</progress>
+ <ownerId>111122223333</ownerId>
+ <volumeSize>10</volumeSize>
+ <description>Daily Backup</description>
+</CreateSnapshotResponse>
+`
+
+// http://goo.gl/vwU1y
+var DeleteSnapshotExample = `
+<DeleteSnapshotResponse xmlns="http://ec2.amazonaws.com/doc/2012-10-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</DeleteSnapshotResponse>
+`
+
+// http://goo.gl/nkovs
+var DescribeSnapshotsExample = `
+<DescribeSnapshotsResponse xmlns="http://ec2.amazonaws.com/doc/2012-10-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <snapshotSet>
+ <item>
+ <snapshotId>snap-1a2b3c4d</snapshotId>
+ <volumeId>vol-8875daef</volumeId>
+ <status>pending</status>
+ <startTime>2010-07-29T04:12:01.000Z</startTime>
+ <progress>30%</progress>
+ <ownerId>111122223333</ownerId>
+ <volumeSize>15</volumeSize>
+ <description>Daily Backup</description>
+ <tagSet>
+ <item>
+ <key>Purpose</key>
+ <value>demo_db_14_backup</value>
+ </item>
+ </tagSet>
+ </item>
+ </snapshotSet>
+</DescribeSnapshotsResponse>
+`
+
+// http://goo.gl/YUjO4G
+var ModifyImageAttributeExample = `
+<ModifyImageAttributeResponse xmlns="http://ec2.amazonaws.com/doc/2013-06-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</ModifyImageAttributeResponse>
+`
+
+// http://goo.gl/hQwPCK
+var CopyImageExample = `
+<CopyImageResponse xmlns="http://ec2.amazonaws.com/doc/2013-06-15/">
+ <requestId>60bc441d-fa2c-494d-b155-5d6a3EXAMPLE</requestId>
+ <imageId>ami-4d3c2b1a</imageId>
+</CopyImageResponse>
+`
+
+var CreateKeyPairExample = `
+<CreateKeyPairResponse xmlns="http://ec2.amazonaws.com/doc/2013-02-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <keyName>foo</keyName>
+ <keyFingerprint>
+ 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
+ </keyFingerprint>
+ <keyMaterial>---- BEGIN RSA PRIVATE KEY ----
+MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w0BAQUFADCBiDELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6
+b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAd
+BgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wHhcNMTEwNDI1MjA0NTIxWhcN
+MTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYD
+VQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25z
+b2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFt
+YXpvbi5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ
+21uUSfwfEvySWtC2XADZ4nB+BLYgVIk60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9T
+rDHudUZg3qX4waLG5M43q7Wgc/MbQITxOUSQv7c7ugFFDzQGBzZswY6786m86gpE
+Ibb3OhjZnzcvQAaRHhdlQWIMm2nrAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4
+nUhVVxYUntneD9+h8Mg9q6q+auNKyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0Fkb
+FFBjvSfpJIlJ00zbhNYS5f6GuoEDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTb
+NYiytVbZPQUQ5Yaxu2jXnimvw3rrszlaEXAMPLE=
+-----END RSA PRIVATE KEY-----
+</keyMaterial>
+</CreateKeyPairResponse>
+`
+
+var DeleteKeyPairExample = `
+<DeleteKeyPairResponse xmlns="http://ec2.amazonaws.com/doc/2013-02-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</DeleteKeyPairResponse>
+`
+
+// http://goo.gl/Eo7Yl
+var CreateSecurityGroupExample = `
+<CreateSecurityGroupResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+ <groupId>sg-67ad940e</groupId>
+</CreateSecurityGroupResponse>
+`
+
+// http://goo.gl/k12Uy
+var DescribeSecurityGroupsExample = `
+<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <securityGroupInfo>
+ <item>
+ <ownerId>999988887777</ownerId>
+ <groupName>WebServers</groupName>
+ <groupId>sg-67ad940e</groupId>
+ <groupDescription>Web Servers</groupDescription>
+ <ipPermissions>
+ <item>
+ <ipProtocol>tcp</ipProtocol>
+ <fromPort>80</fromPort>
+ <toPort>80</toPort>
+ <groups/>
+ <ipRanges>
+ <item>
+ <cidrIp>0.0.0.0/0</cidrIp>
+ </item>
+ </ipRanges>
+ </item>
+ </ipPermissions>
+ <ipPermissionsEgress>
+ <item>
+ <ipProtocol>tcp</ipProtocol>
+ <fromPort>80</fromPort>
+ <toPort>80</toPort>
+ <groups/>
+ <ipRanges>
+ <item>
+ <cidrIp>0.0.0.0/0</cidrIp>
+ </item>
+ </ipRanges>
+ </item>
+ </ipPermissionsEgress>
+ </item>
+ <item>
+ <ownerId>999988887777</ownerId>
+ <groupName>RangedPortsBySource</groupName>
+ <groupId>sg-76abc467</groupId>
+ <groupDescription>Group A</groupDescription>
+ <ipPermissions>
+ <item>
+ <ipProtocol>tcp</ipProtocol>
+ <fromPort>6000</fromPort>
+ <toPort>7000</toPort>
+ <groups/>
+ <ipRanges/>
+ </item>
+ </ipPermissions>
+ </item>
+ </securityGroupInfo>
+</DescribeSecurityGroupsResponse>
+`
+
+// A dump which includes groups within ip permissions.
+var DescribeSecurityGroupsDump = `
+<?xml version="1.0" encoding="UTF-8"?>
+<DescribeSecurityGroupsResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>87b92b57-cc6e-48b2-943f-f6f0e5c9f46c</requestId>
+ <securityGroupInfo>
+ <item>
+ <ownerId>12345</ownerId>
+ <groupName>default</groupName>
+ <groupDescription>default group</groupDescription>
+ <ipPermissions>
+ <item>
+ <ipProtocol>icmp</ipProtocol>
+ <fromPort>-1</fromPort>
+ <toPort>-1</toPort>
+ <groups>
+ <item>
+ <userId>12345</userId>
+ <groupName>default</groupName>
+ <groupId>sg-67ad940e</groupId>
+ </item>
+ </groups>
+ <ipRanges/>
+ </item>
+ <item>
+ <ipProtocol>tcp</ipProtocol>
+ <fromPort>0</fromPort>
+ <toPort>65535</toPort>
+ <groups>
+ <item>
+ <userId>12345</userId>
+ <groupName>other</groupName>
+ <groupId>sg-76abc467</groupId>
+ </item>
+ </groups>
+ <ipRanges/>
+ </item>
+ </ipPermissions>
+ </item>
+ </securityGroupInfo>
+</DescribeSecurityGroupsResponse>
+`
+
+// http://goo.gl/QJJDO
+var DeleteSecurityGroupExample = `
+<DeleteSecurityGroupResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</DeleteSecurityGroupResponse>
+`
+
+// http://goo.gl/u2sDJ
+var AuthorizeSecurityGroupIngressExample = `
+<AuthorizeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</AuthorizeSecurityGroupIngressResponse>
+`
+
+// http://goo.gl/Mz7xr
+var RevokeSecurityGroupIngressExample = `
+<RevokeSecurityGroupIngressResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</RevokeSecurityGroupIngressResponse>
+`
+
+// http://goo.gl/Vmkqc
+var CreateTagsExample = `
+<CreateTagsResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</CreateTagsResponse>
+`
+
+// http://goo.gl/awKeF
+var StartInstancesExample = `
+<StartInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <instancesSet>
+ <item>
+ <instanceId>i-10a64379</instanceId>
+ <currentState>
+ <code>0</code>
+ <name>pending</name>
+ </currentState>
+ <previousState>
+ <code>80</code>
+ <name>stopped</name>
+ </previousState>
+ </item>
+ </instancesSet>
+</StartInstancesResponse>
+`
+
+// http://goo.gl/436dJ
+var StopInstancesExample = `
+<StopInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <instancesSet>
+ <item>
+ <instanceId>i-10a64379</instanceId>
+ <currentState>
+ <code>64</code>
+ <name>stopping</name>
+ </currentState>
+ <previousState>
+ <code>16</code>
+ <name>running</name>
+ </previousState>
+ </item>
+ </instancesSet>
+</StopInstancesResponse>
+`
+
+// http://goo.gl/baoUf
+var RebootInstancesExample = `
+<RebootInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-12-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</RebootInstancesResponse>
+`
+
+var DescribeRouteTablesExample = `
+<DescribeRouteTablesResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>6f570b0b-9c18-4b07-bdec-73740dcf861aEXAMPLE</requestId>
+ <routeTableSet>
+ <item>
+ <routeTableId>rtb-13ad487a</routeTableId>
+ <vpcId>vpc-11ad4878</vpcId>
+ <routeSet>
+ <item>
+ <destinationCidrBlock>10.0.0.0/22</destinationCidrBlock>
+ <gatewayId>local</gatewayId>
+ <state>active</state>
+ <origin>CreateRouteTable</origin>
+ </item>
+ </routeSet>
+ <associationSet>
+ <item>
+ <routeTableAssociationId>rtbassoc-12ad487b</routeTableAssociationId>
+ <routeTableId>rtb-13ad487a</routeTableId>
+ <main>true</main>
+ </item>
+ </associationSet>
+ <tagSet/>
+ </item>
+ <item>
+ <routeTableId>rtb-f9ad4890</routeTableId>
+ <vpcId>vpc-11ad4878</vpcId>
+ <routeSet>
+ <item>
+ <destinationCidrBlock>10.0.0.0/22</destinationCidrBlock>
+ <gatewayId>local</gatewayId>
+ <state>active</state>
+ <origin>CreateRouteTable</origin>
+ </item>
+ <item>
+ <destinationCidrBlock>0.0.0.0/0</destinationCidrBlock>
+ <gatewayId>igw-eaad4883</gatewayId>
+ <state>active</state>
+ </item>
+ </routeSet>
+ <associationSet>
+ <item>
+ <routeTableAssociationId>rtbassoc-faad4893</routeTableAssociationId>
+ <routeTableId>rtb-f9ad4890</routeTableId>
+ <subnetId>subnet-15ad487c</subnetId>
+ </item>
+ </associationSet>
+ <tagSet/>
+ </item>
+ </routeTableSet>
+</DescribeRouteTablesResponse>
+`
+
+var CreateRouteTableExample = `
+<CreateRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>59abcd43-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <routeTable>
+ <routeTableId>rtb-f9ad4890</routeTableId>
+ <vpcId>vpc-11ad4878</vpcId>
+ <routeSet>
+ <item>
+ <destinationCidrBlock>10.0.0.0/22</destinationCidrBlock>
+ <gatewayId>local</gatewayId>
+ <state>active</state>
+ </item>
+ </routeSet>
+ <associationSet/>
+ <tagSet/>
+ </routeTable>
+</CreateRouteTableResponse>
+`
+
+var DeleteRouteTableExample = `
+<DeleteRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>49dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</DeleteRouteTableResponse>
+`
+
+var AssociateRouteTableExample = `
+<AssociateRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <associationId>rtbassoc-f8ad4891</associationId>
+</AssociateRouteTableResponse>
+`
+
+var DisassociateRouteTableExample = `
+<DisassociateRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</DisassociateRouteTableResponse>
+`
+
+var ReplaceRouteTableAssociationExample = `
+<ReplaceRouteTableAssociationResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>59dbff89-35bd-4eac-88ed-be587EXAMPLE</requestId>
+ <newAssociationId>rtbassoc-faad2958</newAssociationId>
+</ReplaceRouteTableAssociationResponse>
+`
+var DescribeReservedInstancesExample = `
+<DescribeReservedInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2014-06-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <reservedInstancesSet>
+ <item>
+ <reservedInstancesId>e5a2ff3b-7d14-494f-90af-0b5d0EXAMPLE</reservedInstancesId>
+ <instanceType>m1.xlarge</instanceType>
+ <availabilityZone>us-east-1b</availabilityZone>
+ <duration>31536000</duration>
+ <fixedPrice>61.0</fixedPrice>
+ <usagePrice>0.034</usagePrice>
+ <instanceCount>3</instanceCount>
+ <productDescription>Linux/UNIX</productDescription>
+ <state>active</state>
+ <instanceTenancy>default</instanceTenancy>
+ <currencyCode>USD</currencyCode>
+ <offeringType>Light Utilization</offeringType>
+ <recurringCharges/>
+ </item>
+ </reservedInstancesSet>
+</DescribeReservedInstancesResponse>
+`
+
+var DescribeVpcsExample = `
+<DescribeVpcsResponse xmlns="http://ec2.amazonaws.com/doc/2015-04-15/">
+ <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
+ <vpcSet>
+ <item>
+ <vpcId>vpc-1a2b3c4d</vpcId>
+ <state>available</state>
+ <cidrBlock>10.0.0.0/23</cidrBlock>
+ <dhcpOptionsId>dopt-7a8b9c2d</dhcpOptionsId>
+ <instanceTenancy>default</instanceTenancy>
+ <isDefault>false</isDefault>
+ <tagSet/>
+ </item>
+ </vpcSet>
+</DescribeVpcsResponse>
+`
+
+var CreateVpcExample = `
+<CreateVpcResponse xmlns="http://ec2.amazonaws.com/doc/2015-04-15/">
+ <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
+ <vpc>
+ <vpcId>vpc-1a2b3c4d</vpcId>
+ <state>pending</state>
+ <cidrBlock>10.0.0.0/16</cidrBlock>
+ <dhcpOptionsId>dopt-1a2b3c4d2</dhcpOptionsId>
+ <instanceTenancy>default</instanceTenancy>
+ <tagSet/>
+ </vpc>
+</CreateVpcResponse>
+`
+
+var DeleteVpcExample = `
+<DeleteVpcResponse xmlns="http://ec2.amazonaws.com/doc/2015-04-15/">
+ <requestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</requestId>
+ <return>true</return>
+</DeleteVpcResponse>
+`
+
+var CreateRouteExample = `
+<CreateRouteResponse xmlns="http://ec2.amazonaws.com/doc/2014-02-01/">
+ <requestId>b4998629-3000-437f-b382-cc96fEXAMPLE</requestId>
+ <return>true</return>
+</CreateRouteResponse>
+`
+
+var DeleteRouteExample = `
+<DeleteRouteResponse xmlns="http://ec2.amazonaws.com/doc/2015-04-15/">
+ <requestId>59dbff89-35bd-4eac-99ed-be587EXAMPLE</requestId>
+ <return>true</return>
+</DeleteRouteResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/ec2/sign.go b/vendor/github.com/goamz/goamz/ec2/sign.go
new file mode 100644
index 000000000..1c30f13bb
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/sign.go
@@ -0,0 +1,45 @@
+package ec2
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "github.com/goamz/goamz/aws"
+ "sort"
+ "strings"
+)
+
+// ----------------------------------------------------------------------------
+// EC2 signing (http://goo.gl/fQmAN)
+
+var b64 = base64.StdEncoding
+
+func sign(auth aws.Auth, method, path string, params map[string]string, host string) {
+ params["AWSAccessKeyId"] = auth.AccessKey
+ params["SignatureVersion"] = "2"
+ params["SignatureMethod"] = "HmacSHA256"
+ if auth.Token() != "" {
+ params["SecurityToken"] = auth.Token()
+ }
+
+ // AWS specifies that the parameters in a signed request must
+ // be provided in the natural order of the keys. This is distinct
+ // from the natural order of the encoded value of key=value.
+ // Percent and equals affect the sorting order.
+ var keys, sarray []string
+ for k, _ := range params {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(params[k]))
+ }
+ joined := strings.Join(sarray, "&")
+ payload := method + "\n" + host + "\n" + path + "\n" + joined
+ hash := hmac.New(sha256.New, []byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum(nil))
+
+ params["Signature"] = string(signature)
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/sign_test.go b/vendor/github.com/goamz/goamz/ec2/sign_test.go
new file mode 100644
index 000000000..bc6996cce
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/sign_test.go
@@ -0,0 +1,68 @@
+package ec2_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/ec2"
+ . "gopkg.in/check.v1"
+)
+
+// EC2 ReST authentication docs: http://goo.gl/fQmAN
+
+var testAuth = aws.Auth{AccessKey: "user", SecretKey: "secret"}
+
+func (s *S) TestBasicSignature(c *C) {
+ params := map[string]string{}
+ ec2.Sign(testAuth, "GET", "/path", params, "localhost")
+ c.Assert(params["SignatureVersion"], Equals, "2")
+ c.Assert(params["SignatureMethod"], Equals, "HmacSHA256")
+ expected := "6lSe5QyXum0jMVc7cOUz32/52ZnL7N5RyKRk/09yiK4="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestParamSignature(c *C) {
+ params := map[string]string{
+ "param1": "value1",
+ "param2": "value2",
+ "param3": "value3",
+ }
+ ec2.Sign(testAuth, "GET", "/path", params, "localhost")
+ expected := "XWOR4+0lmK8bD8CGDGZ4kfuSPbb2JibLJiCl/OPu1oU="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestManyParams(c *C) {
+ params := map[string]string{
+ "param1": "value10",
+ "param2": "value2",
+ "param3": "value3",
+ "param4": "value4",
+ "param5": "value5",
+ "param6": "value6",
+ "param7": "value7",
+ "param8": "value8",
+ "param9": "value9",
+ "param10": "value1",
+ }
+ ec2.Sign(testAuth, "GET", "/path", params, "localhost")
+ expected := "di0sjxIvezUgQ1SIL6i+C/H8lL+U0CQ9frLIak8jkVg="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestEscaping(c *C) {
+ params := map[string]string{"Nonce": "+ +"}
+ ec2.Sign(testAuth, "GET", "/path", params, "localhost")
+ c.Assert(params["Nonce"], Equals, "+ +")
+ expected := "bqffDELReIqwjg/W0DnsnVUmfLK4wXVLO4/LuG+1VFA="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestSignatureExample1(c *C) {
+ params := map[string]string{
+ "Timestamp": "2009-02-01T12:53:20+00:00",
+ "Version": "2007-11-07",
+ "Action": "ListDomains",
+ }
+ ec2.Sign(aws.Auth{AccessKey: "access", SecretKey: "secret"}, "GET", "/", params, "sdb.amazonaws.com")
+ expected := "okj96/5ucWBSc1uR2zXVfm6mDHtgfNv657rRtt/aunQ="
+ c.Assert(params["Signature"], Equals, expected)
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/vpc.go b/vendor/github.com/goamz/goamz/ec2/vpc.go
new file mode 100644
index 000000000..3a2ff7c6e
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/vpc.go
@@ -0,0 +1,399 @@
+package ec2
+
+// RouteTable describes a route table which contains a set of rules, called routes
+// that are used to determine where network traffic is directed.
+//
+// See http://goo.gl/bI9hkg for more details.
+type RouteTable struct {
+ Id string `xml:"routeTableId"`
+ VpcId string `xml:"vpcId"`
+ Routes []Route `xml:"routeSet>item"`
+ Associations []RouteTableAssociation `xml:"associationSet>item"`
+ PropagatingVgws []PropagatingVgw `xml:"propagatingVgwSet>item"`
+ Tags []Tag `xml:"tagSet>item"`
+}
+
+// Route describes a route in a route table.
+//
+// See http://goo.gl/hE5Kxe for more details.
+type Route struct {
+ DestinationCidrBlock string `xml:"destinationCidrBlock"` // The CIDR block used for the destination match.
+ GatewayId string `xml:"gatewayId"` // The ID of a gateway attached to your VPC.
+ InstanceId string `xml:"instanceId"` // The ID of a NAT instance in your VPC.
+ InstanceOwnerId string `xml:"instanceOwnerId"` // The AWS account ID of the owner of the instance.
+ NetworkInterfaceId string `xml:"networkInterfaceId"` // The ID of the network interface.
+ State string `xml:"state"` // The state of the route. Valid values: active | blackhole
+ Origin string `xml:"origin"` // Describes how the route was created. Valid values: Valid values: CreateRouteTable | CreateRoute | EnableVgwRoutePropagation
+ VpcPeeringConnectionId string `xml:"vpcPeeringConnectionId"` // The ID of the VPC peering connection.
+}
+
+// RouteTableAssociation describes an association between a route table and a subnet.
+//
+// See http://goo.gl/BZB8o8 for more details.
+type RouteTableAssociation struct {
+ Id string `xml:"routeTableAssociationId"` // The ID of the association between a route table and a subnet.
+ RouteTableId string `xml:"routeTableId"` // The ID of the route table.
+ SubnetId string `xml:"subnetId"` // The ID of the subnet.
+ Main bool `xml:"main"` // Indicates whether this is the main route table.
+}
+
+// PropagatingVgw describes a virtual private gateway propagating route.
+//
+// See http://goo.gl/myGQtG for more details.
+type PropagatingVgw struct {
+ GatewayId string `xml:"gatewayID"`
+}
+
+// CreateRouteTableResp represents a response from a CreateRouteTable request
+//
+// See http://goo.gl/LD0TqP for more details.
+type CreateRouteTableResp struct {
+ RequestId string `xml:"requestId"`
+ RouteTable RouteTable `xml:"routeTable"`
+}
+
+// CreateRouteTable creates a route table for the specified VPC.
+// After you create a route table, you can add routes and associate the table with a subnet.
+//
+// See http://goo.gl/V9h6gE for more details..
+func (ec2 *EC2) CreateRouteTable(vpcId string) (resp *CreateRouteTableResp, err error) {
+ params := makeParams("CreateRouteTable")
+ params["VpcId"] = vpcId
+ resp = &CreateRouteTableResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// DescribeRouteTablesResp represents a response from a DescribeRouteTables call
+//
+// See http://goo.gl/T3tVsg for more details.
+type DescribeRouteTablesResp struct {
+ RequestId string `xml:"requestId"`
+ RouteTables []RouteTable `xml:"routeTableSet>item"`
+}
+
+// DescribeRouteTables describes one or more of your route tables
+//
+// See http://goo.gl/S0RVos for more details.
+func (ec2 *EC2) DescribeRouteTables(routeTableIds []string, filter *Filter) (resp *DescribeRouteTablesResp, err error) {
+ params := makeParams("DescribeRouteTables")
+ addParamsList(params, "RouteTableId", routeTableIds)
+ filter.addParams(params)
+ resp = &DescribeRouteTablesResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// AssociateRouteTableResp represents a response from an AssociateRouteTable call
+//
+// See http://goo.gl/T4KlYk for more details.
+type AssociateRouteTableResp struct {
+ RequestId string `xml:"requestId"`
+ AssociationId string `xml:"associationId"`
+}
+
+// AssociateRouteTable associates a subnet with a route table.
+//
+// The subnet and route table must be in the same VPC. This association causes
+// traffic originating from the subnet to be routed according to the routes
+// in the route table. The action returns an association ID, which you need in
+// order to disassociate the route table from the subnet later.
+// A route table can be associated with multiple subnets.
+//
+// See http://goo.gl/bfnONU for more details.
+func (ec2 *EC2) AssociateRouteTable(routeTableId, subnetId string) (resp *AssociateRouteTableResp, err error) {
+ params := makeParams("AssociateRouteTable")
+ params["RouteTableId"] = routeTableId
+ params["SubnetId"] = subnetId
+ resp = &AssociateRouteTableResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// DisassociateRouteTableResp represents the response from a DisassociateRouteTable request
+//
+// See http://goo.gl/1v4reT for more details.
+type DisassociateRouteTableResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"` // True if the request succeeds
+}
+
+// DisassociateRouteTable disassociates a subnet from a route table.
+//
+// See http://goo.gl/A4NJum for more details.
+func (ec2 *EC2) DisassociateRouteTable(associationId string) (resp *DisassociateRouteTableResp, err error) {
+ params := makeParams("DisassociateRouteTable")
+ params["AssociationId"] = associationId
+ resp = &DisassociateRouteTableResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ReplaceRouteTableAssociationResp represents a response from a ReplaceRouteTableAssociation call
+//
+// See http://goo.gl/VhILGe for more details.
+type ReplaceRouteTableAssociationResp struct {
+ RequestId string `xml:"requestId"`
+ NewAssociationId string `xml:"newAssociationId"`
+}
+
+// ReplaceRouteTableAssociation changes the route table associated with a given subnet in a VPC.
+//
+// See http://goo.gl/kiit8j for more details.
+func (ec2 *EC2) ReplaceRouteTableAssociation(associationId, routeTableId string) (resp *ReplaceRouteTableAssociationResp, err error) {
+ params := makeParams("ReplaceRouteTableAssociation")
+ params["AssociationId"] = associationId
+ params["RouteTableId"] = routeTableId
+ resp = &ReplaceRouteTableAssociationResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// DeleteRouteTableResp represents a response from a DeleteRouteTable request
+//
+// See http://goo.gl/b8usig for more details.
+type DeleteRouteTableResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"` // True if the request succeeds
+}
+
+// DeleteRouteTable deletes the specified route table.
+// You must disassociate the route table from any subnets before you can delete it.
+// You can't delete the main route table.
+//
+// See http://goo.gl/crHxT2 for more details.
+func (ec2 *EC2) DeleteRouteTable(routeTableId string) (resp *DeleteRouteTableResp, err error) {
+ params := makeParams("DeleteRouteTable")
+ params["RouteTableId"] = routeTableId
+ resp = &DeleteRouteTableResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// VPC describes a VPC.
+//
+// See http://goo.gl/WjX0Es for more details.
+type VPC struct {
+ CidrBlock string `xml:"cidrBlock"`
+ DHCPOptionsID string `xml:"dhcpOptionsId"`
+ State string `xml:"state"`
+ VpcId string `xml:"vpcId"`
+ InstanceTenancy string `xml:"instanceTenancy"`
+ IsDefault bool `xml:"isDefault"`
+ Tags []Tag `xml:"tagSet>item"`
+}
+
+// CreateVpcResp represents a response from a CreateVpcResp request
+//
+// See http://goo.gl/QoK11F for more details.
+type CreateVpcResp struct {
+ RequestId string `xml:"requestId"`
+ VPC VPC `xml:"vpc"` // Information about the VPC.
+}
+
+// CreateVpc creates a VPC with the specified CIDR block.
+//
+// The smallest VPC you can create uses a /28 netmask (16 IP addresses),
+// and the largest uses a /16 netmask (65,536 IP addresses).
+//
+// By default, each instance you launch in the VPC has the default DHCP options,
+// which includes only a default DNS server that Amazon provides (AmazonProvidedDNS).
+//
+// See http://goo.gl/QoK11F for more details.
+func (ec2 *EC2) CreateVpc(cidrBlock, instanceTenancy string) (resp *CreateVpcResp, err error) {
+ params := makeParams("CreateVpc")
+ params["CidrBlock"] = cidrBlock
+
+ if instanceTenancy != "" {
+ params["InstanceTenancy"] = instanceTenancy
+ }
+
+ resp = &CreateVpcResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// DeleteVpcResp represents a response from a DeleteVpc request
+//
+// See http://goo.gl/qawyrz for more details.
+type DeleteVpcResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"` // True if the request succeeds
+}
+
+// DeleteVpc deletes the specified VPC.
+//
+// You must detach or delete all gateways and resources that are associated with
+// the VPC before you can delete it. For example, you must terminate all
+// instances running in the VPC, delete all security groups associated with
+// the VPC (except the default one), delete all route tables associated with
+// the VPC (except the default one), and so on.
+//
+// See http://goo.gl/qawyrz for more details.
+func (ec2 *EC2) DeleteVpc(vpcId string) (resp *DeleteVpcResp, err error) {
+ params := makeParams("DeleteVpc")
+ params["VpcId"] = vpcId
+
+ resp = &DeleteVpcResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// DescribeVpcsResp represents a response from a DescribeVpcs request
+//
+// See http://goo.gl/DWQWvZ for more details.
+type DescribeVpcsResp struct {
+ RequestId string `xml:"requestId"`
+ VPCs []VPC `xml:"vpcSet>item"` // Information about one or more VPCs.
+}
+
+// DescribeVpcs describes one or more of your VPCs.
+//
+// See http://goo.gl/DWQWvZ for more details.
+func (ec2 *EC2) DescribeVpcs(vpcIds []string, filter *Filter) (resp *DescribeVpcsResp, err error) {
+ params := makeParams("DescribeVpcs")
+ addParamsList(params, "VpcId", vpcIds)
+ filter.addParams(params)
+ resp = &DescribeVpcsResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
+
+// DeleteRouteResp represents a response from a DeleteRoute request
+//
+// See http://goo.gl/Uqyt3w for more details.
+type DeleteRouteResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"` // True if the request succeeds
+}
+
+// DeleteRoute deletes the specified route from the specified route table.
+//
+// See http://goo.gl/Uqyt3w for more details.
+func (ec2 *EC2) DeleteRoute(routeTableId, destinationCidrBlock string) (resp *DeleteRouteResp, err error) {
+ params := makeParams("DeleteRoute")
+ params["RouteTableId"] = routeTableId
+ params["DestinationCidrBlock"] = destinationCidrBlock
+ resp = &DeleteRouteResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// CreateRouteResp represents a response from a CreateRoute request
+//
+// See http://goo.gl/c6Bg7e for more details.
+type CreateRouteResp struct {
+ RequestId string `xml:"requestId"`
+ Return bool `xml:"return"` // True if the request succeeds
+}
+
+// CreateRoute structure contains the options for a CreateRoute API call.
+type CreateRoute struct {
+ DestinationCidrBlock string
+ GatewayId string
+ InstanceId string
+ NetworkInterfaceId string
+ VpcPeeringConnectionId string
+}
+
+// CreateRoute creates a route in a route table within a VPC.
+// You must specify one of the following targets: Internet gateway or virtual
+// private gateway, NAT instance, VPC peering connection, or network interface.
+//
+// See http://goo.gl/c6Bg7e for more details.
+func (ec2 *EC2) CreateRoute(routeTableId string, options *CreateRoute) (resp *CreateRouteResp, err error) {
+ params := makeParams("CreateRoute")
+ params["RouteTableId"] = routeTableId
+ if options.DestinationCidrBlock != "" {
+ params["DestinationCidrBlock"] = options.DestinationCidrBlock
+ }
+ if options.GatewayId != "" {
+ params["GatewayId"] = options.GatewayId
+ }
+ if options.InstanceId != "" {
+ params["InstanceId"] = options.InstanceId
+ }
+ if options.NetworkInterfaceId != "" {
+ params["NetworkInterfaceId"] = options.NetworkInterfaceId
+ }
+ if options.VpcPeeringConnectionId != "" {
+ params["VpcPeeringConnectionId"] = options.VpcPeeringConnectionId
+ }
+ resp = &CreateRouteResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Subnet describes a subnet
+//
+// See http://goo.gl/bifW4R
+type Subnet struct {
+ AvailabilityZone string `xml:"availabilityZone"`
+ AvailableIpAddressCount int `xml:"availableIpAddressCount"`
+ CidrBlock string `xml:"cidrBlock"`
+ DefaultForAZ bool `xml:"defaultForAz"`
+ MapPublicIpOnLaunch bool `xml:"mapPublicIpOnLaunch"`
+ State string `xml:"state"`
+ SubnetId string `xml:"subnetId"`
+ Tags []Tag `xml:"tagSet>item"`
+ VpcId string `xml:"vpcId"`
+}
+
+// DescribeSubnetsResp represents a response from a DescribeSubnets request
+//
+// See https://goo.gl/1s0UQd for more details.
+type DescribeSubnetsResp struct {
+ RequestId string `xml:"requestId"`
+ Subnets []Subnet `xml:"subnetSet>item"`
+}
+
+// DescribeSubnets describes one or more Subnets.
+//
+// See https://goo.gl/1s0UQd for more details.
+func (ec2 *EC2) DescribeSubnets(subnetIds []string, filter *Filter) (resp *DescribeSubnetsResp, err error) {
+ params := makeParams("DescribeSubnets")
+ addParamsList(params, "SubnetId", subnetIds)
+ filter.addParams(params)
+ resp = &DescribeSubnetsResp{}
+ err = ec2.query(params, resp)
+ if err != nil {
+ return nil, err
+ }
+
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/ec2/vpc_test.go b/vendor/github.com/goamz/goamz/ec2/vpc_test.go
new file mode 100644
index 000000000..a6e67eeed
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ec2/vpc_test.go
@@ -0,0 +1,224 @@
+package ec2_test
+
+import (
+ "github.com/goamz/goamz/ec2"
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) TestCreateRouteTable(c *C) {
+ testServer.Response(200, nil, CreateRouteTableExample)
+
+ resp, err := s.ec2.CreateRouteTable("vpc-11ad4878")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CreateRouteTable"})
+ c.Assert(req.Form["VpcId"], DeepEquals, []string{"vpc-11ad4878"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59abcd43-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.RouteTable.Id, Equals, "rtb-f9ad4890")
+ c.Assert(resp.RouteTable.VpcId, Equals, "vpc-11ad4878")
+ c.Assert(resp.RouteTable.Routes, HasLen, 1)
+ c.Assert(resp.RouteTable.Routes[0], DeepEquals, ec2.Route{
+ DestinationCidrBlock: "10.0.0.0/22",
+ GatewayId: "local",
+ State: "active",
+ })
+ c.Assert(resp.RouteTable.Associations, HasLen, 0)
+ c.Assert(resp.RouteTable.Tags, HasLen, 0)
+}
+
+func (s *S) TestDescribeRouteTables(c *C) {
+ testServer.Response(200, nil, DescribeRouteTablesExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.DescribeRouteTables([]string{"rt1", "rt2"}, nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeRouteTables"})
+ c.Assert(req.Form["RouteTableId.1"], DeepEquals, []string{"rt1"})
+ c.Assert(req.Form["RouteTableId.2"], DeepEquals, []string{"rt2"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "6f570b0b-9c18-4b07-bdec-73740dcf861aEXAMPLE")
+ c.Assert(resp.RouteTables, HasLen, 2)
+
+ rt1 := resp.RouteTables[0]
+ c.Assert(rt1.Id, Equals, "rtb-13ad487a")
+ c.Assert(rt1.VpcId, Equals, "vpc-11ad4878")
+ c.Assert(rt1.Routes, DeepEquals, []ec2.Route{
+ {DestinationCidrBlock: "10.0.0.0/22", GatewayId: "local", State: "active", Origin: "CreateRouteTable"},
+ })
+ c.Assert(rt1.Associations, DeepEquals, []ec2.RouteTableAssociation{
+ {Id: "rtbassoc-12ad487b", RouteTableId: "rtb-13ad487a", Main: true},
+ })
+
+ rt2 := resp.RouteTables[1]
+ c.Assert(rt2.Id, Equals, "rtb-f9ad4890")
+ c.Assert(rt2.VpcId, Equals, "vpc-11ad4878")
+ c.Assert(rt2.Routes, DeepEquals, []ec2.Route{
+ {DestinationCidrBlock: "10.0.0.0/22", GatewayId: "local", State: "active", Origin: "CreateRouteTable"},
+ {DestinationCidrBlock: "0.0.0.0/0", GatewayId: "igw-eaad4883", State: "active"},
+ })
+ c.Assert(rt2.Associations, DeepEquals, []ec2.RouteTableAssociation{
+ {Id: "rtbassoc-faad4893", RouteTableId: "rtb-f9ad4890", SubnetId: "subnet-15ad487c"},
+ })
+}
+
+func (s *S) TestAssociateRouteTable(c *C) {
+ testServer.Response(200, nil, AssociateRouteTableExample)
+
+ resp, err := s.ec2.AssociateRouteTable("rtb-e4ad488d", "subnet-15ad487c")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"AssociateRouteTable"})
+ c.Assert(req.Form["RouteTableId"], DeepEquals, []string{"rtb-e4ad488d"})
+ c.Assert(req.Form["SubnetId"], DeepEquals, []string{"subnet-15ad487c"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.AssociationId, Equals, "rtbassoc-f8ad4891")
+}
+
+func (s *S) TestDisassociateRouteTable(c *C) {
+ testServer.Response(200, nil, DisassociateRouteTableExample)
+
+ resp, err := s.ec2.DisassociateRouteTable("rtbassoc-f8ad4891")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DisassociateRouteTable"})
+ c.Assert(req.Form["AssociationId"], DeepEquals, []string{"rtbassoc-f8ad4891"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Return, Equals, true)
+}
+
+func (s *S) TestReplaceRouteTableAssociation(c *C) {
+ testServer.Response(200, nil, ReplaceRouteTableAssociationExample)
+
+ resp, err := s.ec2.ReplaceRouteTableAssociation("rtbassoc-f8ad4891", "rtb-f9ad4890")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"ReplaceRouteTableAssociation"})
+ c.Assert(req.Form["RouteTableId"], DeepEquals, []string{"rtb-f9ad4890"})
+ c.Assert(req.Form["AssociationId"], DeepEquals, []string{"rtbassoc-f8ad4891"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-88ed-be587EXAMPLE")
+ c.Assert(resp.NewAssociationId, Equals, "rtbassoc-faad2958")
+}
+
+func (s *S) TestDeleteRouteTable(c *C) {
+ testServer.Response(200, nil, DeleteRouteTableExample)
+
+ resp, err := s.ec2.DeleteRouteTable("rtb-f9ad4890")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DeleteRouteTable"})
+ c.Assert(req.Form["RouteTableId"], DeepEquals, []string{"rtb-f9ad4890"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "49dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Return, Equals, true)
+}
+
+func (s *S) TestDescribeVpcs(c *C) {
+ testServer.Response(200, nil, DescribeVpcsExample)
+
+ filter := ec2.NewFilter()
+ filter.Add("key1", "value1")
+ filter.Add("key2", "value2", "value3")
+
+ resp, err := s.ec2.DescribeVpcs([]string{"id1", "id2"}, filter)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeVpcs"})
+ c.Assert(req.Form["VpcId.1"], DeepEquals, []string{"id1"})
+ c.Assert(req.Form["VpcId.2"], DeepEquals, []string{"id2"})
+ c.Assert(req.Form["VpcId.3"], IsNil)
+ c.Assert(req.Form["Filter.1.Name"], DeepEquals, []string{"key1"})
+ c.Assert(req.Form["Filter.1.Value.1"], DeepEquals, []string{"value1"})
+ c.Assert(req.Form["Filter.1.Value.2"], IsNil)
+ c.Assert(req.Form["Filter.2.Name"], DeepEquals, []string{"key2"})
+ c.Assert(req.Form["Filter.2.Value.1"], DeepEquals, []string{"value2"})
+ c.Assert(req.Form["Filter.2.Value.2"], DeepEquals, []string{"value3"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+ c.Assert(resp.VPCs[0].VpcId, Equals, "vpc-1a2b3c4d")
+ c.Assert(resp.VPCs, HasLen, 1)
+}
+
+func (s *S) TestCreateVpc(c *C) {
+ testServer.Response(200, nil, CreateVpcExample)
+
+ resp, err := s.ec2.CreateVpc("foo", "bar")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["CidrBlock"], DeepEquals, []string{"foo"})
+ c.Assert(req.Form["InstanceTenancy"], DeepEquals, []string{"bar"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+ c.Assert(resp.VPC.VpcId, Equals, "vpc-1a2b3c4d")
+ c.Assert(resp.VPC.State, Equals, "pending")
+ c.Assert(resp.VPC.CidrBlock, Equals, "10.0.0.0/16")
+ c.Assert(resp.VPC.DHCPOptionsID, Equals, "dopt-1a2b3c4d2")
+ c.Assert(resp.VPC.InstanceTenancy, Equals, "default")
+}
+
+func (s *S) TestDeleteVpc(c *C) {
+ testServer.Response(200, nil, DeleteVpcExample)
+
+ resp, err := s.ec2.DeleteVpc("id1")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["VpcId"], DeepEquals, []string{"id1"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestCreateRoute(c *C) {
+ testServer.Response(200, nil, CreateRouteExample)
+
+ options := ec2.CreateRoute{
+ DestinationCidrBlock: "12.34.56.78/90",
+ GatewayId: "foo",
+ InstanceId: "i-bar",
+ NetworkInterfaceId: "foobar",
+ VpcPeeringConnectionId: "barfoo",
+ }
+
+ resp, err := s.ec2.CreateRoute("rtb-deadbeef", &options)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["RouteTableId"], DeepEquals, []string{"rtb-deadbeef"})
+ c.Assert(req.Form["DestinationCidrBlock"], DeepEquals, []string{"12.34.56.78/90"})
+ c.Assert(req.Form["GatewayId"], DeepEquals, []string{"foo"})
+ c.Assert(req.Form["InstanceId"], DeepEquals, []string{"i-bar"})
+ c.Assert(req.Form["NetworkInterfaceId"], DeepEquals, []string{"foobar"})
+ c.Assert(req.Form["VpcPeeringConnectionId"], DeepEquals, []string{"barfoo"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "b4998629-3000-437f-b382-cc96fEXAMPLE")
+ c.Assert(resp.Return, Equals, true)
+}
+
+func (s *S) TestDeleteRoute(c *C) {
+ testServer.Response(200, nil, DeleteRouteExample)
+
+ resp, err := s.ec2.DeleteRoute("rtb-baddcafe", "foobar")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["RouteTableId"], DeepEquals, []string{"rtb-baddcafe"})
+ c.Assert(req.Form["DestinationCidrBlock"], DeepEquals, []string{"foobar"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "59dbff89-35bd-4eac-99ed-be587EXAMPLE")
+ c.Assert(resp.Return, Equals, true)
+}
diff --git a/vendor/github.com/goamz/goamz/ecs/ecs.go b/vendor/github.com/goamz/goamz/ecs/ecs.go
new file mode 100644
index 000000000..89c7243d4
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ecs/ecs.go
@@ -0,0 +1,1075 @@
+//
+// ecs: This package provides types and functions to interact with the AWS EC2 Container Service API
+//
+// Depends on https://github.com/goamz/goamz
+//
+// Author Boyan Dimitrov <boyann@gmail.com>
+//
+
+package ecs
+
+import (
+ "encoding/xml"
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+const debug = false
+
+var timeNow = time.Now
+
+// ECS contains the details of the AWS region to perform operations against.
+type ECS struct {
+ aws.Auth
+ aws.Region
+}
+
+// New creates a new ECS Client.
+func New(auth aws.Auth, region aws.Region) *ECS {
+ return &ECS{auth, region}
+}
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+// Error encapsulates an error returned by the AWS ECS API.
+//
+// See http://goo.gl/VZGuC for more details.
+type Error struct {
+ // HTTP status code (200, 403, ...)
+ StatusCode int
+ // ECS error code ("UnsupportedOperation", ...)
+ Code string
+ // The error type
+ Type string
+ // The human-oriented error message
+ Message string
+ RequestId string `xml:"RequestID"`
+}
+
+func (err *Error) Error() string {
+ if err.Code == "" {
+ return err.Message
+ }
+
+ return fmt.Sprintf("%s (%s)", err.Message, err.Code)
+}
+
+type xmlErrors struct {
+ RequestId string `xml:"RequestId"`
+ Errors []Error `xml:"Error"`
+}
+
+func (e *ECS) query(params map[string]string, resp interface{}) error {
+ params["Version"] = "2014-11-13"
+ data := strings.NewReader(multimap(params).Encode())
+
+ hreq, err := http.NewRequest("POST", e.Region.ECSEndpoint+"/", data)
+ if err != nil {
+ return err
+ }
+
+ hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+ token := e.Auth.Token()
+ if token != "" {
+ hreq.Header.Set("X-Amz-Security-Token", token)
+ }
+
+ signer := aws.NewV4Signer(e.Auth, "ecs", e.Region)
+ signer.Sign(hreq)
+
+ if debug {
+ log.Printf("%v -> {\n", hreq)
+ }
+ r, err := http.DefaultClient.Do(hreq)
+
+ if err != nil {
+ log.Printf("Error calling Amazon %v", err)
+ return err
+ }
+
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("response:\n")
+ log.Printf("%v\n}\n", string(dump))
+ }
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+func buildError(r *http.Response) error {
+ var (
+ err Error
+ errors xmlErrors
+ )
+ xml.NewDecoder(r.Body).Decode(&errors)
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+
+ err.RequestId = errors.RequestId
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+func addParamsList(params map[string]string, label string, ids []string) {
+ for i, id := range ids {
+ params[label+"."+strconv.Itoa(i+1)] = id
+ }
+}
+
+// ----------------------------------------------------------------------------
+// ECS types and related functions.
+
+// SimpleResp is the beic response from most actions.
+type SimpleResp struct {
+ XMLName xml.Name
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// Cluster encapsulates the cluster datatype
+//
+// See
+type Cluster struct {
+ ClusterArn string `xml:"clusterArn"`
+ ClusterName string `xml:"clusterName"`
+ Status string `xml:"status"`
+}
+
+// CreateClusterReq encapsulates the createcluster req params
+type CreateClusterReq struct {
+ ClusterName string
+}
+
+// CreateClusterResp encapsulates the createcluster response
+type CreateClusterResp struct {
+ Cluster Cluster `xml:"CreateClusterResult>cluster"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// CreateCluster creates a new Amazon ECS cluster. By default, your account
+// will receive a default cluster when you launch your first container instance
+func (e *ECS) CreateCluster(req *CreateClusterReq) (resp *CreateClusterResp, err error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("CreateCluster")
+ params["clusterName"] = req.ClusterName
+
+ resp = new(CreateClusterResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Resource describes the resources available for a container instance.
+type Resource struct {
+ DoubleValue float64 `xml:"doubleValue"`
+ IntegerValue int32 `xml:"integerValue"`
+ LongValue int64 `xml:"longValue"`
+ Name string `xml:"name"`
+ StringSetValue []string `xml:"stringSetValue>member"`
+ Type string `xml:"type"`
+}
+
+// ContainerInstance represents n Amazon EC2 instance that is running
+// the Amazon ECS agent and has been registered with a cluster
+type ContainerInstance struct {
+ AgentConnected bool `xml:"agentConnected"`
+ ContainerInstanceArn string `xml:"containerInstanceArn"`
+ Ec2InstanceId string `xml:"ec2InstanceId"`
+ RegisteredResources []Resource `xml:"registeredResources>member"`
+ RemainingResources []Resource `xml:"remainingResources>member"`
+ Status string `xml:"status"`
+}
+
+// DeregisterContainerInstanceReq encapsulates DeregisterContainerInstance request params
+type DeregisterContainerInstanceReq struct {
+ Cluster string
+ // arn:aws:ecs:region:aws_account_id:container-instance/container_instance_UUID.
+ ContainerInstance string
+ Force bool
+}
+
+// DeregisterContainerInstanceResp encapsulates DeregisterContainerInstance response
+type DeregisterContainerInstanceResp struct {
+ ContainerInstance ContainerInstance `xml:"DeregisterContainerInstanceResult>containerInstance"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DeregisterContainerInstance deregisters an Amazon ECS container instance from the specified cluster
+func (e *ECS) DeregisterContainerInstance(req *DeregisterContainerInstanceReq) (
+ resp *DeregisterContainerInstanceResp, err error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("DeregisterContainerInstance")
+ params["containerInstance"] = req.ContainerInstance
+ params["force"] = strconv.FormatBool(req.Force)
+
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+
+ resp = new(DeregisterContainerInstanceResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// PortMapping encapsulates the PortMapping data type
+type PortMapping struct {
+ ContainerPort int32 `xml:containerPort`
+ HostPort int32 `xml:hostPort`
+}
+
+// KeyValuePair encapsulates the KeyValuePair data type
+type KeyValuePair struct {
+ Name string `xml:"name"`
+ Value string `xml:"value"`
+}
+
+// MountPoint encapsulates the MountPoint data type
+type MountPoint struct {
+ ContainerPath string `xml:"containerPath"`
+ ReadOnly bool `xml:"readOnly"`
+ SourceVolume string `xml:"sourceVolume"`
+}
+
+// VolumeFrom encapsulates the VolumeFrom data type
+type VolumeFrom struct {
+ ReadOnly bool `xml:"readOnly"`
+ SourceContainer string `xml:"sourceContainer"`
+}
+
+// HostVolumeProperties encapsulates the HostVolumeProperties data type
+type HostVolumeProperties struct {
+ SourcePath string `xml:"sourcePath"`
+}
+
+// Volume encapsulates the Volume data type
+type Volume struct {
+ Host HostVolumeProperties `xml:"host"`
+ Name string `xml:"name"`
+}
+
+// ContainerDefinition encapsulates the container definition type
+// Container definitions are used in task definitions to describe
+// the different containers that are launched as part of a task
+type ContainerDefinition struct {
+ Command []string `xml:"command>member"`
+ Cpu int32 `xml:"cpu"`
+ EntryPoint []string `xml:"entryPoint>member"`
+ Environment []KeyValuePair `xml:"environment>member"`
+ Essential bool `xml:"essential"`
+ Image string `xml:"image"`
+ Links []string `xml:"links>member"`
+ Memory int32 `xml:"memory"`
+ MountPoints []MountPoint `xml:"mountPoints>member"`
+ Name string `xml:"name"`
+ PortMappings []PortMapping `xml:"portMappings>member"`
+ VolumesFrom []VolumeFrom `xml:"volumesFrom>member"`
+}
+
+// TaskDefinition encapsulates the task definition type
+type TaskDefinition struct {
+ ContainerDefinitions []ContainerDefinition `xml:"containerDefinitions>member"`
+ Family string `xml:"family"`
+ Revision int32 `xml:"revision"`
+ TaskDefinitionArn string `xml:"taskDefinitionArn"`
+ Status string `xml:"status"`
+ Volumes []Volume `xml:"volumes>member"`
+}
+
+// DeregisterTaskDefinitionReq encapsulates DeregisterTaskDefinition req params
+type DeregisterTaskDefinitionReq struct {
+ TaskDefinition string
+}
+
+// DeregisterTaskDefinitionResp encapsuates the DeregisterTaskDefinition response
+type DeregisterTaskDefinitionResp struct {
+ TaskDefinition TaskDefinition `xml:"DeregisterTaskDefinitionResult>taskDefinition"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DeregisterTaskDefinition deregisters the specified task definition
+func (e *ECS) DeregisterTaskDefinition(req *DeregisterTaskDefinitionReq) (
+ *DeregisterTaskDefinitionResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("DeregisterTaskDefinition")
+ params["taskDefinition"] = req.TaskDefinition
+
+ resp := new(DeregisterTaskDefinitionResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Failure encapsulates the failure type
+type Failure struct {
+ Arn string `xml:"arn"`
+ Reason string `xml:"reason"`
+}
+
+// DescribeClustersReq encapsulates DescribeClusters req params
+type DescribeClustersReq struct {
+ Clusters []string
+}
+
+// DescribeClustersResp encapsuates the DescribeClusters response
+type DescribeClustersResp struct {
+ Clusters []Cluster `xml:"DescribeClustersResult>clusters>member"`
+ Failures []Failure `xml:"DescribeClustersResult>failures>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeClusters describes one or more of your clusters
+func (e *ECS) DescribeClusters(req *DescribeClustersReq) (*DescribeClustersResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("DescribeClusters")
+ if len(req.Clusters) > 0 {
+ addParamsList(params, "clusters.member", req.Clusters)
+ }
+
+ resp := new(DescribeClustersResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeContainerInstancesReq ecapsulates DescribeContainerInstances req params
+type DescribeContainerInstancesReq struct {
+ Cluster string
+ ContainerInstances []string
+}
+
+// DescribeContainerInstancesResp ecapsulates DescribeContainerInstances response
+type DescribeContainerInstancesResp struct {
+ ContainerInstances []ContainerInstance `xml:"DescribeContainerInstancesResult>containerInstances>member"`
+ Failures []Failure `xml:"DescribeContainerInstancesResult>failures>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeContainerInstances describes Amazon EC2 Container Service container instances
+// Returns metadata about registered and remaining resources on each container instance requested
+func (e *ECS) DescribeContainerInstances(req *DescribeContainerInstancesReq) (
+ *DescribeContainerInstancesResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("DescribeContainerInstances")
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ if len(req.ContainerInstances) > 0 {
+ addParamsList(params, "containerInstances.member", req.ContainerInstances)
+ }
+
+ resp := new(DescribeContainerInstancesResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DescribeTaskDefinitionReq encapsulates DescribeTaskDefinition req params
+type DescribeTaskDefinitionReq struct {
+ TaskDefinition string
+}
+
+// DescribeTaskDefinitionResp encapsuates the DescribeTaskDefinition response
+type DescribeTaskDefinitionResp struct {
+ TaskDefinition TaskDefinition `xml:"DescribeTaskDefinitionResult>taskDefinition"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeTaskDefinition describes a task definition
+func (e *ECS) DescribeTaskDefinition(req *DescribeTaskDefinitionReq) (
+ *DescribeTaskDefinitionResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("DescribeTaskDefinition")
+ params["taskDefinition"] = req.TaskDefinition
+
+ resp := new(DescribeTaskDefinitionResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// NetworkBinding encapsulates the network binding data type
+type NetworkBinding struct {
+ BindIp string `xml:"bindIp"`
+ ContainerPort int32 `xml:"containerPort"`
+ HostPort int32 `xml:"hostPort"`
+}
+
+// Container encapsulates the container data type
+type Container struct {
+ ContainerArn string `xml:"containerArn"`
+ ExitCode int32 `xml:"exitCode"`
+ LastStatus string `xml:"lastStatus"`
+ Name string `xml:"name"`
+ NetworkBindings []NetworkBinding `xml:"networkBindings>member"`
+ Reason string `xml:"reason"`
+ TaskArn string `xml:"taskArn"`
+}
+
+// ContainerOverride encapsulates the container override data type
+type ContainerOverride struct {
+ Command []string `xml:"command>member"`
+ Environment []KeyValuePair `xml:"environment>member"`
+ Name string `xml:"name"`
+}
+
+// TaskOverride encapsulates the task override data type
+type TaskOverride struct {
+ ContainerOverrides []ContainerOverride `xml:"containerOverrides>member"`
+}
+
+// Task encapsulates the task data type
+type Task struct {
+ ClusterArn string `xml:"clusterArn"`
+ ContainerInstanceArn string `xml:"containerInstanceArn"`
+ Containers []Container `xml:"containers>member"`
+ DesiredStatus string `xml:"desiredStatus"`
+ LastStatus string `xml:"lastStatus"`
+ Overrides TaskOverride `xml:"overrides"`
+ TaskArn string `xml:"taskArn"`
+ TaskDefinitionArn string `xml:"taskDefinitionArn"`
+}
+
+// DescribeTasksReq encapsulates DescribeTasks req params
+type DescribeTasksReq struct {
+ Cluster string
+ Tasks []string
+}
+
+// DescribeTasksResp encapsuates the DescribeTasks response
+type DescribeTasksResp struct {
+ Tasks []Task `xml:"DescribeTasksResult>tasks>member"`
+ Failures []Failure `xml:"DescribeTasksResult>failures>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeTasks describes a task definition
+func (e *ECS) DescribeTasks(req *DescribeTasksReq) (*DescribeTasksResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("DescribeTasks")
+ if len(req.Tasks) > 0 {
+ addParamsList(params, "tasks.member", req.Tasks)
+ }
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+
+ resp := new(DescribeTasksResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DiscoverPollEndpointReq encapsulates DiscoverPollEndpoint req params
+type DiscoverPollEndpointReq struct {
+ ContainerInstance string
+}
+
+// DiscoverPollEndpointResp encapsuates the DiscoverPollEndpoint response
+type DiscoverPollEndpointResp struct {
+ Endpoint string `xml:"DiscoverPollEndpointResult>endpoint"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DiscoverPollEndpoint returns an endpoint for the Amazon EC2 Container Service agent
+// to poll for updates
+func (e *ECS) DiscoverPollEndpoint(req *DiscoverPollEndpointReq) (
+ *DiscoverPollEndpointResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("DiscoverPollEndpoint")
+ if req.ContainerInstance != "" {
+ params["containerInstance"] = req.ContainerInstance
+ }
+
+ resp := new(DiscoverPollEndpointResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ListClustersReq encapsulates ListClusters req params
+type ListClustersReq struct {
+ MaxResults int32
+ NextToken string
+}
+
+// ListClustersResp encapsuates the ListClusters response
+type ListClustersResp struct {
+ ClusterArns []string `xml:"ListClustersResult>clusterArns>member"`
+ NextToken string `xml:"ListClustersResult>nextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ListClusters returns a list of existing clusters
+func (e *ECS) ListClusters(req *ListClustersReq) (
+ *ListClustersResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("ListClusters")
+ if req.MaxResults > 0 {
+ params["maxResults"] = strconv.Itoa(int(req.MaxResults))
+ }
+ if req.NextToken != "" {
+ params["nextToken"] = req.NextToken
+ }
+
+ resp := new(ListClustersResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ListContainerInstancesReq encapsulates ListContainerInstances req params
+type ListContainerInstancesReq struct {
+ Cluster string
+ MaxResults int32
+ NextToken string
+}
+
+// ListContainerInstancesResp encapsuates the ListContainerInstances response
+type ListContainerInstancesResp struct {
+ ContainerInstanceArns []string `xml:"ListContainerInstancesResult>containerInstanceArns>member"`
+ NextToken string `xml:"ListContainerInstancesResult>nextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ListContainerInstances returns a list of container instances in a specified cluster.
+func (e *ECS) ListContainerInstances(req *ListContainerInstancesReq) (
+ *ListContainerInstancesResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("ListContainerInstances")
+ if req.MaxResults > 0 {
+ params["maxResults"] = strconv.Itoa(int(req.MaxResults))
+ }
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ if req.NextToken != "" {
+ params["nextToken"] = req.NextToken
+ }
+
+ resp := new(ListContainerInstancesResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ListTaskDefinitionsReq encapsulates ListTaskDefinitions req params
+type ListTaskDefinitionsReq struct {
+ FamilyPrefix string
+ MaxResults int32
+ NextToken string
+}
+
+// ListTaskDefinitionsResp encapsuates the ListTaskDefinitions response
+type ListTaskDefinitionsResp struct {
+ TaskDefinitionArns []string `xml:"ListTaskDefinitionsResult>taskDefinitionArns>member"`
+ NextToken string `xml:"ListTaskDefinitionsResult>nextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ListTaskDefinitions Returns a list of task definitions that are registered to your account.
+func (e *ECS) ListTaskDefinitions(req *ListTaskDefinitionsReq) (
+ *ListTaskDefinitionsResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("ListTaskDefinitions")
+ if req.MaxResults > 0 {
+ params["maxResults"] = strconv.Itoa(int(req.MaxResults))
+ }
+ if req.FamilyPrefix != "" {
+ params["familyPrefix"] = req.FamilyPrefix
+ }
+ if req.NextToken != "" {
+ params["nextToken"] = req.NextToken
+ }
+
+ resp := new(ListTaskDefinitionsResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ListTasksReq encapsulates ListTasks req params
+type ListTasksReq struct {
+ Cluster string
+ ContainerInstance string
+ Family string
+ MaxResults int32
+ NextToken string
+}
+
+// ListTasksResp encapsuates the ListTasks response
+type ListTasksResp struct {
+ TaskArns []string `xml:"ListTasksResult>taskArns>member"`
+ NextToken string `xml:"ListTasksResult>nextToken"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ListTasks Returns a list of tasks for a specified cluster.
+// You can filter the results by family name or by a particular container instance
+// with the family and containerInstance parameters.
+func (e *ECS) ListTasks(req *ListTasksReq) (
+ *ListTasksResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("ListTasks")
+ if req.MaxResults > 0 {
+ params["maxResults"] = strconv.Itoa(int(req.MaxResults))
+ }
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ if req.ContainerInstance != "" {
+ params["containerInstance"] = req.ContainerInstance
+ }
+ if req.Family != "" {
+ params["family"] = req.Family
+ }
+ if req.NextToken != "" {
+ params["nextToken"] = req.NextToken
+ }
+
+ resp := new(ListTasksResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// RegisterContainerInstanceReq encapsulates RegisterContainerInstance req params
+type RegisterContainerInstanceReq struct {
+ Cluster string
+ InstanceIdentityDocument string
+ InstanceIdentityDocumentSignature string
+ TotalResources []Resource
+}
+
+// DeregisterContainerInstanceResp encapsulates RegisterContainerInstance response
+type RegisterContainerInstanceResp struct {
+ ContainerInstance ContainerInstance `xml:"RegisterContainerInstanceResult>containerInstance"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// RegisterContainerInstance registers an Amazon EC2 instance into the specified cluster.
+// This instance will become available to place containers on.
+func (e *ECS) RegisterContainerInstance(req *RegisterContainerInstanceReq) (
+ resp *RegisterContainerInstanceResp, err error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("RegisterContainerInstance")
+ if req.InstanceIdentityDocument != "" {
+ params["instanceIdentityDocument"] = req.InstanceIdentityDocument
+ }
+ if req.InstanceIdentityDocumentSignature != "" {
+ params["instanceIdentityDocumentSignature"] = req.InstanceIdentityDocumentSignature
+ }
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ // Marshal Resources
+ for i, r := range req.TotalResources {
+ key := fmt.Sprintf("totalResources.member.%d", i+1)
+ params[fmt.Sprintf("%s.doubleValue", key)] = strconv.FormatFloat(r.DoubleValue, 'f', 1, 64)
+ params[fmt.Sprintf("%s.integerValue", key)] = strconv.Itoa(int(r.IntegerValue))
+ params[fmt.Sprintf("%s.longValue", key)] = strconv.Itoa(int(r.LongValue))
+ params[fmt.Sprintf("%s.name", key)] = r.Name
+ params[fmt.Sprintf("%s.type", key)] = r.Type
+ for k, sv := range r.StringSetValue {
+ params[fmt.Sprintf("%s.stringSetValue.member.%d", key, k+1)] = sv
+ }
+ }
+
+ resp = new(RegisterContainerInstanceResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// RegisterTaskDefinitionReq encapsulates RegisterTaskDefinition req params
+type RegisterTaskDefinitionReq struct {
+ Family string
+ ContainerDefinitions []ContainerDefinition
+ Volumes []Volume
+}
+
+// RegisterTaskDefinitionResp encapsulates RegisterTaskDefinition response
+type RegisterTaskDefinitionResp struct {
+ TaskDefinition TaskDefinition `xml:"RegisterTaskDefinitionResult>taskDefinition"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// RegisterTaskDefinition registers a new task definition from the supplied family and containerDefinitions.
+func (e *ECS) RegisterTaskDefinition(req *RegisterTaskDefinitionReq) (
+ resp *RegisterTaskDefinitionResp, err error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+ params := makeParams("RegisterTaskDefinition")
+ if req.Family != "" {
+ params["family"] = req.Family
+ }
+
+ // Marshal Container Definitions
+ for i, c := range req.ContainerDefinitions {
+ key := fmt.Sprintf("containerDefinitions.member.%d", i+1)
+ params[fmt.Sprintf("%s.cpu", key)] = strconv.Itoa(int(c.Cpu))
+ params[fmt.Sprintf("%s.essential", key)] = strconv.FormatBool(c.Essential)
+ params[fmt.Sprintf("%s.image", key)] = c.Image
+ params[fmt.Sprintf("%s.memory", key)] = strconv.Itoa(int(c.Memory))
+ params[fmt.Sprintf("%s.name", key)] = c.Name
+
+ for k, cmd := range c.Command {
+ params[fmt.Sprintf("%s.command.member.%d", key, k+1)] = cmd
+ }
+ for k, ep := range c.EntryPoint {
+ params[fmt.Sprintf("%s.entryPoint.member.%d", key, k+1)] = ep
+ }
+ for k, env := range c.Environment {
+ params[fmt.Sprintf("%s.environment.member.%d.name", key, k+1)] = env.Name
+ params[fmt.Sprintf("%s.environment.member.%d.value", key, k+1)] = env.Value
+ }
+ for k, l := range c.Links {
+ params[fmt.Sprintf("%s.links.member.%d", key, k+1)] = l
+ }
+ for k, p := range c.PortMappings {
+ params[fmt.Sprintf("%s.portMappings.member.%d.containerPort", key, k+1)] = strconv.Itoa(int(p.ContainerPort))
+ params[fmt.Sprintf("%s.portMappings.member.%d.hostPort", key, k+1)] = strconv.Itoa(int(p.HostPort))
+ }
+ for k, m := range c.MountPoints {
+ params[fmt.Sprintf("%s.mountPoints.member.%d.containerPath", key, k+1)] = m.ContainerPath
+ params[fmt.Sprintf("%s.mountPoints.member.%d.readOnly", key, k+1)] = strconv.FormatBool(m.ReadOnly)
+ params[fmt.Sprintf("%s.mountPoints.member.%d.sourceVolume", key, k+1)] = m.SourceVolume
+ }
+ for k, v := range c.VolumesFrom {
+ params[fmt.Sprintf("%s.volumesFrom.member.%d.readOnly", key, k+1)] = strconv.FormatBool(v.ReadOnly)
+ params[fmt.Sprintf("%s.volumesFrom.member.%d.sourceContainer", key, k+1)] = v.SourceContainer
+ }
+ }
+
+ for k, v := range req.Volumes {
+ params[fmt.Sprintf("volumes.member.%d.name", k+1)] = v.Name
+ params[fmt.Sprintf("volumes.member.%d.host.sourcePath", k+1)] = v.Host.SourcePath
+ }
+
+ resp = new(RegisterTaskDefinitionResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// RunTaskReq encapsulates RunTask req params
+type RunTaskReq struct {
+ Cluster string
+ Count int32
+ Overrides TaskOverride
+ TaskDefinition string
+}
+
+// RunTaskResp encapsuates the RunTask response
+type RunTaskResp struct {
+ Tasks []Task `xml:"RunTaskResult>tasks>member"`
+ Failures []Failure `xml:"RunTaskResult>failures>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// RunTask Start a task using random placement and the default Amazon ECS scheduler.
+// If you want to use your own scheduler or place a task on a specific container instance,
+// use StartTask instead.
+func (e *ECS) RunTask(req *RunTaskReq) (*RunTaskResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("RunTask")
+ if req.Count > 0 {
+ params["count"] = strconv.Itoa(int(req.Count))
+ }
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ if req.TaskDefinition != "" {
+ params["taskDefinition"] = req.TaskDefinition
+ }
+
+ for i, co := range req.Overrides.ContainerOverrides {
+ key := fmt.Sprintf("overrides.containerOverrides.member.%d", i+1)
+ params[fmt.Sprintf("%s.name", key)] = co.Name
+ for k, cmd := range co.Command {
+ params[fmt.Sprintf("%s.command.member.%d", key, k+1)] = cmd
+ }
+ for k, env := range co.Environment {
+ params[fmt.Sprintf("%s.environment.member.%d.name", key, k+1)] = env.Name
+ params[fmt.Sprintf("%s.environment.member.%d.value", key, k+1)] = env.Value
+ }
+ }
+
+ resp := new(RunTaskResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StartTaskReq encapsulates StartTask req params
+type StartTaskReq struct {
+ Cluster string
+ ContainerInstances []string
+ Overrides TaskOverride
+ TaskDefinition string
+}
+
+// StartTaskResp encapsuates the StartTask response
+type StartTaskResp struct {
+ Tasks []Task `xml:"StartTaskResult>tasks>member"`
+ Failures []Failure `xml:"StartTaskResult>failures>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// StartTask Starts a new task from the specified task definition on the specified
+// container instance or instances. If you want to use the default Amazon ECS scheduler
+// to place your task, use RunTask instead.
+func (e *ECS) StartTask(req *StartTaskReq) (*StartTaskResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("StartTask")
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ if req.TaskDefinition != "" {
+ params["taskDefinition"] = req.TaskDefinition
+ }
+ for i, ci := range req.ContainerInstances {
+ params[fmt.Sprintf("containerInstances.member.%d", i+1)] = ci
+ }
+ for i, co := range req.Overrides.ContainerOverrides {
+ key := fmt.Sprintf("overrides.containerOverrides.member.%d", i+1)
+ params[fmt.Sprintf("%s.name", key)] = co.Name
+ for k, cmd := range co.Command {
+ params[fmt.Sprintf("%s.command.member.%d", key, k+1)] = cmd
+ }
+ }
+
+ resp := new(StartTaskResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// StopTaskReq encapsulates StopTask req params
+type StopTaskReq struct {
+ Cluster string
+ Task string
+}
+
+// StopTaskResp encapsuates the StopTask response
+type StopTaskResp struct {
+ Task Task `xml:"StopTaskResult>task"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// StopTask stops a running task
+func (e *ECS) StopTask(req *StopTaskReq) (*StopTaskResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("StopTask")
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ if req.Task != "" {
+ params["task"] = req.Task
+ }
+
+ resp := new(StopTaskResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// SubmitContainerStateChangeReq encapsulates SubmitContainerStateChange req params
+type SubmitContainerStateChangeReq struct {
+ Cluster string
+ ContainerName string
+ ExitCode int32
+ NetworkBindings []NetworkBinding
+ Reason string
+ Status string
+ Task string
+}
+
+// SubmitContainerStateChangeResp encapsuates the SubmitContainerStateChange response
+type SubmitContainerStateChangeResp struct {
+ Acknowledgment string `xml:"SubmitContainerStateChangeResult>acknowledgment"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// SubmitContainerStateChange is used to acknowledge that a container changed states.
+// Note: This action is only used by the Amazon EC2 Container Service agent,
+// and it is not intended for use outside of the agent.
+func (e *ECS) SubmitContainerStateChange(req *SubmitContainerStateChangeReq) (
+ *SubmitContainerStateChangeResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("SubmitContainerStateChange")
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+ if req.ContainerName != "" {
+ params["containerName"] = req.ContainerName
+ }
+ if req.Reason != "" {
+ params["reason"] = req.Reason
+ }
+ if req.Status != "" {
+ params["status"] = req.Status
+ }
+ if req.Task != "" {
+ params["task"] = req.Task
+ }
+ for i, nb := range req.NetworkBindings {
+ key := fmt.Sprintf("networkBindings.member.%d", i+1)
+ params[fmt.Sprintf("%s.bindIp", key)] = nb.BindIp
+ params[fmt.Sprintf("%s.containerPort", key)] = strconv.Itoa(int(nb.ContainerPort))
+ params[fmt.Sprintf("%s.hostPort", key)] = strconv.Itoa(int(nb.HostPort))
+ }
+ params["exitCode"] = strconv.Itoa(int(req.ExitCode))
+
+ resp := new(SubmitContainerStateChangeResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// SubmitTaskStateChangeReq encapsulates SubmitTaskStateChange req params
+type SubmitTaskStateChangeReq struct {
+ Cluster string
+ Reason string
+ Status string
+ Task string
+}
+
+// SubmitTaskStateChangeResp encapsuates the SubmitTaskStateChange response
+type SubmitTaskStateChangeResp struct {
+ Acknowledgment string `xml:"SubmitTaskStateChangeResult>acknowledgment"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// SubmitTaskStateChange is used to acknowledge that a task changed states.
+// Note: This action is only used by the Amazon EC2 Container Service agent,
+// and it is not intended for use outside of the agent.
+func (e *ECS) SubmitTaskStateChange(req *SubmitTaskStateChangeReq) (
+ *SubmitTaskStateChangeResp, error) {
+ if req == nil {
+ return nil, fmt.Errorf("The req params cannot be nil")
+ }
+
+ params := makeParams("SubmitTaskStateChange")
+ if req.Cluster != "" {
+ params["cluster"] = req.Cluster
+ }
+
+ if req.Reason != "" {
+ params["reason"] = req.Reason
+ }
+ if req.Status != "" {
+ params["status"] = req.Status
+ }
+ if req.Task != "" {
+ params["task"] = req.Task
+ }
+
+ resp := new(SubmitTaskStateChangeResp)
+ if err := e.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
diff --git a/vendor/github.com/goamz/goamz/ecs/ecs_test.go b/vendor/github.com/goamz/goamz/ecs/ecs_test.go
new file mode 100644
index 000000000..7fe4a74ae
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ecs/ecs_test.go
@@ -0,0 +1,806 @@
+package ecs
+
+import (
+ "testing"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/testutil"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ ecs *ECS
+}
+
+var testServer = testutil.NewHTTPServer()
+
+var mockTest bool
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.ecs = New(auth, aws.Region{ECSEndpoint: testServer.URL})
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+// --------------------------------------------------------------------------
+// Detailed Unit Tests
+
+func (s *S) TestCreateCluster(c *C) {
+ testServer.Response(200, nil, CreateClusterResponse)
+ req := &CreateClusterReq{
+ ClusterName: "default",
+ }
+ resp, err := s.ecs.CreateCluster(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "CreateCluster")
+ c.Assert(values.Get("clusterName"), Equals, "default")
+
+ c.Assert(resp.Cluster.ClusterArn, Equals, "arn:aws:ecs:region:aws_account_id:cluster/default")
+ c.Assert(resp.Cluster.ClusterName, Equals, "default")
+ c.Assert(resp.Cluster.Status, Equals, "ACTIVE")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestDeregisterContainerInstance(c *C) {
+ testServer.Response(200, nil, DeregisterContainerInstanceResponse)
+ req := &DeregisterContainerInstanceReq{
+ Cluster: "default",
+ ContainerInstance: "uuid",
+ Force: true,
+ }
+ resp, err := s.ecs.DeregisterContainerInstance(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "DeregisterContainerInstance")
+ c.Assert(values.Get("cluster"), Equals, "default")
+ c.Assert(values.Get("containerInstance"), Equals, "uuid")
+ c.Assert(values.Get("force"), Equals, "true")
+
+ expectedResource := []Resource{
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 2048,
+ LongValue: 0,
+ Name: "CPU",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 3955,
+ LongValue: 0,
+ Name: "MEMORY",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 0,
+ LongValue: 0,
+ Name: "PORTS",
+ StringSetValue: []string{"2376", "22", "51678", "2375"},
+ Type: "STRINGSET",
+ },
+ }
+
+ c.Assert(resp.ContainerInstance.AgentConnected, Equals, false)
+ c.Assert(resp.ContainerInstance.ContainerInstanceArn, Equals, "arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID")
+ c.Assert(resp.ContainerInstance.Status, Equals, "INACTIVE")
+ c.Assert(resp.ContainerInstance.Ec2InstanceId, Equals, "instance_id")
+ c.Assert(resp.ContainerInstance.RegisteredResources, DeepEquals, expectedResource)
+ c.Assert(resp.ContainerInstance.RemainingResources, DeepEquals, expectedResource)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestDeregisterTaskDefinition(c *C) {
+ testServer.Response(200, nil, DeregisterTaskDefinitionResponse)
+ req := &DeregisterTaskDefinitionReq{
+ TaskDefinition: "sleep360:2",
+ }
+ resp, err := s.ecs.DeregisterTaskDefinition(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "DeregisterTaskDefinition")
+ c.Assert(values.Get("taskDefinition"), Equals, "sleep360:2")
+
+ expected := TaskDefinition{
+ Family: "sleep360",
+ Revision: 2,
+ TaskDefinitionArn: "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2",
+ ContainerDefinitions: []ContainerDefinition{
+ {
+ Command: []string{"sleep", "360"},
+ Cpu: 10,
+ EntryPoint: []string{"/bin/sh"},
+ Environment: []KeyValuePair{
+ {
+ Name: "envVar",
+ Value: "foo",
+ },
+ },
+ Essential: true,
+ Image: "busybox",
+ Memory: 10,
+ Name: "sleep",
+ },
+ },
+ }
+
+ c.Assert(resp.TaskDefinition, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestDescribeClusters(c *C) {
+ testServer.Response(200, nil, DescribeClustersResponse)
+ req := &DescribeClustersReq{
+ Clusters: []string{"test", "default"},
+ }
+ resp, err := s.ecs.DescribeClusters(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "DescribeClusters")
+ c.Assert(values.Get("clusters.member.1"), Equals, "test")
+ c.Assert(values.Get("clusters.member.2"), Equals, "default")
+
+ expected := []Cluster{
+ {
+ ClusterName: "test",
+ ClusterArn: "arn:aws:ecs:us-east-1:aws_account_id:cluster/test",
+ Status: "ACTIVE",
+ },
+ {
+ ClusterName: "default",
+ ClusterArn: "arn:aws:ecs:us-east-1:aws_account_id:cluster/default",
+ Status: "ACTIVE",
+ },
+ }
+
+ c.Assert(resp.Clusters, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestDescribeContainerInstances(c *C) {
+ testServer.Response(200, nil, DescribeContainerInstancesResponse)
+ req := &DescribeContainerInstancesReq{
+ Cluster: "test",
+ ContainerInstances: []string{"arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID"},
+ }
+ resp, err := s.ecs.DescribeContainerInstances(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "DescribeContainerInstances")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("containerInstances.member.1"),
+ Equals, "arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID")
+
+ expected := []ContainerInstance{
+ ContainerInstance{
+ AgentConnected: true,
+ ContainerInstanceArn: "arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID",
+ Status: "ACTIVE",
+ Ec2InstanceId: "instance_id",
+ RegisteredResources: []Resource{
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 2048,
+ LongValue: 0,
+ Name: "CPU",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 3955,
+ LongValue: 0,
+ Name: "MEMORY",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 0,
+ LongValue: 0,
+ Name: "PORTS",
+ StringSetValue: []string{"2376", "22", "51678", "2375"},
+ Type: "STRINGSET",
+ },
+ },
+ RemainingResources: []Resource{
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 2048,
+ LongValue: 0,
+ Name: "CPU",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 3955,
+ LongValue: 0,
+ Name: "MEMORY",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 0,
+ LongValue: 0,
+ Name: "PORTS",
+ StringSetValue: []string{"2376", "22", "51678", "2375"},
+ Type: "STRINGSET",
+ },
+ },
+ },
+ }
+
+ c.Assert(resp.ContainerInstances, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestDescribeTaskDefinition(c *C) {
+ testServer.Response(200, nil, DescribeTaskDefinitionResponse)
+ req := &DescribeTaskDefinitionReq{
+ TaskDefinition: "sleep360:2",
+ }
+ resp, err := s.ecs.DescribeTaskDefinition(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "DescribeTaskDefinition")
+ c.Assert(values.Get("taskDefinition"), Equals, "sleep360:2")
+
+ expected := TaskDefinition{
+ Family: "sleep360",
+ Revision: 2,
+ TaskDefinitionArn: "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2",
+ ContainerDefinitions: []ContainerDefinition{
+ {
+ Command: []string{"sleep", "360"},
+ Cpu: 10,
+ EntryPoint: []string{"/bin/sh"},
+ Environment: []KeyValuePair{
+ {
+ Name: "envVar",
+ Value: "foo",
+ },
+ },
+ Essential: true,
+ Image: "busybox",
+ Memory: 10,
+ Name: "sleep",
+ },
+ },
+ }
+
+ c.Assert(resp.TaskDefinition, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestDescribeTasks(c *C) {
+ testServer.Response(200, nil, DescribeTasksResponse)
+ req := &DescribeTasksReq{
+ Cluster: "test",
+ Tasks: []string{"arn:aws:ecs:us-east-1:aws_account_id:task/UUID"},
+ }
+ resp, err := s.ecs.DescribeTasks(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "DescribeTasks")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("tasks.member.1"),
+ Equals, "arn:aws:ecs:us-east-1:aws_account_id:task/UUID")
+
+ expected := []Task{
+ Task{
+ Containers: []Container{
+ {
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ Name: "sleep",
+ ContainerArn: "arn:aws:ecs:us-east-1:aws_account_id:container/UUID",
+ LastStatus: "RUNNING",
+ },
+ },
+ Overrides: TaskOverride{
+ ContainerOverrides: []ContainerOverride{
+ {
+ Name: "sleep",
+ },
+ },
+ },
+ DesiredStatus: "RUNNING",
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ ContainerInstanceArn: "arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID",
+ LastStatus: "RUNNING",
+ TaskDefinitionArn: "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2",
+ },
+ }
+
+ c.Assert(resp.Tasks, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestDiscoverPollEndpoint(c *C) {
+ testServer.Response(200, nil, DiscoverPollEndpointResponse)
+ req := &DiscoverPollEndpointReq{
+ ContainerInstance: "arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID",
+ }
+ resp, err := s.ecs.DiscoverPollEndpoint(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "DiscoverPollEndpoint")
+ c.Assert(values.Get("containerInstance"),
+ Equals, "arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID")
+
+ c.Assert(resp.Endpoint, Equals, "https://ecs-x-1.us-east-1.amazonaws.com/")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestListClusters(c *C) {
+ testServer.Response(200, nil, ListClustersResponse)
+ req := &ListClustersReq{
+ MaxResults: 2,
+ NextToken: "Token_UUID",
+ }
+ resp, err := s.ecs.ListClusters(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "ListClusters")
+ c.Assert(values.Get("maxResults"), Equals, "2")
+ c.Assert(values.Get("nextToken"), Equals, "Token_UUID")
+
+ c.Assert(resp.ClusterArns, DeepEquals, []string{"arn:aws:ecs:us-east-1:aws_account_id:cluster/default",
+ "arn:aws:ecs:us-east-1:aws_account_id:cluster/test"})
+ c.Assert(resp.NextToken, Equals, "token_UUID")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestListContainerInstances(c *C) {
+ testServer.Response(200, nil, ListContainerInstancesResponse)
+ req := &ListContainerInstancesReq{
+ MaxResults: 2,
+ NextToken: "Token_UUID",
+ Cluster: "test",
+ }
+ resp, err := s.ecs.ListContainerInstances(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "ListContainerInstances")
+ c.Assert(values.Get("maxResults"), Equals, "2")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("nextToken"), Equals, "Token_UUID")
+
+ c.Assert(resp.ContainerInstanceArns, DeepEquals, []string{
+ "arn:aws:ecs:us-east-1:aws_account_id:container-instance/uuid-1",
+ "arn:aws:ecs:us-east-1:aws_account_id:container-instance/uuid-2"})
+ c.Assert(resp.NextToken, Equals, "token_UUID")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestListTaskDefinitions(c *C) {
+ testServer.Response(200, nil, ListTaskDefinitionsResponse)
+ req := &ListTaskDefinitionsReq{
+ MaxResults: 2,
+ NextToken: "Token_UUID",
+ FamilyPrefix: "sleep360",
+ }
+ resp, err := s.ecs.ListTaskDefinitions(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "ListTaskDefinitions")
+ c.Assert(values.Get("maxResults"), Equals, "2")
+ c.Assert(values.Get("familyPrefix"), Equals, "sleep360")
+ c.Assert(values.Get("nextToken"), Equals, "Token_UUID")
+
+ c.Assert(resp.TaskDefinitionArns, DeepEquals, []string{
+ "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:1",
+ "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2"})
+ c.Assert(resp.NextToken, Equals, "token_UUID")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestListTasks(c *C) {
+ testServer.Response(200, nil, ListTasksResponse)
+ req := &ListTasksReq{
+ MaxResults: 2,
+ NextToken: "Token_UUID",
+ Family: "sleep360",
+ Cluster: "test",
+ ContainerInstance: "container_uuid",
+ }
+ resp, err := s.ecs.ListTasks(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "ListTasks")
+ c.Assert(values.Get("maxResults"), Equals, "2")
+ c.Assert(values.Get("family"), Equals, "sleep360")
+ c.Assert(values.Get("containerInstance"), Equals, "container_uuid")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("nextToken"), Equals, "Token_UUID")
+
+ c.Assert(resp.TaskArns, DeepEquals, []string{
+ "arn:aws:ecs:us-east-1:aws_account_id:task/uuid_1",
+ "arn:aws:ecs:us-east-1:aws_account_id:task/uuid_2"})
+ c.Assert(resp.NextToken, Equals, "token_UUID")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestRegisterContainerInstance(c *C) {
+ testServer.Response(200, nil, RegisterContainerInstanceResponse)
+
+ resources := []Resource{
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 2048,
+ LongValue: 0,
+ Name: "CPU",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 3955,
+ LongValue: 0,
+ Name: "MEMORY",
+ Type: "INTEGER",
+ },
+ {
+ DoubleValue: 0.0,
+ IntegerValue: 0,
+ LongValue: 0,
+ Name: "PORTS",
+ StringSetValue: []string{"2376", "22", "51678", "2375"},
+ Type: "STRINGSET",
+ },
+ }
+
+ req := &RegisterContainerInstanceReq{
+ Cluster: "default",
+ InstanceIdentityDocument: "foo",
+ InstanceIdentityDocumentSignature: "baz",
+ TotalResources: resources,
+ }
+
+ resp, err := s.ecs.RegisterContainerInstance(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "RegisterContainerInstance")
+ c.Assert(values.Get("cluster"), Equals, "default")
+ c.Assert(values.Get("instanceIdentityDocument"), Equals, "foo")
+ c.Assert(values.Get("instanceIdentityDocumentSignature"), Equals, "baz")
+ c.Assert(values.Get("totalResources.member.1.doubleValue"), Equals, "0.0")
+ c.Assert(values.Get("totalResources.member.1.integerValue"), Equals, "2048")
+ c.Assert(values.Get("totalResources.member.1.longValue"), Equals, "0")
+ c.Assert(values.Get("totalResources.member.1.name"), Equals, "CPU")
+ c.Assert(values.Get("totalResources.member.1.type"), Equals, "INTEGER")
+ c.Assert(values.Get("totalResources.member.2.doubleValue"), Equals, "0.0")
+ c.Assert(values.Get("totalResources.member.2.integerValue"), Equals, "3955")
+ c.Assert(values.Get("totalResources.member.2.longValue"), Equals, "0")
+ c.Assert(values.Get("totalResources.member.2.name"), Equals, "MEMORY")
+ c.Assert(values.Get("totalResources.member.2.type"), Equals, "INTEGER")
+ c.Assert(values.Get("totalResources.member.3.doubleValue"), Equals, "0.0")
+ c.Assert(values.Get("totalResources.member.3.integerValue"), Equals, "0")
+ c.Assert(values.Get("totalResources.member.3.longValue"), Equals, "0")
+ c.Assert(values.Get("totalResources.member.3.name"), Equals, "PORTS")
+ c.Assert(values.Get("totalResources.member.3.stringSetValue.member.1"), Equals, "2376")
+ c.Assert(values.Get("totalResources.member.3.stringSetValue.member.2"), Equals, "22")
+ c.Assert(values.Get("totalResources.member.3.stringSetValue.member.3"), Equals, "51678")
+ c.Assert(values.Get("totalResources.member.3.stringSetValue.member.4"), Equals, "2375")
+ c.Assert(values.Get("totalResources.member.3.type"), Equals, "STRINGSET")
+
+ c.Assert(resp.ContainerInstance.AgentConnected, Equals, true)
+ c.Assert(resp.ContainerInstance.ContainerInstanceArn, Equals, "arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID")
+ c.Assert(resp.ContainerInstance.Status, Equals, "ACTIVE")
+ c.Assert(resp.ContainerInstance.Ec2InstanceId, Equals, "instance_id")
+ c.Assert(resp.ContainerInstance.RegisteredResources, DeepEquals, resources)
+ c.Assert(resp.ContainerInstance.RemainingResources, DeepEquals, resources)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestRegisterTaskDefinition(c *C) {
+ testServer.Response(200, nil, RegisterTaskDefinitionResponse)
+
+ CDefinitions := []ContainerDefinition{
+ {
+ Command: []string{"sleep", "360"},
+ Cpu: 10,
+ EntryPoint: []string{"/bin/sh"},
+ Environment: []KeyValuePair{
+ {
+ Name: "envVar",
+ Value: "foo",
+ },
+ },
+ Essential: true,
+ Image: "busybox",
+ Memory: 10,
+ Name: "sleep",
+ MountPoints: []MountPoint{
+ {
+ ContainerPath: "/tmp/myfile",
+ ReadOnly: false,
+ SourceVolume: "/srv/myfile",
+ },
+ {
+ ContainerPath: "/tmp/myfile2",
+ ReadOnly: true,
+ SourceVolume: "/srv/myfile2",
+ },
+ },
+ VolumesFrom: []VolumeFrom{
+ {
+ ReadOnly: true,
+ SourceContainer: "foo",
+ },
+ },
+ },
+ }
+
+ req := &RegisterTaskDefinitionReq{
+ Family: "sleep360",
+ ContainerDefinitions: CDefinitions,
+ Volumes: []Volume{
+ {
+ Name: "/srv/myfile",
+ Host: HostVolumeProperties{
+ SourcePath: "/srv/myfile",
+ },
+ },
+ },
+ }
+ resp, err := s.ecs.RegisterTaskDefinition(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "RegisterTaskDefinition")
+ c.Assert(values.Get("containerDefinitions.member.1.command.member.1"), Equals, "sleep")
+ c.Assert(values.Get("containerDefinitions.member.1.command.member.2"), Equals, "360")
+ c.Assert(values.Get("containerDefinitions.member.1.cpu"), Equals, "10")
+ c.Assert(values.Get("containerDefinitions.member.1.memory"), Equals, "10")
+ c.Assert(values.Get("containerDefinitions.member.1.entryPoint.member.1"), Equals, "/bin/sh")
+ c.Assert(values.Get("containerDefinitions.member.1.environment.member.1.name"), Equals, "envVar")
+ c.Assert(values.Get("containerDefinitions.member.1.environment.member.1.value"), Equals, "foo")
+ c.Assert(values.Get("containerDefinitions.member.1.essential"), Equals, "true")
+ c.Assert(values.Get("containerDefinitions.member.1.image"), Equals, "busybox")
+ c.Assert(values.Get("containerDefinitions.member.1.memory"), Equals, "10")
+ c.Assert(values.Get("containerDefinitions.member.1.name"), Equals, "sleep")
+ c.Assert(values.Get("containerDefinitions.member.1.mountPoints.member.1.containerPath"), Equals, "/tmp/myfile")
+ c.Assert(values.Get("containerDefinitions.member.1.mountPoints.member.1.readOnly"), Equals, "false")
+ c.Assert(values.Get("containerDefinitions.member.1.mountPoints.member.1.sourceVolume"), Equals, "/srv/myfile")
+ c.Assert(values.Get("containerDefinitions.member.1.mountPoints.member.2.containerPath"), Equals, "/tmp/myfile2")
+ c.Assert(values.Get("containerDefinitions.member.1.mountPoints.member.2.readOnly"), Equals, "true")
+ c.Assert(values.Get("containerDefinitions.member.1.mountPoints.member.2.sourceVolume"), Equals, "/srv/myfile2")
+ c.Assert(values.Get("containerDefinitions.member.1.volumesFrom.member.1.readOnly"), Equals, "true")
+ c.Assert(values.Get("containerDefinitions.member.1.volumesFrom.member.1.sourceContainer"), Equals, "foo")
+
+ c.Assert(values.Get("family"), Equals, "sleep360")
+ c.Assert(values.Get("volumes.member.1.name"), Equals, "/srv/myfile")
+ c.Assert(values.Get("volumes.member.1.host.sourcePath"), Equals, "/srv/myfile")
+
+ expected := TaskDefinition{
+ Family: "sleep360",
+ Revision: 2,
+ TaskDefinitionArn: "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2",
+ ContainerDefinitions: CDefinitions,
+ Volumes: []Volume{
+ {
+ Name: "/srv/myfile",
+ Host: HostVolumeProperties{
+ SourcePath: "/srv/myfile",
+ },
+ },
+ },
+ }
+
+ c.Assert(resp.TaskDefinition, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestRunTask(c *C) {
+ testServer.Response(200, nil, RunTaskResponse)
+ req := &RunTaskReq{
+ Cluster: "test",
+ Count: 1,
+ TaskDefinition: "sleep360:2",
+ }
+ resp, err := s.ecs.RunTask(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "RunTask")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("count"), Equals, "1")
+ c.Assert(values.Get("taskDefinition"), Equals, "sleep360:2")
+
+ expected := []Task{
+ Task{
+ Containers: []Container{
+ {
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ Name: "sleep",
+ ContainerArn: "arn:aws:ecs:us-east-1:aws_account_id:container/UUID",
+ LastStatus: "RUNNING",
+ },
+ },
+ Overrides: TaskOverride{
+ ContainerOverrides: []ContainerOverride{
+ {
+ Name: "sleep",
+ },
+ },
+ },
+ DesiredStatus: "RUNNING",
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ ContainerInstanceArn: "arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID",
+ LastStatus: "PENDING",
+ TaskDefinitionArn: "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2",
+ },
+ }
+
+ c.Assert(resp.Tasks, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestStartTask(c *C) {
+ testServer.Response(200, nil, StartTaskResponse)
+ req := &StartTaskReq{
+ Cluster: "test",
+ ContainerInstances: []string{"containerUUID"},
+ TaskDefinition: "sleep360:2",
+ }
+ resp, err := s.ecs.StartTask(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "StartTask")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("taskDefinition"), Equals, "sleep360:2")
+ c.Assert(values.Get("containerInstances.member.1"), Equals, "containerUUID")
+
+ expected := []Task{
+ Task{
+ Containers: []Container{
+ {
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ Name: "sleep",
+ ContainerArn: "arn:aws:ecs:us-east-1:aws_account_id:container/UUID",
+ LastStatus: "RUNNING",
+ },
+ },
+ Overrides: TaskOverride{
+ ContainerOverrides: []ContainerOverride{
+ {
+ Name: "sleep",
+ },
+ },
+ },
+ DesiredStatus: "RUNNING",
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ ContainerInstanceArn: "arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID",
+ LastStatus: "PENDING",
+ TaskDefinitionArn: "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2",
+ },
+ }
+
+ c.Assert(resp.Tasks, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestStopTask(c *C) {
+ testServer.Response(200, nil, StopTaskResponse)
+ req := &StopTaskReq{
+ Cluster: "test",
+ Task: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ }
+ resp, err := s.ecs.StopTask(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "StopTask")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("task"), Equals, "arn:aws:ecs:us-east-1:aws_account_id:task/UUID")
+
+ expected := Task{
+ Containers: []Container{
+ {
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ Name: "sleep",
+ ContainerArn: "arn:aws:ecs:us-east-1:aws_account_id:container/UUID",
+ LastStatus: "RUNNING",
+ },
+ },
+ Overrides: TaskOverride{
+ ContainerOverrides: []ContainerOverride{
+ {
+ Name: "sleep",
+ },
+ },
+ },
+ DesiredStatus: "STOPPED",
+ TaskArn: "arn:aws:ecs:us-east-1:aws_account_id:task/UUID",
+ ContainerInstanceArn: "arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID",
+ LastStatus: "RUNNING",
+ TaskDefinitionArn: "arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2",
+ }
+
+ c.Assert(resp.Task, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestSubmitContainerStateChange(c *C) {
+ testServer.Response(200, nil, SubmitContainerStateChangeResponse)
+ networkBindings := []NetworkBinding{
+ {
+ BindIp: "127.0.0.1",
+ ContainerPort: 80,
+ HostPort: 80,
+ },
+ }
+ req := &SubmitContainerStateChangeReq{
+ Cluster: "test",
+ ContainerName: "container",
+ ExitCode: 0,
+ Reason: "reason",
+ Status: "status",
+ Task: "taskUUID",
+ NetworkBindings: networkBindings,
+ }
+
+ resp, err := s.ecs.SubmitContainerStateChange(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "SubmitContainerStateChange")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("containerName"), Equals, "container")
+ c.Assert(values.Get("exitCode"), Equals, "0")
+ c.Assert(values.Get("reason"), Equals, "reason")
+ c.Assert(values.Get("status"), Equals, "status")
+ c.Assert(values.Get("task"), Equals, "taskUUID")
+ c.Assert(values.Get("networkBindings.member.1.bindIp"), Equals, "127.0.0.1")
+ c.Assert(values.Get("networkBindings.member.1.containerPort"), Equals, "80")
+ c.Assert(values.Get("networkBindings.member.1.hostPort"), Equals, "80")
+
+ c.Assert(resp.Acknowledgment, Equals, "ACK")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
+
+func (s *S) TestSubmitTaskStateChange(c *C) {
+ testServer.Response(200, nil, SubmitTaskStateChangeResponse)
+ req := &SubmitTaskStateChangeReq{
+ Cluster: "test",
+ Reason: "reason",
+ Status: "status",
+ Task: "taskUUID",
+ }
+
+ resp, err := s.ecs.SubmitTaskStateChange(req)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ c.Assert(values.Get("Version"), Equals, "2014-11-13")
+ c.Assert(values.Get("Action"), Equals, "SubmitTaskStateChange")
+ c.Assert(values.Get("cluster"), Equals, "test")
+ c.Assert(values.Get("reason"), Equals, "reason")
+ c.Assert(values.Get("status"), Equals, "status")
+ c.Assert(values.Get("task"), Equals, "taskUUID")
+
+ c.Assert(resp.Acknowledgment, Equals, "ACK")
+ c.Assert(resp.RequestId, Equals, "8d798a29-f083-11e1-bdfb-cb223EXAMPLE")
+}
diff --git a/vendor/github.com/goamz/goamz/ecs/responses_test.go b/vendor/github.com/goamz/goamz/ecs/responses_test.go
new file mode 100644
index 000000000..6a4b0ce71
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/ecs/responses_test.go
@@ -0,0 +1,637 @@
+package ecs
+
+var CreateClusterResponse = `
+<CreateClusterResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+ <CreateClusterResult>
+ <cluster>
+ <clusterArn>arn:aws:ecs:region:aws_account_id:cluster/default</clusterArn>
+ <clusterName>default</clusterName>
+ <status>ACTIVE</status>
+ </cluster>
+ </CreateClusterResult>
+</CreateClusterResponse>
+`
+var DeregisterContainerInstanceResponse = `
+<DeregisterContainerInstanceResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+ <DeregisterContainerInstanceResult>
+ <containerInstance>
+ <agentConnected>False</agentConnected>
+ <containerInstanceArn>arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID</containerInstanceArn>
+ <ec2InstanceId>instance_id</ec2InstanceId>
+ <status>INACTIVE</status>
+ <registeredResources>
+ <member>
+ <integerValue>2048</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>CPU</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>3955</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>MEMORY</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>0</integerValue>
+ <longValue>0</longValue>
+ <type>STRINGSET</type>
+ <stringSetValue>
+ <member>2376</member>
+ <member>22</member>
+ <member>51678</member>
+ <member>2375</member>
+ </stringSetValue>
+ <name>PORTS</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ </registeredResources>
+ <remainingResources>
+ <member>
+ <integerValue>2048</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>CPU</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>3955</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>MEMORY</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>0</integerValue>
+ <longValue>0</longValue>
+ <type>STRINGSET</type>
+ <stringSetValue>
+ <member>2376</member>
+ <member>22</member>
+ <member>51678</member>
+ <member>2375</member>
+ </stringSetValue>
+ <name>PORTS</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ </remainingResources>
+ </containerInstance>
+ </DeregisterContainerInstanceResult>
+</DeregisterContainerInstanceResponse>
+`
+
+var DeregisterTaskDefinitionResponse = `
+<DeregisterTaskDefinitionResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <DeregisterTaskDefinitionResult>
+ <taskDefinition>
+ <revision>2</revision>
+ <family>sleep360</family>
+ <containerDefinitions>
+ <member>
+ <portMappings/>
+ <essential>true</essential>
+ <environment>
+ <member>
+ <name>envVar</name>
+ <value>foo</value>
+ </member>
+ </environment>
+ <entryPoint>
+ <member>/bin/sh</member>
+ </entryPoint>
+ <name>sleep</name>
+ <command>
+ <member>sleep</member>
+ <member>360</member>
+ </command>
+ <cpu>10</cpu>
+ <image>busybox</image>
+ <memory>10</memory>
+ </member>
+ </containerDefinitions>
+ <taskDefinitionArn>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</taskDefinitionArn>
+ </taskDefinition>
+ </DeregisterTaskDefinitionResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DeregisterTaskDefinitionResponse>
+`
+
+var DescribeClustersResponse = `
+<DescribeClustersResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <DescribeClustersResult>
+ <failures/>
+ <clusters>
+ <member>
+ <clusterName>test</clusterName>
+ <clusterArn>arn:aws:ecs:us-east-1:aws_account_id:cluster/test</clusterArn>
+ <status>ACTIVE</status>
+ </member>
+ <member>
+ <clusterName>default</clusterName>
+ <clusterArn>arn:aws:ecs:us-east-1:aws_account_id:cluster/default</clusterArn>
+ <status>ACTIVE</status>
+ </member>
+ </clusters>
+ </DescribeClustersResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeClustersResponse>
+`
+
+var DescribeContainerInstancesResponse = `
+<DescribeContainerInstancesResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+ <DescribeContainerInstancesResult>
+ <failures/>
+ <containerInstances>
+ <member>
+ <agentConnected>true</agentConnected>
+ <containerInstanceArn>arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID</containerInstanceArn>
+ <ec2InstanceId>instance_id</ec2InstanceId>
+ <status>ACTIVE</status>
+ <registeredResources>
+ <member>
+ <integerValue>2048</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>CPU</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>3955</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>MEMORY</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>0</integerValue>
+ <longValue>0</longValue>
+ <type>STRINGSET</type>
+ <stringSetValue>
+ <member>2376</member>
+ <member>22</member>
+ <member>51678</member>
+ <member>2375</member>
+ </stringSetValue>
+ <name>PORTS</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ </registeredResources>
+ <remainingResources>
+ <member>
+ <integerValue>2048</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>CPU</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>3955</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>MEMORY</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>0</integerValue>
+ <longValue>0</longValue>
+ <type>STRINGSET</type>
+ <stringSetValue>
+ <member>2376</member>
+ <member>22</member>
+ <member>51678</member>
+ <member>2375</member>
+ </stringSetValue>
+ <name>PORTS</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ </remainingResources>
+ </member>
+ </containerInstances>
+ </DescribeContainerInstancesResult>
+</DescribeContainerInstancesResponse>
+`
+
+var DescribeTaskDefinitionResponse = `
+<DescribeTaskDefinitionResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <DescribeTaskDefinitionResult>
+ <taskDefinition>
+ <revision>2</revision>
+ <family>sleep360</family>
+ <containerDefinitions>
+ <member>
+ <portMappings/>
+ <essential>true</essential>
+ <environment>
+ <member>
+ <name>envVar</name>
+ <value>foo</value>
+ </member>
+ </environment>
+ <entryPoint>
+ <member>/bin/sh</member>
+ </entryPoint>
+ <name>sleep</name>
+ <command>
+ <member>sleep</member>
+ <member>360</member>
+ </command>
+ <cpu>10</cpu>
+ <image>busybox</image>
+ <memory>10</memory>
+ </member>
+ </containerDefinitions>
+ <taskDefinitionArn>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</taskDefinitionArn>
+ </taskDefinition>
+ </DescribeTaskDefinitionResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeTaskDefinitionResponse>
+`
+
+var DescribeTasksResponse = `
+<DescribeTasksResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <DescribeTasksResult>
+ <failures/>
+ <tasks>
+ <member>
+ <containers>
+ <member>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <name>sleep</name>
+ <containerArn>arn:aws:ecs:us-east-1:aws_account_id:container/UUID</containerArn>
+ <networkBindings/>
+ <lastStatus>RUNNING</lastStatus>
+ </member>
+ </containers>
+ <overrides>
+ <containerOverrides>
+ <member>
+ <name>sleep</name>
+ </member>
+ </containerOverrides>
+ </overrides>
+ <desiredStatus>RUNNING</desiredStatus>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <containerInstanceArn>arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID</containerInstanceArn>
+ <lastStatus>RUNNING</lastStatus>
+ <taskDefinitionArn>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</taskDefinitionArn>
+ </member>
+ </tasks>
+ </DescribeTasksResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DescribeTasksResponse>
+`
+
+var DiscoverPollEndpointResponse = `
+<DiscoverPollEndpointResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <DiscoverPollEndpointResult>
+ <endpoint>https://ecs-x-1.us-east-1.amazonaws.com/</endpoint>
+ </DiscoverPollEndpointResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</DiscoverPollEndpointResponse>
+`
+
+var ListClustersResponse = `
+<ListClustersResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ListClustersResult>
+ <clusterArns>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:cluster/default</member>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:cluster/test</member>
+ </clusterArns>
+ <nextToken>token_UUID</nextToken>
+ </ListClustersResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</ListClustersResponse>
+`
+
+var ListContainerInstancesResponse = `
+<ListContainerInstancesResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ListContainerInstancesResult>
+ <containerInstanceArns>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:container-instance/uuid-1</member>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:container-instance/uuid-2</member>
+ </containerInstanceArns>
+ <nextToken>token_UUID</nextToken>
+ </ListContainerInstancesResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</ListContainerInstancesResponse>
+`
+
+var ListTaskDefinitionsResponse = `
+<ListTaskDefinitionsResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ListTaskDefinitionsResult>
+ <taskDefinitionArns>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:1</member>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</member>
+ </taskDefinitionArns>
+ <nextToken>token_UUID</nextToken>
+ </ListTaskDefinitionsResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</ListTaskDefinitionsResponse>
+`
+
+var ListTasksResponse = `
+<ListTasksResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ListTasksResult>
+ <taskArns>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:task/uuid_1</member>
+ <member>arn:aws:ecs:us-east-1:aws_account_id:task/uuid_2</member>
+ </taskArns>
+ <nextToken>token_UUID</nextToken>
+ </ListTasksResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</ListTasksResponse>
+`
+
+var RegisterContainerInstanceResponse = `
+<RegisterContainerInstanceResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+ <RegisterContainerInstanceResult>
+ <containerInstance>
+ <agentConnected>True</agentConnected>
+ <containerInstanceArn>arn:aws:ecs:us-east-1:aws_account_id:container-instance/container_instance_UUID</containerInstanceArn>
+ <ec2InstanceId>instance_id</ec2InstanceId>
+ <status>ACTIVE</status>
+ <registeredResources>
+ <member>
+ <integerValue>2048</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>CPU</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>3955</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>MEMORY</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>0</integerValue>
+ <longValue>0</longValue>
+ <type>STRINGSET</type>
+ <stringSetValue>
+ <member>2376</member>
+ <member>22</member>
+ <member>51678</member>
+ <member>2375</member>
+ </stringSetValue>
+ <name>PORTS</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ </registeredResources>
+ <remainingResources>
+ <member>
+ <integerValue>2048</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>CPU</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>3955</integerValue>
+ <longValue>0</longValue>
+ <type>INTEGER</type>
+ <name>MEMORY</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ <member>
+ <integerValue>0</integerValue>
+ <longValue>0</longValue>
+ <type>STRINGSET</type>
+ <stringSetValue>
+ <member>2376</member>
+ <member>22</member>
+ <member>51678</member>
+ <member>2375</member>
+ </stringSetValue>
+ <name>PORTS</name>
+ <doubleValue>0.0</doubleValue>
+ </member>
+ </remainingResources>
+ </containerInstance>
+ </RegisterContainerInstanceResult>
+</RegisterContainerInstanceResponse>
+`
+
+var RegisterTaskDefinitionResponse = `
+<RegisterTaskDefinitionResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <RegisterTaskDefinitionResult>
+ <taskDefinition>
+ <revision>2</revision>
+ <family>sleep360</family>
+ <containerDefinitions>
+ <member>
+ <portMappings/>
+ <essential>true</essential>
+ <environment>
+ <member>
+ <name>envVar</name>
+ <value>foo</value>
+ </member>
+ </environment>
+ <entryPoint>
+ <member>/bin/sh</member>
+ </entryPoint>
+ <name>sleep</name>
+ <command>
+ <member>sleep</member>
+ <member>360</member>
+ </command>
+ <cpu>10</cpu>
+ <image>busybox</image>
+ <memory>10</memory>
+ <mountPoints>
+ <member>
+ <containerPath>/tmp/myfile</containerPath>
+ <readOnly>false</readOnly>
+ <sourceVolume>/srv/myfile</sourceVolume>
+ </member>
+ <member>
+ <containerPath>/tmp/myfile2</containerPath>
+ <readOnly>true</readOnly>
+ <sourceVolume>/srv/myfile2</sourceVolume>
+ </member>
+ </mountPoints>
+ <volumesFrom>
+ <member>
+ <readOnly>true</readOnly>
+ <sourceContainer>foo</sourceContainer>
+ </member>
+ </volumesFrom>
+ </member>
+ </containerDefinitions>
+ <taskDefinitionArn>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</taskDefinitionArn>
+ <volumes>
+ <member>
+ <name>/srv/myfile</name>
+ <host>
+ <sourcePath>/srv/myfile</sourcePath>
+ </host>
+ </member>
+ </volumes>
+ </taskDefinition>
+ </RegisterTaskDefinitionResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</RegisterTaskDefinitionResponse>
+`
+
+var RunTaskResponse = `
+<RunTaskResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <RunTaskResult>
+ <failures/>
+ <tasks>
+ <member>
+ <containers>
+ <member>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <name>sleep</name>
+ <containerArn>arn:aws:ecs:us-east-1:aws_account_id:container/UUID</containerArn>
+ <networkBindings/>
+ <lastStatus>RUNNING</lastStatus>
+ </member>
+ </containers>
+ <overrides>
+ <containerOverrides>
+ <member>
+ <name>sleep</name>
+ </member>
+ </containerOverrides>
+ </overrides>
+ <desiredStatus>RUNNING</desiredStatus>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <containerInstanceArn>arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID</containerInstanceArn>
+ <lastStatus>PENDING</lastStatus>
+ <taskDefinitionArn>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</taskDefinitionArn>
+ </member>
+ </tasks>
+ </RunTaskResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</RunTaskResponse>
+`
+
+var StartTaskResponse = `
+<StartTaskResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <StartTaskResult>
+ <failures/>
+ <tasks>
+ <member>
+ <containers>
+ <member>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <name>sleep</name>
+ <containerArn>arn:aws:ecs:us-east-1:aws_account_id:container/UUID</containerArn>
+ <networkBindings/>
+ <lastStatus>RUNNING</lastStatus>
+ </member>
+ </containers>
+ <overrides>
+ <containerOverrides>
+ <member>
+ <name>sleep</name>
+ </member>
+ </containerOverrides>
+ </overrides>
+ <desiredStatus>RUNNING</desiredStatus>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <containerInstanceArn>arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID</containerInstanceArn>
+ <lastStatus>PENDING</lastStatus>
+ <taskDefinitionArn>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</taskDefinitionArn>
+ </member>
+ </tasks>
+ </StartTaskResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</StartTaskResponse>
+`
+
+var StopTaskResponse = `
+<StopTaskResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <StopTaskResult>
+ <task>
+ <containers>
+ <member>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <name>sleep</name>
+ <containerArn>arn:aws:ecs:us-east-1:aws_account_id:container/UUID</containerArn>
+ <networkBindings/>
+ <lastStatus>RUNNING</lastStatus>
+ </member>
+ </containers>
+ <overrides>
+ <containerOverrides>
+ <member>
+ <name>sleep</name>
+ </member>
+ </containerOverrides>
+ </overrides>
+ <desiredStatus>STOPPED</desiredStatus>
+ <taskArn>arn:aws:ecs:us-east-1:aws_account_id:task/UUID</taskArn>
+ <containerInstanceArn>arn:aws:ecs:us-east-1:aws_account_id:container-instance/UUID</containerInstanceArn>
+ <lastStatus>RUNNING</lastStatus>
+ <taskDefinitionArn>arn:aws:ecs:us-east-1:aws_account_id:task-definition/sleep360:2</taskDefinitionArn>
+ </task>
+ </StopTaskResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</StopTaskResponse>
+`
+
+var SubmitContainerStateChangeResponse = `
+<SubmitContainerStateChangeResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <SubmitContainerStateChangeResult>
+ <acknowledgment>ACK</acknowledgment>
+ </SubmitContainerStateChangeResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</SubmitContainerStateChangeResponse>
+`
+
+var SubmitTaskStateChangeResponse = `
+<SubmitTaskStateChangeResponse xmlns="http://ecs.amazonaws.com/doc/2014-11-13/">
+ <SubmitTaskStateChangeResult>
+ <acknowledgment>ACK</acknowledgment>
+ </SubmitTaskStateChangeResult>
+ <ResponseMetadata>
+ <RequestId>8d798a29-f083-11e1-bdfb-cb223EXAMPLE</RequestId>
+ </ResponseMetadata>
+</SubmitTaskStateChangeResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/elb/elb.go b/vendor/github.com/goamz/goamz/elb/elb.go
new file mode 100644
index 000000000..0127435a7
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/elb.go
@@ -0,0 +1,435 @@
+// This package provides types and functions to interact Elastic Load Balancing service
+package elb
+
+import (
+ "encoding/xml"
+ "fmt"
+ "net/http"
+ "net/url"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+type ELB struct {
+ aws.Auth
+ aws.Region
+}
+
+func New(auth aws.Auth, region aws.Region) *ELB {
+ return &ELB{auth, region}
+}
+
+// The CreateLoadBalancer type encapsulates options for the respective request in AWS.
+// The creation of a Load Balancer may differ inside EC2 and VPC.
+//
+// See http://goo.gl/4QFKi for more details.
+type CreateLoadBalancer struct {
+ Name string
+ AvailabilityZones []string
+ Listeners []Listener
+ Scheme string
+ SecurityGroups []string
+ Subnets []string
+}
+
+// Listener to configure in Load Balancer.
+//
+// See http://goo.gl/NJQCj for more details.
+type Listener struct {
+ InstancePort int
+ InstanceProtocol string
+ LoadBalancerPort int
+ Protocol string
+ SSLCertificateId string
+}
+
+// Response to a CreateLoadBalance request.
+//
+// See http://goo.gl/4QFKi for more details.
+type CreateLoadBalancerResp struct {
+ DNSName string `xml:"CreateLoadBalancerResult>DNSName"`
+}
+
+type SimpleResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// Creates a Load Balancer in Amazon.
+//
+// See http://goo.gl/4QFKi for more details.
+func (elb *ELB) CreateLoadBalancer(options *CreateLoadBalancer) (resp *CreateLoadBalancerResp, err error) {
+ params := makeCreateParams(options)
+ resp = new(CreateLoadBalancerResp)
+ if err := elb.query(params, resp); err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Deletes a Load Balancer.
+//
+// See http://goo.gl/sDmPp for more details.
+func (elb *ELB) DeleteLoadBalancer(name string) (resp *SimpleResp, err error) {
+ params := map[string]string{
+ "Action": "DeleteLoadBalancer",
+ "LoadBalancerName": name,
+ }
+ resp = new(SimpleResp)
+ if err := elb.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+type RegisterInstancesResp struct {
+ InstanceIds []string `xml:"RegisterInstancesWithLoadBalancerResult>Instances>member>InstanceId"`
+}
+
+// Register N instances with a given Load Balancer.
+//
+// See http://goo.gl/x9hru for more details.
+func (elb *ELB) RegisterInstancesWithLoadBalancer(instanceIds []string, lbName string) (resp *RegisterInstancesResp, err error) {
+ // TODO: change params order and use ..., e.g (lbName string, instanceIds ...string)
+ params := map[string]string{
+ "Action": "RegisterInstancesWithLoadBalancer",
+ "LoadBalancerName": lbName,
+ }
+ for i, instanceId := range instanceIds {
+ key := fmt.Sprintf("Instances.member.%d.InstanceId", i+1)
+ params[key] = instanceId
+ }
+ resp = new(RegisterInstancesResp)
+ if err := elb.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Deregister N instances from a given Load Balancer.
+//
+// See http://goo.gl/Hgo4U for more details.
+func (elb *ELB) DeregisterInstancesFromLoadBalancer(instanceIds []string, lbName string) (resp *SimpleResp, err error) {
+ // TODO: change params order and use ..., e.g (lbName string, instanceIds ...string)
+ params := map[string]string{
+ "Action": "DeregisterInstancesFromLoadBalancer",
+ "LoadBalancerName": lbName,
+ }
+ for i, instanceId := range instanceIds {
+ key := fmt.Sprintf("Instances.member.%d.InstanceId", i+1)
+ params[key] = instanceId
+ }
+ resp = new(SimpleResp)
+ if err := elb.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+type DescribeLoadBalancerResp struct {
+ LoadBalancerDescriptions []LoadBalancerDescription `xml:"DescribeLoadBalancersResult>LoadBalancerDescriptions>member"`
+}
+
+type LoadBalancerDescription struct {
+ AvailabilityZones []string `xml:"AvailabilityZones>member"`
+ BackendServerDescriptions []BackendServerDescriptions `xml:"BackendServerDescriptions>member"`
+ CanonicalHostedZoneName string `xml:"CanonicalHostedZoneName"`
+ CanonicalHostedZoneNameId string `xml:"CanonicalHostedZoneNameID"`
+ CreatedTime time.Time `xml:"CreatedTime"`
+ DNSName string `xml:"DNSName"`
+ HealthCheck HealthCheck `xml:"HealthCheck"`
+ Instances []Instance `xml:"Instances>member"`
+ ListenerDescriptions []ListenerDescription `xml:"ListenerDescriptions>member"`
+ LoadBalancerName string `xml:"LoadBalancerName"`
+ Policies Policies `xml:"Policies"`
+ Scheme string `xml:"Scheme"`
+ SecurityGroups []string `xml:"SecurityGroups>member"` //vpc only
+ SourceSecurityGroup SourceSecurityGroup `xml:"SourceSecurityGroup"`
+ Subnets []string `xml:"Subnets>member"`
+ VPCId string `xml:"VPCId"`
+}
+
+// Describe Load Balancers.
+// It can be used to describe all Load Balancers or specific ones.
+//
+// See http://goo.gl/wofJA for more details.
+func (elb *ELB) DescribeLoadBalancers(names ...string) (*DescribeLoadBalancerResp, error) {
+ params := map[string]string{"Action": "DescribeLoadBalancers"}
+ for i, name := range names {
+ index := fmt.Sprintf("LoadBalancerNames.member.%d", i+1)
+ params[index] = name
+ }
+ resp := new(DescribeLoadBalancerResp)
+ if err := elb.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+type BackendServerDescriptions struct {
+ InstancePort int `xml:"InstancePort"`
+ PolicyNames []string `xml:"PolicyNames>member"`
+}
+
+type HealthCheck struct {
+ HealthyThreshold int `xml:"HealthyThreshold"`
+ Interval int `xml:"Interval"`
+ Target string `xml:"Target"`
+ Timeout int `xml:"Timeout"`
+ UnhealthyThreshold int `xml:"UnhealthyThreshold"`
+}
+
+type Instance struct {
+ InstanceId string `xml:"InstanceId"`
+}
+
+type ListenerDescription struct {
+ Listener Listener `xml:"Listener"`
+ PolicyNames []string `xml:"PolicyNames>member"`
+}
+
+type Policies struct {
+ AppCookieStickinessPolicies []AppCookieStickinessPolicies `xml:"AppCookieStickinessPolicies>member"`
+ LBCookieStickinessPolicies []LBCookieStickinessPolicies `xml:"LBCookieStickinessPolicies>member"`
+ OtherPolicies []string `xml:"OtherPolicies>member"`
+}
+
+// see http://goo.gl/clXGV for more information.
+type AppCookieStickinessPolicies struct {
+ CookieName string `xml:"CookieName"`
+ PolicyName string `xml:"PolicyName"`
+}
+
+type LBCookieStickinessPolicies struct {
+ CookieExpirationPeriod int `xml:"CookieExpirationPeriod"`
+ PolicyName string `xml:"PolicyName"`
+}
+
+type SourceSecurityGroup struct {
+ GroupName string `xml:"GroupName"`
+ OwnerAlias string `xml:"OwnerAlias"`
+}
+
+// Represents a XML response for DescribeInstanceHealth action
+//
+// See http://goo.gl/ovIB1 for more information.
+type DescribeInstanceHealthResp struct {
+ InstanceStates []InstanceState `xml:"DescribeInstanceHealthResult>InstanceStates>member"`
+}
+
+// See http://goo.gl/dzWfP for more information.
+type InstanceState struct {
+ Description string `xml:"Description"`
+ InstanceId string `xml:"InstanceId"`
+ ReasonCode string `xml:"ReasonCode"`
+ State string `xml:"State"`
+}
+
+// Describe instance health.
+//
+// See http://goo.gl/ovIB1 for more information.
+func (elb *ELB) DescribeInstanceHealth(lbName string, instanceIds ...string) (*DescribeInstanceHealthResp, error) {
+ params := map[string]string{
+ "Action": "DescribeInstanceHealth",
+ "LoadBalancerName": lbName,
+ }
+ for i, iId := range instanceIds {
+ key := fmt.Sprintf("Instances.member.%d.InstanceId", i+1)
+ params[key] = iId
+ }
+ resp := new(DescribeInstanceHealthResp)
+ if err := elb.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+type HealthCheckResp struct {
+ HealthCheck *HealthCheck `xml:"ConfigureHealthCheckResult>HealthCheck"`
+}
+
+// Configure health check for a LB
+//
+// See http://goo.gl/2HE6a for more information
+func (elb *ELB) ConfigureHealthCheck(lbName string, healthCheck *HealthCheck) (*HealthCheckResp, error) {
+ params := map[string]string{
+ "Action": "ConfigureHealthCheck",
+ "LoadBalancerName": lbName,
+ "HealthCheck.HealthyThreshold": strconv.Itoa(healthCheck.HealthyThreshold),
+ "HealthCheck.Interval": strconv.Itoa(healthCheck.Interval),
+ "HealthCheck.Target": healthCheck.Target,
+ "HealthCheck.Timeout": strconv.Itoa(healthCheck.Timeout),
+ "HealthCheck.UnhealthyThreshold": strconv.Itoa(healthCheck.UnhealthyThreshold),
+ }
+ resp := new(HealthCheckResp)
+ if err := elb.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Add tags to the named ELB
+//
+// Note that AWS only accepts one ELB name at a time (even though it is sent as a list)
+//
+// See http://goo.gl/6JW4Wf for the rest of the details
+func (elb *ELB) AddTags(elbName string, tags map[string]string) (*SimpleResp, error) {
+ var sortedKeys []string
+ params := make(map[string]string)
+ response := &SimpleResp{}
+
+ for tagKey := range tags {
+ sortedKeys = append(sortedKeys, tagKey)
+ }
+
+ sort.Strings(sortedKeys)
+
+ for _, key := range sortedKeys {
+ number := len(tags)
+ params[fmt.Sprintf("Tags.member.%d.Key", number)] = key
+ params[fmt.Sprintf("Tags.member.%d.Value", number)] = tags[key]
+ delete(tags, key)
+ }
+
+ params["Action"] = "AddTags"
+ params["LoadBalancerNames.member.1"] = elbName
+
+ if err := elb.query(params, response); err != nil {
+ return nil, err
+ }
+
+ return response, nil
+}
+
+// Remove tags from the named ELB
+//
+// Note that AWS only accepts one ELB name at a time (even though it is sent as a list)
+//
+// see http://goo.gl/ochFqo for more details
+
+func (elb *ELB) RemoveTags(elbName string, tagKeys []string) (*SimpleResp, error) {
+ response := &SimpleResp{}
+ params := make(map[string]string)
+
+ params["Action"] = "RemoveTags"
+ params["LoadBalancerNames.member.1"] = elbName
+
+ for i, tagKey := range tagKeys {
+ params[fmt.Sprintf("Tags.member.%d.Key", i+1)] = tagKey
+ }
+
+ if err := elb.query(params, response); err != nil {
+ return nil, err
+ }
+
+ return response, nil
+}
+
+func (elb *ELB) query(params map[string]string, resp interface{}) error {
+ params["Version"] = "2012-06-01"
+ params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
+ data := strings.NewReader(multimap(params).Encode())
+ hreq, err := http.NewRequest("GET", elb.Region.ELBEndpoint+"/", data)
+ if err != nil {
+ return err
+ }
+
+ hreq.URL.RawQuery = multimap(params).Encode()
+ token := elb.Auth.Token()
+ if token != "" {
+ hreq.Header.Set("X-Amz-Security-Token", token)
+ }
+
+ signer := aws.NewV4Signer(elb.Auth, "elasticloadbalancing", elb.Region)
+ signer.Sign(hreq)
+
+ r, err := http.DefaultClient.Do(hreq)
+
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ return xml.NewDecoder(r.Body).Decode(resp)
+}
+
+// Error encapsulates an error returned by ELB.
+type Error struct {
+ // HTTP status code
+ StatusCode int
+ // AWS error code
+ Code string
+ // The human-oriented error message
+ Message string
+}
+
+func (err *Error) Error() string {
+ if err.Code == "" {
+ return err.Message
+ }
+
+ return fmt.Sprintf("%s (%s)", err.Message, err.Code)
+}
+
+type xmlErrors struct {
+ Errors []Error `xml:"Error"`
+}
+
+func buildError(r *http.Response) error {
+ var (
+ err Error
+ errors xmlErrors
+ )
+ xml.NewDecoder(r.Body).Decode(&errors)
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+func makeCreateParams(createLB *CreateLoadBalancer) map[string]string {
+ params := make(map[string]string)
+ params["LoadBalancerName"] = createLB.Name
+ params["Action"] = "CreateLoadBalancer"
+ if createLB.Scheme != "" {
+ params["Scheme"] = createLB.Scheme
+ }
+ for i, s := range createLB.SecurityGroups {
+ key := fmt.Sprintf("SecurityGroups.member.%d", i+1)
+ params[key] = s
+ }
+ for i, s := range createLB.Subnets {
+ key := fmt.Sprintf("Subnets.member.%d", i+1)
+ params[key] = s
+ }
+ for i, l := range createLB.Listeners {
+ key := "Listeners.member.%d.%s"
+ index := i + 1
+ params[fmt.Sprintf(key, index, "InstancePort")] = strconv.Itoa(l.InstancePort)
+ params[fmt.Sprintf(key, index, "InstanceProtocol")] = l.InstanceProtocol
+ params[fmt.Sprintf(key, index, "Protocol")] = l.Protocol
+ params[fmt.Sprintf(key, index, "LoadBalancerPort")] = strconv.Itoa(l.LoadBalancerPort)
+ }
+ for i, az := range createLB.AvailabilityZones {
+ key := fmt.Sprintf("AvailabilityZones.member.%d", i+1)
+ params[key] = az
+ }
+ return params
+}
diff --git a/vendor/github.com/goamz/goamz/elb/elb_test.go b/vendor/github.com/goamz/goamz/elb/elb_test.go
new file mode 100644
index 000000000..db799fdfc
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/elb_test.go
@@ -0,0 +1,369 @@
+package elb_test
+
+import (
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/elb"
+ . "gopkg.in/check.v1"
+)
+
+type S struct {
+ HTTPSuite
+ elb *elb.ELB
+}
+
+var _ = Suite(&S{})
+
+func (s *S) SetUpSuite(c *C) {
+ s.HTTPSuite.SetUpSuite(c)
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.elb = elb.New(auth, aws.Region{ELBEndpoint: testServer.URL})
+}
+
+func (s *S) TestCreateLoadBalancer(c *C) {
+ testServer.PrepareResponse(200, nil, CreateLoadBalancer)
+ createLB := &elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a", "us-east-1b"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ Protocol: "http",
+ LoadBalancerPort: 80,
+ },
+ },
+ }
+ resp, err := s.elb.CreateLoadBalancer(createLB)
+ c.Assert(err, IsNil)
+ defer s.elb.DeleteLoadBalancer(createLB.Name)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Action"), Equals, "CreateLoadBalancer")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("LoadBalancerName"), Equals, "testlb")
+ c.Assert(values.Get("AvailabilityZones.member.1"), Equals, "us-east-1a")
+ c.Assert(values.Get("AvailabilityZones.member.2"), Equals, "us-east-1b")
+ c.Assert(values.Get("Listeners.member.1.InstancePort"), Equals, "80")
+ c.Assert(values.Get("Listeners.member.1.InstanceProtocol"), Equals, "http")
+ c.Assert(values.Get("Listeners.member.1.Protocol"), Equals, "http")
+ c.Assert(values.Get("Listeners.member.1.LoadBalancerPort"), Equals, "80")
+ c.Assert(resp.DNSName, Equals, "testlb-339187009.us-east-1.elb.amazonaws.com")
+}
+
+func (s *S) TestCreateLoadBalancerWithSubnetsAndMoreListeners(c *C) {
+ testServer.PrepareResponse(200, nil, CreateLoadBalancer)
+ createLB := &elb.CreateLoadBalancer{
+ Name: "testlb",
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ Protocol: "http",
+ LoadBalancerPort: 80,
+ },
+ {
+ InstancePort: 8080,
+ InstanceProtocol: "http",
+ Protocol: "http",
+ LoadBalancerPort: 8080,
+ },
+ },
+ Subnets: []string{"subnetid-1", "subnetid-2"},
+ SecurityGroups: []string{"sg-1", "sg-2"},
+ }
+ _, err := s.elb.CreateLoadBalancer(createLB)
+ c.Assert(err, IsNil)
+ defer s.elb.DeleteLoadBalancer(createLB.Name)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Listeners.member.1.InstancePort"), Equals, "80")
+ c.Assert(values.Get("Listeners.member.1.LoadBalancerPort"), Equals, "80")
+ c.Assert(values.Get("Listeners.member.2.InstancePort"), Equals, "8080")
+ c.Assert(values.Get("Listeners.member.2.LoadBalancerPort"), Equals, "8080")
+ c.Assert(values.Get("Subnets.member.1"), Equals, "subnetid-1")
+ c.Assert(values.Get("Subnets.member.2"), Equals, "subnetid-2")
+ c.Assert(values.Get("SecurityGroups.member.1"), Equals, "sg-1")
+ c.Assert(values.Get("SecurityGroups.member.2"), Equals, "sg-2")
+}
+
+func (s *S) TestCreateLoadBalancerWithWrongParamsCombination(c *C) {
+ testServer.PrepareResponse(400, nil, CreateLoadBalancerBadRequest)
+ createLB := &elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a", "us-east-1b"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ Protocol: "http",
+ LoadBalancerPort: 80,
+ },
+ },
+ Subnets: []string{"subnetid-1", "subnetid2"},
+ }
+ resp, err := s.elb.CreateLoadBalancer(createLB)
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ e, ok := err.(*elb.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(e.Message, Equals, "Only one of SubnetIds or AvailabilityZones may be specified")
+ c.Assert(e.Code, Equals, "ValidationError")
+}
+
+func (s *S) TestDeleteLoadBalancer(c *C) {
+ testServer.PrepareResponse(200, nil, DeleteLoadBalancer)
+ resp, err := s.elb.DeleteLoadBalancer("testlb")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("Action"), Equals, "DeleteLoadBalancer")
+ c.Assert(values.Get("LoadBalancerName"), Equals, "testlb")
+ c.Assert(resp.RequestId, Equals, "8d7223db-49d7-11e2-bba9-35ba56032fe1")
+}
+
+func (s *S) TestRegisterInstancesWithLoadBalancer(c *C) {
+ testServer.PrepareResponse(200, nil, RegisterInstancesWithLoadBalancer)
+ resp, err := s.elb.RegisterInstancesWithLoadBalancer([]string{"i-b44db8ca", "i-461ecf38"}, "testlb")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("Action"), Equals, "RegisterInstancesWithLoadBalancer")
+ c.Assert(values.Get("LoadBalancerName"), Equals, "testlb")
+ c.Assert(values.Get("Instances.member.1.InstanceId"), Equals, "i-b44db8ca")
+ c.Assert(values.Get("Instances.member.2.InstanceId"), Equals, "i-461ecf38")
+ c.Assert(resp.InstanceIds, DeepEquals, []string{"i-b44db8ca", "i-461ecf38"})
+}
+
+func (s *S) TestRegisterInstancesWithLoadBalancerBadRequest(c *C) {
+ testServer.PrepareResponse(400, nil, RegisterInstancesWithLoadBalancerBadRequest)
+ resp, err := s.elb.RegisterInstancesWithLoadBalancer([]string{"i-b44db8ca", "i-461ecf38"}, "absentLB")
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ e, ok := err.(*elb.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(e.Message, Equals, "There is no ACTIVE Load Balancer named 'absentLB'")
+ c.Assert(e.Code, Equals, "LoadBalancerNotFound")
+}
+
+func (s *S) TestDeregisterInstancesFromLoadBalancer(c *C) {
+ testServer.PrepareResponse(200, nil, DeregisterInstancesFromLoadBalancer)
+ resp, err := s.elb.DeregisterInstancesFromLoadBalancer([]string{"i-b44db8ca", "i-461ecf38"}, "testlb")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("Action"), Equals, "DeregisterInstancesFromLoadBalancer")
+ c.Assert(values.Get("LoadBalancerName"), Equals, "testlb")
+ c.Assert(values.Get("Instances.member.1.InstanceId"), Equals, "i-b44db8ca")
+ c.Assert(values.Get("Instances.member.2.InstanceId"), Equals, "i-461ecf38")
+ c.Assert(resp.RequestId, Equals, "d6490837-49fd-11e2-bba9-35ba56032fe1")
+}
+
+func (s *S) TestDeregisterInstancesFromLoadBalancerBadRequest(c *C) {
+ testServer.PrepareResponse(400, nil, DeregisterInstancesFromLoadBalancerBadRequest)
+ resp, err := s.elb.DeregisterInstancesFromLoadBalancer([]string{"i-b44db8ca", "i-461ecf38"}, "testlb")
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ e, ok := err.(*elb.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(e.Message, Equals, "There is no ACTIVE Load Balancer named 'absentlb'")
+ c.Assert(e.Code, Equals, "LoadBalancerNotFound")
+}
+
+func (s *S) TestDescribeLoadBalancers(c *C) {
+ testServer.PrepareResponse(200, nil, DescribeLoadBalancers)
+ resp, err := s.elb.DescribeLoadBalancers()
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("Action"), Equals, "DescribeLoadBalancers")
+ t, _ := time.Parse(time.RFC3339, "2012-12-27T11:51:52.970Z")
+ expected := &elb.DescribeLoadBalancerResp{
+ []elb.LoadBalancerDescription{
+ {
+ AvailabilityZones: []string{"us-east-1a"},
+ BackendServerDescriptions: []elb.BackendServerDescriptions(nil),
+ CanonicalHostedZoneName: "testlb-2087227216.us-east-1.elb.amazonaws.com",
+ CanonicalHostedZoneNameId: "Z3DZXE0Q79N41H",
+ CreatedTime: t,
+ DNSName: "testlb-2087227216.us-east-1.elb.amazonaws.com",
+ HealthCheck: elb.HealthCheck{
+ HealthyThreshold: 10,
+ Interval: 30,
+ Target: "TCP:80",
+ Timeout: 5,
+ UnhealthyThreshold: 2,
+ },
+ Instances: []elb.Instance(nil),
+ ListenerDescriptions: []elb.ListenerDescription{
+ {
+ Listener: elb.Listener{
+ Protocol: "HTTP",
+ LoadBalancerPort: 80,
+ InstanceProtocol: "HTTP",
+ InstancePort: 80,
+ },
+ },
+ },
+ LoadBalancerName: "testlb",
+ //Policies: elb.Policies(nil),
+ Scheme: "internet-facing",
+ SecurityGroups: []string(nil),
+ SourceSecurityGroup: elb.SourceSecurityGroup{
+ GroupName: "amazon-elb-sg",
+ OwnerAlias: "amazon-elb",
+ },
+ Subnets: []string(nil),
+ },
+ },
+ }
+ c.Assert(resp, DeepEquals, expected)
+}
+
+func (s *S) TestDescribeLoadBalancersByName(c *C) {
+ testServer.PrepareResponse(200, nil, DescribeLoadBalancers)
+ s.elb.DescribeLoadBalancers("somelb")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("Action"), Equals, "DescribeLoadBalancers")
+ c.Assert(values.Get("LoadBalancerNames.member.1"), Equals, "somelb")
+}
+
+func (s *S) TestDescribeLoadBalancersBadRequest(c *C) {
+ testServer.PrepareResponse(400, nil, DescribeLoadBalancersBadRequest)
+ resp, err := s.elb.DescribeLoadBalancers()
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, `^Cannot find Load Balancer absentlb \(LoadBalancerNotFound\)$`)
+}
+
+func (s *S) TestDescribeInstanceHealth(c *C) {
+ testServer.PrepareResponse(200, nil, DescribeInstanceHealth)
+ resp, err := s.elb.DescribeInstanceHealth("testlb", "i-b44db8ca")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("Action"), Equals, "DescribeInstanceHealth")
+ c.Assert(values.Get("LoadBalancerName"), Equals, "testlb")
+ c.Assert(values.Get("Instances.member.1.InstanceId"), Equals, "i-b44db8ca")
+ c.Assert(len(resp.InstanceStates) > 0, Equals, true)
+ c.Assert(resp.InstanceStates[0].Description, Equals, "Instance registration is still in progress.")
+ c.Assert(resp.InstanceStates[0].InstanceId, Equals, "i-b44db8ca")
+ c.Assert(resp.InstanceStates[0].State, Equals, "OutOfService")
+ c.Assert(resp.InstanceStates[0].ReasonCode, Equals, "ELB")
+}
+
+func (s *S) TestDescribeInstanceHealthBadRequest(c *C) {
+ testServer.PrepareResponse(400, nil, DescribeInstanceHealthBadRequest)
+ resp, err := s.elb.DescribeInstanceHealth("testlb", "i-foooo")
+ c.Assert(err, NotNil)
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, ".*i-foooo.*(InvalidInstance).*")
+}
+
+func (s *S) TestConfigureHealthCheck(c *C) {
+ testServer.PrepareResponse(200, nil, ConfigureHealthCheck)
+ hc := elb.HealthCheck{
+ HealthyThreshold: 10,
+ Interval: 30,
+ Target: "HTTP:80/",
+ Timeout: 5,
+ UnhealthyThreshold: 2,
+ }
+ resp, err := s.elb.ConfigureHealthCheck("testlb", &hc)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("Action"), Equals, "ConfigureHealthCheck")
+ c.Assert(values.Get("LoadBalancerName"), Equals, "testlb")
+ c.Assert(values.Get("HealthCheck.HealthyThreshold"), Equals, "10")
+ c.Assert(values.Get("HealthCheck.Interval"), Equals, "30")
+ c.Assert(values.Get("HealthCheck.Target"), Equals, "HTTP:80/")
+ c.Assert(values.Get("HealthCheck.Timeout"), Equals, "5")
+ c.Assert(values.Get("HealthCheck.UnhealthyThreshold"), Equals, "2")
+ c.Assert(resp.HealthCheck.HealthyThreshold, Equals, 10)
+ c.Assert(resp.HealthCheck.Interval, Equals, 30)
+ c.Assert(resp.HealthCheck.Target, Equals, "HTTP:80/")
+ c.Assert(resp.HealthCheck.Timeout, Equals, 5)
+ c.Assert(resp.HealthCheck.UnhealthyThreshold, Equals, 2)
+}
+
+func (s *S) TestConfigureHealthCheckBadRequest(c *C) {
+ testServer.PrepareResponse(400, nil, ConfigureHealthCheckBadRequest)
+ hc := elb.HealthCheck{
+ HealthyThreshold: 10,
+ Interval: 30,
+ Target: "HTTP:80/",
+ Timeout: 5,
+ UnhealthyThreshold: 2,
+ }
+ resp, err := s.elb.ConfigureHealthCheck("foolb", &hc)
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, ".*foolb.*(LoadBalancerNotFound).*")
+}
+
+func (s *S) TestAddTags(c *C) {
+ testServer.PrepareResponse(200, nil, AddTagsSuccessResponse)
+ tagsToAdd := map[string]string{
+ "my-key": "my-value",
+ "my-super-silly-tag": "its-another-valid-value",
+ }
+
+ resp, err := s.elb.AddTags("my-elb", tagsToAdd)
+ c.Assert(err, IsNil)
+
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Action"), Equals, "AddTags")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("LoadBalancerNames.member.1"), Equals, "my-elb")
+ c.Assert(values.Get("Tags.member.1.Key"), Equals, "my-super-silly-tag")
+ c.Assert(values.Get("Tags.member.1.Value"), Equals, "its-another-valid-value")
+ c.Assert(values.Get("Tags.member.2.Key"), Equals, "my-key")
+ c.Assert(values.Get("Tags.member.2.Value"), Equals, "my-value")
+
+ c.Assert(resp.RequestId, Equals, "360e81f7-1100-11e4-b6ed-0f30SOME-SAUCY-EXAMPLE")
+}
+
+func (s *S) TestAddBadTags(c *C) {
+ testServer.PrepareResponse(400, nil, TagsBadRequest)
+ tagsToAdd := map[string]string{
+ "my-first-key": "an invalid value",
+ }
+
+ resp, err := s.elb.AddTags("my-bad-elb", tagsToAdd)
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, ".*(InvalidParameterValue).*")
+}
+
+func (s *S) TestRemoveTags(c *C) {
+ testServer.PrepareResponse(200, nil, RemoveTagsSuccessResponse)
+ tagKeysToRemove := []string{"a-key-one", "a-key-two"}
+
+ resp, err := s.elb.RemoveTags("my-test-elb-1", tagKeysToRemove)
+ c.Assert(err, IsNil)
+
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Version"), Equals, "2012-06-01")
+ c.Assert(values.Get("Action"), Equals, "RemoveTags")
+ c.Assert(values.Get("Timestamp"), Not(Equals), "")
+ c.Assert(values.Get("LoadBalancerNames.member.1"), Equals, "my-test-elb-1")
+ c.Assert([]string{values.Get("Tags.member.1.Key"), values.Get("Tags.member.2.Key")}, DeepEquals, tagKeysToRemove)
+ c.Assert(resp.RequestId, Equals, "83c88b9d-12b7-11e3-8b82-87b12DIFFEXAMPLE")
+}
+
+func (s *S) TestRemoveTagsFailure(c *C) {
+ testServer.PrepareResponse(400, nil, TagsBadRequest)
+
+ resp, err := s.elb.RemoveTags("my-test-elb", []string{"non-existant-tag"})
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, ".*(InvalidParameterValue).*")
+}
diff --git a/vendor/github.com/goamz/goamz/elb/elbi_test.go b/vendor/github.com/goamz/goamz/elb/elbi_test.go
new file mode 100644
index 000000000..4c21f9e38
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/elbi_test.go
@@ -0,0 +1,308 @@
+package elb_test
+
+import (
+ "flag"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/ec2"
+ "github.com/goamz/goamz/elb"
+ . "gopkg.in/check.v1"
+)
+
+var amazon = flag.Bool("amazon", false, "Enable tests against amazon server")
+
+// AmazonServer represents an Amazon AWS server.
+type AmazonServer struct {
+ auth aws.Auth
+}
+
+func (s *AmazonServer) SetUp(c *C) {
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ c.Fatal(err)
+ }
+ s.auth = auth
+}
+
+var _ = Suite(&AmazonClientSuite{})
+
+// AmazonClientSuite tests the client against a live AWS server.
+type AmazonClientSuite struct {
+ srv AmazonServer
+ ClientTests
+}
+
+// ClientTests defines integration tests designed to test the client.
+// It is not used as a test suite in itself, but embedded within
+// another type.
+type ClientTests struct {
+ elb *elb.ELB
+ ec2 *ec2.EC2
+}
+
+func (s *AmazonClientSuite) SetUpSuite(c *C) {
+ if !*amazon {
+ c.Skip("AmazonClientSuite tests not enabled")
+ }
+ s.srv.SetUp(c)
+ s.elb = elb.New(s.srv.auth, aws.USEast)
+ s.ec2 = ec2.New(s.srv.auth, aws.USEast)
+}
+
+func (s *ClientTests) TestCreateAndDeleteLoadBalancer(c *C) {
+ createLBReq := elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ }
+ resp, err := s.elb.CreateLoadBalancer(&createLBReq)
+ c.Assert(err, IsNil)
+ defer s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Assert(resp.DNSName, Not(Equals), "")
+ deleteResp, err := s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Assert(err, IsNil)
+ c.Assert(deleteResp.RequestId, Not(Equals), "")
+}
+
+func (s *ClientTests) TestCreateLoadBalancerError(c *C) {
+ createLBReq := elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a"},
+ Subnets: []string{"subnetid-1"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ }
+ resp, err := s.elb.CreateLoadBalancer(&createLBReq)
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ e, ok := err.(*elb.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(e.Message, Matches, "Only one of .* or .* may be specified")
+ c.Assert(e.Code, Equals, "ValidationError")
+}
+
+func (s *ClientTests) createInstanceAndLB(c *C) (*elb.CreateLoadBalancer, string) {
+ options := ec2.RunInstancesOptions{
+ ImageId: "ami-ccf405a5",
+ InstanceType: "t1.micro",
+ AvailabilityZone: "us-east-1c",
+ }
+ resp1, err := s.ec2.RunInstances(&options)
+ c.Assert(err, IsNil)
+ instId := resp1.Instances[0].InstanceId
+ createLBReq := elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1c"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ }
+ _, err = s.elb.CreateLoadBalancer(&createLBReq)
+ c.Assert(err, IsNil)
+ return &createLBReq, instId
+}
+
+// Cost: 0.02 USD
+func (s *ClientTests) TestCreateRegisterAndDeregisterInstanceWithLoadBalancer(c *C) {
+ createLBReq, instId := s.createInstanceAndLB(c)
+ defer func() {
+ _, err := s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Check(err, IsNil)
+ _, err = s.ec2.TerminateInstances([]string{instId})
+ c.Check(err, IsNil)
+ }()
+ resp, err := s.elb.RegisterInstancesWithLoadBalancer([]string{instId}, createLBReq.Name)
+ c.Assert(err, IsNil)
+ c.Assert(resp.InstanceIds, DeepEquals, []string{instId})
+ resp2, err := s.elb.DeregisterInstancesFromLoadBalancer([]string{instId}, createLBReq.Name)
+ c.Assert(err, IsNil)
+ c.Assert(resp2, Not(Equals), "")
+}
+
+func (s *ClientTests) TestDescribeLoadBalancers(c *C) {
+ createLBReq := elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ }
+ _, err := s.elb.CreateLoadBalancer(&createLBReq)
+ c.Assert(err, IsNil)
+ defer func() {
+ _, err := s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Check(err, IsNil)
+ }()
+ resp, err := s.elb.DescribeLoadBalancers()
+ c.Assert(err, IsNil)
+ c.Assert(len(resp.LoadBalancerDescriptions) > 0, Equals, true)
+ c.Assert(resp.LoadBalancerDescriptions[0].AvailabilityZones, DeepEquals, []string{"us-east-1a"})
+ c.Assert(resp.LoadBalancerDescriptions[0].LoadBalancerName, Equals, "testlb")
+ c.Assert(resp.LoadBalancerDescriptions[0].Scheme, Equals, "internet-facing")
+ hc := elb.HealthCheck{
+ HealthyThreshold: 10,
+ Interval: 30,
+ Target: "TCP:80",
+ Timeout: 5,
+ UnhealthyThreshold: 2,
+ }
+ c.Assert(resp.LoadBalancerDescriptions[0].HealthCheck, DeepEquals, hc)
+ ld := []elb.ListenerDescription{
+ {
+ Listener: elb.Listener{
+ Protocol: "HTTP",
+ LoadBalancerPort: 80,
+ InstanceProtocol: "HTTP",
+ InstancePort: 80,
+ },
+ },
+ }
+ c.Assert(resp.LoadBalancerDescriptions[0].ListenerDescriptions, DeepEquals, ld)
+ ssg := elb.SourceSecurityGroup{
+ GroupName: "amazon-elb-sg",
+ OwnerAlias: "amazon-elb",
+ }
+ c.Assert(resp.LoadBalancerDescriptions[0].SourceSecurityGroup, DeepEquals, ssg)
+}
+
+func (s *ClientTests) TestDescribeLoadBalancersBadRequest(c *C) {
+ resp, err := s.elb.DescribeLoadBalancers("absentlb")
+ c.Assert(err, NotNil)
+ c.Assert(resp, IsNil)
+ c.Assert(err, ErrorMatches, ".*(LoadBalancerNotFound).*")
+}
+
+func (s *ClientTests) TestDescribeInstanceHealth(c *C) {
+ createLBReq, instId := s.createInstanceAndLB(c)
+ defer func() {
+ _, err := s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Check(err, IsNil)
+ _, err = s.ec2.TerminateInstances([]string{instId})
+ c.Check(err, IsNil)
+ }()
+ _, err := s.elb.RegisterInstancesWithLoadBalancer([]string{instId}, createLBReq.Name)
+ c.Assert(err, IsNil)
+ resp, err := s.elb.DescribeInstanceHealth(createLBReq.Name, instId)
+ c.Assert(err, IsNil)
+ c.Assert(len(resp.InstanceStates) > 0, Equals, true)
+ c.Assert(resp.InstanceStates[0].Description, Equals, "Instance is in pending state.")
+ c.Assert(resp.InstanceStates[0].InstanceId, Equals, instId)
+ c.Assert(resp.InstanceStates[0].State, Equals, "OutOfService")
+ c.Assert(resp.InstanceStates[0].ReasonCode, Equals, "Instance")
+}
+
+func (s *ClientTests) TestDescribeInstanceHealthBadRequest(c *C) {
+ createLBReq := elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ }
+ _, err := s.elb.CreateLoadBalancer(&createLBReq)
+ c.Assert(err, IsNil)
+ defer func() {
+ _, err := s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Check(err, IsNil)
+ }()
+ resp, err := s.elb.DescribeInstanceHealth(createLBReq.Name, "i-foo")
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, ".*i-foo.*(InvalidInstance).*")
+}
+
+func (s *ClientTests) TestConfigureHealthCheck(c *C) {
+ createLBReq := elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ }
+ _, err := s.elb.CreateLoadBalancer(&createLBReq)
+ c.Assert(err, IsNil)
+ defer func() {
+ _, err := s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Check(err, IsNil)
+ }()
+ hc := elb.HealthCheck{
+ HealthyThreshold: 10,
+ Interval: 30,
+ Target: "HTTP:80/",
+ Timeout: 5,
+ UnhealthyThreshold: 2,
+ }
+ resp, err := s.elb.ConfigureHealthCheck(createLBReq.Name, &hc)
+ c.Assert(err, IsNil)
+ c.Assert(resp.HealthCheck.HealthyThreshold, Equals, 10)
+ c.Assert(resp.HealthCheck.Interval, Equals, 30)
+ c.Assert(resp.HealthCheck.Target, Equals, "HTTP:80/")
+ c.Assert(resp.HealthCheck.Timeout, Equals, 5)
+ c.Assert(resp.HealthCheck.UnhealthyThreshold, Equals, 2)
+}
+
+func (s *ClientTests) TestConfigureHealthCheckBadRequest(c *C) {
+ createLBReq := elb.CreateLoadBalancer{
+ Name: "testlb",
+ AvailabilityZones: []string{"us-east-1a"},
+ Listeners: []elb.Listener{
+ {
+ InstancePort: 80,
+ InstanceProtocol: "http",
+ LoadBalancerPort: 80,
+ Protocol: "http",
+ },
+ },
+ }
+ _, err := s.elb.CreateLoadBalancer(&createLBReq)
+ c.Assert(err, IsNil)
+ defer func() {
+ _, err := s.elb.DeleteLoadBalancer(createLBReq.Name)
+ c.Check(err, IsNil)
+ }()
+ hc := elb.HealthCheck{
+ HealthyThreshold: 10,
+ Interval: 30,
+ Target: "HTTP:80",
+ Timeout: 5,
+ UnhealthyThreshold: 2,
+ }
+ resp, err := s.elb.ConfigureHealthCheck(createLBReq.Name, &hc)
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ expected := "HealthCheck HTTP Target must specify a port followed by a path that begins with a slash. e.g. HTTP:80/ping/this/path (ValidationError)"
+ c.Assert(err.Error(), Equals, expected)
+}
diff --git a/vendor/github.com/goamz/goamz/elb/elbt_test.go b/vendor/github.com/goamz/goamz/elb/elbt_test.go
new file mode 100644
index 000000000..2ea529452
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/elbt_test.go
@@ -0,0 +1,243 @@
+package elb_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/elb"
+ "github.com/goamz/goamz/elb/elbtest"
+ . "gopkg.in/check.v1"
+)
+
+// LocalServer represents a local elbtest fake server.
+type LocalServer struct {
+ auth aws.Auth
+ region aws.Region
+ srv *elbtest.Server
+}
+
+func (s *LocalServer) SetUp(c *C) {
+ srv, err := elbtest.NewServer()
+ c.Assert(err, IsNil)
+ c.Assert(srv, NotNil)
+ s.srv = srv
+ s.region = aws.Region{ELBEndpoint: srv.URL()}
+}
+
+// LocalServerSuite defines tests that will run
+// against the local elbtest server. It includes
+// selected tests from ClientTests;
+// when the elbtest functionality is sufficient, it should
+// include all of them, and ClientTests can be simply embedded.
+type LocalServerSuite struct {
+ srv LocalServer
+ ServerTests
+ clientTests ClientTests
+}
+
+// ServerTests defines a set of tests designed to test
+// the elbtest local fake elb server.
+// It is not used as a test suite in itself, but embedded within
+// another type.
+type ServerTests struct {
+ elb *elb.ELB
+}
+
+// AmazonServerSuite runs the elbtest server tests against a live ELB server.
+// It will only be activated if the -all flag is specified.
+type AmazonServerSuite struct {
+ srv AmazonServer
+ ServerTests
+}
+
+var _ = Suite(&AmazonServerSuite{})
+
+func (s *AmazonServerSuite) SetUpSuite(c *C) {
+ if !*amazon {
+ c.Skip("AmazonServerSuite tests not enabled")
+ }
+ s.srv.SetUp(c)
+ s.ServerTests.elb = elb.New(s.srv.auth, aws.USEast)
+}
+
+var _ = Suite(&LocalServerSuite{})
+
+func (s *LocalServerSuite) SetUpSuite(c *C) {
+ s.srv.SetUp(c)
+ s.ServerTests.elb = elb.New(s.srv.auth, s.srv.region)
+ s.clientTests.elb = elb.New(s.srv.auth, s.srv.region)
+}
+
+func (s *LocalServerSuite) TestCreateLoadBalancer(c *C) {
+ s.clientTests.TestCreateAndDeleteLoadBalancer(c)
+}
+
+func (s *LocalServerSuite) TestCreateLoadBalancerError(c *C) {
+ s.clientTests.TestCreateLoadBalancerError(c)
+}
+
+func (s *LocalServerSuite) TestDescribeLoadBalancer(c *C) {
+ s.clientTests.TestDescribeLoadBalancers(c)
+}
+
+func (s *LocalServerSuite) TestDescribeLoadBalancerListsAddedByNewLoadbalancerFunc(c *C) {
+ srv := s.srv.srv
+ srv.NewLoadBalancer("wierdlb")
+ defer srv.RemoveLoadBalancer("wierdlb")
+ resp, err := s.clientTests.elb.DescribeLoadBalancers()
+ c.Assert(err, IsNil)
+ isPresent := false
+ for _, desc := range resp.LoadBalancerDescriptions {
+ if desc.LoadBalancerName == "wierdlb" {
+ isPresent = true
+ }
+ }
+ c.Assert(isPresent, Equals, true)
+}
+
+func (s *LocalServerSuite) TestDescribeLoadBalancerListsInstancesAddedByRegisterInstancesFunc(c *C) {
+ srv := s.srv.srv
+ lbName := "somelb"
+ srv.NewLoadBalancer(lbName)
+ defer srv.RemoveLoadBalancer(lbName)
+ instId := srv.NewInstance()
+ defer srv.RemoveInstance(instId)
+ srv.RegisterInstance(instId, lbName) // no need to deregister, since we're removing the lb
+ resp, err := s.clientTests.elb.DescribeLoadBalancers()
+ c.Assert(err, IsNil)
+ c.Assert(len(resp.LoadBalancerDescriptions) > 0, Equals, true)
+ c.Assert(len(resp.LoadBalancerDescriptions[0].Instances) > 0, Equals, true)
+ c.Assert(resp.LoadBalancerDescriptions[0].Instances, DeepEquals, []elb.Instance{{InstanceId: instId}})
+ srv.DeregisterInstance(instId, lbName)
+ resp, err = s.clientTests.elb.DescribeLoadBalancers()
+ c.Assert(err, IsNil)
+ c.Assert(resp.LoadBalancerDescriptions[0].Instances, DeepEquals, []elb.Instance(nil))
+}
+
+func (s *LocalServerSuite) TestDescribeLoadBalancersBadRequest(c *C) {
+ s.clientTests.TestDescribeLoadBalancersBadRequest(c)
+}
+
+func (s *LocalServerSuite) TestRegisterInstanceWithLoadBalancer(c *C) {
+ srv := s.srv.srv
+ instId := srv.NewInstance()
+ defer srv.RemoveInstance(instId)
+ srv.NewLoadBalancer("testlb")
+ defer srv.RemoveLoadBalancer("testlb")
+ resp, err := s.clientTests.elb.RegisterInstancesWithLoadBalancer([]string{instId}, "testlb")
+ c.Assert(err, IsNil)
+ c.Assert(resp.InstanceIds, DeepEquals, []string{instId})
+}
+
+func (s *LocalServerSuite) TestRegisterInstanceWithLoadBalancerWithAbsentInstance(c *C) {
+ srv := s.srv.srv
+ srv.NewLoadBalancer("testlb")
+ defer srv.RemoveLoadBalancer("testlb")
+ resp, err := s.clientTests.elb.RegisterInstancesWithLoadBalancer([]string{"i-212"}, "testlb")
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, `^InvalidInstance found in \[i-212\]. Invalid id: "i-212" \(InvalidInstance\)$`)
+ c.Assert(resp, IsNil)
+}
+
+func (s *LocalServerSuite) TestRegisterInstanceWithLoadBalancerWithAbsentLoadBalancer(c *C) {
+ // the verification if the lb exists is done before the instances, so there is no need to create
+ // fixture instances for this test, it'll never get that far
+ resp, err := s.clientTests.elb.RegisterInstancesWithLoadBalancer([]string{"i-212"}, "absentlb")
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, `^There is no ACTIVE Load Balancer named 'absentlb' \(LoadBalancerNotFound\)$`)
+ c.Assert(resp, IsNil)
+}
+
+func (s *LocalServerSuite) TestDeregisterInstanceWithLoadBalancer(c *C) {
+ // there is no need to register the instance first, amazon returns the same response
+ // in both cases (instance registered or not)
+ srv := s.srv.srv
+ instId := srv.NewInstance()
+ defer srv.RemoveInstance(instId)
+ srv.NewLoadBalancer("testlb")
+ defer srv.RemoveLoadBalancer("testlb")
+ resp, err := s.clientTests.elb.DeregisterInstancesFromLoadBalancer([]string{instId}, "testlb")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Not(Equals), "")
+}
+
+func (s *LocalServerSuite) TestDeregisterInstanceWithLoadBalancerWithAbsentLoadBalancer(c *C) {
+ resp, err := s.clientTests.elb.DeregisterInstancesFromLoadBalancer([]string{"i-212"}, "absentlb")
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, `^There is no ACTIVE Load Balancer named 'absentlb' \(LoadBalancerNotFound\)$`)
+}
+
+func (s *LocalServerSuite) TestDeregisterInstancewithLoadBalancerWithAbsentInstance(c *C) {
+ srv := s.srv.srv
+ srv.NewLoadBalancer("testlb")
+ defer srv.RemoveLoadBalancer("testlb")
+ resp, err := s.clientTests.elb.DeregisterInstancesFromLoadBalancer([]string{"i-212"}, "testlb")
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ c.Assert(err, ErrorMatches, `^InvalidInstance found in \[i-212\]. Invalid id: "i-212" \(InvalidInstance\)$`)
+}
+
+func (s *LocalServerSuite) TestDescribeInstanceHealth(c *C) {
+ srv := s.srv.srv
+ instId := srv.NewInstance()
+ defer srv.RemoveInstance(instId)
+ srv.NewLoadBalancer("testlb")
+ defer srv.RemoveLoadBalancer("testlb")
+ resp, err := s.clientTests.elb.DescribeInstanceHealth("testlb", instId)
+ c.Assert(err, IsNil)
+ c.Assert(len(resp.InstanceStates) > 0, Equals, true)
+ c.Assert(resp.InstanceStates[0].Description, Equals, "Instance is in pending state.")
+ c.Assert(resp.InstanceStates[0].InstanceId, Equals, instId)
+ c.Assert(resp.InstanceStates[0].State, Equals, "OutOfService")
+ c.Assert(resp.InstanceStates[0].ReasonCode, Equals, "Instance")
+}
+
+func (s *LocalServerSuite) TestDescribeInstanceHealthBadRequest(c *C) {
+ s.clientTests.TestDescribeInstanceHealthBadRequest(c)
+}
+
+func (s *LocalServerSuite) TestDescribeInstanceHealthWithoutSpecifyingInstances(c *C) {
+ srv := s.srv.srv
+ instId := srv.NewInstance()
+ defer srv.RemoveInstance(instId)
+ srv.NewLoadBalancer("testlb")
+ defer srv.RemoveLoadBalancer("testlb")
+ srv.RegisterInstance(instId, "testlb")
+ resp, err := s.clientTests.elb.DescribeInstanceHealth("testlb")
+ c.Assert(err, IsNil)
+ c.Assert(len(resp.InstanceStates) > 0, Equals, true)
+ c.Assert(resp.InstanceStates[0].Description, Equals, "Instance is in pending state.")
+ c.Assert(resp.InstanceStates[0].InstanceId, Equals, instId)
+ c.Assert(resp.InstanceStates[0].State, Equals, "OutOfService")
+ c.Assert(resp.InstanceStates[0].ReasonCode, Equals, "Instance")
+}
+
+func (s *LocalServerSuite) TestDescribeInstanceHealthChangingIt(c *C) {
+ srv := s.srv.srv
+ instId := srv.NewInstance()
+ defer srv.RemoveInstance(instId)
+ srv.NewLoadBalancer("somelb")
+ defer srv.RemoveLoadBalancer("somelb")
+ srv.RegisterInstance(instId, "somelb")
+ state := elb.InstanceState{
+ Description: "Instance has failed at least the UnhealthyThreshold number of health checks consecutively",
+ InstanceId: instId,
+ State: "OutOfService",
+ ReasonCode: "Instance",
+ }
+ srv.ChangeInstanceState("somelb", state)
+ resp, err := s.clientTests.elb.DescribeInstanceHealth("somelb")
+ c.Assert(err, IsNil)
+ c.Assert(len(resp.InstanceStates) > 0, Equals, true)
+ c.Assert(resp.InstanceStates[0].Description, Equals, "Instance has failed at least the UnhealthyThreshold number of health checks consecutively")
+ c.Assert(resp.InstanceStates[0].InstanceId, Equals, instId)
+ c.Assert(resp.InstanceStates[0].State, Equals, "OutOfService")
+ c.Assert(resp.InstanceStates[0].ReasonCode, Equals, "Instance")
+}
+
+func (s *LocalServerSuite) TestConfigureHealthCheck(c *C) {
+ s.clientTests.TestConfigureHealthCheck(c)
+}
+
+func (s *LocalServerSuite) TestConfigureHealthCheckBadRequest(c *C) {
+ s.clientTests.TestConfigureHealthCheckBadRequest(c)
+}
diff --git a/vendor/github.com/goamz/goamz/elb/elbtest/server.go b/vendor/github.com/goamz/goamz/elb/elbtest/server.go
new file mode 100644
index 000000000..9b8f79d4e
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/elbtest/server.go
@@ -0,0 +1,551 @@
+// Package elbtest implements a fake ELB provider with the capability of
+// inducing errors on any given operation, and retrospectively determining what
+// operations have been carried out.
+package elbtest
+
+import (
+ "encoding/xml"
+ "fmt"
+ "github.com/goamz/goamz/elb"
+ "net"
+ "net/http"
+ "net/url"
+ "regexp"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+// Server implements an ELB simulator for use in testing.
+type Server struct {
+ url string
+ listener net.Listener
+ mutex sync.Mutex
+ reqId int
+ lbs map[string]*elb.LoadBalancerDescription
+ lbsReqs map[string]url.Values
+ instances []string
+ instanceStates map[string][]*elb.InstanceState
+ instCount int
+}
+
+// Starts and returns a new server
+func NewServer() (*Server, error) {
+ l, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ return nil, fmt.Errorf("cannot listen on localhost: %v", err)
+ }
+ srv := &Server{
+ listener: l,
+ url: "http://" + l.Addr().String(),
+ lbs: make(map[string]*elb.LoadBalancerDescription),
+ instanceStates: make(map[string][]*elb.InstanceState),
+ }
+ go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ srv.serveHTTP(w, req)
+ }))
+ return srv, nil
+}
+
+// Quit closes down the server.
+func (srv *Server) Quit() {
+ srv.listener.Close()
+}
+
+// URL returns the URL of the server.
+func (srv *Server) URL() string {
+ return srv.url
+}
+
+type xmlErrors struct {
+ XMLName string `xml:"ErrorResponse"`
+ Error elb.Error
+}
+
+func (srv *Server) error(w http.ResponseWriter, err *elb.Error) {
+ w.WriteHeader(err.StatusCode)
+ xmlErr := xmlErrors{Error: *err}
+ if e := xml.NewEncoder(w).Encode(xmlErr); e != nil {
+ panic(e)
+ }
+}
+
+func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) {
+ req.ParseForm()
+ srv.mutex.Lock()
+ defer srv.mutex.Unlock()
+ f := actions[req.Form.Get("Action")]
+ if f == nil {
+ srv.error(w, &elb.Error{
+ StatusCode: 400,
+ Code: "InvalidParameterValue",
+ Message: "Unrecognized Action",
+ })
+ }
+ reqId := fmt.Sprintf("req%0X", srv.reqId)
+ srv.reqId++
+ if resp, err := f(srv, w, req, reqId); err == nil {
+ if err := xml.NewEncoder(w).Encode(resp); err != nil {
+ panic(err)
+ }
+ } else {
+ switch err.(type) {
+ case *elb.Error:
+ srv.error(w, err.(*elb.Error))
+ default:
+ panic(err)
+ }
+ }
+}
+
+func (srv *Server) createLoadBalancer(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ composition := map[string]string{
+ "AvailabilityZones.member.1": "Subnets.member.1",
+ }
+ if err := srv.validateComposition(req, composition); err != nil {
+ return nil, err
+ }
+ required := []string{
+ "Listeners.member.1.InstancePort",
+ "Listeners.member.1.InstanceProtocol",
+ "Listeners.member.1.Protocol",
+ "Listeners.member.1.LoadBalancerPort",
+ "LoadBalancerName",
+ }
+ if err := srv.validate(req, required); err != nil {
+ return nil, err
+ }
+ path := req.FormValue("Path")
+ if path == "" {
+ path = "/"
+ }
+ lbName := req.FormValue("LoadBalancerName")
+ srv.lbs[lbName] = srv.makeLoadBalancerDescription(req.Form)
+ srv.lbs[lbName].DNSName = fmt.Sprintf("%s-some-aws-stuff.us-east-1.elb.amazonaws.com", lbName)
+ return elb.CreateLoadBalancerResp{
+ DNSName: srv.lbs[lbName].DNSName,
+ }, nil
+}
+
+func (srv *Server) deleteLoadBalancer(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"LoadBalancerName"}); err != nil {
+ return nil, err
+ }
+ srv.RemoveLoadBalancer(req.FormValue("LoadBalancerName"))
+ return elb.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) registerInstancesWithLoadBalancer(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ required := []string{"LoadBalancerName", "Instances.member.1.InstanceId"}
+ if err := srv.validate(req, required); err != nil {
+ return nil, err
+ }
+ lbName := req.FormValue("LoadBalancerName")
+ if err := srv.lbExists(lbName); err != nil {
+ return nil, err
+ }
+ instIds := []string{}
+ instances := []elb.Instance{}
+ i := 1
+ instId := req.FormValue(fmt.Sprintf("Instances.member.%d.InstanceId", i))
+ for instId != "" {
+ if err := srv.instanceExists(instId); err != nil {
+ return nil, err
+ }
+ instIds = append(instIds, instId)
+ instances = append(instances, elb.Instance{InstanceId: instId})
+ i++
+ instId = req.FormValue(fmt.Sprintf("Instances.member.%d.InstanceId", i))
+ }
+ srv.instanceStates[lbName] = append(srv.instanceStates[lbName], srv.makeInstanceState(instId))
+ srv.lbs[lbName].Instances = append(srv.lbs[lbName].Instances, instances...)
+ return elb.RegisterInstancesResp{InstanceIds: instIds}, nil
+}
+
+func (srv *Server) deregisterInstancesFromLoadBalancer(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ required := []string{"LoadBalancerName"}
+ if err := srv.validate(req, required); err != nil {
+ return nil, err
+ }
+ lbName := req.FormValue("LoadBalancerName")
+ if err := srv.lbExists(lbName); err != nil {
+ return nil, err
+ }
+ i := 1
+ lb := srv.lbs[lbName]
+ instId := req.FormValue(fmt.Sprintf("Instances.member.%d.InstanceId", i))
+ for instId != "" {
+ if err := srv.instanceExists(instId); err != nil {
+ return nil, err
+ }
+ i++
+ removeInstanceFromLB(lb, instId)
+ instId = req.FormValue(fmt.Sprintf("Instances.member.%d.InstanceId", i))
+ }
+ srv.lbs[lbName] = lb
+ srv.removeInstanceStatesFromLoadBalancer(lbName, instId)
+ return elb.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) describeLoadBalancers(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ i := 1
+ lbName := req.FormValue(fmt.Sprintf("LoadBalancerNames.member.%d", i))
+ for lbName != "" {
+ key := fmt.Sprintf("LoadBalancerNames.member.%d", i)
+ if req.FormValue(key) != "" {
+ if err := srv.lbExists(req.FormValue(key)); err != nil {
+ return nil, err
+ }
+ }
+ i++
+ lbName = req.FormValue(fmt.Sprintf("LoadBalancerNames.member.%d", i))
+ }
+ lbsDesc := make([]elb.LoadBalancerDescription, len(srv.lbs))
+ i = 0
+ for _, lb := range srv.lbs {
+ lbsDesc[i] = *lb
+ i++
+ }
+ resp := elb.DescribeLoadBalancerResp{
+ LoadBalancerDescriptions: lbsDesc,
+ }
+ return resp, nil
+}
+
+// getParameters returns the value all parameters from a request that matches a
+// prefix.
+//
+// For example, for the prefix "Subnets.member.", it will return a slice
+// containing the value of keys "Subnets.member.1", "Subnets.member.2" ...
+// "Subnets.member.N". The prefix must include the trailing dot.
+func (srv *Server) getParameters(prefix string, values url.Values) []string {
+ i, key := 1, ""
+ var k = func(n int) string {
+ return fmt.Sprintf(prefix+"%d", n)
+ }
+ var result []string
+ for i, key = 2, k(i); values.Get(key) != ""; i, key = i+1, k(i) {
+ result = append(result, values.Get(key))
+ }
+ return result
+}
+
+func (srv *Server) makeInstanceState(id string) *elb.InstanceState {
+ return &elb.InstanceState{
+ Description: "Instance is in pending state.",
+ InstanceId: id,
+ State: "OutOfService",
+ ReasonCode: "Instance",
+ }
+}
+
+func removeInstanceFromLB(lb *elb.LoadBalancerDescription, id string) {
+ index := -1
+ for i, instance := range lb.Instances {
+ if instance.InstanceId == id {
+ index = i
+ break
+ }
+ }
+ if index > -1 {
+ copy(lb.Instances[index:], lb.Instances[index+1:])
+ lb.Instances = lb.Instances[:len(lb.Instances)-1]
+ }
+}
+
+func (srv *Server) removeInstanceStatesFromLoadBalancer(lb, id string) {
+ for i, state := range srv.instanceStates[lb] {
+ if state.InstanceId == id {
+ a := srv.instanceStates[lb]
+ a[i], a = a[len(a)-1], a[:len(a)-1]
+ srv.instanceStates[lb] = a
+ return
+ }
+ }
+}
+
+func (srv *Server) makeLoadBalancerDescription(value url.Values) *elb.LoadBalancerDescription {
+ lds := []elb.ListenerDescription{}
+ i := 1
+ protocol := value.Get(fmt.Sprintf("Listeners.member.%d.Protocol", i))
+ for protocol != "" {
+ key := fmt.Sprintf("Listeners.member.%d.", i)
+ lInstPort, _ := strconv.Atoi(value.Get(key + "InstancePort"))
+ lLBPort, _ := strconv.Atoi(value.Get(key + "LoadBalancerPort"))
+ lDescription := elb.ListenerDescription{
+ Listener: elb.Listener{
+ Protocol: strings.ToUpper(protocol),
+ InstanceProtocol: strings.ToUpper(value.Get(key + "InstanceProtocol")),
+ LoadBalancerPort: lLBPort,
+ InstancePort: lInstPort,
+ },
+ }
+ i++
+ protocol = value.Get(fmt.Sprintf("Listeners.member.%d.Protocol", i))
+ lds = append(lds, lDescription)
+ }
+ sourceSecGroup := srv.makeSourceSecGroup(value)
+ lbDesc := elb.LoadBalancerDescription{
+ AvailabilityZones: srv.getParameters("AvailabilityZones.member.", value),
+ Subnets: srv.getParameters("Subnets.member.", value),
+ SecurityGroups: srv.getParameters("SecurityGroups.member.", value),
+ HealthCheck: srv.makeHealthCheck(value),
+ ListenerDescriptions: lds,
+ Scheme: value.Get("Scheme"),
+ SourceSecurityGroup: sourceSecGroup,
+ LoadBalancerName: value.Get("LoadBalancerName"),
+ }
+ if lbDesc.Scheme == "" {
+ lbDesc.Scheme = "internet-facing"
+ }
+ return &lbDesc
+}
+
+func (srv *Server) makeHealthCheck(value url.Values) elb.HealthCheck {
+ ht := 10
+ timeout := 5
+ ut := 2
+ interval := 30
+ target := "TCP:80"
+ if v := value.Get("HealthCheck.HealthyThreshold"); v != "" {
+ ht, _ = strconv.Atoi(v)
+ }
+ if v := value.Get("HealthCheck.Timeout"); v != "" {
+ timeout, _ = strconv.Atoi(v)
+ }
+ if v := value.Get("HealthCheck.UnhealthyThreshold"); v != "" {
+ ut, _ = strconv.Atoi(v)
+ }
+ if v := value.Get("HealthCheck.Interval"); v != "" {
+ interval, _ = strconv.Atoi(v)
+ }
+ if v := value.Get("HealthCheck.Target"); v != "" {
+ target = v
+ }
+ return elb.HealthCheck{
+ HealthyThreshold: ht,
+ Interval: interval,
+ Target: target,
+ Timeout: timeout,
+ UnhealthyThreshold: ut,
+ }
+}
+
+func (srv *Server) makeSourceSecGroup(value url.Values) elb.SourceSecurityGroup {
+ name := "amazon-elb-sg"
+ alias := "amazon-elb"
+ if v := value.Get("SourceSecurityGroup.GroupName"); v != "" {
+ name = v
+ }
+ if v := value.Get("SourceSecurityGroup.OwnerAlias"); v != "" {
+ alias = v
+ }
+ return elb.SourceSecurityGroup{
+ GroupName: name,
+ OwnerAlias: alias,
+ }
+}
+
+func (srv *Server) describeInstanceHealth(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.lbExists(req.FormValue("LoadBalancerName")); err != nil {
+ return nil, err
+ }
+ resp := elb.DescribeInstanceHealthResp{
+ InstanceStates: []elb.InstanceState{},
+ }
+ for _, state := range srv.instanceStates[req.FormValue("LoadBalancerName")] {
+ resp.InstanceStates = append(resp.InstanceStates, *state)
+ }
+ i := 1
+ instanceId := req.FormValue("Instances.member.1.InstanceId")
+ for instanceId != "" {
+ if err := srv.instanceExists(instanceId); err != nil {
+ return nil, err
+ }
+ is := elb.InstanceState{
+ Description: "Instance is in pending state.",
+ InstanceId: instanceId,
+ State: "OutOfService",
+ ReasonCode: "Instance",
+ }
+ resp.InstanceStates = append(resp.InstanceStates, is)
+ i++
+ instanceId = req.FormValue(fmt.Sprintf("Instances.member.%d.InstanceId", i))
+ }
+ return resp, nil
+}
+
+func (srv *Server) configureHealthCheck(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ required := []string{
+ "LoadBalancerName",
+ "HealthCheck.HealthyThreshold",
+ "HealthCheck.Interval",
+ "HealthCheck.Target",
+ "HealthCheck.Timeout",
+ "HealthCheck.UnhealthyThreshold",
+ }
+ if err := srv.validate(req, required); err != nil {
+ return nil, err
+ }
+ target := req.FormValue("HealthCheck.Target")
+ r, err := regexp.Compile(`[\w]+:[\d]+\/+`)
+ if err != nil {
+ panic(err)
+ }
+ if m := r.FindStringSubmatch(target); m == nil {
+ return nil, &elb.Error{
+ StatusCode: 400,
+ Code: "ValidationError",
+ Message: "HealthCheck HTTP Target must specify a port followed by a path that begins with a slash. e.g. HTTP:80/ping/this/path",
+ }
+ }
+ ht, _ := strconv.Atoi(req.FormValue("HealthCheck.HealthyThreshold"))
+ interval, _ := strconv.Atoi(req.FormValue("HealthCheck.Interval"))
+ timeout, _ := strconv.Atoi(req.FormValue("HealthCheck.Timeout"))
+ ut, _ := strconv.Atoi(req.FormValue("HealthCheck.UnhealthyThreshold"))
+ return elb.HealthCheckResp{
+ HealthCheck: &elb.HealthCheck{
+ HealthyThreshold: ht,
+ Interval: interval,
+ Target: target,
+ Timeout: timeout,
+ UnhealthyThreshold: ut,
+ },
+ }, nil
+}
+
+func (srv *Server) instanceExists(id string) error {
+ for _, instId := range srv.instances {
+ if instId == id {
+ return nil
+ }
+ }
+ return &elb.Error{
+ StatusCode: 400,
+ Code: "InvalidInstance",
+ Message: fmt.Sprintf("InvalidInstance found in [%s]. Invalid id: \"%s\"", id, id),
+ }
+}
+
+func (srv *Server) lbExists(name string) error {
+ if _, ok := srv.lbs[name]; !ok {
+ return &elb.Error{
+ StatusCode: 400,
+ Code: "LoadBalancerNotFound",
+ Message: fmt.Sprintf("There is no ACTIVE Load Balancer named '%s'", name),
+ }
+ }
+ return nil
+}
+
+func (srv *Server) validate(req *http.Request, required []string) error {
+ for _, field := range required {
+ if req.FormValue(field) == "" {
+ return &elb.Error{
+ StatusCode: 400,
+ Code: "ValidationError",
+ Message: fmt.Sprintf("%s is required.", field),
+ }
+ }
+ }
+ return nil
+}
+
+// Validates the composition of the fields.
+//
+// Some fields cannot be together in the same request, such as AvailabilityZones and Subnets.
+// A sample map with the above requirement would be
+// c := map[string]string{
+// "AvailabilityZones.member.1": "Subnets.member.1",
+// }
+//
+// The server also requires that at least one of those fields are specified.
+func (srv *Server) validateComposition(req *http.Request, composition map[string]string) error {
+ for k, v := range composition {
+ if req.FormValue(k) != "" && req.FormValue(v) != "" {
+ return &elb.Error{
+ StatusCode: 400,
+ Code: "ValidationError",
+ Message: fmt.Sprintf("Only one of %s or %s may be specified", k, v),
+ }
+ }
+ if req.FormValue(k) == "" && req.FormValue(v) == "" {
+ return &elb.Error{
+ StatusCode: 400,
+ Code: "ValidationError",
+ Message: fmt.Sprintf("Either %s or %s must be specified", k, v),
+ }
+ }
+ }
+ return nil
+}
+
+// Creates a fake instance in the server
+func (srv *Server) NewInstance() string {
+ srv.instCount++
+ instId := fmt.Sprintf("i-%d", srv.instCount)
+ srv.instances = append(srv.instances, instId)
+ return instId
+}
+
+// Removes a fake instance from the server
+//
+// If no instance is found it does nothing
+func (srv *Server) RemoveInstance(instId string) {
+ for i, id := range srv.instances {
+ if id == instId {
+ srv.instances[i], srv.instances = srv.instances[len(srv.instances)-1], srv.instances[:len(srv.instances)-1]
+ }
+ }
+}
+
+// Creates a fake load balancer in the fake server
+func (srv *Server) NewLoadBalancer(name string) {
+ srv.lbs[name] = &elb.LoadBalancerDescription{
+ LoadBalancerName: name,
+ DNSName: fmt.Sprintf("%s-some-aws-stuff.sa-east-1.amazonaws.com", name),
+ }
+}
+
+// Removes a fake load balancer from the fake server
+func (srv *Server) RemoveLoadBalancer(name string) {
+ delete(srv.lbs, name)
+}
+
+// Register a fake instance with a fake Load Balancer
+//
+// If the Load Balancer does not exists it does nothing
+func (srv *Server) RegisterInstance(instId, lbName string) {
+ lb, ok := srv.lbs[lbName]
+ if !ok {
+ fmt.Println("lb not found :/")
+ return
+ }
+ lb.Instances = append(lb.Instances, elb.Instance{InstanceId: instId})
+ srv.instanceStates[lbName] = append(srv.instanceStates[lbName], srv.makeInstanceState(instId))
+}
+
+func (srv *Server) DeregisterInstance(instId, lbName string) {
+ removeInstanceFromLB(srv.lbs[lbName], instId)
+ srv.removeInstanceStatesFromLoadBalancer(lbName, instId)
+}
+
+func (srv *Server) ChangeInstanceState(lb string, state elb.InstanceState) {
+ states := srv.instanceStates[lb]
+ for i, s := range states {
+ if s.InstanceId == state.InstanceId {
+ srv.instanceStates[lb][i] = &state
+ return
+ }
+ }
+}
+
+var actions = map[string]func(*Server, http.ResponseWriter, *http.Request, string) (interface{}, error){
+ "CreateLoadBalancer": (*Server).createLoadBalancer,
+ "DeleteLoadBalancer": (*Server).deleteLoadBalancer,
+ "RegisterInstancesWithLoadBalancer": (*Server).registerInstancesWithLoadBalancer,
+ "DeregisterInstancesFromLoadBalancer": (*Server).deregisterInstancesFromLoadBalancer,
+ "DescribeLoadBalancers": (*Server).describeLoadBalancers,
+ "DescribeInstanceHealth": (*Server).describeInstanceHealth,
+ "ConfigureHealthCheck": (*Server).configureHealthCheck,
+}
diff --git a/vendor/github.com/goamz/goamz/elb/export_test.go b/vendor/github.com/goamz/goamz/elb/export_test.go
new file mode 100644
index 000000000..49a2d50fe
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/export_test.go
@@ -0,0 +1,9 @@
+package elb
+
+import (
+ "github.com/goamz/goamz/aws"
+)
+
+func Sign(auth aws.Auth, method, path string, params map[string]string, host string) {
+ sign(auth, method, path, params, host)
+}
diff --git a/vendor/github.com/goamz/goamz/elb/response_test.go b/vendor/github.com/goamz/goamz/elb/response_test.go
new file mode 100644
index 000000000..637d1e140
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/response_test.go
@@ -0,0 +1,234 @@
+package elb_test
+
+var CreateLoadBalancer = `
+<CreateLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <CreateLoadBalancerResult>
+ <DNSName>testlb-339187009.us-east-1.elb.amazonaws.com</DNSName>
+ </CreateLoadBalancerResult>
+ <ResponseMetadata>
+ <RequestId>0c3a8e29-490e-11e2-8647-e14ad5151f1f</RequestId>
+ </ResponseMetadata>
+</CreateLoadBalancerResponse>
+`
+
+var CreateLoadBalancerBadRequest = `
+<ErrorResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>ValidationError</Code>
+ <Message>Only one of SubnetIds or AvailabilityZones may be specified</Message>
+ </Error>
+ <RequestId>159253fc-49dc-11e2-a47d-cde463c91a3c</RequestId>
+</ErrorResponse>
+`
+
+var DeleteLoadBalancer = `
+<DeleteLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <DeleteLoadBalancerResult/>
+ <ResponseMetadata>
+ <RequestId>8d7223db-49d7-11e2-bba9-35ba56032fe1</RequestId>
+ </ResponseMetadata>
+</DeleteLoadBalancerResponse>
+`
+
+var RegisterInstancesWithLoadBalancer = `
+<RegisterInstancesWithLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <RegisterInstancesWithLoadBalancerResult>
+ <Instances>
+ <member>
+ <InstanceId>i-b44db8ca</InstanceId>
+ </member>
+ <member>
+ <InstanceId>i-461ecf38</InstanceId>
+ </member>
+ </Instances>
+ </RegisterInstancesWithLoadBalancerResult>
+ <ResponseMetadata>
+ <RequestId>0fc82478-49e1-11e2-b947-8768f15220aa</RequestId>
+ </ResponseMetadata>
+</RegisterInstancesWithLoadBalancerResponse>
+`
+
+var RegisterInstancesWithLoadBalancerBadRequest = `
+<ErrorResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>LoadBalancerNotFound</Code>
+ <Message>There is no ACTIVE Load Balancer named 'absentLB'</Message>
+ </Error>
+ <RequestId>19a0bb97-49f7-11e2-90b4-6bb9ec8331bf</RequestId>
+</ErrorResponse>
+`
+
+var DeregisterInstancesFromLoadBalancer = `
+<DeregisterInstancesFromLoadBalancerResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <DeregisterInstancesFromLoadBalancerResult>
+ <Instances/>
+ </DeregisterInstancesFromLoadBalancerResult>
+ <ResponseMetadata>
+ <RequestId>d6490837-49fd-11e2-bba9-35ba56032fe1</RequestId>
+ </ResponseMetadata>
+</DeregisterInstancesFromLoadBalancerResponse>
+`
+
+var DeregisterInstancesFromLoadBalancerBadRequest = `
+<ErrorResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>LoadBalancerNotFound</Code>
+ <Message>There is no ACTIVE Load Balancer named 'absentlb'</Message>
+ </Error>
+ <RequestId>498e2b4a-4aa1-11e2-8839-d19a879f2eec</RequestId>
+</ErrorResponse>
+`
+
+var DescribeLoadBalancers = `
+<DescribeLoadBalancersResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <DescribeLoadBalancersResult>
+ <LoadBalancerDescriptions>
+ <member>
+ <SecurityGroups/>
+ <CreatedTime>2012-12-27T11:51:52.970Z</CreatedTime>
+ <LoadBalancerName>testlb</LoadBalancerName>
+ <HealthCheck>
+ <Interval>30</Interval>
+ <Target>TCP:80</Target>
+ <HealthyThreshold>10</HealthyThreshold>
+ <Timeout>5</Timeout>
+ <UnhealthyThreshold>2</UnhealthyThreshold>
+ </HealthCheck>
+ <ListenerDescriptions>
+ <member>
+ <PolicyNames/>
+ <Listener>
+ <Protocol>HTTP</Protocol>
+ <LoadBalancerPort>80</LoadBalancerPort>
+ <InstanceProtocol>HTTP</InstanceProtocol>
+ <InstancePort>80</InstancePort>
+ </Listener>
+ </member>
+ </ListenerDescriptions>
+ <Instances/>
+ <Policies>
+ <AppCookieStickinessPolicies/>
+ <OtherPolicies/>
+ <LBCookieStickinessPolicies/>
+ </Policies>
+ <AvailabilityZones>
+ <member>us-east-1a</member>
+ </AvailabilityZones>
+ <CanonicalHostedZoneName>testlb-2087227216.us-east-1.elb.amazonaws.com</CanonicalHostedZoneName>
+ <CanonicalHostedZoneNameID>Z3DZXE0Q79N41H</CanonicalHostedZoneNameID>
+ <Scheme>internet-facing</Scheme>
+ <SourceSecurityGroup>
+ <OwnerAlias>amazon-elb</OwnerAlias>
+ <GroupName>amazon-elb-sg</GroupName>
+ </SourceSecurityGroup>
+ <DNSName>testlb-2087227216.us-east-1.elb.amazonaws.com</DNSName>
+ <BackendServerDescriptions/>
+ <Subnets/>
+ </member>
+ </LoadBalancerDescriptions>
+ </DescribeLoadBalancersResult>
+ <ResponseMetadata>
+ <RequestId>e2e81963-5055-11e2-99c7-434205631d9b</RequestId>
+ </ResponseMetadata>
+</DescribeLoadBalancersResponse>
+`
+
+var DescribeLoadBalancersBadRequest = `
+<ErrorResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>LoadBalancerNotFound</Code>
+ <Message>Cannot find Load Balancer absentlb</Message>
+ </Error>
+ <RequestId>f14f348e-50f7-11e2-9831-f770dd71c209</RequestId>
+</ErrorResponse>
+`
+
+var DescribeInstanceHealth = `
+<DescribeInstanceHealthResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <DescribeInstanceHealthResult>
+ <InstanceStates>
+ <member>
+ <Description>Instance registration is still in progress.</Description>
+ <InstanceId>i-b44db8ca</InstanceId>
+ <State>OutOfService</State>
+ <ReasonCode>ELB</ReasonCode>
+ </member>
+ </InstanceStates>
+ </DescribeInstanceHealthResult>
+ <ResponseMetadata>
+ <RequestId>da0d0f9e-5669-11e2-9f81-319facce7423</RequestId>
+ </ResponseMetadata>
+</DescribeInstanceHealthResponse>
+`
+
+var DescribeInstanceHealthBadRequest = `
+<ErrorResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>InvalidInstance</Code>
+ <Message>Could not find EC2 instance i-foooo.</Message>
+ </Error>
+ <RequestId>352e00d6-566c-11e2-a46d-313272bbb522</RequestId>
+</ErrorResponse>
+`
+
+var ConfigureHealthCheck = `
+<ConfigureHealthCheckResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <ConfigureHealthCheckResult>
+ <HealthCheck>
+ <Interval>30</Interval>
+ <Target>HTTP:80/</Target>
+ <HealthyThreshold>10</HealthyThreshold>
+ <Timeout>5</Timeout>
+ <UnhealthyThreshold>2</UnhealthyThreshold>
+ </HealthCheck>
+ </ConfigureHealthCheckResult>
+ <ResponseMetadata>
+ <RequestId>a882d12c-5694-11e2-b647-594652c9487c</RequestId>
+ </ResponseMetadata>
+</ConfigureHealthCheckResponse>
+`
+
+var ConfigureHealthCheckBadRequest = `
+<ErrorResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>LoadBalancerNotFound</Code>
+ <Message>There is no ACTIVE Load Balancer named 'foolb'</Message>
+ </Error>
+ <RequestId>2d9fe4a5-5697-11e2-9415-e325c02171d7</RequestId>
+</ErrorResponse>
+`
+
+var AddTagsSuccessResponse = `
+<AddTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06- 01/">
+ <AddTagsResult/>
+ <ResponseMetadata>
+ <RequestId>360e81f7-1100-11e4-b6ed-0f30SOME-SAUCY-EXAMPLE</RequestId>
+ </ResponseMetadata>
+</AddTagsResponse>
+`
+
+var TagsBadRequest = `
+<ErrorResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>InvalidParameterValue</Code>
+ <Message>An invalid or out-of-range value was supplied for the input parameter.</Message>
+ </Error>
+ <RequestId>terrible-request-id</RequestId>
+</ErrorResponse>
+`
+
+var RemoveTagsSuccessResponse = `
+<RemoveTagsResponse xmlns="http://elasticloadbalancing.amazonaws.com/doc/2012-06-01/">
+ <RemoveTagsResult/>
+ <ResponseMetadata>
+ <RequestId>83c88b9d-12b7-11e3-8b82-87b12DIFFEXAMPLE</RequestId>
+ </ResponseMetadata>
+</RemoveTagsResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/elb/sign.go b/vendor/github.com/goamz/goamz/elb/sign.go
new file mode 100644
index 000000000..b7da14772
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/sign.go
@@ -0,0 +1,35 @@
+package elb
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "github.com/goamz/goamz/aws"
+ "sort"
+ "strings"
+)
+
+var b64 = base64.StdEncoding
+
+func sign(auth aws.Auth, method, path string, params map[string]string, host string) {
+ params["AWSAccessKeyId"] = auth.AccessKey
+ params["SignatureVersion"] = "2"
+ params["SignatureMethod"] = "HmacSHA256"
+
+ var keys, sarray []string
+ for k := range params {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(params[k]))
+ }
+ joined := strings.Join(sarray, "&")
+ payload := method + "\n" + host + "\n" + path + "\n" + joined
+ hash := hmac.New(sha256.New, []byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum(nil))
+
+ params["Signature"] = string(signature)
+}
diff --git a/vendor/github.com/goamz/goamz/elb/sign_test.go b/vendor/github.com/goamz/goamz/elb/sign_test.go
new file mode 100644
index 000000000..0dda1667e
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/sign_test.go
@@ -0,0 +1,66 @@
+package elb_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/elb"
+ . "gopkg.in/check.v1"
+)
+
+var testAuth = aws.Auth{AccessKey: "user", SecretKey: "secret"}
+
+func (s *S) TestBasicSignature(c *C) {
+ params := map[string]string{}
+ elb.Sign(testAuth, "GET", "/path", params, "localhost")
+ c.Assert(params["SignatureVersion"], Equals, "2")
+ c.Assert(params["SignatureMethod"], Equals, "HmacSHA256")
+ expected := "6lSe5QyXum0jMVc7cOUz32/52ZnL7N5RyKRk/09yiK4="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestParamSignature(c *C) {
+ params := map[string]string{
+ "param1": "value1",
+ "param2": "value2",
+ "param3": "value3",
+ }
+ elb.Sign(testAuth, "GET", "/path", params, "localhost")
+ expected := "XWOR4+0lmK8bD8CGDGZ4kfuSPbb2JibLJiCl/OPu1oU="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestManyParams(c *C) {
+ params := map[string]string{
+ "param1": "value10",
+ "param2": "value2",
+ "param3": "value3",
+ "param4": "value4",
+ "param5": "value5",
+ "param6": "value6",
+ "param7": "value7",
+ "param8": "value8",
+ "param9": "value9",
+ "param10": "value1",
+ }
+ elb.Sign(testAuth, "GET", "/path", params, "localhost")
+ expected := "di0sjxIvezUgQ1SIL6i+C/H8lL+U0CQ9frLIak8jkVg="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestEscaping(c *C) {
+ params := map[string]string{"Nonce": "+ +"}
+ elb.Sign(testAuth, "GET", "/path", params, "localhost")
+ c.Assert(params["Nonce"], Equals, "+ +")
+ expected := "bqffDELReIqwjg/W0DnsnVUmfLK4wXVLO4/LuG+1VFA="
+ c.Assert(params["Signature"], Equals, expected)
+}
+
+func (s *S) TestSignatureExample1(c *C) {
+ params := map[string]string{
+ "Timestamp": "2009-02-01T12:53:20+00:00",
+ "Version": "2007-11-07",
+ "Action": "ListDomains",
+ }
+ elb.Sign(aws.Auth{AccessKey: "access", SecretKey: "secret"}, "GET", "/", params, "sdb.amazonaws.com")
+ expected := "okj96/5ucWBSc1uR2zXVfm6mDHtgfNv657rRtt/aunQ="
+ c.Assert(params["Signature"], Equals, expected)
+}
diff --git a/vendor/github.com/goamz/goamz/elb/suite_test.go b/vendor/github.com/goamz/goamz/elb/suite_test.go
new file mode 100644
index 000000000..fe4c81d47
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/elb/suite_test.go
@@ -0,0 +1,119 @@
+package elb_test
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "os"
+ "testing"
+ "time"
+
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+type HTTPSuite struct{}
+
+var testServer = NewTestHTTPServer("http://localhost:4444", 5*time.Second)
+
+func (s *HTTPSuite) SetUpSuite(c *C) {
+ testServer.Start()
+}
+
+func (s *HTTPSuite) TearDownTest(c *C) {
+ testServer.FlushRequests()
+}
+
+type TestHTTPServer struct {
+ URL string
+ Timeout time.Duration
+ started bool
+ request chan *http.Request
+ response chan *testResponse
+ pending chan bool
+}
+
+type testResponse struct {
+ Status int
+ Headers map[string]string
+ Body string
+}
+
+func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
+ return &TestHTTPServer{URL: url, Timeout: timeout}
+}
+
+func (s *TestHTTPServer) Start() {
+ if s.started {
+ return
+ }
+ s.started = true
+
+ s.request = make(chan *http.Request, 64)
+ s.response = make(chan *testResponse, 64)
+ s.pending = make(chan bool, 64)
+
+ url, _ := url.Parse(s.URL)
+ go http.ListenAndServe(url.Host, s)
+
+ s.PrepareResponse(202, nil, "Nothing.")
+ for {
+ // Wait for it to be up.
+ resp, err := http.Get(s.URL)
+ if err == nil && resp.StatusCode == 202 {
+ break
+ }
+ time.Sleep(1e8)
+ }
+ s.WaitRequest() // Consume dummy request.
+}
+
+// FlushRequests discards requests which were not yet consumed by WaitRequest.
+func (s *TestHTTPServer) FlushRequests() {
+ for {
+ select {
+ case <-s.request:
+ default:
+ return
+ }
+ }
+}
+
+func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ s.request <- req
+ var resp *testResponse
+ select {
+ case resp = <-s.response:
+ case <-time.After(s.Timeout):
+ fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
+ resp = &testResponse{500, nil, ""}
+ }
+ if resp.Headers != nil {
+ h := w.Header()
+ for k, v := range resp.Headers {
+ h.Set(k, v)
+ }
+ }
+ if resp.Status != 0 {
+ w.WriteHeader(resp.Status)
+ }
+ w.Write([]byte(resp.Body))
+}
+
+func (s *TestHTTPServer) WaitRequest() *http.Request {
+ select {
+ case req := <-s.request:
+ req.ParseForm()
+ return req
+ case <-time.After(s.Timeout):
+ panic("Timeout waiting for goamz request")
+ }
+ panic("unreached")
+}
+
+func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
+ s.response <- &testResponse{status, headers, body}
+}
diff --git a/vendor/github.com/goamz/goamz/exp/mturk/example_test.go b/vendor/github.com/goamz/goamz/exp/mturk/example_test.go
new file mode 100644
index 000000000..806ce95fd
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/mturk/example_test.go
@@ -0,0 +1,66 @@
+package mturk_test
+
+import (
+ "fmt"
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/exp/mturk"
+)
+
+var turk *mturk.MTurk
+
+func ExampleNew() {
+ // These are your AWS tokens. Note that Turk do not support IAM.
+ // So you'll have to use your main profile's tokens.
+ var auth = aws.Auth{AccessKey: "<ACCESS_KEY>", SecretKey: "<SECRET_KEY>"}
+ turk = mturk.New(auth, true) // true to use sandbox mode
+}
+
+func Examplemturk_CreateHIT_withExternalQuestion() {
+ question := mturk.ExternalQuestion{
+ ExternalURL: "http://www.amazon.com",
+ FrameHeight: 200,
+ }
+ reward := mturk.Price{
+ Amount: "0.01",
+ CurrencyCode: "USD",
+ }
+
+ hit, err := turk.CreateHIT("title", "description", question, reward, 30, 30, "key1,key2", 3, nil, "annotation")
+
+ if err == nil {
+ fmt.Println(hit)
+ }
+}
+
+func Examplemturk_CreateHIT_withHTMLQuestion() {
+ question := mturk.HTMLQuestion{
+ HTMLContent: mturk.HTMLContent{`<![CDATA[
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
+ <script type='text/javascript' src='https://s3.amazonaws.com/mturk-public/externalHIT_v1.js'></script>
+ </head>
+ <body>
+ <form name='mturk_form' method='post' id='mturk_form' action='https://www.mturk.com/mturk/externalSubmit'>
+ <input type='hidden' value='' name='assignmentId' id='assignmentId'/>
+ <h1>What's up?</h1>
+ <p><textarea name='comment' cols='80' rows='3'></textarea></p>
+ <p><input type='submit' id='submitButton' value='Submit' /></p></form>
+ <script language='Javascript'>turkSetAssignmentID();</script>
+ </body>
+</html>
+]]>`},
+ FrameHeight: 200,
+ }
+ reward := mturk.Price{
+ Amount: "0.01",
+ CurrencyCode: "USD",
+ }
+
+ hit, err := turk.CreateHIT("title", "description", question, reward, 30, 30, "key1,key2", 3, nil, "")
+
+ if err == nil {
+ fmt.Println(hit)
+ }
+}
diff --git a/vendor/github.com/goamz/goamz/exp/mturk/export_test.go b/vendor/github.com/goamz/goamz/exp/mturk/export_test.go
new file mode 100644
index 000000000..736678a56
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/mturk/export_test.go
@@ -0,0 +1,9 @@
+package mturk
+
+import (
+ "github.com/goamz/goamz/aws"
+)
+
+func Sign(auth aws.Auth, service, method, timestamp string, params map[string]string) {
+ sign(auth, service, method, timestamp, params)
+}
diff --git a/vendor/github.com/goamz/goamz/exp/mturk/mturk.go b/vendor/github.com/goamz/goamz/exp/mturk/mturk.go
new file mode 100644
index 000000000..fbbf700c2
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/mturk/mturk.go
@@ -0,0 +1,480 @@
+//
+// goamz - Go packages to interact with the Amazon Web Services.
+//
+// https://wiki.ubuntu.com/goamz
+//
+// Copyright (c) 2011 Canonical Ltd.
+//
+// Written by Graham Miller <graham.miller@gmail.com>
+
+// This package is in an experimental state, and does not currently
+// follow conventions and style of the rest of goamz or common
+// Go conventions. It must be polished before it's considered a
+// first-class package in goamz.
+package mturk
+
+import (
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "github.com/goamz/goamz/aws"
+ "net/http"
+ //"net/http/httputil"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type MTurk struct {
+ aws.Auth
+ URL *url.URL
+}
+
+func New(auth aws.Auth, sandbox bool) *MTurk {
+ mt := &MTurk{Auth: auth}
+ var err error
+ if sandbox {
+ mt.URL, err = url.Parse("https://mechanicalturk.sandbox.amazonaws.com/")
+ } else {
+ mt.URL, err = url.Parse("https://mechanicalturk.amazonaws.com/")
+ }
+ if err != nil {
+ panic(err.Error())
+ }
+ return mt
+}
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+// Error encapsulates an error returned by MTurk.
+type Error struct {
+ StatusCode int // HTTP status code (200, 403, ...)
+ Code string // EC2 error code ("UnsupportedOperation", ...)
+ Message string // The human-oriented error message
+ RequestId string
+}
+
+func (err *Error) Error() string {
+ return err.Message
+}
+
+// The request stanza included in several response types, for example
+// in a "CreateHITResponse". http://goo.gl/qGeKf
+type xmlRequest struct {
+ RequestId string
+ IsValid string
+ Errors []Error `xml:"Errors>Error"`
+}
+
+/*
+A Price represents an amount of money in a given currency.
+
+Reference:
+http://docs.aws.amazon.com/AWSMechTurk/latest/AWSMturkAPI/ApiReference_PriceDataStructureArticle.html
+*/
+type Price struct {
+ // The amount of money, as a number. The amount is in the currency specified
+ // by the CurrencyCode. For example, if CurrencyCode is USD, the amount will
+ // be in United States dollars (e.g. 12.75 is $12.75 US).
+ Amount string
+
+ // A code that represents the country and units of the currency. Its value is
+ // Type an ISO 4217 currency code, such as USD for United States dollars.
+ //
+ // Constraints: Currently only USD is supported.
+ CurrencyCode string
+
+ // A textual representation of the price, using symbols and formatting
+ // appropriate for the currency. Symbols are represented using the Unicode
+ // character set. You do not need to specify FormattedPrice in a request.
+ // It is only provided by the service in responses, as a convenience to
+ // your application.
+ FormattedPrice string
+}
+
+/*
+Really just a country string.
+
+Reference:
+
+- http://docs.aws.amazon.com/AWSMechTurk/latest/AWSMturkAPI/ApiReference_LocaleDataStructureArticle.html
+- http://www.iso.org/iso/country_codes/country_codes
+*/
+type Locale string
+
+/*
+A QualificationRequirement describes a Qualification a Worker must
+have before the Worker is allowed to accept a HIT. A requirement may optionally
+state that a Worker must have the Qualification to preview the HIT.
+
+Reference:
+
+http://docs.aws.amazon.com/AWSMechTurk/latest/AWSMturkAPI/ApiReference_QualificationRequirementDataStructureArticle.html
+*/
+type QualificationRequirement struct {
+ // The ID of the Qualification type for the requirement.
+ // See http://docs.aws.amazon.com/AWSMechTurk/latest/AWSMturkAPI/ApiReference_QualificationRequirementDataStructureArticle.html#ApiReference_QualificationType-IDs
+ QualificationTypeId string
+
+ // The kind of comparison to make against a Qualification's value.
+ // Two values can be compared to see if one value is "LessThan",
+ // "LessThanOrEqualTo", "GreaterThan", "GreaterThanOrEqualTo", "EqualTo", or
+ // "NotEqualTo" the other. A Qualification requirement can also test if a
+ // Qualification "Exists" in the user's profile, regardless of its value.
+ Comparator string
+
+ // The integer value to compare against the Qualification's value.
+ IntegerValue int
+
+ // The locale value to compare against the Qualification's value, if the
+ // Qualification being compared is the locale Qualification.
+ LocaleValue Locale
+
+ // If true, the question data for the HIT will not be shown when a Worker
+ // whose Qualifications do not meet this requirement tries to preview the HIT.
+ // That is, a Worker's Qualifications must meet all of the requirements for
+ // which RequiredToPreview is true in order to preview the HIT.
+ //
+ // If a Worker meets all of the requirements where RequiredToPreview is true
+ // (or if there are no such requirements), but does not meet all of the
+ // requirements for the HIT, the Worker will be allowed to preview the HIT's
+ // question data, but will not be allowed to accept and complete the HIT.
+ RequiredToPreview bool
+}
+
+// Data structure holding the contents of an "external"
+// question. http://goo.gl/NP8Aa
+type ExternalQuestion struct {
+ XMLName xml.Name `xml:"http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2006-07-14/ExternalQuestion.xsd ExternalQuestion"`
+ ExternalURL string
+ FrameHeight int
+}
+
+// Holds the html content of the HTMLQuestion.
+type HTMLContent struct {
+ Content string `xml:",innerxml"`
+}
+
+// Data structure holding the contents of an "html"
+// question. http://goo.gl/hQn5An
+type HTMLQuestion struct {
+ XMLName xml.Name `xml:"http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2011-11-11/HTMLQuestion.xsd HTMLQuestion"`
+ HTMLContent HTMLContent
+
+ FrameHeight int
+}
+
+// The data structure representing a "human interface task" (HIT)
+// Currently only supports "external" questions, because Go
+// structs don't support union types. http://goo.gl/NP8Aa
+// This type is returned, for example, from SearchHITs
+// http://goo.gl/PskcX
+type HIT struct {
+ Request xmlRequest
+
+ HITId string
+ HITTypeId string
+ CreationTime string
+ Title string
+ Description string
+ Keywords string
+ HITStatus string
+ Reward Price
+ LifetimeInSeconds uint
+ AssignmentDurationInSeconds uint
+ MaxAssignments uint
+ AutoApprovalDelayInSeconds uint
+ QualificationRequirement QualificationRequirement
+ Question interface{}
+ RequesterAnnotation string
+ NumberofSimilarHITs uint
+ HITReviewStatus string
+ NumberOfAssignmentsPending uint
+ NumberOfAssignmentsAvailable uint
+ NumberOfAssignmentsCompleted uint
+}
+
+// The main data structure returned by SearchHITs
+// http://goo.gl/PskcX
+type SearchHITsResult struct {
+ NumResults uint
+ PageNumber uint
+ TotalNumResults uint
+ HITs []HIT `xml:"HIT"`
+}
+
+// The wrapper data structure returned by SearchHITs
+// http://goo.gl/PskcX
+type SearchHITsResponse struct {
+ RequestId string `xml:"OperationRequest>RequestId"`
+ SearchHITsResult SearchHITsResult
+}
+
+// The wrapper data structure returned by CreateHIT
+// http://goo.gl/PskcX
+type CreateHITResponse struct {
+ RequestId string `xml:"OperationRequest>RequestId"`
+ HIT HIT
+}
+
+type Assignment struct {
+ AssignmentId string
+ WorkerId string
+ HITId string
+ AssignmentStatus string
+ AutoApprovalTime string
+ AcceptTime string
+ SubmitTime string
+ ApprovalTime string
+ Answer string
+}
+
+func (a Assignment) Answers() (answers map[string]string) {
+ answers = make(map[string]string)
+
+ decoder := xml.NewDecoder(strings.NewReader(a.Answer))
+
+ for {
+ token, _ := decoder.Token()
+ if token == nil {
+ break
+ }
+ switch startElement := token.(type) {
+ case xml.StartElement:
+ if startElement.Name.Local == "Answer" {
+ var answer struct {
+ QuestionIdentifier string
+ FreeText string
+ }
+
+ decoder.DecodeElement(&answer, &startElement)
+ answers[answer.QuestionIdentifier] = answer.FreeText
+ }
+ }
+ }
+
+ return
+}
+
+type GetAssignmentsForHITResponse struct {
+ RequestId string `xml:"OperationRequest>RequestId"`
+ GetAssignmentsForHITResult struct {
+ Request xmlRequest
+ NumResults uint
+ TotalNumResults uint
+ PageNumber uint
+ Assignment Assignment
+ }
+}
+
+/*
+CreateHIT corresponds to the "CreateHIT" operation of the Mechanical Turk
+API. Currently only supports "external" questions (see "HIT" struct above).
+
+Here are the detailed description for the parameters:
+
+ title Required. A title should be short and descriptive about the
+ kind of task the HIT contains. On the Amazon Mechanical Turk
+ web site, the HIT title appears in search results, and
+ everywhere the HIT is mentioned.
+ description Required. A description includes detailed information about the
+ kind of task the HIT contains. On the Amazon Mechanical Turk
+ web site, the HIT description appears in the expanded view of
+ search results, and in the HIT and assignment screens. A good
+ description gives the user enough information to evaluate the
+ HIT before accepting it.
+ question Required. The data the person completing the HIT uses to produce
+ the results. Consstraints: Must be a QuestionForm data structure,
+ an ExternalQuestion data structure, or an HTMLQuestion data
+ structure. The XML question data must not be larger than 64
+ kilobytes (65,535 bytes) in size, including whitespace.
+ reward Required. The amount of money the Requester will pay a Worker
+ for successfully completing the HIT.
+ assignmentDurationInSeconds Required. The amount of time, in seconds, that
+ a Worker has to complete the HIT after accepting
+ it. If a Worker does not complete the assignment
+ within the specified duration, the assignment is
+ considered abandoned. If the HIT is still
+ active (that is, its lifetime has not elapsed),
+ the assignment becomes available for other users
+ to find and accept. Valid Values: any integer
+ between 30 (30 seconds) and 31536000 (365 days).
+ lifetimeInSeconds Required. An amount of time, in seconds, after which the
+ HIT is no longer available for users to accept. After
+ the lifetime of the HIT elapses, the HIT no longer
+ appears in HIT searches, even if not all of the
+ assignments for the HIT have been accepted. Valid Values:
+ any integer between 30 (30 seconds) and 31536000 (365 days).
+ keywords One or more words or phrases that describe the HIT,
+ separated by commas. These words are used in searches to
+ find HITs. Constraints: cannot be more than 1,000
+ characters.
+ maxAssignments The number of times the HIT can be accepted and completed
+ before the HIT becomes unavailable. Valid Values: any
+ integer between 1 and 1000000000 (1 billion). Default: 1
+ qualificationRequirement A condition that a Worker's Qualifications must
+ meet before the Worker is allowed to accept and
+ complete the HIT. Constraints: no more than 10
+ QualificationRequirement for each HIT.
+ requesterAnnotation An arbitrary data field. The RequesterAnnotation
+ parameter lets your application attach arbitrary data to
+ the HIT for tracking purposes. For example, the
+ RequesterAnnotation parameter could be an identifier
+ internal to the Requester's application that corresponds
+ with the HIT. Constraints: must not be longer than 255
+ characters in length.
+
+Reference:
+http://docs.aws.amazon.com/AWSMechTurk/latest/AWSMturkAPI/ApiReference_CreateHITOperation.html
+*/
+func (mt *MTurk) CreateHIT(
+ title, description string,
+ question interface{},
+ reward Price,
+ assignmentDurationInSeconds,
+ lifetimeInSeconds uint,
+ keywords string,
+ maxAssignments uint,
+ qualificationRequirement *QualificationRequirement,
+ requesterAnnotation string) (h *HIT, err error) {
+
+ params := make(map[string]string)
+ params["Title"] = title
+ params["Description"] = description
+ params["Question"], err = xmlEncode(&question)
+ if err != nil {
+ return
+ }
+ params["Reward.1.Amount"] = reward.Amount
+ params["Reward.1.CurrencyCode"] = reward.CurrencyCode
+ params["AssignmentDurationInSeconds"] = strconv.FormatUint(uint64(assignmentDurationInSeconds), 10)
+
+ params["LifetimeInSeconds"] = strconv.FormatUint(uint64(lifetimeInSeconds), 10)
+ if keywords != "" {
+ params["Keywords"] = keywords
+ }
+ if maxAssignments != 0 {
+ params["MaxAssignments"] = strconv.FormatUint(uint64(maxAssignments), 10)
+ }
+ if qualificationRequirement != nil {
+ params["QualificationRequirement"], err = xmlEncode(qualificationRequirement)
+ if err != nil {
+ return
+ }
+ }
+ if requesterAnnotation != "" {
+ params["RequesterAnnotation"] = requesterAnnotation
+ }
+
+ var response CreateHITResponse
+ err = mt.query(params, "CreateHIT", &response)
+ if err == nil {
+ h = &response.HIT
+ }
+ return
+}
+
+// Corresponds to the "CreateHIT" operation of the Mechanical Turk
+// API, using an existing "hit type". http://goo.gl/cDBRc Currently only
+// supports "external" questions (see "HIT" struct above). If
+// "maxAssignments" or "requesterAnnotation" are the zero value for
+// their types, they will not be included in the request.
+func (mt *MTurk) CreateHITOfType(hitTypeId string, q ExternalQuestion, lifetimeInSeconds uint, maxAssignments uint, requesterAnnotation string) (h *HIT, err error) {
+ params := make(map[string]string)
+ params["HITTypeId"] = hitTypeId
+ params["Question"], err = xmlEncode(&q)
+ if err != nil {
+ return
+ }
+ params["LifetimeInSeconds"] = strconv.FormatUint(uint64(lifetimeInSeconds), 10)
+ if maxAssignments != 0 {
+ params["MaxAssignments"] = strconv.FormatUint(uint64(maxAssignments), 10)
+ }
+ if requesterAnnotation != "" {
+ params["RequesterAnnotation"] = requesterAnnotation
+ }
+
+ var response CreateHITResponse
+ err = mt.query(params, "CreateHIT", &response)
+ if err == nil {
+ h = &response.HIT
+ }
+ return
+}
+
+// Get the Assignments for a HIT.
+func (mt *MTurk) GetAssignmentsForHIT(hitId string) (r *Assignment, err error) {
+ params := make(map[string]string)
+ params["HITId"] = hitId
+ var response GetAssignmentsForHITResponse
+ err = mt.query(params, "GetAssignmentsForHIT", &response)
+ if err == nil {
+ r = &response.GetAssignmentsForHITResult.Assignment
+ }
+ return
+}
+
+// Corresponds to "SearchHITs" operation of Mechanical Turk. http://goo.gl/PskcX
+// Currenlty supports none of the optional parameters.
+func (mt *MTurk) SearchHITs() (s *SearchHITsResult, err error) {
+ params := make(map[string]string)
+ var response SearchHITsResponse
+ err = mt.query(params, "SearchHITs", &response)
+ if err == nil {
+ s = &response.SearchHITsResult
+ }
+ return
+}
+
+// Adds common parameters to the "params" map, signs the request,
+// adds the signature to the "params" map and sends the request
+// to the server. It then unmarshals the response in to the "resp"
+// parameter using xml.Unmarshal()
+func (mt *MTurk) query(params map[string]string, operation string, resp interface{}) error {
+ service := "AWSMechanicalTurkRequester"
+ timestamp := time.Now().UTC().Format("2006-01-02T15:04:05Z")
+
+ params["AWSAccessKeyId"] = mt.Auth.AccessKey
+ params["Service"] = service
+ params["Timestamp"] = timestamp
+ params["Operation"] = operation
+
+ // make a copy
+ url := *mt.URL
+
+ sign(mt.Auth, service, operation, timestamp, params)
+ url.RawQuery = multimap(params).Encode()
+ r, err := http.Get(url.String())
+ if err != nil {
+ return err
+ }
+ //dump, _ := httputil.DumpResponse(r, true)
+ //println("DUMP:\n", string(dump))
+ if r.StatusCode != 200 {
+ return errors.New(fmt.Sprintf("%d: unexpected status code", r.StatusCode))
+ }
+ dec := xml.NewDecoder(r.Body)
+ err = dec.Decode(resp)
+ r.Body.Close()
+ return err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+func xmlEncode(i interface{}) (s string, err error) {
+ var buf []byte
+ buf, err = xml.Marshal(i)
+ if err != nil {
+ return
+ }
+ s = string(buf)
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/exp/mturk/mturk_test.go b/vendor/github.com/goamz/goamz/exp/mturk/mturk_test.go
new file mode 100644
index 000000000..0c546571f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/mturk/mturk_test.go
@@ -0,0 +1,170 @@
+package mturk_test
+
+import (
+ "net/url"
+ "testing"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/exp/mturk"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ mturk *mturk.MTurk
+}
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ u, err := url.Parse(testServer.URL)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ s.mturk = &mturk.MTurk{
+ Auth: auth,
+ URL: u,
+ }
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestCreateHITExternalQuestion(c *C) {
+ testServer.Response(200, nil, BasicHitResponse)
+
+ question := mturk.ExternalQuestion{
+ ExternalURL: "http://www.amazon.com",
+ FrameHeight: 200,
+ }
+ reward := mturk.Price{
+ Amount: "0.01",
+ CurrencyCode: "USD",
+ }
+ hit, err := s.mturk.CreateHIT("title", "description", question, reward, 1, 2, "key1,key2", 3, nil, "annotation")
+
+ testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(hit, NotNil)
+
+ c.Assert(hit.HITId, Equals, "28J4IXKO2L927XKJTHO34OCDNASCDW")
+ c.Assert(hit.HITTypeId, Equals, "2XZ7D1X3V0FKQVW7LU51S7PKKGFKDF")
+}
+
+func (s *S) TestCreateHITHTMLQuestion(c *C) {
+ testServer.Response(200, nil, BasicHitResponse)
+
+ question := mturk.HTMLQuestion{
+ HTMLContent: mturk.HTMLContent{`<![CDATA[
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
+ <script type='text/javascript' src='https://s3.amazonaws.com/mturk-public/externalHIT_v1.js'></script>
+ </head>
+ <body>
+ <form name='mturk_form' method='post' id='mturk_form' action='https://www.mturk.com/mturk/externalSubmit'>
+ <input type='hidden' value='' name='assignmentId' id='assignmentId'/>
+ <h1>What's up?</h1>
+ <p><textarea name='comment' cols='80' rows='3'></textarea></p>
+ <p><input type='submit' id='submitButton' value='Submit' /></p></form>
+ <script language='Javascript'>turkSetAssignmentID();</script>
+ </body>
+</html>
+]]>`},
+ FrameHeight: 200,
+ }
+ reward := mturk.Price{
+ Amount: "0.01",
+ CurrencyCode: "USD",
+ }
+ hit, err := s.mturk.CreateHIT("title", "description", question, reward, 1, 2, "key1,key2", 3, nil, "annotation")
+
+ testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(hit, NotNil)
+
+ c.Assert(hit.HITId, Equals, "28J4IXKO2L927XKJTHO34OCDNASCDW")
+ c.Assert(hit.HITTypeId, Equals, "2XZ7D1X3V0FKQVW7LU51S7PKKGFKDF")
+}
+
+func (s *S) TestSearchHITs(c *C) {
+ testServer.Response(200, nil, SearchHITResponse)
+
+ hitResult, err := s.mturk.SearchHITs()
+
+ c.Assert(err, IsNil)
+ c.Assert(hitResult, NotNil)
+
+ c.Assert(hitResult.NumResults, Equals, uint(1))
+ c.Assert(hitResult.PageNumber, Equals, uint(1))
+ c.Assert(hitResult.TotalNumResults, Equals, uint(1))
+
+ c.Assert(len(hitResult.HITs), Equals, 1)
+ c.Assert(hitResult.HITs[0].HITId, Equals, "2BU26DG67D1XTE823B3OQ2JF2XWF83")
+ c.Assert(hitResult.HITs[0].HITTypeId, Equals, "22OWJ5OPB0YV6IGL5727KP9U38P5XR")
+ c.Assert(hitResult.HITs[0].CreationTime, Equals, "2011-12-28T19:56:20Z")
+ c.Assert(hitResult.HITs[0].Title, Equals, "test hit")
+ c.Assert(hitResult.HITs[0].Description, Equals, "please disregard, testing only")
+ c.Assert(hitResult.HITs[0].HITStatus, Equals, "Reviewable")
+ c.Assert(hitResult.HITs[0].MaxAssignments, Equals, uint(1))
+ c.Assert(hitResult.HITs[0].Reward.Amount, Equals, "0.01")
+ c.Assert(hitResult.HITs[0].Reward.CurrencyCode, Equals, "USD")
+ c.Assert(hitResult.HITs[0].AutoApprovalDelayInSeconds, Equals, uint(2592000))
+ c.Assert(hitResult.HITs[0].AssignmentDurationInSeconds, Equals, uint(30))
+ c.Assert(hitResult.HITs[0].NumberOfAssignmentsPending, Equals, uint(0))
+ c.Assert(hitResult.HITs[0].NumberOfAssignmentsAvailable, Equals, uint(1))
+ c.Assert(hitResult.HITs[0].NumberOfAssignmentsCompleted, Equals, uint(0))
+}
+
+func (s *S) TestGetAssignmentsForHIT_NoAnswer(c *C) {
+ testServer.Response(200, nil, GetAssignmentsForHITNoAnswerResponse)
+
+ assignment, err := s.mturk.GetAssignmentsForHIT("emptyassignment")
+
+ testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(assignment, NotNil)
+
+ c.Assert(assignment.HITId, Equals, "")
+}
+
+func (s *S) TestGetAssignmentsForHIT_Answer(c *C) {
+ testServer.Response(200, nil, GetAssignmentsForHITAnswerResponse)
+
+ assignment, err := s.mturk.GetAssignmentsForHIT("emptyassignment")
+
+ testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(assignment, NotNil)
+
+ c.Assert(assignment.AssignmentId, Equals, "2QKNTL0XULRGFAQWUWDD05FP94V2O3")
+ c.Assert(assignment.WorkerId, Equals, "A1ZUQ2YDM61713")
+ c.Assert(assignment.HITId, Equals, "2W36VCPWZ9RN5DX1MBJ7VN3D6WEPAM")
+ c.Assert(assignment.AssignmentStatus, Equals, "Submitted")
+ c.Assert(assignment.AutoApprovalTime, Equals, "2014-02-26T09:39:48Z")
+ c.Assert(assignment.AcceptTime, Equals, "2014-01-27T09:39:38Z")
+ c.Assert(assignment.SubmitTime, Equals, "2014-01-27T09:39:48Z")
+ c.Assert(assignment.ApprovalTime, Equals, "")
+
+ answers := assignment.Answers()
+ c.Assert(len(answers), Equals, 4)
+ c.Assert(answers["tags"], Equals, "asd")
+ c.Assert(answers["text_in_image"], Equals, "asd")
+ c.Assert(answers["is_pattern"], Equals, "yes")
+ c.Assert(answers["is_map"], Equals, "yes")
+}
diff --git a/vendor/github.com/goamz/goamz/exp/mturk/responses_test.go b/vendor/github.com/goamz/goamz/exp/mturk/responses_test.go
new file mode 100644
index 000000000..abc483945
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/mturk/responses_test.go
@@ -0,0 +1,36 @@
+package mturk_test
+
+var BasicHitResponse = `<?xml version="1.0"?>
+<CreateHITResponse><OperationRequest><RequestId>643b794b-66b6-4427-bb8a-4d3df5c9a20e</RequestId></OperationRequest><HIT><Request><IsValid>True</IsValid></Request><HITId>28J4IXKO2L927XKJTHO34OCDNASCDW</HITId><HITTypeId>2XZ7D1X3V0FKQVW7LU51S7PKKGFKDF</HITTypeId></HIT></CreateHITResponse>
+`
+
+var SearchHITResponse = `<?xml version="1.0"?>
+<SearchHITsResponse><OperationRequest><RequestId>38862d9c-f015-4177-a2d3-924110a9d6f2</RequestId></OperationRequest><SearchHITsResult><Request><IsValid>True</IsValid></Request><NumResults>1</NumResults><TotalNumResults>1</TotalNumResults><PageNumber>1</PageNumber><HIT><HITId>2BU26DG67D1XTE823B3OQ2JF2XWF83</HITId><HITTypeId>22OWJ5OPB0YV6IGL5727KP9U38P5XR</HITTypeId><CreationTime>2011-12-28T19:56:20Z</CreationTime><Title>test hit</Title><Description>please disregard, testing only</Description><HITStatus>Reviewable</HITStatus><MaxAssignments>1</MaxAssignments><Reward><Amount>0.01</Amount><CurrencyCode>USD</CurrencyCode><FormattedPrice>$0.01</FormattedPrice></Reward><AutoApprovalDelayInSeconds>2592000</AutoApprovalDelayInSeconds><Expiration>2011-12-28T19:56:50Z</Expiration><AssignmentDurationInSeconds>30</AssignmentDurationInSeconds><NumberOfAssignmentsPending>0</NumberOfAssignmentsPending><NumberOfAssignmentsAvailable>1</NumberOfAssignmentsAvailable><NumberOfAssignmentsCompleted>0</NumberOfAssignmentsCompleted></HIT></SearchHITsResult></SearchHITsResponse>
+`
+
+var GetAssignmentsForHITNoAnswerResponse = `<?xml version="1.0"?>
+<GetAssignmentsForHITResponse><OperationRequest><RequestId>536934be-a35b-4e4e-9822-72fbf36d5862</RequestId></OperationRequest><GetAssignmentsForHITResult><Request><IsValid>True</IsValid></Request><NumResults>0</NumResults><TotalNumResults>0</TotalNumResults><PageNumber>1</PageNumber></GetAssignmentsForHITResult></GetAssignmentsForHITResponse>
+`
+
+var GetAssignmentsForHITAnswerResponse = `<?xml version="1.0"?>
+<GetAssignmentsForHITResponse><OperationRequest><RequestId>2f113bdf-2e3e-4c5a-a396-3ed01384ecb9</RequestId></OperationRequest><GetAssignmentsForHITResult><Request><IsValid>True</IsValid></Request><NumResults>1</NumResults><TotalNumResults>1</TotalNumResults><PageNumber>1</PageNumber><Assignment><AssignmentId>2QKNTL0XULRGFAQWUWDD05FP94V2O3</AssignmentId><WorkerId>A1ZUQ2YDM61713</WorkerId><HITId>2W36VCPWZ9RN5DX1MBJ7VN3D6WEPAM</HITId><AssignmentStatus>Submitted</AssignmentStatus><AutoApprovalTime>2014-02-26T09:39:48Z</AutoApprovalTime><AcceptTime>2014-01-27T09:39:38Z</AcceptTime><SubmitTime>2014-01-27T09:39:48Z</SubmitTime><Answer>&lt;?xml version="1.0" encoding="UTF-8" standalone="no"?&gt;
+&lt;QuestionFormAnswers xmlns="http://mechanicalturk.amazonaws.com/AWSMechanicalTurkDataSchemas/2005-10-01/QuestionFormAnswers.xsd"&gt;
+&lt;Answer&gt;
+&lt;QuestionIdentifier&gt;tags&lt;/QuestionIdentifier&gt;
+&lt;FreeText&gt;asd&lt;/FreeText&gt;
+&lt;/Answer&gt;
+&lt;Answer&gt;
+&lt;QuestionIdentifier&gt;text_in_image&lt;/QuestionIdentifier&gt;
+&lt;FreeText&gt;asd&lt;/FreeText&gt;
+&lt;/Answer&gt;
+&lt;Answer&gt;
+&lt;QuestionIdentifier&gt;is_pattern&lt;/QuestionIdentifier&gt;
+&lt;FreeText&gt;yes&lt;/FreeText&gt;
+&lt;/Answer&gt;
+&lt;Answer&gt;
+&lt;QuestionIdentifier&gt;is_map&lt;/QuestionIdentifier&gt;
+&lt;FreeText&gt;yes&lt;/FreeText&gt;
+&lt;/Answer&gt;
+&lt;/QuestionFormAnswers&gt;
+</Answer></Assignment></GetAssignmentsForHITResult></GetAssignmentsForHITResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/exp/mturk/sign.go b/vendor/github.com/goamz/goamz/exp/mturk/sign.go
new file mode 100644
index 000000000..f2ff8cbfe
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/mturk/sign.go
@@ -0,0 +1,22 @@
+package mturk
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+ "encoding/base64"
+ "github.com/goamz/goamz/aws"
+)
+
+var b64 = base64.StdEncoding
+
+// ----------------------------------------------------------------------------
+// Mechanical Turk signing (http://goo.gl/wrzfn)
+func sign(auth aws.Auth, service, method, timestamp string, params map[string]string) {
+ payload := service + method + timestamp
+ hash := hmac.New(sha1.New, []byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum(nil))
+
+ params["Signature"] = string(signature)
+}
diff --git a/vendor/github.com/goamz/goamz/exp/mturk/sign_test.go b/vendor/github.com/goamz/goamz/exp/mturk/sign_test.go
new file mode 100644
index 000000000..49296eb73
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/mturk/sign_test.go
@@ -0,0 +1,19 @@
+package mturk_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/exp/mturk"
+ . "gopkg.in/check.v1"
+)
+
+// Mechanical Turk REST authentication docs: http://goo.gl/wrzfn
+
+var testAuth = aws.Auth{AccessKey: "user", SecretKey: "secret"}
+
+// == fIJy9wCApBNL2R4J2WjJGtIBFX4=
+func (s *S) TestBasicSignature(c *C) {
+ params := map[string]string{}
+ mturk.Sign(testAuth, "AWSMechanicalTurkRequester", "CreateHIT", "2012-02-16T20:30:47Z", params)
+ expected := "b/TnvzrdeD/L/EyzdFrznPXhido="
+ c.Assert(params["Signature"], Equals, expected)
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sdb/export_test.go b/vendor/github.com/goamz/goamz/exp/sdb/export_test.go
new file mode 100644
index 000000000..7807a914a
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sdb/export_test.go
@@ -0,0 +1,9 @@
+package sdb
+
+import (
+ "github.com/goamz/goamz/aws"
+)
+
+func Sign(auth aws.Auth, method, path string, params map[string][]string, headers map[string][]string) {
+ sign(auth, method, path, params, headers)
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sdb/responses_test.go b/vendor/github.com/goamz/goamz/exp/sdb/responses_test.go
new file mode 100644
index 000000000..034c2b31c
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sdb/responses_test.go
@@ -0,0 +1,120 @@
+package sdb_test
+
+var TestCreateDomainXmlOK = `
+<?xml version="1.0"?>
+<CreateDomainResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <ResponseMetadata>
+ <RequestId>63264005-7a5f-e01a-a224-395c63b89f6d</RequestId>
+ <BoxUsage>0.0055590279</BoxUsage>
+ </ResponseMetadata>
+</CreateDomainResponse>
+`
+
+var TestListDomainsXmlOK = `
+<?xml version="1.0"?>
+<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <ListDomainsResult>
+ <DomainName>Account</DomainName>
+ <DomainName>Domain</DomainName>
+ <DomainName>Record</DomainName>
+ </ListDomainsResult>
+ <ResponseMetadata>
+ <RequestId>15fcaf55-9914-63c2-21f3-951e31193790</RequestId>
+ <BoxUsage>0.0000071759</BoxUsage>
+ </ResponseMetadata>
+</ListDomainsResponse>
+`
+
+var TestListDomainsWithNextTokenXmlOK = `
+<?xml version="1.0"?>
+<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <ListDomainsResult>
+ <DomainName>Domain1-200706011651</DomainName>
+ <DomainName>Domain2-200706011652</DomainName>
+ <NextToken>TWV0ZXJpbmdUZXN0RG9tYWluMS0yMDA3MDYwMTE2NTY=</NextToken>
+ </ListDomainsResult>
+ <ResponseMetadata>
+ <RequestId>eb13162f-1b95-4511-8b12-489b86acfd28</RequestId>
+ <BoxUsage>0.0000219907</BoxUsage>
+ </ResponseMetadata>
+</ListDomainsResponse>
+`
+
+var TestDeleteDomainXmlOK = `
+<?xml version="1.0"?>
+<DeleteDomainResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <ResponseMetadata>
+ <RequestId>039e1e25-9a64-2a74-93da-2fda36122a97</RequestId>
+ <BoxUsage>0.0055590278</BoxUsage>
+ </ResponseMetadata>
+</DeleteDomainResponse>
+`
+
+var TestDomainMetadataXmlNoSuchDomain = `
+<?xml version="1.0"?>
+<Response xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <Errors>
+ <Error>
+ <Code>NoSuchDomain</Code>
+ <Message>The specified domain does not exist.</Message>
+ <BoxUsage>0.0000071759</BoxUsage>
+ </Error>
+ </Errors>
+ <RequestID>e050cea2-a772-f90e-2cb0-98ebd42c2898</RequestID>
+</Response>
+`
+
+var TestPutAttrsXmlOK = `
+<?xml version="1.0"?>
+<PutAttributesResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <ResponseMetadata>
+ <RequestId>490206ce-8292-456c-a00f-61b335eb202b</RequestId>
+ <BoxUsage>0.0000219907</BoxUsage>
+ </ResponseMetadata>
+</PutAttributesResponse>
+`
+
+var TestAttrsXmlOK = `
+<?xml version="1.0"?>
+<GetAttributesResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <GetAttributesResult>
+ <Attribute><Name>Color</Name><Value>Blue</Value></Attribute>
+ <Attribute><Name>Size</Name><Value>Med</Value></Attribute>
+ </GetAttributesResult>
+ <ResponseMetadata>
+ <RequestId>b1e8f1f7-42e9-494c-ad09-2674e557526d</RequestId>
+ <BoxUsage>0.0000219942</BoxUsage>
+ </ResponseMetadata>
+</GetAttributesResponse>
+`
+
+var TestSelectXmlOK = `
+<?xml version="1.0"?>
+<SelectResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
+ <SelectResult>
+ <Item>
+ <Name>Item_03</Name>
+ <Attribute><Name>Category</Name><Value>Clothes</Value></Attribute>
+ <Attribute><Name>Subcategory</Name><Value>Pants</Value></Attribute>
+ <Attribute><Name>Name</Name><Value>Sweatpants</Value></Attribute>
+ <Attribute><Name>Color</Name><Value>Blue</Value></Attribute>
+ <Attribute><Name>Color</Name><Value>Yellow</Value></Attribute>
+ <Attribute><Name>Color</Name><Value>Pink</Value></Attribute>
+ <Attribute><Name>Size</Name><Value>Large</Value></Attribute>
+ </Item>
+ <Item>
+ <Name>Item_06</Name>
+ <Attribute><Name>Category</Name><Value>Motorcycle Parts</Value></Attribute>
+ <Attribute><Name>Subcategory</Name><Value>Bodywork</Value></Attribute>
+ <Attribute><Name>Name</Name><Value>Fender Eliminator</Value></Attribute>
+ <Attribute><Name>Color</Name><Value>Blue</Value></Attribute>
+ <Attribute><Name>Make</Name><Value>Yamaha</Value></Attribute>
+ <Attribute><Name>Model</Name><Value>R1</Value></Attribute>
+ </Item>
+ </SelectResult>
+ <ResponseMetadata>
+ <RequestId>b1e8f1f7-42e9-494c-ad09-2674e557526d</RequestId>
+ <BoxUsage>0.0000219907</BoxUsage>
+ </ResponseMetadata>
+</SelectResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sdb.go b/vendor/github.com/goamz/goamz/exp/sdb/sdb.go
new file mode 100644
index 000000000..0d13f4a9e
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sdb/sdb.go
@@ -0,0 +1,413 @@
+//
+// goamz - Go packages to interact with the Amazon Web Services.
+//
+// https://wiki.ubuntu.com/goamz
+//
+// Copyright (c) 2011 AppsAttic Ltd.
+//
+// sdb package written by:
+//
+// Andrew Chilton <chilts@appsattic.com>
+// Brad Rydzewski <brad.rydzewski@gmail.com>
+
+// This package is in an experimental state, and does not currently
+// follow conventions and style of the rest of goamz or common
+// Go conventions. It must be polished before it's considered a
+// first-class package in goamz.
+package sdb
+
+// BUG: SelectResp isn't properly organized. It must change.
+
+//
+
+import (
+ "encoding/xml"
+ "github.com/goamz/goamz/aws"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "strconv"
+ "time"
+)
+
+const debug = false
+
+// The SDB type encapsulates operations with a specific SimpleDB region.
+type SDB struct {
+ aws.Auth
+ aws.Region
+ private byte // Reserve the right of using private data.
+}
+
+// New creates a new SDB.
+func New(auth aws.Auth, region aws.Region) *SDB {
+ return &SDB{auth, region, 0}
+}
+
+// The Domain type represents a collection of items that are described
+// by name-value attributes.
+type Domain struct {
+ *SDB
+ Name string
+}
+
+// Domain returns a Domain with the given name.
+func (sdb *SDB) Domain(name string) *Domain {
+ return &Domain{sdb, name}
+}
+
+// The Item type represent individual objects that contain one or more
+// name-value attributes stored within a SDB Domain as rows.
+type Item struct {
+ *SDB
+ *Domain
+ Name string
+}
+
+// Item returns an Item with the given name.
+func (domain *Domain) Item(name string) *Item {
+ return &Item{domain.SDB, domain, name}
+}
+
+// The Attr type represent categories of data that can be assigned to items.
+type Attr struct {
+ Name string
+ Value string
+}
+
+// ----------------------------------------------------------------------------
+// Service-level operations.
+
+// --- ListDomains
+
+// Response to a ListDomains request.
+//
+// See http://goo.gl/3u0Cf for more details.
+type ListDomainsResp struct {
+ Domains []string `xml:"ListDomainsResult>DomainName"`
+ NextToken string `xml:"ListDomainsResult>NextToken"`
+ ResponseMetadata ResponseMetadata
+}
+
+// ListDomains lists all domains in sdb.
+//
+// See http://goo.gl/Dsw15 for more details.
+func (sdb *SDB) ListDomains() (resp *ListDomainsResp, err error) {
+ return sdb.ListDomainsN(0, "")
+}
+
+// ListDomainsN lists domains in sdb up to maxDomains.
+// If nextToken is not empty, domains listed will start at the given token.
+//
+// See http://goo.gl/Dsw15 for more details.
+func (sdb *SDB) ListDomainsN(maxDomains int, nextToken string) (resp *ListDomainsResp, err error) {
+ params := makeParams("ListDomains")
+ if maxDomains != 0 {
+ params["MaxNumberOfDomains"] = []string{strconv.Itoa(maxDomains)}
+ }
+ if nextToken != "" {
+ params["NextToken"] = []string{nextToken}
+ }
+ resp = &ListDomainsResp{}
+ err = sdb.query(nil, nil, params, nil, resp)
+ return
+}
+
+// --- SelectExpression
+
+// Response to a Select request.
+//
+// See http://goo.gl/GTsSZ for more details.
+type SelectResp struct {
+ Items []struct {
+ Name string
+ Attrs []Attr `xml:"Attribute"`
+ } `xml:"SelectResult>Item"`
+ ResponseMetadata ResponseMetadata
+}
+
+// Select returns a set of items and attributes that match expr.
+// Select is similar to the standard SQL SELECT statement.
+//
+// See http://goo.gl/GTsSZ for more details.
+func (sdb *SDB) Select(expr string, consistent bool) (resp *SelectResp, err error) {
+ resp = &SelectResp{}
+ params := makeParams("Select")
+ params["SelectExpression"] = []string{expr}
+ if consistent {
+ params["ConsistentRead"] = []string{"true"}
+ }
+ err = sdb.query(nil, nil, params, nil, resp)
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Domain-level operations.
+
+// --- CreateDomain
+
+// CreateDomain creates a new domain.
+//
+// See http://goo.gl/jDjGH for more details.
+func (domain *Domain) CreateDomain() (resp *SimpleResp, err error) {
+ params := makeParams("CreateDomain")
+ resp = &SimpleResp{}
+ err = domain.SDB.query(domain, nil, params, nil, resp)
+ return
+}
+
+// DeleteDomain deletes an existing domain.
+//
+// See http://goo.gl/S0dCL for more details.
+func (domain *Domain) DeleteDomain() (resp *SimpleResp, err error) {
+ params := makeParams("DeleteDomain")
+ resp = &SimpleResp{}
+ err = domain.SDB.query(domain, nil, params, nil, resp)
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Item-level operations.
+
+type PutAttrs struct {
+ attrs []Attr
+ expected []Attr
+ replace map[string]bool
+ missing map[string]bool
+}
+
+func (pa *PutAttrs) Add(name, value string) {
+ pa.attrs = append(pa.attrs, Attr{name, value})
+}
+
+func (pa *PutAttrs) Replace(name, value string) {
+ pa.Add(name, value)
+ if pa.replace == nil {
+ pa.replace = make(map[string]bool)
+ }
+ pa.replace[name] = true
+}
+
+// The PutAttrs request will only succeed if the existing
+// item in SimpleDB contains a matching name / value pair.
+func (pa *PutAttrs) IfValue(name, value string) {
+ pa.expected = append(pa.expected, Attr{name, value})
+}
+
+// Flag to test the existence of an attribute while performing
+// conditional updates. X can be any positive integer or 0.
+//
+// This should set Expected.N.Name=name and Expected.N.Exists=false
+func (pa *PutAttrs) IfMissing(name string) {
+ if pa.missing == nil {
+ pa.missing = make(map[string]bool)
+ }
+ pa.missing[name] = true
+}
+
+// PutAttrs adds attrs to item.
+//
+// See http://goo.gl/yTAV4 for more details.
+func (item *Item) PutAttrs(attrs *PutAttrs) (resp *SimpleResp, err error) {
+ params := makeParams("PutAttributes")
+ resp = &SimpleResp{}
+
+ // copy these attrs over to the parameters
+ itemNum := 1
+ for _, attr := range attrs.attrs {
+ itemNumStr := strconv.Itoa(itemNum)
+
+ // do the name, value and replace
+ params["Attribute."+itemNumStr+".Name"] = []string{attr.Name}
+ params["Attribute."+itemNumStr+".Value"] = []string{attr.Value}
+
+ if _, ok := attrs.replace[attr.Name]; ok {
+ params["Attribute."+itemNumStr+".Replace"] = []string{"true"}
+ }
+
+ itemNum++
+ }
+
+ //append expected values to params
+ expectedNum := 1
+ for _, attr := range attrs.expected {
+ expectedNumStr := strconv.Itoa(expectedNum)
+ params["Expected."+expectedNumStr+".Name"] = []string{attr.Name}
+ params["Expected."+expectedNumStr+".Value"] = []string{attr.Value}
+
+ if attrs.missing[attr.Name] {
+ params["Expected."+expectedNumStr+".Exists"] = []string{"false"}
+ }
+ expectedNum++
+ }
+
+ err = item.query(params, nil, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// Response to an Attrs request.
+//
+// See http://goo.gl/45X1M for more details.
+type AttrsResp struct {
+ Attrs []Attr `xml:"GetAttributesResult>Attribute"`
+ ResponseMetadata ResponseMetadata
+}
+
+// Attrs returns one or more of the named attributes, or
+// all of item's attributes if names is nil.
+// If consistent is true, previous writes will necessarily
+// be observed.
+//
+// See http://goo.gl/45X1M for more details.
+func (item *Item) Attrs(names []string, consistent bool) (resp *AttrsResp, err error) {
+ params := makeParams("GetAttributes")
+ params["ItemName"] = []string{item.Name}
+ if consistent {
+ params["ConsistentRead"] = []string{"true"}
+ }
+
+ // Copy these attributes over to the parameters
+ for i, name := range names {
+ params["AttributeName."+strconv.Itoa(i+1)] = []string{name}
+ }
+
+ resp = &AttrsResp{}
+ err = item.query(params, nil, resp)
+ if err != nil {
+ return nil, err
+ }
+ return
+}
+
+// ----------------------------------------------------------------------------
+// Generic data structures for all requests/responses.
+
+// Error encapsulates an error returned by SDB.
+type Error struct {
+ StatusCode int // HTTP status code (200, 403, ...)
+ StatusMsg string // HTTP status message ("Service Unavailable", "Bad Request", ...)
+ Code string // SimpleDB error code ("InvalidParameterValue", ...)
+ Message string // The human-oriented error message
+ RequestId string // A unique ID for this request
+ BoxUsage float64 // The measure of machine utilization for this request.
+}
+
+func (err *Error) Error() string {
+ return err.Message
+}
+
+// SimpleResp represents a response to an SDB request which on success
+// will return no other information besides ResponseMetadata.
+type SimpleResp struct {
+ ResponseMetadata ResponseMetadata
+}
+
+// ResponseMetadata
+type ResponseMetadata struct {
+ RequestId string // A unique ID for tracking the request
+ BoxUsage float64 // The measure of machine utilization for this request.
+}
+
+func buildError(r *http.Response) error {
+ err := Error{}
+ err.StatusCode = r.StatusCode
+ err.StatusMsg = r.Status
+ xml.NewDecoder(r.Body).Decode(&err)
+ return &err
+}
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+func (item *Item) query(params url.Values, headers http.Header, resp interface{}) error {
+ return item.Domain.SDB.query(item.Domain, item, params, headers, resp)
+}
+
+func (domain *Domain) query(item *Item, params url.Values, headers http.Header, resp interface{}) error {
+ return domain.SDB.query(domain, item, params, headers, resp)
+}
+
+func (sdb *SDB) query(domain *Domain, item *Item, params url.Values, headers http.Header, resp interface{}) error {
+ // all SimpleDB operations have path="/"
+ method := "GET"
+ path := "/"
+
+ // if we have been given no headers or params, create them
+ if headers == nil {
+ headers = map[string][]string{}
+ }
+ if params == nil {
+ params = map[string][]string{}
+ }
+
+ // setup some default parameters
+ params["Version"] = []string{"2009-04-15"}
+ params["Timestamp"] = []string{time.Now().UTC().Format(time.RFC3339)}
+
+ // set the DomainName param (every request must have one)
+ if domain != nil {
+ params["DomainName"] = []string{domain.Name}
+ }
+
+ // set the ItemName if we have one
+ if item != nil {
+ params["ItemName"] = []string{item.Name}
+ }
+
+ // check the endpoint URL
+ u, err := url.Parse(sdb.Region.SDBEndpoint)
+ if err != nil {
+ return err
+ }
+ headers["Host"] = []string{u.Host}
+ sign(sdb.Auth, method, path, params, headers)
+
+ u.Path = path
+ if len(params) > 0 {
+ u.RawQuery = params.Encode()
+ }
+ req := http.Request{
+ URL: u,
+ Method: method,
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Close: true,
+ Header: headers,
+ }
+
+ if v, ok := headers["Content-Length"]; ok {
+ req.ContentLength, _ = strconv.ParseInt(v[0], 10, 64)
+ delete(headers, "Content-Length")
+ }
+
+ r, err := http.DefaultClient.Do(&req)
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("response:\n")
+ log.Printf("%v\n}\n", string(dump))
+ }
+
+ // status code is always 200 when successful (since we're always doing a GET)
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+
+ // everything was fine, so unmarshal the XML and return what it's err is (if any)
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+func makeParams(action string) map[string][]string {
+ params := make(map[string][]string)
+ params["Action"] = []string{action}
+ return params
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go b/vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go
new file mode 100644
index 000000000..83e7f9f86
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sdb/sdb_test.go
@@ -0,0 +1,219 @@
+package sdb_test
+
+import (
+ "testing"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/exp/sdb"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ sdb *sdb.SDB
+}
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.sdb = sdb.New(auth, aws.Region{SDBEndpoint: testServer.URL})
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestCreateDomainOK(c *C) {
+ testServer.Response(200, nil, TestCreateDomainXmlOK)
+
+ domain := s.sdb.Domain("domain")
+ resp, err := domain.CreateDomain()
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "63264005-7a5f-e01a-a224-395c63b89f6d")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0055590279)
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestListDomainsOK(c *C) {
+ testServer.Response(200, nil, TestListDomainsXmlOK)
+
+ resp, err := s.sdb.ListDomains()
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "15fcaf55-9914-63c2-21f3-951e31193790")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000071759)
+ c.Assert(resp.Domains, DeepEquals, []string{"Account", "Domain", "Record"})
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestListDomainsWithNextTokenXmlOK(c *C) {
+ testServer.Response(200, nil, TestListDomainsWithNextTokenXmlOK)
+
+ resp, err := s.sdb.ListDomains()
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "eb13162f-1b95-4511-8b12-489b86acfd28")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219907)
+ c.Assert(resp.Domains, DeepEquals, []string{"Domain1-200706011651", "Domain2-200706011652"})
+ c.Assert(resp.NextToken, Equals, "TWV0ZXJpbmdUZXN0RG9tYWluMS0yMDA3MDYwMTE2NTY=")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestDeleteDomainOK(c *C) {
+ testServer.Response(200, nil, TestDeleteDomainXmlOK)
+
+ domain := s.sdb.Domain("domain")
+ resp, err := domain.DeleteDomain()
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "039e1e25-9a64-2a74-93da-2fda36122a97")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0055590278)
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestPutAttrsOK(c *C) {
+ testServer.Response(200, nil, TestPutAttrsXmlOK)
+
+ domain := s.sdb.Domain("MyDomain")
+ item := domain.Item("Item123")
+
+ putAttrs := new(sdb.PutAttrs)
+ putAttrs.Add("FirstName", "john")
+ putAttrs.Add("LastName", "smith")
+ putAttrs.Replace("MiddleName", "jacob")
+
+ putAttrs.IfValue("FirstName", "john")
+ putAttrs.IfMissing("FirstName")
+
+ resp, err := item.PutAttrs(putAttrs)
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Form["Action"], DeepEquals, []string{"PutAttributes"})
+ c.Assert(req.Form["ItemName"], DeepEquals, []string{"Item123"})
+ c.Assert(req.Form["DomainName"], DeepEquals, []string{"MyDomain"})
+ c.Assert(req.Form["Attribute.1.Name"], DeepEquals, []string{"FirstName"})
+ c.Assert(req.Form["Attribute.1.Value"], DeepEquals, []string{"john"})
+ c.Assert(req.Form["Attribute.2.Name"], DeepEquals, []string{"LastName"})
+ c.Assert(req.Form["Attribute.2.Value"], DeepEquals, []string{"smith"})
+ c.Assert(req.Form["Attribute.3.Name"], DeepEquals, []string{"MiddleName"})
+ c.Assert(req.Form["Attribute.3.Value"], DeepEquals, []string{"jacob"})
+ c.Assert(req.Form["Attribute.3.Replace"], DeepEquals, []string{"true"})
+
+ c.Assert(req.Form["Expected.1.Name"], DeepEquals, []string{"FirstName"})
+ c.Assert(req.Form["Expected.1.Value"], DeepEquals, []string{"john"})
+ c.Assert(req.Form["Expected.1.Exists"], DeepEquals, []string{"false"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "490206ce-8292-456c-a00f-61b335eb202b")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219907)
+
+}
+
+func (s *S) TestAttrsOK(c *C) {
+ testServer.Response(200, nil, TestAttrsXmlOK)
+
+ domain := s.sdb.Domain("MyDomain")
+ item := domain.Item("Item123")
+
+ resp, err := item.Attrs(nil, true)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+ c.Assert(req.Form["Action"], DeepEquals, []string{"GetAttributes"})
+ c.Assert(req.Form["ItemName"], DeepEquals, []string{"Item123"})
+ c.Assert(req.Form["DomainName"], DeepEquals, []string{"MyDomain"})
+ c.Assert(req.Form["ConsistentRead"], DeepEquals, []string{"true"})
+
+ c.Assert(resp.Attrs[0].Name, Equals, "Color")
+ c.Assert(resp.Attrs[0].Value, Equals, "Blue")
+ c.Assert(resp.Attrs[1].Name, Equals, "Size")
+ c.Assert(resp.Attrs[1].Value, Equals, "Med")
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "b1e8f1f7-42e9-494c-ad09-2674e557526d")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219942)
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestAttrsSelectOK(c *C) {
+ testServer.Response(200, nil, TestAttrsXmlOK)
+
+ domain := s.sdb.Domain("MyDomain")
+ item := domain.Item("Item123")
+
+ resp, err := item.Attrs([]string{"Color", "Size"}, true)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+ c.Assert(req.Form["Action"], DeepEquals, []string{"GetAttributes"})
+ c.Assert(req.Form["ItemName"], DeepEquals, []string{"Item123"})
+ c.Assert(req.Form["DomainName"], DeepEquals, []string{"MyDomain"})
+ c.Assert(req.Form["ConsistentRead"], DeepEquals, []string{"true"})
+ c.Assert(req.Form["AttributeName.1"], DeepEquals, []string{"Color"})
+ c.Assert(req.Form["AttributeName.2"], DeepEquals, []string{"Size"})
+
+ c.Assert(resp.Attrs[0].Name, Equals, "Color")
+ c.Assert(resp.Attrs[0].Value, Equals, "Blue")
+ c.Assert(resp.Attrs[1].Name, Equals, "Size")
+ c.Assert(resp.Attrs[1].Value, Equals, "Med")
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "b1e8f1f7-42e9-494c-ad09-2674e557526d")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219942)
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSelectOK(c *C) {
+ testServer.Response(200, nil, TestSelectXmlOK)
+
+ resp, err := s.sdb.Select("select Color from MyDomain where Color like 'Blue%'", true)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+ c.Assert(req.Form["Action"], DeepEquals, []string{"Select"})
+ c.Assert(req.Form["ConsistentRead"], DeepEquals, []string{"true"})
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "b1e8f1f7-42e9-494c-ad09-2674e557526d")
+ c.Assert(resp.ResponseMetadata.BoxUsage, Equals, 0.0000219907)
+ c.Assert(len(resp.Items), Equals, 2)
+ c.Assert(resp.Items[0].Name, Equals, "Item_03")
+ c.Assert(resp.Items[1].Name, Equals, "Item_06")
+ c.Assert(resp.Items[0].Attrs[0].Name, Equals, "Category")
+ c.Assert(resp.Items[0].Attrs[0].Value, Equals, "Clothes")
+
+ c.Assert(err, IsNil)
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sign.go b/vendor/github.com/goamz/goamz/exp/sdb/sign.go
new file mode 100644
index 000000000..040ed5385
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sdb/sign.go
@@ -0,0 +1,54 @@
+package sdb
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "github.com/goamz/goamz/aws"
+ "net/http"
+ "net/url"
+ "sort"
+ "strings"
+)
+
+var b64 = base64.StdEncoding
+
+// ----------------------------------------------------------------------------
+// SimpleDB signing (http://goo.gl/CaY81)
+
+func sign(auth aws.Auth, method, path string, params url.Values, headers http.Header) {
+ var host string
+ for k, v := range headers {
+ k = strings.ToLower(k)
+ switch k {
+ case "host":
+ host = v[0]
+ }
+ }
+
+ // set up some defaults used for signing the request
+ params["AWSAccessKeyId"] = []string{auth.AccessKey}
+ params["SignatureVersion"] = []string{"2"}
+ params["SignatureMethod"] = []string{"HmacSHA256"}
+ if auth.Token() != "" {
+ params["SecurityToken"] = []string{auth.Token()}
+ }
+
+ // join up all the incoming params
+ var sarray []string
+ for k, v := range params {
+ sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(v[0]))
+ }
+ sort.StringSlice(sarray).Sort()
+ joined := strings.Join(sarray, "&")
+
+ // create the payload, sign it and create the signature
+ payload := strings.Join([]string{method, host, "/", joined}, "\n")
+ hash := hmac.New(sha256.New, []byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum(nil))
+
+ // add the signature to the outgoing params
+ params["Signature"] = []string{string(signature)}
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sdb/sign_test.go b/vendor/github.com/goamz/goamz/exp/sdb/sign_test.go
new file mode 100644
index 000000000..f45ad15e1
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sdb/sign_test.go
@@ -0,0 +1,29 @@
+package sdb_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/exp/sdb"
+ . "gopkg.in/check.v1"
+)
+
+// SimpleDB ReST authentication docs: http://goo.gl/CaY81
+
+var testAuth = aws.Auth{AccessKey: "access-key-id-s8eBOWuU", SecretKey: "secret-access-key-UkQjTLd9"}
+
+func (s *S) TestSignExampleDomainCreate(c *C) {
+ method := "GET"
+ params := map[string][]string{
+ "Action": {"CreateDomain"},
+ "DomainName": {"MyDomain"},
+ "Timestamp": {"2011-08-20T07:23:57+12:00"},
+ "Version": {"2009-04-15"},
+ }
+ headers := map[string][]string{
+ "Host": {"sdb.amazonaws.com"},
+ }
+ sdb.Sign(testAuth, method, "", params, headers)
+ expected := "ot2JaeeqMRJqgAqW67hkzUlffgxdOz4RykbrECB+tDU="
+ c.Assert(params["Signature"], DeepEquals, []string{expected})
+}
+
+// Do a few test methods which takes combinations of params
diff --git a/vendor/github.com/goamz/goamz/exp/ses/ses.go b/vendor/github.com/goamz/goamz/exp/ses/ses.go
new file mode 100644
index 000000000..7c9c7c352
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/ses/ses.go
@@ -0,0 +1,145 @@
+// ses.go
+package ses
+
+import (
+ "encoding/xml"
+ "github.com/goamz/goamz/aws"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+)
+
+type SES struct {
+ auth aws.Auth
+ region aws.Region
+ client *http.Client
+}
+
+// Initializes a pointer to an SES struct which can be used
+// to perform SES API calls.
+func NewSES(auth aws.Auth, region aws.Region) *SES {
+ ses := SES{auth, region, nil}
+ return &ses
+}
+
+// Sends an email to the specifications stored in the Email struct.
+func (ses *SES) SendEmail(email *Email) error {
+ data := make(url.Values)
+
+ index := 0
+ for i := range email.destination.bccAddresses {
+ if len(email.destination.bccAddresses[i]) > 0 {
+ index += 1
+ key := "Destination.BccAddresses.member." + strconv.Itoa(index)
+ data.Add(key, email.destination.bccAddresses[i])
+ }
+ }
+
+ index = 0
+ for i := range email.destination.ccAddresses {
+ if len(email.destination.ccAddresses[i]) > 0 {
+ index += 1
+ key := "Destination.CcAddresses.member." + strconv.Itoa(index)
+ data.Add(key, email.destination.ccAddresses[i])
+ }
+ }
+
+ index = 0
+ for i := range email.destination.toAddresses {
+ if len(email.destination.toAddresses[i]) > 0 {
+ index += 1
+ key := "Destination.ToAddresses.member." + strconv.Itoa(index)
+ data.Add(key, email.destination.toAddresses[i])
+ }
+ }
+
+ index = 0
+ for i := range email.replyTo {
+ if len(email.replyTo[i]) > 0 {
+ index += 1
+ key := "ReplyToAddresses.member." + strconv.Itoa(index)
+ data.Add(key, email.replyTo[i])
+ }
+ }
+
+ if len(email.message.Subject.Data) > 0 {
+ if len(email.message.Subject.Charset) > 0 {
+ data.Add("Message.Subject.Charset", email.message.Subject.Charset)
+ }
+ data.Add("Message.Subject.Data", email.message.Subject.Data)
+ }
+
+ if len(email.message.Body.Html.Data) > 0 {
+ if len(email.message.Body.Html.Charset) > 0 {
+ data.Add("Message.Body.Html.Charset", email.message.Body.Html.Charset)
+ }
+ data.Add("Message.Body.Html.Data", email.message.Body.Html.Data)
+ }
+
+ if len(email.message.Body.Text.Data) > 0 {
+ if len(email.message.Body.Text.Charset) > 0 {
+ data.Add("Message.Body.Text.Charset", email.message.Body.Text.Charset)
+ }
+ data.Add("Message.Body.Text.Data", email.message.Body.Text.Data)
+ }
+
+ if len(email.returnPath) > 0 {
+ data.Add("ReturnPath", email.returnPath)
+ }
+
+ if len(email.source) > 0 {
+ data.Add("Source", email.source)
+ }
+
+ return ses.doPost("SendEmail", data)
+}
+
+// Do an SES POST action.
+func (ses *SES) doPost(action string, data url.Values) error {
+ req := http.Request{
+ Method: "POST",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Close: true,
+ Header: http.Header{}}
+
+ URL, err := url.Parse(ses.region.SESEndpoint)
+ if err != nil {
+ return err
+ }
+ URL.Path = "/"
+
+ req.URL = URL
+ req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+ sign(ses.auth, "POST", req.Header)
+
+ data.Add("AWSAccessKeyId", ses.auth.AccessKey)
+ data.Add("Action", action)
+
+ body := data.Encode()
+ req.Header.Add("Content-Length", strconv.Itoa(len(body)))
+ req.Body = ioutil.NopCloser(strings.NewReader(body))
+
+ if ses.client == nil {
+ ses.client = &http.Client{}
+ }
+
+ resp, err := ses.client.Do(&req)
+ if err != nil {
+ return err
+ }
+ if resp.StatusCode > 204 {
+ defer resp.Body.Close()
+ return buildError(resp)
+ }
+
+ return nil
+}
+
+func buildError(r *http.Response) *SESError {
+ err := SESError{}
+ xml.NewDecoder(r.Body).Decode(&err)
+ return &err
+}
diff --git a/vendor/github.com/goamz/goamz/exp/ses/ses_test.go b/vendor/github.com/goamz/goamz/exp/ses/ses_test.go
new file mode 100644
index 000000000..ae93215ed
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/ses/ses_test.go
@@ -0,0 +1,69 @@
+// ses_test
+package ses_test
+
+import (
+ "bytes"
+ "net/url"
+ "testing"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/exp/ses"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+type S struct {
+ ses *ses.SES
+}
+
+var _ = Suite(&S{})
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.ses = ses.NewSES(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL})
+}
+
+func (s *S) TearDownStrategy(c *C) {
+
+}
+
+func (s *S) SetUpTest(c *C) {
+
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestSendEmail(c *C) {
+ testServer.Response(200, nil, "")
+
+ email := ses.NewEmail()
+ email.AddTo("test@test.com")
+ email.AddSource("test@test.com")
+ email.SetSubject("test")
+ email.SetBodyHtml("test")
+
+ s.ses.SendEmail(email)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(req.Body)
+ body, _ := url.ParseQuery(buf.String())
+
+ c.Assert(body, Not(IsNil))
+ c.Assert(body["Destination.ToAddresses.member.1"], Equals, "test@test.com")
+ c.Assert(body["Source"], Equals, "test@test.com")
+ c.Assert(body["Message.Subject.Data"], Equals, "test")
+ c.Assert(body["Message.Body.Html.Data"], Equals, "test")
+}
diff --git a/vendor/github.com/goamz/goamz/exp/ses/ses_types.go b/vendor/github.com/goamz/goamz/exp/ses/ses_types.go
new file mode 100644
index 000000000..698fa7623
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/ses/ses_types.go
@@ -0,0 +1,156 @@
+// ses_types
+package ses
+
+// Private internal representation of message body.
+type Body struct {
+ Html Content
+ Text Content
+}
+
+// Content data structure with charset and payload (Data).
+type Content struct {
+ Charset string
+ Data string
+}
+
+// Email data structure. Should be main data structure used
+// for sending emails using SES.
+type Email struct {
+ destination *destination
+ message Message
+ replyTo []string
+ returnPath string
+ source string
+}
+
+// Private internal representation for email destinations.
+type destination struct {
+ bccAddresses []string
+ ccAddresses []string
+ toAddresses []string
+}
+
+// Message data structure.
+type Message struct {
+ Body Body
+ Subject Content
+}
+
+// SES Error structure.
+type SESError struct {
+ Type string
+ Code string
+ Message string
+ Detail string
+ RequestId string
+}
+
+func (err *SESError) Error() string {
+ return err.Message
+}
+
+// Returns a pointer to an empty but initialized Email.
+func NewEmail() *Email {
+ return &Email{
+ destination: newDestination(),
+ replyTo: make([]string, 5)}
+}
+
+// Private function to return an initialized destination.
+func newDestination() *destination {
+ return &destination{
+ bccAddresses: make([]string, 5),
+ ccAddresses: make([]string, 5),
+ toAddresses: make([]string, 5)}
+}
+
+// Add a BCC destination to Email.
+func (em *Email) AddBCC(address string) {
+ em.destination.bccAddresses = append(em.destination.bccAddresses, address)
+}
+
+// Add multiple BCC destinations to Email.
+func (em *Email) AddBCCs(addresses []string) {
+ em.destination.bccAddresses = append(em.destination.bccAddresses, addresses...)
+}
+
+// Add a CC destination to Email.
+func (em *Email) AddCC(address string) {
+ em.destination.ccAddresses = append(em.destination.ccAddresses, address)
+}
+
+// Add multiple CC destinations to Email.
+func (em *Email) AddCCs(addresses []string) {
+ em.destination.ccAddresses = append(em.destination.ccAddresses, addresses...)
+}
+
+// Add a To destination to Email.
+func (em *Email) AddTo(address string) {
+ em.destination.toAddresses = append(em.destination.toAddresses, address)
+}
+
+// Add multiple To destinations to Email.
+func (em *Email) AddTos(addresses []string) {
+ em.destination.toAddresses = append(em.destination.toAddresses, addresses...)
+}
+
+// Add a reply-to address to Email.
+func (em *Email) AddReplyTo(address string) {
+ em.replyTo = append(em.replyTo, address)
+}
+
+// Add multiple reply-to addresses to Email.
+func (em *Email) AddReplyTos(addresses []string) {
+ em.replyTo = append(em.replyTo, addresses...)
+}
+
+// Set the return path for Email.
+func (em *Email) SetReturnPath(path string) {
+ em.returnPath = path
+}
+
+// Set the source address for Email.
+func (em *Email) SetSource(source string) {
+ em.source = source
+}
+
+// Set the Email message.
+func (em *Email) SetMessage(message Message) {
+ em.message = message
+}
+
+// Set the subject for the Email message.
+// Uses ASCII as charset.
+func (em *Email) SetSubject(subject string) {
+ em.message.Subject = Content{Data: subject}
+}
+
+// Set the subject for the Email message.
+// Uses the charset (or ASCII if none) of Content.
+func (em *Email) SetSubjectAsContent(subject Content) {
+ em.message.Subject = subject
+}
+
+// Sets the HTML body of the Email message.
+// Uses ASCII as charset.
+func (em *Email) SetBodyHtml(html string) {
+ em.message.Body.Html = Content{Data: html}
+}
+
+// Sets the HTML body of the Email message.
+// Uses the charset (or ASCII if none) of Content.
+func (em *Email) SetBodyHtmlAsContent(html Content) {
+ em.message.Body.Html = html
+}
+
+// Sets the raw text body of the Email message.
+// Uses ASCII as charset.
+func (em *Email) SetBodyRawText(text string) {
+ em.message.Body.Text = Content{Data: text}
+}
+
+// Sets the raw test body of the Email message.
+// Uses the charset (or ASCII if none) of Content.
+func (em *Email) SetBodyRawTextAsContent(text Content) {
+ em.message.Body.Text = text
+}
diff --git a/vendor/github.com/goamz/goamz/exp/ses/sign.go b/vendor/github.com/goamz/goamz/exp/ses/sign.go
new file mode 100644
index 000000000..5c9c840c8
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/ses/sign.go
@@ -0,0 +1,26 @@
+// sign
+package ses
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "fmt"
+ "github.com/goamz/goamz/aws"
+ "time"
+)
+
+const (
+ AMZ_DATE_STYLE = "Mon, 02 Jan 2006 15:04:05 -0700"
+)
+
+// Sign SES request as dictated by Amazon's Version 3 signature method.
+func sign(auth aws.Auth, method string, headers map[string][]string) {
+ date := time.Now().UTC().Format(AMZ_DATE_STYLE)
+ h := hmac.New(sha256.New, []byte(auth.SecretKey))
+ h.Write([]byte(date))
+ signature := base64.StdEncoding.EncodeToString(h.Sum(nil))
+ authHeader := fmt.Sprintf("AWS3-HTTPS AWSAccessKeyId=%s, Algorithm=HmacSHA256, Signature=%s", auth.AccessKey, signature)
+ headers["Date"] = []string{date}
+ headers["X-Amzn-Authorization"] = []string{authHeader}
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/Makefile b/vendor/github.com/goamz/goamz/exp/sns/Makefile
new file mode 100644
index 000000000..1e5b9da3b
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/Makefile
@@ -0,0 +1,21 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=launchpad.net/goamz/sns
+
+GOFILES=\
+ sns.go\
+ sign.go\
+
+include $(GOROOT)/src/Make.pkg
+
+GOFMT=gofmt
+BADFMT=$(shell $(GOFMT) -l $(GOFILES) 2> /dev/null)
+
+gofmt: $(BADFMT)
+ @for F in $(BADFMT); do $(GOFMT) -w $$F && echo $$F; done
+
+ifneq ($(BADFMT),)
+ifneq ($(MAKECMDGOALS), gofmt)
+#$(warning WARNING: make gofmt: $(BADFMT))
+endif
+endif
diff --git a/vendor/github.com/goamz/goamz/exp/sns/README b/vendor/github.com/goamz/goamz/exp/sns/README
new file mode 100644
index 000000000..87770adb5
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/README
@@ -0,0 +1 @@
+Amazon Simple Notification Service API for Golang.
diff --git a/vendor/github.com/goamz/goamz/exp/sns/endpoint.go b/vendor/github.com/goamz/goamz/exp/sns/endpoint.go
new file mode 100644
index 000000000..c6e6e4433
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/endpoint.go
@@ -0,0 +1,132 @@
+package sns
+
+import (
+ "fmt"
+ "strconv"
+)
+
+type DeleteEndpointResponse struct {
+ ResponseMetadata
+}
+
+type GetEndpointAttributesResponse struct {
+ Attributes []AttributeEntry `xml:"GetEndpointAttributesResult>Attributes>entry"`
+ ResponseMetadata
+}
+
+type PlatformEndpointOpt struct {
+ Attributes []AttributeEntry
+ PlatformApplicationArn string
+ CustomUserData string
+ Token string
+}
+
+type CreatePlatformEndpointResponse struct {
+ EndpointArn string `xml:"CreatePlatformEndpointResult>EndpointArn"`
+ ResponseMetadata
+}
+
+type PlatformEndpoints struct {
+ EndpointArn string `xml:"EndpointArn"`
+ Attributes []AttributeEntry `xml:"Attributes>entry"`
+}
+
+type ListEndpointsByPlatformApplicationResponse struct {
+ Endpoints []PlatformEndpoints `xml:"ListEndpointsByPlatformApplicationResult>Endpoints>member"`
+ ResponseMetadata
+}
+
+type SetEndpointAttributesOpt struct {
+ Attributes []AttributeEntry
+ EndpointArn string
+}
+
+type SetEndpointAttributesResponse struct {
+ ResponseMetadata
+}
+
+// DeleteEndpoint
+//
+// See http://goo.gl/9SlUD9 for more details.
+func (sns *SNS) DeleteEndpoint(endpointArn string) (resp *DeleteEndpointResponse, err error) {
+ resp = &DeleteEndpointResponse{}
+ params := makeParams("DeleteEndpoint")
+
+ params["EndpointArn"] = endpointArn
+
+ err = sns.query(params, resp)
+
+ return
+}
+
+// GetEndpointAttributes
+//
+// See http://goo.gl/c8E5X1 for more details.
+func (sns *SNS) GetEndpointAttributes(endpointArn string) (resp *GetEndpointAttributesResponse, err error) {
+ resp = &GetEndpointAttributesResponse{}
+
+ params := makeParams("GetEndpointAttributes")
+
+ params["EndpointArn"] = endpointArn
+
+ err = sns.query(params, resp)
+
+ return
+}
+
+// CreatePlatformEndpoint
+//
+// See http://goo.gl/4tnngi for more details.
+func (sns *SNS) CreatePlatformEndpoint(options *PlatformEndpointOpt) (resp *CreatePlatformEndpointResponse, err error) {
+
+ resp = &CreatePlatformEndpointResponse{}
+ params := makeParams("CreatePlatformEndpoint")
+
+ params["PlatformApplicationArn"] = options.PlatformApplicationArn
+ params["Token"] = options.Token
+
+ if options.CustomUserData != "" {
+ params["CustomUserData"] = options.CustomUserData
+ }
+
+ err = sns.query(params, resp)
+
+ return
+}
+
+// ListEndpointsByPlatformApplication
+//
+// See http://goo.gl/L7ioyR for more detail.
+func (sns *SNS) ListEndpointsByPlatformApplication(platformApplicationArn, nextToken string) (resp *ListEndpointsByPlatformApplicationResponse, err error) {
+ resp = &ListEndpointsByPlatformApplicationResponse{}
+
+ params := makeParams("ListEndpointsByPlatformApplication")
+
+ params["PlatformApplicationArn"] = platformApplicationArn
+
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ err = sns.query(params, resp)
+ return
+
+}
+
+// SetEndpointAttributes
+//
+// See http://goo.gl/GTktCj for more detail.
+func (sns *SNS) SetEndpointAttributes(options *SetEndpointAttributesOpt) (resp *SetEndpointAttributesResponse, err error) {
+ resp = &SetEndpointAttributesResponse{}
+ params := makeParams("SetEndpointAttributes")
+
+ params["EndpointArn"] = options.EndpointArn
+
+ for i, attr := range options.Attributes {
+ params[fmt.Sprintf("Attributes.entry.%s.key", strconv.Itoa(i+1))] = attr.Key
+ params[fmt.Sprintf("Attributes.entry.%s.value", strconv.Itoa(i+1))] = attr.Value
+ }
+
+ err = sns.query(params, resp)
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/permissions.go b/vendor/github.com/goamz/goamz/exp/sns/permissions.go
new file mode 100644
index 000000000..e7c73629f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/permissions.go
@@ -0,0 +1,51 @@
+package sns
+
+import (
+ "strconv"
+)
+
+type Permission struct {
+ ActionName string
+ AccountId string
+}
+
+type AddPermissionResponse struct {
+ ResponseMetadata
+}
+
+// AddPermission
+//
+// See http://goo.gl/mbY4a for more details.
+func (sns *SNS) AddPermission(permissions []Permission, Label, TopicArn string) (resp *AddPermissionResponse, err error) {
+ resp = &AddPermissionResponse{}
+ params := makeParams("AddPermission")
+
+ for i, p := range permissions {
+ params["AWSAccountId.member."+strconv.Itoa(i+1)] = p.AccountId
+ params["ActionName.member."+strconv.Itoa(i+1)] = p.ActionName
+ }
+
+ params["Label"] = Label
+ params["TopicArn"] = TopicArn
+
+ err = sns.query(params, resp)
+ return
+}
+
+type RemovePermissionResponse struct {
+ ResponseMetadata
+}
+
+// RemovePermission
+//
+// See http://goo.gl/wGl5j for more details.
+func (sns *SNS) RemovePermission(Label, TopicArn string) (resp *RemovePermissionResponse, err error) {
+ resp = &RemovePermissionResponse{}
+ params := makeParams("RemovePermission")
+
+ params["Label"] = Label
+ params["TopicArn"] = TopicArn
+
+ err = sns.query(params, resp)
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/platform.go b/vendor/github.com/goamz/goamz/exp/sns/platform.go
new file mode 100644
index 000000000..b650cdda7
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/platform.go
@@ -0,0 +1,135 @@
+package sns
+
+import (
+ "fmt"
+ "strconv"
+)
+
+type CreatePlatformApplicationResponse struct {
+ PlatformApplicationArn string `xml:"CreatePlatformApplicationResult>PlatformApplicationArn"`
+ ResponseMetadata
+}
+
+type PlatformApplicationOpt struct {
+ Attributes []AttributeEntry
+ Name string
+ Platform string
+}
+
+type DeletePlatformApplicationResponse struct {
+ ResponseMetadata
+}
+
+type GetPlatformApplicationAttributesResponse struct {
+ Attributes []AttributeEntry `xml:"GetPlatformApplicationAttributesResult>Attributes>entry"`
+ ResponseMetadata
+}
+
+type SetPlatformApplicationAttributesOpt struct {
+ Attributes []AttributeEntry
+ PlatformApplicationArn string
+}
+
+type SetPlatformApplicationAttributesResponse struct {
+ ResponseMetadata
+}
+
+type PlatformApplication struct {
+ Attributes []AttributeEntry `xml:"Attributes>entry"`
+ PlatformApplicationArn string
+}
+
+type ListPlatformApplicationsResponse struct {
+ NextToken string
+ PlatformApplications []PlatformApplication `xml:"ListPlatformApplicationsResult>PlatformApplications>member"`
+ ResponseMetadata
+}
+
+// CreatePlatformApplication
+//
+// See http://goo.gl/Mbbl6Z for more details.
+
+func (sns *SNS) CreatePlatformApplication(options *PlatformApplicationOpt) (resp *CreatePlatformApplicationResponse, err error) {
+ resp = &CreatePlatformApplicationResponse{}
+ params := makeParams("CreatePlatformApplication")
+
+ params["Platform"] = options.Platform
+ params["Name"] = options.Name
+
+ for i, attr := range options.Attributes {
+ params[fmt.Sprintf("Attributes.entry.%s.key", strconv.Itoa(i+1))] = attr.Key
+ params[fmt.Sprintf("Attributes.entry.%s.value", strconv.Itoa(i+1))] = attr.Value
+ }
+
+ err = sns.query(params, resp)
+
+ return
+
+}
+
+// DeletePlatformApplication
+//
+// See http://goo.gl/6GB3DN for more details.
+func (sns *SNS) DeletePlatformApplication(platformApplicationArn string) (resp *DeletePlatformApplicationResponse, err error) {
+ resp = &DeletePlatformApplicationResponse{}
+
+ params := makeParams("DeletePlatformApplication")
+
+ params["PlatformApplicationArn"] = platformApplicationArn
+
+ err = sns.query(params, resp)
+
+ return
+}
+
+// GetPlatformApplicationAttributes
+//
+// See http://goo.gl/GswJ8I for more details.
+func (sns *SNS) GetPlatformApplicationAttributes(platformApplicationArn, nextToken string) (resp *GetPlatformApplicationAttributesResponse, err error) {
+ resp = &GetPlatformApplicationAttributesResponse{}
+
+ params := makeParams("GetPlatformApplicationAttributes")
+
+ params["PlatformApplicationArn"] = platformApplicationArn
+
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ err = sns.query(params, resp)
+
+ return
+}
+
+// ListPlatformApplications
+//
+// See http://goo.gl/vQ3ooV for more detail.
+func (sns *SNS) ListPlatformApplications(nextToken string) (resp *ListPlatformApplicationsResponse, err error) {
+ resp = &ListPlatformApplicationsResponse{}
+ params := makeParams("ListPlatformApplications")
+
+ if nextToken != "" {
+ params["NextToken"] = nextToken
+ }
+
+ err = sns.query(params, resp)
+ return
+}
+
+// SetPlatformApplicationAttributes
+//
+// See http://goo.gl/RWnzzb for more detail.
+func (sns *SNS) SetPlatformApplicationAttributes(options *SetPlatformApplicationAttributesOpt) (resp *SetPlatformApplicationAttributesResponse, err error) {
+ resp = &SetPlatformApplicationAttributesResponse{}
+ params := makeParams("SetPlatformApplicationAttributes")
+
+ params["PlatformApplicationArn"] = options.PlatformApplicationArn
+
+ for i, attr := range options.Attributes {
+ params[fmt.Sprintf("Attributes.entry.%s.key", strconv.Itoa(i+1))] = attr.Key
+ params[fmt.Sprintf("Attributes.entry.%s.value", strconv.Itoa(i+1))] = attr.Value
+ }
+
+ err = sns.query(params, resp)
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/responses_test.go b/vendor/github.com/goamz/goamz/exp/sns/responses_test.go
new file mode 100644
index 000000000..53a06429d
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/responses_test.go
@@ -0,0 +1,317 @@
+package sns_test
+
+var TestListTopicsXmlOK = `
+<?xml version="1.0"?>
+<ListTopicsResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ListTopicsResult>
+ <Topics>
+ <member>
+ <TopicArn>arn:aws:sns:us-west-1:331995417492:Transcoding</TopicArn>
+ </member>
+ </Topics>
+ </ListTopicsResult>
+ <ResponseMetadata>
+ <RequestId>bd10b26c-e30e-11e0-ba29-93c3aca2f103</RequestId>
+ </ResponseMetadata>
+</ListTopicsResponse>
+`
+
+var TestCreateTopicXmlOK = `
+<?xml version="1.0"?>
+<CreateTopicResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <CreateTopicResult>
+ <TopicArn>arn:aws:sns:us-east-1:123456789012:My-Topic</TopicArn>
+ </CreateTopicResult>
+ <ResponseMetadata>
+ <RequestId>a8dec8b3-33a4-11df-8963-01868b7c937a</RequestId>
+ </ResponseMetadata>
+</CreateTopicResponse>
+`
+
+var TestDeleteTopicXmlOK = `
+<DeleteTopicResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>f3aa9ac9-3c3d-11df-8235-9dab105e9c32</RequestId>
+ </ResponseMetadata>
+</DeleteTopicResponse>
+`
+
+var TestListSubscriptionsXmlOK = `
+<ListSubscriptionsResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ListSubscriptionsResult>
+ <Subscriptions>
+ <member>
+ <TopicArn>arn:aws:sns:us-east-1:698519295917:My-Topic</TopicArn>
+ <Protocol>email</Protocol>
+ <SubscriptionArn>arn:aws:sns:us-east-1:123456789012:My-Topic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca</SubscriptionArn>
+ <Owner>123456789012</Owner>
+ <Endpoint>example@amazon.com</Endpoint>
+ </member>
+ </Subscriptions>
+ </ListSubscriptionsResult>
+ <ResponseMetadata>
+ <RequestId>384ac68d-3775-11df-8963-01868b7c937a</RequestId>
+ </ResponseMetadata>
+</ListSubscriptionsResponse>
+`
+
+var TestGetTopicAttributesXmlOK = `
+<GetTopicAttributesResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <GetTopicAttributesResult>
+ <Attributes>
+ <entry>
+ <key>Owner</key>
+ <value>123456789012</value>
+ </entry>
+ <entry>
+ <key>Policy</key>
+ <value>{"Version":"2008-10-17","Id":"us-east-1/698519295917/test__default_policy_ID","Statement" : [{"Effect":"Allow","Sid":"us-east-1/698519295917/test__default_statement_ID","Principal" : {"AWS": "*"},"Action":["SNS:GetTopicAttributes","SNS:SetTopicAttributes","SNS:AddPermission","SNS:RemovePermission","SNS:DeleteTopic","SNS:Subscribe","SNS:ListSubscriptionsByTopic","SNS:Publish","SNS:Receive"],"Resource":"arn:aws:sns:us-east-1:698519295917:test","Condition" : {"StringLike" : {"AWS:SourceArn": "arn:aws:*:*:698519295917:*"}}}]}</value>
+ </entry>
+ <entry>
+ <key>TopicArn</key>
+ <value>arn:aws:sns:us-east-1:123456789012:My-Topic</value>
+ </entry>
+ </Attributes>
+ </GetTopicAttributesResult>
+ <ResponseMetadata>
+ <RequestId>057f074c-33a7-11df-9540-99d0768312d3</RequestId>
+ </ResponseMetadata>
+</GetTopicAttributesResponse>
+`
+
+var TestPublishXmlOK = `
+<PublishResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <PublishResult>
+ <MessageId>94f20ce6-13c5-43a0-9a9e-ca52d816e90b</MessageId>
+ </PublishResult>
+ <ResponseMetadata>
+ <RequestId>f187a3c1-376f-11df-8963-01868b7c937a</RequestId>
+ </ResponseMetadata>
+</PublishResponse>
+`
+
+var TestSetTopicAttributesXmlOK = `
+<SetTopicAttributesResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>a8763b99-33a7-11df-a9b7-05d48da6f042</RequestId>
+ </ResponseMetadata>
+</SetTopicAttributesResponse>
+`
+
+var TestSubscribeXmlOK = `
+<SubscribeResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <SubscribeResult>
+ <SubscriptionArn>pending confirmation</SubscriptionArn>
+ </SubscribeResult>
+ <ResponseMetadata>
+ <RequestId>a169c740-3766-11df-8963-01868b7c937a</RequestId>
+ </ResponseMetadata>
+</SubscribeResponse>
+`
+
+var TestUnsubscribeXmlOK = `
+<UnsubscribeResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>18e0ac39-3776-11df-84c0-b93cc1666b84</RequestId>
+ </ResponseMetadata>
+</UnsubscribeResponse>
+`
+
+var TestConfirmSubscriptionXmlOK = `
+<ConfirmSubscriptionResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ConfirmSubscriptionResult>
+ <SubscriptionArn>arn:aws:sns:us-east-1:123456789012:My-Topic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca</SubscriptionArn>
+ </ConfirmSubscriptionResult>
+ <ResponseMetadata>
+ <RequestId>7a50221f-3774-11df-a9b7-05d48da6f042</RequestId>
+ </ResponseMetadata>
+</ConfirmSubscriptionResponse>
+`
+
+var TestAddPermissionXmlOK = `
+<AddPermissionResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>6a213e4e-33a8-11df-9540-99d0768312d3</RequestId>
+ </ResponseMetadata>
+</AddPermissionResponse>
+`
+
+var TestRemovePermissionXmlOK = `
+<RemovePermissionResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>d170b150-33a8-11df-995a-2d6fbe836cc1</RequestId>
+ </ResponseMetadata>
+</RemovePermissionResponse>
+`
+
+var TestListSubscriptionsByTopicXmlOK = `
+<ListSubscriptionsByTopicResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ListSubscriptionsByTopicResult>
+ <Subscriptions>
+ <member>
+ <TopicArn>arn:aws:sns:us-east-1:123456789012:My-Topic</TopicArn>
+ <Protocol>email</Protocol>
+ <SubscriptionArn>arn:aws:sns:us-east-1:123456789012:My-Topic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca</SubscriptionArn>
+ <Owner>123456789012</Owner>
+ <Endpoint>example@amazon.com</Endpoint>
+ </member>
+ </Subscriptions>
+ </ListSubscriptionsByTopicResult>
+ <ResponseMetadata>
+ <RequestId>b9275252-3774-11df-9540-99d0768312d3</RequestId>
+ </ResponseMetadata>
+</ListSubscriptionsByTopicResponse>
+`
+
+var TestCreatePlatformApplicationXmlOK = `
+<CreatePlatformApplicationResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <CreatePlatformApplicationResult>
+ <PlatformApplicationArn>arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp</PlatformApplicationArn>
+ </CreatePlatformApplicationResult>
+ <ResponseMetadata>
+ <RequestId>b6f0e78b-e9d4-5a0e-b973-adc04e8a4ff9</RequestId>
+ </ResponseMetadata>
+</CreatePlatformApplicationResponse>
+`
+
+var TestCreatePlatformEndpointXmlOK = `
+<CreatePlatformEndpointResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <CreatePlatformEndpointResult>
+ <EndpointArn>arn:aws:sns:us-west-2:123456789012:endpoint/GCM/gcmpushapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3</EndpointArn>
+ </CreatePlatformEndpointResult>
+ <ResponseMetadata>
+ <RequestId>6613341d-3e15-53f7-bf3c-7e56994ba278</RequestId>
+ </ResponseMetadata>
+</CreatePlatformEndpointResponse>
+`
+
+var DeleteEndpointXmlOK = `
+<DeleteEndpointResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>c1d2b191-353c-5a5f-8969-fbdd3900afa8</RequestId>
+ </ResponseMetadata>
+</DeleteEndpointResponse>
+`
+
+var TestDeletePlatformApplicationXmlOK = `
+<DeletePlatformApplicationResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>097dac18-7a77-5823-a8dd-e65476dcb037</RequestId>
+ </ResponseMetadata>
+</DeletePlatformApplicationResponse>
+`
+
+var TestGetEndpointAttributesXmlOK = `
+<GetEndpointAttributesResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <GetEndpointAttributesResult>
+ <Attributes>
+ <entry>
+ <key>Enabled</key>
+ <value>true</value>
+ </entry>
+ <entry>
+ <key>CustomUserData</key>
+ <value>UserId=01234567</value>
+ </entry>
+ <entry>
+ <key>Token</key>
+ <value>APA91bGi7fFachkC1xjlqT66VYEucGHochmf1VQAr9k...jsM0PKPxKhddCzx6paEsyay9Zn3D4wNUJb8m6HZrBEXAMPLE</value>
+ </entry>
+ </Attributes>
+ </GetEndpointAttributesResult>
+ <ResponseMetadata>
+ <RequestId>6c725a19-a142-5b77-94f9-1055a9ea04e7</RequestId>
+ </ResponseMetadata>
+</GetEndpointAttributesResponse>
+`
+
+var TestGetPlatformApplicationAttributesXmlOK = `
+<GetPlatformApplicationAttributesResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <GetPlatformApplicationAttributesResult>
+ <Attributes>
+ <entry>
+ <key>AllowEndpointPolicies</key>
+ <value>false</value>
+ </entry>
+ </Attributes>
+ </GetPlatformApplicationAttributesResult>
+ <ResponseMetadata>
+ <RequestId>74848df2-87f6-55ed-890c-c7be80442462</RequestId>
+ </ResponseMetadata>
+</GetPlatformApplicationAttributesResponse>
+`
+
+var TestListEndpointsByPlatformApplicationXmlOK = `
+<ListEndpointsByPlatformApplicationResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ListEndpointsByPlatformApplicationResult>
+ <Endpoints>
+ <member>
+ <EndpointArn>arn:aws:sns:us-west-2:123456789012:endpoint/GCM/gcmpushapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3</EndpointArn>
+ <Attributes>
+ <entry>
+ <key>Enabled</key>
+ <value>true</value>
+ </entry>
+ <entry>
+ <key>CustomUserData</key>
+ <value>UserId=27576823</value>
+ </entry>
+ <entry>
+ <key>Token</key>
+ <value>APA91bGi7fFachkC1xjlqT66VYEucGHochmf1VQAr9k...jsM0PKPxKhddCzx6paEsyay9Zn3D4wNUJb8m6HZrBEXAMPLE</value>
+ </entry>
+ </Attributes>
+ </member>
+ </Endpoints>
+ </ListEndpointsByPlatformApplicationResult>
+ <ResponseMetadata>
+ <RequestId>9a48768c-dac8-5a60-aec0-3cc27ea08d96</RequestId>
+ </ResponseMetadata>
+</ListEndpointsByPlatformApplicationResponse>
+`
+
+var TestListPlatformApplicationsXmlOK = `
+<ListPlatformApplicationsResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ListPlatformApplicationsResult>
+ <PlatformApplications>
+ <member>
+ <PlatformApplicationArn>arn:aws:sns:us-west-2:123456789012:app/APNS_SANDBOX/apnspushapp</PlatformApplicationArn>
+ <Attributes>
+ <entry>
+ <key>AllowEndpointPolicies</key>
+ <value>false</value>
+ </entry>
+ </Attributes>
+ </member>
+ <member>
+ <PlatformApplicationArn>arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp</PlatformApplicationArn>
+ <Attributes>
+ <entry>
+ <key>AllowEndpointPolicies</key>
+ <value>false</value>
+ </entry>
+ </Attributes>
+ </member>
+ </PlatformApplications>
+ </ListPlatformApplicationsResult>
+ <ResponseMetadata>
+ <RequestId>315a335e-85d8-52df-9349-791283cbb529</RequestId>
+ </ResponseMetadata>
+</ListPlatformApplicationsResponse>
+`
+
+var TestSetEndpointAttributesXmlOK = `
+<SetEndpointAttributesResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>2fe0bfc7-3e85-5ee5-a9e2-f58b35e85f6a</RequestId>
+ </ResponseMetadata>
+</SetEndpointAttributesResponse>
+`
+
+var TestSetPlatformApplicationAttributesXmlOK = `
+<SetPlatformApplicationAttributesResponse xmlns="http://sns.amazonaws.com/doc/2010-03-31/">
+ <ResponseMetadata>
+ <RequestId>cf577bcc-b3dc-5463-88f1-3180b9412395</RequestId>
+ </ResponseMetadata>
+</SetPlatformApplicationAttributesResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/exp/sns/sign.go b/vendor/github.com/goamz/goamz/exp/sns/sign.go
new file mode 100644
index 000000000..0c35f05ae
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/sign.go
@@ -0,0 +1,72 @@
+package sns
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "github.com/goamz/goamz/aws"
+ "sort"
+ "strings"
+)
+
+var b64 = base64.StdEncoding
+
+/*
+func sign(auth aws.Auth, method, path string, params url.Values, headers http.Header) {
+ var host string
+ for k, v := range headers {
+ k = strings.ToLower(k)
+ switch k {
+ case "host":
+ host = v[0]
+ }
+ }
+
+ params["AWSAccessKeyId"] = []string{auth.AccessKey}
+ params["SignatureVersion"] = []string{"2"}
+ params["SignatureMethod"] = []string{"HmacSHA256"}
+ if auth.Token() != "" {
+ params["SecurityToken"] = auth.Token()
+ }
+
+ var sarry []string
+ for k, v := range params {
+ sarry = append(sarry, aws.Encode(k) + "=" + aws.Encode(v[0]))
+ }
+
+ sort.StringSlice(sarry).Sort()
+ joined := strings.Join(sarry, "&")
+
+ payload := strings.Join([]string{method, host, "/", joined}, "\n")
+ hash := hmac.NewSHA256([]byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum())
+
+ params["Signature"] = []string{"AWS " + string(signature)}
+ println("Payload:", payload)
+ println("Signature:", strings.Join(params["Signature"], "|"))
+}*/
+
+func sign(auth aws.Auth, method, path string, params map[string]string, host string) {
+ params["AWSAccessKeyId"] = auth.AccessKey
+ if auth.Token() != "" {
+ params["SecurityToken"] = auth.Token()
+ }
+ params["SignatureVersion"] = "2"
+ params["SignatureMethod"] = "HmacSHA256"
+
+ var sarray []string
+ for k, v := range params {
+ sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(v))
+ }
+ sort.StringSlice(sarray).Sort()
+ joined := strings.Join(sarray, "&")
+ payload := method + "\n" + host + "\n" + path + "\n" + joined
+ hash := hmac.New(sha256.New, []byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum(nil))
+
+ params["Signature"] = string(signature)
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/sns.go b/vendor/github.com/goamz/goamz/exp/sns/sns.go
new file mode 100644
index 000000000..4d4622211
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/sns.go
@@ -0,0 +1,113 @@
+//
+// goamz - Go packages to interact with the Amazon Web Services.
+//
+// https://wiki.ubuntu.com/goamz
+//
+// Copyright (c) 2011 Memeo Inc.
+//
+// Written by Prudhvi Krishna Surapaneni <me@prudhvi.net>
+
+// This package is in an experimental state, and does not currently
+// follow conventions and style of the rest of goamz or common
+// Go conventions. It must be polished before it's considered a
+// first-class package in goamz.
+package sns
+
+// BUG(niemeyer): Package needs documentation.
+
+import (
+ "encoding/xml"
+ "net/http"
+ "net/url"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+// The SNS type encapsulates operation with an SNS region.
+type SNS struct {
+ aws.Auth
+ aws.Region
+ private byte // Reserve the right of using private data.
+}
+
+type AttributeEntry struct {
+ Key string `xml:"key"`
+ Value string `xml:"value"`
+}
+
+type ResponseMetadata struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+ BoxUsage float64 `xml:"ResponseMetadata>BoxUsage"`
+}
+
+func New(auth aws.Auth, region aws.Region) *SNS {
+ return &SNS{auth, region, 0}
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+type Error struct {
+ StatusCode int
+ Code string
+ Message string
+ RequestId string
+}
+
+func (err *Error) Error() string {
+ return err.Message
+}
+
+type xmlErrors struct {
+ RequestId string
+ Errors []Error `xml:"Errors>Error"`
+}
+
+func (sns *SNS) query(params map[string]string, resp interface{}) error {
+ params["Timestamp"] = time.Now().UTC().Format(time.RFC3339)
+ u, err := url.Parse(sns.Region.SNSEndpoint)
+ if err != nil {
+ return err
+ }
+
+ sign(sns.Auth, "GET", "/", params, u.Host)
+ u.RawQuery = multimap(params).Encode()
+ r, err := http.Get(u.String())
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+func buildError(r *http.Response) error {
+ errors := xmlErrors{}
+ xml.NewDecoder(r.Body).Decode(&errors)
+ var err Error
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+ err.RequestId = errors.RequestId
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/sns_test.go b/vendor/github.com/goamz/goamz/exp/sns/sns_test.go
new file mode 100644
index 000000000..054db13d3
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/sns_test.go
@@ -0,0 +1,455 @@
+package sns_test
+
+import (
+ "testing"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/exp/sns"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ sns *sns.SNS
+}
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.sns = sns.New(auth, aws.Region{SNSEndpoint: testServer.URL})
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestListTopicsOK(c *C) {
+ testServer.Response(200, nil, TestListTopicsXmlOK)
+
+ resp, err := s.sns.ListTopics(nil)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.Topics[0].SNS, Equals, s.sns)
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "bd10b26c-e30e-11e0-ba29-93c3aca2f103")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestCreateTopic(c *C) {
+ testServer.Response(200, nil, TestCreateTopicXmlOK)
+
+ resp, err := s.sns.CreateTopic("My-Topic")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.Topic.SNS, Equals, s.sns)
+ c.Assert(resp.Topic.TopicArn, Equals, "arn:aws:sns:us-east-1:123456789012:My-Topic")
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "a8dec8b3-33a4-11df-8963-01868b7c937a")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestDeleteTopic(c *C) {
+ testServer.Response(200, nil, TestDeleteTopicXmlOK)
+
+ t := sns.Topic{s.sns, "arn:aws:sns:us-east-1:123456789012:My-Topic"}
+ resp, err := t.Delete()
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "f3aa9ac9-3c3d-11df-8235-9dab105e9c32")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestListSubscriptions(c *C) {
+ testServer.Response(200, nil, TestListSubscriptionsXmlOK)
+
+ resp, err := s.sns.ListSubscriptions(nil)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.Subscriptions), Not(Equals), 0)
+ c.Assert(resp.Subscriptions[0].Protocol, Equals, "email")
+ c.Assert(resp.Subscriptions[0].Endpoint, Equals, "example@amazon.com")
+ c.Assert(resp.Subscriptions[0].SubscriptionArn, Equals, "arn:aws:sns:us-east-1:123456789012:My-Topic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca")
+ c.Assert(resp.Subscriptions[0].TopicArn, Equals, "arn:aws:sns:us-east-1:698519295917:My-Topic")
+ c.Assert(resp.Subscriptions[0].Owner, Equals, "123456789012")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestGetTopicAttributes(c *C) {
+ testServer.Response(200, nil, TestGetTopicAttributesXmlOK)
+
+ resp, err := s.sns.GetTopicAttributes("arn:aws:sns:us-east-1:123456789012:My-Topic")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.Attributes), Not(Equals), 0)
+ c.Assert(resp.Attributes[0].Key, Equals, "Owner")
+ c.Assert(resp.Attributes[0].Value, Equals, "123456789012")
+ c.Assert(resp.Attributes[1].Key, Equals, "Policy")
+ c.Assert(resp.Attributes[1].Value, Equals, `{"Version":"2008-10-17","Id":"us-east-1/698519295917/test__default_policy_ID","Statement" : [{"Effect":"Allow","Sid":"us-east-1/698519295917/test__default_statement_ID","Principal" : {"AWS": "*"},"Action":["SNS:GetTopicAttributes","SNS:SetTopicAttributes","SNS:AddPermission","SNS:RemovePermission","SNS:DeleteTopic","SNS:Subscribe","SNS:ListSubscriptionsByTopic","SNS:Publish","SNS:Receive"],"Resource":"arn:aws:sns:us-east-1:698519295917:test","Condition" : {"StringLike" : {"AWS:SourceArn": "arn:aws:*:*:698519295917:*"}}}]}`)
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "057f074c-33a7-11df-9540-99d0768312d3")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestPublish(c *C) {
+ testServer.Response(200, nil, TestPublishXmlOK)
+
+ pubOpt := &sns.PublishOpt{"foobar", "", "subject", "arn:aws:sns:us-east-1:123456789012:My-Topic"}
+ resp, err := s.sns.Publish(pubOpt)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.MessageId, Equals, "94f20ce6-13c5-43a0-9a9e-ca52d816e90b")
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "f187a3c1-376f-11df-8963-01868b7c937a")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSetTopicAttributes(c *C) {
+ testServer.Response(200, nil, TestSetTopicAttributesXmlOK)
+
+ resp, err := s.sns.SetTopicAttributes("DisplayName", "MyTopicName", "arn:aws:sns:us-east-1:123456789012:My-Topic")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "a8763b99-33a7-11df-a9b7-05d48da6f042")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSubscribe(c *C) {
+ testServer.Response(200, nil, TestSubscribeXmlOK)
+
+ resp, err := s.sns.Subscribe("example@amazon.com", "email", "arn:aws:sns:us-east-1:123456789012:My-Topic")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.SubscriptionArn, Equals, "pending confirmation")
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "a169c740-3766-11df-8963-01868b7c937a")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestUnsubscribe(c *C) {
+ testServer.Response(200, nil, TestUnsubscribeXmlOK)
+
+ resp, err := s.sns.Unsubscribe("arn:aws:sns:us-east-1:123456789012:My-Topic:a169c740-3766-11df-8963-01868b7c937a")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "18e0ac39-3776-11df-84c0-b93cc1666b84")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestConfirmSubscription(c *C) {
+ testServer.Response(200, nil, TestConfirmSubscriptionXmlOK)
+
+ opt := &sns.ConfirmSubscriptionOpt{"", "51b2ff3edb475b7d91550e0ab6edf0c1de2a34e6ebaf6", "arn:aws:sns:us-east-1:123456789012:My-Topic"}
+ resp, err := s.sns.ConfirmSubscription(opt)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.SubscriptionArn, Equals, "arn:aws:sns:us-east-1:123456789012:My-Topic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca")
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "7a50221f-3774-11df-a9b7-05d48da6f042")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestAddPermission(c *C) {
+ testServer.Response(200, nil, TestAddPermissionXmlOK)
+ perm := make([]sns.Permission, 2)
+ perm[0].ActionName = "Publish"
+ perm[1].ActionName = "GetTopicAttributes"
+ perm[0].AccountId = "987654321000"
+ perm[1].AccountId = "876543210000"
+
+ resp, err := s.sns.AddPermission(perm, "NewPermission", "arn:aws:sns:us-east-1:123456789012:My-Topic")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.RequestId, Equals, "6a213e4e-33a8-11df-9540-99d0768312d3")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestRemovePermission(c *C) {
+ testServer.Response(200, nil, TestRemovePermissionXmlOK)
+
+ resp, err := s.sns.RemovePermission("NewPermission", "arn:aws:sns:us-east-1:123456789012:My-Topic")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.RequestId, Equals, "d170b150-33a8-11df-995a-2d6fbe836cc1")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestListSubscriptionByTopic(c *C) {
+ testServer.Response(200, nil, TestListSubscriptionsByTopicXmlOK)
+
+ opt := &sns.ListSubscriptionByTopicOpt{"", "arn:aws:sns:us-east-1:123456789012:My-Topic"}
+ resp, err := s.sns.ListSubscriptionByTopic(opt)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.Subscriptions), Not(Equals), 0)
+ c.Assert(resp.Subscriptions[0].TopicArn, Equals, "arn:aws:sns:us-east-1:123456789012:My-Topic")
+ c.Assert(resp.Subscriptions[0].SubscriptionArn, Equals, "arn:aws:sns:us-east-1:123456789012:My-Topic:80289ba6-0fd4-4079-afb4-ce8c8260f0ca")
+ c.Assert(resp.Subscriptions[0].Owner, Equals, "123456789012")
+ c.Assert(resp.Subscriptions[0].Endpoint, Equals, "example@amazon.com")
+ c.Assert(resp.Subscriptions[0].Protocol, Equals, "email")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestCreatePlatformApplication(c *C) {
+ testServer.Response(200, nil, TestCreatePlatformApplicationXmlOK)
+
+ attrs := []sns.AttributeEntry{
+ sns.AttributeEntry{Key: "PlatformCredential", Value: "AIzaSyClE2lcV2zEKTLYYo645zfk2jhQPFeyxDo"},
+ sns.AttributeEntry{Key: "PlatformPrincipal", Value: "There is no principal for GCM"},
+ }
+ opt := &sns.PlatformApplicationOpt{Name: "gcmpushapp", Platform: "GCM", Attributes: attrs}
+ resp, err := s.sns.CreatePlatformApplication(opt)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.PlatformApplicationArn, Equals, "arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp")
+ c.Assert(resp.RequestId, Equals, "b6f0e78b-e9d4-5a0e-b973-adc04e8a4ff9")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestCreatePlatformEndpoint(c *C) {
+ testServer.Response(200, nil, TestCreatePlatformEndpointXmlOK)
+
+ opt := &sns.PlatformEndpointOpt{PlatformApplicationArn: "arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp",
+ CustomUserData: "UserId=27576823", Token: "APA91bGi7fFachkC1xjlqT66VYEucGHochmf1VQAr9k...jsM0PKPxKhddCzx6paEsyay9Zn3D4wNUJb8m6HZrBEXAMPLE"}
+
+ resp, err := s.sns.CreatePlatformEndpoint(opt)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.EndpointArn, Equals, "arn:aws:sns:us-west-2:123456789012:endpoint/GCM/gcmpushapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3")
+ c.Assert(resp.RequestId, Equals, "6613341d-3e15-53f7-bf3c-7e56994ba278")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestDeleteEndpoint(c *C) {
+ testServer.Response(200, nil, DeleteEndpointXmlOK)
+
+ resp, err := s.sns.DeleteEndpoint("arn:aws:sns:us-west-2:123456789012:endpoint/GCM%/gcmpushapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.RequestId, Equals, "c1d2b191-353c-5a5f-8969-fbdd3900afa8")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestDeletePlatformApplication(c *C) {
+ testServer.Response(200, nil, TestDeletePlatformApplicationXmlOK)
+
+ resp, err := s.sns.DeletePlatformApplication("arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.RequestId, Equals, "097dac18-7a77-5823-a8dd-e65476dcb037")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestGetEndpointAttributes(c *C) {
+ testServer.Response(200, nil, TestGetEndpointAttributesXmlOK)
+
+ resp, err := s.sns.GetEndpointAttributes("arn:aws:sns:us-west-2:123456789012:endpoint/GCM/gcmpushapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.Attributes), Equals, 3)
+ c.Assert(resp.Attributes[0].Key, Equals, "Enabled")
+ c.Assert(resp.Attributes[0].Value, Equals, "true")
+
+ c.Assert(resp.Attributes[1].Key, Equals, "CustomUserData")
+ c.Assert(resp.Attributes[1].Value, Equals, "UserId=01234567")
+
+ c.Assert(resp.Attributes[2].Key, Equals, "Token")
+ c.Assert(resp.Attributes[2].Value, Equals, "APA91bGi7fFachkC1xjlqT66VYEucGHochmf1VQAr9k...jsM0PKPxKhddCzx6paEsyay9Zn3D4wNUJb8m6HZrBEXAMPLE")
+
+ c.Assert(resp.RequestId, Equals, "6c725a19-a142-5b77-94f9-1055a9ea04e7")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestGetPlatformApplicationAttributes(c *C) {
+ testServer.Response(200, nil, TestGetPlatformApplicationAttributesXmlOK)
+
+ resp, err := s.sns.GetPlatformApplicationAttributes("arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp", "")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.Attributes), Not(Equals), 0)
+ c.Assert(resp.Attributes[0].Key, Equals, "AllowEndpointPolicies")
+ c.Assert(resp.Attributes[0].Value, Equals, "false")
+ c.Assert(resp.RequestId, Equals, "74848df2-87f6-55ed-890c-c7be80442462")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestListEndpointsByPlatformApplication(c *C) {
+ testServer.Response(200, nil, TestListEndpointsByPlatformApplicationXmlOK)
+
+ resp, err := s.sns.ListEndpointsByPlatformApplication("arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp", "")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.Endpoints), Not(Equals), 0)
+ c.Assert(resp.Endpoints[0].EndpointArn, Equals, "arn:aws:sns:us-west-2:123456789012:endpoint/GCM/gcmpushapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3")
+ c.Assert(len(resp.Endpoints[0].Attributes), Equals, 3)
+ c.Assert(resp.Endpoints[0].Attributes[0].Key, Equals, "Enabled")
+ c.Assert(resp.Endpoints[0].Attributes[0].Value, Equals, "true")
+ c.Assert(resp.Endpoints[0].Attributes[1].Key, Equals, "CustomUserData")
+ c.Assert(resp.Endpoints[0].Attributes[1].Value, Equals, "UserId=27576823")
+ c.Assert(resp.Endpoints[0].Attributes[2].Key, Equals, "Token")
+ c.Assert(resp.Endpoints[0].Attributes[2].Value, Equals, "APA91bGi7fFachkC1xjlqT66VYEucGHochmf1VQAr9k...jsM0PKPxKhddCzx6paEsyay9Zn3D4wNUJb8m6HZrBEXAMPLE")
+
+ c.Assert(resp.RequestId, Equals, "9a48768c-dac8-5a60-aec0-3cc27ea08d96")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestListPlatformApplications(c *C) {
+ testServer.Response(200, nil, TestListPlatformApplicationsXmlOK)
+
+ resp, err := s.sns.ListPlatformApplications("")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.PlatformApplications), Not(Equals), 0)
+
+ c.Assert(resp.PlatformApplications[0].PlatformApplicationArn, Equals, "arn:aws:sns:us-west-2:123456789012:app/APNS_SANDBOX/apnspushapp")
+ c.Assert(len(resp.PlatformApplications[0].Attributes), Equals, 1)
+ c.Assert(resp.PlatformApplications[0].Attributes[0].Key, Equals, "AllowEndpointPolicies")
+ c.Assert(resp.PlatformApplications[0].Attributes[0].Value, Equals, "false")
+
+ c.Assert(resp.PlatformApplications[1].PlatformApplicationArn, Equals, "arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp")
+ c.Assert(len(resp.PlatformApplications[1].Attributes), Equals, 1)
+ c.Assert(resp.PlatformApplications[1].Attributes[0].Key, Equals, "AllowEndpointPolicies")
+ c.Assert(resp.PlatformApplications[1].Attributes[0].Value, Equals, "false")
+
+ c.Assert(resp.RequestId, Equals, "315a335e-85d8-52df-9349-791283cbb529")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSetEndpointAttributes(c *C) {
+ testServer.Response(200, nil, TestSetEndpointAttributesXmlOK)
+
+ attrs := []sns.AttributeEntry{
+ sns.AttributeEntry{Key: "CustomUserData", Value: "My custom userdata"},
+ }
+
+ opts := &sns.SetEndpointAttributesOpt{
+ EndpointArn: "arn:aws:sns:us-west-2:123456789012:endpoint/GCM/gcmpushapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3",
+ Attributes: attrs}
+
+ resp, err := s.sns.SetEndpointAttributes(opts)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.RequestId, Equals, "2fe0bfc7-3e85-5ee5-a9e2-f58b35e85f6a")
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSetPlatformApplicationAttributes(c *C) {
+ testServer.Response(200, nil, TestSetPlatformApplicationAttributesXmlOK)
+
+ attrs := []sns.AttributeEntry{
+ sns.AttributeEntry{Key: "EventEndpointCreated", Value: "arn:aws:sns:us-west-2:123456789012:topicarn"},
+ }
+
+ opts := &sns.SetPlatformApplicationAttributesOpt{
+ PlatformApplicationArn: "arn:aws:sns:us-west-2:123456789012:app/GCM/gcmpushapp",
+ Attributes: attrs}
+
+ resp, err := s.sns.SetPlatformApplicationAttributes(opts)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.RequestId, Equals, "cf577bcc-b3dc-5463-88f1-3180b9412395")
+
+ c.Assert(err, IsNil)
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/subscription.go b/vendor/github.com/goamz/goamz/exp/sns/subscription.go
new file mode 100644
index 000000000..cbfef8b2c
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/subscription.go
@@ -0,0 +1,165 @@
+package sns
+
+type Subscription struct {
+ Endpoint string
+ Owner string
+ Protocol string
+ SubscriptionArn string
+ TopicArn string
+}
+
+type ListSubscriptionsResp struct {
+ Subscriptions []Subscription `xml:"ListSubscriptionsResult>Subscriptions>member"`
+ NextToken string
+ ResponseMetadata
+}
+
+type PublishOpt struct {
+ Message string
+ MessageStructure string
+ Subject string
+ TopicArn string
+ TargetArn string
+}
+
+type PublishResp struct {
+ MessageId string `xml:"PublishResult>MessageId"`
+ ResponseMetadata
+}
+
+type SubscribeResponse struct {
+ SubscriptionArn string `xml:"SubscribeResult>SubscriptionArn"`
+ ResponseMetadata
+}
+
+type UnsubscribeResponse struct {
+ ResponseMetadata
+}
+
+type ConfirmSubscriptionResponse struct {
+ SubscriptionArn string `xml:"ConfirmSubscriptionResult>SubscriptionArn"`
+ ResponseMetadata
+}
+
+type ConfirmSubscriptionOpt struct {
+ AuthenticateOnUnsubscribe string
+ Token string
+ TopicArn string
+}
+
+type ListSubscriptionByTopicResponse struct {
+ Subscriptions []Subscription `xml:"ListSubscriptionsByTopicResult>Subscriptions>member"`
+ ResponseMetadata
+}
+
+type ListSubscriptionByTopicOpt struct {
+ NextToken string
+ TopicArn string
+}
+
+// Publish
+//
+// See http://goo.gl/AY2D8 for more details.
+func (sns *SNS) Publish(options *PublishOpt) (resp *PublishResp, err error) {
+ resp = &PublishResp{}
+ params := makeParams("Publish")
+
+ if options.Subject != "" {
+ params["Subject"] = options.Subject
+ }
+
+ if options.MessageStructure != "" {
+ params["MessageStructure"] = options.MessageStructure
+ }
+
+ if options.Message != "" {
+ params["Message"] = options.Message
+ }
+
+ if options.TopicArn != "" {
+ params["TopicArn"] = options.TopicArn
+ }
+
+ if options.TargetArn != "" {
+ params["TargetArn"] = options.TargetArn
+ }
+
+ err = sns.query(params, resp)
+ return
+}
+
+// Subscribe
+//
+// See http://goo.gl/c3iGS for more details.
+func (sns *SNS) Subscribe(Endpoint, Protocol, TopicArn string) (resp *SubscribeResponse, err error) {
+ resp = &SubscribeResponse{}
+ params := makeParams("Subscribe")
+
+ params["Endpoint"] = Endpoint
+ params["Protocol"] = Protocol
+ params["TopicArn"] = TopicArn
+
+ err = sns.query(params, resp)
+ return
+}
+
+// Unsubscribe
+//
+// See http://goo.gl/4l5Ge for more details.
+func (sns *SNS) Unsubscribe(SubscriptionArn string) (resp *UnsubscribeResponse, err error) {
+ resp = &UnsubscribeResponse{}
+ params := makeParams("Unsubscribe")
+
+ params["SubscriptionArn"] = SubscriptionArn
+
+ err = sns.query(params, resp)
+ return
+}
+
+// ConfirmSubscription
+//
+// See http://goo.gl/3hXzH for more details.
+func (sns *SNS) ConfirmSubscription(options *ConfirmSubscriptionOpt) (resp *ConfirmSubscriptionResponse, err error) {
+ resp = &ConfirmSubscriptionResponse{}
+ params := makeParams("ConfirmSubscription")
+
+ if options.AuthenticateOnUnsubscribe != "" {
+ params["AuthenticateOnUnsubscribe"] = options.AuthenticateOnUnsubscribe
+ }
+
+ params["Token"] = options.Token
+ params["TopicArn"] = options.TopicArn
+
+ err = sns.query(params, resp)
+ return
+}
+
+// ListSubscriptions
+//
+// See http://goo.gl/k3aGn for more details.
+func (sns *SNS) ListSubscriptions(NextToken *string) (resp *ListSubscriptionsResp, err error) {
+ resp = &ListSubscriptionsResp{}
+ params := makeParams("ListSubscriptions")
+ if NextToken != nil {
+ params["NextToken"] = *NextToken
+ }
+ err = sns.query(params, resp)
+ return
+}
+
+// ListSubscriptionByTopic
+//
+// See http://goo.gl/LaVcC for more details.
+func (sns *SNS) ListSubscriptionByTopic(options *ListSubscriptionByTopicOpt) (resp *ListSubscriptionByTopicResponse, err error) {
+ resp = &ListSubscriptionByTopicResponse{}
+ params := makeParams("ListSbubscriptionByTopic")
+
+ if options.NextToken != "" {
+ params["NextToken"] = options.NextToken
+ }
+
+ params["TopicArn"] = options.TopicArn
+
+ err = sns.query(params, resp)
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/exp/sns/topic.go b/vendor/github.com/goamz/goamz/exp/sns/topic.go
new file mode 100644
index 000000000..601325ec9
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/exp/sns/topic.go
@@ -0,0 +1,104 @@
+package sns
+
+import (
+ "errors"
+)
+
+type Topic struct {
+ SNS *SNS
+ TopicArn string
+}
+
+type ListTopicsResp struct {
+ Topics []Topic `xml:"ListTopicsResult>Topics>member"`
+ NextToken string
+ ResponseMetadata
+}
+
+type CreateTopicResp struct {
+ Topic Topic `xml:"CreateTopicResult"`
+ ResponseMetadata
+}
+
+type DeleteTopicResp struct {
+ ResponseMetadata
+}
+
+type GetTopicAttributesResp struct {
+ Attributes []AttributeEntry `xml:"GetTopicAttributesResult>Attributes>entry"`
+ ResponseMetadata
+}
+
+type SetTopicAttributesResponse struct {
+ ResponseMetadata
+}
+
+// ListTopics
+//
+// See http://goo.gl/lfrMK for more details.
+func (sns *SNS) ListTopics(NextToken *string) (resp *ListTopicsResp, err error) {
+ resp = &ListTopicsResp{}
+ params := makeParams("ListTopics")
+ if NextToken != nil {
+ params["NextToken"] = *NextToken
+ }
+
+ err = sns.query(params, resp)
+ for i, _ := range resp.Topics {
+ resp.Topics[i].SNS = sns
+ }
+ return
+}
+
+// CreateTopic
+//
+// See http://goo.gl/m9aAt for more details.
+func (sns *SNS) CreateTopic(Name string) (resp *CreateTopicResp, err error) {
+ resp = &CreateTopicResp{}
+ params := makeParams("CreateTopic")
+ params["Name"] = Name
+ err = sns.query(params, resp)
+ resp.Topic.SNS = sns
+ return
+}
+
+// Delete
+//
+// Helper function for deleting a topic
+func (topic *Topic) Delete() (resp *DeleteTopicResp, err error) {
+ resp = &DeleteTopicResp{}
+ params := makeParams("DeleteTopic")
+ params["TopicArn"] = topic.TopicArn
+ err = topic.SNS.query(params, resp)
+ return
+}
+
+// GetTopicAttributes
+//
+// See http://goo.gl/WXRoX for more details.
+func (sns *SNS) GetTopicAttributes(TopicArn string) (resp *GetTopicAttributesResp, err error) {
+ resp = &GetTopicAttributesResp{}
+ params := makeParams("GetTopicAttributes")
+ params["TopicArn"] = TopicArn
+ err = sns.query(params, resp)
+ return
+}
+
+// SetTopicAttributes
+//
+// See http://goo.gl/oVYW7 for more details.
+func (sns *SNS) SetTopicAttributes(AttributeName, AttributeValue, TopicArn string) (resp *SetTopicAttributesResponse, err error) {
+ resp = &SetTopicAttributesResponse{}
+ params := makeParams("SetTopicAttributes")
+
+ if AttributeName == "" || TopicArn == "" {
+ return nil, errors.New("Invalid Attribute Name or TopicArn")
+ }
+
+ params["AttributeName"] = AttributeName
+ params["AttributeValue"] = AttributeValue
+ params["TopicArn"] = TopicArn
+
+ err = sns.query(params, resp)
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/iam/iam.go b/vendor/github.com/goamz/goamz/iam/iam.go
new file mode 100644
index 000000000..7271f1bf6
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/iam.go
@@ -0,0 +1,643 @@
+// The iam package provides types and functions for interaction with the AWS
+// Identity and Access Management (IAM) service.
+package iam
+
+import (
+ "encoding/xml"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+// The IAM type encapsulates operations operations with the IAM endpoint.
+type IAM struct {
+ aws.Auth
+ aws.Region
+ httpClient *http.Client
+}
+
+// New creates a new IAM instance.
+func New(auth aws.Auth, region aws.Region) *IAM {
+ return NewWithClient(auth, region, aws.RetryingClient)
+}
+
+func NewWithClient(auth aws.Auth, region aws.Region, httpClient *http.Client) *IAM {
+ return &IAM{auth, region, httpClient}
+}
+
+func (iam *IAM) query(params map[string]string, resp interface{}) error {
+ params["Version"] = "2010-05-08"
+ params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
+ endpoint, err := url.Parse(iam.IAMEndpoint)
+ if err != nil {
+ return err
+ }
+ sign(iam.Auth, "GET", "/", params, endpoint.Host)
+ endpoint.RawQuery = multimap(params).Encode()
+ r, err := iam.httpClient.Get(endpoint.String())
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+ if r.StatusCode > 200 {
+ return buildError(r)
+ }
+
+ return xml.NewDecoder(r.Body).Decode(resp)
+}
+
+func (iam *IAM) postQuery(params map[string]string, resp interface{}) error {
+ endpoint, err := url.Parse(iam.IAMEndpoint)
+ if err != nil {
+ return err
+ }
+ params["Version"] = "2010-05-08"
+ params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
+ sign(iam.Auth, "POST", "/", params, endpoint.Host)
+ encoded := multimap(params).Encode()
+ body := strings.NewReader(encoded)
+ req, err := http.NewRequest("POST", endpoint.String(), body)
+ if err != nil {
+ return err
+ }
+ req.Header.Set("Host", endpoint.Host)
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ req.Header.Set("Content-Length", strconv.Itoa(len(encoded)))
+ r, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+ if r.StatusCode > 200 {
+ return buildError(r)
+ }
+ return xml.NewDecoder(r.Body).Decode(resp)
+}
+
+func buildError(r *http.Response) error {
+ var (
+ err Error
+ errors xmlErrors
+ )
+ xml.NewDecoder(r.Body).Decode(&errors)
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+// Response to a CreateUser request.
+//
+// See http://goo.gl/JS9Gz for more details.
+type CreateUserResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+ User User `xml:"CreateUserResult>User"`
+}
+
+// User encapsulates a user managed by IAM.
+//
+// See http://goo.gl/BwIQ3 for more details.
+type User struct {
+ Arn string
+ Path string
+ Id string `xml:"UserId"`
+ Name string `xml:"UserName"`
+}
+
+// CreateUser creates a new user in IAM.
+//
+// See http://goo.gl/JS9Gz for more details.
+func (iam *IAM) CreateUser(name, path string) (*CreateUserResp, error) {
+ params := map[string]string{
+ "Action": "CreateUser",
+ "Path": path,
+ "UserName": name,
+ }
+ resp := new(CreateUserResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response for GetUser requests.
+//
+// See http://goo.gl/ZnzRN for more details.
+type GetUserResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+ User User `xml:"GetUserResult>User"`
+}
+
+// GetUser gets a user from IAM.
+//
+// See http://goo.gl/ZnzRN for more details.
+func (iam *IAM) GetUser(name string) (*GetUserResp, error) {
+ params := map[string]string{
+ "Action": "GetUser",
+ "UserName": name,
+ }
+ resp := new(GetUserResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteUser deletes a user from IAM.
+//
+// See http://goo.gl/jBuCG for more details.
+func (iam *IAM) DeleteUser(name string) (*SimpleResp, error) {
+ params := map[string]string{
+ "Action": "DeleteUser",
+ "UserName": name,
+ }
+ resp := new(SimpleResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a CreateGroup request.
+//
+// See http://goo.gl/n7NNQ for more details.
+type CreateGroupResp struct {
+ Group Group `xml:"CreateGroupResult>Group"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// Group encapsulates a group managed by IAM.
+//
+// See http://goo.gl/ae7Vs for more details.
+type Group struct {
+ Arn string
+ Id string `xml:"GroupId"`
+ Name string `xml:"GroupName"`
+ Path string
+}
+
+// CreateGroup creates a new group in IAM.
+//
+// The path parameter can be used to identify which division or part of the
+// organization the user belongs to.
+//
+// If path is unset ("") it defaults to "/".
+//
+// See http://goo.gl/n7NNQ for more details.
+func (iam *IAM) CreateGroup(name string, path string) (*CreateGroupResp, error) {
+ params := map[string]string{
+ "Action": "CreateGroup",
+ "GroupName": name,
+ }
+ if path != "" {
+ params["Path"] = path
+ }
+ resp := new(CreateGroupResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a ListGroups request.
+//
+// See http://goo.gl/W2TRj for more details.
+type GroupsResp struct {
+ Groups []Group `xml:"ListGroupsResult>Groups>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// Groups list the groups that have the specified path prefix.
+//
+// The parameter pathPrefix is optional. If pathPrefix is "", all groups are
+// returned.
+//
+// See http://goo.gl/W2TRj for more details.
+func (iam *IAM) Groups(pathPrefix string) (*GroupsResp, error) {
+ params := map[string]string{
+ "Action": "ListGroups",
+ }
+ if pathPrefix != "" {
+ params["PathPrefix"] = pathPrefix
+ }
+ resp := new(GroupsResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteGroup deletes a group from IAM.
+//
+// See http://goo.gl/d5i2i for more details.
+func (iam *IAM) DeleteGroup(name string) (*SimpleResp, error) {
+ params := map[string]string{
+ "Action": "DeleteGroup",
+ "GroupName": name,
+ }
+ resp := new(SimpleResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a CreateAccessKey request.
+//
+// See http://goo.gl/L46Py for more details.
+type CreateAccessKeyResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+ AccessKey AccessKey `xml:"CreateAccessKeyResult>AccessKey"`
+}
+
+// AccessKey encapsulates an access key generated for a user.
+//
+// See http://goo.gl/LHgZR for more details.
+type AccessKey struct {
+ UserName string
+ Id string `xml:"AccessKeyId"`
+ Secret string `xml:"SecretAccessKey,omitempty"`
+ Status string
+}
+
+// CreateAccessKey creates a new access key in IAM.
+//
+// See http://goo.gl/L46Py for more details.
+func (iam *IAM) CreateAccessKey(userName string) (*CreateAccessKeyResp, error) {
+ params := map[string]string{
+ "Action": "CreateAccessKey",
+ "UserName": userName,
+ }
+ resp := new(CreateAccessKeyResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to AccessKeys request.
+//
+// See http://goo.gl/Vjozx for more details.
+type AccessKeysResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+ AccessKeys []AccessKey `xml:"ListAccessKeysResult>AccessKeyMetadata>member"`
+}
+
+// AccessKeys lists all acccess keys associated with a user.
+//
+// The userName parameter is optional. If set to "", the userName is determined
+// implicitly based on the AWS Access Key ID used to sign the request.
+//
+// See http://goo.gl/Vjozx for more details.
+func (iam *IAM) AccessKeys(userName string) (*AccessKeysResp, error) {
+ params := map[string]string{
+ "Action": "ListAccessKeys",
+ }
+ if userName != "" {
+ params["UserName"] = userName
+ }
+ resp := new(AccessKeysResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteAccessKey deletes an access key from IAM.
+//
+// The userName parameter is optional. If set to "", the userName is determined
+// implicitly based on the AWS Access Key ID used to sign the request.
+//
+// See http://goo.gl/hPGhw for more details.
+func (iam *IAM) DeleteAccessKey(id, userName string) (*SimpleResp, error) {
+ params := map[string]string{
+ "Action": "DeleteAccessKey",
+ "AccessKeyId": id,
+ }
+ if userName != "" {
+ params["UserName"] = userName
+ }
+ resp := new(SimpleResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response to a GetUserPolicy request.
+//
+// See http://goo.gl/BH04O for more details.
+type GetUserPolicyResp struct {
+ Policy UserPolicy `xml:"GetUserPolicyResult"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// UserPolicy encapsulates an IAM group policy.
+//
+// See http://goo.gl/C7hgS for more details.
+type UserPolicy struct {
+ Name string `xml:"PolicyName"`
+ UserName string `xml:"UserName"`
+ Document string `xml:"PolicyDocument"`
+}
+
+// GetUserPolicy gets a user policy in IAM.
+//
+// See http://goo.gl/BH04O for more details.
+func (iam *IAM) GetUserPolicy(userName, policyName string) (*GetUserPolicyResp, error) {
+ params := map[string]string{
+ "Action": "GetUserPolicy",
+ "UserName": userName,
+ "PolicyName": policyName,
+ }
+ resp := new(GetUserPolicyResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+ return nil, nil
+}
+
+// PutUserPolicy creates a user policy in IAM.
+//
+// See http://goo.gl/ldCO8 for more details.
+func (iam *IAM) PutUserPolicy(userName, policyName, policyDocument string) (*SimpleResp, error) {
+ params := map[string]string{
+ "Action": "PutUserPolicy",
+ "UserName": userName,
+ "PolicyName": policyName,
+ "PolicyDocument": policyDocument,
+ }
+ resp := new(SimpleResp)
+ if err := iam.postQuery(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// DeleteUserPolicy deletes a user policy from IAM.
+//
+// See http://goo.gl/7Jncn for more details.
+func (iam *IAM) DeleteUserPolicy(userName, policyName string) (*SimpleResp, error) {
+ params := map[string]string{
+ "Action": "DeleteUserPolicy",
+ "PolicyName": policyName,
+ "UserName": userName,
+ }
+ resp := new(SimpleResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response for AddUserToGroup requests.
+//
+// See http://goo.gl/ZnzRN for more details.
+type AddUserToGroupResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// AddUserToGroup adds a user to a specific group
+//
+// See http://goo.gl/ZnzRN for more details.
+func (iam *IAM) AddUserToGroup(name, group string) (*AddUserToGroupResp, error) {
+
+ params := map[string]string{
+ "Action": "AddUserToGroup",
+ "GroupName": group,
+ "UserName": name}
+ resp := new(AddUserToGroupResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response for a ListAccountAliases request.
+//
+// See http://goo.gl/MMN79v for more details.
+type ListAccountAliasesResp struct {
+ AccountAliases []string `xml:"ListAccountAliasesResult>AccountAliases>member"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// ListAccountAliases lists the account aliases associated with the account
+//
+// See http://goo.gl/MMN79v for more details.
+func (iam *IAM) ListAccountAliases() (*ListAccountAliasesResp, error) {
+ params := map[string]string{
+ "Action": "ListAccountAliases",
+ }
+ resp := new(ListAccountAliasesResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response for a CreateAccountAlias request.
+//
+// See http://goo.gl/oU5C4H for more details.
+type CreateAccountAliasResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// CreateAccountAlias creates an alias for your AWS account.
+//
+// See http://goo.gl/oU5C4H for more details.
+func (iam *IAM) CreateAccountAlias(alias string) (*CreateAccountAliasResp, error) {
+ params := map[string]string{
+ "Action": "CreateAccountAlias",
+ "AccountAlias": alias,
+ }
+ resp := new(CreateAccountAliasResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Response for a DeleteAccountAlias request.
+//
+// See http://goo.gl/hKalgg for more details.
+type DeleteAccountAliasResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DeleteAccountAlias deletes the specified AWS account alias.
+//
+// See http://goo.gl/hKalgg for more details.
+func (iam *IAM) DeleteAccountAlias(alias string) (*DeleteAccountAliasResp, error) {
+ params := map[string]string{
+ "Action": "DeleteAccountAlias",
+ "AccountAlias": alias,
+ }
+ resp := new(DeleteAccountAliasResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+type SimpleResp struct {
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+type xmlErrors struct {
+ Errors []Error `xml:"Error"`
+}
+
+// ServerCertificateMetadata represents a ServerCertificateMetadata object
+//
+// See http://goo.gl/Rfu7LD for more details.
+type ServerCertificateMetadata struct {
+ Arn string `xml:"Arn"`
+ Expiration time.Time `xml:"Expiration"`
+ Path string `xml:"Path"`
+ ServerCertificateId string `xml:"ServerCertificateId"`
+ ServerCertificateName string `xml:"ServerCertificateName"`
+ UploadDate time.Time `xml:"UploadDate"`
+}
+
+// UploadServerCertificateResponse wraps up for UploadServerCertificate request.
+//
+// See http://goo.gl/bomzce for more details.
+type UploadServerCertificateResponse struct {
+ ServerCertificateMetadata ServerCertificateMetadata `xml:"UploadServerCertificateResult>ServerCertificateMetadata"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// UploadServerCertificateParams wraps up the params to be passed for the UploadServerCertificate request
+//
+// See http://goo.gl/bomzce for more details.
+type UploadServerCertificateParams struct {
+ ServerCertificateName string
+ PrivateKey string
+ CertificateBody string
+ CertificateChain string
+ Path string
+}
+
+// UploadServerCertificate uploads a server certificate entity for the AWS account.
+//
+// Required Params: ServerCertificateName, PrivateKey, CertificateBody
+//
+// See http://goo.gl/bomzce for more details.
+func (iam *IAM) UploadServerCertificate(options *UploadServerCertificateParams) (
+ *UploadServerCertificateResponse, error) {
+ params := map[string]string{
+ "Action": "UploadServerCertificate",
+ "ServerCertificateName": options.ServerCertificateName,
+ "PrivateKey": options.PrivateKey,
+ "CertificateBody": options.CertificateBody,
+ }
+ if options.CertificateChain != "" {
+ params["CertificateChain"] = options.CertificateChain
+ }
+ if options.Path != "" {
+ params["Path"] = options.Path
+ }
+
+ resp := new(UploadServerCertificateResponse)
+ if err := iam.postQuery(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// ListServerCertificates lists all available certificates for the AWS account specified
+//
+// Required Params: None
+//
+// Optional Params: Marker, and, PathPrefix
+//
+// See http://goo.gl/bwn0Nb for specifics
+
+type ListServerCertificatesParams struct {
+ Marker string
+ PathPrefix string
+}
+
+type ListServerCertificatesResp struct {
+ ServerCertificates []ServerCertificateMetadata `xml:"ListServerCertificatesResult>ServerCertificateMetadataList>member>ServerCertificateMetadata"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+ IsTruncated bool `xml:"ListServerCertificatesResult>IsTruncated"`
+}
+
+func (iam *IAM) ListServerCertificates(options *ListServerCertificatesParams) (
+ *ListServerCertificatesResp, error) {
+ params := map[string]string{
+ "Action": "ListServerCertificates",
+ }
+
+ if options.Marker != "" {
+ params["Marker"] = options.Marker
+ }
+
+ if options.PathPrefix != "" {
+ params["PathPrefix"] = options.PathPrefix
+ }
+
+ resp := new(ListServerCertificatesResp)
+ if err := iam.query(params, resp); err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+}
+
+// DeleteServerCertificate deletes the specified server certificate.
+//
+// See http://goo.gl/W4nmxQ for more details.
+func (iam *IAM) DeleteServerCertificate(serverCertificateName string) (*SimpleResp, error) {
+ params := map[string]string{
+ "Action": "DeleteServerCertificate",
+ "ServerCertificateName": serverCertificateName,
+ }
+
+ resp := new(SimpleResp)
+ if err := iam.postQuery(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// Error encapsulates an IAM error.
+type Error struct {
+ // HTTP status code of the error.
+ StatusCode int
+
+ // AWS code of the error.
+ Code string
+
+ // Message explaining the error.
+ Message string
+}
+
+func (e *Error) Error() string {
+ var prefix string
+ if e.Code != "" {
+ prefix = e.Code + ": "
+ }
+ if prefix == "" && e.StatusCode > 0 {
+ prefix = strconv.Itoa(e.StatusCode) + ": "
+ }
+ return prefix + e.Message
+}
diff --git a/vendor/github.com/goamz/goamz/iam/iam_test.go b/vendor/github.com/goamz/goamz/iam/iam_test.go
new file mode 100644
index 000000000..e73935670
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/iam_test.go
@@ -0,0 +1,450 @@
+package iam_test
+
+import (
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/iam"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+type S struct {
+ iam *iam.IAM
+}
+
+var _ = Suite(&S{})
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.iam = iam.NewWithClient(auth, aws.Region{IAMEndpoint: testServer.URL}, testutil.DefaultClient)
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestCreateUser(c *C) {
+ testServer.Response(200, nil, CreateUserExample)
+ resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "CreateUser")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(values.Get("Path"), Equals, "/division_abc/subdivision_xyz/")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+ expected := iam.User{
+ Path: "/division_abc/subdivision_xyz/",
+ Name: "Bob",
+ Id: "AIDACKCEVSQ6C2EXAMPLE",
+ Arn: "arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob",
+ }
+ c.Assert(resp.User, DeepEquals, expected)
+}
+
+func (s *S) TestCreateUserConflict(c *C) {
+ testServer.Response(409, nil, DuplicateUserExample)
+ resp, err := s.iam.CreateUser("Bob", "/division_abc/subdivision_xyz/")
+ testServer.WaitRequest()
+ c.Assert(resp, IsNil)
+ c.Assert(err, NotNil)
+ e, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(e.Message, Equals, "User with name Bob already exists.")
+ c.Assert(e.Code, Equals, "EntityAlreadyExists")
+}
+
+func (s *S) TestGetUser(c *C) {
+ testServer.Response(200, nil, GetUserExample)
+ resp, err := s.iam.GetUser("Bob")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "GetUser")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+ expected := iam.User{
+ Path: "/division_abc/subdivision_xyz/",
+ Name: "Bob",
+ Id: "AIDACKCEVSQ6C2EXAMPLE",
+ Arn: "arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob",
+ }
+ c.Assert(resp.User, DeepEquals, expected)
+}
+
+func (s *S) TestDeleteUser(c *C) {
+ testServer.Response(200, nil, RequestIdExample)
+ resp, err := s.iam.DeleteUser("Bob")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "DeleteUser")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestCreateGroup(c *C) {
+ testServer.Response(200, nil, CreateGroupExample)
+ resp, err := s.iam.CreateGroup("Admins", "/admins/")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "CreateGroup")
+ c.Assert(values.Get("GroupName"), Equals, "Admins")
+ c.Assert(values.Get("Path"), Equals, "/admins/")
+ c.Assert(err, IsNil)
+ c.Assert(resp.Group.Path, Equals, "/admins/")
+ c.Assert(resp.Group.Name, Equals, "Admins")
+ c.Assert(resp.Group.Id, Equals, "AGPACKCEVSQ6C2EXAMPLE")
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestCreateGroupWithoutPath(c *C) {
+ testServer.Response(200, nil, CreateGroupExample)
+ _, err := s.iam.CreateGroup("Managers", "")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "CreateGroup")
+ c.Assert(err, IsNil)
+ _, ok := map[string][]string(values)["Path"]
+ c.Assert(ok, Equals, false)
+}
+
+func (s *S) TestDeleteGroup(c *C) {
+ testServer.Response(200, nil, RequestIdExample)
+ resp, err := s.iam.DeleteGroup("Admins")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "DeleteGroup")
+ c.Assert(values.Get("GroupName"), Equals, "Admins")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestListGroups(c *C) {
+ testServer.Response(200, nil, ListGroupsExample)
+ resp, err := s.iam.Groups("/division_abc/")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "ListGroups")
+ c.Assert(values.Get("PathPrefix"), Equals, "/division_abc/")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+ expected := []iam.Group{
+ {
+ Path: "/division_abc/subdivision_xyz/",
+ Name: "Admins",
+ Id: "AGPACKCEVSQ6C2EXAMPLE",
+ Arn: "arn:aws:iam::123456789012:group/Admins",
+ },
+ {
+ Path: "/division_abc/subdivision_xyz/product_1234/engineering/",
+ Name: "Test",
+ Id: "AGP2MAB8DPLSRHEXAMPLE",
+ Arn: "arn:aws:iam::123456789012:group/division_abc/subdivision_xyz/product_1234/engineering/Test",
+ },
+ {
+ Path: "/division_abc/subdivision_xyz/product_1234/",
+ Name: "Managers",
+ Id: "AGPIODR4TAW7CSEXAMPLE",
+ Arn: "arn:aws:iam::123456789012:group/division_abc/subdivision_xyz/product_1234/Managers",
+ },
+ }
+ c.Assert(resp.Groups, DeepEquals, expected)
+}
+
+func (s *S) TestListGroupsWithoutPathPrefix(c *C) {
+ testServer.Response(200, nil, ListGroupsExample)
+ _, err := s.iam.Groups("")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "ListGroups")
+ c.Assert(err, IsNil)
+ _, ok := map[string][]string(values)["PathPrefix"]
+ c.Assert(ok, Equals, false)
+}
+
+func (s *S) TestCreateAccessKey(c *C) {
+ testServer.Response(200, nil, CreateAccessKeyExample)
+ resp, err := s.iam.CreateAccessKey("Bob")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "CreateAccessKey")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(err, IsNil)
+ c.Assert(resp.AccessKey.UserName, Equals, "Bob")
+ c.Assert(resp.AccessKey.Id, Equals, "AKIAIOSFODNN7EXAMPLE")
+ c.Assert(resp.AccessKey.Secret, Equals, "wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY")
+ c.Assert(resp.AccessKey.Status, Equals, "Active")
+}
+
+func (s *S) TestDeleteAccessKey(c *C) {
+ testServer.Response(200, nil, RequestIdExample)
+ resp, err := s.iam.DeleteAccessKey("ysa8hasdhasdsi", "Bob")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "DeleteAccessKey")
+ c.Assert(values.Get("AccessKeyId"), Equals, "ysa8hasdhasdsi")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestDeleteAccessKeyBlankUserName(c *C) {
+ testServer.Response(200, nil, RequestIdExample)
+ _, err := s.iam.DeleteAccessKey("ysa8hasdhasdsi", "")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "DeleteAccessKey")
+ c.Assert(values.Get("AccessKeyId"), Equals, "ysa8hasdhasdsi")
+ _, ok := map[string][]string(values)["UserName"]
+ c.Assert(ok, Equals, false)
+}
+
+func (s *S) TestAccessKeys(c *C) {
+ testServer.Response(200, nil, ListAccessKeyExample)
+ resp, err := s.iam.AccessKeys("Bob")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "ListAccessKeys")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+ c.Assert(resp.AccessKeys, HasLen, 2)
+ c.Assert(resp.AccessKeys[0].Id, Equals, "AKIAIOSFODNN7EXAMPLE")
+ c.Assert(resp.AccessKeys[0].UserName, Equals, "Bob")
+ c.Assert(resp.AccessKeys[0].Status, Equals, "Active")
+ c.Assert(resp.AccessKeys[1].Id, Equals, "AKIAI44QH8DHBEXAMPLE")
+ c.Assert(resp.AccessKeys[1].UserName, Equals, "Bob")
+ c.Assert(resp.AccessKeys[1].Status, Equals, "Inactive")
+}
+
+func (s *S) TestAccessKeysBlankUserName(c *C) {
+ testServer.Response(200, nil, ListAccessKeyExample)
+ _, err := s.iam.AccessKeys("")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "ListAccessKeys")
+ _, ok := map[string][]string(values)["UserName"]
+ c.Assert(ok, Equals, false)
+}
+
+func (s *S) TestGetUserPolicy(c *C) {
+ testServer.Response(200, nil, GetUserPolicyExample)
+ resp, err := s.iam.GetUserPolicy("Bob", "AllAccessPolicy")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "GetUserPolicy")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(values.Get("PolicyName"), Equals, "AllAccessPolicy")
+ c.Assert(err, IsNil)
+ c.Assert(resp.Policy.UserName, Equals, "Bob")
+ c.Assert(resp.Policy.Name, Equals, "AllAccessPolicy")
+ c.Assert(strings.TrimSpace(resp.Policy.Document), Equals, `{"Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}`)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestPutUserPolicy(c *C) {
+ document := `{
+ "Statement": [
+ {
+ "Action": [
+ "s3:*"
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ "arn:aws:s3:::8shsns19s90ajahadsj/*",
+ "arn:aws:s3:::8shsns19s90ajahadsj"
+ ]
+ }]
+ }`
+ testServer.Response(200, nil, RequestIdExample)
+ resp, err := s.iam.PutUserPolicy("Bob", "AllAccessPolicy", document)
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.FormValue("Action"), Equals, "PutUserPolicy")
+ c.Assert(req.FormValue("PolicyName"), Equals, "AllAccessPolicy")
+ c.Assert(req.FormValue("UserName"), Equals, "Bob")
+ c.Assert(req.FormValue("PolicyDocument"), Equals, document)
+ c.Assert(req.FormValue("Version"), Equals, "2010-05-08")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestDeleteUserPolicy(c *C) {
+ testServer.Response(200, nil, RequestIdExample)
+ resp, err := s.iam.DeleteUserPolicy("Bob", "AllAccessPolicy")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "DeleteUserPolicy")
+ c.Assert(values.Get("PolicyName"), Equals, "AllAccessPolicy")
+ c.Assert(values.Get("UserName"), Equals, "Bob")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestAddUserToGroup(c *C) {
+ testServer.Response(200, nil, AddUserToGroupExample)
+ resp, err := s.iam.AddUserToGroup("admin1", "Admins")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "AddUserToGroup")
+ c.Assert(values.Get("GroupName"), Equals, "Admins")
+ c.Assert(values.Get("UserName"), Equals, "admin1")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestListAccountAliases(c *C) {
+ testServer.Response(200, nil, ListAccountAliasesExample)
+ resp, err := s.iam.ListAccountAliases()
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "ListAccountAliases")
+ c.Assert(err, IsNil)
+ c.Assert(resp.AccountAliases[0], Equals, "foocorporation")
+ c.Assert(resp.RequestId, Equals, "c5a076e9-f1b0-11df-8fbe-45274EXAMPLE")
+}
+
+func (s *S) TestCreateAccountAlias(c *C) {
+ testServer.Response(200, nil, CreateAccountAliasExample)
+ resp, err := s.iam.CreateAccountAlias("foobaz")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "CreateAccountAlias")
+ c.Assert(values.Get("AccountAlias"), Equals, "foobaz")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "36b5db08-f1b0-11df-8fbe-45274EXAMPLE")
+}
+
+func (s *S) TestDeleteAccountAlias(c *C) {
+ testServer.Response(200, nil, DeleteAccountAliasExample)
+ resp, err := s.iam.DeleteAccountAlias("foobaz")
+ values := testServer.WaitRequest().URL.Query()
+ c.Assert(values.Get("Action"), Equals, "DeleteAccountAlias")
+ c.Assert(values.Get("AccountAlias"), Equals, "foobaz")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestUploadServerCertificate(c *C) {
+ testServer.Response(200, nil, UploadServerCertificateExample)
+
+ certificateBody := `
+-----BEGIN CERTIFICATE-----
+MIICdzCCAeCgAwIBAgIGANc+Ha2wMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNVBAYT
+AlVTMRMwEQYDVQQKEwpBbWF6b24uY29tMQwwCgYDVQQLEwNBV1MxITAfBgNVBAMT
+GEFXUyBMaW1pdGVkLUFzc3VyYW5jZSBDQTAeFw0wOTAyMDQxNzE5MjdaFw0xMDAy
+MDQxNzE5MjdaMFIxCzAJBgNVBAYTAlVTMRMwEQYDVQQKEwpBbWF6b24uY29tMRcw
+FQYDVQQLEw5BV1MtRGV2ZWxvcGVyczEVMBMGA1UEAxMMNTdxNDl0c3ZwYjRtMIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCpB/vsOwmT/O0td1RqzKjttSBaPjbr
+dqwNe9BrOyB08fw2+Ch5oonZYXfGUrT6mkYXH5fQot9HvASrzAKHO596FdJA6DmL
+ywdWe1Oggk7zFSXO1Xv+3vPrJtaYxYo3eRIp7w80PMkiOv6M0XK8ubcTouODeJbf
+suDqcLnLDxwsvwIDAQABo1cwVTAOBgNVHQ8BAf8EBAMCBaAwFgYDVR0lAQH/BAww
+CgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQULGNaBphBumaKbDRK
+CAi0mH8B3mowDQYJKoZIhvcNAQEFBQADgYEAuKxhkXaCLGcqDuweKtO/AEw9ZePH
+wr0XqsaIK2HZboqruebXEGsojK4Ks0WzwgrEynuHJwTn760xe39rSqXWIOGrOBaX
+wFpWHVjTFMKk+tSDG1lssLHyYWWdFFU4AnejRGORJYNaRHgVTKjHphc5jEhHm0BX
+AEaHzTpmEXAMPLE=
+-----END CERTIFICATE-----
+`
+ privateKey := `
+-----BEGIN DSA PRIVATE KEY-----
+MIIBugIBTTKBgQD33xToSXPJ6hr37L3+KNi3/7DgywlBcvlFPPSHIw3ORuO/22mT
+8Cy5fT89WwNvZ3BPKWU6OZ38TQv3eWjNc/3U3+oqVNG2poX5nCPOtO1b96HYX2mR
+3FTdH6FRKbQEhpDzZ6tRrjTHjMX6sT3JRWkBd2c4bGu+HUHO1H7QvrCTeQIVTKMs
+TCKCyrLiGhUWuUGNJUMU6y6zToGTHl84Tz7TPwDGDXuy/Dk5s4jTVr+xibROC/gS
+Qrs4Dzz3T1ze6lvU8S1KT9UsOB5FUJNTTPCPey+Lo4mmK6b23XdTyCIT8e2fsm2j
+jHHC1pIPiTkdLS3j6ZYjF8LY6TENFng+LDY/xwPOl7TJVoD3J/WXC2J9CEYq9o34
+kq6WWn3CgYTuo54nXUgnoCb3xdG8COFrg+oTbIkHTSzs3w5o/GGgKK7TDF3UlJjq
+vHNyJQ6kWBrQRR1Xp5KYQ4c/Dm5kef+62mH53HpcCELguWVcffuVQpmq3EWL9Zp9
+jobTJQ2VHjb5IVxiO6HRSd27di3njyrzUuJCyHSDTqwLJmTThpd6OTIUTL3Tc4m2
+62TITdw53KWJEXAMPLE=
+-----END DSA PRIVATE KEY-----
+`
+ params := &iam.UploadServerCertificateParams{
+ ServerCertificateName: "ProdServerCert",
+ Path: "/company/servercerts/",
+ PrivateKey: privateKey,
+ CertificateBody: certificateBody,
+ }
+
+ resp, err := s.iam.UploadServerCertificate(params)
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.FormValue("Action"), Equals, "UploadServerCertificate")
+ c.Assert(req.FormValue("CertificateBody"), Equals, certificateBody)
+ c.Assert(req.FormValue("PrivateKey"), Equals, privateKey)
+ c.Assert(req.FormValue("ServerCertificateName"), Equals, "ProdServerCert")
+ c.Assert(req.FormValue("CertificateChain"), Equals, "")
+ c.Assert(req.FormValue("Path"), Equals, "/company/servercerts/")
+ c.Assert(req.FormValue("Version"), Equals, "2010-05-08")
+ c.Assert(err, IsNil)
+
+ ud, _ := time.Parse(time.RFC3339, "2010-05-08T01:02:03.004Z")
+ exp, _ := time.Parse(time.RFC3339, "2012-05-08T01:02:03.004Z")
+ expected := iam.ServerCertificateMetadata{
+ Arn: "arn:aws:iam::123456789012:server-certificate/company/servercerts/ProdServerCert",
+ ServerCertificateName: "ProdServerCert",
+ ServerCertificateId: "ASCACKCEVSQ6C2EXAMPLE",
+ Path: "/company/servercerts/",
+ UploadDate: ud,
+ Expiration: exp,
+ }
+ c.Assert(resp.ServerCertificateMetadata, DeepEquals, expected)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
+
+func (s *S) TestListServerCertificates(c *C) {
+ testServer.Response(200, nil, ListServerCertificatesExample)
+ params := &iam.ListServerCertificatesParams{
+ Marker: "my-fake-marker",
+ PathPrefix: "/some/fake/path",
+ }
+
+ resp, err := s.iam.ListServerCertificates(params)
+ req := testServer.WaitRequest()
+
+ c.Assert(err, IsNil)
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.FormValue("Action"), Equals, "ListServerCertificates")
+ c.Assert(req.FormValue("Marker"), Equals, "my-fake-marker")
+ c.Assert(req.FormValue("PathPrefix"), Equals, "/some/fake/path")
+ c.Assert(req.FormValue("Version"), Equals, "2010-05-08")
+
+ uploadDate, _ := time.Parse(time.RFC3339, "2010-05-08T01:02:03.004Z")
+ expirationDate, _ := time.Parse(time.RFC3339, "2012-05-08T01:02:03.004Z")
+ expected := []iam.ServerCertificateMetadata{
+ {
+ Arn: "arn:aws:iam::123456789012:server-certificate/company/servercerts/ProdServerCert",
+ ServerCertificateName: "ProdServerCert",
+ ServerCertificateId: "ASCACKCEVSQ6C2EXAMPLE1",
+ Path: "/some/fake/path",
+ UploadDate: uploadDate,
+ Expiration: expirationDate,
+ },
+ {
+ Arn: "arn:aws:iam::123456789012:server-certificate/company/servercerts/BetaServerCert",
+ ServerCertificateName: "BetaServerCert",
+ ServerCertificateId: "ASCACKCEVSQ6C2EXAMPLE2",
+ Path: "/some/fake/path",
+ UploadDate: uploadDate,
+ Expiration: expirationDate,
+ },
+ {
+ Arn: "arn:aws:iam::123456789012:server-certificate/company/servercerts/TestServerCert",
+ ServerCertificateName: "TestServerCert",
+ ServerCertificateId: "ASCACKCEVSQ6C2EXAMPLE3",
+ Path: "/some/fake/path",
+ UploadDate: uploadDate,
+ Expiration: expirationDate,
+ },
+ }
+
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eTHISDIFFERENTTEST")
+ c.Assert(resp.IsTruncated, Equals, false)
+ c.Assert(resp.ServerCertificates, DeepEquals, expected)
+}
+
+func (s *S) TestDeleteServerCertificate(c *C) {
+ testServer.Response(200, nil, DeleteServerCertificateExample)
+ resp, err := s.iam.DeleteServerCertificate("ProdServerCert")
+ req := testServer.WaitRequest()
+ c.Assert(req.FormValue("Action"), Equals, "DeleteServerCertificate")
+ c.Assert(req.FormValue("ServerCertificateName"), Equals, "ProdServerCert")
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "7a62c49f-347e-4fc4-9331-6e8eEXAMPLE")
+}
diff --git a/vendor/github.com/goamz/goamz/iam/iami_test.go b/vendor/github.com/goamz/goamz/iam/iami_test.go
new file mode 100644
index 000000000..26f32386f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/iami_test.go
@@ -0,0 +1,209 @@
+package iam_test
+
+import (
+ "net/url"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/iam"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+// AmazonServer represents an Amazon AWS server.
+type AmazonServer struct {
+ auth aws.Auth
+}
+
+func (s *AmazonServer) SetUp(c *C) {
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ c.Fatal(err)
+ }
+ s.auth = auth
+}
+
+var _ = Suite(&AmazonClientSuite{})
+
+// AmazonClientSuite tests the client against a live AWS server.
+type AmazonClientSuite struct {
+ srv AmazonServer
+ ClientTests
+}
+
+func (s *AmazonClientSuite) SetUpSuite(c *C) {
+ if !testutil.Amazon {
+ c.Skip("AmazonClientSuite tests not enabled")
+ }
+ s.srv.SetUp(c)
+ s.iam = iam.New(s.srv.auth, aws.USEast)
+}
+
+// ClientTests defines integration tests designed to test the client.
+// It is not used as a test suite in itself, but embedded within
+// another type.
+type ClientTests struct {
+ iam *iam.IAM
+}
+
+func (s *ClientTests) TestCreateAndDeleteUser(c *C) {
+ createResp, err := s.iam.CreateUser("gopher", "/gopher/")
+ c.Assert(err, IsNil)
+ getResp, err := s.iam.GetUser("gopher")
+ c.Assert(err, IsNil)
+ c.Assert(createResp.User, DeepEquals, getResp.User)
+ _, err = s.iam.DeleteUser("gopher")
+ c.Assert(err, IsNil)
+}
+
+func (s *ClientTests) TestCreateUserError(c *C) {
+ _, err := s.iam.CreateUser("gopher", "/gopher/")
+ c.Assert(err, IsNil)
+ defer s.iam.DeleteUser("gopher")
+ _, err = s.iam.CreateUser("gopher", "/")
+ iamErr, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(iamErr.StatusCode, Equals, 409)
+ c.Assert(iamErr.Code, Equals, "EntityAlreadyExists")
+ c.Assert(iamErr.Message, Equals, "User with name gopher already exists.")
+}
+
+func (s *ClientTests) TestDeleteUserError(c *C) {
+ _, err := s.iam.DeleteUser("gopher")
+ iamErr, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(iamErr.StatusCode, Equals, 404)
+ c.Assert(iamErr.Code, Equals, "NoSuchEntity")
+ c.Assert(iamErr.Message, Equals, "The user with name gopher cannot be found.")
+}
+
+func (s *ClientTests) TestGetUserError(c *C) {
+ _, err := s.iam.GetUser("gopher")
+ iamErr, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(iamErr.StatusCode, Equals, 404)
+ c.Assert(iamErr.Code, Equals, "NoSuchEntity")
+ c.Assert(iamErr.Message, Equals, "The user with name gopher cannot be found.")
+}
+
+func (s *ClientTests) TestCreateListAndDeleteAccessKey(c *C) {
+ createUserResp, err := s.iam.CreateUser("gopher", "/gopher/")
+ c.Assert(err, IsNil)
+ defer s.iam.DeleteUser(createUserResp.User.Name)
+ createKeyResp, err := s.iam.CreateAccessKey(createUserResp.User.Name)
+ c.Assert(err, IsNil)
+ listKeyResp, err := s.iam.AccessKeys(createUserResp.User.Name)
+ c.Assert(err, IsNil)
+ c.Assert(listKeyResp.AccessKeys, HasLen, 1)
+ createKeyResp.AccessKey.Secret = ""
+ c.Assert(listKeyResp.AccessKeys[0], DeepEquals, createKeyResp.AccessKey)
+ _, err = s.iam.DeleteAccessKey(createKeyResp.AccessKey.Id, createUserResp.User.Name)
+ c.Assert(err, IsNil)
+}
+
+func (s *ClientTests) TestCreateAccessKeyError(c *C) {
+ _, err := s.iam.CreateAccessKey("unknowngopher")
+ c.Assert(err, NotNil)
+ iamErr, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(iamErr.StatusCode, Equals, 404)
+ c.Assert(iamErr.Code, Equals, "NoSuchEntity")
+ c.Assert(iamErr.Message, Equals, "The user with name unknowngopher cannot be found.")
+}
+
+func (s *ClientTests) TestListAccessKeysUserNotFound(c *C) {
+ _, err := s.iam.AccessKeys("unknowngopher")
+ c.Assert(err, NotNil)
+ iamErr, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(iamErr.StatusCode, Equals, 404)
+ c.Assert(iamErr.Code, Equals, "NoSuchEntity")
+ c.Assert(iamErr.Message, Equals, "The user with name unknowngopher cannot be found.")
+}
+
+func (s *ClientTests) TestListAccessKeysUserWithoutKeys(c *C) {
+ createUserResp, err := s.iam.CreateUser("gopher", "/")
+ c.Assert(err, IsNil)
+ defer s.iam.DeleteUser(createUserResp.User.Name)
+ resp, err := s.iam.AccessKeys(createUserResp.User.Name)
+ c.Assert(err, IsNil)
+ c.Assert(resp.AccessKeys, HasLen, 0)
+}
+
+func (s *ClientTests) TestCreateListAndDeleteGroup(c *C) {
+ cResp1, err := s.iam.CreateGroup("Finances", "/finances/")
+ c.Assert(err, IsNil)
+ cResp2, err := s.iam.CreateGroup("DevelopmentManagers", "/development/managers/")
+ c.Assert(err, IsNil)
+ lResp, err := s.iam.Groups("/development/")
+ c.Assert(err, IsNil)
+ c.Assert(lResp.Groups, HasLen, 1)
+ c.Assert(cResp2.Group, DeepEquals, lResp.Groups[0])
+ lResp, err = s.iam.Groups("")
+ c.Assert(err, IsNil)
+ c.Assert(lResp.Groups, HasLen, 2)
+ if lResp.Groups[0].Name == cResp1.Group.Name {
+ c.Assert([]iam.Group{cResp1.Group, cResp2.Group}, DeepEquals, lResp.Groups)
+ } else {
+ c.Assert([]iam.Group{cResp2.Group, cResp1.Group}, DeepEquals, lResp.Groups)
+ }
+ _, err = s.iam.DeleteGroup("DevelopmentManagers")
+ c.Assert(err, IsNil)
+ lResp, err = s.iam.Groups("/development/")
+ c.Assert(err, IsNil)
+ c.Assert(lResp.Groups, HasLen, 0)
+ _, err = s.iam.DeleteGroup("Finances")
+ c.Assert(err, IsNil)
+}
+
+func (s *ClientTests) TestCreateGroupError(c *C) {
+ _, err := s.iam.CreateGroup("Finances", "/finances/")
+ c.Assert(err, IsNil)
+ defer s.iam.DeleteGroup("Finances")
+ _, err = s.iam.CreateGroup("Finances", "/something-else/")
+ iamErr, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(iamErr.StatusCode, Equals, 409)
+ c.Assert(iamErr.Code, Equals, "EntityAlreadyExists")
+ c.Assert(iamErr.Message, Equals, "Group with name Finances already exists.")
+}
+
+func (s *ClientTests) TestDeleteGroupError(c *C) {
+ _, err := s.iam.DeleteGroup("Finances")
+ iamErr, ok := err.(*iam.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(iamErr.StatusCode, Equals, 404)
+ c.Assert(iamErr.Code, Equals, "NoSuchEntity")
+ c.Assert(iamErr.Message, Equals, "The group with name Finances cannot be found.")
+}
+
+func (s *ClientTests) TestPutGetAndDeleteUserPolicy(c *C) {
+ userResp, err := s.iam.CreateUser("gopher", "/gopher/")
+ c.Assert(err, IsNil)
+ defer s.iam.DeleteUser(userResp.User.Name)
+ document := `{
+ "Statement": [
+ {
+ "Action": [
+ "s3:*"
+ ],
+ "Effect": "Allow",
+ "Resource": [
+ "arn:aws:s3:::8shsns19s90ajahadsj/*",
+ "arn:aws:s3:::8shsns19s90ajahadsj"
+ ]
+ }]
+ }`
+ _, err = s.iam.PutUserPolicy(userResp.User.Name, "EverythingS3", document)
+ c.Assert(err, IsNil)
+ resp, err := s.iam.GetUserPolicy(userResp.User.Name, "EverythingS3")
+ c.Assert(err, IsNil)
+ c.Assert(resp.Policy.Name, Equals, "EverythingS3")
+ c.Assert(resp.Policy.UserName, Equals, userResp.User.Name)
+ gotDocument, err := url.QueryUnescape(resp.Policy.Document)
+ c.Assert(err, IsNil)
+ c.Assert(gotDocument, Equals, document)
+ _, err = s.iam.DeleteUserPolicy(userResp.User.Name, "EverythingS3")
+ c.Assert(err, IsNil)
+ _, err = s.iam.GetUserPolicy(userResp.User.Name, "EverythingS3")
+ c.Assert(err, NotNil)
+}
diff --git a/vendor/github.com/goamz/goamz/iam/iamt_test.go b/vendor/github.com/goamz/goamz/iam/iamt_test.go
new file mode 100644
index 000000000..9d89f43e3
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/iamt_test.go
@@ -0,0 +1,39 @@
+package iam_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/iam"
+ "github.com/goamz/goamz/iam/iamtest"
+ . "gopkg.in/check.v1"
+)
+
+// LocalServer represents a local ec2test fake server.
+type LocalServer struct {
+ auth aws.Auth
+ region aws.Region
+ srv *iamtest.Server
+}
+
+func (s *LocalServer) SetUp(c *C) {
+ srv, err := iamtest.NewServer()
+ c.Assert(err, IsNil)
+ c.Assert(srv, NotNil)
+
+ s.srv = srv
+ s.region = aws.Region{IAMEndpoint: srv.URL()}
+}
+
+// LocalServerSuite defines tests that will run
+// against the local iamtest server. It includes
+// tests from ClientTests.
+type LocalServerSuite struct {
+ srv LocalServer
+ ClientTests
+}
+
+var _ = Suite(&LocalServerSuite{})
+
+func (s *LocalServerSuite) SetUpSuite(c *C) {
+ s.srv.SetUp(c)
+ s.ClientTests.iam = iam.New(s.srv.auth, s.srv.region)
+}
diff --git a/vendor/github.com/goamz/goamz/iam/iamtest/server.go b/vendor/github.com/goamz/goamz/iam/iamtest/server.go
new file mode 100644
index 000000000..08991d2f8
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/iamtest/server.go
@@ -0,0 +1,432 @@
+// Package iamtest implements a fake IAM provider with the capability of
+// inducing errors on any given operation, and retrospectively determining what
+// operations have been carried out.
+package iamtest
+
+import (
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "github.com/goamz/goamz/iam"
+ "net"
+ "net/http"
+ "strings"
+ "sync"
+)
+
+type action struct {
+ srv *Server
+ w http.ResponseWriter
+ req *http.Request
+ reqId string
+}
+
+// Server implements an IAM simulator for use in tests.
+type Server struct {
+ reqId int
+ url string
+ listener net.Listener
+ users []iam.User
+ groups []iam.Group
+ accessKeys []iam.AccessKey
+ userPolicies []iam.UserPolicy
+ mutex sync.Mutex
+}
+
+func NewServer() (*Server, error) {
+ l, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ return nil, fmt.Errorf("cannot listen on localhost: %v", err)
+ }
+ srv := &Server{
+ listener: l,
+ url: "http://" + l.Addr().String(),
+ }
+ go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ srv.serveHTTP(w, req)
+ }))
+ return srv, nil
+}
+
+// Quit closes down the server.
+func (srv *Server) Quit() error {
+ return srv.listener.Close()
+}
+
+// URL returns a URL for the server.
+func (srv *Server) URL() string {
+ return srv.url
+}
+
+type xmlErrors struct {
+ XMLName string `xml:"ErrorResponse"`
+ Error iam.Error
+}
+
+func (srv *Server) error(w http.ResponseWriter, err *iam.Error) {
+ w.WriteHeader(err.StatusCode)
+ xmlErr := xmlErrors{Error: *err}
+ if e := xml.NewEncoder(w).Encode(xmlErr); e != nil {
+ panic(e)
+ }
+}
+
+func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) {
+ req.ParseForm()
+ srv.mutex.Lock()
+ defer srv.mutex.Unlock()
+ action := req.FormValue("Action")
+ if action == "" {
+ srv.error(w, &iam.Error{
+ StatusCode: 400,
+ Code: "MissingAction",
+ Message: "Missing action",
+ })
+ }
+ if a, ok := actions[action]; ok {
+ reqId := fmt.Sprintf("req%0X", srv.reqId)
+ srv.reqId++
+ if resp, err := a(srv, w, req, reqId); err == nil {
+ if err := xml.NewEncoder(w).Encode(resp); err != nil {
+ panic(err)
+ }
+ } else {
+ switch err.(type) {
+ case *iam.Error:
+ srv.error(w, err.(*iam.Error))
+ default:
+ panic(err)
+ }
+ }
+ } else {
+ srv.error(w, &iam.Error{
+ StatusCode: 400,
+ Code: "InvalidAction",
+ Message: "Invalid action: " + action,
+ })
+ }
+}
+
+func (srv *Server) createUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ path := req.FormValue("Path")
+ if path == "" {
+ path = "/"
+ }
+ name := req.FormValue("UserName")
+ for _, user := range srv.users {
+ if user.Name == name {
+ return nil, &iam.Error{
+ StatusCode: 409,
+ Code: "EntityAlreadyExists",
+ Message: fmt.Sprintf("User with name %s already exists.", name),
+ }
+ }
+ }
+ user := iam.User{
+ Id: "USER" + reqId + "EXAMPLE",
+ Arn: fmt.Sprintf("arn:aws:iam:::123456789012:user%s%s", path, name),
+ Name: name,
+ Path: path,
+ }
+ srv.users = append(srv.users, user)
+ return iam.CreateUserResp{
+ RequestId: reqId,
+ User: user,
+ }, nil
+}
+
+func (srv *Server) getUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("UserName")
+ index, err := srv.findUser(name)
+ if err != nil {
+ return nil, err
+ }
+ return iam.GetUserResp{RequestId: reqId, User: srv.users[index]}, nil
+}
+
+func (srv *Server) deleteUser(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("UserName")
+ index, err := srv.findUser(name)
+ if err != nil {
+ return nil, err
+ }
+ copy(srv.users[index:], srv.users[index+1:])
+ srv.users = srv.users[:len(srv.users)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) createAccessKey(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ userName := req.FormValue("UserName")
+ if _, err := srv.findUser(userName); err != nil {
+ return nil, err
+ }
+ key := iam.AccessKey{
+ Id: fmt.Sprintf("%s%d", userName, len(srv.accessKeys)),
+ Secret: "",
+ UserName: userName,
+ Status: "Active",
+ }
+ srv.accessKeys = append(srv.accessKeys, key)
+ return iam.CreateAccessKeyResp{RequestId: reqId, AccessKey: key}, nil
+}
+
+func (srv *Server) deleteAccessKey(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"AccessKeyId", "UserName"}); err != nil {
+ return nil, err
+ }
+ key := req.FormValue("AccessKeyId")
+ index := -1
+ for i, ak := range srv.accessKeys {
+ if ak.Id == key {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: "No such key.",
+ }
+ }
+ copy(srv.accessKeys[index:], srv.accessKeys[index+1:])
+ srv.accessKeys = srv.accessKeys[:len(srv.accessKeys)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) listAccessKeys(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName"}); err != nil {
+ return nil, err
+ }
+ userName := req.FormValue("UserName")
+ if _, err := srv.findUser(userName); err != nil {
+ return nil, err
+ }
+ var keys []iam.AccessKey
+ for _, k := range srv.accessKeys {
+ if k.UserName == userName {
+ keys = append(keys, k)
+ }
+ }
+ return iam.AccessKeysResp{
+ RequestId: reqId,
+ AccessKeys: keys,
+ }, nil
+}
+
+func (srv *Server) createGroup(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"GroupName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("GroupName")
+ path := req.FormValue("Path")
+ for _, group := range srv.groups {
+ if group.Name == name {
+ return nil, &iam.Error{
+ StatusCode: 409,
+ Code: "EntityAlreadyExists",
+ Message: fmt.Sprintf("Group with name %s already exists.", name),
+ }
+ }
+ }
+ group := iam.Group{
+ Id: "GROUP " + reqId + "EXAMPLE",
+ Arn: fmt.Sprintf("arn:aws:iam:::123456789012:group%s%s", path, name),
+ Name: name,
+ Path: path,
+ }
+ srv.groups = append(srv.groups, group)
+ return iam.CreateGroupResp{
+ RequestId: reqId,
+ Group: group,
+ }, nil
+}
+
+func (srv *Server) listGroups(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ pathPrefix := req.FormValue("PathPrefix")
+ if pathPrefix == "" {
+ return iam.GroupsResp{
+ RequestId: reqId,
+ Groups: srv.groups,
+ }, nil
+ }
+ var groups []iam.Group
+ for _, group := range srv.groups {
+ if strings.HasPrefix(group.Path, pathPrefix) {
+ groups = append(groups, group)
+ }
+ }
+ return iam.GroupsResp{
+ RequestId: reqId,
+ Groups: groups,
+ }, nil
+}
+
+func (srv *Server) deleteGroup(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"GroupName"}); err != nil {
+ return nil, err
+ }
+ name := req.FormValue("GroupName")
+ index := -1
+ for i, group := range srv.groups {
+ if group.Name == name {
+ index = i
+ break
+ }
+ }
+ if index == -1 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: fmt.Sprintf("The group with name %s cannot be found.", name),
+ }
+ }
+ copy(srv.groups[index:], srv.groups[index+1:])
+ srv.groups = srv.groups[:len(srv.groups)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) putUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName", "PolicyDocument", "PolicyName"}); err != nil {
+ return nil, err
+ }
+ var exists bool
+ policyName := req.FormValue("PolicyName")
+ userName := req.FormValue("UserName")
+ for _, policy := range srv.userPolicies {
+ if policyName == policy.Name && userName == policy.UserName {
+ exists = true
+ break
+ }
+ }
+ if !exists {
+ policy := iam.UserPolicy{
+ Name: policyName,
+ UserName: userName,
+ Document: req.FormValue("PolicyDocument"),
+ }
+ var dumb interface{}
+ if err := json.Unmarshal([]byte(policy.Document), &dumb); err != nil {
+ return nil, &iam.Error{
+ StatusCode: 400,
+ Code: "MalformedPolicyDocument",
+ Message: "Malformed policy document",
+ }
+ }
+ srv.userPolicies = append(srv.userPolicies, policy)
+ }
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) deleteUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName", "PolicyName"}); err != nil {
+ return nil, err
+ }
+ policyName := req.FormValue("PolicyName")
+ userName := req.FormValue("UserName")
+ index := -1
+ for i, policy := range srv.userPolicies {
+ if policyName == policy.Name && userName == policy.UserName {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: "No such user policy",
+ }
+ }
+ copy(srv.userPolicies[index:], srv.userPolicies[index+1:])
+ srv.userPolicies = srv.userPolicies[:len(srv.userPolicies)-1]
+ return iam.SimpleResp{RequestId: reqId}, nil
+}
+
+func (srv *Server) getUserPolicy(w http.ResponseWriter, req *http.Request, reqId string) (interface{}, error) {
+ if err := srv.validate(req, []string{"UserName", "PolicyName"}); err != nil {
+ return nil, err
+ }
+ policyName := req.FormValue("PolicyName")
+ userName := req.FormValue("UserName")
+ index := -1
+ for i, policy := range srv.userPolicies {
+ if policyName == policy.Name && userName == policy.UserName {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ return nil, &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: "No such user policy",
+ }
+ }
+ return iam.GetUserPolicyResp{
+ Policy: srv.userPolicies[index],
+ RequestId: reqId,
+ }, nil
+}
+
+func (srv *Server) findUser(userName string) (int, error) {
+ var (
+ err error
+ index = -1
+ )
+ for i, user := range srv.users {
+ if user.Name == userName {
+ index = i
+ break
+ }
+ }
+ if index < 0 {
+ err = &iam.Error{
+ StatusCode: 404,
+ Code: "NoSuchEntity",
+ Message: fmt.Sprintf("The user with name %s cannot be found.", userName),
+ }
+ }
+ return index, err
+}
+
+// Validates the presence of required request parameters.
+func (srv *Server) validate(req *http.Request, required []string) error {
+ for _, r := range required {
+ if req.FormValue(r) == "" {
+ return &iam.Error{
+ StatusCode: 400,
+ Code: "InvalidParameterCombination",
+ Message: fmt.Sprintf("%s is required.", r),
+ }
+ }
+ }
+ return nil
+}
+
+var actions = map[string]func(*Server, http.ResponseWriter, *http.Request, string) (interface{}, error){
+ "CreateUser": (*Server).createUser,
+ "DeleteUser": (*Server).deleteUser,
+ "GetUser": (*Server).getUser,
+ "CreateAccessKey": (*Server).createAccessKey,
+ "DeleteAccessKey": (*Server).deleteAccessKey,
+ "ListAccessKeys": (*Server).listAccessKeys,
+ "PutUserPolicy": (*Server).putUserPolicy,
+ "DeleteUserPolicy": (*Server).deleteUserPolicy,
+ "GetUserPolicy": (*Server).getUserPolicy,
+ "CreateGroup": (*Server).createGroup,
+ "DeleteGroup": (*Server).deleteGroup,
+ "ListGroups": (*Server).listGroups,
+}
diff --git a/vendor/github.com/goamz/goamz/iam/responses_test.go b/vendor/github.com/goamz/goamz/iam/responses_test.go
new file mode 100644
index 000000000..d8a0b2c4c
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/responses_test.go
@@ -0,0 +1,261 @@
+package iam_test
+
+// http://goo.gl/EUIvl
+var CreateUserExample = `
+<CreateUserResponse>
+ <CreateUserResult>
+ <User>
+ <Path>/division_abc/subdivision_xyz/</Path>
+ <UserName>Bob</UserName>
+ <UserId>AIDACKCEVSQ6C2EXAMPLE</UserId>
+ <Arn>arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob</Arn>
+ </User>
+ </CreateUserResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateUserResponse>
+`
+
+var DuplicateUserExample = `
+<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
+ <Error>
+ <Type>Sender</Type>
+ <Code>EntityAlreadyExists</Code>
+ <Message>User with name Bob already exists.</Message>
+ </Error>
+ <RequestId>1d5f5000-1316-11e2-a60f-91a8e6fb6d21</RequestId>
+</ErrorResponse>
+`
+
+var GetUserExample = `
+<GetUserResponse>
+ <GetUserResult>
+ <User>
+ <Path>/division_abc/subdivision_xyz/</Path>
+ <UserName>Bob</UserName>
+ <UserId>AIDACKCEVSQ6C2EXAMPLE</UserId>
+ <Arn>arn:aws:iam::123456789012:user/division_abc/subdivision_xyz/Bob</Arn>
+ </User>
+ </GetUserResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</GetUserResponse>
+`
+
+var CreateGroupExample = `
+<CreateGroupResponse>
+ <CreateGroupResult>
+ <Group>
+ <Path>/admins/</Path>
+ <GroupName>Admins</GroupName>
+ <GroupId>AGPACKCEVSQ6C2EXAMPLE</GroupId>
+ <Arn>arn:aws:iam::123456789012:group/Admins</Arn>
+ </Group>
+ </CreateGroupResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateGroupResponse>
+`
+
+var ListGroupsExample = `
+<ListGroupsResponse>
+ <ListGroupsResult>
+ <Groups>
+ <member>
+ <Path>/division_abc/subdivision_xyz/</Path>
+ <GroupName>Admins</GroupName>
+ <GroupId>AGPACKCEVSQ6C2EXAMPLE</GroupId>
+ <Arn>arn:aws:iam::123456789012:group/Admins</Arn>
+ </member>
+ <member>
+ <Path>/division_abc/subdivision_xyz/product_1234/engineering/</Path>
+ <GroupName>Test</GroupName>
+ <GroupId>AGP2MAB8DPLSRHEXAMPLE</GroupId>
+ <Arn>arn:aws:iam::123456789012:group/division_abc/subdivision_xyz/product_1234/engineering/Test</Arn>
+ </member>
+ <member>
+ <Path>/division_abc/subdivision_xyz/product_1234/</Path>
+ <GroupName>Managers</GroupName>
+ <GroupId>AGPIODR4TAW7CSEXAMPLE</GroupId>
+ <Arn>arn:aws:iam::123456789012:group/division_abc/subdivision_xyz/product_1234/Managers</Arn>
+ </member>
+ </Groups>
+ <IsTruncated>false</IsTruncated>
+ </ListGroupsResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</ListGroupsResponse>
+`
+
+var RequestIdExample = `
+<AddUserToGroupResponse>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</AddUserToGroupResponse>
+`
+
+var CreateAccessKeyExample = `
+<CreateAccessKeyResponse>
+ <CreateAccessKeyResult>
+ <AccessKey>
+ <UserName>Bob</UserName>
+ <AccessKeyId>AKIAIOSFODNN7EXAMPLE</AccessKeyId>
+ <Status>Active</Status>
+ <SecretAccessKey>wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY</SecretAccessKey>
+ </AccessKey>
+ </CreateAccessKeyResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateAccessKeyResponse>
+`
+
+var ListAccessKeyExample = `
+<ListAccessKeysResponse>
+ <ListAccessKeysResult>
+ <UserName>Bob</UserName>
+ <AccessKeyMetadata>
+ <member>
+ <UserName>Bob</UserName>
+ <AccessKeyId>AKIAIOSFODNN7EXAMPLE</AccessKeyId>
+ <Status>Active</Status>
+ </member>
+ <member>
+ <UserName>Bob</UserName>
+ <AccessKeyId>AKIAI44QH8DHBEXAMPLE</AccessKeyId>
+ <Status>Inactive</Status>
+ </member>
+ </AccessKeyMetadata>
+ <IsTruncated>false</IsTruncated>
+ </ListAccessKeysResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</ListAccessKeysResponse>
+`
+
+var GetUserPolicyExample = `
+<GetUserPolicyResponse>
+ <GetUserPolicyResult>
+ <UserName>Bob</UserName>
+ <PolicyName>AllAccessPolicy</PolicyName>
+ <PolicyDocument>
+ {"Statement":[{"Effect":"Allow","Action":"*","Resource":"*"}]}
+ </PolicyDocument>
+ </GetUserPolicyResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</GetUserPolicyResponse>
+`
+
+var AddUserToGroupExample = `
+<AddUserToGroupResponse>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</AddUserToGroupResponse>
+`
+
+var ListAccountAliasesExample = `
+<ListAccountAliasesResponse>
+ <ListAccountAliasesResult>
+ <IsTruncated>false</IsTruncated>
+ <AccountAliases>
+ <member>foocorporation</member>
+ </AccountAliases>
+ </ListAccountAliasesResult>
+ <ResponseMetadata>
+ <RequestId>c5a076e9-f1b0-11df-8fbe-45274EXAMPLE</RequestId>
+ </ResponseMetadata>
+</ListAccountAliasesResponse>
+`
+
+var CreateAccountAliasExample = `
+<CreateAccountAliasResponse>
+ <ResponseMetadata>
+ <RequestId>36b5db08-f1b0-11df-8fbe-45274EXAMPLE</RequestId>
+ </ResponseMetadata>
+</CreateAccountAliasResponse>
+`
+
+var DeleteAccountAliasExample = `
+<DeleteAccountAliasResponse>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+ </ResponseMetadata>
+</DeleteAccountAliasResponse>
+`
+
+var UploadServerCertificateExample = `
+<UploadServerCertificateResponse>
+<UploadServerCertificateResult>
+ <ServerCertificateMetadata>
+ <ServerCertificateName>ProdServerCert</ServerCertificateName>
+ <Path>/company/servercerts/</Path>
+ <Arn>arn:aws:iam::123456789012:server-certificate/company/servercerts/ProdServerCert</Arn>
+ <UploadDate>2010-05-08T01:02:03.004Z</UploadDate>
+ <ServerCertificateId>ASCACKCEVSQ6C2EXAMPLE</ServerCertificateId>
+ <Expiration>2012-05-08T01:02:03.004Z</Expiration>
+ </ServerCertificateMetadata>
+</UploadServerCertificateResult>
+<ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+</ResponseMetadata>
+</UploadServerCertificateResponse>
+`
+var ListServerCertificatesExample = `
+<ListServerCertificatesResponse>
+<ListServerCertificatesResult>
+ <IsTruncated>false</IsTruncated>
+ <ServerCertificateMetadataList>
+ <member>
+ <ServerCertificateMetadata>
+ <ServerCertificateName>ProdServerCert</ServerCertificateName>
+ <Path>/some/fake/path</Path>
+ <Arn>arn:aws:iam::123456789012:server-certificate/company/servercerts/ProdServerCert</Arn>
+ <UploadDate>2010-05-08T01:02:03.004Z</UploadDate>
+ <ServerCertificateId>ASCACKCEVSQ6C2EXAMPLE1</ServerCertificateId>
+ <Expiration>2012-05-08T01:02:03.004Z</Expiration>
+ </ServerCertificateMetadata>
+ </member>
+ <member>
+ <ServerCertificateMetadata>
+ <ServerCertificateName>BetaServerCert</ServerCertificateName>
+ <Path>/some/fake/path</Path>
+ <Arn>arn:aws:iam::123456789012:server-certificate/company/servercerts/BetaServerCert</Arn>
+ <UploadDate>2010-05-08T01:02:03.004Z</UploadDate>
+ <ServerCertificateId>ASCACKCEVSQ6C2EXAMPLE2</ServerCertificateId>
+ <Expiration>2012-05-08T01:02:03.004Z</Expiration>
+ </ServerCertificateMetadata>
+ </member>
+ <member>
+ <ServerCertificateMetadata>
+ <ServerCertificateName>TestServerCert</ServerCertificateName>
+ <Path>/some/fake/path</Path>
+ <Arn>arn:aws:iam::123456789012:server-certificate/company/servercerts/TestServerCert</Arn>
+ <UploadDate>2010-05-08T01:02:03.004Z</UploadDate>
+ <ServerCertificateId>ASCACKCEVSQ6C2EXAMPLE3</ServerCertificateId>
+ <Expiration>2012-05-08T01:02:03.004Z</Expiration>
+ </ServerCertificateMetadata>
+ </member>
+ </ServerCertificateMetadataList>
+</ListServerCertificatesResult>
+<ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8eTHISDIFFERENTTEST</RequestId>
+</ResponseMetadata>
+</ListServerCertificatesResponse>
+`
+
+var DeleteServerCertificateExample = `
+<DeleteServerCertificateResponse>
+<ResponseMetadata>
+<RequestId>7a62c49f-347e-4fc4-9331-6e8eEXAMPLE</RequestId>
+</ResponseMetadata>
+</DeleteServerCertificateResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/iam/sign.go b/vendor/github.com/goamz/goamz/iam/sign.go
new file mode 100644
index 000000000..b704fd8d6
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/iam/sign.go
@@ -0,0 +1,38 @@
+package iam
+
+import (
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/base64"
+ "github.com/goamz/goamz/aws"
+ "sort"
+ "strings"
+)
+
+// ----------------------------------------------------------------------------
+// Version 2 signing (http://goo.gl/RSRp5)
+
+var b64 = base64.StdEncoding
+
+func sign(auth aws.Auth, method, path string, params map[string]string, host string) {
+ params["AWSAccessKeyId"] = auth.AccessKey
+ params["SignatureVersion"] = "2"
+ params["SignatureMethod"] = "HmacSHA256"
+ if auth.Token() != "" {
+ params["SecurityToken"] = auth.Token()
+ }
+
+ var sarray []string
+ for k, v := range params {
+ sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(v))
+ }
+ sort.StringSlice(sarray).Sort()
+ joined := strings.Join(sarray, "&")
+ payload := method + "\n" + host + "\n" + path + "\n" + joined
+ hash := hmac.New(sha256.New, []byte(auth.SecretKey))
+ hash.Write([]byte(payload))
+ signature := make([]byte, b64.EncodedLen(hash.Size()))
+ b64.Encode(signature, hash.Sum(nil))
+
+ params["Signature"] = string(signature)
+}
diff --git a/vendor/github.com/goamz/goamz/rds/rds.go b/vendor/github.com/goamz/goamz/rds/rds.go
new file mode 100644
index 000000000..f00b52c64
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/rds/rds.go
@@ -0,0 +1,96 @@
+package rds
+
+import (
+ "encoding/xml"
+ "github.com/goamz/goamz/aws"
+ "log"
+ "net/http/httputil"
+ "strconv"
+)
+
+const debug = false
+
+const (
+ ServiceName = "rds"
+ ApiVersion = "2013-09-09"
+)
+
+// The RDS type encapsulates operations within a specific EC2 region.
+type RDS struct {
+ Service aws.AWSService
+}
+
+// New creates a new RDS Client.
+func New(auth aws.Auth, region aws.Region) (*RDS, error) {
+ service, err := aws.NewService(auth, region.RDSEndpoint)
+ if err != nil {
+ return nil, err
+ }
+ return &RDS{
+ Service: service,
+ }, nil
+}
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+// query dispatches a request to the RDS API signed with a version 2 signature
+func (rds *RDS) query(method, path string, params map[string]string, resp interface{}) error {
+ // Add basic RDS param
+ params["Version"] = ApiVersion
+
+ r, err := rds.Service.Query(method, path, params)
+ if err != nil {
+ return err
+ }
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("response:\n")
+ log.Printf("%v\n}\n", string(dump))
+ }
+
+ if r.StatusCode != 200 {
+ return rds.Service.BuildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+// ----------------------------------------------------------------------------
+// API methods and corresponding response types.
+
+// Response to a DescribeDBInstances request
+//
+// See http://goo.gl/KSPlAl for more details.
+type DescribeDBInstancesResponse struct {
+ DBInstances []DBInstance `xml:"DescribeDBInstancesResult>DBInstances>DBInstance"` // The list of database instances
+ Marker string `xml:"DescribeDBInstancesResult>Marker"` // An optional pagination token provided by a previous request
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// DescribeDBInstances - Returns a description of each Database Instance
+// Supports pagination by using the "Marker" parameter, and "maxRecords" for subsequent calls
+// Unfortunately RDS does not currently support filtering
+//
+// See http://goo.gl/lzZMyz for more details.
+func (rds *RDS) DescribeDBInstances(id string, maxRecords int, marker string) (*DescribeDBInstancesResponse, error) {
+
+ params := aws.MakeParams("DescribeDBInstances")
+
+ if id != "" {
+ params["DBInstanceIdentifier"] = id
+ }
+
+ if maxRecords != 0 {
+ params["MaxRecords"] = strconv.Itoa(maxRecords)
+ }
+ if marker != "" {
+ params["Marker"] = marker
+ }
+
+ resp := &DescribeDBInstancesResponse{}
+ err := rds.query("POST", "/", params, resp)
+ return resp, err
+}
diff --git a/vendor/github.com/goamz/goamz/rds/rds_test.go b/vendor/github.com/goamz/goamz/rds/rds_test.go
new file mode 100644
index 000000000..ac277d4d7
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/rds/rds_test.go
@@ -0,0 +1,77 @@
+package rds_test
+
+import (
+ "testing"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/rds"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ rds *rds.RDS
+}
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ var err error
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.rds, err = rds.New(auth, aws.Region{RDSEndpoint: aws.ServiceInfo{testServer.URL, aws.V2Signature}})
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestDescribeDBInstancesExample1(c *C) {
+ testServer.Response(200, nil, DescribeDBInstancesExample1)
+
+ resp, err := s.rds.DescribeDBInstances("simcoprod01", 0, "")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Form["Action"], DeepEquals, []string{"DescribeDBInstances"})
+ c.Assert(req.Form["DBInstanceIdentifier"], DeepEquals, []string{"simcoprod01"})
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.RequestId, Equals, "9135fff3-8509-11e0-bd9b-a7b1ece36d51")
+ c.Assert(resp.DBInstances, HasLen, 1)
+
+ db0 := resp.DBInstances[0]
+ c.Assert(db0.AllocatedStorage, Equals, 10)
+ c.Assert(db0.AutoMinorVersionUpgrade, Equals, true)
+ c.Assert(db0.AvailabilityZone, Equals, "us-east-1a")
+ c.Assert(db0.BackupRetentionPeriod, Equals, 1)
+
+ c.Assert(db0.DBInstanceClass, Equals, "db.m1.large")
+ c.Assert(db0.DBInstanceIdentifier, Equals, "simcoprod01")
+ c.Assert(db0.DBInstanceStatus, Equals, "available")
+ c.Assert(db0.DBName, Equals, "simcoprod")
+
+ c.Assert(db0.Endpoint.Address, Equals, "simcoprod01.cu7u2t4uz396.us-east-1.rds.amazonaws.com")
+ c.Assert(db0.Endpoint.Port, Equals, 3306)
+ c.Assert(db0.Engine, Equals, "mysql")
+ c.Assert(db0.EngineVersion, Equals, "5.1.50")
+ c.Assert(db0.InstanceCreateTime, Equals, "2011-05-23T06:06:43.110Z")
+
+ c.Assert(db0.LatestRestorableTime, Equals, "2011-05-23T06:50:00Z")
+ c.Assert(db0.LicenseModel, Equals, "general-public-license")
+ c.Assert(db0.MasterUsername, Equals, "master")
+ c.Assert(db0.MultiAZ, Equals, false)
+ c.Assert(db0.OptionGroupMemberships, HasLen, 1)
+ c.Assert(db0.OptionGroupMemberships[0].Name, Equals, "default.mysql5.1")
+ c.Assert(db0.OptionGroupMemberships[0].Status, Equals, "in-sync")
+
+ c.Assert(db0.PreferredBackupWindow, Equals, "00:00-00:30")
+ c.Assert(db0.PreferredMaintenanceWindow, Equals, "sat:07:30-sat:08:00")
+ c.Assert(db0.PubliclyAccessible, Equals, false)
+}
diff --git a/vendor/github.com/goamz/goamz/rds/responses_test.go b/vendor/github.com/goamz/goamz/rds/responses_test.go
new file mode 100644
index 000000000..b7912f84b
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/rds/responses_test.go
@@ -0,0 +1,57 @@
+package rds_test
+
+var DescribeDBInstancesExample1 = `
+<DescribeDBInstancesResponse xmlns="http://rds.amazonaws.com/doc/2013-09-09/">
+ <DescribeDBInstancesResult>
+ <DBInstances>
+ <DBInstance>
+ <ReadReplicaDBInstanceIdentifiers/>
+ <LatestRestorableTime>2011-05-23T06:50:00Z</LatestRestorableTime>
+ <Engine>mysql</Engine>
+ <PendingModifiedValues/>
+ <BackupRetentionPeriod>1</BackupRetentionPeriod>
+ <MultiAZ>false</MultiAZ>
+ <LicenseModel>general-public-license</LicenseModel>
+ <DBInstanceStatus>available</DBInstanceStatus>
+ <EngineVersion>5.1.50</EngineVersion>
+ <Endpoint>
+ <Port>3306</Port>
+ <Address>simcoprod01.cu7u2t4uz396.us-east-1.rds.amazonaws.com</Address>
+ </Endpoint>
+ <DBInstanceIdentifier>simcoprod01</DBInstanceIdentifier>
+ <DBName>simcoprod</DBName>
+ <DBParameterGroups>
+ <DBParameterGroup>
+ <ParameterApplyStatus>in-sync</ParameterApplyStatus>
+ <DBParameterGroupName>default.mysql5.1</DBParameterGroupName>
+ </DBParameterGroup>
+ </DBParameterGroups>
+ <DBSecurityGroups>
+ <DBSecurityGroup>
+ <Status>active</Status>
+ <DBSecurityGroupName>default</DBSecurityGroupName>
+ </DBSecurityGroup>
+ </DBSecurityGroups>
+ <PreferredBackupWindow>00:00-00:30</PreferredBackupWindow>
+ <AutoMinorVersionUpgrade>true</AutoMinorVersionUpgrade>
+ <PreferredMaintenanceWindow>sat:07:30-sat:08:00</PreferredMaintenanceWindow>
+ <AvailabilityZone>us-east-1a</AvailabilityZone>
+ <InstanceCreateTime>2011-05-23T06:06:43.110Z</InstanceCreateTime>
+ <AllocatedStorage>10</AllocatedStorage>
+ <OptionGroupMemberships>
+ <OptionGroupMembership>
+ <OptionGroupName>default.mysql5.1</OptionGroupName>
+ <Status>in-sync</Status>
+ </OptionGroupMembership>
+ </OptionGroupMemberships>
+ <DBInstanceClass>db.m1.large</DBInstanceClass>
+ <MasterUsername>master</MasterUsername>
+ <PubliclyAccessible>false</PubliclyAccessible>
+ </DBInstance>
+ </DBInstances>
+ </DescribeDBInstancesResult>
+ <ResponseMetadata>
+ <RequestId>9135fff3-8509-11e0-bd9b-a7b1ece36d51</RequestId>
+ </ResponseMetadata>
+</DescribeDBInstancesResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/rds/types.go b/vendor/github.com/goamz/goamz/rds/types.go
new file mode 100644
index 000000000..aa9c4024f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/rds/types.go
@@ -0,0 +1,388 @@
+package rds
+
+// AvailabilityZone contains Availability Zone information
+// See http://goo.gl/GWF4zF for more details.
+type AvailabilityZone struct {
+ Name string `xml:"Name"`
+ ProvisionedIopsCapable bool `xml:"ProvisionedIopsCapable"`
+}
+
+// CharacterSet represents a character set used by a Database Engine
+// See http://goo.gl/0BXwFp for more details.
+type CharacterSet struct {
+ Name string `xml:"CharacterSetName"`
+ Description string `xml:"CharacterSetDescription"`
+}
+
+// DBEngineVersion describes a version of a Database Engine
+// See http://goo.gl/a5l6cv for more details.
+type DBEngineVersion struct {
+ DBEngineDescription string `xml:"DBEngineDescription"` // The description of the database engine
+ DBEngineVersionDescription string `xml:"DBEngineVersionDescription"` // The description of the database engine version
+ DBParameterGroupFamily string `xml:"DBParameterGroupFamily"` // The name of the DB parameter group family for the database engine
+ DefaultCharacterSet CharacterSet `xml:"DefaultCharacterSet"` // The default character set for new instances of this engine version, if the CharacterSetName parameter of the CreateDBInstance API is not specified
+ Engine string `xml:"Engine"` // The name of the database engine
+ EngineVersion string `xml:"EngineVersion"` // The version number of the database engine
+ SupportedCharacterSets []CharacterSet `xml:"SupportedCharacterSets"` // A list of the character sets supported by this engine for the CharacterSetName parameter of the CreateDBInstance API
+}
+
+// DBInstance encapsulates an instance of a Database
+// See http://goo.gl/rQFpAe for more details.
+type DBInstance struct {
+ AllocatedStorage int `xml:"AllocatedStorage"` // Specifies the allocated storage size specified in gigabytes.
+ AutoMinorVersionUpgrade bool `xml:"AutoMinorVersionUpgrade"` // Indicates that minor version patches are applied automatically.
+ AvailabilityZone string `xml:"AvailabilityZone"` // Specifies the name of the Availability Zone the DB instance is located in.
+ BackupRetentionPeriod int `xml:"BackupRetentionPeriod"` // Specifies the number of days for which automatic DB snapshots are retained.
+ CharacterSetName string `xml:"CharacterSetName"` // If present, specifies the name of the character set that this instance is associated with.
+ DBInstanceClass string `xml:"DBInstanceClass"` // Contains the name of the compute and memory capacity class of the DB instance.
+ DBInstanceIdentifier string `xml:"DBInstanceIdentifier"` // Contains a user-supplied database identifier. This is the unique key that identifies a DB instance.
+ DBInstanceStatus string `xml:"DBInstanceStatus"` // Specifies the current state of this database.
+ DBName string `xml:"DBName"` // The meaning of this parameter differs according to the database engine you use.
+ DBParameterGroups []DBParameterGroupStatus `xml:"DBParameterGroups>DBParameterGroup"` // Provides the list of DB parameter groups applied to this DB instance.
+ DBSecurityGroups []DBSecurityGroupMembership `xml:"DBSecurityGroups>DBSecurityGroup"` // Provides List of DB security group elements containing only DBSecurityGroup.Name and DBSecurityGroup.Status subelements.
+ DBSubnetGroup DBSubnetGroup `xml:"DBSubnetGroup"` // Specifies information on the subnet group associated with the DB instance, including the name, description, and subnets in the subnet group.
+ Endpoint Endpoint `xml:"Endpoint"` // Specifies the connection endpoint.
+ Engine string `xml:"Engine"` // Provides the name of the database engine to be used for this DB instance.
+ EngineVersion string `xml:"EngineVersion"` // Indicates the database engine version.
+ InstanceCreateTime string `xml:"InstanceCreateTime"` // Provides the date and time the DB instance was created.
+ Iops int `xml:"Iops"` // Specifies the Provisioned IOPS (I/O operations per second) value.
+ LatestRestorableTime string `xml:"LatestRestorableTime"` // Specifies the latest time to which a database can be restored with point-in-time restore.
+ LicenseModel string `xml:"LicenseModel"` // License model information for this DB instance.
+ MasterUsername string `xml:"MasterUsername"` // Contains the master username for the DB instance.
+ MultiAZ bool `xml:"MultiAZ"` // Specifies if the DB instance is a Multi-AZ deployment.
+ OptionGroupMemberships []OptionGroupMembership `xml:"OptionGroupMemberships>OptionGroupMembership"` // Provides the list of option group memberships for this DB instance.
+ PendingModifiedValues PendingModifiedValues `xml:"PendingModifiedValues"` // Specifies that changes to the DB instance are pending. This element is only included when changes are pending. Specific changes are identified by subelements.
+ PreferredBackupWindow string `xml:"PreferredBackupWindow"` // Specifies the daily time range during which automated backups are created if automated backups are enabled, as determined by the BackupRetentionPeriod.
+ PreferredMaintenanceWindow string `xml:"PreferredMaintenanceWindow"` // Specifies the weekly time range (in UTC) during which system maintenance can occur.
+ PubliclyAccessible bool `xml:"PubliclyAccessible"` // Specifies the accessibility options for the DB instance. A value of true specifies an Internet-facing instance with a publicly resolvable DNS name, which resolves to a public IP address. A value of false specifies an internal instance with a DNS name that resolves to a private IP address.
+ ReadReplicaDBInstanceIdentifiers []string `xml:"ReadReplicaDBInstanceIdentifiers"` // Contains one or more identifiers of the read replicas associated with this DB instance.
+ ReadReplicaSourceDBInstanceIdentifier string `xml:"ReadReplicaSourceDBInstanceIdentifier"` // Contains the identifier of the source DB instance if this DB instance is a read replica.
+ SecondaryAvailabilityZone string `xml:"SecondaryAvailabilityZone"` // If present, specifies the name of the secondary Availability Zone for a DB instance with multi-AZ support.
+ StatusInfos []DBInstanceStatusInfo `xml:"StatusInfos"` // The status of a read replica. If the instance is not a read replica, this will be blank.
+ VpcSecurityGroups []VpcSecurityGroupMembership `xml:"VpcSecurityGroups"` // Provides List of VPC security group elements that the DB instance belongs to.
+}
+
+// DBInstanceStatusInfo provides a list of status information for a DB instance
+// See http://goo.gl/WuePdz for more details.
+type DBInstanceStatusInfo struct {
+ Message string `xml:"Message"` // Details of the error if there is an error for the instance. If the instance is not in an error state, this value is blank.
+ Normal bool `xml:"Normal"` // Boolean value that is true if the instance is operating normally, or false if the instance is in an error state.
+ Status string `xml:"Status"` // Status of the DB instance. For a StatusType of read replica, the values can be replicating, error, stopped, or terminated.
+ StatusType string `xml:"StatusType"` // This value is currently "read replication."
+}
+
+// DBParameterGroup contains the result of a successful invocation of the CreateDBParameterGroup action
+// See http://goo.gl/a8BCTy for more details.
+type DBParameterGroup struct {
+ Name string `xml:"DBParameterGroupName"`
+ Description string `xml:"Description"`
+ Family string `xml:"DBParameterGroupFamily"`
+}
+
+// DBParameterGroupStatus represents the status of the DB parameter group
+// See http://goo.gl/X318cI for more details.
+type DBParameterGroupStatus struct {
+ Name string `xml:"DBParameterGroupName"`
+ Status string `xml:"ParameterApplyStatus"`
+}
+
+// DBSecurityGroup represents a RDS DB Security Group which controls network access to a DB instance that is not inside a VPC
+// See http://goo.gl/JF5oJy for more details.
+type DBSecurityGroup struct {
+ Name string `xml:"DBSecurityGroupName"`
+ Description string `xml:"DBSecurityGroupDescription"`
+ EC2SecurityGroups []EC2SecurityGroup `xml:"EC2SecurityGroups"`
+ IPRanges []IPRange `xml:"IPRanges"`
+ OwnerId string `xml:"OwnerId"`
+ VpcId string `xml:"VpcId"`
+}
+
+// DBSecurityGroupMembership represents a DBSecurityGroup which a Database Instance belongs to
+// See http://goo.gl/QjTK0b for more details.
+type DBSecurityGroupMembership struct {
+ Name string `xml:"DBSecurityGroupName"`
+ Status string `xml:"Status"`
+}
+
+// DBSnapshot represents a snapshot of a Database (a backup of the Instance data)
+// See http://goo.gl/wkf0L9 for more details.
+type DBSnapshot struct {
+ AllocatedStorage int `xml:"AllocatedStorage"` // Specifies the allocated storage size in gigabytes (GB)
+ AvailabilityZone string `xml:"AvailabilityZone"`
+ DBInstanceIdentifier string `xml:"DBInstanceIdentifier"`
+ DBSnapshotIdentifier string `xml:"DBSnapshotIdentifier"`
+ Engine string `xml:"Engine"`
+ EngineVersion string `xml:"EngineVersion"`
+ InstanceCreateTime string `xml:"InstanceCreateTime"`
+ Iops int `xml:"Iops"`
+ LicenseModel string `xml:"LicenseModel"`
+ MasterUsername string `xml:"MasterUsername"`
+ OptionGroupName string `xml:"OptionGroupName"`
+ PercentProgress int `xml:"PercentProgress"`
+ Port int `xml:"Port"`
+ SnapshotCreateTime string `xml:"SnapshotCreateTime"`
+ SnapshotType string `xml:"SnapshotType"`
+ SourceRegion string `xml:"SourceRegion"`
+ Status string `xml:"Status"`
+ VpcId string `xml:"VpcId"`
+}
+
+// DBSubnetGroup is a collection of subnets that is designated for an RDS DB Instance in a VPC
+// See http://goo.gl/8vMPkE for more details.
+type DBSubnetGroup struct {
+ Name string `xml:"DBSubnetGroupName"`
+ Description string `xml:"DBSubnetGroupDescription"`
+ Status string `xml:"SubnetGroupStatus"`
+ Subnets []Subnet `xml:"Subnets>Subnet"`
+ VpcId string `xml:"VpcId"`
+}
+
+// EC2SecurityGroup a standard EC2 Security Group which can be assigned to a DB Instance
+// See http://goo.gl/AWavZ2 for more details.
+type EC2SecurityGroup struct {
+ Id string `xml:"EC2SecurityGroupId"`
+ Name string `xml:"EC2SecurityGroupName"`
+ OwnerId string `xml:"EC2SecurityGroupOwnerId"` // The AWS ID of the owner of the EC2 security group
+ Status string `xml:"Status"` // Status can be "authorizing", "authorized", "revoking", and "revoked"
+}
+
+// Endpoint encapsulates the connection endpoint for a DB Instance
+// See http://goo.gl/jefsJ4 for more details.
+type Endpoint struct {
+ Address string `xml:"Address"`
+ Port int `xml:"Port"`
+}
+
+// EngineDefaults describes the system parameter information for a given database engine
+// See http://goo.gl/XFy7Wv for more details.
+type EngineDefaults struct {
+ DBParameterGroupFamily string `xml:"DBParameterGroupFamily"`
+ Marker string `xml:"Marker"`
+ Parameters []Parameter `xml:"Parameters"`
+}
+
+// Event encapsulates events related to DB instances, DB security groups, DB snapshots, and DB parameter groups
+// See http://goo.gl/6fUQow for more details.
+type Event struct {
+ Date string `xml:"Date"` // Specifies the date and time of the event
+ EventCategories []string `xml:"EventCategories"` // Specifies the category for the event
+ Message string `xml:"Message"` // Provides the text of this event
+ SourceIdentifier string `xml:"SourceIdentifier"` // Provides the identifier for the source of the event
+ SourceType string `xml:"SourceType"` // Valid Values: db-instance | db-parameter-group | db-security-group | db-snapshot
+}
+
+// EventCategoriesMap encapsulates event categories for the specified source type
+// See http://goo.gl/9VY3aS for more details.
+type EventCategoriesMap struct {
+ EventCategories []string `xml:"EventCategories"`
+ SourceType string `xml:"SourceType"`
+}
+
+// EventSubscription describes a subscription, for a customer account, to a series of events
+// See http://goo.gl/zgNdXw for more details.
+type EventSubscription struct {
+ CustSubscriptionId string `xml:"CustSubscriptionId"` // The RDS event notification subscription Id
+ CustomerAwsId string `xml:"CustomerAwsId"` // The AWS customer account associated with the RDS event notification subscription
+ Enabled bool `xml:"Enabled"` // True indicates the subscription is enabled
+ EventCategoriesList []string `xml:"EventCategoriesList"` // A list of event categories for the RDS event notification subscription
+ SnsTopicArn string `xml:"SnsTopicArn"` // The topic ARN of the RDS event notification subscription
+ SourceIdsList []string `xml:"SourceIdsList"` // A list of source Ids for the RDS event notification subscription
+ SourceType string `xml:"SourceType"` // The source type for the RDS event notification subscription
+ Status string `xml:"Status"` // Can be one of the following: creating | modifying | deleting | active | no-permission | topic-not-exist
+ SubscriptionCreationTime string `xml:"SubscriptionCreationTime"` // The time the RDS event notification subscription was created
+}
+
+// IPRange encapsulates an IP range (and its status) used by a DB Security Group
+// See http://goo.gl/VfntNm for more details.
+type IPRange struct {
+ CIDRIP string `xml:"CIDRIP"`
+ Status string `xml:"Status"` // Specifies the status of the IP range. Status can be "authorizing", "authorized", "revoking", and "revoked".
+}
+
+// Option describes a feature available for an RDS instance along with any settings applicable to it
+// See http://goo.gl/8DYY0J for more details.
+type Option struct {
+ Name string `xml:"OptionName"`
+ Description string `xml:"OptionDescription"`
+ Settings []OptionSetting `xml:"OptionSettings"`
+ Permanent bool `xml:"Permanent"`
+ Persistent bool `xml:"Persistent"`
+ Port int `xml:"Port"`
+ DBSecurityGroupMemberships []DBSecurityGroupMembership `xml:"DBSecurityGroupMemberships"` // If the option requires access to a port, then this DB security group allows access to the port
+ VpcSecurityGroupMemberships []VpcSecurityGroupMembership `xml:"VpcSecurityGroupMemberships"` // If the option requires access to a port, then this VPC security group allows access to the port
+}
+
+// OptionConfiguration is a list of all available options
+// See http://goo.gl/kkEzw1 for more details.
+type OptionConfiguration struct {
+ OptionName string `xml:"OptionName"`
+ OptionSettings []OptionSetting `xml:"OptionSettings"`
+ Port int `xml:"Port"`
+ DBSecurityGroupMemberships []string `xml:"DBSecurityGroupMemberships"`
+ VpcSecurityGroupMemberships []string `xml:"VpcSecurityGroupMemberships"`
+}
+
+// OptionGroup represents a set of features, called options, that are available for a particular Amazon RDS DB instance
+// See http://goo.gl/NedBJl for more details.
+type OptionGroup struct {
+ Name string `xml:"OptionGroupName"`
+ Description string `xml:"OptionGroupDescription"`
+ VpcId string `xml:"VpcId"`
+ AllowsVpcAndNonVpcInstanceMemberships bool `xml:"AllowsVpcAndNonVpcInstanceMemberships"`
+ EngineName string `xml:"EngineName"`
+ MajorEngineVersion string `xml:"MajorEngineVersion"`
+ Options []Option `xml:"Options"`
+}
+
+// OptionGroupMembership provides information on the option groups the DB instance is a member of
+// See http://goo.gl/XBW6j4 for more details.
+type OptionGroupMembership struct {
+ Name string `xml:"OptionGroupName"` // The name of the option group that the instance belongs to
+ Status string `xml:"Status"` // The status of the option group membership, e.g. in-sync, pending, pending-maintenance, applying
+}
+
+// OptionGroupOption represents an option within an option group
+// See http://goo.gl/jQYL0U for more details.
+type OptionGroupOption struct {
+ DefaultPort int `xml:"DefaultPort"`
+ Description string `xml:"Description"`
+ EngineName string `xml:"EngineName"`
+ MajorEngineVersion string `xml:"MajorEngineVersion"`
+ MinimumRequiredMinorEngineVersion string `xml:"MinimumRequiredMinorEngineVersion"`
+ Name string `xml:"Name"`
+ OptionGroupOptionSettings []OptionGroupOptionSetting `xml:"OptionGroupOptionSettings"`
+ OptionsDependedOn string `xml:"OptionsDependedOn"`
+ Permanent bool `xml:"Permanent"`
+ Persistent bool `xml:"Persistent"`
+ PortRequired bool `xml:"PortRequired"`
+}
+
+// OptionGroupOptionSetting are used to display settings available for each option with their default values and other information
+// See http://goo.gl/9aIwNX for more details.
+type OptionGroupOptionSetting struct {
+ AllowedValues string `xml:"AllowedValues"`
+ ApplyType string `xml:"ApplyType"`
+ DefaultValue string `xml:"DefaultValue"`
+ IsModifiable bool `xml:"IsModifiable"`
+ SettingDescription string `xml:"SettingDescription"`
+ SettingName string `xml:"SettingName"`
+}
+
+// OptionSetting encapsulates modifiable settings for a particular option (a feature available for a Database Instance)
+// See http://goo.gl/VjOJmW for more details.
+type OptionSetting struct {
+ Name string `xml:"Name"`
+ Value string `xml:"Value"`
+ Description string `xml:"Description"`
+ AllowedValues string `xml:"AllowedValues"`
+ ApplyType string `xml:"ApplyType"`
+ DataType string `xml:"DataType"`
+ DefaultValue string `xml:"DefaultValue"`
+ IsCollection bool `xml:"IsCollection"`
+ IsModifiable bool `xml:"IsModifiable"`
+}
+
+// OrderableDBInstanceOption contains a list of available options for a DB instance
+// See http://goo.gl/FVPeVC for more details.
+type OrderableDBInstanceOption struct {
+ AvailabilityZones []AvailabilityZone `xml:"AvailabilityZones"`
+ DBInstanceClass string `xml:"DBInstanceClass"`
+ Engine string `xml:"Engine"`
+ EngineVersion string `xml:"EngineVersion"`
+ LicenseModel string `xml:"LicenseModel"`
+ MultiAZCapable bool `xml:"MultiAZCapable"`
+ ReadReplicaCapable bool `xml:"ReadReplicaCapable"`
+ Vpc bool `xml:"Vpc"`
+}
+
+// Parameter is used as a request parameter in various actions
+// See http://goo.gl/cJmvVT for more details.
+type Parameter struct {
+ AllowedValues string `xml:"AllowedValues"`
+ ApplyMethod string `xml:"ApplyMethod"` // Valid Values: immediate | pending-reboot
+ ApplyType string `xml:"ApplyType"`
+ DataType string `xml:"DataType"`
+ Description string `xml:"Description"`
+ IsModifiable bool `xml:"IsModifiable"`
+ MinimumEngineVersion string `xml:"MinimumEngineVersion"`
+ ParameterName string `xml:"ParameterName"`
+ ParameterValue string `xml:"ParameterValue"`
+ Source string `xml:"Source"`
+}
+
+// PendingModifiedValues represents values modified in a ModifyDBInstance action
+// See http://goo.gl/UoXhLH for more details.
+type PendingModifiedValues struct {
+ AllocatedStorage int `xml:"AllocatedStorage"`
+ BackupRetentionPeriod int `xml:"BackupRetentionPeriod"`
+ DBInstanceClass string `xml:"DBInstanceClass"`
+ DBInstanceIdentifier string `xml:"DBInstanceIdentifier"`
+ EngineVersion string `xml:"EngineVersion"`
+ Iops int `xml:"Iops"`
+ MasterUserPassword string `xml:"MasterUserPassword"`
+ MultiAZ bool `xml:"MultiAZ"`
+ Port string `xml:"Port"`
+}
+
+// RecurringCharge describes an amount that will be charged on a recurring basis with a given frequency
+// See http://goo.gl/3GDplh for more details.
+type RecurringCharge struct {
+ Amount float64 `xml:"RecurringChargeAmount"`
+ Frequency string `xml:"RecurringChargeFrequency"`
+}
+
+// ReservedDBInstance encapsulates a reserved Database Instance
+// See http://goo.gl/mjLhNI for more details.
+type ReservedDBInstance struct {
+ CurrencyCode string `xml:"CurrencyCode"`
+ DBInstanceClass string `xml:"DBInstanceClass"`
+ DBInstanceCount int `xml:"DBInstanceCount"`
+ Duration int `xml:"Duration"`
+ FixedPrice float64 `xml:"FixedPrice"`
+ MultiAZ bool `xml:"MultiAZ"`
+ OfferingType string `xml:"OfferingType"`
+ ProductDescription string `xml:"ProductDescription"`
+ RecurringCharges []RecurringCharge `xml:"RecurringCharges"`
+ ReservedDBInstanceId string `xml:"ReservedDBInstanceId"`
+ ReservedDBInstancesOfferingId string `xml:"ReservedDBInstancesOfferingId"`
+ StartTime string `xml:"StartTime"`
+ State string `xml:"State"`
+ UsagePrice float64 `xml:"UsagePrice"`
+}
+
+// ReservedDBInstancesOffering describes an available Reserved DB instance offering which can be purchased
+// See http://goo.gl/h5s8e6 for more details.
+type ReservedDBInstancesOffering struct {
+ CurrencyCode string `xml:"CurrencyCode"`
+ DBInstanceClass string `xml:"DBInstanceClass"`
+ Duration int `xml:"Duration"`
+ FixedPrice float64 `xml:"FixedPrice"`
+ MultiAZ bool `xml:"MultiAZ"`
+ OfferingType string `xml:"OfferingType"`
+ ProductDescription string `xml:"ProductDescription"`
+ RecurringCharges []RecurringCharge `xml:"RecurringCharges"`
+ ReservedDBInstancesOfferingId string `xml:"ReservedDBInstancesOfferingId"`
+ UsagePrice float64 `xml:"UsagePrice"`
+}
+
+// Subnet describes an EC2 subnet, along with its status and location
+// See http://goo.gl/Nc8ymd for more details.
+type Subnet struct {
+ Id string `xml:"SubnetIdentifier"`
+ Status string `xml:"SubnetStatus"`
+ AvailabilityZone AvailabilityZone `xml:"SubnetAvailabilityZone"`
+}
+
+// Tag represents metadata assigned to an Amazon RDS resource consisting of a key-value pair
+// See http://goo.gl/YnXRrE for more details.
+type Tag struct {
+ Key string `xml:"Key"`
+ Value string `xml:"Value"`
+}
+
+// VpcSecurityGroupMembership describes a standard VPC Security Group which has been assigned to a DB Instance located in a VPC
+// See http://goo.gl/UIvmlS for more details.
+type VpcSecurityGroupMembership struct {
+ Id string `xml:"VpcSecurityGroupId"`
+ Status string `xml:"Status"`
+}
diff --git a/vendor/github.com/goamz/goamz/route53/route53.go b/vendor/github.com/goamz/goamz/route53/route53.go
new file mode 100644
index 000000000..0e26a6f73
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/route53/route53.go
@@ -0,0 +1,254 @@
+package route53
+
+import (
+ "bytes"
+ "encoding/xml"
+ "fmt"
+ "github.com/goamz/goamz/aws"
+ "io"
+ "net/http"
+)
+
+type Route53 struct {
+ Auth aws.Auth
+ Endpoint string
+ Signer *aws.Route53Signer
+ Service *aws.Service
+}
+
+const route53_host = "https://route53.amazonaws.com"
+
+// Factory for the route53 type
+func NewRoute53(auth aws.Auth) (*Route53, error) {
+ signer := aws.NewRoute53Signer(auth)
+
+ return &Route53{
+ Auth: auth,
+ Signer: signer,
+ Endpoint: route53_host + "/2013-04-01/hostedzone",
+ }, nil
+}
+
+// General Structs used in all types of requests
+type HostedZone struct {
+ XMLName xml.Name `xml:"HostedZone"`
+ Id string
+ Name string
+ CallerReference string
+ Config Config
+ ResourceRecordSetCount int
+}
+
+type Config struct {
+ XMLName xml.Name `xml:"Config"`
+ Comment string
+}
+
+// Structs for getting the existing Hosted Zones
+type ListHostedZonesResponse struct {
+ XMLName xml.Name `xml:"ListHostedZonesResponse"`
+ HostedZones []HostedZone `xml:"HostedZones>HostedZone"`
+ Marker string
+ IsTruncated bool
+ NextMarker string
+ MaxItems int
+}
+
+// Structs for Creating a New Host
+type CreateHostedZoneRequest struct {
+ XMLName xml.Name `xml:"CreateHostedZoneRequest"`
+ Xmlns string `xml:"xmlns,attr"`
+ Name string
+ CallerReference string
+ HostedZoneConfig HostedZoneConfig
+}
+
+type ResourceRecordValue struct {
+ Value string `xml:"Value"`
+}
+
+type AliasTarget struct {
+ HostedZoneId string `xml:"HostedZoneId"`
+ DNSName string `xml:"DNSName"`
+ EvaluateTargetHealth bool `xml:"EvaluateTargetHealth"`
+}
+
+// Wrapper for all the different resource record sets
+type ResourceRecordSet interface{}
+
+// Basic Change
+type Change struct {
+ Action string `xml:"Action"`
+ Name string `xml:"ResourceRecordSet>Name"`
+ Type string `xml:"ResourceRecordSet>Type"`
+ TTL int `xml:"ResourceRecordSet>TTL,omitempty"`
+ Values []ResourceRecordValue `xml:"ResourceRecordSet>ResourceRecords>ResourceRecord"`
+ HealthCheckId string `xml:"ResourceRecordSet>HealthCheckId,omitempty"`
+}
+
+// Basic Resource Recod Set
+type BasicResourceRecordSet struct {
+ Action string `xml:"Action"`
+ Name string `xml:"ResourceRecordSet>Name"`
+ Type string `xml:"ResourceRecordSet>Type"`
+ TTL int `xml:"ResourceRecordSet>TTL,omitempty"`
+ Values []ResourceRecordValue `xml:"ResourceRecordSet>ResourceRecords>ResourceRecord"`
+ HealthCheckId string `xml:"ResourceRecordSet>HealthCheckId,omitempty"`
+}
+
+// Alias Resource Record Set
+type AliasResourceRecordSet struct {
+ Action string `xml:"Action"`
+ Name string `xml:"ResourceRecordSet>Name"`
+ Type string `xml:"ResourceRecordSet>Type"`
+ AliasTarget AliasTarget `xml:"ResourceRecordSet>AliasTarget"`
+ HealthCheckId string `xml:"ResourceRecordSet>HealthCheckId,omitempty"`
+}
+
+type ChangeResourceRecordSetsRequest struct {
+ XMLName xml.Name `xml:"ChangeResourceRecordSetsRequest"`
+ Xmlns string `xml:"xmlns,attr"`
+ Changes []ResourceRecordSet `xml:"ChangeBatch>Changes>Change"`
+}
+
+type HostedZoneConfig struct {
+ XMLName xml.Name `xml:"HostedZoneConfig"`
+ Comment string
+}
+
+type CreateHostedZoneResponse struct {
+ XMLName xml.Name `xml:"CreateHostedZoneResponse"`
+ HostedZone HostedZone
+ ChangeInfo ChangeInfo
+ DelegationSet DelegationSet
+}
+
+type ChangeResourceRecordSetsResponse struct {
+ XMLName xml.Name `xml:"ChangeResourceRecordSetsResponse"`
+ Id string `xml:"ChangeInfo>Id"`
+ Status string `xml:"ChangeInfo>Status"`
+ SubmittedAt string `xml:"ChangeInfo>SubmittedAt"`
+}
+
+type ChangeInfo struct {
+ XMLName xml.Name `xml:"ChangeInfo"`
+ Id string
+ Status string
+ SubmittedAt string
+}
+
+type DelegationSet struct {
+ XMLName xml.Name `xml:"DelegationSet`
+ NameServers NameServers
+}
+
+type NameServers struct {
+ XMLName xml.Name `xml:"NameServers`
+ NameServer []string
+}
+
+type GetHostedZoneResponse struct {
+ XMLName xml.Name `xml:"GetHostedZoneResponse"`
+ HostedZone HostedZone
+ DelegationSet DelegationSet
+}
+
+type DeleteHostedZoneResponse struct {
+ XMLName xml.Name `xml:"DeleteHostedZoneResponse"`
+ Xmlns string `xml:"xmlns,attr"`
+ ChangeInfo ChangeInfo
+}
+
+// query sends the specified HTTP request to the path and signs the request
+// with the required authentication and headers based on the Auth.
+//
+// Automatically decodes the response into the the result interface
+func (r *Route53) query(method string, path string, body io.Reader, result interface{}) error {
+ var err error
+
+ // Create the POST request and sign the headers
+ req, err := http.NewRequest(method, path, body)
+ r.Signer.Sign(req)
+
+ // Send the request and capture the response
+ client := &http.Client{}
+ res, err := client.Do(req)
+ if err != nil {
+ return err
+ }
+
+ if method == "POST" {
+ defer req.Body.Close()
+ }
+
+ if res.StatusCode != 201 && res.StatusCode != 200 {
+ err = r.Service.BuildError(res)
+ return err
+ }
+
+ err = xml.NewDecoder(res.Body).Decode(result)
+
+ return err
+}
+
+// CreateHostedZone send a creation request to the AWS Route53 API
+func (r *Route53) CreateHostedZone(hostedZoneReq *CreateHostedZoneRequest) (*CreateHostedZoneResponse, error) {
+ xmlBytes, err := xml.Marshal(hostedZoneReq)
+ if err != nil {
+ return nil, err
+ }
+
+ result := new(CreateHostedZoneResponse)
+ err = r.query("POST", r.Endpoint, bytes.NewBuffer(xmlBytes), result)
+
+ return result, err
+}
+
+// ChangeResourceRecordSet send a change resource record request to the AWS Route53 API
+func (r *Route53) ChangeResourceRecordSet(req *ChangeResourceRecordSetsRequest, zoneId string) (*ChangeResourceRecordSetsResponse, error) {
+ xmlBytes, err := xml.Marshal(req)
+ if err != nil {
+ return nil, err
+ }
+ xmlBytes = []byte(xml.Header + string(xmlBytes))
+
+ result := new(ChangeResourceRecordSetsResponse)
+ path := fmt.Sprintf("%s/%s/rrset", r.Endpoint, zoneId)
+ err = r.query("POST", path, bytes.NewBuffer(xmlBytes), result)
+
+ return result, err
+}
+
+// ListedHostedZones fetches a collection of HostedZones through the AWS Route53 API
+func (r *Route53) ListHostedZones(marker string, maxItems int) (result *ListHostedZonesResponse, err error) {
+ path := ""
+
+ if marker == "" {
+ path = fmt.Sprintf("%s?maxitems=%d", r.Endpoint, maxItems)
+ } else {
+ path = fmt.Sprintf("%s?marker=%v&maxitems=%d", r.Endpoint, marker, maxItems)
+ }
+
+ result = new(ListHostedZonesResponse)
+ err = r.query("GET", path, nil, result)
+
+ return
+}
+
+// GetHostedZone fetches a particular hostedzones DelegationSet by id
+func (r *Route53) GetHostedZone(id string) (result *GetHostedZoneResponse, err error) {
+ result = new(GetHostedZoneResponse)
+ err = r.query("GET", fmt.Sprintf("%s/%v", r.Endpoint, id), nil, result)
+
+ return
+}
+
+// DeleteHostedZone deletes the hosted zone with the given id
+func (r *Route53) DeleteHostedZone(id string) (result *DeleteHostedZoneResponse, err error) {
+ path := fmt.Sprintf("%s/%s", r.Endpoint, id)
+
+ result = new(DeleteHostedZoneResponse)
+ err = r.query("DELETE", path, nil, result)
+
+ return
+}
diff --git a/vendor/github.com/goamz/goamz/s3/export_test.go b/vendor/github.com/goamz/goamz/s3/export_test.go
new file mode 100644
index 000000000..4ff913cde
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/export_test.go
@@ -0,0 +1,17 @@
+package s3
+
+import (
+ "github.com/goamz/goamz/aws"
+)
+
+func Sign(auth aws.Auth, method, path string, params, headers map[string][]string) {
+ sign(auth, method, path, params, headers)
+}
+
+func SetListPartsMax(n int) {
+ listPartsMax = n
+}
+
+func SetListMultiMax(n int) {
+ listMultiMax = n
+}
diff --git a/vendor/github.com/goamz/goamz/s3/multi_test.go b/vendor/github.com/goamz/goamz/s3/multi_test.go
new file mode 100644
index 000000000..5c788d9cc
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/multi_test.go
@@ -0,0 +1,373 @@
+package s3_test
+
+import (
+ "encoding/xml"
+ "io"
+ "io/ioutil"
+ "strings"
+
+ "github.com/goamz/goamz/s3"
+ . "gopkg.in/check.v1"
+)
+
+func (s *S) TestInitMulti(c *C) {
+ testServer.Response(200, nil, InitMultiResultDump)
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Header["Content-Type"], DeepEquals, []string{"text/plain"})
+ c.Assert(req.Header["X-Amz-Acl"], DeepEquals, []string{"private"})
+ c.Assert(req.Form["uploads"], DeepEquals, []string{""})
+
+ c.Assert(multi.UploadId, Matches, "JNbR_[A-Za-z0-9.]+QQ--")
+}
+
+func (s *S) TestMultiNoPreviousUpload(c *C) {
+ // Don't retry the NoSuchUpload error.
+ s.DisableRetries()
+
+ testServer.Response(404, nil, NoSuchUploadErrorDump)
+ testServer.Response(200, nil, InitMultiResultDump)
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.Multi("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/")
+ c.Assert(req.Form["uploads"], DeepEquals, []string{""})
+ c.Assert(req.Form["prefix"], DeepEquals, []string{"multi"})
+
+ req = testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form["uploads"], DeepEquals, []string{""})
+
+ c.Assert(multi.UploadId, Matches, "JNbR_[A-Za-z0-9.]+QQ--")
+}
+
+func (s *S) TestMultiReturnOld(c *C) {
+ testServer.Response(200, nil, ListMultiResultDump)
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.Multi("multi1", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+ c.Assert(multi.Key, Equals, "multi1")
+ c.Assert(multi.UploadId, Equals, "iUVug89pPvSswrikD")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/")
+ c.Assert(req.Form["uploads"], DeepEquals, []string{""})
+ c.Assert(req.Form["prefix"], DeepEquals, []string{"multi1"})
+}
+
+func (s *S) TestListParts(c *C) {
+ testServer.Response(200, nil, InitMultiResultDump)
+ testServer.Response(200, nil, ListPartsResultDump1)
+ testServer.Response(404, nil, NoSuchUploadErrorDump) // :-(
+ testServer.Response(200, nil, ListPartsResultDump2)
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ parts, err := multi.ListParts()
+ c.Assert(err, IsNil)
+ c.Assert(parts, HasLen, 3)
+ c.Assert(parts[0].N, Equals, 1)
+ c.Assert(parts[0].Size, Equals, int64(5))
+ c.Assert(parts[0].ETag, Equals, `"ffc88b4ca90a355f8ddba6b2c3b2af5c"`)
+ c.Assert(parts[1].N, Equals, 2)
+ c.Assert(parts[1].Size, Equals, int64(5))
+ c.Assert(parts[1].ETag, Equals, `"d067a0fa9dc61a6e7195ca99696b5a89"`)
+ c.Assert(parts[2].N, Equals, 3)
+ c.Assert(parts[2].Size, Equals, int64(5))
+ c.Assert(parts[2].ETag, Equals, `"49dcd91231f801159e893fb5c6674985"`)
+ testServer.WaitRequest()
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form.Get("uploadId"), Matches, "JNbR_[A-Za-z0-9.]+QQ--")
+ c.Assert(req.Form["max-parts"], DeepEquals, []string{"1000"})
+
+ testServer.WaitRequest() // The internal error.
+ req = testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form.Get("uploadId"), Matches, "JNbR_[A-Za-z0-9.]+QQ--")
+ c.Assert(req.Form["max-parts"], DeepEquals, []string{"1000"})
+ c.Assert(req.Form["part-number-marker"], DeepEquals, []string{"2"})
+}
+
+func (s *S) TestPutPart(c *C) {
+ headers := map[string]string{
+ "ETag": `"26f90efd10d614f100252ff56d88dad8"`,
+ }
+ testServer.Response(200, nil, InitMultiResultDump)
+ testServer.Response(200, headers, "")
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ part, err := multi.PutPart(1, strings.NewReader("<part 1>"))
+ c.Assert(err, IsNil)
+ c.Assert(part.N, Equals, 1)
+ c.Assert(part.Size, Equals, int64(8))
+ c.Assert(part.ETag, Equals, headers["ETag"])
+
+ testServer.WaitRequest()
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form.Get("uploadId"), Matches, "JNbR_[A-Za-z0-9.]+QQ--")
+ c.Assert(req.Form["partNumber"], DeepEquals, []string{"1"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"8"})
+ c.Assert(req.Header["Content-Md5"], DeepEquals, []string{"JvkO/RDWFPEAJS/1bYja2A=="})
+}
+
+func readAll(r io.Reader) string {
+ data, err := ioutil.ReadAll(r)
+ if err != nil {
+ panic(err)
+ }
+ return string(data)
+}
+
+func (s *S) TestPutAllNoPreviousUpload(c *C) {
+ // Don't retry the NoSuchUpload error.
+ s.DisableRetries()
+
+ etag1 := map[string]string{"ETag": `"etag1"`}
+ etag2 := map[string]string{"ETag": `"etag2"`}
+ etag3 := map[string]string{"ETag": `"etag3"`}
+ testServer.Response(200, nil, InitMultiResultDump)
+ testServer.Response(404, nil, NoSuchUploadErrorDump)
+ testServer.Response(200, etag1, "")
+ testServer.Response(200, etag2, "")
+ testServer.Response(200, etag3, "")
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ parts, err := multi.PutAll(strings.NewReader("part1part2last"), 5)
+ c.Assert(parts, HasLen, 3)
+ c.Assert(parts[0].ETag, Equals, `"etag1"`)
+ c.Assert(parts[1].ETag, Equals, `"etag2"`)
+ c.Assert(parts[2].ETag, Equals, `"etag3"`)
+ c.Assert(err, IsNil)
+
+ // Init
+ testServer.WaitRequest()
+
+ // List old parts. Won't find anything.
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+
+ // Send part 1.
+ req = testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form["partNumber"], DeepEquals, []string{"1"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"5"})
+ c.Assert(readAll(req.Body), Equals, "part1")
+
+ // Send part 2.
+ req = testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form["partNumber"], DeepEquals, []string{"2"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"5"})
+ c.Assert(readAll(req.Body), Equals, "part2")
+
+ // Send part 3 with shorter body.
+ req = testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form["partNumber"], DeepEquals, []string{"3"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"4"})
+ c.Assert(readAll(req.Body), Equals, "last")
+}
+
+func (s *S) TestPutAllZeroSizeFile(c *C) {
+ // Don't retry the NoSuchUpload error.
+ s.DisableRetries()
+
+ etag1 := map[string]string{"ETag": `"etag1"`}
+ testServer.Response(200, nil, InitMultiResultDump)
+ testServer.Response(404, nil, NoSuchUploadErrorDump)
+ testServer.Response(200, etag1, "")
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ // Must send at least one part, so that completing it will work.
+ parts, err := multi.PutAll(strings.NewReader(""), 5)
+ c.Assert(parts, HasLen, 1)
+ c.Assert(parts[0].ETag, Equals, `"etag1"`)
+ c.Assert(err, IsNil)
+
+ // Init
+ testServer.WaitRequest()
+
+ // List old parts. Won't find anything.
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+
+ // Send empty part.
+ req = testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form["partNumber"], DeepEquals, []string{"1"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"0"})
+ c.Assert(readAll(req.Body), Equals, "")
+}
+
+func (s *S) TestPutAllResume(c *C) {
+ etag2 := map[string]string{"ETag": `"etag2"`}
+ testServer.Response(200, nil, InitMultiResultDump)
+ testServer.Response(200, nil, ListPartsResultDump1)
+ testServer.Response(200, nil, ListPartsResultDump2)
+ testServer.Response(200, etag2, "")
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ // "part1" and "part3" match the checksums in ResultDump1.
+ // The middle one is a mismatch (it refers to "part2").
+ parts, err := multi.PutAll(strings.NewReader("part1partXpart3"), 5)
+ c.Assert(parts, HasLen, 3)
+ c.Assert(parts[0].N, Equals, 1)
+ c.Assert(parts[0].Size, Equals, int64(5))
+ c.Assert(parts[0].ETag, Equals, `"ffc88b4ca90a355f8ddba6b2c3b2af5c"`)
+ c.Assert(parts[1].N, Equals, 2)
+ c.Assert(parts[1].Size, Equals, int64(5))
+ c.Assert(parts[1].ETag, Equals, `"etag2"`)
+ c.Assert(parts[2].N, Equals, 3)
+ c.Assert(parts[2].Size, Equals, int64(5))
+ c.Assert(parts[2].ETag, Equals, `"49dcd91231f801159e893fb5c6674985"`)
+ c.Assert(err, IsNil)
+
+ // Init
+ testServer.WaitRequest()
+
+ // List old parts, broken in two requests.
+ for i := 0; i < 2; i++ {
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ }
+
+ // Send part 2, as it didn't match the checksum.
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form["partNumber"], DeepEquals, []string{"2"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"5"})
+ c.Assert(readAll(req.Body), Equals, "partX")
+}
+
+func (s *S) TestMultiComplete(c *C) {
+ testServer.Response(200, nil, InitMultiResultDump)
+ // Note the 200 response. Completing will hold the connection on some
+ // kind of long poll, and may return a late error even after a 200.
+ testServer.Response(200, nil, InternalErrorDump)
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ err = multi.Complete([]s3.Part{{2, `"ETag2"`, 32}, {1, `"ETag1"`, 64}})
+ // returns InternalErrorDump in the payload, which should manifest as
+ // an error.
+ c.Assert(err, NotNil)
+
+ testServer.WaitRequest()
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form.Get("uploadId"), Matches, "JNbR_[A-Za-z0-9.]+QQ--")
+
+ var payload struct {
+ XMLName xml.Name
+ Part []struct {
+ PartNumber int
+ ETag string
+ }
+ }
+
+ dec := xml.NewDecoder(req.Body)
+ err = dec.Decode(&payload)
+ c.Assert(err, IsNil)
+
+ c.Assert(payload.XMLName.Local, Equals, "CompleteMultipartUpload")
+ c.Assert(len(payload.Part), Equals, 2)
+ c.Assert(payload.Part[0].PartNumber, Equals, 1)
+ c.Assert(payload.Part[0].ETag, Equals, `"ETag1"`)
+ c.Assert(payload.Part[1].PartNumber, Equals, 2)
+ c.Assert(payload.Part[1].ETag, Equals, `"ETag2"`)
+}
+
+func (s *S) TestMultiAbort(c *C) {
+ testServer.Response(200, nil, InitMultiResultDump)
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("sample")
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+
+ err = multi.Abort()
+ c.Assert(err, IsNil)
+
+ testServer.WaitRequest()
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "DELETE")
+ c.Assert(req.URL.Path, Equals, "/sample/multi")
+ c.Assert(req.Form.Get("uploadId"), Matches, "JNbR_[A-Za-z0-9.]+QQ--")
+}
+
+func (s *S) TestListMulti(c *C) {
+ testServer.Response(200, nil, ListMultiResultDump)
+
+ b := s.s3.Bucket("sample")
+
+ multis, prefixes, err := b.ListMulti("", "/")
+ c.Assert(err, IsNil)
+ c.Assert(prefixes, DeepEquals, []string{"a/", "b/"})
+ c.Assert(multis, HasLen, 2)
+ c.Assert(multis[0].Key, Equals, "multi1")
+ c.Assert(multis[0].UploadId, Equals, "iUVug89pPvSswrikD")
+ c.Assert(multis[1].Key, Equals, "multi2")
+ c.Assert(multis[1].UploadId, Equals, "DkirwsSvPp98guVUi")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/sample/")
+ c.Assert(req.Form["uploads"], DeepEquals, []string{""})
+ c.Assert(req.Form["prefix"], DeepEquals, []string{""})
+ c.Assert(req.Form["delimiter"], DeepEquals, []string{"/"})
+ c.Assert(req.Form["max-uploads"], DeepEquals, []string{"1000"})
+}
diff --git a/vendor/github.com/goamz/goamz/s3/responses_test.go b/vendor/github.com/goamz/goamz/s3/responses_test.go
new file mode 100644
index 000000000..414ede0a7
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/responses_test.go
@@ -0,0 +1,202 @@
+package s3_test
+
+var GetObjectErrorDump = `
+<?xml version="1.0" encoding="UTF-8"?>
+<Error>
+ <Code>NoSuchBucket</Code>
+ <Message>The specified bucket does not exist</Message>
+ <BucketName>non-existent-bucket</BucketName>
+ <RequestId>3F1B667FAD71C3D8</RequestId>
+ <HostId>L4ee/zrm1irFXY5F45fKXIRdOf9ktsKY/8TDVawuMK2jWRb1RF84i1uBzkdNqS5D</HostId>
+</Error>
+`
+
+var GetListResultDump1 = `
+<?xml version="1.0" encoding="UTF-8"?>
+<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01">
+ <Name>quotes</Name>
+ <Prefix>N</Prefix>
+ <IsTruncated>false</IsTruncated>
+ <Contents>
+ <Key>Nelson</Key>
+ <LastModified>2006-01-01T12:00:00.000Z</LastModified>
+ <ETag>&quot;828ef3fdfa96f00ad9f27c383fc9ac7f&quot;</ETag>
+ <Size>5</Size>
+ <StorageClass>STANDARD</StorageClass>
+ <Owner>
+ <ID>bcaf161ca5fb16fd081034f</ID>
+ <DisplayName>webfile</DisplayName>
+ </Owner>
+ </Contents>
+ <Contents>
+ <Key>Neo</Key>
+ <LastModified>2006-01-01T12:00:00.000Z</LastModified>
+ <ETag>&quot;828ef3fdfa96f00ad9f27c383fc9ac7f&quot;</ETag>
+ <Size>4</Size>
+ <StorageClass>STANDARD</StorageClass>
+ <Owner>
+ <ID>bcaf1ffd86a5fb16fd081034f</ID>
+ <DisplayName>webfile</DisplayName>
+ </Owner>
+ </Contents>
+</ListBucketResult>
+`
+
+var GetListResultDump2 = `
+<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ <Name>example-bucket</Name>
+ <Prefix>photos/2006/</Prefix>
+ <Marker>some-marker</Marker>
+ <MaxKeys>1000</MaxKeys>
+ <Delimiter>/</Delimiter>
+ <IsTruncated>false</IsTruncated>
+
+ <CommonPrefixes>
+ <Prefix>photos/2006/feb/</Prefix>
+ </CommonPrefixes>
+ <CommonPrefixes>
+ <Prefix>photos/2006/jan/</Prefix>
+ </CommonPrefixes>
+</ListBucketResult>
+`
+
+var InitMultiResultDump = `
+<?xml version="1.0" encoding="UTF-8"?>
+<InitiateMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ <Bucket>sample</Bucket>
+ <Key>multi</Key>
+ <UploadId>JNbR_cMdwnGiD12jKAd6WK2PUkfj2VxA7i4nCwjE6t71nI9Tl3eVDPFlU0nOixhftH7I17ZPGkV3QA.l7ZD.QQ--</UploadId>
+</InitiateMultipartUploadResult>
+`
+
+var ListPartsResultDump1 = `
+<?xml version="1.0" encoding="UTF-8"?>
+<ListPartsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ <Bucket>sample</Bucket>
+ <Key>multi</Key>
+ <UploadId>JNbR_cMdwnGiD12jKAd6WK2PUkfj2VxA7i4nCwjE6t71nI9Tl3eVDPFlU0nOixhftH7I17ZPGkV3QA.l7ZD.QQ--</UploadId>
+ <Initiator>
+ <ID>bb5c0f63b0b25f2d099c</ID>
+ <DisplayName>joe</DisplayName>
+ </Initiator>
+ <Owner>
+ <ID>bb5c0f63b0b25f2d099c</ID>
+ <DisplayName>joe</DisplayName>
+ </Owner>
+ <StorageClass>STANDARD</StorageClass>
+ <PartNumberMarker>0</PartNumberMarker>
+ <NextPartNumberMarker>2</NextPartNumberMarker>
+ <MaxParts>2</MaxParts>
+ <IsTruncated>true</IsTruncated>
+ <Part>
+ <PartNumber>1</PartNumber>
+ <LastModified>2013-01-30T13:45:51.000Z</LastModified>
+ <ETag>&quot;ffc88b4ca90a355f8ddba6b2c3b2af5c&quot;</ETag>
+ <Size>5</Size>
+ </Part>
+ <Part>
+ <PartNumber>2</PartNumber>
+ <LastModified>2013-01-30T13:45:52.000Z</LastModified>
+ <ETag>&quot;d067a0fa9dc61a6e7195ca99696b5a89&quot;</ETag>
+ <Size>5</Size>
+ </Part>
+</ListPartsResult>
+`
+
+var ListPartsResultDump2 = `
+<?xml version="1.0" encoding="UTF-8"?>
+<ListPartsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ <Bucket>sample</Bucket>
+ <Key>multi</Key>
+ <UploadId>JNbR_cMdwnGiD12jKAd6WK2PUkfj2VxA7i4nCwjE6t71nI9Tl3eVDPFlU0nOixhftH7I17ZPGkV3QA.l7ZD.QQ--</UploadId>
+ <Initiator>
+ <ID>bb5c0f63b0b25f2d099c</ID>
+ <DisplayName>joe</DisplayName>
+ </Initiator>
+ <Owner>
+ <ID>bb5c0f63b0b25f2d099c</ID>
+ <DisplayName>joe</DisplayName>
+ </Owner>
+ <StorageClass>STANDARD</StorageClass>
+ <PartNumberMarker>2</PartNumberMarker>
+ <NextPartNumberMarker>3</NextPartNumberMarker>
+ <MaxParts>2</MaxParts>
+ <IsTruncated>false</IsTruncated>
+ <Part>
+ <PartNumber>3</PartNumber>
+ <LastModified>2013-01-30T13:46:50.000Z</LastModified>
+ <ETag>&quot;49dcd91231f801159e893fb5c6674985&quot;</ETag>
+ <Size>5</Size>
+ </Part>
+</ListPartsResult>
+`
+
+var ListMultiResultDump = `
+<?xml version="1.0"?>
+<ListMultipartUploadsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+ <Bucket>goamz-test-bucket-us-east-1-akiajk3wyewhctyqbf7a</Bucket>
+ <KeyMarker/>
+ <UploadIdMarker/>
+ <NextKeyMarker>multi1</NextKeyMarker>
+ <NextUploadIdMarker>iUVug89pPvSswrikD72p8uO62EzhNtpDxRmwC5WSiWDdK9SfzmDqe3xpP1kMWimyimSnz4uzFc3waVM5ufrKYQ--</NextUploadIdMarker>
+ <Delimiter>/</Delimiter>
+ <MaxUploads>1000</MaxUploads>
+ <IsTruncated>false</IsTruncated>
+ <Upload>
+ <Key>multi1</Key>
+ <UploadId>iUVug89pPvSswrikD</UploadId>
+ <Initiator>
+ <ID>bb5c0f63b0b25f2d0</ID>
+ <DisplayName>gustavoniemeyer</DisplayName>
+ </Initiator>
+ <Owner>
+ <ID>bb5c0f63b0b25f2d0</ID>
+ <DisplayName>gustavoniemeyer</DisplayName>
+ </Owner>
+ <StorageClass>STANDARD</StorageClass>
+ <Initiated>2013-01-30T18:15:47.000Z</Initiated>
+ </Upload>
+ <Upload>
+ <Key>multi2</Key>
+ <UploadId>DkirwsSvPp98guVUi</UploadId>
+ <Initiator>
+ <ID>bb5c0f63b0b25f2d0</ID>
+ <DisplayName>joe</DisplayName>
+ </Initiator>
+ <Owner>
+ <ID>bb5c0f63b0b25f2d0</ID>
+ <DisplayName>joe</DisplayName>
+ </Owner>
+ <StorageClass>STANDARD</StorageClass>
+ <Initiated>2013-01-30T18:15:47.000Z</Initiated>
+ </Upload>
+ <CommonPrefixes>
+ <Prefix>a/</Prefix>
+ </CommonPrefixes>
+ <CommonPrefixes>
+ <Prefix>b/</Prefix>
+ </CommonPrefixes>
+</ListMultipartUploadsResult>
+`
+
+var NoSuchUploadErrorDump = `
+<?xml version="1.0" encoding="UTF-8"?>
+<Error>
+ <Code>NoSuchUpload</Code>
+ <Message>Not relevant</Message>
+ <BucketName>sample</BucketName>
+ <RequestId>3F1B667FAD71C3D8</RequestId>
+ <HostId>kjhwqk</HostId>
+</Error>
+`
+
+var InternalErrorDump = `
+<?xml version="1.0" encoding="UTF-8"?>
+<Error>
+ <Code>InternalError</Code>
+ <Message>Not relevant</Message>
+ <BucketName>sample</BucketName>
+ <RequestId>3F1B667FAD71C3D8</RequestId>
+ <HostId>kjhwqk</HostId>
+</Error>
+`
diff --git a/vendor/github.com/goamz/goamz/s3/s3_test.go b/vendor/github.com/goamz/goamz/s3/s3_test.go
new file mode 100644
index 000000000..24d4dfcc0
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/s3_test.go
@@ -0,0 +1,427 @@
+package s3_test
+
+import (
+ "bytes"
+ "io/ioutil"
+ "net/http"
+ "testing"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/s3"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+type S struct {
+ s3 *s3.S3
+}
+
+var _ = Suite(&S{})
+
+var testServer = testutil.NewHTTPServer()
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.s3 = s3.New(auth, aws.Region{Name: "faux-region-1", S3Endpoint: testServer.URL})
+}
+
+func (s *S) TearDownSuite(c *C) {
+ s.s3.AttemptStrategy = s3.DefaultAttemptStrategy
+}
+
+func (s *S) SetUpTest(c *C) {
+ s.s3.AttemptStrategy = aws.AttemptStrategy{
+ Total: 300 * time.Millisecond,
+ Delay: 100 * time.Millisecond,
+ }
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) DisableRetries() {
+ s.s3.AttemptStrategy = aws.AttemptStrategy{}
+}
+
+// PutBucket docs: http://goo.gl/kBTCu
+
+func (s *S) TestPutBucket(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ err := b.PutBucket(s3.Private)
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/bucket/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+}
+
+// Head docs: http://bit.ly/17K1ylI
+
+func (s *S) TestHead(c *C) {
+ testServer.Response(200, nil, "content")
+
+ b := s.s3.Bucket("bucket")
+ resp, err := b.Head("name", nil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "HEAD")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(err, IsNil)
+ c.Assert(resp.ContentLength, FitsTypeOf, int64(0))
+ c.Assert(resp, FitsTypeOf, &http.Response{})
+}
+
+// DeleteBucket docs: http://goo.gl/GoBrY
+
+func (s *S) TestDelBucket(c *C) {
+ testServer.Response(204, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ err := b.DelBucket()
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "DELETE")
+ c.Assert(req.URL.Path, Equals, "/bucket/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+}
+
+// GetObject docs: http://goo.gl/isCO7
+
+func (s *S) TestGet(c *C) {
+ testServer.Response(200, nil, "content")
+
+ b := s.s3.Bucket("bucket")
+ data, err := b.Get("name")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, "content")
+}
+
+func (s *S) TestURL(c *C) {
+ testServer.Response(200, nil, "content")
+
+ b := s.s3.Bucket("bucket")
+ url := b.URL("name")
+ r, err := http.Get(url)
+ c.Assert(err, IsNil)
+ data, err := ioutil.ReadAll(r.Body)
+ r.Body.Close()
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, "content")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+}
+
+func (s *S) TestGetReader(c *C) {
+ testServer.Response(200, nil, "content")
+
+ b := s.s3.Bucket("bucket")
+ rc, err := b.GetReader("name")
+ c.Assert(err, IsNil)
+ data, err := ioutil.ReadAll(rc)
+ rc.Close()
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, "content")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+}
+
+func (s *S) TestGetNotFound(c *C) {
+ for i := 0; i < 10; i++ {
+ testServer.Response(404, nil, GetObjectErrorDump)
+ }
+
+ b := s.s3.Bucket("non-existent-bucket")
+ data, err := b.Get("non-existent")
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/non-existent-bucket/non-existent")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ s3err, _ := err.(*s3.Error)
+ c.Assert(s3err, NotNil)
+ c.Assert(s3err.StatusCode, Equals, 404)
+ c.Assert(s3err.BucketName, Equals, "non-existent-bucket")
+ c.Assert(s3err.RequestId, Equals, "3F1B667FAD71C3D8")
+ c.Assert(s3err.HostId, Equals, "L4ee/zrm1irFXY5F45fKXIRdOf9ktsKY/8TDVawuMK2jWRb1RF84i1uBzkdNqS5D")
+ c.Assert(s3err.Code, Equals, "NoSuchBucket")
+ c.Assert(s3err.Message, Equals, "The specified bucket does not exist")
+ c.Assert(s3err.Error(), Equals, "The specified bucket does not exist")
+ c.Assert(data, IsNil)
+}
+
+// PutObject docs: http://goo.gl/FEBPD
+
+func (s *S) TestPutObject(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ err := b.Put("name", []byte("content"), "content-type", s3.Private, s3.Options{})
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(DeepEquals), []string{""})
+ c.Assert(req.Header["Content-Type"], DeepEquals, []string{"content-type"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"7"})
+ //c.Assert(req.Header["Content-MD5"], DeepEquals, "...")
+ c.Assert(req.Header["X-Amz-Acl"], DeepEquals, []string{"private"})
+}
+
+func (s *S) TestPutObjectReadTimeout(c *C) {
+ s.s3.ReadTimeout = 50 * time.Millisecond
+ defer func() {
+ s.s3.ReadTimeout = 0
+ }()
+
+ b := s.s3.Bucket("bucket")
+ err := b.Put("name", []byte("content"), "content-type", s3.Private, s3.Options{})
+
+ // Make sure that we get a timeout error.
+ c.Assert(err, NotNil)
+
+ // Set the response after the request times out so that the next request will work.
+ testServer.Response(200, nil, "")
+
+ // This time set the response within our timeout period so that we expect the call
+ // to return successfully.
+ go func() {
+ time.Sleep(25 * time.Millisecond)
+ testServer.Response(200, nil, "")
+ }()
+ err = b.Put("name", []byte("content"), "content-type", s3.Private, s3.Options{})
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestPutObjectHeader(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ err := b.PutHeader(
+ "name",
+ []byte("content"),
+ map[string][]string{"Content-Type": {"content-type"}},
+ s3.Private,
+ )
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(DeepEquals), []string{""})
+ c.Assert(req.Header["Content-Type"], DeepEquals, []string{"content-type"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"7"})
+ //c.Assert(req.Header["Content-MD5"], DeepEquals, "...")
+ c.Assert(req.Header["X-Amz-Acl"], DeepEquals, []string{"private"})
+}
+
+func (s *S) TestPutReader(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ buf := bytes.NewBufferString("content")
+ err := b.PutReader("name", buf, int64(buf.Len()), "content-type", s3.Private, s3.Options{})
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(DeepEquals), []string{""})
+ c.Assert(req.Header["Content-Type"], DeepEquals, []string{"content-type"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"7"})
+ //c.Assert(req.Header["Content-MD5"], Equals, "...")
+ c.Assert(req.Header["X-Amz-Acl"], DeepEquals, []string{"private"})
+}
+
+func (s *S) TestPutReaderHeader(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ buf := bytes.NewBufferString("content")
+ err := b.PutReaderHeader(
+ "name",
+ buf,
+ int64(buf.Len()),
+ map[string][]string{"Content-Type": {"content-type"}},
+ s3.Private,
+ )
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "PUT")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(DeepEquals), []string{""})
+ c.Assert(req.Header["Content-Type"], DeepEquals, []string{"content-type"})
+ c.Assert(req.Header["Content-Length"], DeepEquals, []string{"7"})
+ //c.Assert(req.Header["Content-MD5"], Equals, "...")
+ c.Assert(req.Header["X-Amz-Acl"], DeepEquals, []string{"private"})
+}
+
+// DelObject docs: http://goo.gl/APeTt
+
+func (s *S) TestDelObject(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ err := b.Del("name")
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "DELETE")
+ c.Assert(req.URL.Path, Equals, "/bucket/name")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+}
+
+func (s *S) TestDelMultiObjects(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ objects := []s3.Object{s3.Object{Key: "test"}}
+ err := b.DelMulti(s3.Delete{
+ Quiet: false,
+ Objects: objects,
+ })
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "POST")
+ c.Assert(req.URL.RawQuery, Equals, "delete=")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+ c.Assert(req.Header["Content-MD5"], Not(Equals), "")
+ c.Assert(req.Header["Content-Type"], Not(Equals), "")
+ c.Assert(req.ContentLength, Not(Equals), "")
+}
+
+// Bucket List Objects docs: http://goo.gl/YjQTc
+
+func (s *S) TestList(c *C) {
+ testServer.Response(200, nil, GetListResultDump1)
+
+ b := s.s3.Bucket("quotes")
+
+ data, err := b.List("N", "", "", 0)
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/quotes/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+ c.Assert(req.Form["prefix"], DeepEquals, []string{"N"})
+ c.Assert(req.Form["delimiter"], DeepEquals, []string{""})
+ c.Assert(req.Form["marker"], DeepEquals, []string{""})
+ c.Assert(req.Form["max-keys"], DeepEquals, []string(nil))
+
+ c.Assert(data.Name, Equals, "quotes")
+ c.Assert(data.Prefix, Equals, "N")
+ c.Assert(data.IsTruncated, Equals, false)
+ c.Assert(len(data.Contents), Equals, 2)
+
+ c.Assert(data.Contents[0].Key, Equals, "Nelson")
+ c.Assert(data.Contents[0].LastModified, Equals, "2006-01-01T12:00:00.000Z")
+ c.Assert(data.Contents[0].ETag, Equals, `"828ef3fdfa96f00ad9f27c383fc9ac7f"`)
+ c.Assert(data.Contents[0].Size, Equals, int64(5))
+ c.Assert(data.Contents[0].StorageClass, Equals, "STANDARD")
+ c.Assert(data.Contents[0].Owner.ID, Equals, "bcaf161ca5fb16fd081034f")
+ c.Assert(data.Contents[0].Owner.DisplayName, Equals, "webfile")
+
+ c.Assert(data.Contents[1].Key, Equals, "Neo")
+ c.Assert(data.Contents[1].LastModified, Equals, "2006-01-01T12:00:00.000Z")
+ c.Assert(data.Contents[1].ETag, Equals, `"828ef3fdfa96f00ad9f27c383fc9ac7f"`)
+ c.Assert(data.Contents[1].Size, Equals, int64(4))
+ c.Assert(data.Contents[1].StorageClass, Equals, "STANDARD")
+ c.Assert(data.Contents[1].Owner.ID, Equals, "bcaf1ffd86a5fb16fd081034f")
+ c.Assert(data.Contents[1].Owner.DisplayName, Equals, "webfile")
+}
+
+func (s *S) TestListWithDelimiter(c *C) {
+ testServer.Response(200, nil, GetListResultDump2)
+
+ b := s.s3.Bucket("quotes")
+
+ data, err := b.List("photos/2006/", "/", "some-marker", 1000)
+ c.Assert(err, IsNil)
+
+ req := testServer.WaitRequest()
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/quotes/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+ c.Assert(req.Form["prefix"], DeepEquals, []string{"photos/2006/"})
+ c.Assert(req.Form["delimiter"], DeepEquals, []string{"/"})
+ c.Assert(req.Form["marker"], DeepEquals, []string{"some-marker"})
+ c.Assert(req.Form["max-keys"], DeepEquals, []string{"1000"})
+
+ c.Assert(data.Name, Equals, "example-bucket")
+ c.Assert(data.Prefix, Equals, "photos/2006/")
+ c.Assert(data.Delimiter, Equals, "/")
+ c.Assert(data.Marker, Equals, "some-marker")
+ c.Assert(data.IsTruncated, Equals, false)
+ c.Assert(len(data.Contents), Equals, 0)
+ c.Assert(data.CommonPrefixes, DeepEquals, []string{"photos/2006/feb/", "photos/2006/jan/"})
+}
+
+func (s *S) TestExists(c *C) {
+ testServer.Response(200, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ result, err := b.Exists("name")
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "HEAD")
+
+ c.Assert(err, IsNil)
+ c.Assert(result, Equals, true)
+}
+
+func (s *S) TestExistsNotFound404(c *C) {
+ testServer.Response(404, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ result, err := b.Exists("name")
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "HEAD")
+
+ c.Assert(err, IsNil)
+ c.Assert(result, Equals, false)
+}
+
+func (s *S) TestExistsNotFound403(c *C) {
+ testServer.Response(403, nil, "")
+
+ b := s.s3.Bucket("bucket")
+ result, err := b.Exists("name")
+
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "HEAD")
+
+ c.Assert(err, IsNil)
+ c.Assert(result, Equals, false)
+}
diff --git a/vendor/github.com/goamz/goamz/s3/s3i_test.go b/vendor/github.com/goamz/goamz/s3/s3i_test.go
new file mode 100644
index 000000000..1b898efc4
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/s3i_test.go
@@ -0,0 +1,590 @@
+package s3_test
+
+import (
+ "bytes"
+ "crypto/md5"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/s3"
+ "github.com/goamz/goamz/testutil"
+ . "gopkg.in/check.v1"
+)
+
+// AmazonServer represents an Amazon S3 server.
+type AmazonServer struct {
+ auth aws.Auth
+}
+
+func (s *AmazonServer) SetUp(c *C) {
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ c.Fatal(err.Error())
+ }
+ s.auth = auth
+}
+
+var _ = Suite(&AmazonClientSuite{Region: aws.USEast})
+var _ = Suite(&AmazonClientSuite{Region: aws.EUWest})
+var _ = Suite(&AmazonDomainClientSuite{Region: aws.USEast})
+
+// AmazonClientSuite tests the client against a live S3 server.
+type AmazonClientSuite struct {
+ aws.Region
+ srv AmazonServer
+ ClientTests
+}
+
+func (s *AmazonClientSuite) SetUpSuite(c *C) {
+ if !testutil.Amazon {
+ c.Skip("live tests against AWS disabled (no -amazon)")
+ }
+ s.srv.SetUp(c)
+ s.s3 = s3.New(s.srv.auth, s.Region)
+ // In case tests were interrupted in the middle before.
+ s.ClientTests.Cleanup()
+}
+
+func (s *AmazonClientSuite) TearDownTest(c *C) {
+ s.ClientTests.Cleanup()
+}
+
+// AmazonDomainClientSuite tests the client against a live S3
+// server using bucket names in the endpoint domain name rather
+// than the request path.
+type AmazonDomainClientSuite struct {
+ aws.Region
+ srv AmazonServer
+ ClientTests
+}
+
+func (s *AmazonDomainClientSuite) SetUpSuite(c *C) {
+ if !testutil.Amazon {
+ c.Skip("live tests against AWS disabled (no -amazon)")
+ }
+ s.srv.SetUp(c)
+ region := s.Region
+ region.S3BucketEndpoint = "https://${bucket}.s3.amazonaws.com"
+ s.s3 = s3.New(s.srv.auth, region)
+ s.ClientTests.Cleanup()
+}
+
+func (s *AmazonDomainClientSuite) TearDownTest(c *C) {
+ s.ClientTests.Cleanup()
+}
+
+// ClientTests defines integration tests designed to test the client.
+// It is not used as a test suite in itself, but embedded within
+// another type.
+type ClientTests struct {
+ s3 *s3.S3
+ authIsBroken bool
+}
+
+func (s *ClientTests) Cleanup() {
+ killBucket(testBucket(s.s3))
+}
+
+func testBucket(s *s3.S3) *s3.Bucket {
+ // Watch out! If this function is corrupted and made to match with something
+ // people own, killBucket will happily remove *everything* inside the bucket.
+ key := s.Auth.AccessKey
+ if len(key) >= 8 {
+ key = s.Auth.AccessKey[:8]
+ }
+ return s.Bucket(fmt.Sprintf("goamz-%s-%s", s.Region.Name, key))
+}
+
+var attempts = aws.AttemptStrategy{
+ Min: 5,
+ Total: 20 * time.Second,
+ Delay: 100 * time.Millisecond,
+}
+
+func killBucket(b *s3.Bucket) {
+ var err error
+ for attempt := attempts.Start(); attempt.Next(); {
+ err = b.DelBucket()
+ if err == nil {
+ return
+ }
+ if _, ok := err.(*net.DNSError); ok {
+ return
+ }
+ e, ok := err.(*s3.Error)
+ if ok && e.Code == "NoSuchBucket" {
+ return
+ }
+ if ok && e.Code == "BucketNotEmpty" {
+ // Errors are ignored here. Just retry.
+ resp, err := b.List("", "", "", 1000)
+ if err == nil {
+ for _, key := range resp.Contents {
+ _ = b.Del(key.Key)
+ }
+ }
+ multis, _, _ := b.ListMulti("", "")
+ for _, m := range multis {
+ _ = m.Abort()
+ }
+ }
+ }
+ message := "cannot delete test bucket"
+ if err != nil {
+ message += ": " + err.Error()
+ }
+ panic(message)
+}
+
+func get(url string) ([]byte, error) {
+ for attempt := attempts.Start(); attempt.Next(); {
+ resp, err := http.Get(url)
+ if err != nil {
+ if attempt.HasNext() {
+ continue
+ }
+ return nil, err
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ if attempt.HasNext() {
+ continue
+ }
+ return nil, err
+ }
+ return data, err
+ }
+ panic("unreachable")
+}
+
+func (s *ClientTests) TestBasicFunctionality(c *C) {
+ b := testBucket(s.s3)
+ err := b.PutBucket(s3.PublicRead)
+ c.Assert(err, IsNil)
+
+ err = b.Put("name", []byte("yo!"), "text/plain", s3.PublicRead, s3.Options{})
+ c.Assert(err, IsNil)
+ defer b.Del("name")
+
+ data, err := b.Get("name")
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, "yo!")
+
+ data, err = get(b.URL("name"))
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, "yo!")
+
+ buf := bytes.NewBufferString("hey!")
+ err = b.PutReader("name2", buf, int64(buf.Len()), "text/plain", s3.Private, s3.Options{})
+ c.Assert(err, IsNil)
+ defer b.Del("name2")
+
+ rc, err := b.GetReader("name2")
+ c.Assert(err, IsNil)
+ data, err = ioutil.ReadAll(rc)
+ c.Check(err, IsNil)
+ c.Check(string(data), Equals, "hey!")
+ rc.Close()
+
+ data, err = get(b.SignedURL("name2", time.Now().Add(time.Hour)))
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, "hey!")
+
+ if !s.authIsBroken {
+ data, err = get(b.SignedURL("name2", time.Now().Add(-time.Hour)))
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Matches, "(?s).*AccessDenied.*")
+ }
+
+ err = b.DelBucket()
+ c.Assert(err, NotNil)
+
+ s3err, ok := err.(*s3.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(s3err.Code, Equals, "BucketNotEmpty")
+ c.Assert(s3err.BucketName, Equals, b.Name)
+ c.Assert(s3err.Message, Equals, "The bucket you tried to delete is not empty")
+
+ err = b.Del("name")
+ c.Assert(err, IsNil)
+ err = b.Del("name2")
+ c.Assert(err, IsNil)
+
+ err = b.DelBucket()
+ c.Assert(err, IsNil)
+}
+
+func (s *ClientTests) TestGetNotFound(c *C) {
+ b := s.s3.Bucket("goamz-" + s.s3.Auth.AccessKey)
+ data, err := b.Get("non-existent")
+
+ s3err, _ := err.(*s3.Error)
+ c.Assert(s3err, NotNil)
+ c.Assert(s3err.StatusCode, Equals, 404)
+ c.Assert(s3err.Code, Equals, "NoSuchBucket")
+ c.Assert(s3err.Message, Equals, "The specified bucket does not exist")
+ c.Assert(data, IsNil)
+}
+
+// Communicate with all endpoints to see if they are alive.
+func (s *ClientTests) TestRegions(c *C) {
+ errs := make(chan error, len(aws.Regions))
+ for _, region := range aws.Regions {
+ go func(r aws.Region) {
+ s := s3.New(s.s3.Auth, r)
+ b := s.Bucket("goamz-" + s.Auth.AccessKey)
+ _, err := b.Get("non-existent")
+ errs <- err
+ }(region)
+ }
+ for _ = range aws.Regions {
+ err := <-errs
+ if err != nil {
+ s3_err, ok := err.(*s3.Error)
+ if ok {
+ c.Check(s3_err.Code, Matches, "NoSuchBucket")
+ } else if _, ok = err.(*net.DNSError); ok {
+ // Okay as well.
+ } else {
+ c.Errorf("Non-S3 error: %s", err)
+ }
+ } else {
+ c.Errorf("Test should have errored but it seems to have succeeded")
+ }
+ }
+}
+
+var objectNames = []string{
+ "index.html",
+ "index2.html",
+ "photos/2006/February/sample2.jpg",
+ "photos/2006/February/sample3.jpg",
+ "photos/2006/February/sample4.jpg",
+ "photos/2006/January/sample.jpg",
+ "test/bar",
+ "test/foo",
+}
+
+func keys(names ...string) []s3.Key {
+ ks := make([]s3.Key, len(names))
+ for i, name := range names {
+ ks[i].Key = name
+ }
+ return ks
+}
+
+// As the ListResp specifies all the parameters to the
+// request too, we use it to specify request parameters
+// and expected results. The Contents field is
+// used only for the key names inside it.
+var listTests = []s3.ListResp{
+ // normal list.
+ {
+ Contents: keys(objectNames...),
+ }, {
+ Marker: objectNames[0],
+ Contents: keys(objectNames[1:]...),
+ }, {
+ Marker: objectNames[0] + "a",
+ Contents: keys(objectNames[1:]...),
+ }, {
+ Marker: "z",
+ },
+
+ // limited results.
+ {
+ MaxKeys: 2,
+ Contents: keys(objectNames[0:2]...),
+ IsTruncated: true,
+ }, {
+ MaxKeys: 2,
+ Marker: objectNames[0],
+ Contents: keys(objectNames[1:3]...),
+ IsTruncated: true,
+ }, {
+ MaxKeys: 2,
+ Marker: objectNames[len(objectNames)-2],
+ Contents: keys(objectNames[len(objectNames)-1:]...),
+ },
+
+ // with delimiter
+ {
+ Delimiter: "/",
+ CommonPrefixes: []string{"photos/", "test/"},
+ Contents: keys("index.html", "index2.html"),
+ }, {
+ Delimiter: "/",
+ Prefix: "photos/2006/",
+ CommonPrefixes: []string{"photos/2006/February/", "photos/2006/January/"},
+ }, {
+ Delimiter: "/",
+ Prefix: "t",
+ CommonPrefixes: []string{"test/"},
+ }, {
+ Delimiter: "/",
+ MaxKeys: 1,
+ Contents: keys("index.html"),
+ IsTruncated: true,
+ }, {
+ Delimiter: "/",
+ MaxKeys: 1,
+ Marker: "index2.html",
+ CommonPrefixes: []string{"photos/"},
+ IsTruncated: true,
+ }, {
+ Delimiter: "/",
+ MaxKeys: 1,
+ Marker: "photos/",
+ CommonPrefixes: []string{"test/"},
+ IsTruncated: false,
+ }, {
+ Delimiter: "Feb",
+ CommonPrefixes: []string{"photos/2006/Feb"},
+ Contents: keys("index.html", "index2.html", "photos/2006/January/sample.jpg", "test/bar", "test/foo"),
+ },
+}
+
+func (s *ClientTests) TestDoublePutBucket(c *C) {
+ b := testBucket(s.s3)
+ err := b.PutBucket(s3.PublicRead)
+ c.Assert(err, IsNil)
+
+ err = b.PutBucket(s3.PublicRead)
+ if err != nil {
+ c.Assert(err, FitsTypeOf, new(s3.Error))
+ c.Assert(err.(*s3.Error).Code, Equals, "BucketAlreadyOwnedByYou")
+ }
+}
+
+func (s *ClientTests) TestBucketList(c *C) {
+ b := testBucket(s.s3)
+ err := b.PutBucket(s3.Private)
+ c.Assert(err, IsNil)
+
+ objData := make(map[string][]byte)
+ for i, path := range objectNames {
+ data := []byte(strings.Repeat("a", i))
+ err := b.Put(path, data, "text/plain", s3.Private, s3.Options{})
+ c.Assert(err, IsNil)
+ defer b.Del(path)
+ objData[path] = data
+ }
+
+ for i, t := range listTests {
+ c.Logf("test %d", i)
+ resp, err := b.List(t.Prefix, t.Delimiter, t.Marker, t.MaxKeys)
+ c.Assert(err, IsNil)
+ c.Check(resp.Name, Equals, b.Name)
+ c.Check(resp.Delimiter, Equals, t.Delimiter)
+ c.Check(resp.IsTruncated, Equals, t.IsTruncated)
+ c.Check(resp.CommonPrefixes, DeepEquals, t.CommonPrefixes)
+ checkContents(c, resp.Contents, objData, t.Contents)
+ }
+}
+
+func etag(data []byte) string {
+ sum := md5.New()
+ sum.Write(data)
+ return fmt.Sprintf(`"%x"`, sum.Sum(nil))
+}
+
+func checkContents(c *C, contents []s3.Key, data map[string][]byte, expected []s3.Key) {
+ c.Assert(contents, HasLen, len(expected))
+ for i, k := range contents {
+ c.Check(k.Key, Equals, expected[i].Key)
+ // TODO mtime
+ c.Check(k.Size, Equals, int64(len(data[k.Key])))
+ c.Check(k.ETag, Equals, etag(data[k.Key]))
+ }
+}
+
+func (s *ClientTests) TestMultiInitPutList(c *C) {
+ b := testBucket(s.s3)
+ err := b.PutBucket(s3.Private)
+ c.Assert(err, IsNil)
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+ c.Assert(multi.UploadId, Matches, ".+")
+ defer multi.Abort()
+
+ var sent []s3.Part
+
+ for i := 0; i < 5; i++ {
+ p, err := multi.PutPart(i+1, strings.NewReader(fmt.Sprintf("<part %d>", i+1)))
+ c.Assert(err, IsNil)
+ c.Assert(p.N, Equals, i+1)
+ c.Assert(p.Size, Equals, int64(8))
+ c.Assert(p.ETag, Matches, ".+")
+ sent = append(sent, p)
+ }
+
+ s3.SetListPartsMax(2)
+
+ parts, err := multi.ListParts()
+ c.Assert(err, IsNil)
+ c.Assert(parts, HasLen, len(sent))
+ for i := range parts {
+ c.Assert(parts[i].N, Equals, sent[i].N)
+ c.Assert(parts[i].Size, Equals, sent[i].Size)
+ c.Assert(parts[i].ETag, Equals, sent[i].ETag)
+ }
+
+ err = multi.Complete(parts)
+ s3err, failed := err.(*s3.Error)
+ c.Assert(failed, Equals, true)
+ c.Assert(s3err.Code, Equals, "EntityTooSmall")
+
+ err = multi.Abort()
+ c.Assert(err, IsNil)
+ _, err = multi.ListParts()
+ s3err, ok := err.(*s3.Error)
+ c.Assert(ok, Equals, true)
+ c.Assert(s3err.Code, Equals, "NoSuchUpload")
+}
+
+// This may take a minute or more due to the minimum size accepted S3
+// on multipart upload parts.
+func (s *ClientTests) TestMultiComplete(c *C) {
+ b := testBucket(s.s3)
+ err := b.PutBucket(s3.Private)
+ c.Assert(err, IsNil)
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+ c.Assert(multi.UploadId, Matches, ".+")
+ defer multi.Abort()
+
+ // Minimum size S3 accepts for all but the last part is 5MB.
+ data1 := make([]byte, 5*1024*1024)
+ data2 := []byte("<part 2>")
+
+ part1, err := multi.PutPart(1, bytes.NewReader(data1))
+ c.Assert(err, IsNil)
+ part2, err := multi.PutPart(2, bytes.NewReader(data2))
+ c.Assert(err, IsNil)
+
+ // Purposefully reversed. The order requirement must be handled.
+ err = multi.Complete([]s3.Part{part2, part1})
+ c.Assert(err, IsNil)
+
+ data, err := b.Get("multi")
+ c.Assert(err, IsNil)
+
+ c.Assert(len(data), Equals, len(data1)+len(data2))
+ for i := range data1 {
+ if data[i] != data1[i] {
+ c.Fatalf("uploaded object at byte %d: want %d, got %d", data1[i], data[i])
+ }
+ }
+ c.Assert(string(data[len(data1):]), Equals, string(data2))
+}
+
+type multiList []*s3.Multi
+
+func (l multiList) Len() int { return len(l) }
+func (l multiList) Less(i, j int) bool { return l[i].Key < l[j].Key }
+func (l multiList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+
+func (s *ClientTests) TestListMulti(c *C) {
+ b := testBucket(s.s3)
+ err := b.PutBucket(s3.Private)
+ c.Assert(err, IsNil)
+
+ // Ensure an empty state before testing its behavior.
+ multis, _, err := b.ListMulti("", "")
+ for _, m := range multis {
+ err := m.Abort()
+ c.Assert(err, IsNil)
+ }
+
+ keys := []string{
+ "a/multi2",
+ "a/multi3",
+ "b/multi4",
+ "multi1",
+ }
+ for _, key := range keys {
+ m, err := b.InitMulti(key, "", s3.Private)
+ c.Assert(err, IsNil)
+ defer m.Abort()
+ }
+
+ // Amazon's implementation of the multiple-request listing for
+ // multipart uploads in progress seems broken in multiple ways.
+ // (next tokens are not provided, etc).
+ //s3.SetListMultiMax(2)
+
+ multis, prefixes, err := b.ListMulti("", "")
+ c.Assert(err, IsNil)
+ for attempt := attempts.Start(); attempt.Next() && len(multis) < len(keys); {
+ multis, prefixes, err = b.ListMulti("", "")
+ c.Assert(err, IsNil)
+ }
+ sort.Sort(multiList(multis))
+ c.Assert(prefixes, IsNil)
+ var gotKeys []string
+ for _, m := range multis {
+ gotKeys = append(gotKeys, m.Key)
+ }
+ c.Assert(gotKeys, DeepEquals, keys)
+ for _, m := range multis {
+ c.Assert(m.Bucket, Equals, b)
+ c.Assert(m.UploadId, Matches, ".+")
+ }
+
+ multis, prefixes, err = b.ListMulti("", "/")
+ for attempt := attempts.Start(); attempt.Next() && len(prefixes) < 2; {
+ multis, prefixes, err = b.ListMulti("", "")
+ c.Assert(err, IsNil)
+ }
+ c.Assert(err, IsNil)
+ c.Assert(prefixes, DeepEquals, []string{"a/", "b/"})
+ c.Assert(multis, HasLen, 1)
+ c.Assert(multis[0].Bucket, Equals, b)
+ c.Assert(multis[0].Key, Equals, "multi1")
+ c.Assert(multis[0].UploadId, Matches, ".+")
+
+ for attempt := attempts.Start(); attempt.Next() && len(multis) < 2; {
+ multis, prefixes, err = b.ListMulti("", "")
+ c.Assert(err, IsNil)
+ }
+ multis, prefixes, err = b.ListMulti("a/", "/")
+ c.Assert(err, IsNil)
+ c.Assert(prefixes, IsNil)
+ c.Assert(multis, HasLen, 2)
+ c.Assert(multis[0].Bucket, Equals, b)
+ c.Assert(multis[0].Key, Equals, "a/multi2")
+ c.Assert(multis[0].UploadId, Matches, ".+")
+ c.Assert(multis[1].Bucket, Equals, b)
+ c.Assert(multis[1].Key, Equals, "a/multi3")
+ c.Assert(multis[1].UploadId, Matches, ".+")
+}
+
+func (s *ClientTests) TestMultiPutAllZeroLength(c *C) {
+ b := testBucket(s.s3)
+ err := b.PutBucket(s3.Private)
+ c.Assert(err, IsNil)
+
+ multi, err := b.InitMulti("multi", "text/plain", s3.Private)
+ c.Assert(err, IsNil)
+ defer multi.Abort()
+
+ // This tests an edge case. Amazon requires at least one
+ // part for multiprat uploads to work, even the part is empty.
+ parts, err := multi.PutAll(strings.NewReader(""), 5*1024*1024)
+ c.Assert(err, IsNil)
+ c.Assert(parts, HasLen, 1)
+ c.Assert(parts[0].Size, Equals, int64(0))
+ c.Assert(parts[0].ETag, Equals, `"d41d8cd98f00b204e9800998ecf8427e"`)
+
+ err = multi.Complete(parts)
+ c.Assert(err, IsNil)
+}
diff --git a/vendor/github.com/goamz/goamz/s3/s3t_test.go b/vendor/github.com/goamz/goamz/s3/s3t_test.go
new file mode 100644
index 000000000..4e6f61fdb
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/s3t_test.go
@@ -0,0 +1,83 @@
+package s3_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/s3"
+ "github.com/goamz/goamz/s3/s3test"
+ . "gopkg.in/check.v1"
+)
+
+type LocalServer struct {
+ auth aws.Auth
+ region aws.Region
+ srv *s3test.Server
+ config *s3test.Config
+}
+
+func (s *LocalServer) SetUp(c *C) {
+ srv, err := s3test.NewServer(s.config)
+ c.Assert(err, IsNil)
+ c.Assert(srv, NotNil)
+
+ s.srv = srv
+ s.region = aws.Region{
+ Name: "faux-region-1",
+ S3Endpoint: srv.URL(),
+ S3LocationConstraint: true, // s3test server requires a LocationConstraint
+ }
+}
+
+// LocalServerSuite defines tests that will run
+// against the local s3test server. It includes
+// selected tests from ClientTests;
+// when the s3test functionality is sufficient, it should
+// include all of them, and ClientTests can be simply embedded.
+type LocalServerSuite struct {
+ srv LocalServer
+ clientTests ClientTests
+}
+
+var (
+ // run tests twice, once in us-east-1 mode, once not.
+ _ = Suite(&LocalServerSuite{
+ srv: LocalServer{
+ config: &s3test.Config{},
+ },
+ })
+ _ = Suite(&LocalServerSuite{
+ srv: LocalServer{
+ config: &s3test.Config{
+ Send409Conflict: true,
+ },
+ },
+ })
+)
+
+func (s *LocalServerSuite) SetUpSuite(c *C) {
+ s.srv.SetUp(c)
+ s.clientTests.s3 = s3.New(s.srv.auth, s.srv.region)
+
+ // TODO Sadly the fake server ignores auth completely right now. :-(
+ s.clientTests.authIsBroken = true
+ s.clientTests.Cleanup()
+}
+
+func (s *LocalServerSuite) TearDownTest(c *C) {
+ s.clientTests.Cleanup()
+}
+
+func (s *LocalServerSuite) TestBasicFunctionality(c *C) {
+ s.clientTests.TestBasicFunctionality(c)
+}
+
+func (s *LocalServerSuite) TestGetNotFound(c *C) {
+ s.clientTests.TestGetNotFound(c)
+}
+
+func (s *LocalServerSuite) TestBucketList(c *C) {
+ s.clientTests.TestBucketList(c)
+}
+
+func (s *LocalServerSuite) TestDoublePutBucket(c *C) {
+ s.clientTests.TestDoublePutBucket(c)
+}
diff --git a/vendor/github.com/goamz/goamz/s3/s3test/server.go b/vendor/github.com/goamz/goamz/s3/s3test/server.go
new file mode 100644
index 000000000..bf4dd8a3c
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/s3test/server.go
@@ -0,0 +1,640 @@
+package s3test
+
+import (
+ "bytes"
+ "crypto/md5"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/xml"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+ "net/url"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+
+ "github.com/goamz/goamz/s3"
+)
+
+const debug = false
+
+type s3Error struct {
+ statusCode int
+ XMLName struct{} `xml:"Error"`
+ Code string
+ Message string
+ BucketName string
+ RequestId string
+ HostId string
+}
+
+type action struct {
+ srv *Server
+ w http.ResponseWriter
+ req *http.Request
+ reqId string
+}
+
+// Config controls the internal behaviour of the Server. A nil config is the default
+// and behaves as if all configurations assume their default behaviour. Once passed
+// to NewServer, the configuration must not be modified.
+type Config struct {
+ // Send409Conflict controls how the Server will respond to calls to PUT on a
+ // previously existing bucket. The default is false, and corresponds to the
+ // us-east-1 s3 enpoint. Setting this value to true emulates the behaviour of
+ // all other regions.
+ // http://docs.amazonwebservices.com/AmazonS3/latest/API/ErrorResponses.html
+ Send409Conflict bool
+ // Set the host string on which to serve s3test server.
+ Host string
+}
+
+func (c *Config) send409Conflict() bool {
+ if c != nil {
+ return c.Send409Conflict
+ }
+ return false
+}
+
+// Server is a fake S3 server for testing purposes.
+// All of the data for the server is kept in memory.
+type Server struct {
+ url string
+ reqId int
+ listener net.Listener
+ mu sync.Mutex
+ buckets map[string]*bucket
+ config *Config
+}
+
+type bucket struct {
+ name string
+ acl s3.ACL
+ ctime time.Time
+ objects map[string]*object
+}
+
+type object struct {
+ name string
+ mtime time.Time
+ meta http.Header // metadata to return with requests.
+ checksum []byte // also held as Content-MD5 in meta.
+ data []byte
+}
+
+// A resource encapsulates the subject of an HTTP request.
+// The resource referred to may or may not exist
+// when the request is made.
+type resource interface {
+ put(a *action) interface{}
+ get(a *action) interface{}
+ post(a *action) interface{}
+ delete(a *action) interface{}
+}
+
+func NewServer(config *Config) (*Server, error) {
+ if config.Host == "" {
+ config.Host = "localhost:0"
+ }
+
+ l, err := net.Listen("tcp", config.Host)
+ if err != nil {
+ return nil, fmt.Errorf("cannot listen on localhost: %v", err)
+ }
+ srv := &Server{
+ listener: l,
+ url: "http://" + l.Addr().String(),
+ buckets: make(map[string]*bucket),
+ config: config,
+ }
+ go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ srv.serveHTTP(w, req)
+ }))
+ return srv, nil
+}
+
+// Quit closes down the server.
+func (srv *Server) Quit() {
+ srv.listener.Close()
+}
+
+// URL returns a URL for the server.
+func (srv *Server) URL() string {
+ return srv.url
+}
+
+func fatalf(code int, codeStr string, errf string, a ...interface{}) {
+ panic(&s3Error{
+ statusCode: code,
+ Code: codeStr,
+ Message: fmt.Sprintf(errf, a...),
+ })
+}
+
+// serveHTTP serves the S3 protocol.
+func (srv *Server) serveHTTP(w http.ResponseWriter, req *http.Request) {
+ // ignore error from ParseForm as it's usually spurious.
+ req.ParseForm()
+
+ srv.mu.Lock()
+ defer srv.mu.Unlock()
+
+ if debug {
+ log.Printf("s3test %q %q", req.Method, req.URL)
+ }
+ a := &action{
+ srv: srv,
+ w: w,
+ req: req,
+ reqId: fmt.Sprintf("%09X", srv.reqId),
+ }
+ srv.reqId++
+
+ var r resource
+ defer func() {
+ switch err := recover().(type) {
+ case *s3Error:
+ switch r := r.(type) {
+ case objectResource:
+ err.BucketName = r.bucket.name
+ case bucketResource:
+ err.BucketName = r.name
+ }
+ err.RequestId = a.reqId
+ // TODO HostId
+ w.Header().Set("Content-Type", `xml version="1.0" encoding="UTF-8"`)
+ w.WriteHeader(err.statusCode)
+ xmlMarshal(w, err)
+ case nil:
+ default:
+ panic(err)
+ }
+ }()
+
+ r = srv.resourceForURL(req.URL)
+
+ var resp interface{}
+ switch req.Method {
+ case "PUT":
+ resp = r.put(a)
+ case "GET", "HEAD":
+ resp = r.get(a)
+ case "DELETE":
+ resp = r.delete(a)
+ case "POST":
+ resp = r.post(a)
+ default:
+ fatalf(400, "MethodNotAllowed", "unknown http request method %q", req.Method)
+ }
+ if resp != nil && req.Method != "HEAD" {
+ xmlMarshal(w, resp)
+ }
+}
+
+// xmlMarshal is the same as xml.Marshal except that
+// it panics on error. The marshalling should not fail,
+// but we want to know if it does.
+func xmlMarshal(w io.Writer, x interface{}) {
+ if err := xml.NewEncoder(w).Encode(x); err != nil {
+ panic(fmt.Errorf("error marshalling %#v: %v", x, err))
+ }
+}
+
+// In a fully implemented test server, each of these would have
+// its own resource type.
+var unimplementedBucketResourceNames = map[string]bool{
+ "acl": true,
+ "lifecycle": true,
+ "policy": true,
+ "location": true,
+ "logging": true,
+ "notification": true,
+ "versions": true,
+ "requestPayment": true,
+ "versioning": true,
+ "website": true,
+ "uploads": true,
+}
+
+var unimplementedObjectResourceNames = map[string]bool{
+ "uploadId": true,
+ "acl": true,
+ "torrent": true,
+ "uploads": true,
+}
+
+var pathRegexp = regexp.MustCompile("/(([^/]+)(/(.*))?)?")
+
+// resourceForURL returns a resource object for the given URL.
+func (srv *Server) resourceForURL(u *url.URL) (r resource) {
+ m := pathRegexp.FindStringSubmatch(u.Path)
+ if m == nil {
+ fatalf(404, "InvalidURI", "Couldn't parse the specified URI")
+ }
+ bucketName := m[2]
+ objectName := m[4]
+ if bucketName == "" {
+ return nullResource{} // root
+ }
+ b := bucketResource{
+ name: bucketName,
+ bucket: srv.buckets[bucketName],
+ }
+ q := u.Query()
+ if objectName == "" {
+ for name := range q {
+ if unimplementedBucketResourceNames[name] {
+ return nullResource{}
+ }
+ }
+ return b
+
+ }
+ if b.bucket == nil {
+ fatalf(404, "NoSuchBucket", "The specified bucket does not exist")
+ }
+ objr := objectResource{
+ name: objectName,
+ version: q.Get("versionId"),
+ bucket: b.bucket,
+ }
+ for name := range q {
+ if unimplementedObjectResourceNames[name] {
+ return nullResource{}
+ }
+ }
+ if obj := objr.bucket.objects[objr.name]; obj != nil {
+ objr.object = obj
+ }
+ return objr
+}
+
+// nullResource has error stubs for all resource methods.
+type nullResource struct{}
+
+func notAllowed() interface{} {
+ fatalf(400, "MethodNotAllowed", "The specified method is not allowed against this resource")
+ return nil
+}
+
+func (nullResource) put(a *action) interface{} { return notAllowed() }
+func (nullResource) get(a *action) interface{} { return notAllowed() }
+func (nullResource) post(a *action) interface{} { return notAllowed() }
+func (nullResource) delete(a *action) interface{} { return notAllowed() }
+
+const timeFormat = "2006-01-02T15:04:05.000Z07:00"
+
+type bucketResource struct {
+ name string
+ bucket *bucket // non-nil if the bucket already exists.
+}
+
+// GET on a bucket lists the objects in the bucket.
+// http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGET.html
+func (r bucketResource) get(a *action) interface{} {
+ if r.bucket == nil {
+ fatalf(404, "NoSuchBucket", "The specified bucket does not exist")
+ }
+ delimiter := a.req.Form.Get("delimiter")
+ marker := a.req.Form.Get("marker")
+ maxKeys := -1
+ if s := a.req.Form.Get("max-keys"); s != "" {
+ i, err := strconv.Atoi(s)
+ if err != nil || i < 0 {
+ fatalf(400, "invalid value for max-keys: %q", s)
+ }
+ maxKeys = i
+ }
+ prefix := a.req.Form.Get("prefix")
+ a.w.Header().Set("Content-Type", "application/xml")
+
+ if a.req.Method == "HEAD" {
+ return nil
+ }
+
+ var objs orderedObjects
+
+ // first get all matching objects and arrange them in alphabetical order.
+ for name, obj := range r.bucket.objects {
+ if strings.HasPrefix(name, prefix) {
+ objs = append(objs, obj)
+ }
+ }
+ sort.Sort(objs)
+
+ if maxKeys <= 0 {
+ maxKeys = 1000
+ }
+ resp := &s3.ListResp{
+ Name: r.bucket.name,
+ Prefix: prefix,
+ Delimiter: delimiter,
+ Marker: marker,
+ MaxKeys: maxKeys,
+ }
+
+ var prefixes []string
+ for _, obj := range objs {
+ if !strings.HasPrefix(obj.name, prefix) {
+ continue
+ }
+ name := obj.name
+ isPrefix := false
+ if delimiter != "" {
+ if i := strings.Index(obj.name[len(prefix):], delimiter); i >= 0 {
+ name = obj.name[:len(prefix)+i+len(delimiter)]
+ if prefixes != nil && prefixes[len(prefixes)-1] == name {
+ continue
+ }
+ isPrefix = true
+ }
+ }
+ if name <= marker {
+ continue
+ }
+ if len(resp.Contents)+len(prefixes) >= maxKeys {
+ resp.IsTruncated = true
+ break
+ }
+ if isPrefix {
+ prefixes = append(prefixes, name)
+ } else {
+ // Contents contains only keys not found in CommonPrefixes
+ resp.Contents = append(resp.Contents, obj.s3Key())
+ }
+ }
+ resp.CommonPrefixes = prefixes
+ return resp
+}
+
+// orderedObjects holds a slice of objects that can be sorted
+// by name.
+type orderedObjects []*object
+
+func (s orderedObjects) Len() int {
+ return len(s)
+}
+func (s orderedObjects) Swap(i, j int) {
+ s[i], s[j] = s[j], s[i]
+}
+func (s orderedObjects) Less(i, j int) bool {
+ return s[i].name < s[j].name
+}
+
+func (obj *object) s3Key() s3.Key {
+ return s3.Key{
+ Key: obj.name,
+ LastModified: obj.mtime.Format(timeFormat),
+ Size: int64(len(obj.data)),
+ ETag: fmt.Sprintf(`"%x"`, obj.checksum),
+ // TODO StorageClass
+ // TODO Owner
+ }
+}
+
+// DELETE on a bucket deletes the bucket if it's not empty.
+func (r bucketResource) delete(a *action) interface{} {
+ b := r.bucket
+ if b == nil {
+ fatalf(404, "NoSuchBucket", "The specified bucket does not exist")
+ }
+ if len(b.objects) > 0 {
+ fatalf(400, "BucketNotEmpty", "The bucket you tried to delete is not empty")
+ }
+ delete(a.srv.buckets, b.name)
+ return nil
+}
+
+// PUT on a bucket creates the bucket.
+// http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketPUT.html
+func (r bucketResource) put(a *action) interface{} {
+ var created bool
+ if r.bucket == nil {
+ if !validBucketName(r.name) {
+ fatalf(400, "InvalidBucketName", "The specified bucket is not valid")
+ }
+ if loc := locationConstraint(a); loc == "" {
+ fatalf(400, "InvalidRequets", "The unspecified location constraint is incompatible for the region specific endpoint this request was sent to.")
+ }
+ // TODO validate acl
+ r.bucket = &bucket{
+ name: r.name,
+ // TODO default acl
+ objects: make(map[string]*object),
+ }
+ a.srv.buckets[r.name] = r.bucket
+ created = true
+ }
+ if !created && a.srv.config.send409Conflict() {
+ fatalf(409, "BucketAlreadyOwnedByYou", "Your previous request to create the named bucket succeeded and you already own it.")
+ }
+ r.bucket.acl = s3.ACL(a.req.Header.Get("x-amz-acl"))
+ return nil
+}
+
+func (bucketResource) post(a *action) interface{} {
+ fatalf(400, "Method", "bucket POST method not available")
+ return nil
+}
+
+// validBucketName returns whether name is a valid bucket name.
+// Here are the rules, from:
+// http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/BucketRestrictions.html
+//
+// Can contain lowercase letters, numbers, periods (.), underscores (_),
+// and dashes (-). You can use uppercase letters for buckets only in the
+// US Standard region.
+//
+// Must start with a number or letter
+//
+// Must be between 3 and 255 characters long
+//
+// There's one extra rule (Must not be formatted as an IP address (e.g., 192.168.5.4)
+// but the real S3 server does not seem to check that rule, so we will not
+// check it either.
+//
+func validBucketName(name string) bool {
+ if len(name) < 3 || len(name) > 255 {
+ return false
+ }
+ r := name[0]
+ if !(r >= '0' && r <= '9' || r >= 'a' && r <= 'z') {
+ return false
+ }
+ for _, r := range name {
+ switch {
+ case r >= '0' && r <= '9':
+ case r >= 'a' && r <= 'z':
+ case r == '_' || r == '-':
+ case r == '.':
+ default:
+ return false
+ }
+ }
+ return true
+}
+
+var responseParams = map[string]bool{
+ "content-type": true,
+ "content-language": true,
+ "expires": true,
+ "cache-control": true,
+ "content-disposition": true,
+ "content-encoding": true,
+}
+
+type objectResource struct {
+ name string
+ version string
+ bucket *bucket // always non-nil.
+ object *object // may be nil.
+}
+
+// GET on an object gets the contents of the object.
+// http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectGET.html
+func (objr objectResource) get(a *action) interface{} {
+ obj := objr.object
+ if obj == nil {
+ fatalf(404, "NoSuchKey", "The specified key does not exist.")
+ }
+ h := a.w.Header()
+ // add metadata
+ for name, d := range obj.meta {
+ h[name] = d
+ }
+ // override header values in response to request parameters.
+ for name, vals := range a.req.Form {
+ if strings.HasPrefix(name, "response-") {
+ name = name[len("response-"):]
+ if !responseParams[name] {
+ continue
+ }
+ h.Set(name, vals[0])
+ }
+ }
+ if r := a.req.Header.Get("Range"); r != "" {
+ fatalf(400, "NotImplemented", "range unimplemented")
+ }
+ // TODO Last-Modified-Since
+ // TODO If-Modified-Since
+ // TODO If-Unmodified-Since
+ // TODO If-Match
+ // TODO If-None-Match
+ // TODO Connection: close ??
+ // TODO x-amz-request-id
+ h.Set("Content-Length", fmt.Sprint(len(obj.data)))
+ h.Set("ETag", hex.EncodeToString(obj.checksum))
+ h.Set("Last-Modified", obj.mtime.Format(time.RFC1123))
+ if a.req.Method == "HEAD" {
+ return nil
+ }
+ // TODO avoid holding the lock when writing data.
+ _, err := a.w.Write(obj.data)
+ if err != nil {
+ // we can't do much except just log the fact.
+ log.Printf("error writing data: %v", err)
+ }
+ return nil
+}
+
+var metaHeaders = map[string]bool{
+ "Content-MD5": true,
+ "x-amz-acl": true,
+ "Content-Type": true,
+ "Content-Encoding": true,
+ "Content-Disposition": true,
+}
+
+// PUT on an object creates the object.
+func (objr objectResource) put(a *action) interface{} {
+ // TODO Cache-Control header
+ // TODO Expires header
+ // TODO x-amz-server-side-encryption
+ // TODO x-amz-storage-class
+
+ // TODO is this correct, or should we erase all previous metadata?
+ obj := objr.object
+ if obj == nil {
+ obj = &object{
+ name: objr.name,
+ meta: make(http.Header),
+ }
+ }
+
+ var expectHash []byte
+ if c := a.req.Header.Get("Content-MD5"); c != "" {
+ var err error
+ expectHash, err = base64.StdEncoding.DecodeString(c)
+ if err != nil || len(expectHash) != md5.Size {
+ fatalf(400, "InvalidDigest", "The Content-MD5 you specified was invalid")
+ }
+ }
+ sum := md5.New()
+ // TODO avoid holding lock while reading data.
+ data, err := ioutil.ReadAll(io.TeeReader(a.req.Body, sum))
+ if err != nil {
+ fatalf(400, "TODO", "read error")
+ }
+ gotHash := sum.Sum(nil)
+ if expectHash != nil && bytes.Compare(gotHash, expectHash) != 0 {
+ fatalf(400, "BadDigest", "The Content-MD5 you specified did not match what we received")
+ }
+ if a.req.ContentLength >= 0 && int64(len(data)) != a.req.ContentLength {
+ fatalf(400, "IncompleteBody", "You did not provide the number of bytes specified by the Content-Length HTTP header")
+ }
+
+ // PUT request has been successful - save data and metadata
+ for key, values := range a.req.Header {
+ key = http.CanonicalHeaderKey(key)
+ if metaHeaders[key] || strings.HasPrefix(key, "X-Amz-Meta-") {
+ obj.meta[key] = values
+ }
+ }
+ obj.data = data
+ obj.checksum = gotHash
+ obj.mtime = time.Now()
+ objr.bucket.objects[objr.name] = obj
+
+ h := a.w.Header()
+ h.Set("ETag", fmt.Sprintf(`"%s"`, hex.EncodeToString(obj.checksum)))
+
+ return nil
+}
+
+func (objr objectResource) delete(a *action) interface{} {
+ delete(objr.bucket.objects, objr.name)
+ return nil
+}
+
+func (objr objectResource) post(a *action) interface{} {
+ fatalf(400, "MethodNotAllowed", "The specified method is not allowed against this resource")
+ return nil
+}
+
+type CreateBucketConfiguration struct {
+ LocationConstraint string
+}
+
+// locationConstraint parses the <CreateBucketConfiguration /> request body (if present).
+// If there is no body, an empty string will be returned.
+func locationConstraint(a *action) string {
+ var body bytes.Buffer
+ if _, err := io.Copy(&body, a.req.Body); err != nil {
+ fatalf(400, "InvalidRequest", err.Error())
+ }
+ if body.Len() == 0 {
+ return ""
+ }
+ var loc CreateBucketConfiguration
+ if err := xml.NewDecoder(&body).Decode(&loc); err != nil {
+ fatalf(400, "InvalidRequest", err.Error())
+ }
+ return loc.LocationConstraint
+}
diff --git a/vendor/github.com/goamz/goamz/s3/sign_test.go b/vendor/github.com/goamz/goamz/s3/sign_test.go
new file mode 100644
index 000000000..112e1ca3e
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/s3/sign_test.go
@@ -0,0 +1,132 @@
+package s3_test
+
+import (
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/s3"
+ . "gopkg.in/check.v1"
+)
+
+// S3 ReST authentication docs: http://goo.gl/G1LrK
+
+var testAuth = aws.Auth{AccessKey: "0PN5J17HBGZHT7JJ3X82", SecretKey: "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"}
+
+func (s *S) TestSignExampleObjectGet(c *C) {
+ method := "GET"
+ path := "/johnsmith/photos/puppy.jpg"
+ headers := map[string][]string{
+ "Host": {"johnsmith.s3.amazonaws.com"},
+ "Date": {"Tue, 27 Mar 2007 19:36:42 +0000"},
+ }
+ s3.Sign(testAuth, method, path, nil, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:xXjDGYUmKxnwqr5KXNPGldn5LbA="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
+
+func (s *S) TestSignExampleObjectPut(c *C) {
+ method := "PUT"
+ path := "/johnsmith/photos/puppy.jpg"
+ headers := map[string][]string{
+ "Host": {"johnsmith.s3.amazonaws.com"},
+ "Date": {"Tue, 27 Mar 2007 21:15:45 +0000"},
+ "Content-Type": {"image/jpeg"},
+ "Content-Length": {"94328"},
+ }
+ s3.Sign(testAuth, method, path, nil, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:hcicpDDvL9SsO6AkvxqmIWkmOuQ="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
+
+func (s *S) TestSignExampleList(c *C) {
+ method := "GET"
+ path := "/johnsmith/"
+ params := map[string][]string{
+ "prefix": {"photos"},
+ "max-keys": {"50"},
+ "marker": {"puppy"},
+ }
+ headers := map[string][]string{
+ "Host": {"johnsmith.s3.amazonaws.com"},
+ "Date": {"Tue, 27 Mar 2007 19:42:41 +0000"},
+ "User-Agent": {"Mozilla/5.0"},
+ }
+ s3.Sign(testAuth, method, path, params, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:jsRt/rhG+Vtp88HrYL706QhE4w4="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
+
+func (s *S) TestSignExampleFetch(c *C) {
+ method := "GET"
+ path := "/johnsmith/"
+ params := map[string][]string{
+ "acl": {""},
+ }
+ headers := map[string][]string{
+ "Host": {"johnsmith.s3.amazonaws.com"},
+ "Date": {"Tue, 27 Mar 2007 19:44:46 +0000"},
+ }
+ s3.Sign(testAuth, method, path, params, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:thdUi9VAkzhkniLj96JIrOPGi0g="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
+
+func (s *S) TestSignExampleDelete(c *C) {
+ method := "DELETE"
+ path := "/johnsmith/photos/puppy.jpg"
+ params := map[string][]string{}
+ headers := map[string][]string{
+ "Host": {"s3.amazonaws.com"},
+ "Date": {"Tue, 27 Mar 2007 21:20:27 +0000"},
+ "User-Agent": {"dotnet"},
+ "x-amz-date": {"Tue, 27 Mar 2007 21:20:26 +0000"},
+ }
+ s3.Sign(testAuth, method, path, params, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:k3nL7gH3+PadhTEVn5Ip83xlYzk="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
+
+func (s *S) TestSignExampleUpload(c *C) {
+ method := "PUT"
+ path := "/static.johnsmith.net/db-backup.dat.gz"
+ params := map[string][]string{}
+ headers := map[string][]string{
+ "Host": {"static.johnsmith.net:8080"},
+ "Date": {"Tue, 27 Mar 2007 21:06:08 +0000"},
+ "User-Agent": {"curl/7.15.5"},
+ "x-amz-acl": {"public-read"},
+ "content-type": {"application/x-download"},
+ "Content-MD5": {"4gJE4saaMU4BqNR0kLY+lw=="},
+ "X-Amz-Meta-ReviewedBy": {"joe@johnsmith.net,jane@johnsmith.net"},
+ "X-Amz-Meta-FileChecksum": {"0x02661779"},
+ "X-Amz-Meta-ChecksumAlgorithm": {"crc32"},
+ "Content-Disposition": {"attachment; filename=database.dat"},
+ "Content-Encoding": {"gzip"},
+ "Content-Length": {"5913339"},
+ }
+ s3.Sign(testAuth, method, path, params, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:C0FlOtU8Ylb9KDTpZqYkZPX91iI="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
+
+func (s *S) TestSignExampleListAllMyBuckets(c *C) {
+ method := "GET"
+ path := "/"
+ headers := map[string][]string{
+ "Host": {"s3.amazonaws.com"},
+ "Date": {"Wed, 28 Mar 2007 01:29:59 +0000"},
+ }
+ s3.Sign(testAuth, method, path, nil, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:Db+gepJSUbZKwpx1FR0DLtEYoZA="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
+
+func (s *S) TestSignExampleUnicodeKeys(c *C) {
+ method := "GET"
+ path := "/dictionary/fran%C3%A7ais/pr%c3%a9f%c3%a8re"
+ headers := map[string][]string{
+ "Host": {"s3.amazonaws.com"},
+ "Date": {"Wed, 28 Mar 2007 01:49:49 +0000"},
+ }
+ s3.Sign(testAuth, method, path, nil, headers)
+ expected := "AWS 0PN5J17HBGZHT7JJ3X82:dxhSBHoI6eVSPcXJqEghlUzZMnY="
+ c.Assert(headers["Authorization"], DeepEquals, []string{expected})
+}
diff --git a/vendor/github.com/goamz/goamz/sqs/Makefile b/vendor/github.com/goamz/goamz/sqs/Makefile
new file mode 100644
index 000000000..1219acfb9
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sqs/Makefile
@@ -0,0 +1,20 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=launchpad.net/goamz/sqs
+
+GOFILES=\
+ sqs.go\
+
+include $(GOROOT)/src/Make.pkg
+
+GOFMT=gofmt
+BADFMT=$(shell $(GOFMT) -l $(GOFILES) 2> /dev/null)
+
+gofmt: $(BADFMT)
+ @for F in $(BADFMT); do $(GOFMT) -w $$F && echo $$F; done
+
+ifneq ($(BADFMT),)
+ifneq ($(MAKECMDGOALS), gofmt)
+#$(warning WARNING: make gofmt: $(BADFMT))
+endif
+endif
diff --git a/vendor/github.com/goamz/goamz/sqs/README.md b/vendor/github.com/goamz/goamz/sqs/README.md
new file mode 100644
index 000000000..a283a4eec
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sqs/README.md
@@ -0,0 +1,38 @@
+Amazon Simple Queue Service API Client Written in Golang.
+=========================================================
+
+Merged from https://github.com/Mistobaan/sqs
+
+Installation
+------------
+
+ go get github.com/goamz/goamz/sqs
+
+Documentation
+-------------
+
+http://godoc.org/github.com/goamz/goamz/sqs
+
+
+Sample Usage
+------------
+
+ var auth = aws.Auth{
+ AccessKey: os.Getenv("AWS_ACCESS_KEY_ID"),
+ SecretKey: os.Getenv("AWS_SECRET_ACCESS_KEY"),
+ }
+
+ conn := sqs.New(auth, aws.USEast)
+
+ q, err := conn.CreateQueue(queueName)
+ if err != nil {
+ log.Fatalf(err.Error())
+ }
+
+ q.SendMessage(batch)
+
+
+Testing
+-------
+
+ go test .
diff --git a/vendor/github.com/goamz/goamz/sqs/responses_test.go b/vendor/github.com/goamz/goamz/sqs/responses_test.go
new file mode 100644
index 000000000..857fb9104
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sqs/responses_test.go
@@ -0,0 +1,196 @@
+package sqs
+
+var TestCreateQueueXmlOK = `
+<CreateQueueResponse>
+ <CreateQueueResult>
+ <QueueUrl>http://sqs.us-east-1.amazonaws.com/123456789012/testQueue</QueueUrl>
+ </CreateQueueResult>
+ <ResponseMetadata>
+ <RequestId>7a62c49f-347e-4fc4-9331-6e8e7a96aa73</RequestId>
+ </ResponseMetadata>
+</CreateQueueResponse>
+`
+
+var TestListQueuesXmlOK = `
+<ListQueuesResponse>
+ <ListQueuesResult>
+ <QueueUrl>http://sqs.us-east-1.amazonaws.com/123456789012/testQueue</QueueUrl>
+ </ListQueuesResult>
+ <ResponseMetadata>
+ <RequestId>725275ae-0b9b-4762-b238-436d7c65a1ac</RequestId>
+ </ResponseMetadata>
+</ListQueuesResponse>
+`
+
+var TestDeleteQueueXmlOK = `
+<DeleteQueueResponse>
+ <ResponseMetadata>
+ <RequestId>6fde8d1e-52cd-4581-8cd9-c512f4c64223</RequestId>
+ </ResponseMetadata>
+</DeleteQueueResponse>
+`
+
+var TestPurgeQueueXmlOK = `
+<PurgeQueueResponse>
+ <ResponseMetadata>
+ <RequestId>6fde8d1e-52cd-4581-8cd9-c512f4c64223</RequestId>
+ </ResponseMetadata>
+</PurgeQueueResponse>
+`
+
+var TestSendMessageXmlOK = `
+<SendMessageResponse>
+ <SendMessageResult>
+ <MD5OfMessageBody>fafb00f5732ab283681e124bf8747ed1</MD5OfMessageBody>
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
+ <MD5OfMessageAttributes>ba056227cfd9533dba1f72ad9816d233</MD5OfMessageAttributes>
+ </SendMessageResult>
+ <ResponseMetadata>
+ <RequestId>27daac76-34dd-47df-bd01-1f6e873584a0</RequestId>
+ </ResponseMetadata>
+</SendMessageResponse>
+`
+
+var TestSendMessageBatchXmlOk = `
+<SendMessageBatchResponse>
+<SendMessageBatchResult>
+ <SendMessageBatchResultEntry>
+ <Id>test_msg_001</Id>
+ <MessageId>0a5231c7-8bff-4955-be2e-8dc7c50a25fa</MessageId>
+ <MD5OfMessageBody>0e024d309850c78cba5eabbeff7cae71</MD5OfMessageBody>
+ </SendMessageBatchResultEntry>
+ <SendMessageBatchResultEntry>
+ <Id>test_msg_002</Id>
+ <MessageId>15ee1ed3-87e7-40c1-bdaa-2e49968ea7e9</MessageId>
+ <MD5OfMessageBody>7fb8146a82f95e0af155278f406862c2</MD5OfMessageBody>
+ </SendMessageBatchResultEntry>
+</SendMessageBatchResult>
+<ResponseMetadata>
+ <RequestId>ca1ad5d0-8271-408b-8d0f-1351bf547e74</RequestId>
+</ResponseMetadata>
+</SendMessageBatchResponse>
+`
+
+var TestReceiveMessageXmlOK = `
+<ReceiveMessageResponse>
+ <ReceiveMessageResult>
+ <Message>
+ <MessageId>5fea7756-0ea4-451a-a703-a558b933e274</MessageId>
+ <ReceiptHandle>MbZj6wDWli+JvwwJaBV+3dcjk2YW2vA3+STFFljTM8tJJg6HRG6PYSasuWXPJB+CwLj1FjgXUv1uSj1gUPAWV66FU/WeR4mq2OKpEGYWbnLmpRCJVAyeMjeU5ZBdtcQ+QEauMZc8ZRv37sIW2iJKq3M9MFx1YvV11A2x/KSbkJ0=</ReceiptHandle>
+ <MD5OfBody>fafb00f5732ab283681e124bf8747ed1</MD5OfBody>
+ <Body>This is a test message</Body>
+ <Attribute>
+ <Name>SenderId</Name>
+ <Value>195004372649</Value>
+ </Attribute>
+ <Attribute>
+ <Name>SentTimestamp</Name>
+ <Value>1238099229000</Value>
+ </Attribute>
+ <Attribute>
+ <Name>ApproximateReceiveCount</Name>
+ <Value>5</Value>
+ </Attribute>
+ <Attribute>
+ <Name>ApproximateFirstReceiveTimestamp</Name>
+ <Value>1250700979248</Value>
+ </Attribute>
+ <MessageAttribute>
+ <Name>CustomAttribute</Name>
+ <Value>
+ <DataType>String</DataType>
+ <StringValue>Testing, testing, 1, 2, 3</StringValue>
+ </Value>
+ </MessageAttribute>
+ <MessageAttribute>
+ <Name>BinaryCustomAttribute</Name>
+ <Value>
+ <DataType>Binary</DataType>
+ <BinaryValue>iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAABA0lEQVQ4T72UrQ4CMRCEewhyiiBPopBgcfAUSIICB88CDhRB8hTgsCBRyJMEdUFwZJpMs/3LHQlhVdPufJ1ut03UjyKJcR5zVc4umbW87eeqvVFBjTdJwP54D+4xGXVUCGiBxoOsJOCd9IKgRnnV8wAezrnRmwGcpKtCJ8UgJBNWLFNzVAOimyqIhElXGkQ3LmQ6fKrdqaW1cixhdKVBcEOBLEwViBugVv8B1elVuLYcoTea624drcl5LW4KTRsFhQpLtVzzQKGCh2DuHI8FvdVH7vGQKEPerHRjgegKMESsXgAgWBtu5D1a9BQWCXSrzx9BvjPPkRQR6IJcQNTRV/cvkj93DqUTWzVDIQAAAABJRU5ErkJggg==</BinaryValue>
+ </Value>
+ </MessageAttribute>
+ </Message>
+ </ReceiveMessageResult>
+<ResponseMetadata>
+ <RequestId>b6633655-283d-45b4-aee4-4e84e0ae6afa</RequestId>
+</ResponseMetadata>
+</ReceiveMessageResponse>
+`
+
+var TestChangeMessageVisibilityXmlOK = `
+<ChangeMessageVisibilityResponse>
+ <ResponseMetadata>
+ <RequestId>6a7a282a-d013-4a59-aba9-335b0fa48bed</RequestId>
+ </ResponseMetadata>
+</ChangeMessageVisibilityResponse>
+`
+
+var TestDeleteMessageBatchXmlOK = `
+<DeleteMessageBatchResponse>
+ <DeleteMessageBatchResult>
+ <DeleteMessageBatchResultEntry>
+ <Id>msg1</Id>
+ </DeleteMessageBatchResultEntry>
+ <DeleteMessageBatchResultEntry>
+ <Id>msg2</Id>
+ </DeleteMessageBatchResultEntry>
+ </DeleteMessageBatchResult>
+ <ResponseMetadata>
+ <RequestId>d6f86b7a-74d1-4439-b43f-196a1e29cd85</RequestId>
+ </ResponseMetadata>
+</DeleteMessageBatchResponse>
+`
+
+var TestDeleteMessageUsingReceiptXmlOK = `
+<DeleteMessageResponse>
+ <ResponseMetadata>
+ <RequestId>d6d86b7a-74d1-4439-b43f-196a1e29cd85</RequestId>
+ </ResponseMetadata>
+</DeleteMessageResponse>
+`
+
+var TestGetQueueAttributesXmlOK = `
+<GetQueueAttributesResponse>
+ <GetQueueAttributesResult>
+ <Attribute>
+ <Name>ReceiveMessageWaitTimeSeconds</Name>
+ <Value>2</Value>
+ </Attribute>
+ <Attribute>
+ <Name>VisibilityTimeout</Name>
+ <Value>30</Value>
+ </Attribute>
+ <Attribute>
+ <Name>ApproximateNumberOfMessages</Name>
+ <Value>0</Value>
+ </Attribute>
+ <Attribute>
+ <Name>ApproximateNumberOfMessagesNotVisible</Name>
+ <Value>0</Value>
+ </Attribute>
+ <Attribute>
+ <Name>CreatedTimestamp</Name>
+ <Value>1286771522</Value>
+ </Attribute>
+ <Attribute>
+ <Name>LastModifiedTimestamp</Name>
+ <Value>1286771522</Value>
+ </Attribute>
+ <Attribute>
+ <Name>QueueArn</Name>
+ <Value>arn:aws:sqs:us-east-1:123456789012:qfoo</Value>
+ </Attribute>
+ <Attribute>
+ <Name>MaximumMessageSize</Name>
+ <Value>8192</Value>
+ </Attribute>
+ <Attribute>
+ <Name>MessageRetentionPeriod</Name>
+ <Value>345600</Value>
+ </Attribute>
+ </GetQueueAttributesResult>
+ <ResponseMetadata>
+ <RequestId>1ea71be5-b5a2-4f9d-b85a-945d8d08cd0b</RequestId>
+ </ResponseMetadata>
+</GetQueueAttributesResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/sqs/sqs.go b/vendor/github.com/goamz/goamz/sqs/sqs.go
new file mode 100644
index 000000000..4005b1b37
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sqs/sqs.go
@@ -0,0 +1,570 @@
+//
+// gosqs - Go packages to interact with the Amazon SQS Web Services.
+//
+// depends on https://wiki.ubuntu.com/goamz
+//
+//
+// Written by Prudhvi Krishna Surapaneni <me@prudhvi.net>
+// Extended by Fabrizio Milo <mistobaan@gmail.com>
+//
+package sqs
+
+import (
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+const API_VERSION = "2012-11-05"
+
+const debug = false
+
+// The SQS type encapsulates operation with an SQS region.
+type SQS struct {
+ aws.Auth
+ aws.Region
+ private byte // Reserve the right of using private data.
+}
+
+// NewFrom Create A new SQS Client given an access and secret Key
+// region must be one of "us.east, us.west, eu.west"
+func NewFrom(accessKey, secretKey, region string) (*SQS, error) {
+
+ auth := aws.Auth{AccessKey: accessKey, SecretKey: secretKey}
+ aws_region := aws.USEast
+
+ switch region {
+ case "us.east", "us.east.1":
+ aws_region = aws.USEast
+ case "us.west", "us.west.1":
+ aws_region = aws.USWest
+ case "us.west.2":
+ aws_region = aws.USWest2
+ case "eu.west":
+ aws_region = aws.EUWest
+ case "ap.southeast", "ap.southeast.1":
+ aws_region = aws.APSoutheast
+ case "ap.southeast.2":
+ aws_region = aws.APSoutheast2
+ case "ap.northeast", "ap.northeast.1":
+ aws_region = aws.APNortheast
+ case "sa.east", "sa.east.1":
+ aws_region = aws.SAEast
+ case "cn.north", "cn.north.1":
+ aws_region = aws.CNNorth
+ default:
+ return nil, errors.New(fmt.Sprintf("Unknown/Unsupported region %s", region))
+ }
+
+ aws_sqs := New(auth, aws_region)
+ return aws_sqs, nil
+}
+
+// NewFrom Create A new SQS Client from an exisisting aws.Auth
+func New(auth aws.Auth, region aws.Region) *SQS {
+ return &SQS{auth, region, 0}
+}
+
+// Queue Reference to a Queue
+type Queue struct {
+ *SQS
+ Url string
+}
+
+type CreateQueueResponse struct {
+ QueueUrl string `xml:"CreateQueueResult>QueueUrl"`
+ ResponseMetadata ResponseMetadata
+}
+
+type GetQueueUrlResponse struct {
+ QueueUrl string `xml:"GetQueueUrlResult>QueueUrl"`
+ ResponseMetadata ResponseMetadata
+}
+
+type ListQueuesResponse struct {
+ QueueUrl []string `xml:"ListQueuesResult>QueueUrl"`
+ ResponseMetadata ResponseMetadata
+}
+
+type DeleteMessageResponse struct {
+ ResponseMetadata ResponseMetadata
+}
+
+type DeleteQueueResponse struct {
+ ResponseMetadata ResponseMetadata
+}
+
+type PurgeQueueResponse struct {
+ ResponseMetadata ResponseMetadata
+}
+
+type SendMessageResponse struct {
+ MD5 string `xml:"SendMessageResult>MD5OfMessageBody"`
+ MD5OfMessageAttributes string `xml:"SendMessageResult>MD5OfMessageAttributes"`
+ Id string `xml:"SendMessageResult>MessageId"`
+ ResponseMetadata ResponseMetadata
+}
+
+type ReceiveMessageResponse struct {
+ Messages []Message `xml:"ReceiveMessageResult>Message"`
+ ResponseMetadata ResponseMetadata
+}
+
+type Message struct {
+ MessageId string `xml:"MessageId"`
+ Body string `xml:"Body"`
+ MD5OfBody string `xml:"MD5OfBody"`
+ ReceiptHandle string `xml:"ReceiptHandle"`
+ Attribute []Attribute `xml:"Attribute"`
+ MessageAttribute []MessageAttribute `xml:"MessageAttribute"`
+ MD5OfMessageAttributes string `xml:"MD5OfMessageAttributes"`
+}
+
+type Attribute struct {
+ Name string `xml:"Name"`
+ Value string `xml:"Value"`
+}
+
+type MessageAttribute struct {
+ Name string `xml:"Name"`
+ Value MessageAttributeValue `xml:"Value"`
+}
+
+type MessageAttributeValue struct {
+ DataType string `xml:"DataType"`
+ BinaryValue []byte `xml:"BinaryValue"`
+ StringValue string `xml:"StringValue"`
+
+ // Not yet implemented (Reserved for future use)
+ BinaryListValues [][]byte `xml:"BinaryListValues"`
+ StringListValues []string `xml:"StringListValues"`
+}
+
+type ChangeMessageVisibilityResponse struct {
+ ResponseMetadata ResponseMetadata
+}
+
+type GetQueueAttributesResponse struct {
+ Attributes []Attribute `xml:"GetQueueAttributesResult>Attribute"`
+ ResponseMetadata ResponseMetadata
+}
+
+type ResponseMetadata struct {
+ RequestId string
+ BoxUsage float64
+}
+
+type Error struct {
+ StatusCode int
+ Code string
+ Message string
+ RequestId string
+}
+
+func (err *Error) Error() string {
+ if err.Code == "" {
+ return err.Message
+ }
+ return fmt.Sprintf("%s (%s)", err.Message, err.Code)
+}
+
+func (err *Error) String() string {
+ return err.Message
+}
+
+type xmlErrors struct {
+ RequestId string
+ Errors []Error `xml:"Errors>Error"`
+ Error Error
+}
+
+// CreateQueue create a queue with a specific name
+func (s *SQS) CreateQueue(queueName string) (*Queue, error) {
+ return s.CreateQueueWithTimeout(queueName, 30)
+}
+
+// CreateQueue create a queue with a specific name and a timeout
+func (s *SQS) CreateQueueWithTimeout(queueName string, timeout int) (*Queue, error) {
+ params := map[string]string{
+ "VisibilityTimeout": strconv.Itoa(timeout),
+ }
+ return s.CreateQueueWithAttributes(queueName, params)
+}
+
+func (s *SQS) CreateQueueWithAttributes(queueName string, attrs map[string]string) (q *Queue, err error) {
+ resp, err := s.newQueue(queueName, attrs)
+ if err != nil {
+ return nil, err
+ }
+ q = &Queue{s, resp.QueueUrl}
+ return
+}
+
+// GetQueue get a reference to the given quename
+func (s *SQS) GetQueue(queueName string) (*Queue, error) {
+ var q *Queue
+ resp, err := s.getQueueUrl(queueName)
+ if err != nil {
+ return q, err
+ }
+ q = &Queue{s, resp.QueueUrl}
+ return q, nil
+}
+
+func (s *SQS) QueueFromArn(queueUrl string) (q *Queue) {
+ q = &Queue{s, queueUrl}
+ return
+}
+
+func (s *SQS) getQueueUrl(queueName string) (resp *GetQueueUrlResponse, err error) {
+ resp = &GetQueueUrlResponse{}
+ params := makeParams("GetQueueUrl")
+ params["QueueName"] = queueName
+ err = s.query("", params, resp)
+ return resp, err
+}
+
+func (s *SQS) newQueue(queueName string, attrs map[string]string) (resp *CreateQueueResponse, err error) {
+ resp = &CreateQueueResponse{}
+ params := makeParams("CreateQueue")
+ params["QueueName"] = queueName
+
+ i := 1
+ for k, v := range attrs {
+ nameParam := fmt.Sprintf("Attribute.%d.Name", i)
+ valParam := fmt.Sprintf("Attribute.%d.Value", i)
+ params[nameParam] = k
+ params[valParam] = v
+ i++
+ }
+
+ err = s.query("", params, resp)
+ return
+}
+
+func (s *SQS) ListQueues(QueueNamePrefix string) (resp *ListQueuesResponse, err error) {
+ resp = &ListQueuesResponse{}
+ params := makeParams("ListQueues")
+
+ if QueueNamePrefix != "" {
+ params["QueueNamePrefix"] = QueueNamePrefix
+ }
+
+ err = s.query("", params, resp)
+ return
+}
+
+func (q *Queue) Delete() (resp *DeleteQueueResponse, err error) {
+ resp = &DeleteQueueResponse{}
+ params := makeParams("DeleteQueue")
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+func (q *Queue) Purge() (resp *PurgeQueueResponse, err error) {
+ resp = &PurgeQueueResponse{}
+ params := makeParams("PurgeQueue")
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+func (q *Queue) SendMessageWithDelay(MessageBody string, DelaySeconds int64) (resp *SendMessageResponse, err error) {
+ resp = &SendMessageResponse{}
+ params := makeParams("SendMessage")
+
+ params["MessageBody"] = MessageBody
+ params["DelaySeconds"] = strconv.Itoa(int(DelaySeconds))
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+func (q *Queue) SendMessage(MessageBody string) (resp *SendMessageResponse, err error) {
+ resp = &SendMessageResponse{}
+ params := makeParams("SendMessage")
+
+ params["MessageBody"] = MessageBody
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+func (q *Queue) SendMessageWithAttributes(MessageBody string, attrs map[string]string) (resp *SendMessageResponse, err error) {
+ resp = &SendMessageResponse{}
+ params := makeParams("SendMessage")
+
+ params["MessageBody"] = MessageBody
+
+ i := 1
+ for k, v := range attrs {
+ nameParam := fmt.Sprintf("MessageAttribute.%d.Name", i)
+ valParam := fmt.Sprintf("MessageAttribute.%d.Value.StringValue", i)
+ typeParam := fmt.Sprintf("MessageAttribute.%d.Value.DataType", i)
+ params[nameParam] = k
+ params[valParam] = v
+ params[typeParam] = "String"
+ i++
+ }
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+// ReceiveMessageWithVisibilityTimeout
+func (q *Queue) ReceiveMessageWithVisibilityTimeout(MaxNumberOfMessages, VisibilityTimeoutSec int) (*ReceiveMessageResponse, error) {
+ params := map[string]string{
+ "MaxNumberOfMessages": strconv.Itoa(MaxNumberOfMessages),
+ "VisibilityTimeout": strconv.Itoa(VisibilityTimeoutSec),
+ }
+ return q.ReceiveMessageWithParameters(params)
+}
+
+// ReceiveMessage
+func (q *Queue) ReceiveMessage(MaxNumberOfMessages int) (*ReceiveMessageResponse, error) {
+ params := map[string]string{
+ "MaxNumberOfMessages": strconv.Itoa(MaxNumberOfMessages),
+ }
+ return q.ReceiveMessageWithParameters(params)
+}
+
+func (q *Queue) ReceiveMessageWithParameters(p map[string]string) (resp *ReceiveMessageResponse, err error) {
+ resp = &ReceiveMessageResponse{}
+ params := makeParams("ReceiveMessage")
+ params["AttributeName"] = "All"
+ params["MessageAttributeNames"] = "All"
+
+ for k, v := range p {
+ params[k] = v
+ }
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+func (q *Queue) ChangeMessageVisibility(M *Message, VisibilityTimeout int) (resp *ChangeMessageVisibilityResponse, err error) {
+ resp = &ChangeMessageVisibilityResponse{}
+ params := makeParams("ChangeMessageVisibility")
+ params["VisibilityTimeout"] = strconv.Itoa(VisibilityTimeout)
+ params["ReceiptHandle"] = M.ReceiptHandle
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+func (q *Queue) GetQueueAttributes(A string) (resp *GetQueueAttributesResponse, err error) {
+ resp = &GetQueueAttributesResponse{}
+ params := makeParams("GetQueueAttributes")
+ params["AttributeName"] = A
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+func (q *Queue) DeleteMessage(M *Message) (resp *DeleteMessageResponse, err error) {
+ return q.DeleteMessageUsingReceiptHandle(M.ReceiptHandle)
+}
+
+func (q *Queue) DeleteMessageUsingReceiptHandle(receiptHandle string) (resp *DeleteMessageResponse, err error) {
+ resp = &DeleteMessageResponse{}
+ params := makeParams("DeleteMessage")
+ params["ReceiptHandle"] = receiptHandle
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+type SendMessageBatchResultEntry struct {
+ Id string `xml:"Id"`
+ MessageId string `xml:"MessageId"`
+ MD5OfMessageBody string `xml:"MD5OfMessageBody"`
+}
+
+type SendMessageBatchResponse struct {
+ SendMessageBatchResult []SendMessageBatchResultEntry `xml:"SendMessageBatchResult>SendMessageBatchResultEntry"`
+ ResponseMetadata ResponseMetadata
+}
+
+/* SendMessageBatch
+ */
+func (q *Queue) SendMessageBatch(msgList []Message) (resp *SendMessageBatchResponse, err error) {
+ resp = &SendMessageBatchResponse{}
+ params := makeParams("SendMessageBatch")
+
+ for idx, msg := range msgList {
+ count := idx + 1
+ params[fmt.Sprintf("SendMessageBatchRequestEntry.%d.Id", count)] = fmt.Sprintf("msg-%d", count)
+ params[fmt.Sprintf("SendMessageBatchRequestEntry.%d.MessageBody", count)] = msg.Body
+ }
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+/* SendMessageBatchString
+ */
+func (q *Queue) SendMessageBatchString(msgList []string) (resp *SendMessageBatchResponse, err error) {
+ resp = &SendMessageBatchResponse{}
+ params := makeParams("SendMessageBatch")
+
+ for idx, msg := range msgList {
+ count := idx + 1
+ params[fmt.Sprintf("SendMessageBatchRequestEntry.%d.Id", count)] = fmt.Sprintf("msg-%d", count)
+ params[fmt.Sprintf("SendMessageBatchRequestEntry.%d.MessageBody", count)] = msg
+ }
+
+ err = q.SQS.query(q.Url, params, resp)
+ return
+}
+
+type DeleteMessageBatchResponse struct {
+ DeleteMessageBatchResult []struct {
+ Id string
+ SenderFault bool
+ Code string
+ Message string
+ } `xml:"DeleteMessageBatchResult>DeleteMessageBatchResultEntry"`
+ ResponseMetadata ResponseMetadata
+}
+
+/* DeleteMessageBatch */
+func (q *Queue) DeleteMessageBatch(msgList []Message) (resp *DeleteMessageBatchResponse, err error) {
+ resp = &DeleteMessageBatchResponse{}
+ params := makeParams("DeleteMessageBatch")
+
+ lutMsg := make(map[string]Message)
+
+ for idx := range msgList {
+ params[fmt.Sprintf("DeleteMessageBatchRequestEntry.%d.Id", idx+1)] = msgList[idx].MessageId
+ params[fmt.Sprintf("DeleteMessageBatchRequestEntry.%d.ReceiptHandle", idx+1)] = msgList[idx].ReceiptHandle
+
+ lutMsg[string(msgList[idx].MessageId)] = msgList[idx]
+ }
+
+ err = q.SQS.query(q.Url, params, resp)
+
+ messageWithErrors := make([]Message, 0, len(msgList))
+
+ for idx := range resp.DeleteMessageBatchResult {
+ if resp.DeleteMessageBatchResult[idx].SenderFault {
+ msg, ok := lutMsg[resp.DeleteMessageBatchResult[idx].Id]
+ if ok {
+ messageWithErrors = append(messageWithErrors, msg)
+ }
+ }
+ }
+
+ if len(messageWithErrors) > 0 {
+ log.Printf("%d Message have not been sent", len(messageWithErrors))
+ }
+
+ return
+}
+
+func (s *SQS) query(queueUrl string, params map[string]string, resp interface{}) (err error) {
+ params["Version"] = API_VERSION
+ params["Timestamp"] = time.Now().In(time.UTC).Format(time.RFC3339)
+ var url_ *url.URL
+
+ switch {
+ // fully qualified queueUrl
+ case strings.HasPrefix(queueUrl, "http"):
+ url_, err = url.Parse(queueUrl)
+ // relative queueUrl
+ case strings.HasPrefix(queueUrl, "/"):
+ url_, err = url.Parse(s.Region.SQSEndpoint + queueUrl)
+ // zero-value for queueUrl
+ default:
+ url_, err = url.Parse(s.Region.SQSEndpoint)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if s.Auth.Token() != "" {
+ params["SecurityToken"] = s.Auth.Token()
+ }
+
+ var r *http.Response
+
+ var sarray []string
+ for k, v := range params {
+ sarray = append(sarray, aws.Encode(k)+"="+aws.Encode(v))
+ }
+
+ req, err := http.NewRequest("GET", fmt.Sprintf("%s?%s", url_, strings.Join(sarray, "&")), nil)
+ if err != nil {
+ return err
+ }
+ signer := aws.NewV4Signer(s.Auth, "sqs", s.Region)
+ signer.Sign(req)
+ client := http.Client{}
+ r, err = client.Do(req)
+
+ if debug {
+ log.Printf("GET ", url_.String())
+ }
+
+ if err != nil {
+ return err
+ }
+
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("DUMP:\n", string(dump))
+ }
+
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ io.Copy(ioutil.Discard, r.Body)
+
+ return err
+}
+
+func buildError(r *http.Response) error {
+ errors := xmlErrors{}
+ xml.NewDecoder(r.Body).Decode(&errors)
+ var err Error
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ } else {
+ err = errors.Error
+ }
+ err.RequestId = errors.RequestId
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
diff --git a/vendor/github.com/goamz/goamz/sqs/sqs_test.go b/vendor/github.com/goamz/goamz/sqs/sqs_test.go
new file mode 100644
index 000000000..a06433535
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sqs/sqs_test.go
@@ -0,0 +1,414 @@
+package sqs
+
+import (
+ "crypto/md5"
+ "encoding/binary"
+ "fmt"
+ "hash"
+
+ "github.com/goamz/goamz/aws"
+ . "gopkg.in/check.v1"
+)
+
+var _ = Suite(&S{})
+
+type S struct {
+ HTTPSuite
+ sqs *SQS
+}
+
+func (s *S) SetUpSuite(c *C) {
+ s.HTTPSuite.SetUpSuite(c)
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.sqs = New(auth, aws.Region{SQSEndpoint: testServer.URL})
+}
+
+func (s *S) TestCreateQueue(c *C) {
+ testServer.PrepareResponse(200, nil, TestCreateQueueXmlOK)
+
+ resp, err := s.sqs.CreateQueue("testQueue")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+ fmt.Printf("%+v\n", req)
+ c.Assert(req.Form["Action"], DeepEquals, []string{"CreateQueue"})
+ c.Assert(req.Form["Attribute.1.Name"], DeepEquals, []string{"VisibilityTimeout"})
+ c.Assert(req.Form["Attribute.1.Value"], DeepEquals, []string{"30"})
+
+ c.Assert(resp.Url, Equals, "http://sqs.us-east-1.amazonaws.com/123456789012/testQueue")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestCreateQueueWithTimeout(c *C) {
+ testServer.PrepareResponse(200, nil, TestCreateQueueXmlOK)
+
+ s.sqs.CreateQueueWithTimeout("testQueue", 180)
+ req := testServer.WaitRequest()
+
+ // TestCreateQueue() tests the core functionality, just check the timeout in this test
+ c.Assert(req.Form["Attribute.1.Name"], DeepEquals, []string{"VisibilityTimeout"})
+ c.Assert(req.Form["Attribute.1.Value"], DeepEquals, []string{"180"})
+}
+
+func (s *S) TestCreateQueueWithAttributes(c *C) {
+ testServer.PrepareResponse(200, nil, TestCreateQueueXmlOK)
+
+ s.sqs.CreateQueueWithAttributes("testQueue", map[string]string{
+ "ReceiveMessageWaitTimeSeconds": "20",
+ "VisibilityTimeout": "240",
+ })
+ req := testServer.WaitRequest()
+
+ // TestCreateQueue() tests the core functionality, just check the timeout in this test
+ var receiveMessageWaitSet bool
+ var visibilityTimeoutSet bool
+
+ for i := 1; i <= 2; i++ {
+ prefix := fmt.Sprintf("Attribute.%d.", i)
+ attr := req.FormValue(prefix + "Name")
+ value := req.FormValue(prefix + "Value")
+ switch attr {
+ case "ReceiveMessageWaitTimeSeconds":
+ c.Assert(value, DeepEquals, "20")
+ receiveMessageWaitSet = true
+ case "VisibilityTimeout":
+ c.Assert(value, DeepEquals, "240")
+ visibilityTimeoutSet = true
+ }
+ }
+ c.Assert(receiveMessageWaitSet, Equals, true)
+ c.Assert(visibilityTimeoutSet, Equals, true)
+}
+
+func (s *S) TestListQueues(c *C) {
+ testServer.PrepareResponse(200, nil, TestListQueuesXmlOK)
+
+ resp, err := s.sqs.ListQueues("")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.QueueUrl), Not(Equals), 0)
+ c.Assert(resp.QueueUrl[0], Equals, "http://sqs.us-east-1.amazonaws.com/123456789012/testQueue")
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "725275ae-0b9b-4762-b238-436d7c65a1ac")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestDeleteQueue(c *C) {
+ testServer.PrepareResponse(200, nil, TestDeleteQueueXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+ resp, err := q.Delete()
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "6fde8d1e-52cd-4581-8cd9-c512f4c64223")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestPurgeQueue(c *C) {
+ testServer.PrepareResponse(200, nil, TestPurgeQueueXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+ resp, err := q.Purge()
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "6fde8d1e-52cd-4581-8cd9-c512f4c64223")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSendMessage(c *C) {
+ testServer.PrepareResponse(200, nil, TestSendMessageXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+ resp, err := q.SendMessage("This is a test message")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ msg := "This is a test message"
+ var h hash.Hash = md5.New()
+ h.Write([]byte(msg))
+ c.Assert(resp.MD5, Equals, fmt.Sprintf("%x", h.Sum(nil)))
+ c.Assert(resp.Id, Equals, "5fea7756-0ea4-451a-a703-a558b933e274")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSendMessageRelativePath(c *C) {
+ testServer.PrepareResponse(200, nil, TestSendMessageXmlOK)
+
+ q := &Queue{s.sqs, "/123456789012/testQueue/"}
+ resp, err := q.SendMessage("This is a test message")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ msg := "This is a test message"
+ var h hash.Hash = md5.New()
+ h.Write([]byte(msg))
+ c.Assert(resp.MD5, Equals, fmt.Sprintf("%x", h.Sum(nil)))
+ c.Assert(resp.Id, Equals, "5fea7756-0ea4-451a-a703-a558b933e274")
+ c.Assert(err, IsNil)
+}
+
+func encodeMessageAttribute(str string) []byte {
+ bstr := []byte(str)
+ bs := make([]byte, 4+len(bstr))
+ binary.BigEndian.PutUint32(bs, uint32(len(bstr)))
+ copy(bs[4:len(bs)], bstr)
+ return bs
+}
+
+func (s *S) TestSendMessageWithAttributes(c *C) {
+ testServer.PrepareResponse(200, nil, TestSendMessageXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+ attrs := map[string]string{
+ "test_attribute_name_1": "test_attribute_value_1",
+ }
+ resp, err := q.SendMessageWithAttributes("This is a test message", attrs)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ var attrsHash = md5.New()
+ attrsHash.Write(encodeMessageAttribute("test_attribute_name_1"))
+ attrsHash.Write(encodeMessageAttribute("String"))
+ attrsHash.Write([]byte{1})
+ attrsHash.Write(encodeMessageAttribute("test_attribute_value_1"))
+ c.Assert(resp.MD5OfMessageAttributes, Equals, fmt.Sprintf("%x", attrsHash.Sum(nil)))
+
+ msg := "This is a test message"
+ var h hash.Hash = md5.New()
+ h.Write([]byte(msg))
+ c.Assert(resp.MD5, Equals, fmt.Sprintf("%x", h.Sum(nil)))
+ c.Assert(resp.Id, Equals, "5fea7756-0ea4-451a-a703-a558b933e274")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestSendMessageBatch(c *C) {
+ testServer.PrepareResponse(200, nil, TestSendMessageBatchXmlOk)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+
+ msgList := []string{"test message body 1", "test message body 2"}
+ resp, err := q.SendMessageBatchString(msgList)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ for idx, msg := range msgList {
+ var h hash.Hash = md5.New()
+ h.Write([]byte(msg))
+ c.Assert(resp.SendMessageBatchResult[idx].MD5OfMessageBody, Equals, fmt.Sprintf("%x", h.Sum(nil)))
+ c.Assert(err, IsNil)
+ }
+}
+
+func (s *S) TestDeleteMessageBatch(c *C) {
+ testServer.PrepareResponse(200, nil, TestDeleteMessageBatchXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+
+ msgList := []Message{*(&Message{ReceiptHandle: "gfk0T0R0waama4fVFffkjPQrrvzMrOg0fTFk2LxT33EuB8wR0ZCFgKWyXGWFoqqpCIiprQUEhir%2F5LeGPpYTLzjqLQxyQYaQALeSNHb0us3uE84uujxpBhsDkZUQkjFFkNqBXn48xlMcVhTcI3YLH%2Bd%2BIqetIOHgBCZAPx6r%2B09dWaBXei6nbK5Ygih21DCDdAwFV68Jo8DXhb3ErEfoDqx7vyvC5nCpdwqv%2BJhU%2FTNGjNN8t51v5c%2FAXvQsAzyZVNapxUrHIt4NxRhKJ72uICcxruyE8eRXlxIVNgeNP8ZEDcw7zZU1Zw%3D%3D"}),
+ *(&Message{ReceiptHandle: "gfk0T0R0waama4fVFffkjKzmhMCymjQvfTFk2LxT33G4ms5subrE0deLKWSscPU1oD3J9zgeS4PQQ3U30qOumIE6AdAv3w%2F%2Fa1IXW6AqaWhGsEPaLm3Vf6IiWqdM8u5imB%2BNTwj3tQRzOWdTOePjOjPcTpRxBtXix%2BEvwJOZUma9wabv%2BSw6ZHjwmNcVDx8dZXJhVp16Bksiox%2FGrUvrVTCJRTWTLc59oHLLF8sEkKzRmGNzTDGTiV%2BYjHfQj60FD3rVaXmzTsoNxRhKJ72uIHVMGVQiAGgB%2BqAbSqfKHDQtVOmJJgkHug%3D%3D"}),
+ }
+
+ resp, err := q.DeleteMessageBatch(msgList)
+ c.Assert(err, IsNil)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ for idx, _ := range msgList {
+ c.Assert(resp.DeleteMessageBatchResult[idx].Id, Equals, fmt.Sprintf("msg%d", idx+1))
+ }
+}
+
+func (s *S) TestDeleteMessageUsingReceiptHandle(c *C) {
+ testServer.PrepareResponse(200, nil, TestDeleteMessageUsingReceiptXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+
+ msg := &Message{ReceiptHandle: "gfk0T0R0waama4fVFffkjRQrrvzMrOg0fTFk2LxT33EuB8wR0ZCFgKWyXGWFoqqpCIiprQUEhir%2F5LeGPpYTLzjqLQxyQYaQALeSNHb0us3uE84uujxpBhsDkZUQkjFFkNqBXn48xlMcVhTcI3YLH%2Bd%2BIqetIOHgBCZAPx6r%2B09dWaBXei6nbK5Ygih21DCDdAwFV68Jo8DXhb3ErEfoDqx7vyvC5nCpdwqv%2BJhU%2FTNGjNN8t51v5c%2FAXvQsAzyZVNapxUrHIt4NxRhKJ72uICcxruyE8eRXlxIVNgeNP8ZEDcw7zZU1Zw%3D%3D"}
+
+ resp, err := q.DeleteMessageUsingReceiptHandle(msg.ReceiptHandle)
+ c.Assert(err, IsNil)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "d6d86b7a-74d1-4439-b43f-196a1e29cd85")
+}
+
+func (s *S) TestReceiveMessage(c *C) {
+ testServer.PrepareResponse(200, nil, TestReceiveMessageXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+ resp, err := q.ReceiveMessage(5)
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(len(resp.Messages), Not(Equals), 0)
+ c.Assert(resp.Messages[0].MessageId, Equals, "5fea7756-0ea4-451a-a703-a558b933e274")
+ c.Assert(resp.Messages[0].MD5OfBody, Equals, "fafb00f5732ab283681e124bf8747ed1")
+ c.Assert(resp.Messages[0].ReceiptHandle, Equals, "MbZj6wDWli+JvwwJaBV+3dcjk2YW2vA3+STFFljTM8tJJg6HRG6PYSasuWXPJB+CwLj1FjgXUv1uSj1gUPAWV66FU/WeR4mq2OKpEGYWbnLmpRCJVAyeMjeU5ZBdtcQ+QEauMZc8ZRv37sIW2iJKq3M9MFx1YvV11A2x/KSbkJ0=")
+ c.Assert(resp.Messages[0].Body, Equals, "This is a test message")
+
+ c.Assert(len(resp.Messages[0].Attribute), Not(Equals), 0)
+
+ expectedAttributeResults := []struct {
+ Name string
+ Value string
+ }{
+ {Name: "SenderId", Value: "195004372649"},
+ {Name: "SentTimestamp", Value: "1238099229000"},
+ {Name: "ApproximateReceiveCount", Value: "5"},
+ {Name: "ApproximateFirstReceiveTimestamp", Value: "1250700979248"},
+ }
+
+ for i, expected := range expectedAttributeResults {
+ c.Assert(resp.Messages[0].Attribute[i].Name, Equals, expected.Name)
+ c.Assert(resp.Messages[0].Attribute[i].Value, Equals, expected.Value)
+ }
+
+ c.Assert(len(resp.Messages[0].MessageAttribute), Not(Equals), 0)
+
+ expectedMessageAttributeResults := []struct {
+ Name string
+ Value struct {
+ DataType string
+ BinaryValue []byte
+ StringValue string
+
+ // Not yet implemented (Reserved for future use)
+ BinaryListValues [][]byte
+ StringListValues []string
+ }
+ }{
+ {
+ Name: "CustomAttribute",
+ Value: struct {
+ DataType string
+ BinaryValue []byte
+ StringValue string
+
+ // Not yet implemented (Reserved for future use)
+ BinaryListValues [][]byte
+ StringListValues []string
+ }{
+ DataType: "String",
+ StringValue: "Testing, testing, 1, 2, 3",
+ },
+ },
+ {
+ Name: "BinaryCustomAttribute",
+ Value: struct {
+ DataType string
+ BinaryValue []byte
+ StringValue string
+
+ // Not yet implemented (Reserved for future use)
+ BinaryListValues [][]byte
+ StringListValues []string
+ }{
+ DataType: "Binary",
+ BinaryValue: []byte("iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAABA0lEQVQ4T72UrQ4CMRCEewhyiiBPopBgcfAUSIICB88CDhRB8hTgsCBRyJMEdUFwZJpMs/3LHQlhVdPufJ1ut03UjyKJcR5zVc4umbW87eeqvVFBjTdJwP54D+4xGXVUCGiBxoOsJOCd9IKgRnnV8wAezrnRmwGcpKtCJ8UgJBNWLFNzVAOimyqIhElXGkQ3LmQ6fKrdqaW1cixhdKVBcEOBLEwViBugVv8B1elVuLYcoTea624drcl5LW4KTRsFhQpLtVzzQKGCh2DuHI8FvdVH7vGQKEPerHRjgegKMESsXgAgWBtu5D1a9BQWCXSrzx9BvjPPkRQR6IJcQNTRV/cvkj93DqUTWzVDIQAAAABJRU5ErkJggg=="),
+ },
+ },
+ }
+
+ for i, expected := range expectedMessageAttributeResults {
+ c.Assert(resp.Messages[0].MessageAttribute[i].Name, Equals, expected.Name)
+ c.Assert(resp.Messages[0].MessageAttribute[i].Value.DataType, Equals, expected.Value.DataType)
+ c.Assert(string(resp.Messages[0].MessageAttribute[i].Value.BinaryValue), Equals, string(expected.Value.BinaryValue))
+ c.Assert(resp.Messages[0].MessageAttribute[i].Value.StringValue, Equals, expected.Value.StringValue)
+ }
+
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestChangeMessageVisibility(c *C) {
+ testServer.PrepareResponse(200, nil, TestReceiveMessageXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+
+ resp1, err := q.ReceiveMessage(1)
+ req := testServer.WaitRequest()
+
+ testServer.PrepareResponse(200, nil, TestChangeMessageVisibilityXmlOK)
+
+ resp, err := q.ChangeMessageVisibility(&resp1.Messages[0], 50)
+ req = testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+ c.Assert(req.Header["Date"], Not(Equals), "")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "6a7a282a-d013-4a59-aba9-335b0fa48bed")
+ c.Assert(err, IsNil)
+}
+
+func (s *S) TestGetQueueAttributes(c *C) {
+ testServer.PrepareResponse(200, nil, TestGetQueueAttributesXmlOK)
+
+ q := &Queue{s.sqs, testServer.URL + "/123456789012/testQueue/"}
+
+ resp, err := q.GetQueueAttributes("All")
+ req := testServer.WaitRequest()
+
+ c.Assert(req.Method, Equals, "GET")
+ c.Assert(req.URL.Path, Equals, "/123456789012/testQueue/")
+
+ c.Assert(resp.ResponseMetadata.RequestId, Equals, "1ea71be5-b5a2-4f9d-b85a-945d8d08cd0b")
+
+ c.Assert(len(resp.Attributes), Equals, 9)
+
+ expectedResults := []struct {
+ Name string
+ Value string
+ }{
+ {Name: "ReceiveMessageWaitTimeSeconds", Value: "2"},
+ {Name: "VisibilityTimeout", Value: "30"},
+ {Name: "ApproximateNumberOfMessages", Value: "0"},
+ {Name: "ApproximateNumberOfMessagesNotVisible", Value: "0"},
+ {Name: "CreatedTimestamp", Value: "1286771522"},
+ {Name: "LastModifiedTimestamp", Value: "1286771522"},
+ {Name: "QueueArn", Value: "arn:aws:sqs:us-east-1:123456789012:qfoo"},
+ {Name: "MaximumMessageSize", Value: "8192"},
+ {Name: "MessageRetentionPeriod", Value: "345600"},
+ }
+
+ for i, expected := range expectedResults {
+ c.Assert(resp.Attributes[i].Name, Equals, expected.Name)
+ c.Assert(resp.Attributes[i].Value, Equals, expected.Value)
+ }
+
+ c.Assert(err, IsNil)
+}
diff --git a/vendor/github.com/goamz/goamz/sqs/suite_test.go b/vendor/github.com/goamz/goamz/sqs/suite_test.go
new file mode 100644
index 000000000..8de1bc04f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sqs/suite_test.go
@@ -0,0 +1,145 @@
+package sqs
+
+import (
+ "flag"
+ "fmt"
+ "net/http"
+ "net/url"
+ "os"
+ "testing"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var integration = flag.Bool("i", false, "Enable integration tests")
+
+type SuiteI struct {
+ auth aws.Auth
+}
+
+func (s *SuiteI) SetUpSuite(c *C) {
+ if !*integration {
+ c.Skip("Integration tests not enabled (-i flag)")
+ }
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ c.Fatal(err.Error())
+ }
+ s.auth = auth
+}
+
+type HTTPSuite struct{}
+
+var testServer = NewTestHTTPServer("http://localhost:4455", 5e9)
+
+func (s *HTTPSuite) SetUpSuite(c *C) {
+ testServer.Start()
+}
+
+func (s *HTTPSuite) TearDownTest(c *C) {
+ testServer.FlushRequests()
+}
+
+type TestHTTPServer struct {
+ URL string
+ Timeout time.Duration
+ started bool
+ request chan *http.Request
+ response chan *testResponse
+ pending chan bool
+}
+
+type testResponse struct {
+ Status int
+ Headers map[string]string
+ Body string
+}
+
+func NewTestHTTPServer(url string, timeout time.Duration) *TestHTTPServer {
+ return &TestHTTPServer{URL: url, Timeout: timeout}
+}
+
+func (s *TestHTTPServer) Start() {
+ if s.started {
+ return
+ }
+ s.started = true
+
+ s.request = make(chan *http.Request, 64)
+ s.response = make(chan *testResponse, 64)
+ s.pending = make(chan bool, 64)
+
+ url, _ := url.Parse(s.URL)
+ go func() {
+ err := http.ListenAndServe(url.Host, s)
+ if err != nil {
+ panic(err)
+ }
+ }()
+
+ s.PrepareResponse(202, nil, "Nothing.")
+ for {
+ // Wait for it to be up.
+ resp, err := http.Get(s.URL)
+ if err == nil && resp.StatusCode == 202 {
+ break
+ }
+ fmt.Fprintf(os.Stderr, "\nWaiting for fake server to be up... ")
+ time.Sleep(1e8)
+ }
+ fmt.Fprintf(os.Stderr, "done\n\n")
+ s.WaitRequest() // Consume dummy request.
+}
+
+// FlushRequests discards requests which were not yet consumed by WaitRequest.
+func (s *TestHTTPServer) FlushRequests() {
+ for {
+ select {
+ case <-s.request:
+ default:
+ return
+ }
+ }
+}
+
+func (s *TestHTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ s.request <- req
+ var resp *testResponse
+ select {
+ case resp = <-s.response:
+ case <-time.After(s.Timeout):
+ fmt.Fprintf(os.Stderr, "ERROR: Timeout waiting for test to provide response\n")
+ resp = &testResponse{500, nil, ""}
+ }
+ if resp.Headers != nil {
+ h := w.Header()
+ for k, v := range resp.Headers {
+ h.Set(k, v)
+ }
+ }
+ if resp.Status != 0 {
+ w.WriteHeader(resp.Status)
+ }
+ w.Write([]byte(resp.Body))
+}
+
+func (s *TestHTTPServer) WaitRequest() *http.Request {
+ select {
+ case req := <-s.request:
+ req.ParseForm()
+ return req
+ case <-time.After(s.Timeout):
+ panic("Timeout waiting for goamz request")
+ }
+ panic("unreached")
+}
+
+func (s *TestHTTPServer) PrepareResponse(status int, headers map[string]string, body string) {
+ s.response <- &testResponse{status, headers, body}
+}
diff --git a/vendor/github.com/goamz/goamz/sts/responses_test.go b/vendor/github.com/goamz/goamz/sts/responses_test.go
new file mode 100644
index 000000000..b25f495e2
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sts/responses_test.go
@@ -0,0 +1,84 @@
+package sts_test
+
+var AssumeRoleResponse = `
+<AssumeRoleResponse xmlns="https://sts.amazonaws.com/doc/
+2011-06-15/">
+ <AssumeRoleResult>
+ <Credentials>
+ <SessionToken>
+ AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQW
+ LWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGd
+ QrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU
+ 9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz
+ +scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
+ </SessionToken>
+ <SecretAccessKey>
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ </SecretAccessKey>
+ <Expiration>2011-07-15T23:28:33.359Z</Expiration>
+ <AccessKeyId>AKIAIOSFODNN7EXAMPLE</AccessKeyId>
+ </Credentials>
+ <AssumedRoleUser>
+ <Arn>arn:aws:sts::123456789012:assumed-role/demo/Bob</Arn>
+ <AssumedRoleId>ARO123EXAMPLE123:Bob</AssumedRoleId>
+ </AssumedRoleUser>
+ <PackedPolicySize>6</PackedPolicySize>
+ </AssumeRoleResult>
+ <ResponseMetadata>
+ <RequestId>c6104cbe-af31-11e0-8154-cbc7ccf896c7</RequestId>
+ </ResponseMetadata>
+</AssumeRoleResponse>
+`
+
+var GetFederationTokenResponse = `
+<GetFederationTokenResponse xmlns="https://sts.amazonaws.com/doc/
+2011-06-15/">
+ <GetFederationTokenResult>
+ <Credentials>
+ <SessionToken>
+ AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQW
+ LWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGd
+ QrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU
+ 9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz
+ +scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
+ </SessionToken>
+ <SecretAccessKey>
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ </SecretAccessKey>
+ <Expiration>2011-07-15T23:28:33.359Z</Expiration>
+ <AccessKeyId>AKIAIOSFODNN7EXAMPLE</AccessKeyId>
+ </Credentials>
+ <FederatedUser>
+ <Arn>arn:aws:sts::123456789012:federated-user/Bob</Arn>
+ <FederatedUserId>123456789012:Bob</FederatedUserId>
+ </FederatedUser>
+ <PackedPolicySize>6</PackedPolicySize>
+ </GetFederationTokenResult>
+ <ResponseMetadata>
+ <RequestId>c6104cbe-af31-11e0-8154-cbc7ccf896c7</RequestId>
+ </ResponseMetadata>
+</GetFederationTokenResponse>
+`
+
+var GetSessionTokenResponse = `
+<GetSessionTokenResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
+ <GetSessionTokenResult>
+ <Credentials>
+ <SessionToken>
+ AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/L
+ To6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3z
+ rkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtp
+ Z3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE
+ </SessionToken>
+ <SecretAccessKey>
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ </SecretAccessKey>
+ <Expiration>2011-07-11T19:55:29.611Z</Expiration>
+ <AccessKeyId>AKIAIOSFODNN7EXAMPLE</AccessKeyId>
+ </Credentials>
+ </GetSessionTokenResult>
+ <ResponseMetadata>
+ <RequestId>58c5dbae-abef-11e0-8cfe-09039844ac7d</RequestId>
+ </ResponseMetadata>
+</GetSessionTokenResponse>
+`
diff --git a/vendor/github.com/goamz/goamz/sts/sts.go b/vendor/github.com/goamz/goamz/sts/sts.go
new file mode 100644
index 000000000..973969223
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sts/sts.go
@@ -0,0 +1,273 @@
+//
+// sts: This package provides types and functions to interact with the AWS STS API
+//
+// Depends on https://github.com/goamz/goamz
+//
+
+package sts
+
+import (
+ "encoding/xml"
+ "fmt"
+ "log"
+ "net/http"
+ "net/http/httputil"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/goamz/goamz/aws"
+)
+
+// The STS type encapsulates operations within a specific EC2 region.
+type STS struct {
+ aws.Auth
+ aws.Region
+ private byte // Reserve the right of using private data.
+}
+
+// New creates a new STS Client.
+// We can only use us-east for region because AWS..
+func New(auth aws.Auth, region aws.Region) *STS {
+ // Make sure we can run the package tests
+ if region.Name == "" {
+ return &STS{auth, region, 0}
+ }
+ return &STS{auth, aws.Regions["us-east-1"], 0}
+}
+
+const debug = false
+
+// ----------------------------------------------------------------------------
+// Request dispatching logic.
+
+// Error encapsulates an error returned by the AWS STS API.
+//
+// See http://goo.gl/zDZbuQ for more details.
+type Error struct {
+ // HTTP status code (200, 403, ...)
+ StatusCode int
+ // STS error code
+ Code string
+ // The human-oriented error message
+ Message string
+ RequestId string `xml:"RequestID"`
+}
+
+func (err *Error) Error() string {
+ if err.Code == "" {
+ return err.Message
+ }
+
+ return fmt.Sprintf("%s (%s)", err.Message, err.Code)
+}
+
+type xmlErrors struct {
+ RequestId string `xml:"RequestId"`
+ Errors []Error `xml:"Error"`
+}
+
+func (sts *STS) query(params map[string]string, resp interface{}) error {
+ params["Version"] = "2011-06-15"
+
+ data := strings.NewReader(multimap(params).Encode())
+
+ hreq, err := http.NewRequest("POST", sts.Region.STSEndpoint+"/", data)
+ if err != nil {
+ return err
+ }
+
+ hreq.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
+
+ token := sts.Auth.Token()
+ if token != "" {
+ hreq.Header.Set("X-Amz-Security-Token", token)
+ }
+
+ signer := aws.NewV4Signer(sts.Auth, "sts", sts.Region)
+ signer.Sign(hreq)
+
+ if debug {
+ log.Printf("%v -> {\n", hreq)
+ }
+ r, err := http.DefaultClient.Do(hreq)
+
+ if err != nil {
+ log.Printf("Error calling Amazon")
+ return err
+ }
+
+ defer r.Body.Close()
+
+ if debug {
+ dump, _ := httputil.DumpResponse(r, true)
+ log.Printf("response:\n")
+ log.Printf("%v\n}\n", string(dump))
+ }
+ if r.StatusCode != 200 {
+ return buildError(r)
+ }
+ err = xml.NewDecoder(r.Body).Decode(resp)
+ return err
+}
+
+func buildError(r *http.Response) error {
+ var (
+ err Error
+ errors xmlErrors
+ )
+ xml.NewDecoder(r.Body).Decode(&errors)
+ if len(errors.Errors) > 0 {
+ err = errors.Errors[0]
+ }
+
+ err.RequestId = errors.RequestId
+ err.StatusCode = r.StatusCode
+ if err.Message == "" {
+ err.Message = r.Status
+ }
+ return &err
+}
+
+func makeParams(action string) map[string]string {
+ params := make(map[string]string)
+ params["Action"] = action
+ return params
+}
+
+func multimap(p map[string]string) url.Values {
+ q := make(url.Values, len(p))
+ for k, v := range p {
+ q[k] = []string{v}
+ }
+ return q
+}
+
+// options for the AssumeRole function
+//
+// See http://goo.gl/Ld6Dbk for details
+type AssumeRoleParams struct {
+ DurationSeconds int
+ ExternalId string
+ Policy string
+ RoleArn string
+ RoleSessionName string
+}
+
+type AssumedRoleUser struct {
+ Arn string `xml:"Arn"`
+ AssumedRoleId string `xml:"AssumedRoleId"`
+}
+
+type Credentials struct {
+ AccessKeyId string `xml:"AccessKeyId"`
+ Expiration time.Time `xml:"Expiration"`
+ SecretAccessKey string `xml:"SecretAccessKey"`
+ SessionToken string `xml:"SessionToken"`
+}
+
+type AssumeRoleResult struct {
+ AssumedRoleUser AssumedRoleUser `xml:"AssumeRoleResult>AssumedRoleUser"`
+ Credentials Credentials `xml:"AssumeRoleResult>Credentials"`
+ PackedPolicySize int `xml:"AssumeRoleResult>PackedPolicySize"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// AssumeRole assumes the specified role
+//
+// See http://goo.gl/zDZbuQ for more details.
+func (sts *STS) AssumeRole(options *AssumeRoleParams) (resp *AssumeRoleResult, err error) {
+ params := makeParams("AssumeRole")
+
+ params["RoleArn"] = options.RoleArn
+ params["RoleSessionName"] = options.RoleSessionName
+
+ if options.DurationSeconds != 0 {
+ params["DurationSeconds"] = strconv.Itoa(options.DurationSeconds)
+ }
+ if options.ExternalId != "" {
+ params["ExternalId"] = options.ExternalId
+ }
+ if options.Policy != "" {
+ params["Policy"] = options.Policy
+ }
+
+ resp = new(AssumeRoleResult)
+ if err := sts.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// FederatedUser presents dentifiers for the federated user that is associated with the credentials.
+//
+// See http://goo.gl/uPtr7V for more details
+type FederatedUser struct {
+ Arn string `xml:"Arn"`
+ FederatedUserId string `xml:"FederatedUserId"`
+}
+
+// GetFederationToken wraps GetFederationToken response
+//
+// See http://goo.gl/Iujjeg for more details
+type GetFederationTokenResult struct {
+ Credentials Credentials `xml:"GetFederationTokenResult>Credentials"`
+ FederatedUser FederatedUser `xml:"GetFederationTokenResult>FederatedUser"`
+ PackedPolicySize int `xml:"GetFederationTokenResult>PackedPolicySize"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// GetFederationToken returns a set of temporary credentials for an AWS account or IAM user
+//
+// See http://goo.gl/Iujjeg for more details
+func (sts *STS) GetFederationToken(name, policy string, durationSeconds int) (
+ resp *GetFederationTokenResult, err error) {
+ params := makeParams("GetFederationToken")
+ params["Name"] = name
+
+ if durationSeconds != 0 {
+ params["DurationSeconds"] = strconv.Itoa(durationSeconds)
+ }
+ if policy != "" {
+ params["Policy"] = policy
+ }
+
+ resp = new(GetFederationTokenResult)
+ if err := sts.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
+
+// GetSessionToken wraps GetSessionToken response
+//
+// See http://goo.gl/v8s5Y for more details
+type GetSessionTokenResult struct {
+ Credentials Credentials `xml:"GetSessionTokenResult>Credentials"`
+ RequestId string `xml:"ResponseMetadata>RequestId"`
+}
+
+// GetSessionToken returns a set of temporary credentials for an AWS account or IAM user
+//
+// See http://goo.gl/v8s5Y for more details
+func (sts *STS) GetSessionToken(durationSeconds int, serialnNumber, tokenCode string) (
+ resp *GetSessionTokenResult, err error) {
+ params := makeParams("GetSessionToken")
+
+ if durationSeconds != 0 {
+ params["DurationSeconds"] = strconv.Itoa(durationSeconds)
+ }
+ if serialnNumber != "" {
+ params["SerialNumber"] = serialnNumber
+ }
+ if tokenCode != "" {
+ params["TokenCode"] = tokenCode
+ }
+
+ resp = new(GetSessionTokenResult)
+ if err := sts.query(params, resp); err != nil {
+ return nil, err
+ }
+ return resp, nil
+}
diff --git a/vendor/github.com/goamz/goamz/sts/sts_test.go b/vendor/github.com/goamz/goamz/sts/sts_test.go
new file mode 100644
index 000000000..354c6272f
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/sts/sts_test.go
@@ -0,0 +1,151 @@
+package sts_test
+
+import (
+ "testing"
+ "time"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/goamz/goamz/aws"
+ "github.com/goamz/goamz/sts"
+ "github.com/goamz/goamz/testutil"
+)
+
+func Test(t *testing.T) {
+ TestingT(t)
+}
+
+var _ = Suite(&S{})
+
+type S struct {
+ sts *sts.STS
+}
+
+var testServer = testutil.NewHTTPServer()
+
+var mockTest bool
+
+func (s *S) SetUpSuite(c *C) {
+ testServer.Start()
+ auth := aws.Auth{AccessKey: "abc", SecretKey: "123"}
+ s.sts = sts.New(auth, aws.Region{STSEndpoint: testServer.URL})
+}
+
+func (s *S) TearDownTest(c *C) {
+ testServer.Flush()
+}
+
+func (s *S) TestAssumeRole(c *C) {
+ testServer.Response(200, nil, AssumeRoleResponse)
+ request := &sts.AssumeRoleParams{
+ DurationSeconds: 3600,
+ ExternalId: "123ABC",
+ Policy: `{"Version":"2012-10-17","Statement":[{"Sid":"Stmt1","Effect":"Allow","Action":"s3:*","Resource":"*"}]}`,
+ RoleArn: "arn:aws:iam::123456789012:role/demo",
+ RoleSessionName: "Bob",
+ }
+ resp, err := s.sts.AssumeRole(request)
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2011-06-15")
+ c.Assert(values.Get("Action"), Equals, "AssumeRole")
+ c.Assert(values.Get("DurationSeconds"), Equals, "3600")
+ c.Assert(values.Get("ExternalId"), Equals, "123ABC")
+ c.Assert(values.Get("Policy"), Equals, `{"Version":"2012-10-17","Statement":[{"Sid":"Stmt1","Effect":"Allow","Action":"s3:*","Resource":"*"}]}`)
+ c.Assert(values.Get("RoleArn"), Equals, "arn:aws:iam::123456789012:role/demo")
+ c.Assert(values.Get("RoleSessionName"), Equals, "Bob")
+ // Response test
+ exp, _ := time.Parse(time.RFC3339, "2011-07-15T23:28:33.359Z")
+ c.Assert(resp.RequestId, Equals, "c6104cbe-af31-11e0-8154-cbc7ccf896c7")
+ c.Assert(resp.PackedPolicySize, Equals, 6)
+ c.Assert(resp.AssumedRoleUser, DeepEquals, sts.AssumedRoleUser{
+ Arn: "arn:aws:sts::123456789012:assumed-role/demo/Bob",
+ AssumedRoleId: "ARO123EXAMPLE123:Bob",
+ })
+ c.Assert(resp.Credentials, DeepEquals, sts.Credentials{
+ SessionToken: `
+ AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQW
+ LWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGd
+ QrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU
+ 9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz
+ +scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
+ `,
+ SecretAccessKey: `
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ `,
+ AccessKeyId: "AKIAIOSFODNN7EXAMPLE",
+ Expiration: exp,
+ })
+
+}
+
+func (s *S) TestGetFederationToken(c *C) {
+ testServer.Response(200, nil, GetFederationTokenResponse)
+ resp, err := s.sts.GetFederationToken(
+ "Bob",
+ `{"Version":"2012-10-17","Statement":[{"Sid":"Stmt1","Effect":"Allow","Action":"s3:*","Resource":"*"}]}`,
+ 3600,
+ )
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2011-06-15")
+ c.Assert(values.Get("Action"), Equals, "GetFederationToken")
+ c.Assert(values.Get("DurationSeconds"), Equals, "3600")
+ c.Assert(values.Get("Policy"), Equals, `{"Version":"2012-10-17","Statement":[{"Sid":"Stmt1","Effect":"Allow","Action":"s3:*","Resource":"*"}]}`)
+ c.Assert(values.Get("Name"), Equals, "Bob")
+ // Response test
+ exp, _ := time.Parse(time.RFC3339, "2011-07-15T23:28:33.359Z")
+ c.Assert(resp.RequestId, Equals, "c6104cbe-af31-11e0-8154-cbc7ccf896c7")
+ c.Assert(resp.PackedPolicySize, Equals, 6)
+ c.Assert(resp.FederatedUser, DeepEquals, sts.FederatedUser{
+ Arn: "arn:aws:sts::123456789012:federated-user/Bob",
+ FederatedUserId: "123456789012:Bob",
+ })
+ c.Assert(resp.Credentials, DeepEquals, sts.Credentials{
+ SessionToken: `
+ AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQW
+ LWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGd
+ QrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU
+ 9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz
+ +scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==
+ `,
+ SecretAccessKey: `
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ `,
+ AccessKeyId: "AKIAIOSFODNN7EXAMPLE",
+ Expiration: exp,
+ })
+
+}
+
+func (s *S) TestGetSessionToken(c *C) {
+ testServer.Response(200, nil, GetSessionTokenResponse)
+ resp, err := s.sts.GetSessionToken(3600, "YourMFADeviceSerialNumber", "123456")
+ c.Assert(err, IsNil)
+ values := testServer.WaitRequest().PostForm
+ // Post request test
+ c.Assert(values.Get("Version"), Equals, "2011-06-15")
+ c.Assert(values.Get("Action"), Equals, "GetSessionToken")
+ c.Assert(values.Get("DurationSeconds"), Equals, "3600")
+ c.Assert(values.Get("SerialNumber"), Equals, "YourMFADeviceSerialNumber")
+ c.Assert(values.Get("TokenCode"), Equals, "123456")
+ // Response test
+ exp, _ := time.Parse(time.RFC3339, "2011-07-11T19:55:29.611Z")
+ c.Assert(resp.RequestId, Equals, "58c5dbae-abef-11e0-8cfe-09039844ac7d")
+ c.Assert(resp.Credentials, DeepEquals, sts.Credentials{
+ SessionToken: `
+ AQoEXAMPLEH4aoAH0gNCAPyJxz4BlCFFxWNE1OPTgk5TthT+FvwqnKwRcOIfrRh3c/L
+ To6UDdyJwOOvEVPvLXCrrrUtdnniCEXAMPLE/IvU1dYUg2RVAJBanLiHb4IgRmpRV3z
+ rkuWJOgQs8IZZaIv2BXIa2R4OlgkBN9bkUDNCJiBeb/AXlzBBko7b15fjrBs2+cTQtp
+ Z3CYWFXG8C5zqx37wnOE49mRl/+OtkIKGO7fAE
+ `,
+ SecretAccessKey: `
+ wJalrXUtnFEMI/K7MDENG/bPxRfiCYzEXAMPLEKEY
+ `,
+ AccessKeyId: "AKIAIOSFODNN7EXAMPLE",
+ Expiration: exp,
+ })
+
+}
diff --git a/vendor/github.com/goamz/goamz/testutil/http.go b/vendor/github.com/goamz/goamz/testutil/http.go
new file mode 100644
index 000000000..ccc570cdd
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/testutil/http.go
@@ -0,0 +1,180 @@
+package testutil
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "time"
+)
+
+type HTTPServer struct {
+ URL string
+ Timeout time.Duration
+ started bool
+ request chan *http.Request
+ response chan ResponseFunc
+}
+
+type Response struct {
+ Status int
+ Headers map[string]string
+ Body string
+}
+
+var DefaultClient = &http.Client{
+ Transport: &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
+ },
+}
+
+func NewHTTPServer() *HTTPServer {
+ return &HTTPServer{URL: "http://localhost:4444", Timeout: 5 * time.Second}
+}
+
+type ResponseFunc func(path string) Response
+
+func (s *HTTPServer) Start() {
+ if s.started {
+ return
+ }
+ s.started = true
+ s.request = make(chan *http.Request, 1024)
+ s.response = make(chan ResponseFunc, 1024)
+ u, err := url.Parse(s.URL)
+ if err != nil {
+ panic(err)
+ }
+ l, err := net.Listen("tcp", u.Host)
+ if err != nil {
+ panic(err)
+ }
+ go http.Serve(l, s)
+
+ s.Response(203, nil, "")
+ for {
+ // Wait for it to be up.
+ resp, err := http.Get(s.URL)
+ if err == nil && resp.StatusCode == 203 {
+ break
+ }
+ time.Sleep(1e8)
+ }
+ s.WaitRequest() // Consume dummy request.
+}
+
+// Flush discards all pending requests and responses.
+func (s *HTTPServer) Flush() {
+ for {
+ select {
+ case <-s.request:
+ case <-s.response:
+ default:
+ return
+ }
+ }
+}
+
+func body(req *http.Request) string {
+ data, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ panic(err)
+ }
+ return string(data)
+}
+
+func (s *HTTPServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ req.ParseMultipartForm(1e6)
+ data, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ panic(err)
+ }
+ req.Body = ioutil.NopCloser(bytes.NewBuffer(data))
+ s.request <- req
+ var resp Response
+ select {
+ case respFunc := <-s.response:
+ resp = respFunc(req.URL.Path)
+ case <-time.After(s.Timeout):
+ const msg = "ERROR: Timeout waiting for test to prepare a response\n"
+ fmt.Fprintf(os.Stderr, msg)
+ resp = Response{500, nil, msg}
+ }
+ if resp.Headers != nil {
+ h := w.Header()
+ for k, v := range resp.Headers {
+ h.Set(k, v)
+ }
+ }
+ if resp.Status != 0 {
+ w.WriteHeader(resp.Status)
+ }
+ w.Write([]byte(resp.Body))
+}
+
+// WaitRequests returns the next n requests made to the http server from
+// the queue. If not enough requests were previously made, it waits until
+// the timeout value for them to be made.
+func (s *HTTPServer) WaitRequests(n int) []*http.Request {
+ reqs := make([]*http.Request, 0, n)
+ for i := 0; i < n; i++ {
+ select {
+ case req := <-s.request:
+ reqs = append(reqs, req)
+ case <-time.After(s.Timeout):
+ panic("Timeout waiting for request")
+ }
+ }
+ return reqs
+}
+
+// WaitRequest returns the next request made to the http server from
+// the queue. If no requests were previously made, it waits until the
+// timeout value for one to be made.
+func (s *HTTPServer) WaitRequest() *http.Request {
+ return s.WaitRequests(1)[0]
+}
+
+// ResponseFunc prepares the test server to respond the following n
+// requests using f to build each response.
+func (s *HTTPServer) ResponseFunc(n int, f ResponseFunc) {
+ for i := 0; i < n; i++ {
+ s.response <- f
+ }
+}
+
+// ResponseMap maps request paths to responses.
+type ResponseMap map[string]Response
+
+// ResponseMap prepares the test server to respond the following n
+// requests using the m to obtain the responses.
+func (s *HTTPServer) ResponseMap(n int, m ResponseMap) {
+ f := func(path string) Response {
+ for rpath, resp := range m {
+ if rpath == path {
+ return resp
+ }
+ }
+ body := "Path not found in response map: " + path
+ return Response{Status: 500, Body: body}
+ }
+ s.ResponseFunc(n, f)
+}
+
+// Responses prepares the test server to respond the following n requests
+// using the provided response parameters.
+func (s *HTTPServer) Responses(n int, status int, headers map[string]string, body string) {
+ f := func(path string) Response {
+ return Response{status, headers, body}
+ }
+ s.ResponseFunc(n, f)
+}
+
+// Response prepares the test server to respond the following request
+// using the provided response parameters.
+func (s *HTTPServer) Response(status int, headers map[string]string, body string) {
+ s.Responses(1, status, headers, body)
+}
diff --git a/vendor/github.com/goamz/goamz/testutil/suite.go b/vendor/github.com/goamz/goamz/testutil/suite.go
new file mode 100644
index 000000000..f4519aa4e
--- /dev/null
+++ b/vendor/github.com/goamz/goamz/testutil/suite.go
@@ -0,0 +1,31 @@
+package testutil
+
+import (
+ "flag"
+
+ "github.com/goamz/goamz/aws"
+ . "gopkg.in/check.v1"
+)
+
+// Amazon must be used by all tested packages to determine whether to
+// run functional tests against the real AWS servers.
+var Amazon bool
+
+func init() {
+ flag.BoolVar(&Amazon, "amazon", false, "Enable tests against amazon server")
+}
+
+type LiveSuite struct {
+ auth aws.Auth
+}
+
+func (s *LiveSuite) SetUpSuite(c *C) {
+ if !Amazon {
+ c.Skip("amazon tests not enabled (-amazon flag)")
+ }
+ auth, err := aws.EnvAuth()
+ if err != nil {
+ c.Fatal(err.Error())
+ }
+ s.auth = auth
+}
diff --git a/vendor/github.com/golang/freetype/cmd/print-glyph-points/main.c b/vendor/github.com/golang/freetype/cmd/print-glyph-points/main.c
new file mode 100644
index 000000000..6e821e892
--- /dev/null
+++ b/vendor/github.com/golang/freetype/cmd/print-glyph-points/main.c
@@ -0,0 +1,87 @@
+/*
+gcc main.c -I/usr/include/freetype2 -lfreetype && ./a.out 12 ../../testdata/luxisr.ttf with_hinting
+*/
+
+#include <stdio.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+void usage(char** argv) {
+ fprintf(stderr, "usage: %s font_size font_file [with_hinting|sans_hinting]\n", argv[0]);
+}
+
+int main(int argc, char** argv) {
+ FT_Error error;
+ FT_Library library;
+ FT_Face face;
+ FT_Glyph_Metrics* m;
+ FT_Outline* o;
+ FT_Int major, minor, patch;
+ int i, j, font_size, no_hinting;
+
+ if (argc != 4) {
+ usage(argv);
+ return 1;
+ }
+ font_size = atoi(argv[1]);
+ if (font_size <= 0) {
+ fprintf(stderr, "invalid font_size\n");
+ usage(argv);
+ return 1;
+ }
+ if (!strcmp(argv[3], "with_hinting")) {
+ no_hinting = 0;
+ } else if (!strcmp(argv[3], "sans_hinting")) {
+ no_hinting = 1;
+ } else {
+ fprintf(stderr, "neither \"with_hinting\" nor \"sans_hinting\"\n");
+ usage(argv);
+ return 1;
+ };
+ error = FT_Init_FreeType(&library);
+ if (error) {
+ fprintf(stderr, "FT_Init_FreeType: error #%d\n", error);
+ return 1;
+ }
+ FT_Library_Version(library, &major, &minor, &patch);
+ printf("freetype version %d.%d.%d\n", major, minor, patch);
+ error = FT_New_Face(library, argv[2], 0, &face);
+ if (error) {
+ fprintf(stderr, "FT_New_Face: error #%d\n", error);
+ return 1;
+ }
+ error = FT_Set_Char_Size(face, 0, font_size*64, 0, 0);
+ if (error) {
+ fprintf(stderr, "FT_Set_Char_Size: error #%d\n", error);
+ return 1;
+ }
+ for (i = 0; i < face->num_glyphs; i++) {
+ error = FT_Load_Glyph(face, i, no_hinting ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT);
+ if (error) {
+ fprintf(stderr, "FT_Load_Glyph: glyph %d: error #%d\n", i, error);
+ return 1;
+ }
+ if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
+ fprintf(stderr, "glyph format for glyph %d is not FT_GLYPH_FORMAT_OUTLINE\n", i);
+ return 1;
+ }
+ m = &face->glyph->metrics;
+ /* Print what Go calls the AdvanceWidth, and then: XMin, YMin, XMax, YMax. */
+ printf("%ld %ld %ld %ld %ld;",
+ m->horiAdvance,
+ m->horiBearingX,
+ m->horiBearingY - m->height,
+ m->horiBearingX + m->width,
+ m->horiBearingY);
+ /* Print the glyph points. */
+ o = &face->glyph->outline;
+ for (j = 0; j < o->n_points; j++) {
+ if (j != 0) {
+ printf(", ");
+ }
+ printf("%ld %ld %d", o->points[j].x, o->points[j].y, o->tags[j] & 0x01);
+ }
+ printf("\n");
+ }
+ return 0;
+}
diff --git a/vendor/github.com/golang/freetype/example/capjoin/main.go b/vendor/github.com/golang/freetype/example/capjoin/main.go
new file mode 100644
index 000000000..71f3356c7
--- /dev/null
+++ b/vendor/github.com/golang/freetype/example/capjoin/main.go
@@ -0,0 +1,85 @@
+// Copyright 2016 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install github.com/golang/freetype/..."
+// doesn't install this example program. Use "go run main.go" to run it or "go
+// install -tags=example" to install it.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "log"
+ "os"
+
+ "github.com/golang/freetype/raster"
+ "golang.org/x/image/math/fixed"
+)
+
+func main() {
+ const (
+ w = 400
+ h = 400
+ )
+ r := raster.NewRasterizer(w, h)
+ r.UseNonZeroWinding = true
+
+ cjs := []struct {
+ c raster.Capper
+ j raster.Joiner
+ }{
+ {raster.RoundCapper, raster.RoundJoiner},
+ {raster.ButtCapper, raster.BevelJoiner},
+ {raster.SquareCapper, raster.BevelJoiner},
+ }
+
+ for i, cj := range cjs {
+ var path raster.Path
+ path.Start(fixed.P(30+100*i, 30+120*i))
+ path.Add1(fixed.P(180+100*i, 80+120*i))
+ path.Add1(fixed.P(50+100*i, 130+120*i))
+ raster.Stroke(r, path, fixed.I(20), cj.c, cj.j)
+ }
+
+ rgba := image.NewRGBA(image.Rect(0, 0, w, h))
+ draw.Draw(rgba, rgba.Bounds(), image.Black, image.Point{}, draw.Src)
+ p := raster.NewRGBAPainter(rgba)
+ p.SetColor(color.RGBA{0x7f, 0x7f, 0x7f, 0xff})
+ r.Rasterize(p)
+
+ white := color.RGBA{0xff, 0xff, 0xff, 0xff}
+ for i := range cjs {
+ rgba.SetRGBA(30+100*i, 30+120*i, white)
+ rgba.SetRGBA(180+100*i, 80+120*i, white)
+ rgba.SetRGBA(50+100*i, 130+120*i, white)
+ }
+
+ // Save that RGBA image to disk.
+ outFile, err := os.Create("out.png")
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ defer outFile.Close()
+ b := bufio.NewWriter(outFile)
+ err = png.Encode(b, rgba)
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ err = b.Flush()
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ fmt.Println("Wrote out.png OK.")
+}
diff --git a/vendor/github.com/golang/freetype/example/drawer/main.go b/vendor/github.com/golang/freetype/example/drawer/main.go
new file mode 100644
index 000000000..d26d066d9
--- /dev/null
+++ b/vendor/github.com/golang/freetype/example/drawer/main.go
@@ -0,0 +1,158 @@
+// Copyright 2015 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install github.com/golang/freetype/..."
+// doesn't install this example program. Use "go run main.go" to run it or "go
+// install -tags=example" to install it.
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "io/ioutil"
+ "log"
+ "math"
+ "os"
+
+ "github.com/golang/freetype/truetype"
+ "golang.org/x/image/font"
+ "golang.org/x/image/math/fixed"
+)
+
+var (
+ dpi = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
+ fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
+ hinting = flag.String("hinting", "none", "none | full")
+ size = flag.Float64("size", 12, "font size in points")
+ spacing = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
+ wonb = flag.Bool("whiteonblack", false, "white text on a black background")
+)
+
+const title = "Jabberwocky"
+
+var text = []string{
+ "’Twas brillig, and the slithy toves",
+ "Did gyre and gimble in the wabe;",
+ "All mimsy were the borogoves,",
+ "And the mome raths outgrabe.",
+ "",
+ "“Beware the Jabberwock, my son!",
+ "The jaws that bite, the claws that catch!",
+ "Beware the Jubjub bird, and shun",
+ "The frumious Bandersnatch!”",
+ "",
+ "He took his vorpal sword in hand:",
+ "Long time the manxome foe he sought—",
+ "So rested he by the Tumtum tree,",
+ "And stood awhile in thought.",
+ "",
+ "And as in uffish thought he stood,",
+ "The Jabberwock, with eyes of flame,",
+ "Came whiffling through the tulgey wood,",
+ "And burbled as it came!",
+ "",
+ "One, two! One, two! and through and through",
+ "The vorpal blade went snicker-snack!",
+ "He left it dead, and with its head",
+ "He went galumphing back.",
+ "",
+ "“And hast thou slain the Jabberwock?",
+ "Come to my arms, my beamish boy!",
+ "O frabjous day! Callooh! Callay!”",
+ "He chortled in his joy.",
+ "",
+ "’Twas brillig, and the slithy toves",
+ "Did gyre and gimble in the wabe;",
+ "All mimsy were the borogoves,",
+ "And the mome raths outgrabe.",
+}
+
+func main() {
+ flag.Parse()
+
+ // Read the font data.
+ fontBytes, err := ioutil.ReadFile(*fontfile)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ f, err := truetype.Parse(fontBytes)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+
+ // Draw the background and the guidelines.
+ fg, bg := image.Black, image.White
+ ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
+ if *wonb {
+ fg, bg = image.White, image.Black
+ ruler = color.RGBA{0x22, 0x22, 0x22, 0xff}
+ }
+ const imgW, imgH = 640, 480
+ rgba := image.NewRGBA(image.Rect(0, 0, imgW, imgH))
+ draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
+ for i := 0; i < 200; i++ {
+ rgba.Set(10, 10+i, ruler)
+ rgba.Set(10+i, 10, ruler)
+ }
+
+ // Draw the text.
+ h := font.HintingNone
+ switch *hinting {
+ case "full":
+ h = font.HintingFull
+ }
+ d := &font.Drawer{
+ Dst: rgba,
+ Src: fg,
+ Face: truetype.NewFace(f, &truetype.Options{
+ Size: *size,
+ DPI: *dpi,
+ Hinting: h,
+ }),
+ }
+ y := 10 + int(math.Ceil(*size**dpi/72))
+ dy := int(math.Ceil(*size * *spacing * *dpi / 72))
+ d.Dot = fixed.Point26_6{
+ X: (fixed.I(imgW) - d.MeasureString(title)) / 2,
+ Y: fixed.I(y),
+ }
+ d.DrawString(title)
+ y += dy
+ for _, s := range text {
+ d.Dot = fixed.P(10, y)
+ d.DrawString(s)
+ y += dy
+ }
+
+ // Save that RGBA image to disk.
+ outFile, err := os.Create("out.png")
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ defer outFile.Close()
+ b := bufio.NewWriter(outFile)
+ err = png.Encode(b, rgba)
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ err = b.Flush()
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ fmt.Println("Wrote out.png OK.")
+}
diff --git a/vendor/github.com/golang/freetype/example/freetype/main.go b/vendor/github.com/golang/freetype/example/freetype/main.go
new file mode 100644
index 000000000..dfbde9a2f
--- /dev/null
+++ b/vendor/github.com/golang/freetype/example/freetype/main.go
@@ -0,0 +1,150 @@
+// Copyright 2010 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install github.com/golang/freetype/..."
+// doesn't install this example program. Use "go run main.go" to run it or "go
+// install -tags=example" to install it.
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "io/ioutil"
+ "log"
+ "os"
+
+ "github.com/golang/freetype"
+ "golang.org/x/image/font"
+)
+
+var (
+ dpi = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
+ fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
+ hinting = flag.String("hinting", "none", "none | full")
+ size = flag.Float64("size", 12, "font size in points")
+ spacing = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
+ wonb = flag.Bool("whiteonblack", false, "white text on a black background")
+)
+
+var text = []string{
+ "’Twas brillig, and the slithy toves",
+ "Did gyre and gimble in the wabe;",
+ "All mimsy were the borogoves,",
+ "And the mome raths outgrabe.",
+ "",
+ "“Beware the Jabberwock, my son!",
+ "The jaws that bite, the claws that catch!",
+ "Beware the Jubjub bird, and shun",
+ "The frumious Bandersnatch!”",
+ "",
+ "He took his vorpal sword in hand:",
+ "Long time the manxome foe he sought—",
+ "So rested he by the Tumtum tree,",
+ "And stood awhile in thought.",
+ "",
+ "And as in uffish thought he stood,",
+ "The Jabberwock, with eyes of flame,",
+ "Came whiffling through the tulgey wood,",
+ "And burbled as it came!",
+ "",
+ "One, two! One, two! and through and through",
+ "The vorpal blade went snicker-snack!",
+ "He left it dead, and with its head",
+ "He went galumphing back.",
+ "",
+ "“And hast thou slain the Jabberwock?",
+ "Come to my arms, my beamish boy!",
+ "O frabjous day! Callooh! Callay!”",
+ "He chortled in his joy.",
+ "",
+ "’Twas brillig, and the slithy toves",
+ "Did gyre and gimble in the wabe;",
+ "All mimsy were the borogoves,",
+ "And the mome raths outgrabe.",
+}
+
+func main() {
+ flag.Parse()
+
+ // Read the font data.
+ fontBytes, err := ioutil.ReadFile(*fontfile)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ f, err := freetype.ParseFont(fontBytes)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+
+ // Initialize the context.
+ fg, bg := image.Black, image.White
+ ruler := color.RGBA{0xdd, 0xdd, 0xdd, 0xff}
+ if *wonb {
+ fg, bg = image.White, image.Black
+ ruler = color.RGBA{0x22, 0x22, 0x22, 0xff}
+ }
+ rgba := image.NewRGBA(image.Rect(0, 0, 640, 480))
+ draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src)
+ c := freetype.NewContext()
+ c.SetDPI(*dpi)
+ c.SetFont(f)
+ c.SetFontSize(*size)
+ c.SetClip(rgba.Bounds())
+ c.SetDst(rgba)
+ c.SetSrc(fg)
+ switch *hinting {
+ default:
+ c.SetHinting(font.HintingNone)
+ case "full":
+ c.SetHinting(font.HintingFull)
+ }
+
+ // Draw the guidelines.
+ for i := 0; i < 200; i++ {
+ rgba.Set(10, 10+i, ruler)
+ rgba.Set(10+i, 10, ruler)
+ }
+
+ // Draw the text.
+ pt := freetype.Pt(10, 10+int(c.PointToFixed(*size)>>6))
+ for _, s := range text {
+ _, err = c.DrawString(s, pt)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ pt.Y += c.PointToFixed(*size * *spacing)
+ }
+
+ // Save that RGBA image to disk.
+ outFile, err := os.Create("out.png")
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ defer outFile.Close()
+ b := bufio.NewWriter(outFile)
+ err = png.Encode(b, rgba)
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ err = b.Flush()
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ fmt.Println("Wrote out.png OK.")
+}
diff --git a/vendor/github.com/golang/freetype/example/gamma/main.go b/vendor/github.com/golang/freetype/example/gamma/main.go
new file mode 100644
index 000000000..cdd50bc3b
--- /dev/null
+++ b/vendor/github.com/golang/freetype/example/gamma/main.go
@@ -0,0 +1,86 @@
+// Copyright 2010 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install github.com/golang/freetype/..."
+// doesn't install this example program. Use "go run main.go" to run it or "go
+// install -tags=example" to install it.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "image"
+ "image/draw"
+ "image/png"
+ "log"
+ "os"
+
+ "github.com/golang/freetype/raster"
+ "golang.org/x/image/math/fixed"
+)
+
+func p(x, y int) fixed.Point26_6 {
+ return fixed.Point26_6{
+ X: fixed.Int26_6(x * 64),
+ Y: fixed.Int26_6(y * 64),
+ }
+}
+
+func main() {
+ // Draw a rounded corner that is one pixel wide.
+ r := raster.NewRasterizer(50, 50)
+ r.Start(p(5, 5))
+ r.Add1(p(5, 25))
+ r.Add2(p(5, 45), p(25, 45))
+ r.Add1(p(45, 45))
+ r.Add1(p(45, 44))
+ r.Add1(p(26, 44))
+ r.Add2(p(6, 44), p(6, 24))
+ r.Add1(p(6, 5))
+ r.Add1(p(5, 5))
+
+ // Rasterize that curve multiple times at different gammas.
+ const (
+ w = 600
+ h = 200
+ )
+ rgba := image.NewRGBA(image.Rect(0, 0, w, h))
+ draw.Draw(rgba, image.Rect(0, 0, w, h/2), image.Black, image.ZP, draw.Src)
+ draw.Draw(rgba, image.Rect(0, h/2, w, h), image.White, image.ZP, draw.Src)
+ mask := image.NewAlpha(image.Rect(0, 0, 50, 50))
+ painter := raster.NewAlphaSrcPainter(mask)
+ gammas := []float64{1.0 / 10.0, 1.0 / 3.0, 1.0 / 2.0, 2.0 / 3.0, 4.0 / 5.0, 1.0, 5.0 / 4.0, 3.0 / 2.0, 2.0, 3.0, 10.0}
+ for i, g := range gammas {
+ draw.Draw(mask, mask.Bounds(), image.Transparent, image.ZP, draw.Src)
+ r.Rasterize(raster.NewGammaCorrectionPainter(painter, g))
+ x, y := 50*i+25, 25
+ draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.White, image.ZP, mask, image.ZP, draw.Over)
+ y += 100
+ draw.DrawMask(rgba, image.Rect(x, y, x+50, y+50), image.Black, image.ZP, mask, image.ZP, draw.Over)
+ }
+
+ // Save that RGBA image to disk.
+ outFile, err := os.Create("out.png")
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ defer outFile.Close()
+ b := bufio.NewWriter(outFile)
+ err = png.Encode(b, rgba)
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ err = b.Flush()
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ fmt.Println("Wrote out.png OK.")
+}
diff --git a/vendor/github.com/golang/freetype/example/raster/main.go b/vendor/github.com/golang/freetype/example/raster/main.go
new file mode 100644
index 000000000..3e572e1c5
--- /dev/null
+++ b/vendor/github.com/golang/freetype/example/raster/main.go
@@ -0,0 +1,185 @@
+// Copyright 2010 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install github.com/golang/freetype/..."
+// doesn't install this example program. Use "go run main.go" to run it or "go
+// install -tags=example" to install it.
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "log"
+ "os"
+
+ "github.com/golang/freetype/raster"
+ "golang.org/x/image/math/fixed"
+)
+
+type node struct {
+ x, y, degree int
+}
+
+// These contours "outside" and "inside" are from the 'A' glyph from the Droid
+// Serif Regular font.
+
+var outside = []node{
+ node{414, 489, 1},
+ node{336, 274, 2},
+ node{327, 250, 0},
+ node{322, 226, 2},
+ node{317, 203, 0},
+ node{317, 186, 2},
+ node{317, 134, 0},
+ node{350, 110, 2},
+ node{384, 86, 0},
+ node{453, 86, 1},
+ node{500, 86, 1},
+ node{500, 0, 1},
+ node{0, 0, 1},
+ node{0, 86, 1},
+ node{39, 86, 2},
+ node{69, 86, 0},
+ node{90, 92, 2},
+ node{111, 99, 0},
+ node{128, 117, 2},
+ node{145, 135, 0},
+ node{160, 166, 2},
+ node{176, 197, 0},
+ node{195, 246, 1},
+ node{649, 1462, 1},
+ node{809, 1462, 1},
+ node{1272, 195, 2},
+ node{1284, 163, 0},
+ node{1296, 142, 2},
+ node{1309, 121, 0},
+ node{1326, 108, 2},
+ node{1343, 96, 0},
+ node{1365, 91, 2},
+ node{1387, 86, 0},
+ node{1417, 86, 1},
+ node{1444, 86, 1},
+ node{1444, 0, 1},
+ node{881, 0, 1},
+ node{881, 86, 1},
+ node{928, 86, 2},
+ node{1051, 86, 0},
+ node{1051, 184, 2},
+ node{1051, 201, 0},
+ node{1046, 219, 2},
+ node{1042, 237, 0},
+ node{1034, 260, 1},
+ node{952, 489, 1},
+ node{414, 489, -1},
+}
+
+var inside = []node{
+ node{686, 1274, 1},
+ node{453, 592, 1},
+ node{915, 592, 1},
+ node{686, 1274, -1},
+}
+
+func p(n node) fixed.Point26_6 {
+ x, y := 20+n.x/4, 380-n.y/4
+ return fixed.Point26_6{
+ X: fixed.Int26_6(x << 6),
+ Y: fixed.Int26_6(y << 6),
+ }
+}
+
+func contour(r *raster.Rasterizer, ns []node) {
+ if len(ns) == 0 {
+ return
+ }
+ i := 0
+ r.Start(p(ns[i]))
+ for {
+ switch ns[i].degree {
+ case -1:
+ // -1 signifies end-of-contour.
+ return
+ case 1:
+ i += 1
+ r.Add1(p(ns[i]))
+ case 2:
+ i += 2
+ r.Add2(p(ns[i-1]), p(ns[i]))
+ default:
+ panic("bad degree")
+ }
+ }
+}
+
+func showNodes(m *image.RGBA, ns []node) {
+ for _, n := range ns {
+ p := p(n)
+ x, y := int(p.X)/64, int(p.Y)/64
+ if !(image.Point{x, y}).In(m.Bounds()) {
+ continue
+ }
+ var c color.Color
+ switch n.degree {
+ case 0:
+ c = color.RGBA{0, 255, 255, 255}
+ case 1:
+ c = color.RGBA{255, 0, 0, 255}
+ case 2:
+ c = color.RGBA{255, 0, 0, 255}
+ }
+ if c != nil {
+ m.Set(x, y, c)
+ }
+ }
+}
+
+func main() {
+ // Rasterize the contours to a mask image.
+ const (
+ w = 400
+ h = 400
+ )
+ r := raster.NewRasterizer(w, h)
+ contour(r, outside)
+ contour(r, inside)
+ mask := image.NewAlpha(image.Rect(0, 0, w, h))
+ p := raster.NewAlphaSrcPainter(mask)
+ r.Rasterize(p)
+
+ // Draw the mask image (in gray) onto an RGBA image.
+ rgba := image.NewRGBA(image.Rect(0, 0, w, h))
+ gray := image.NewUniform(color.Alpha{0x1f})
+ draw.Draw(rgba, rgba.Bounds(), image.Black, image.ZP, draw.Src)
+ draw.DrawMask(rgba, rgba.Bounds(), gray, image.ZP, mask, image.ZP, draw.Over)
+ showNodes(rgba, outside)
+ showNodes(rgba, inside)
+
+ // Save that RGBA image to disk.
+ outFile, err := os.Create("out.png")
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ defer outFile.Close()
+ b := bufio.NewWriter(outFile)
+ err = png.Encode(b, rgba)
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ err = b.Flush()
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ fmt.Println("Wrote out.png OK.")
+}
diff --git a/vendor/github.com/golang/freetype/example/round/main.go b/vendor/github.com/golang/freetype/example/round/main.go
new file mode 100644
index 000000000..2920e8335
--- /dev/null
+++ b/vendor/github.com/golang/freetype/example/round/main.go
@@ -0,0 +1,110 @@
+// Copyright 2010 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install github.com/golang/freetype/..."
+// doesn't install this example program. Use "go run main.go" to run it or "go
+// install -tags=example" to install it.
+
+// This program visualizes the quadratic approximation to the circle, used to
+// implement round joins when stroking paths. The approximation is used in the
+// stroking code for arcs between 0 and 45 degrees, but is visualized here
+// between 0 and 90 degrees. The discrepancy between the approximation and the
+// true circle is clearly visible at angles above 65 degrees.
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "log"
+ "math"
+ "os"
+
+ "github.com/golang/freetype/raster"
+ "golang.org/x/image/math/fixed"
+)
+
+// pDot returns the dot product p·q.
+func pDot(p, q fixed.Point26_6) fixed.Int52_12 {
+ px, py := int64(p.X), int64(p.Y)
+ qx, qy := int64(q.X), int64(q.Y)
+ return fixed.Int52_12(px*qx + py*qy)
+}
+
+func main() {
+ const (
+ n = 17
+ r = 64 * 80
+ )
+ s := fixed.Int26_6(r * math.Sqrt(2) / 2)
+ t := fixed.Int26_6(r * math.Tan(math.Pi/8))
+
+ m := image.NewRGBA(image.Rect(0, 0, 800, 600))
+ draw.Draw(m, m.Bounds(), image.NewUniform(color.RGBA{63, 63, 63, 255}), image.ZP, draw.Src)
+ mp := raster.NewRGBAPainter(m)
+ mp.SetColor(image.Black)
+ z := raster.NewRasterizer(800, 600)
+
+ for i := 0; i < n; i++ {
+ cx := fixed.Int26_6(6400 + 12800*(i%4))
+ cy := fixed.Int26_6(640 + 8000*(i/4))
+ c := fixed.Point26_6{X: cx, Y: cy}
+ theta := math.Pi * (0.5 + 0.5*float64(i)/(n-1))
+ dx := fixed.Int26_6(r * math.Cos(theta))
+ dy := fixed.Int26_6(r * math.Sin(theta))
+ d := fixed.Point26_6{X: dx, Y: dy}
+ // Draw a quarter-circle approximated by two quadratic segments,
+ // with each segment spanning 45 degrees.
+ z.Start(c)
+ z.Add1(c.Add(fixed.Point26_6{X: r, Y: 0}))
+ z.Add2(c.Add(fixed.Point26_6{X: r, Y: t}), c.Add(fixed.Point26_6{X: s, Y: s}))
+ z.Add2(c.Add(fixed.Point26_6{X: t, Y: r}), c.Add(fixed.Point26_6{X: 0, Y: r}))
+ // Add another quadratic segment whose angle ranges between 0 and 90
+ // degrees. For an explanation of the magic constants 128, 150, 181 and
+ // 256, read the comments in the freetype/raster package.
+ dot := 256 * pDot(d, fixed.Point26_6{X: 0, Y: r}) / (r * r)
+ multiple := fixed.Int26_6(150-(150-128)*(dot-181)/(256-181)) >> 2
+ z.Add2(c.Add(fixed.Point26_6{X: dx, Y: r + dy}.Mul(multiple)), c.Add(d))
+ // Close the curve.
+ z.Add1(c)
+ }
+ z.Rasterize(mp)
+
+ for i := 0; i < n; i++ {
+ cx := fixed.Int26_6(6400 + 12800*(i%4))
+ cy := fixed.Int26_6(640 + 8000*(i/4))
+ for j := 0; j < n; j++ {
+ theta := math.Pi * float64(j) / (n - 1)
+ dx := fixed.Int26_6(r * math.Cos(theta))
+ dy := fixed.Int26_6(r * math.Sin(theta))
+ m.Set(int((cx+dx)/64), int((cy+dy)/64), color.RGBA{255, 255, 0, 255})
+ }
+ }
+
+ // Save that RGBA image to disk.
+ outFile, err := os.Create("out.png")
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ defer outFile.Close()
+ b := bufio.NewWriter(outFile)
+ err = png.Encode(b, m)
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ err = b.Flush()
+ if err != nil {
+ log.Println(err)
+ os.Exit(1)
+ }
+ fmt.Println("Wrote out.png OK.")
+}
diff --git a/vendor/github.com/golang/freetype/example/truetype/main.go b/vendor/github.com/golang/freetype/example/truetype/main.go
new file mode 100644
index 000000000..e7db2d0ca
--- /dev/null
+++ b/vendor/github.com/golang/freetype/example/truetype/main.go
@@ -0,0 +1,89 @@
+// Copyright 2010 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install github.com/golang/freetype/..."
+// doesn't install this example program. Use "go run main.go" to run it or "go
+// install -tags=example" to install it.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+
+ "github.com/golang/freetype/truetype"
+ "golang.org/x/image/font"
+ "golang.org/x/image/math/fixed"
+)
+
+var fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
+
+func printBounds(b fixed.Rectangle26_6) {
+ fmt.Printf("Min.X:%d Min.Y:%d Max.X:%d Max.Y:%d\n", b.Min.X, b.Min.Y, b.Max.X, b.Max.Y)
+}
+
+func printGlyph(g *truetype.GlyphBuf) {
+ printBounds(g.Bounds)
+ fmt.Print("Points:\n---\n")
+ e := 0
+ for i, p := range g.Points {
+ fmt.Printf("%4d, %4d", p.X, p.Y)
+ if p.Flags&0x01 != 0 {
+ fmt.Print(" on\n")
+ } else {
+ fmt.Print(" off\n")
+ }
+ if i+1 == int(g.Ends[e]) {
+ fmt.Print("---\n")
+ e++
+ }
+ }
+}
+
+func main() {
+ flag.Parse()
+ fmt.Printf("Loading fontfile %q\n", *fontfile)
+ b, err := ioutil.ReadFile(*fontfile)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ f, err := truetype.Parse(b)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ fupe := fixed.Int26_6(f.FUnitsPerEm())
+ printBounds(f.Bounds(fupe))
+ fmt.Printf("FUnitsPerEm:%d\n\n", fupe)
+
+ c0, c1 := 'A', 'V'
+
+ i0 := f.Index(c0)
+ hm := f.HMetric(fupe, i0)
+ g := &truetype.GlyphBuf{}
+ err = g.Load(f, fupe, i0, font.HintingNone)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ fmt.Printf("'%c' glyph\n", c0)
+ fmt.Printf("AdvanceWidth:%d LeftSideBearing:%d\n", hm.AdvanceWidth, hm.LeftSideBearing)
+ printGlyph(g)
+ i1 := f.Index(c1)
+ fmt.Printf("\n'%c', '%c' Kern:%d\n", c0, c1, f.Kern(fupe, i0, i1))
+
+ fmt.Printf("\nThe numbers above are in FUnits.\n" +
+ "The numbers below are in 26.6 fixed point pixels, at 12pt and 72dpi.\n\n")
+ a := truetype.NewFace(f, &truetype.Options{
+ Size: 12,
+ DPI: 72,
+ })
+ fmt.Printf("%#v\n", a.Metrics())
+}
diff --git a/vendor/github.com/golang/freetype/freetype.go b/vendor/github.com/golang/freetype/freetype.go
index bec01f6b7..96035866c 100644
--- a/vendor/github.com/golang/freetype/freetype.go
+++ b/vendor/github.com/golang/freetype/freetype.go
@@ -6,7 +6,7 @@
// The freetype package provides a convenient API to draw text onto an image.
// Use the freetype/raster and freetype/truetype packages for lower level
// control over rasterization and TrueType parsing.
-package freetype
+package freetype // import "github.com/golang/freetype"
import (
"errors"
diff --git a/vendor/github.com/golang/freetype/freetype_test.go b/vendor/github.com/golang/freetype/freetype_test.go
new file mode 100644
index 000000000..348c411ab
--- /dev/null
+++ b/vendor/github.com/golang/freetype/freetype_test.go
@@ -0,0 +1,59 @@
+// Copyright 2012 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+package freetype
+
+import (
+ "image"
+ "image/draw"
+ "io/ioutil"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func BenchmarkDrawString(b *testing.B) {
+ data, err := ioutil.ReadFile("licenses/gpl.txt")
+ if err != nil {
+ b.Fatal(err)
+ }
+ lines := strings.Split(string(data), "\n")
+
+ data, err = ioutil.ReadFile("testdata/luxisr.ttf")
+ if err != nil {
+ b.Fatal(err)
+ }
+ f, err := ParseFont(data)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ dst := image.NewRGBA(image.Rect(0, 0, 800, 600))
+ draw.Draw(dst, dst.Bounds(), image.White, image.ZP, draw.Src)
+
+ c := NewContext()
+ c.SetDst(dst)
+ c.SetClip(dst.Bounds())
+ c.SetSrc(image.Black)
+ c.SetFont(f)
+
+ var ms runtime.MemStats
+ runtime.ReadMemStats(&ms)
+ mallocs := ms.Mallocs
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ for j, line := range lines {
+ _, err := c.DrawString(line, Pt(0, (j*16)%600))
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ }
+ b.StopTimer()
+ runtime.ReadMemStats(&ms)
+ mallocs = ms.Mallocs - mallocs
+ b.Logf("%d iterations, %d mallocs per iteration\n", b.N, int(mallocs)/b.N)
+}
diff --git a/vendor/github.com/golang/freetype/licenses/ftl.txt b/vendor/github.com/golang/freetype/licenses/ftl.txt
new file mode 100644
index 000000000..bbaba33f4
--- /dev/null
+++ b/vendor/github.com/golang/freetype/licenses/ftl.txt
@@ -0,0 +1,169 @@
+ The FreeType Project LICENSE
+ ----------------------------
+
+ 2006-Jan-27
+
+ Copyright 1996-2002, 2006 by
+ David Turner, Robert Wilhelm, and Werner Lemberg
+
+
+
+Introduction
+============
+
+ The FreeType Project is distributed in several archive packages;
+ some of them may contain, in addition to the FreeType font engine,
+ various tools and contributions which rely on, or relate to, the
+ FreeType Project.
+
+ This license applies to all files found in such packages, and
+ which do not fall under their own explicit license. The license
+ affects thus the FreeType font engine, the test programs,
+ documentation and makefiles, at the very least.
+
+ This license was inspired by the BSD, Artistic, and IJG
+ (Independent JPEG Group) licenses, which all encourage inclusion
+ and use of free software in commercial and freeware products
+ alike. As a consequence, its main points are that:
+
+ o We don't promise that this software works. However, we will be
+ interested in any kind of bug reports. (`as is' distribution)
+
+ o You can use this software for whatever you want, in parts or
+ full form, without having to pay us. (`royalty-free' usage)
+
+ o You may not pretend that you wrote this software. If you use
+ it, or only parts of it, in a program, you must acknowledge
+ somewhere in your documentation that you have used the
+ FreeType code. (`credits')
+
+ We specifically permit and encourage the inclusion of this
+ software, with or without modifications, in commercial products.
+ We disclaim all warranties covering The FreeType Project and
+ assume no liability related to The FreeType Project.
+
+
+ Finally, many people asked us for a preferred form for a
+ credit/disclaimer to use in compliance with this license. We thus
+ encourage you to use the following text:
+
+ """
+ Portions of this software are copyright <year> The FreeType
+ Project (www.freetype.org). All rights reserved.
+ """
+
+ Please replace <year> with the value from the FreeType version you
+ actually use.
+
+
+Legal Terms
+===========
+
+0. Definitions
+--------------
+
+ Throughout this license, the terms `package', `FreeType Project',
+ and `FreeType archive' refer to the set of files originally
+ distributed by the authors (David Turner, Robert Wilhelm, and
+ Werner Lemberg) as the `FreeType Project', be they named as alpha,
+ beta or final release.
+
+ `You' refers to the licensee, or person using the project, where
+ `using' is a generic term including compiling the project's source
+ code as well as linking it to form a `program' or `executable'.
+ This program is referred to as `a program using the FreeType
+ engine'.
+
+ This license applies to all files distributed in the original
+ FreeType Project, including all source code, binaries and
+ documentation, unless otherwise stated in the file in its
+ original, unmodified form as distributed in the original archive.
+ If you are unsure whether or not a particular file is covered by
+ this license, you must contact us to verify this.
+
+ The FreeType Project is copyright (C) 1996-2000 by David Turner,
+ Robert Wilhelm, and Werner Lemberg. All rights reserved except as
+ specified below.
+
+1. No Warranty
+--------------
+
+ THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
+ USE, OF THE FREETYPE PROJECT.
+
+2. Redistribution
+-----------------
+
+ This license grants a worldwide, royalty-free, perpetual and
+ irrevocable right and license to use, execute, perform, compile,
+ display, copy, create derivative works of, distribute and
+ sublicense the FreeType Project (in both source and object code
+ forms) and derivative works thereof for any purpose; and to
+ authorize others to exercise some or all of the rights granted
+ herein, subject to the following conditions:
+
+ o Redistribution of source code must retain this license file
+ (`FTL.TXT') unaltered; any additions, deletions or changes to
+ the original files must be clearly indicated in accompanying
+ documentation. The copyright notices of the unaltered,
+ original files must be preserved in all copies of source
+ files.
+
+ o Redistribution in binary form must provide a disclaimer that
+ states that the software is based in part of the work of the
+ FreeType Team, in the distribution documentation. We also
+ encourage you to put an URL to the FreeType web page in your
+ documentation, though this isn't mandatory.
+
+ These conditions apply to any software derived from or based on
+ the FreeType Project, not just the unmodified files. If you use
+ our work, you must acknowledge us. However, no fee need be paid
+ to us.
+
+3. Advertising
+--------------
+
+ Neither the FreeType authors and contributors nor you shall use
+ the name of the other for commercial, advertising, or promotional
+ purposes without specific prior written permission.
+
+ We suggest, but do not require, that you use one or more of the
+ following phrases to refer to this software in your documentation
+ or advertising materials: `FreeType Project', `FreeType Engine',
+ `FreeType library', or `FreeType Distribution'.
+
+ As you have not signed this license, you are not required to
+ accept it. However, as the FreeType Project is copyrighted
+ material, only this license, or another one contracted with the
+ authors, grants you the right to use, distribute, and modify it.
+ Therefore, by using, distributing, or modifying the FreeType
+ Project, you indicate that you understand and accept all the terms
+ of this license.
+
+4. Contacts
+-----------
+
+ There are two mailing lists related to FreeType:
+
+ o freetype@nongnu.org
+
+ Discusses general use and applications of FreeType, as well as
+ future and wanted additions to the library and distribution.
+ If you are looking for support, start in this list if you
+ haven't found anything to help you in the documentation.
+
+ o freetype-devel@nongnu.org
+
+ Discusses bugs, as well as engine internals, design issues,
+ specific licenses, porting, etc.
+
+ Our home page can be found at
+
+ http://www.freetype.org
+
+
+--- end of FTL.TXT ---
diff --git a/vendor/github.com/golang/freetype/licenses/gpl.txt b/vendor/github.com/golang/freetype/licenses/gpl.txt
new file mode 100644
index 000000000..b2fe7b6af
--- /dev/null
+++ b/vendor/github.com/golang/freetype/licenses/gpl.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/vendor/github.com/golang/freetype/raster/raster.go b/vendor/github.com/golang/freetype/raster/raster.go
index 995925e2a..7e6cd4e2b 100644
--- a/vendor/github.com/golang/freetype/raster/raster.go
+++ b/vendor/github.com/golang/freetype/raster/raster.go
@@ -13,7 +13,7 @@
// the Freetype "smooth" module, and the Anti-Grain Geometry library. A
// description of the area/coverage algorithm is at
// http://projects.tuxee.net/cl-vectors/section-the-cl-aa-algorithm
-package raster
+package raster // import "github.com/golang/freetype/raster"
import (
"strconv"
diff --git a/vendor/github.com/golang/freetype/testdata/COPYING b/vendor/github.com/golang/freetype/testdata/COPYING
new file mode 100644
index 000000000..78c606533
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/COPYING
@@ -0,0 +1,42 @@
+Luxi fonts copyright (c) 2001 by Bigelow & Holmes Inc. Luxi font
+instruction code copyright (c) 2001 by URW++ GmbH. All Rights
+Reserved. Luxi is a registered trademark of Bigelow & Holmes Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of these Fonts and associated documentation files (the "Font
+Software"), to deal in the Font Software, including without
+limitation the rights to use, copy, merge, publish, distribute,
+sublicense, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software.
+
+The Font Software may not be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may not
+be modified nor may additional glyphs or characters be added to the
+Fonts. This License becomes null and void when the Fonts or Font
+Software have been modified.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+BIGELOW & HOLMES INC. OR URW++ GMBH. BE LIABLE FOR ANY CLAIM, DAMAGES
+OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT,
+INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
+INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT
+SOFTWARE.
+
+Except as contained in this notice, the names of Bigelow & Holmes
+Inc. and URW++ GmbH. shall not be used in advertising or otherwise to
+promote the sale, use or other dealings in this Font Software without
+prior written authorization from Bigelow & Holmes Inc. and URW++ GmbH.
+
+For further information, contact:
+
+info@urwpp.de
+or
+design@bigelowandholmes.com
diff --git a/vendor/github.com/golang/freetype/testdata/README b/vendor/github.com/golang/freetype/testdata/README
new file mode 100644
index 000000000..bae438269
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/README
@@ -0,0 +1,13 @@
+The luxi*.ttf and COPYING files in this directory were copied from the X.org
+project, specifically
+http://xorg.freedesktop.org/releases/individual/font/font-bh-ttf-1.0.0.tar.bz2
+
+There are three Luxi fonts: sans (s), serif (r) and monospaced (m). For example,
+luxisr.ttf is Luxi Sans. The 'r' here means regular, as opposed to bold.
+
+The *.ttx files in this directory were generated from the *.ttf files
+by the ttx command-line tool.
+http://www.letterror.com/code/ttx/index.html
+
+The *-hinting.txt files in this directory were generated from the *.ttf files
+by the ../cmd/print-glyph-points command-line tool.
diff --git a/vendor/github.com/golang/freetype/testdata/luximr.ttf b/vendor/github.com/golang/freetype/testdata/luximr.ttf
new file mode 100644
index 000000000..6ad6e1266
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luximr.ttf
Binary files differ
diff --git a/vendor/github.com/golang/freetype/testdata/luximr.ttx b/vendor/github.com/golang/freetype/testdata/luximr.ttx
new file mode 100644
index 000000000..e60ebca45
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luximr.ttx
@@ -0,0 +1,24616 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="2.4">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name=".notdef#1"/>
+ <GlyphID id="2" name=".notdef#2"/>
+ <GlyphID id="3" name="space"/>
+ <GlyphID id="4" name="exclam"/>
+ <GlyphID id="5" name="quotedbl"/>
+ <GlyphID id="6" name="numbersign"/>
+ <GlyphID id="7" name="dollar"/>
+ <GlyphID id="8" name="percent"/>
+ <GlyphID id="9" name="ampersand"/>
+ <GlyphID id="10" name="quotesingle"/>
+ <GlyphID id="11" name="parenleft"/>
+ <GlyphID id="12" name="parenright"/>
+ <GlyphID id="13" name="asterisk"/>
+ <GlyphID id="14" name="plus"/>
+ <GlyphID id="15" name="comma"/>
+ <GlyphID id="16" name="hyphen"/>
+ <GlyphID id="17" name="period"/>
+ <GlyphID id="18" name="slash"/>
+ <GlyphID id="19" name="zero"/>
+ <GlyphID id="20" name="one"/>
+ <GlyphID id="21" name="two"/>
+ <GlyphID id="22" name="three"/>
+ <GlyphID id="23" name="four"/>
+ <GlyphID id="24" name="five"/>
+ <GlyphID id="25" name="six"/>
+ <GlyphID id="26" name="seven"/>
+ <GlyphID id="27" name="eight"/>
+ <GlyphID id="28" name="nine"/>
+ <GlyphID id="29" name="colon"/>
+ <GlyphID id="30" name="semicolon"/>
+ <GlyphID id="31" name="less"/>
+ <GlyphID id="32" name="equal"/>
+ <GlyphID id="33" name="greater"/>
+ <GlyphID id="34" name="question"/>
+ <GlyphID id="35" name="at"/>
+ <GlyphID id="36" name="A"/>
+ <GlyphID id="37" name="B"/>
+ <GlyphID id="38" name="C"/>
+ <GlyphID id="39" name="D"/>
+ <GlyphID id="40" name="E"/>
+ <GlyphID id="41" name="F"/>
+ <GlyphID id="42" name="G"/>
+ <GlyphID id="43" name="H"/>
+ <GlyphID id="44" name="I"/>
+ <GlyphID id="45" name="J"/>
+ <GlyphID id="46" name="K"/>
+ <GlyphID id="47" name="L"/>
+ <GlyphID id="48" name="M"/>
+ <GlyphID id="49" name="N"/>
+ <GlyphID id="50" name="O"/>
+ <GlyphID id="51" name="P"/>
+ <GlyphID id="52" name="Q"/>
+ <GlyphID id="53" name="R"/>
+ <GlyphID id="54" name="S"/>
+ <GlyphID id="55" name="T"/>
+ <GlyphID id="56" name="U"/>
+ <GlyphID id="57" name="V"/>
+ <GlyphID id="58" name="W"/>
+ <GlyphID id="59" name="X"/>
+ <GlyphID id="60" name="Y"/>
+ <GlyphID id="61" name="Z"/>
+ <GlyphID id="62" name="bracketleft"/>
+ <GlyphID id="63" name="backslash"/>
+ <GlyphID id="64" name="bracketright"/>
+ <GlyphID id="65" name="asciicircum"/>
+ <GlyphID id="66" name="underscore"/>
+ <GlyphID id="67" name="grave"/>
+ <GlyphID id="68" name="a"/>
+ <GlyphID id="69" name="b"/>
+ <GlyphID id="70" name="c"/>
+ <GlyphID id="71" name="d"/>
+ <GlyphID id="72" name="e"/>
+ <GlyphID id="73" name="f"/>
+ <GlyphID id="74" name="g"/>
+ <GlyphID id="75" name="h"/>
+ <GlyphID id="76" name="i"/>
+ <GlyphID id="77" name="j"/>
+ <GlyphID id="78" name="k"/>
+ <GlyphID id="79" name="l"/>
+ <GlyphID id="80" name="m"/>
+ <GlyphID id="81" name="n"/>
+ <GlyphID id="82" name="o"/>
+ <GlyphID id="83" name="p"/>
+ <GlyphID id="84" name="q"/>
+ <GlyphID id="85" name="r"/>
+ <GlyphID id="86" name="s"/>
+ <GlyphID id="87" name="t"/>
+ <GlyphID id="88" name="u"/>
+ <GlyphID id="89" name="v"/>
+ <GlyphID id="90" name="w"/>
+ <GlyphID id="91" name="x"/>
+ <GlyphID id="92" name="y"/>
+ <GlyphID id="93" name="z"/>
+ <GlyphID id="94" name="braceleft"/>
+ <GlyphID id="95" name="bar"/>
+ <GlyphID id="96" name="braceright"/>
+ <GlyphID id="97" name="asciitilde"/>
+ <GlyphID id="98" name="Adieresis"/>
+ <GlyphID id="99" name="Aring"/>
+ <GlyphID id="100" name="Ccedilla"/>
+ <GlyphID id="101" name="Eacute"/>
+ <GlyphID id="102" name="Ntilde"/>
+ <GlyphID id="103" name="Odieresis"/>
+ <GlyphID id="104" name="Udieresis"/>
+ <GlyphID id="105" name="aacute"/>
+ <GlyphID id="106" name="agrave"/>
+ <GlyphID id="107" name="acircumflex"/>
+ <GlyphID id="108" name="adieresis"/>
+ <GlyphID id="109" name="atilde"/>
+ <GlyphID id="110" name="aring"/>
+ <GlyphID id="111" name="ccedilla"/>
+ <GlyphID id="112" name="eacute"/>
+ <GlyphID id="113" name="egrave"/>
+ <GlyphID id="114" name="ecircumflex"/>
+ <GlyphID id="115" name="edieresis"/>
+ <GlyphID id="116" name="iacute"/>
+ <GlyphID id="117" name="igrave"/>
+ <GlyphID id="118" name="icircumflex"/>
+ <GlyphID id="119" name="idieresis"/>
+ <GlyphID id="120" name="ntilde"/>
+ <GlyphID id="121" name="oacute"/>
+ <GlyphID id="122" name="ograve"/>
+ <GlyphID id="123" name="ocircumflex"/>
+ <GlyphID id="124" name="odieresis"/>
+ <GlyphID id="125" name="otilde"/>
+ <GlyphID id="126" name="uacute"/>
+ <GlyphID id="127" name="ugrave"/>
+ <GlyphID id="128" name="ucircumflex"/>
+ <GlyphID id="129" name="udieresis"/>
+ <GlyphID id="130" name="dagger"/>
+ <GlyphID id="131" name="degree"/>
+ <GlyphID id="132" name="cent"/>
+ <GlyphID id="133" name="sterling"/>
+ <GlyphID id="134" name="section"/>
+ <GlyphID id="135" name="bullet"/>
+ <GlyphID id="136" name="paragraph"/>
+ <GlyphID id="137" name="germandbls"/>
+ <GlyphID id="138" name="registered"/>
+ <GlyphID id="139" name="copyright"/>
+ <GlyphID id="140" name="trademark"/>
+ <GlyphID id="141" name="acute"/>
+ <GlyphID id="142" name="dieresis"/>
+ <GlyphID id="143" name=".notdef#3"/>
+ <GlyphID id="144" name="AE"/>
+ <GlyphID id="145" name="Oslash"/>
+ <GlyphID id="146" name=".notdef#4"/>
+ <GlyphID id="147" name="plusminus"/>
+ <GlyphID id="148" name=".notdef#5"/>
+ <GlyphID id="149" name=".notdef#6"/>
+ <GlyphID id="150" name="yen"/>
+ <GlyphID id="151" name="mu"/>
+ <GlyphID id="152" name=".notdef#7"/>
+ <GlyphID id="153" name=".notdef#8"/>
+ <GlyphID id="154" name=".notdef#9"/>
+ <GlyphID id="155" name=".notdef#10"/>
+ <GlyphID id="156" name=".notdef#11"/>
+ <GlyphID id="157" name="ordfeminine"/>
+ <GlyphID id="158" name="ordmasculine"/>
+ <GlyphID id="159" name=".notdef#12"/>
+ <GlyphID id="160" name="ae"/>
+ <GlyphID id="161" name="oslash"/>
+ <GlyphID id="162" name="questiondown"/>
+ <GlyphID id="163" name="exclamdown"/>
+ <GlyphID id="164" name="logicalnot"/>
+ <GlyphID id="165" name=".notdef#13"/>
+ <GlyphID id="166" name="florin"/>
+ <GlyphID id="167" name=".notdef#14"/>
+ <GlyphID id="168" name=".notdef#15"/>
+ <GlyphID id="169" name="guillemotleft"/>
+ <GlyphID id="170" name="guillemotright"/>
+ <GlyphID id="171" name="ellipsis"/>
+ <GlyphID id="172" name=".notdef#16"/>
+ <GlyphID id="173" name="Agrave"/>
+ <GlyphID id="174" name="Atilde"/>
+ <GlyphID id="175" name="Otilde"/>
+ <GlyphID id="176" name="OE"/>
+ <GlyphID id="177" name="oe"/>
+ <GlyphID id="178" name="endash"/>
+ <GlyphID id="179" name="emdash"/>
+ <GlyphID id="180" name="quotedblleft"/>
+ <GlyphID id="181" name="quotedblright"/>
+ <GlyphID id="182" name="quoteleft"/>
+ <GlyphID id="183" name="quoteright"/>
+ <GlyphID id="184" name="divide"/>
+ <GlyphID id="185" name=".notdef#17"/>
+ <GlyphID id="186" name="ydieresis"/>
+ <GlyphID id="187" name="Ydieresis"/>
+ <GlyphID id="188" name="fraction"/>
+ <GlyphID id="189" name="currency"/>
+ <GlyphID id="190" name="guilsinglleft"/>
+ <GlyphID id="191" name="guilsinglright"/>
+ <GlyphID id="192" name="fi"/>
+ <GlyphID id="193" name="fl"/>
+ <GlyphID id="194" name="daggerdbl"/>
+ <GlyphID id="195" name="periodcentered"/>
+ <GlyphID id="196" name="quotesinglbase"/>
+ <GlyphID id="197" name="quotedblbase"/>
+ <GlyphID id="198" name="perthousand"/>
+ <GlyphID id="199" name="Acircumflex"/>
+ <GlyphID id="200" name="Ecircumflex"/>
+ <GlyphID id="201" name="Aacute"/>
+ <GlyphID id="202" name="Edieresis"/>
+ <GlyphID id="203" name="Egrave"/>
+ <GlyphID id="204" name="Iacute"/>
+ <GlyphID id="205" name="Icircumflex"/>
+ <GlyphID id="206" name="Idieresis"/>
+ <GlyphID id="207" name="Igrave"/>
+ <GlyphID id="208" name="Oacute"/>
+ <GlyphID id="209" name="Ocircumflex"/>
+ <GlyphID id="210" name="Euro"/>
+ <GlyphID id="211" name="Ograve"/>
+ <GlyphID id="212" name="Uacute"/>
+ <GlyphID id="213" name="Ucircumflex"/>
+ <GlyphID id="214" name="Ugrave"/>
+ <GlyphID id="215" name="dotlessi"/>
+ <GlyphID id="216" name="circumflex"/>
+ <GlyphID id="217" name="tilde"/>
+ <GlyphID id="218" name="macron"/>
+ <GlyphID id="219" name="breve"/>
+ <GlyphID id="220" name="dotaccent"/>
+ <GlyphID id="221" name="ring"/>
+ <GlyphID id="222" name="cedilla"/>
+ <GlyphID id="223" name="hungarumlaut"/>
+ <GlyphID id="224" name="ogonek"/>
+ <GlyphID id="225" name="caron"/>
+ <GlyphID id="226" name="Euro#1"/>
+ <GlyphID id="227" name="nonbreakingspace"/>
+ <GlyphID id="228" name="brokenbar"/>
+ <GlyphID id="229" name="sfthyphen"/>
+ <GlyphID id="230" name="macron#1"/>
+ <GlyphID id="231" name="twosuperior"/>
+ <GlyphID id="232" name="threesuperior"/>
+ <GlyphID id="233" name="periodcentered#1"/>
+ <GlyphID id="234" name="onesuperior"/>
+ <GlyphID id="235" name="onequarter"/>
+ <GlyphID id="236" name="onehalf"/>
+ <GlyphID id="237" name="threequarters"/>
+ <GlyphID id="238" name="Eth"/>
+ <GlyphID id="239" name="multiply"/>
+ <GlyphID id="240" name="Yacute"/>
+ <GlyphID id="241" name="Thorn"/>
+ <GlyphID id="242" name="eth"/>
+ <GlyphID id="243" name="yacute"/>
+ <GlyphID id="244" name="thorn"/>
+ <GlyphID id="245" name="Amacron"/>
+ <GlyphID id="246" name="amacron"/>
+ <GlyphID id="247" name="Abreve"/>
+ <GlyphID id="248" name="abreve"/>
+ <GlyphID id="249" name="Aogonek"/>
+ <GlyphID id="250" name="aogonek"/>
+ <GlyphID id="251" name="Cacute"/>
+ <GlyphID id="252" name="cacute"/>
+ <GlyphID id="253" name="Ccircumflex"/>
+ <GlyphID id="254" name="ccircumflex"/>
+ <GlyphID id="255" name="Cdotaccent"/>
+ <GlyphID id="256" name="cdotaccent"/>
+ <GlyphID id="257" name="Ccaron"/>
+ <GlyphID id="258" name="ccaron"/>
+ <GlyphID id="259" name="Dcaron"/>
+ <GlyphID id="260" name="dcaron"/>
+ <GlyphID id="261" name="Dcroat"/>
+ <GlyphID id="262" name="dcroat"/>
+ <GlyphID id="263" name="Emacron"/>
+ <GlyphID id="264" name="emacron"/>
+ <GlyphID id="265" name="Ebreve"/>
+ <GlyphID id="266" name="ebreve"/>
+ <GlyphID id="267" name="Edotaccent"/>
+ <GlyphID id="268" name="edotaccent"/>
+ <GlyphID id="269" name="Eogonek"/>
+ <GlyphID id="270" name="eogonek"/>
+ <GlyphID id="271" name="Ecaron"/>
+ <GlyphID id="272" name="ecaron"/>
+ <GlyphID id="273" name="Gcircumflex"/>
+ <GlyphID id="274" name="gcircumflex"/>
+ <GlyphID id="275" name="Gbreve"/>
+ <GlyphID id="276" name="gbreve"/>
+ <GlyphID id="277" name="Gdotaccent"/>
+ <GlyphID id="278" name="gdotaccent"/>
+ <GlyphID id="279" name="Gcommaaccent"/>
+ <GlyphID id="280" name="gcommaaccent"/>
+ <GlyphID id="281" name="Hcircumflex"/>
+ <GlyphID id="282" name="hcircumflex"/>
+ <GlyphID id="283" name="Hbar"/>
+ <GlyphID id="284" name="hbar"/>
+ <GlyphID id="285" name="Itilde"/>
+ <GlyphID id="286" name="itilde"/>
+ <GlyphID id="287" name="Imacron"/>
+ <GlyphID id="288" name="imacron"/>
+ <GlyphID id="289" name="Ibreve"/>
+ <GlyphID id="290" name="ibreve"/>
+ <GlyphID id="291" name="Iogonek"/>
+ <GlyphID id="292" name="iogonek"/>
+ <GlyphID id="293" name="Idotaccent"/>
+ <GlyphID id="294" name="IJ"/>
+ <GlyphID id="295" name="ij"/>
+ <GlyphID id="296" name="Jcircumflex"/>
+ <GlyphID id="297" name="jcircumflex"/>
+ <GlyphID id="298" name="Kcommaaccent"/>
+ <GlyphID id="299" name="kcommaaccent"/>
+ <GlyphID id="300" name="kgreenlandic"/>
+ <GlyphID id="301" name="Lacute"/>
+ <GlyphID id="302" name="lacute"/>
+ <GlyphID id="303" name="Lcommaaccent"/>
+ <GlyphID id="304" name="lcommaaccent"/>
+ <GlyphID id="305" name="Lcaron"/>
+ <GlyphID id="306" name="lcaron"/>
+ <GlyphID id="307" name="Ldot"/>
+ <GlyphID id="308" name="ldot"/>
+ <GlyphID id="309" name="Lslash"/>
+ <GlyphID id="310" name="lslash"/>
+ <GlyphID id="311" name="Nacute"/>
+ <GlyphID id="312" name="nacute"/>
+ <GlyphID id="313" name="Ncommaaccent"/>
+ <GlyphID id="314" name="ncommaaccent"/>
+ <GlyphID id="315" name="Ncaron"/>
+ <GlyphID id="316" name="ncaron"/>
+ <GlyphID id="317" name="napostrophe"/>
+ <GlyphID id="318" name="Eng"/>
+ <GlyphID id="319" name="eng"/>
+ <GlyphID id="320" name="Omacron"/>
+ <GlyphID id="321" name="omacron"/>
+ <GlyphID id="322" name="Obreve"/>
+ <GlyphID id="323" name="obreve"/>
+ <GlyphID id="324" name="Ohungarumlaut"/>
+ <GlyphID id="325" name="ohungarumlaut"/>
+ <GlyphID id="326" name="Racute"/>
+ <GlyphID id="327" name="racute"/>
+ <GlyphID id="328" name="Rcommaaccent"/>
+ <GlyphID id="329" name="rcommaaccent"/>
+ <GlyphID id="330" name="Rcaron"/>
+ <GlyphID id="331" name="rcaron"/>
+ <GlyphID id="332" name="Sacute"/>
+ <GlyphID id="333" name="sacute"/>
+ <GlyphID id="334" name="Scircumflex"/>
+ <GlyphID id="335" name="scircumflex"/>
+ <GlyphID id="336" name="Scedilla"/>
+ <GlyphID id="337" name="scedilla"/>
+ <GlyphID id="338" name="Scaron"/>
+ <GlyphID id="339" name="scaron"/>
+ <GlyphID id="340" name="Tcommaaccent"/>
+ <GlyphID id="341" name="tcommaaccent"/>
+ <GlyphID id="342" name="Tcaron"/>
+ <GlyphID id="343" name="tcaron"/>
+ <GlyphID id="344" name="Tbar"/>
+ <GlyphID id="345" name="tbar"/>
+ <GlyphID id="346" name="Utilde"/>
+ <GlyphID id="347" name="utilde"/>
+ <GlyphID id="348" name="Umacron"/>
+ <GlyphID id="349" name="umacron"/>
+ <GlyphID id="350" name="Ubreve"/>
+ <GlyphID id="351" name="ubreve"/>
+ <GlyphID id="352" name="Uring"/>
+ <GlyphID id="353" name="uring"/>
+ <GlyphID id="354" name="Uhungarumlaut"/>
+ <GlyphID id="355" name="uhungarumlaut"/>
+ <GlyphID id="356" name="Uogonek"/>
+ <GlyphID id="357" name="uogonek"/>
+ <GlyphID id="358" name="Wcircumflex"/>
+ <GlyphID id="359" name="wcircumflex"/>
+ <GlyphID id="360" name="Ycircumflex"/>
+ <GlyphID id="361" name="ycircumflex"/>
+ <GlyphID id="362" name="Zacute"/>
+ <GlyphID id="363" name="zacute"/>
+ <GlyphID id="364" name="Zdotaccent"/>
+ <GlyphID id="365" name="zdotaccent"/>
+ <GlyphID id="366" name="Zcaron"/>
+ <GlyphID id="367" name="zcaron"/>
+ <GlyphID id="368" name="longs"/>
+ <GlyphID id="369" name="Scommaaccent"/>
+ <GlyphID id="370" name="scommaaccent"/>
+ <GlyphID id="371" name="Tcommabelow"/>
+ <GlyphID id="372" name="tcommabelow"/>
+ <GlyphID id="373" name="Unterkomma"/>
+ <GlyphID id="374" name="semicolon#1"/>
+ <GlyphID id="375" name="anoteleia"/>
+ <GlyphID id="376" name="hyphen#1"/>
+ <GlyphID id="377" name="nbhyphen"/>
+ <GlyphID id="378" name="figuredash"/>
+ <GlyphID id="379" name="afii00208"/>
+ <GlyphID id="380" name="quotereversed"/>
+ <GlyphID id="381" name="radicalex"/>
+ <GlyphID id="382" name="estimated"/>
+ <GlyphID id="383" name="minus"/>
+ <GlyphID id="384" name="fraction#1"/>
+ <GlyphID id="385" name="dotmath"/>
+ <GlyphID id="386" name="fi#1"/>
+ <GlyphID id="387" name="fl#1"/>
+ <GlyphID id="388" name="foursuperiour"/>
+ <GlyphID id="389" name="onesuperiour"/>
+ <GlyphID id="390" name="twosuperiour"/>
+ <GlyphID id="391" name="threesuperiour"/>
+ <GlyphID id="392" name="foursuperiour#1"/>
+ <GlyphID id="393" name="dotlessj"/>
+ <GlyphID id="394" name=".notdef#18"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.19999694824"/>
+ <checkSumAdjustment value="0x4e0d8101"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00001111"/>
+ <unitsPerEm value="2048"/>
+ <created value="Fri Oct 12 14:05:57 2001"/>
+ <modified value="Fri Oct 12 10:47:54 2001"/>
+ <xMin value="0"/>
+ <yMin value="-432"/>
+ <xMax value="1229"/>
+ <yMax value="2033"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="12"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="2033"/>
+ <descent value="-432"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="1229"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="0"/>
+ <xMaxExtent value="1229"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="395"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="395"/>
+ <maxPoints value="79"/>
+ <maxContours value="7"/>
+ <maxCompositePoints value="85"/>
+ <maxCompositeContours value="4"/>
+ <maxZones value="2"/>
+ <maxTwilightPoints value="4"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="15"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="2048"/>
+ <maxSizeOfInstructions value="197"/>
+ <maxComponentElements value="2"/>
+ <maxComponentDepth value="1"/>
+ </maxp>
+
+ <OS_2>
+ <version value="2"/>
+ <xAvgCharWidth value="1229"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000000"/>
+ <ySubscriptXSize value="1434"/>
+ <ySubscriptYSize value="1331"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="283"/>
+ <ySuperscriptXSize value="1434"/>
+ <ySuperscriptYSize value="1331"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="977"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="0"/>
+ <sFamilyClass value="1285"/>
+ <panose>
+ <bFamilyType value="2"/>
+ <bSerifStyle value="6"/>
+ <bWeight value="6"/>
+ <bProportion value="9"/>
+ <bContrast value="5"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000111"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000010"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="B&amp;H "/>
+ <fsSelection value="00000000 01000000"/>
+ <fsFirstCharIndex value="32"/>
+ <fsLastCharIndex value="64258"/>
+ <sTypoAscender value="1604"/>
+ <sTypoDescender value="-420"/>
+ <sTypoLineGap value="167"/>
+ <usWinAscent value="1935"/>
+ <usWinDescent value="432"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 10010011"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="0"/>
+ <sCapHeight value="0"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="0"/>
+ <usMaxContex value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="1229" lsb="123"/>
+ <mtx name=".notdef#1" width="0" lsb="0"/>
+ <mtx name=".notdef#10" width="1229" lsb="0"/>
+ <mtx name=".notdef#11" width="1229" lsb="0"/>
+ <mtx name=".notdef#12" width="1229" lsb="0"/>
+ <mtx name=".notdef#13" width="1229" lsb="0"/>
+ <mtx name=".notdef#14" width="1229" lsb="0"/>
+ <mtx name=".notdef#15" width="1229" lsb="0"/>
+ <mtx name=".notdef#16" width="1229" lsb="0"/>
+ <mtx name=".notdef#17" width="1229" lsb="0"/>
+ <mtx name=".notdef#18" width="1229" lsb="0"/>
+ <mtx name=".notdef#2" width="1229" lsb="0"/>
+ <mtx name=".notdef#3" width="1229" lsb="0"/>
+ <mtx name=".notdef#4" width="1229" lsb="0"/>
+ <mtx name=".notdef#5" width="1229" lsb="0"/>
+ <mtx name=".notdef#6" width="1229" lsb="0"/>
+ <mtx name=".notdef#7" width="1229" lsb="0"/>
+ <mtx name=".notdef#8" width="1229" lsb="0"/>
+ <mtx name=".notdef#9" width="1229" lsb="0"/>
+ <mtx name="A" width="1229" lsb="25"/>
+ <mtx name="AE" width="1229" lsb="12"/>
+ <mtx name="Aacute" width="1229" lsb="25"/>
+ <mtx name="Abreve" width="1229" lsb="25"/>
+ <mtx name="Acircumflex" width="1229" lsb="25"/>
+ <mtx name="Adieresis" width="1229" lsb="25"/>
+ <mtx name="Agrave" width="1229" lsb="25"/>
+ <mtx name="Amacron" width="1229" lsb="25"/>
+ <mtx name="Aogonek" width="1229" lsb="25"/>
+ <mtx name="Aring" width="1229" lsb="25"/>
+ <mtx name="Atilde" width="1229" lsb="25"/>
+ <mtx name="B" width="1229" lsb="74"/>
+ <mtx name="C" width="1229" lsb="123"/>
+ <mtx name="Cacute" width="1229" lsb="123"/>
+ <mtx name="Ccaron" width="1229" lsb="123"/>
+ <mtx name="Ccedilla" width="1229" lsb="123"/>
+ <mtx name="Ccircumflex" width="1229" lsb="123"/>
+ <mtx name="Cdotaccent" width="1229" lsb="123"/>
+ <mtx name="D" width="1229" lsb="49"/>
+ <mtx name="Dcaron" width="1229" lsb="49"/>
+ <mtx name="Dcroat" width="1229" lsb="49"/>
+ <mtx name="E" width="1229" lsb="74"/>
+ <mtx name="Eacute" width="1229" lsb="74"/>
+ <mtx name="Ebreve" width="1229" lsb="74"/>
+ <mtx name="Ecaron" width="1229" lsb="74"/>
+ <mtx name="Ecircumflex" width="1229" lsb="74"/>
+ <mtx name="Edieresis" width="1229" lsb="74"/>
+ <mtx name="Edotaccent" width="1229" lsb="74"/>
+ <mtx name="Egrave" width="1229" lsb="74"/>
+ <mtx name="Emacron" width="1229" lsb="74"/>
+ <mtx name="Eng" width="1229" lsb="74"/>
+ <mtx name="Eogonek" width="1229" lsb="74"/>
+ <mtx name="Eth" width="1229" lsb="49"/>
+ <mtx name="Euro" width="1229" lsb="6"/>
+ <mtx name="Euro#1" width="1229" lsb="6"/>
+ <mtx name="F" width="1229" lsb="111"/>
+ <mtx name="G" width="1229" lsb="74"/>
+ <mtx name="Gbreve" width="1229" lsb="74"/>
+ <mtx name="Gcircumflex" width="1229" lsb="74"/>
+ <mtx name="Gcommaaccent" width="1229" lsb="74"/>
+ <mtx name="Gdotaccent" width="1229" lsb="74"/>
+ <mtx name="H" width="1229" lsb="62"/>
+ <mtx name="Hbar" width="1229" lsb="37"/>
+ <mtx name="Hcircumflex" width="1229" lsb="62"/>
+ <mtx name="I" width="1229" lsb="160"/>
+ <mtx name="IJ" width="1229" lsb="45"/>
+ <mtx name="Iacute" width="1229" lsb="160"/>
+ <mtx name="Ibreve" width="1229" lsb="160"/>
+ <mtx name="Icircumflex" width="1229" lsb="160"/>
+ <mtx name="Idieresis" width="1229" lsb="160"/>
+ <mtx name="Idotaccent" width="1229" lsb="160"/>
+ <mtx name="Igrave" width="1229" lsb="160"/>
+ <mtx name="Imacron" width="1229" lsb="160"/>
+ <mtx name="Iogonek" width="1229" lsb="160"/>
+ <mtx name="Itilde" width="1229" lsb="160"/>
+ <mtx name="J" width="1229" lsb="111"/>
+ <mtx name="Jcircumflex" width="1229" lsb="111"/>
+ <mtx name="K" width="1229" lsb="74"/>
+ <mtx name="Kcommaaccent" width="1229" lsb="74"/>
+ <mtx name="L" width="1229" lsb="86"/>
+ <mtx name="Lacute" width="1229" lsb="86"/>
+ <mtx name="Lcaron" width="1229" lsb="86"/>
+ <mtx name="Lcommaaccent" width="1229" lsb="86"/>
+ <mtx name="Ldot" width="1229" lsb="86"/>
+ <mtx name="Lslash" width="1229" lsb="86"/>
+ <mtx name="M" width="1229" lsb="25"/>
+ <mtx name="N" width="1229" lsb="74"/>
+ <mtx name="Nacute" width="1229" lsb="74"/>
+ <mtx name="Ncaron" width="1229" lsb="74"/>
+ <mtx name="Ncommaaccent" width="1229" lsb="74"/>
+ <mtx name="Ntilde" width="1229" lsb="74"/>
+ <mtx name="O" width="1229" lsb="62"/>
+ <mtx name="OE" width="1229" lsb="37"/>
+ <mtx name="Oacute" width="1229" lsb="62"/>
+ <mtx name="Obreve" width="1229" lsb="62"/>
+ <mtx name="Ocircumflex" width="1229" lsb="62"/>
+ <mtx name="Odieresis" width="1229" lsb="62"/>
+ <mtx name="Ograve" width="1229" lsb="62"/>
+ <mtx name="Ohungarumlaut" width="1229" lsb="62"/>
+ <mtx name="Omacron" width="1229" lsb="62"/>
+ <mtx name="Oslash" width="1229" lsb="62"/>
+ <mtx name="Otilde" width="1229" lsb="62"/>
+ <mtx name="P" width="1229" lsb="86"/>
+ <mtx name="Q" width="1229" lsb="62"/>
+ <mtx name="R" width="1229" lsb="86"/>
+ <mtx name="Racute" width="1229" lsb="86"/>
+ <mtx name="Rcaron" width="1229" lsb="86"/>
+ <mtx name="Rcommaaccent" width="1229" lsb="86"/>
+ <mtx name="S" width="1229" lsb="151"/>
+ <mtx name="Sacute" width="1229" lsb="151"/>
+ <mtx name="Scaron" width="1229" lsb="151"/>
+ <mtx name="Scedilla" width="1229" lsb="151"/>
+ <mtx name="Scircumflex" width="1229" lsb="151"/>
+ <mtx name="Scommaaccent" width="1229" lsb="151"/>
+ <mtx name="T" width="1229" lsb="62"/>
+ <mtx name="Tbar" width="1229" lsb="62"/>
+ <mtx name="Tcaron" width="1229" lsb="62"/>
+ <mtx name="Tcommaaccent" width="1229" lsb="62"/>
+ <mtx name="Tcommabelow" width="1229" lsb="62"/>
+ <mtx name="Thorn" width="1229" lsb="86"/>
+ <mtx name="U" width="1229" lsb="62"/>
+ <mtx name="Uacute" width="1229" lsb="62"/>
+ <mtx name="Ubreve" width="1229" lsb="62"/>
+ <mtx name="Ucircumflex" width="1229" lsb="62"/>
+ <mtx name="Udieresis" width="1229" lsb="62"/>
+ <mtx name="Ugrave" width="1229" lsb="62"/>
+ <mtx name="Uhungarumlaut" width="1229" lsb="62"/>
+ <mtx name="Umacron" width="1229" lsb="62"/>
+ <mtx name="Unterkomma" width="1229" lsb="464"/>
+ <mtx name="Uogonek" width="1229" lsb="62"/>
+ <mtx name="Uring" width="1229" lsb="62"/>
+ <mtx name="Utilde" width="1229" lsb="62"/>
+ <mtx name="V" width="1229" lsb="26"/>
+ <mtx name="W" width="1229" lsb="23"/>
+ <mtx name="Wcircumflex" width="1229" lsb="23"/>
+ <mtx name="X" width="1229" lsb="49"/>
+ <mtx name="Y" width="1229" lsb="27"/>
+ <mtx name="Yacute" width="1229" lsb="27"/>
+ <mtx name="Ycircumflex" width="1229" lsb="27"/>
+ <mtx name="Ydieresis" width="1229" lsb="27"/>
+ <mtx name="Z" width="1229" lsb="148"/>
+ <mtx name="Zacute" width="1229" lsb="148"/>
+ <mtx name="Zcaron" width="1229" lsb="148"/>
+ <mtx name="Zdotaccent" width="1229" lsb="148"/>
+ <mtx name="a" width="1229" lsb="148"/>
+ <mtx name="aacute" width="1229" lsb="148"/>
+ <mtx name="abreve" width="1229" lsb="148"/>
+ <mtx name="acircumflex" width="1229" lsb="148"/>
+ <mtx name="acute" width="1229" lsb="392"/>
+ <mtx name="adieresis" width="1229" lsb="148"/>
+ <mtx name="ae" width="1229" lsb="37"/>
+ <mtx name="afii00208" width="1229" lsb="0"/>
+ <mtx name="agrave" width="1229" lsb="148"/>
+ <mtx name="amacron" width="1229" lsb="148"/>
+ <mtx name="ampersand" width="1229" lsb="57"/>
+ <mtx name="anoteleia" width="1229" lsb="491"/>
+ <mtx name="aogonek" width="1229" lsb="148"/>
+ <mtx name="aring" width="1229" lsb="148"/>
+ <mtx name="asciicircum" width="1229" lsb="146"/>
+ <mtx name="asciitilde" width="1229" lsb="121"/>
+ <mtx name="asterisk" width="1229" lsb="161"/>
+ <mtx name="at" width="1229" lsb="87"/>
+ <mtx name="atilde" width="1229" lsb="148"/>
+ <mtx name="b" width="1229" lsb="62"/>
+ <mtx name="backslash" width="1229" lsb="99"/>
+ <mtx name="bar" width="1229" lsb="540"/>
+ <mtx name="braceleft" width="1229" lsb="183"/>
+ <mtx name="braceright" width="1229" lsb="227"/>
+ <mtx name="bracketleft" width="1229" lsb="395"/>
+ <mtx name="bracketright" width="1229" lsb="291"/>
+ <mtx name="breve" width="1229" lsb="269"/>
+ <mtx name="brokenbar" width="1229" lsb="540"/>
+ <mtx name="bullet" width="1229" lsb="318"/>
+ <mtx name="c" width="1229" lsb="148"/>
+ <mtx name="cacute" width="1229" lsb="148"/>
+ <mtx name="caron" width="1229" lsb="248"/>
+ <mtx name="ccaron" width="1229" lsb="148"/>
+ <mtx name="ccedilla" width="1229" lsb="148"/>
+ <mtx name="ccircumflex" width="1229" lsb="148"/>
+ <mtx name="cdotaccent" width="1229" lsb="148"/>
+ <mtx name="cedilla" width="1229" lsb="441"/>
+ <mtx name="cent" width="1229" lsb="173"/>
+ <mtx name="circumflex" width="1229" lsb="248"/>
+ <mtx name="colon" width="1229" lsb="466"/>
+ <mtx name="comma" width="1229" lsb="466"/>
+ <mtx name="copyright" width="1229" lsb="62"/>
+ <mtx name="currency" width="1229" lsb="85"/>
+ <mtx name="d" width="1229" lsb="111"/>
+ <mtx name="dagger" width="1229" lsb="170"/>
+ <mtx name="daggerdbl" width="1229" lsb="170"/>
+ <mtx name="dcaron" width="1229" lsb="111"/>
+ <mtx name="dcroat" width="1229" lsb="111"/>
+ <mtx name="degree" width="1229" lsb="318"/>
+ <mtx name="dieresis" width="1229" lsb="281"/>
+ <mtx name="divide" width="1229" lsb="99"/>
+ <mtx name="dollar" width="1229" lsb="143"/>
+ <mtx name="dotaccent" width="1229" lsb="516"/>
+ <mtx name="dotlessi" width="1229" lsb="148"/>
+ <mtx name="dotlessj" width="1229" lsb="159"/>
+ <mtx name="dotmath" width="1229" lsb="491"/>
+ <mtx name="e" width="1229" lsb="123"/>
+ <mtx name="eacute" width="1229" lsb="123"/>
+ <mtx name="ebreve" width="1229" lsb="123"/>
+ <mtx name="ecaron" width="1229" lsb="123"/>
+ <mtx name="ecircumflex" width="1229" lsb="123"/>
+ <mtx name="edieresis" width="1229" lsb="123"/>
+ <mtx name="edotaccent" width="1229" lsb="123"/>
+ <mtx name="egrave" width="1229" lsb="123"/>
+ <mtx name="eight" width="1229" lsb="120"/>
+ <mtx name="ellipsis" width="1229" lsb="81"/>
+ <mtx name="emacron" width="1229" lsb="123"/>
+ <mtx name="emdash" width="1229" lsb="0"/>
+ <mtx name="endash" width="1229" lsb="121"/>
+ <mtx name="eng" width="1229" lsb="69"/>
+ <mtx name="eogonek" width="1229" lsb="123"/>
+ <mtx name="equal" width="1229" lsb="99"/>
+ <mtx name="estimated" width="1229" lsb="123"/>
+ <mtx name="eth" width="1229" lsb="111"/>
+ <mtx name="exclam" width="1229" lsb="491"/>
+ <mtx name="exclamdown" width="1229" lsb="491"/>
+ <mtx name="f" width="1229" lsb="148"/>
+ <mtx name="fi" width="1229" lsb="69"/>
+ <mtx name="fi#1" width="1229" lsb="69"/>
+ <mtx name="figuredash" width="1229" lsb="121"/>
+ <mtx name="five" width="1229" lsb="249"/>
+ <mtx name="fl" width="1229" lsb="69"/>
+ <mtx name="fl#1" width="1229" lsb="69"/>
+ <mtx name="florin" width="1229" lsb="84"/>
+ <mtx name="four" width="1229" lsb="84"/>
+ <mtx name="foursuperiour" width="1229" lsb="284"/>
+ <mtx name="foursuperiour#1" width="1229" lsb="155"/>
+ <mtx name="fraction" width="1229" lsb="155"/>
+ <mtx name="fraction#1" width="1229" lsb="155"/>
+ <mtx name="g" width="1229" lsb="86"/>
+ <mtx name="gbreve" width="1229" lsb="86"/>
+ <mtx name="gcircumflex" width="1229" lsb="86"/>
+ <mtx name="gcommaaccent" width="1229" lsb="86"/>
+ <mtx name="gdotaccent" width="1229" lsb="86"/>
+ <mtx name="germandbls" width="1229" lsb="62"/>
+ <mtx name="grave" width="1229" lsb="392"/>
+ <mtx name="greater" width="1229" lsb="99"/>
+ <mtx name="guillemotleft" width="1229" lsb="82"/>
+ <mtx name="guillemotright" width="1229" lsb="123"/>
+ <mtx name="guilsinglleft" width="1229" lsb="234"/>
+ <mtx name="guilsinglright" width="1229" lsb="283"/>
+ <mtx name="h" width="1229" lsb="69"/>
+ <mtx name="hbar" width="1229" lsb="69"/>
+ <mtx name="hcircumflex" width="1229" lsb="69"/>
+ <mtx name="hungarumlaut" width="1229" lsb="223"/>
+ <mtx name="hyphen" width="1229" lsb="148"/>
+ <mtx name="hyphen#1" width="1229" lsb="148"/>
+ <mtx name="i" width="1229" lsb="148"/>
+ <mtx name="iacute" width="1229" lsb="148"/>
+ <mtx name="ibreve" width="1229" lsb="148"/>
+ <mtx name="icircumflex" width="1229" lsb="148"/>
+ <mtx name="idieresis" width="1229" lsb="148"/>
+ <mtx name="igrave" width="1229" lsb="148"/>
+ <mtx name="ij" width="1229" lsb="57"/>
+ <mtx name="imacron" width="1229" lsb="148"/>
+ <mtx name="iogonek" width="1229" lsb="148"/>
+ <mtx name="itilde" width="1229" lsb="148"/>
+ <mtx name="j" width="1229" lsb="159"/>
+ <mtx name="jcircumflex" width="1229" lsb="159"/>
+ <mtx name="k" width="1229" lsb="74"/>
+ <mtx name="kcommaaccent" width="1229" lsb="74"/>
+ <mtx name="kgreenlandic" width="1229" lsb="74"/>
+ <mtx name="l" width="1229" lsb="148"/>
+ <mtx name="lacute" width="1229" lsb="148"/>
+ <mtx name="lcaron" width="1229" lsb="123"/>
+ <mtx name="lcommaaccent" width="1229" lsb="148"/>
+ <mtx name="ldot" width="1229" lsb="123"/>
+ <mtx name="less" width="1229" lsb="99"/>
+ <mtx name="logicalnot" width="1229" lsb="99"/>
+ <mtx name="longs" width="1229" lsb="148"/>
+ <mtx name="lslash" width="1229" lsb="148"/>
+ <mtx name="m" width="1229" lsb="26"/>
+ <mtx name="macron" width="1229" lsb="269"/>
+ <mtx name="macron#1" width="1229" lsb="0"/>
+ <mtx name="minus" width="1229" lsb="99"/>
+ <mtx name="mu" width="1229" lsb="68"/>
+ <mtx name="multiply" width="1229" lsb="99"/>
+ <mtx name="n" width="1229" lsb="69"/>
+ <mtx name="nacute" width="1229" lsb="69"/>
+ <mtx name="napostrophe" width="1229" lsb="8"/>
+ <mtx name="nbhyphen" width="1229" lsb="148"/>
+ <mtx name="ncaron" width="1229" lsb="69"/>
+ <mtx name="ncommaaccent" width="1229" lsb="69"/>
+ <mtx name="nine" width="1229" lsb="96"/>
+ <mtx name="nonbreakingspace" width="1229" lsb="0"/>
+ <mtx name="ntilde" width="1229" lsb="69"/>
+ <mtx name="numbersign" width="1229" lsb="41"/>
+ <mtx name="o" width="1229" lsb="111"/>
+ <mtx name="oacute" width="1229" lsb="111"/>
+ <mtx name="obreve" width="1229" lsb="111"/>
+ <mtx name="ocircumflex" width="1229" lsb="111"/>
+ <mtx name="odieresis" width="1229" lsb="111"/>
+ <mtx name="oe" width="1229" lsb="49"/>
+ <mtx name="ogonek" width="1229" lsb="444"/>
+ <mtx name="ograve" width="1229" lsb="111"/>
+ <mtx name="ohungarumlaut" width="1229" lsb="111"/>
+ <mtx name="omacron" width="1229" lsb="111"/>
+ <mtx name="one" width="1229" lsb="112"/>
+ <mtx name="onehalf" width="1229" lsb="43"/>
+ <mtx name="onequarter" width="1229" lsb="43"/>
+ <mtx name="onesuperior" width="1229" lsb="266"/>
+ <mtx name="onesuperiour" width="1229" lsb="407"/>
+ <mtx name="ordfeminine" width="1229" lsb="136"/>
+ <mtx name="ordmasculine" width="1229" lsb="148"/>
+ <mtx name="oslash" width="1229" lsb="111"/>
+ <mtx name="otilde" width="1229" lsb="111"/>
+ <mtx name="p" width="1229" lsb="62"/>
+ <mtx name="paragraph" width="1229" lsb="100"/>
+ <mtx name="parenleft" width="1229" lsb="321"/>
+ <mtx name="parenright" width="1229" lsb="247"/>
+ <mtx name="percent" width="1229" lsb="21"/>
+ <mtx name="period" width="1229" lsb="466"/>
+ <mtx name="periodcentered" width="1229" lsb="491"/>
+ <mtx name="periodcentered#1" width="1229" lsb="491"/>
+ <mtx name="perthousand" width="1229" lsb="12"/>
+ <mtx name="plus" width="1229" lsb="99"/>
+ <mtx name="plusminus" width="1229" lsb="99"/>
+ <mtx name="q" width="1229" lsb="111"/>
+ <mtx name="question" width="1229" lsb="202"/>
+ <mtx name="questiondown" width="1229" lsb="151"/>
+ <mtx name="quotedbl" width="1229" lsb="244"/>
+ <mtx name="quotedblbase" width="1229" lsb="257"/>
+ <mtx name="quotedblleft" width="1229" lsb="232"/>
+ <mtx name="quotedblright" width="1229" lsb="257"/>
+ <mtx name="quoteleft" width="1229" lsb="454"/>
+ <mtx name="quotereversed" width="1229" lsb="0"/>
+ <mtx name="quoteright" width="1229" lsb="479"/>
+ <mtx name="quotesinglbase" width="1229" lsb="479"/>
+ <mtx name="quotesingle" width="1229" lsb="466"/>
+ <mtx name="r" width="1229" lsb="74"/>
+ <mtx name="racute" width="1229" lsb="74"/>
+ <mtx name="radicalex" width="1229" lsb="0"/>
+ <mtx name="rcaron" width="1229" lsb="74"/>
+ <mtx name="rcommaaccent" width="1229" lsb="74"/>
+ <mtx name="registered" width="1229" lsb="62"/>
+ <mtx name="ring" width="1229" lsb="388"/>
+ <mtx name="s" width="1229" lsb="173"/>
+ <mtx name="sacute" width="1229" lsb="173"/>
+ <mtx name="scaron" width="1229" lsb="173"/>
+ <mtx name="scedilla" width="1229" lsb="173"/>
+ <mtx name="scircumflex" width="1229" lsb="173"/>
+ <mtx name="scommaaccent" width="1229" lsb="173"/>
+ <mtx name="section" width="1229" lsb="154"/>
+ <mtx name="semicolon" width="1229" lsb="466"/>
+ <mtx name="semicolon#1" width="1229" lsb="466"/>
+ <mtx name="seven" width="1229" lsb="145"/>
+ <mtx name="sfthyphen" width="1229" lsb="148"/>
+ <mtx name="six" width="1229" lsb="122"/>
+ <mtx name="slash" width="1229" lsb="99"/>
+ <mtx name="space" width="1229" lsb="0"/>
+ <mtx name="sterling" width="1229" lsb="149"/>
+ <mtx name="t" width="1229" lsb="119"/>
+ <mtx name="tbar" width="1229" lsb="119"/>
+ <mtx name="tcaron" width="1229" lsb="119"/>
+ <mtx name="tcommaaccent" width="1229" lsb="119"/>
+ <mtx name="tcommabelow" width="1229" lsb="119"/>
+ <mtx name="thorn" width="1229" lsb="62"/>
+ <mtx name="three" width="1229" lsb="185"/>
+ <mtx name="threequarters" width="1229" lsb="37"/>
+ <mtx name="threesuperior" width="1229" lsb="263"/>
+ <mtx name="threesuperiour" width="1229" lsb="365"/>
+ <mtx name="tilde" width="1229" lsb="281"/>
+ <mtx name="trademark" width="1229" lsb="43"/>
+ <mtx name="two" width="1229" lsb="133"/>
+ <mtx name="twosuperior" width="1229" lsb="257"/>
+ <mtx name="twosuperiour" width="1229" lsb="361"/>
+ <mtx name="u" width="1229" lsb="68"/>
+ <mtx name="uacute" width="1229" lsb="68"/>
+ <mtx name="ubreve" width="1229" lsb="68"/>
+ <mtx name="ucircumflex" width="1229" lsb="68"/>
+ <mtx name="udieresis" width="1229" lsb="68"/>
+ <mtx name="ugrave" width="1229" lsb="68"/>
+ <mtx name="uhungarumlaut" width="1229" lsb="68"/>
+ <mtx name="umacron" width="1229" lsb="68"/>
+ <mtx name="underscore" width="1229" lsb="0"/>
+ <mtx name="uogonek" width="1229" lsb="68"/>
+ <mtx name="uring" width="1229" lsb="68"/>
+ <mtx name="utilde" width="1229" lsb="68"/>
+ <mtx name="v" width="1229" lsb="55"/>
+ <mtx name="w" width="1229" lsb="23"/>
+ <mtx name="wcircumflex" width="1229" lsb="23"/>
+ <mtx name="x" width="1229" lsb="59"/>
+ <mtx name="y" width="1229" lsb="55"/>
+ <mtx name="yacute" width="1229" lsb="55"/>
+ <mtx name="ycircumflex" width="1229" lsb="55"/>
+ <mtx name="ydieresis" width="1229" lsb="55"/>
+ <mtx name="yen" width="1229" lsb="49"/>
+ <mtx name="z" width="1229" lsb="123"/>
+ <mtx name="zacute" width="1229" lsb="123"/>
+ <mtx name="zcaron" width="1229" lsb="123"/>
+ <mtx name="zdotaccent" width="1229" lsb="123"/>
+ <mtx name="zero" width="1229" lsb="96"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_0 platformID="1" platEncID="0" language="0">
+ <map code="0x0" name=".notdef#1"/>
+ <map code="0x1" name=".notdef"/>
+ <map code="0x2" name=".notdef"/>
+ <map code="0x3" name=".notdef"/>
+ <map code="0x4" name=".notdef"/>
+ <map code="0x5" name=".notdef"/>
+ <map code="0x6" name=".notdef"/>
+ <map code="0x7" name=".notdef"/>
+ <map code="0x8" name=".notdef#1"/>
+ <map code="0x9" name="space"/>
+ <map code="0xa" name=".notdef"/>
+ <map code="0xb" name=".notdef"/>
+ <map code="0xc" name=".notdef"/>
+ <map code="0xd" name=".notdef#2"/>
+ <map code="0xe" name=".notdef"/>
+ <map code="0xf" name=".notdef"/>
+ <map code="0x10" name=".notdef"/>
+ <map code="0x11" name=".notdef"/>
+ <map code="0x12" name=".notdef"/>
+ <map code="0x13" name=".notdef"/>
+ <map code="0x14" name=".notdef"/>
+ <map code="0x15" name=".notdef"/>
+ <map code="0x16" name=".notdef"/>
+ <map code="0x17" name=".notdef"/>
+ <map code="0x18" name=".notdef"/>
+ <map code="0x19" name=".notdef"/>
+ <map code="0x1a" name=".notdef"/>
+ <map code="0x1b" name=".notdef"/>
+ <map code="0x1c" name=".notdef"/>
+ <map code="0x1d" name=".notdef#1"/>
+ <map code="0x1e" name=".notdef"/>
+ <map code="0x1f" name=".notdef"/>
+ <map code="0x20" name="space"/>
+ <map code="0x21" name="exclam"/>
+ <map code="0x22" name="quotedbl"/>
+ <map code="0x23" name="numbersign"/>
+ <map code="0x24" name="dollar"/>
+ <map code="0x25" name="percent"/>
+ <map code="0x26" name="ampersand"/>
+ <map code="0x27" name="quotesingle"/>
+ <map code="0x28" name="parenleft"/>
+ <map code="0x29" name="parenright"/>
+ <map code="0x2a" name="asterisk"/>
+ <map code="0x2b" name="plus"/>
+ <map code="0x2c" name="comma"/>
+ <map code="0x2d" name="hyphen"/>
+ <map code="0x2e" name="period"/>
+ <map code="0x2f" name="slash"/>
+ <map code="0x30" name="zero"/>
+ <map code="0x31" name="one"/>
+ <map code="0x32" name="two"/>
+ <map code="0x33" name="three"/>
+ <map code="0x34" name="four"/>
+ <map code="0x35" name="five"/>
+ <map code="0x36" name="six"/>
+ <map code="0x37" name="seven"/>
+ <map code="0x38" name="eight"/>
+ <map code="0x39" name="nine"/>
+ <map code="0x3a" name="colon"/>
+ <map code="0x3b" name="semicolon"/>
+ <map code="0x3c" name="less"/>
+ <map code="0x3d" name="equal"/>
+ <map code="0x3e" name="greater"/>
+ <map code="0x3f" name="question"/>
+ <map code="0x40" name="at"/>
+ <map code="0x41" name="A"/>
+ <map code="0x42" name="B"/>
+ <map code="0x43" name="C"/>
+ <map code="0x44" name="D"/>
+ <map code="0x45" name="E"/>
+ <map code="0x46" name="F"/>
+ <map code="0x47" name="G"/>
+ <map code="0x48" name="H"/>
+ <map code="0x49" name="I"/>
+ <map code="0x4a" name="J"/>
+ <map code="0x4b" name="K"/>
+ <map code="0x4c" name="L"/>
+ <map code="0x4d" name="M"/>
+ <map code="0x4e" name="N"/>
+ <map code="0x4f" name="O"/>
+ <map code="0x50" name="P"/>
+ <map code="0x51" name="Q"/>
+ <map code="0x52" name="R"/>
+ <map code="0x53" name="S"/>
+ <map code="0x54" name="T"/>
+ <map code="0x55" name="U"/>
+ <map code="0x56" name="V"/>
+ <map code="0x57" name="W"/>
+ <map code="0x58" name="X"/>
+ <map code="0x59" name="Y"/>
+ <map code="0x5a" name="Z"/>
+ <map code="0x5b" name="bracketleft"/>
+ <map code="0x5c" name="backslash"/>
+ <map code="0x5d" name="bracketright"/>
+ <map code="0x5e" name="asciicircum"/>
+ <map code="0x5f" name="underscore"/>
+ <map code="0x60" name="grave"/>
+ <map code="0x61" name="a"/>
+ <map code="0x62" name="b"/>
+ <map code="0x63" name="c"/>
+ <map code="0x64" name="d"/>
+ <map code="0x65" name="e"/>
+ <map code="0x66" name="f"/>
+ <map code="0x67" name="g"/>
+ <map code="0x68" name="h"/>
+ <map code="0x69" name="i"/>
+ <map code="0x6a" name="j"/>
+ <map code="0x6b" name="k"/>
+ <map code="0x6c" name="l"/>
+ <map code="0x6d" name="m"/>
+ <map code="0x6e" name="n"/>
+ <map code="0x6f" name="o"/>
+ <map code="0x70" name="p"/>
+ <map code="0x71" name="q"/>
+ <map code="0x72" name="r"/>
+ <map code="0x73" name="s"/>
+ <map code="0x74" name="t"/>
+ <map code="0x75" name="u"/>
+ <map code="0x76" name="v"/>
+ <map code="0x77" name="w"/>
+ <map code="0x78" name="x"/>
+ <map code="0x79" name="y"/>
+ <map code="0x7a" name="z"/>
+ <map code="0x7b" name="braceleft"/>
+ <map code="0x7c" name="bar"/>
+ <map code="0x7d" name="braceright"/>
+ <map code="0x7e" name="asciitilde"/>
+ <map code="0x7f" name=".notdef"/>
+ <map code="0x80" name="Adieresis"/>
+ <map code="0x81" name="Aring"/>
+ <map code="0x82" name="Ccedilla"/>
+ <map code="0x83" name="Eacute"/>
+ <map code="0x84" name="Ntilde"/>
+ <map code="0x85" name="Odieresis"/>
+ <map code="0x86" name="Udieresis"/>
+ <map code="0x87" name="aacute"/>
+ <map code="0x88" name="agrave"/>
+ <map code="0x89" name="acircumflex"/>
+ <map code="0x8a" name="adieresis"/>
+ <map code="0x8b" name="atilde"/>
+ <map code="0x8c" name="aring"/>
+ <map code="0x8d" name="ccedilla"/>
+ <map code="0x8e" name="eacute"/>
+ <map code="0x8f" name="egrave"/>
+ <map code="0x90" name="ecircumflex"/>
+ <map code="0x91" name="edieresis"/>
+ <map code="0x92" name="iacute"/>
+ <map code="0x93" name="igrave"/>
+ <map code="0x94" name="icircumflex"/>
+ <map code="0x95" name="idieresis"/>
+ <map code="0x96" name="ntilde"/>
+ <map code="0x97" name="oacute"/>
+ <map code="0x98" name="ograve"/>
+ <map code="0x99" name="ocircumflex"/>
+ <map code="0x9a" name="odieresis"/>
+ <map code="0x9b" name="otilde"/>
+ <map code="0x9c" name="uacute"/>
+ <map code="0x9d" name="ugrave"/>
+ <map code="0x9e" name="ucircumflex"/>
+ <map code="0x9f" name="udieresis"/>
+ <map code="0xa0" name="dagger"/>
+ <map code="0xa1" name="degree"/>
+ <map code="0xa2" name="cent"/>
+ <map code="0xa3" name="sterling"/>
+ <map code="0xa4" name="section"/>
+ <map code="0xa5" name="bullet"/>
+ <map code="0xa6" name="paragraph"/>
+ <map code="0xa7" name="germandbls"/>
+ <map code="0xa8" name="registered"/>
+ <map code="0xa9" name="copyright"/>
+ <map code="0xaa" name="trademark"/>
+ <map code="0xab" name="acute"/>
+ <map code="0xac" name="dieresis"/>
+ <map code="0xad" name=".notdef"/>
+ <map code="0xae" name="AE"/>
+ <map code="0xaf" name="Oslash"/>
+ <map code="0xb0" name=".notdef"/>
+ <map code="0xb1" name="plusminus"/>
+ <map code="0xb2" name=".notdef"/>
+ <map code="0xb3" name=".notdef"/>
+ <map code="0xb4" name="yen"/>
+ <map code="0xb5" name="mu"/>
+ <map code="0xb6" name=".notdef"/>
+ <map code="0xb7" name=".notdef"/>
+ <map code="0xb8" name=".notdef"/>
+ <map code="0xb9" name=".notdef"/>
+ <map code="0xba" name=".notdef"/>
+ <map code="0xbb" name="ordfeminine"/>
+ <map code="0xbc" name="ordmasculine"/>
+ <map code="0xbd" name=".notdef"/>
+ <map code="0xbe" name="ae"/>
+ <map code="0xbf" name="oslash"/>
+ <map code="0xc0" name="questiondown"/>
+ <map code="0xc1" name="exclamdown"/>
+ <map code="0xc2" name="logicalnot"/>
+ <map code="0xc3" name=".notdef"/>
+ <map code="0xc4" name="florin"/>
+ <map code="0xc5" name=".notdef"/>
+ <map code="0xc6" name=".notdef"/>
+ <map code="0xc7" name="guillemotleft"/>
+ <map code="0xc8" name="guillemotright"/>
+ <map code="0xc9" name="ellipsis"/>
+ <map code="0xca" name=".notdef#16"/>
+ <map code="0xcb" name="Agrave"/>
+ <map code="0xcc" name="Atilde"/>
+ <map code="0xcd" name="Otilde"/>
+ <map code="0xce" name="OE"/>
+ <map code="0xcf" name="oe"/>
+ <map code="0xd0" name="endash"/>
+ <map code="0xd1" name="emdash"/>
+ <map code="0xd2" name="quotedblleft"/>
+ <map code="0xd3" name="quotedblright"/>
+ <map code="0xd4" name="quoteleft"/>
+ <map code="0xd5" name="quoteright"/>
+ <map code="0xd6" name="divide"/>
+ <map code="0xd7" name=".notdef"/>
+ <map code="0xd8" name="ydieresis"/>
+ <map code="0xd9" name="Ydieresis"/>
+ <map code="0xda" name="fraction"/>
+ <map code="0xdb" name="currency"/>
+ <map code="0xdc" name="guilsinglleft"/>
+ <map code="0xdd" name="guilsinglright"/>
+ <map code="0xde" name="fi"/>
+ <map code="0xdf" name="fl"/>
+ <map code="0xe0" name="daggerdbl"/>
+ <map code="0xe1" name="periodcentered"/>
+ <map code="0xe2" name="quotesinglbase"/>
+ <map code="0xe3" name="quotedblbase"/>
+ <map code="0xe4" name="perthousand"/>
+ <map code="0xe5" name="Acircumflex"/>
+ <map code="0xe6" name="Ecircumflex"/>
+ <map code="0xe7" name="Aacute"/>
+ <map code="0xe8" name="Edieresis"/>
+ <map code="0xe9" name="Egrave"/>
+ <map code="0xea" name="Iacute"/>
+ <map code="0xeb" name="Icircumflex"/>
+ <map code="0xec" name="Idieresis"/>
+ <map code="0xed" name="Igrave"/>
+ <map code="0xee" name="Oacute"/>
+ <map code="0xef" name="Ocircumflex"/>
+ <map code="0xf0" name="Euro"/>
+ <map code="0xf1" name="Ograve"/>
+ <map code="0xf2" name="Uacute"/>
+ <map code="0xf3" name="Ucircumflex"/>
+ <map code="0xf4" name="Ugrave"/>
+ <map code="0xf5" name="dotlessi"/>
+ <map code="0xf6" name="circumflex"/>
+ <map code="0xf7" name="tilde"/>
+ <map code="0xf8" name="macron"/>
+ <map code="0xf9" name="breve"/>
+ <map code="0xfa" name="dotaccent"/>
+ <map code="0xfb" name="ring"/>
+ <map code="0xfc" name="cedilla"/>
+ <map code="0xfd" name="hungarumlaut"/>
+ <map code="0xfe" name="ogonek"/>
+ <map code="0xff" name="caron"/>
+ </cmap_format_0>
+ <cmap_format_4 platformID="3" platEncID="1" language="0">
+ <map code="0x20" name="space"/><!-- SPACE -->
+ <map code="0x21" name="exclam"/><!-- EXCLAMATION MARK -->
+ <map code="0x22" name="quotedbl"/><!-- QUOTATION MARK -->
+ <map code="0x23" name="numbersign"/><!-- NUMBER SIGN -->
+ <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
+ <map code="0x25" name="percent"/><!-- PERCENT SIGN -->
+ <map code="0x26" name="ampersand"/><!-- AMPERSAND -->
+ <map code="0x27" name="quotesingle"/><!-- APOSTROPHE -->
+ <map code="0x28" name="parenleft"/><!-- LEFT PARENTHESIS -->
+ <map code="0x29" name="parenright"/><!-- RIGHT PARENTHESIS -->
+ <map code="0x2a" name="asterisk"/><!-- ASTERISK -->
+ <map code="0x2b" name="plus"/><!-- PLUS SIGN -->
+ <map code="0x2c" name="comma"/><!-- COMMA -->
+ <map code="0x2d" name="hyphen"/><!-- HYPHEN-MINUS -->
+ <map code="0x2e" name="period"/><!-- FULL STOP -->
+ <map code="0x2f" name="slash"/><!-- SOLIDUS -->
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
+ <map code="0x39" name="nine"/><!-- DIGIT NINE -->
+ <map code="0x3a" name="colon"/><!-- COLON -->
+ <map code="0x3b" name="semicolon"/><!-- SEMICOLON -->
+ <map code="0x3c" name="less"/><!-- LESS-THAN SIGN -->
+ <map code="0x3d" name="equal"/><!-- EQUALS SIGN -->
+ <map code="0x3e" name="greater"/><!-- GREATER-THAN SIGN -->
+ <map code="0x3f" name="question"/><!-- QUESTION MARK -->
+ <map code="0x40" name="at"/><!-- COMMERCIAL AT -->
+ <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
+ <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
+ <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
+ <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
+ <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
+ <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
+ <map code="0x47" name="G"/><!-- LATIN CAPITAL LETTER G -->
+ <map code="0x48" name="H"/><!-- LATIN CAPITAL LETTER H -->
+ <map code="0x49" name="I"/><!-- LATIN CAPITAL LETTER I -->
+ <map code="0x4a" name="J"/><!-- LATIN CAPITAL LETTER J -->
+ <map code="0x4b" name="K"/><!-- LATIN CAPITAL LETTER K -->
+ <map code="0x4c" name="L"/><!-- LATIN CAPITAL LETTER L -->
+ <map code="0x4d" name="M"/><!-- LATIN CAPITAL LETTER M -->
+ <map code="0x4e" name="N"/><!-- LATIN CAPITAL LETTER N -->
+ <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
+ <map code="0x50" name="P"/><!-- LATIN CAPITAL LETTER P -->
+ <map code="0x51" name="Q"/><!-- LATIN CAPITAL LETTER Q -->
+ <map code="0x52" name="R"/><!-- LATIN CAPITAL LETTER R -->
+ <map code="0x53" name="S"/><!-- LATIN CAPITAL LETTER S -->
+ <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
+ <map code="0x55" name="U"/><!-- LATIN CAPITAL LETTER U -->
+ <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
+ <map code="0x57" name="W"/><!-- LATIN CAPITAL LETTER W -->
+ <map code="0x58" name="X"/><!-- LATIN CAPITAL LETTER X -->
+ <map code="0x59" name="Y"/><!-- LATIN CAPITAL LETTER Y -->
+ <map code="0x5a" name="Z"/><!-- LATIN CAPITAL LETTER Z -->
+ <map code="0x5b" name="bracketleft"/><!-- LEFT SQUARE BRACKET -->
+ <map code="0x5c" name="backslash"/><!-- REVERSE SOLIDUS -->
+ <map code="0x5d" name="bracketright"/><!-- RIGHT SQUARE BRACKET -->
+ <map code="0x5e" name="asciicircum"/><!-- CIRCUMFLEX ACCENT -->
+ <map code="0x5f" name="underscore"/><!-- LOW LINE -->
+ <map code="0x60" name="grave"/><!-- GRAVE ACCENT -->
+ <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
+ <map code="0x62" name="b"/><!-- LATIN SMALL LETTER B -->
+ <map code="0x63" name="c"/><!-- LATIN SMALL LETTER C -->
+ <map code="0x64" name="d"/><!-- LATIN SMALL LETTER D -->
+ <map code="0x65" name="e"/><!-- LATIN SMALL LETTER E -->
+ <map code="0x66" name="f"/><!-- LATIN SMALL LETTER F -->
+ <map code="0x67" name="g"/><!-- LATIN SMALL LETTER G -->
+ <map code="0x68" name="h"/><!-- LATIN SMALL LETTER H -->
+ <map code="0x69" name="i"/><!-- LATIN SMALL LETTER I -->
+ <map code="0x6a" name="j"/><!-- LATIN SMALL LETTER J -->
+ <map code="0x6b" name="k"/><!-- LATIN SMALL LETTER K -->
+ <map code="0x6c" name="l"/><!-- LATIN SMALL LETTER L -->
+ <map code="0x6d" name="m"/><!-- LATIN SMALL LETTER M -->
+ <map code="0x6e" name="n"/><!-- LATIN SMALL LETTER N -->
+ <map code="0x6f" name="o"/><!-- LATIN SMALL LETTER O -->
+ <map code="0x70" name="p"/><!-- LATIN SMALL LETTER P -->
+ <map code="0x71" name="q"/><!-- LATIN SMALL LETTER Q -->
+ <map code="0x72" name="r"/><!-- LATIN SMALL LETTER R -->
+ <map code="0x73" name="s"/><!-- LATIN SMALL LETTER S -->
+ <map code="0x74" name="t"/><!-- LATIN SMALL LETTER T -->
+ <map code="0x75" name="u"/><!-- LATIN SMALL LETTER U -->
+ <map code="0x76" name="v"/><!-- LATIN SMALL LETTER V -->
+ <map code="0x77" name="w"/><!-- LATIN SMALL LETTER W -->
+ <map code="0x78" name="x"/><!-- LATIN SMALL LETTER X -->
+ <map code="0x79" name="y"/><!-- LATIN SMALL LETTER Y -->
+ <map code="0x7a" name="z"/><!-- LATIN SMALL LETTER Z -->
+ <map code="0x7b" name="braceleft"/><!-- LEFT CURLY BRACKET -->
+ <map code="0x7c" name="bar"/><!-- VERTICAL LINE -->
+ <map code="0x7d" name="braceright"/><!-- RIGHT CURLY BRACKET -->
+ <map code="0x7e" name="asciitilde"/><!-- TILDE -->
+ <map code="0x80" name="Euro#1"/><!-- &lt;control> -->
+ <map code="0xa0" name="nonbreakingspace"/><!-- NO-BREAK SPACE -->
+ <map code="0xa1" name="exclamdown"/><!-- INVERTED EXCLAMATION MARK -->
+ <map code="0xa2" name="cent"/><!-- CENT SIGN -->
+ <map code="0xa3" name="sterling"/><!-- POUND SIGN -->
+ <map code="0xa4" name="currency"/><!-- CURRENCY SIGN -->
+ <map code="0xa5" name="yen"/><!-- YEN SIGN -->
+ <map code="0xa6" name="brokenbar"/><!-- BROKEN BAR -->
+ <map code="0xa7" name="section"/><!-- SECTION SIGN -->
+ <map code="0xa8" name="dieresis"/><!-- DIAERESIS -->
+ <map code="0xa9" name="copyright"/><!-- COPYRIGHT SIGN -->
+ <map code="0xaa" name="ordfeminine"/><!-- FEMININE ORDINAL INDICATOR -->
+ <map code="0xab" name="guillemotleft"/><!-- LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <map code="0xac" name="logicalnot"/><!-- NOT SIGN -->
+ <map code="0xad" name="sfthyphen"/><!-- SOFT HYPHEN -->
+ <map code="0xae" name="registered"/><!-- REGISTERED SIGN -->
+ <map code="0xaf" name="macron#1"/><!-- MACRON -->
+ <map code="0xb0" name="degree"/><!-- DEGREE SIGN -->
+ <map code="0xb1" name="plusminus"/><!-- PLUS-MINUS SIGN -->
+ <map code="0xb2" name="twosuperior"/><!-- SUPERSCRIPT TWO -->
+ <map code="0xb3" name="threesuperior"/><!-- SUPERSCRIPT THREE -->
+ <map code="0xb4" name="acute"/><!-- ACUTE ACCENT -->
+ <map code="0xb5" name="mu"/><!-- MICRO SIGN -->
+ <map code="0xb6" name="paragraph"/><!-- PILCROW SIGN -->
+ <map code="0xb7" name="periodcentered#1"/><!-- MIDDLE DOT -->
+ <map code="0xb8" name="cedilla"/><!-- CEDILLA -->
+ <map code="0xb9" name="onesuperior"/><!-- SUPERSCRIPT ONE -->
+ <map code="0xba" name="ordmasculine"/><!-- MASCULINE ORDINAL INDICATOR -->
+ <map code="0xbb" name="guillemotright"/><!-- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <map code="0xbc" name="onequarter"/><!-- VULGAR FRACTION ONE QUARTER -->
+ <map code="0xbd" name="onehalf"/><!-- VULGAR FRACTION ONE HALF -->
+ <map code="0xbe" name="threequarters"/><!-- VULGAR FRACTION THREE QUARTERS -->
+ <map code="0xbf" name="questiondown"/><!-- INVERTED QUESTION MARK -->
+ <map code="0xc0" name="Agrave"/><!-- LATIN CAPITAL LETTER A WITH GRAVE -->
+ <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
+ <map code="0xc2" name="Acircumflex"/><!-- LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+ <map code="0xc3" name="Atilde"/><!-- LATIN CAPITAL LETTER A WITH TILDE -->
+ <map code="0xc4" name="Adieresis"/><!-- LATIN CAPITAL LETTER A WITH DIAERESIS -->
+ <map code="0xc5" name="Aring"/><!-- LATIN CAPITAL LETTER A WITH RING ABOVE -->
+ <map code="0xc6" name="AE"/><!-- LATIN CAPITAL LETTER AE -->
+ <map code="0xc7" name="Ccedilla"/><!-- LATIN CAPITAL LETTER C WITH CEDILLA -->
+ <map code="0xc8" name="Egrave"/><!-- LATIN CAPITAL LETTER E WITH GRAVE -->
+ <map code="0xc9" name="Eacute"/><!-- LATIN CAPITAL LETTER E WITH ACUTE -->
+ <map code="0xca" name="Ecircumflex"/><!-- LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+ <map code="0xcb" name="Edieresis"/><!-- LATIN CAPITAL LETTER E WITH DIAERESIS -->
+ <map code="0xcc" name="Igrave"/><!-- LATIN CAPITAL LETTER I WITH GRAVE -->
+ <map code="0xcd" name="Iacute"/><!-- LATIN CAPITAL LETTER I WITH ACUTE -->
+ <map code="0xce" name="Icircumflex"/><!-- LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+ <map code="0xcf" name="Idieresis"/><!-- LATIN CAPITAL LETTER I WITH DIAERESIS -->
+ <map code="0xd0" name="Eth"/><!-- LATIN CAPITAL LETTER ETH -->
+ <map code="0xd1" name="Ntilde"/><!-- LATIN CAPITAL LETTER N WITH TILDE -->
+ <map code="0xd2" name="Ograve"/><!-- LATIN CAPITAL LETTER O WITH GRAVE -->
+ <map code="0xd3" name="Oacute"/><!-- LATIN CAPITAL LETTER O WITH ACUTE -->
+ <map code="0xd4" name="Ocircumflex"/><!-- LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+ <map code="0xd5" name="Otilde"/><!-- LATIN CAPITAL LETTER O WITH TILDE -->
+ <map code="0xd6" name="Odieresis"/><!-- LATIN CAPITAL LETTER O WITH DIAERESIS -->
+ <map code="0xd7" name="multiply"/><!-- MULTIPLICATION SIGN -->
+ <map code="0xd8" name="Oslash"/><!-- LATIN CAPITAL LETTER O WITH STROKE -->
+ <map code="0xd9" name="Ugrave"/><!-- LATIN CAPITAL LETTER U WITH GRAVE -->
+ <map code="0xda" name="Uacute"/><!-- LATIN CAPITAL LETTER U WITH ACUTE -->
+ <map code="0xdb" name="Ucircumflex"/><!-- LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+ <map code="0xdc" name="Udieresis"/><!-- LATIN CAPITAL LETTER U WITH DIAERESIS -->
+ <map code="0xdd" name="Yacute"/><!-- LATIN CAPITAL LETTER Y WITH ACUTE -->
+ <map code="0xde" name="Thorn"/><!-- LATIN CAPITAL LETTER THORN -->
+ <map code="0xdf" name="germandbls"/><!-- LATIN SMALL LETTER SHARP S -->
+ <map code="0xe0" name="agrave"/><!-- LATIN SMALL LETTER A WITH GRAVE -->
+ <map code="0xe1" name="aacute"/><!-- LATIN SMALL LETTER A WITH ACUTE -->
+ <map code="0xe2" name="acircumflex"/><!-- LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+ <map code="0xe3" name="atilde"/><!-- LATIN SMALL LETTER A WITH TILDE -->
+ <map code="0xe4" name="adieresis"/><!-- LATIN SMALL LETTER A WITH DIAERESIS -->
+ <map code="0xe5" name="aring"/><!-- LATIN SMALL LETTER A WITH RING ABOVE -->
+ <map code="0xe6" name="ae"/><!-- LATIN SMALL LETTER AE -->
+ <map code="0xe7" name="ccedilla"/><!-- LATIN SMALL LETTER C WITH CEDILLA -->
+ <map code="0xe8" name="egrave"/><!-- LATIN SMALL LETTER E WITH GRAVE -->
+ <map code="0xe9" name="eacute"/><!-- LATIN SMALL LETTER E WITH ACUTE -->
+ <map code="0xea" name="ecircumflex"/><!-- LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+ <map code="0xeb" name="edieresis"/><!-- LATIN SMALL LETTER E WITH DIAERESIS -->
+ <map code="0xec" name="igrave"/><!-- LATIN SMALL LETTER I WITH GRAVE -->
+ <map code="0xed" name="iacute"/><!-- LATIN SMALL LETTER I WITH ACUTE -->
+ <map code="0xee" name="icircumflex"/><!-- LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+ <map code="0xef" name="idieresis"/><!-- LATIN SMALL LETTER I WITH DIAERESIS -->
+ <map code="0xf0" name="eth"/><!-- LATIN SMALL LETTER ETH -->
+ <map code="0xf1" name="ntilde"/><!-- LATIN SMALL LETTER N WITH TILDE -->
+ <map code="0xf2" name="ograve"/><!-- LATIN SMALL LETTER O WITH GRAVE -->
+ <map code="0xf3" name="oacute"/><!-- LATIN SMALL LETTER O WITH ACUTE -->
+ <map code="0xf4" name="ocircumflex"/><!-- LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+ <map code="0xf5" name="otilde"/><!-- LATIN SMALL LETTER O WITH TILDE -->
+ <map code="0xf6" name="odieresis"/><!-- LATIN SMALL LETTER O WITH DIAERESIS -->
+ <map code="0xf7" name="divide"/><!-- DIVISION SIGN -->
+ <map code="0xf8" name="oslash"/><!-- LATIN SMALL LETTER O WITH STROKE -->
+ <map code="0xf9" name="ugrave"/><!-- LATIN SMALL LETTER U WITH GRAVE -->
+ <map code="0xfa" name="uacute"/><!-- LATIN SMALL LETTER U WITH ACUTE -->
+ <map code="0xfb" name="ucircumflex"/><!-- LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+ <map code="0xfc" name="udieresis"/><!-- LATIN SMALL LETTER U WITH DIAERESIS -->
+ <map code="0xfd" name="yacute"/><!-- LATIN SMALL LETTER Y WITH ACUTE -->
+ <map code="0xfe" name="thorn"/><!-- LATIN SMALL LETTER THORN -->
+ <map code="0xff" name="ydieresis"/><!-- LATIN SMALL LETTER Y WITH DIAERESIS -->
+ <map code="0x100" name="Amacron"/><!-- LATIN CAPITAL LETTER A WITH MACRON -->
+ <map code="0x101" name="amacron"/><!-- LATIN SMALL LETTER A WITH MACRON -->
+ <map code="0x102" name="Abreve"/><!-- LATIN CAPITAL LETTER A WITH BREVE -->
+ <map code="0x103" name="abreve"/><!-- LATIN SMALL LETTER A WITH BREVE -->
+ <map code="0x104" name="Aogonek"/><!-- LATIN CAPITAL LETTER A WITH OGONEK -->
+ <map code="0x105" name="aogonek"/><!-- LATIN SMALL LETTER A WITH OGONEK -->
+ <map code="0x106" name="Cacute"/><!-- LATIN CAPITAL LETTER C WITH ACUTE -->
+ <map code="0x107" name="cacute"/><!-- LATIN SMALL LETTER C WITH ACUTE -->
+ <map code="0x108" name="Ccircumflex"/><!-- LATIN CAPITAL LETTER C WITH CIRCUMFLEX -->
+ <map code="0x109" name="ccircumflex"/><!-- LATIN SMALL LETTER C WITH CIRCUMFLEX -->
+ <map code="0x10a" name="Cdotaccent"/><!-- LATIN CAPITAL LETTER C WITH DOT ABOVE -->
+ <map code="0x10b" name="cdotaccent"/><!-- LATIN SMALL LETTER C WITH DOT ABOVE -->
+ <map code="0x10c" name="Ccaron"/><!-- LATIN CAPITAL LETTER C WITH CARON -->
+ <map code="0x10d" name="ccaron"/><!-- LATIN SMALL LETTER C WITH CARON -->
+ <map code="0x10e" name="Dcaron"/><!-- LATIN CAPITAL LETTER D WITH CARON -->
+ <map code="0x10f" name="dcaron"/><!-- LATIN SMALL LETTER D WITH CARON -->
+ <map code="0x110" name="Dcroat"/><!-- LATIN CAPITAL LETTER D WITH STROKE -->
+ <map code="0x111" name="dcroat"/><!-- LATIN SMALL LETTER D WITH STROKE -->
+ <map code="0x112" name="Emacron"/><!-- LATIN CAPITAL LETTER E WITH MACRON -->
+ <map code="0x113" name="emacron"/><!-- LATIN SMALL LETTER E WITH MACRON -->
+ <map code="0x114" name="Ebreve"/><!-- LATIN CAPITAL LETTER E WITH BREVE -->
+ <map code="0x115" name="ebreve"/><!-- LATIN SMALL LETTER E WITH BREVE -->
+ <map code="0x116" name="Edotaccent"/><!-- LATIN CAPITAL LETTER E WITH DOT ABOVE -->
+ <map code="0x117" name="edotaccent"/><!-- LATIN SMALL LETTER E WITH DOT ABOVE -->
+ <map code="0x118" name="Eogonek"/><!-- LATIN CAPITAL LETTER E WITH OGONEK -->
+ <map code="0x119" name="eogonek"/><!-- LATIN SMALL LETTER E WITH OGONEK -->
+ <map code="0x11a" name="Ecaron"/><!-- LATIN CAPITAL LETTER E WITH CARON -->
+ <map code="0x11b" name="ecaron"/><!-- LATIN SMALL LETTER E WITH CARON -->
+ <map code="0x11c" name="Gcircumflex"/><!-- LATIN CAPITAL LETTER G WITH CIRCUMFLEX -->
+ <map code="0x11d" name="gcircumflex"/><!-- LATIN SMALL LETTER G WITH CIRCUMFLEX -->
+ <map code="0x11e" name="Gbreve"/><!-- LATIN CAPITAL LETTER G WITH BREVE -->
+ <map code="0x11f" name="gbreve"/><!-- LATIN SMALL LETTER G WITH BREVE -->
+ <map code="0x120" name="Gdotaccent"/><!-- LATIN CAPITAL LETTER G WITH DOT ABOVE -->
+ <map code="0x121" name="gdotaccent"/><!-- LATIN SMALL LETTER G WITH DOT ABOVE -->
+ <map code="0x122" name="Gcommaaccent"/><!-- LATIN CAPITAL LETTER G WITH CEDILLA -->
+ <map code="0x123" name="gcommaaccent"/><!-- LATIN SMALL LETTER G WITH CEDILLA -->
+ <map code="0x124" name="Hcircumflex"/><!-- LATIN CAPITAL LETTER H WITH CIRCUMFLEX -->
+ <map code="0x125" name="hcircumflex"/><!-- LATIN SMALL LETTER H WITH CIRCUMFLEX -->
+ <map code="0x126" name="Hbar"/><!-- LATIN CAPITAL LETTER H WITH STROKE -->
+ <map code="0x127" name="hbar"/><!-- LATIN SMALL LETTER H WITH STROKE -->
+ <map code="0x128" name="Itilde"/><!-- LATIN CAPITAL LETTER I WITH TILDE -->
+ <map code="0x129" name="itilde"/><!-- LATIN SMALL LETTER I WITH TILDE -->
+ <map code="0x12a" name="Imacron"/><!-- LATIN CAPITAL LETTER I WITH MACRON -->
+ <map code="0x12b" name="imacron"/><!-- LATIN SMALL LETTER I WITH MACRON -->
+ <map code="0x12c" name="Ibreve"/><!-- LATIN CAPITAL LETTER I WITH BREVE -->
+ <map code="0x12d" name="ibreve"/><!-- LATIN SMALL LETTER I WITH BREVE -->
+ <map code="0x12e" name="Iogonek"/><!-- LATIN CAPITAL LETTER I WITH OGONEK -->
+ <map code="0x12f" name="iogonek"/><!-- LATIN SMALL LETTER I WITH OGONEK -->
+ <map code="0x130" name="Idotaccent"/><!-- LATIN CAPITAL LETTER I WITH DOT ABOVE -->
+ <map code="0x131" name="dotlessi"/><!-- LATIN SMALL LETTER DOTLESS I -->
+ <map code="0x132" name="IJ"/><!-- LATIN CAPITAL LIGATURE IJ -->
+ <map code="0x133" name="ij"/><!-- LATIN SMALL LIGATURE IJ -->
+ <map code="0x134" name="Jcircumflex"/><!-- LATIN CAPITAL LETTER J WITH CIRCUMFLEX -->
+ <map code="0x135" name="jcircumflex"/><!-- LATIN SMALL LETTER J WITH CIRCUMFLEX -->
+ <map code="0x136" name="Kcommaaccent"/><!-- LATIN CAPITAL LETTER K WITH CEDILLA -->
+ <map code="0x137" name="kcommaaccent"/><!-- LATIN SMALL LETTER K WITH CEDILLA -->
+ <map code="0x138" name="kgreenlandic"/><!-- LATIN SMALL LETTER KRA -->
+ <map code="0x139" name="Lacute"/><!-- LATIN CAPITAL LETTER L WITH ACUTE -->
+ <map code="0x13a" name="lacute"/><!-- LATIN SMALL LETTER L WITH ACUTE -->
+ <map code="0x13b" name="Lcommaaccent"/><!-- LATIN CAPITAL LETTER L WITH CEDILLA -->
+ <map code="0x13c" name="lcommaaccent"/><!-- LATIN SMALL LETTER L WITH CEDILLA -->
+ <map code="0x13d" name="Lcaron"/><!-- LATIN CAPITAL LETTER L WITH CARON -->
+ <map code="0x13e" name="lcaron"/><!-- LATIN SMALL LETTER L WITH CARON -->
+ <map code="0x13f" name="Ldot"/><!-- LATIN CAPITAL LETTER L WITH MIDDLE DOT -->
+ <map code="0x140" name="ldot"/><!-- LATIN SMALL LETTER L WITH MIDDLE DOT -->
+ <map code="0x141" name="Lslash"/><!-- LATIN CAPITAL LETTER L WITH STROKE -->
+ <map code="0x142" name="lslash"/><!-- LATIN SMALL LETTER L WITH STROKE -->
+ <map code="0x143" name="Nacute"/><!-- LATIN CAPITAL LETTER N WITH ACUTE -->
+ <map code="0x144" name="nacute"/><!-- LATIN SMALL LETTER N WITH ACUTE -->
+ <map code="0x145" name="Ncommaaccent"/><!-- LATIN CAPITAL LETTER N WITH CEDILLA -->
+ <map code="0x146" name="ncommaaccent"/><!-- LATIN SMALL LETTER N WITH CEDILLA -->
+ <map code="0x147" name="Ncaron"/><!-- LATIN CAPITAL LETTER N WITH CARON -->
+ <map code="0x148" name="ncaron"/><!-- LATIN SMALL LETTER N WITH CARON -->
+ <map code="0x149" name="napostrophe"/><!-- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE -->
+ <map code="0x14a" name="Eng"/><!-- LATIN CAPITAL LETTER ENG -->
+ <map code="0x14b" name="eng"/><!-- LATIN SMALL LETTER ENG -->
+ <map code="0x14c" name="Omacron"/><!-- LATIN CAPITAL LETTER O WITH MACRON -->
+ <map code="0x14d" name="omacron"/><!-- LATIN SMALL LETTER O WITH MACRON -->
+ <map code="0x14e" name="Obreve"/><!-- LATIN CAPITAL LETTER O WITH BREVE -->
+ <map code="0x14f" name="obreve"/><!-- LATIN SMALL LETTER O WITH BREVE -->
+ <map code="0x150" name="Ohungarumlaut"/><!-- LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -->
+ <map code="0x151" name="ohungarumlaut"/><!-- LATIN SMALL LETTER O WITH DOUBLE ACUTE -->
+ <map code="0x152" name="OE"/><!-- LATIN CAPITAL LIGATURE OE -->
+ <map code="0x153" name="oe"/><!-- LATIN SMALL LIGATURE OE -->
+ <map code="0x154" name="Racute"/><!-- LATIN CAPITAL LETTER R WITH ACUTE -->
+ <map code="0x155" name="racute"/><!-- LATIN SMALL LETTER R WITH ACUTE -->
+ <map code="0x156" name="Rcommaaccent"/><!-- LATIN CAPITAL LETTER R WITH CEDILLA -->
+ <map code="0x157" name="rcommaaccent"/><!-- LATIN SMALL LETTER R WITH CEDILLA -->
+ <map code="0x158" name="Rcaron"/><!-- LATIN CAPITAL LETTER R WITH CARON -->
+ <map code="0x159" name="rcaron"/><!-- LATIN SMALL LETTER R WITH CARON -->
+ <map code="0x15a" name="Sacute"/><!-- LATIN CAPITAL LETTER S WITH ACUTE -->
+ <map code="0x15b" name="sacute"/><!-- LATIN SMALL LETTER S WITH ACUTE -->
+ <map code="0x15c" name="Scircumflex"/><!-- LATIN CAPITAL LETTER S WITH CIRCUMFLEX -->
+ <map code="0x15d" name="scircumflex"/><!-- LATIN SMALL LETTER S WITH CIRCUMFLEX -->
+ <map code="0x15e" name="Scedilla"/><!-- LATIN CAPITAL LETTER S WITH CEDILLA -->
+ <map code="0x15f" name="scedilla"/><!-- LATIN SMALL LETTER S WITH CEDILLA -->
+ <map code="0x160" name="Scaron"/><!-- LATIN CAPITAL LETTER S WITH CARON -->
+ <map code="0x161" name="scaron"/><!-- LATIN SMALL LETTER S WITH CARON -->
+ <map code="0x162" name="Tcommaaccent"/><!-- LATIN CAPITAL LETTER T WITH CEDILLA -->
+ <map code="0x163" name="tcommaaccent"/><!-- LATIN SMALL LETTER T WITH CEDILLA -->
+ <map code="0x164" name="Tcaron"/><!-- LATIN CAPITAL LETTER T WITH CARON -->
+ <map code="0x165" name="tcaron"/><!-- LATIN SMALL LETTER T WITH CARON -->
+ <map code="0x166" name="Tbar"/><!-- LATIN CAPITAL LETTER T WITH STROKE -->
+ <map code="0x167" name="tbar"/><!-- LATIN SMALL LETTER T WITH STROKE -->
+ <map code="0x168" name="Utilde"/><!-- LATIN CAPITAL LETTER U WITH TILDE -->
+ <map code="0x169" name="utilde"/><!-- LATIN SMALL LETTER U WITH TILDE -->
+ <map code="0x16a" name="Umacron"/><!-- LATIN CAPITAL LETTER U WITH MACRON -->
+ <map code="0x16b" name="umacron"/><!-- LATIN SMALL LETTER U WITH MACRON -->
+ <map code="0x16c" name="Ubreve"/><!-- LATIN CAPITAL LETTER U WITH BREVE -->
+ <map code="0x16d" name="ubreve"/><!-- LATIN SMALL LETTER U WITH BREVE -->
+ <map code="0x16e" name="Uring"/><!-- LATIN CAPITAL LETTER U WITH RING ABOVE -->
+ <map code="0x16f" name="uring"/><!-- LATIN SMALL LETTER U WITH RING ABOVE -->
+ <map code="0x170" name="Uhungarumlaut"/><!-- LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -->
+ <map code="0x171" name="uhungarumlaut"/><!-- LATIN SMALL LETTER U WITH DOUBLE ACUTE -->
+ <map code="0x172" name="Uogonek"/><!-- LATIN CAPITAL LETTER U WITH OGONEK -->
+ <map code="0x173" name="uogonek"/><!-- LATIN SMALL LETTER U WITH OGONEK -->
+ <map code="0x174" name="Wcircumflex"/><!-- LATIN CAPITAL LETTER W WITH CIRCUMFLEX -->
+ <map code="0x175" name="wcircumflex"/><!-- LATIN SMALL LETTER W WITH CIRCUMFLEX -->
+ <map code="0x176" name="Ycircumflex"/><!-- LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -->
+ <map code="0x177" name="ycircumflex"/><!-- LATIN SMALL LETTER Y WITH CIRCUMFLEX -->
+ <map code="0x178" name="Ydieresis"/><!-- LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+ <map code="0x179" name="Zacute"/><!-- LATIN CAPITAL LETTER Z WITH ACUTE -->
+ <map code="0x17a" name="zacute"/><!-- LATIN SMALL LETTER Z WITH ACUTE -->
+ <map code="0x17b" name="Zdotaccent"/><!-- LATIN CAPITAL LETTER Z WITH DOT ABOVE -->
+ <map code="0x17c" name="zdotaccent"/><!-- LATIN SMALL LETTER Z WITH DOT ABOVE -->
+ <map code="0x17d" name="Zcaron"/><!-- LATIN CAPITAL LETTER Z WITH CARON -->
+ <map code="0x17e" name="zcaron"/><!-- LATIN SMALL LETTER Z WITH CARON -->
+ <map code="0x17f" name="longs"/><!-- LATIN SMALL LETTER LONG S -->
+ <map code="0x192" name="florin"/><!-- LATIN SMALL LETTER F WITH HOOK -->
+ <map code="0x218" name="Scommaaccent"/><!-- LATIN CAPITAL LETTER S WITH COMMA BELOW -->
+ <map code="0x219" name="scommaaccent"/><!-- LATIN SMALL LETTER S WITH COMMA BELOW -->
+ <map code="0x21a" name="Tcommabelow"/><!-- LATIN CAPITAL LETTER T WITH COMMA BELOW -->
+ <map code="0x21b" name="tcommabelow"/><!-- LATIN SMALL LETTER T WITH COMMA BELOW -->
+ <map code="0x2c6" name="circumflex"/><!-- MODIFIER LETTER CIRCUMFLEX ACCENT -->
+ <map code="0x2c7" name="caron"/><!-- CARON -->
+ <map code="0x2c9" name="macron"/><!-- MODIFIER LETTER MACRON -->
+ <map code="0x2d8" name="breve"/><!-- BREVE -->
+ <map code="0x2d9" name="dotaccent"/><!-- DOT ABOVE -->
+ <map code="0x2da" name="ring"/><!-- RING ABOVE -->
+ <map code="0x2db" name="ogonek"/><!-- OGONEK -->
+ <map code="0x2dc" name="tilde"/><!-- SMALL TILDE -->
+ <map code="0x2dd" name="hungarumlaut"/><!-- DOUBLE ACUTE ACCENT -->
+ <map code="0x326" name="Unterkomma"/><!-- COMBINING COMMA BELOW -->
+ <map code="0x37e" name="semicolon#1"/><!-- GREEK QUESTION MARK -->
+ <map code="0x387" name="anoteleia"/><!-- GREEK ANO TELEIA -->
+ <map code="0x2010" name="hyphen#1"/><!-- HYPHEN -->
+ <map code="0x2011" name="nbhyphen"/><!-- NON-BREAKING HYPHEN -->
+ <map code="0x2012" name="figuredash"/><!-- FIGURE DASH -->
+ <map code="0x2013" name="endash"/><!-- EN DASH -->
+ <map code="0x2014" name="emdash"/><!-- EM DASH -->
+ <map code="0x2015" name="afii00208"/><!-- HORIZONTAL BAR -->
+ <map code="0x2018" name="quoteleft"/><!-- LEFT SINGLE QUOTATION MARK -->
+ <map code="0x2019" name="quoteright"/><!-- RIGHT SINGLE QUOTATION MARK -->
+ <map code="0x201a" name="quotesinglbase"/><!-- SINGLE LOW-9 QUOTATION MARK -->
+ <map code="0x201b" name="quotereversed"/><!-- SINGLE HIGH-REVERSED-9 QUOTATION MARK -->
+ <map code="0x201c" name="quotedblleft"/><!-- LEFT DOUBLE QUOTATION MARK -->
+ <map code="0x201d" name="quotedblright"/><!-- RIGHT DOUBLE QUOTATION MARK -->
+ <map code="0x201e" name="quotedblbase"/><!-- DOUBLE LOW-9 QUOTATION MARK -->
+ <map code="0x2020" name="dagger"/><!-- DAGGER -->
+ <map code="0x2021" name="daggerdbl"/><!-- DOUBLE DAGGER -->
+ <map code="0x2022" name="bullet"/><!-- BULLET -->
+ <map code="0x2026" name="ellipsis"/><!-- HORIZONTAL ELLIPSIS -->
+ <map code="0x2030" name="perthousand"/><!-- PER MILLE SIGN -->
+ <map code="0x2039" name="guilsinglleft"/><!-- SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+ <map code="0x203a" name="guilsinglright"/><!-- SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+ <map code="0x203e" name="radicalex"/><!-- OVERLINE -->
+ <map code="0x2044" name="fraction"/><!-- FRACTION SLASH -->
+ <map code="0x20ac" name="Euro"/><!-- EURO SIGN -->
+ <map code="0x2122" name="trademark"/><!-- TRADE MARK SIGN -->
+ <map code="0x212e" name="estimated"/><!-- ESTIMATED SYMBOL -->
+ <map code="0x2212" name="minus"/><!-- MINUS SIGN -->
+ <map code="0x2215" name="fraction#1"/><!-- DIVISION SLASH -->
+ <map code="0x2219" name="periodcentered"/><!-- BULLET OPERATOR -->
+ <map code="0x22c5" name="dotmath"/><!-- DOT OPERATOR -->
+ <map code="0xea01" name="fi#1"/><!-- Private Use -->
+ <map code="0xea02" name="fl#1"/><!-- Private Use -->
+ <map code="0xf001" name="fi"/><!-- Private Use -->
+ <map code="0xf002" name="fl"/><!-- Private Use -->
+ <map code="0xf004" name="foursuperiour"/><!-- Private Use -->
+ <map code="0xf005" name="onesuperiour"/><!-- Private Use -->
+ <map code="0xf006" name="twosuperiour"/><!-- Private Use -->
+ <map code="0xf007" name="threesuperiour"/><!-- Private Use -->
+ <map code="0xf008" name="foursuperiour#1"/><!-- Private Use -->
+ <map code="0xf6be" name="dotlessj"/><!-- Private Use -->
+ <map code="0xfb01" name="fi"/><!-- LATIN SMALL LIGATURE FI -->
+ <map code="0xfb02" name="fl"/><!-- LATIN SMALL LIGATURE FL -->
+ </cmap_format_4>
+ </cmap>
+
+ <fpgm>
+ <assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ FDEF[ ]
+ SLOOP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP1[ ]
+ SRP2[ ]
+ IP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP1[ ]
+ SRP2[ ]
+ SLOOP[ ]
+ IP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MIRP[11101]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MIRP[10100]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MDRP[11101]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MDRP[10100]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MIRP[11101]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MIRP[10100]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MDRP[11101]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MDRP[10100]
+ ENDF[ ]
+ FDEF[ ]
+ MDRP[00100]
+ ENDF[ ]
+ FDEF[ ]
+ MDRP[00000]
+ ENDF[ ]
+ FDEF[ ]
+ SVTCA[0]
+ NPUSHB[ ] /* 10 values pushed */
+ 1 0 0 1 1 2 2 3 3 0
+ SZPS[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SZPS[ ]
+ ENDF[ ]
+ </assembly>
+ </fpgm>
+
+ <prep>
+ <assembly>
+ PUSHB[ ] /* 2 values pushed */
+ 48 1
+ PUSHW[ ] /* 1 value pushed */
+ 329
+ RTG[ ]
+ SCANCTRL[ ]
+ SCANTYPE[ ]
+ SCVTCI[ ]
+ </assembly>
+ </prep>
+
+ <cvt>
+ <cv index="0" value="1480"/>
+ <cv index="1" value="1086"/>
+ <cv index="2" value="0"/>
+ <cv index="3" value="-512"/>
+ <cv index="4" value="247"/>
+ <cv index="5" value="121"/>
+ <cv index="6" value="125"/>
+ <cv index="7" value="147"/>
+ <cv index="8" value="299"/>
+ <cv index="9" value="224"/>
+ <cv index="10" value="200"/>
+ <cv index="11" value="210"/>
+ <cv index="12" value="174"/>
+ <cv index="13" value="179"/>
+ <cv index="14" value="145"/>
+ <cv index="15" value="171"/>
+ <cv index="16" value="149"/>
+ <cv index="17" value="96"/>
+ <cv index="18" value="102"/>
+ <cv index="19" value="188"/>
+ <cv index="20" value="138"/>
+ <cv index="21" value="97"/>
+ <cv index="22" value="172"/>
+ <cv index="23" value="36"/>
+ <cv index="24" value="203"/>
+ <cv index="25" value="131"/>
+ <cv index="26" value="230"/>
+ <cv index="27" value="186"/>
+ <cv index="28" value="196"/>
+ <cv index="29" value="22"/>
+ <cv index="30" value="157"/>
+ <cv index="31" value="114"/>
+ <cv index="32" value="87"/>
+ <cv index="33" value="101"/>
+ <cv index="34" value="162"/>
+ <cv index="35" value="155"/>
+ <cv index="36" value="213"/>
+ <cv index="37" value="176"/>
+ <cv index="38" value="152"/>
+ <cv index="39" value="212"/>
+ <cv index="40" value="113"/>
+ </cvt>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef" xMin="123" yMin="0" xMax="1106" yMax="1480">
+ <contour>
+ <pt x="123" y="0" on="1"/>
+ <pt x="123" y="1480" on="1"/>
+ <pt x="1106" y="1480" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="983" y="123" on="1"/>
+ <pt x="983" y="1357" on="1"/>
+ <pt x="246" y="1357" on="1"/>
+ <pt x="246" y="123" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 16 values pushed */
+ 5 6 2 1 4 7 3 0 5 4 2 3 6 7 1 0
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ SVTCA[0]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name=".notdef#1"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#10"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#11"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#12"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#13"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#14"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#15"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#16"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#17"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#18"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#2"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#3"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#4"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#5"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#6"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#7"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#8"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#9"/><!-- contains no outline data -->
+
+ <TTGlyph name="A" xMin="25" yMin="0" xMax="1203" yMax="1480">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 19 18 2 7 16 3 0 0 17 16 6 1 0 14 13 10 9 6 5 2 1 6 7 3 2
+ 4 48 200 15 0 1 12 11 4 3 3 2 0 8 7 0 14 19 18 17 16 15 14 13 12
+ 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="AE" xMin="12" yMin="0" xMax="1217" yMax="1480">
+ <contour>
+ <pt x="824" y="703" on="1"/>
+ <pt x="824" y="123" on="1"/>
+ <pt x="1093" y="123" on="1"/>
+ <pt x="1093" y="333" on="1"/>
+ <pt x="1217" y="333" on="1"/>
+ <pt x="1217" y="0" on="1"/>
+ <pt x="528" y="0" on="1"/>
+ <pt x="528" y="123" on="1"/>
+ <pt x="639" y="123" on="1"/>
+ <pt x="639" y="419" on="1"/>
+ <pt x="310" y="419" on="1"/>
+ <pt x="183" y="123" on="1"/>
+ <pt x="304" y="123" on="1"/>
+ <pt x="304" y="0" on="1"/>
+ <pt x="12" y="0" on="1"/>
+ <pt x="12" y="123" on="1"/>
+ <pt x="56" y="123" on="1"/>
+ <pt x="639" y="1480" on="1"/>
+ <pt x="1198" y="1480" on="1"/>
+ <pt x="1198" y="1166" on="1"/>
+ <pt x="1075" y="1166" on="1"/>
+ <pt x="1075" y="1357" on="1"/>
+ <pt x="824" y="1357" on="1"/>
+ <pt x="824" y="827" on="1"/>
+ <pt x="1001" y="827" on="1"/>
+ <pt x="1001" y="950" on="1"/>
+ <pt x="1124" y="950" on="1"/>
+ <pt x="1124" y="580" on="1"/>
+ <pt x="1001" y="580" on="1"/>
+ <pt x="1001" y="703" on="1"/>
+ </contour>
+ <contour>
+ <pt x="363" y="543" on="1"/>
+ <pt x="639" y="543" on="1"/>
+ <pt x="639" y="1180" on="1"/>
+ <pt x="638" y="1180" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 133 values pushed */
+ 33 32 26 25 20 19 6 21 23 3 28 27 2 0 30 3 4 3 2 9 1 3 0 0 22
+ 21 6 1 17 29 0 6 1 23 31 30 6 1 9 16 15 12 11 8 7 2 1 6 7 5
+ 4 4 48 200 24 23 1 10 9 1 14 13 6 5 3 3 0 18 17 0 14 29 28 25 24
+ 4 20 0 3 33 30 16 15 14 13 12 11 10 7 6 11 13 8 0 0 3 2 6 1 4
+ 21 20 6 1 18 32 31 17 9 8 19 4 0 3 4 48 200 5 4 1 19 18 1 27 26
+ 1 23 22 1 0 3 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aacute" xMin="25" yMin="0" xMax="1203" yMax="1925">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="491" y="1604" on="1"/>
+ <pt x="707" y="1925" on="1"/>
+ <pt x="935" y="1925" on="1"/>
+ <pt x="614" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 23 20 2 21 7 3 19 18 2 7 16 3 0 0 17 16 6 1 0 14 13 10 9 6 5
+ 2 1 6 7 3 2 4 48 200 22 21 1 15 0 1 12 11 4 3 3 3 0 8 7 0
+ 14 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Abreve" xMin="25" yMin="0" xMax="1203" yMax="1925">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="269" y="1925" on="1"/>
+ <pt x="392" y="1925" on="1"/>
+ <pt x="440" y="1777" on="0"/>
+ <pt x="614" y="1777" on="1"/>
+ <pt x="789" y="1777" on="0"/>
+ <pt x="837" y="1925" on="1"/>
+ <pt x="960" y="1925" on="1"/>
+ <pt x="937" y="1836" on="0"/>
+ <pt x="911" y="1790" on="1"/>
+ <pt x="820" y="1635" on="0"/>
+ <pt x="618" y="1635" on="1"/>
+ <pt x="466" y="1635" on="0"/>
+ <pt x="377" y="1716" on="1"/>
+ <pt x="322" y="1765" on="0"/>
+ <pt x="294" y="1837" on="1"/>
+ <pt x="283" y="1866" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 23 14 30 48 200 19 18 2 7 16 3 26 25 21 20 4 13 30 7 0 0 17 16
+ 6 1 0 14 13 10 9 6 5 2 1 6 7 3 2 4 48 200 15 0 1 12 11 4 3
+ 3 2 0 8 7 0 14 26 25 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6
+ 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Acircumflex" xMin="25" yMin="0" xMax="1203" yMax="1925">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="249" y="1604" on="1"/>
+ <pt x="505" y="1925" on="1"/>
+ <pt x="724" y="1925" on="1"/>
+ <pt x="980" y="1604" on="1"/>
+ <pt x="857" y="1604" on="1"/>
+ <pt x="616" y="1806" on="1"/>
+ <pt x="613" y="1806" on="1"/>
+ <pt x="372" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 27 26 25 24 23 20 6 21 7 3 19 18 2 7 16 3 0 0 17 16 6 1 0 14 13
+ 10 9 6 5 2 1 6 7 3 2 4 48 200 22 21 1 15 0 1 12 11 4 3 3 3
+ 0 8 7 0 14 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8
+ 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Adieresis" xMin="25" yMin="0" xMax="1203" yMax="1801">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="281" y="1604" on="1"/>
+ <pt x="281" y="1801" on="1"/>
+ <pt x="478" y="1801" on="1"/>
+ <pt x="478" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="750" y="1604" on="1"/>
+ <pt x="750" y="1801" on="1"/>
+ <pt x="947" y="1801" on="1"/>
+ <pt x="947" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 116 values pushed */
+ 19 18 2 7 16 3 0 0 27 24 23 20 10 3 21 17 16 6 1 0 14 13 10 9 6
+ 5 2 1 6 7 3 3 4 48 200 26 25 22 21 3 15 0 1 12 11 4 3 3 3 0
+ 8 7 0 14 17 15 14 13 12 5 26 24 3 19 18 8 7 4 24 22 3 16 3 2 0
+ 4 22 20 3 11 10 9 3 13 26 6 5 4 1 4 13 20 0 0 25 24 10 1 26 23
+ 22 10 1 20 2 4 48 200 27 26 1 21 20 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Agrave" xMin="25" yMin="0" xMax="1203" yMax="1925">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="738" y="1604" on="1"/>
+ <pt x="615" y="1604" on="1"/>
+ <pt x="294" y="1925" on="1"/>
+ <pt x="522" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 21 20 2 22 7 3 19 18 2 7 16 3 0 0 17 16 6 1 0 14 13 10 9 6 5
+ 2 1 6 7 3 2 4 48 200 23 22 1 15 0 1 12 11 4 3 3 3 0 8 7 0
+ 14 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Amacron" xMin="25" yMin="0" xMax="1203" yMax="1728">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="259" y="1604" on="1"/>
+ <pt x="259" y="1728" on="1"/>
+ <pt x="950" y="1728" on="1"/>
+ <pt x="950" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 19 18 2 7 16 3 0 0 23 20 6 1 21 17 16 6 1 0 14 13 10 9 6 5 2
+ 1 6 7 3 3 4 48 200 22 21 1 15 0 1 12 11 4 3 3 3 0 8 7 0 14
+ 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aogonek" xMin="25" yMin="-370" xMax="1203" yMax="1480">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="920" y="0" on="1"/>
+ <pt x="1027" y="0" on="1"/>
+ <pt x="898" y="-81" on="0"/>
+ <pt x="898" y="-179" on="1"/>
+ <pt x="898" y="-275" on="0"/>
+ <pt x="1013" y="-275" on="1"/>
+ <pt x="1067" y="-275" on="0"/>
+ <pt x="1104" y="-260" on="1"/>
+ <pt x="1104" y="-341" on="1"/>
+ <pt x="1042" y="-370" on="0"/>
+ <pt x="964" y="-370" on="1"/>
+ <pt x="762" y="-370" on="0"/>
+ <pt x="762" y="-213" on="1"/>
+ <pt x="762" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 25 17 30 48 200 19 18 2 7 16 3 28 27 30 3 0 0 17 16 6 1 0 14
+ 13 10 9 6 5 2 1 6 7 3 2 4 48 200 15 0 1 21 20 12 11 4 3 5 2
+ 0 8 7 0 14 0 0 23 20 32 48 200 32 28 27 21 20 19 18 17 16 15 14 13 12
+ 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aring" xMin="25" yMin="0" xMax="1203" yMax="1935">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1935" on="1"/>
+ <pt x="709" y="1935" on="0"/>
+ <pt x="775" y="1869" on="1"/>
+ <pt x="842" y="1803" on="0"/>
+ <pt x="842" y="1709" on="1"/>
+ <pt x="842" y="1612" on="0"/>
+ <pt x="775" y="1547" on="1"/>
+ <pt x="709" y="1481" on="0"/>
+ <pt x="613" y="1481" on="1"/>
+ <pt x="530" y="1481" on="0"/>
+ <pt x="468" y="1535" on="1"/>
+ <pt x="388" y="1604" on="0"/>
+ <pt x="388" y="1708" on="1"/>
+ <pt x="388" y="1802" on="0"/>
+ <pt x="455" y="1868" on="1"/>
+ <pt x="521" y="1935" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1848" on="1"/>
+ <pt x="557" y="1848" on="0"/>
+ <pt x="516" y="1808" on="1"/>
+ <pt x="474" y="1767" on="0"/>
+ <pt x="474" y="1709" on="1"/>
+ <pt x="474" y="1650" on="0"/>
+ <pt x="515" y="1609" on="1"/>
+ <pt x="556" y="1567" on="0"/>
+ <pt x="613" y="1567" on="1"/>
+ <pt x="667" y="1567" on="0"/>
+ <pt x="706" y="1600" on="1"/>
+ <pt x="756" y="1643" on="0"/>
+ <pt x="756" y="1709" on="1"/>
+ <pt x="756" y="1767" on="0"/>
+ <pt x="714" y="1808" on="1"/>
+ <pt x="673" y="1848" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 88 values pushed */
+ 0 0 44 32 28 36 32 20 48 200 28 0 19 18 2 7 16 3 20 7 0 0 17 16 6
+ 1 0 14 13 10 9 6 5 2 1 6 7 3 2 4 48 200 15 0 1 12 11 4 3 3
+ 2 0 8 7 0 14 0 0 48 32 24 40 32 32 48 200 32 24 19 18 17 16 15 14 13
+ 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Atilde" xMin="25" yMin="0" xMax="1203" yMax="1839">
+ <contour>
+ <pt x="327" y="444" on="1"/>
+ <pt x="228" y="123" on="1"/>
+ <pt x="371" y="123" on="1"/>
+ <pt x="371" y="0" on="1"/>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="99" y="123" on="1"/>
+ <pt x="520" y="1480" on="1"/>
+ <pt x="709" y="1480" on="1"/>
+ <pt x="1129" y="123" on="1"/>
+ <pt x="1203" y="123" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="766" y="123" on="1"/>
+ <pt x="923" y="123" on="1"/>
+ <pt x="823" y="444" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="568" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="577" y="1243" on="1"/>
+ <pt x="575" y="1243" on="1"/>
+ </contour>
+ <contour>
+ <pt x="281" y="1604" on="1"/>
+ <pt x="287" y="1699" on="0"/>
+ <pt x="312" y="1749" on="1"/>
+ <pt x="357" y="1839" on="0"/>
+ <pt x="466" y="1839" on="1"/>
+ <pt x="538" y="1839" on="0"/>
+ <pt x="601" y="1800" on="1"/>
+ <pt x="661" y="1763" on="1"/>
+ <pt x="723" y="1725" on="0"/>
+ <pt x="757" y="1725" on="1"/>
+ <pt x="825" y="1725" on="0"/>
+ <pt x="836" y="1839" on="1"/>
+ <pt x="947" y="1839" on="1"/>
+ <pt x="940" y="1745" on="0"/>
+ <pt x="915" y="1695" on="1"/>
+ <pt x="869" y="1604" on="0"/>
+ <pt x="762" y="1604" on="1"/>
+ <pt x="689" y="1604" on="0"/>
+ <pt x="626" y="1643" on="1"/>
+ <pt x="566" y="1680" on="1"/>
+ <pt x="506" y="1717" on="0"/>
+ <pt x="470" y="1717" on="1"/>
+ <pt x="402" y="1717" on="0"/>
+ <pt x="391" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 41 5 24 29 5 36 48 200 19 18 2 7 16 3 43 32 31 20 4 13 36 24 7
+ 0 0 17 16 6 1 0 14 13 10 9 6 5 2 1 6 7 3 2 4 48 200 15 0 1
+ 12 11 4 3 3 2 0 8 7 0 14 43 32 31 20 19 18 17 16 15 14 13 12 11 10
+ 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="B" xMin="74" yMin="0" xMax="1112" yMax="1480">
+ <contour>
+ <pt x="247" y="123" on="1"/>
+ <pt x="247" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="692" y="1480" on="1"/>
+ <pt x="1066" y="1480" on="0"/>
+ <pt x="1066" y="1155" on="1"/>
+ <pt x="1066" y="987" on="0"/>
+ <pt x="964" y="882" on="1"/>
+ <pt x="904" y="819" on="0"/>
+ <pt x="790" y="771" on="1"/>
+ <pt x="888" y="745" on="0"/>
+ <pt x="938" y="715" on="1"/>
+ <pt x="1112" y="610" on="0"/>
+ <pt x="1112" y="377" on="1"/>
+ <pt x="1112" y="0" on="0"/>
+ <pt x="668" y="0" on="1"/>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ </contour>
+ <contour>
+ <pt x="444" y="123" on="1"/>
+ <pt x="607" y="123" on="1"/>
+ <pt x="902" y="123" on="0"/>
+ <pt x="902" y="384" on="1"/>
+ <pt x="902" y="532" on="0"/>
+ <pt x="805" y="618" on="1"/>
+ <pt x="709" y="703" on="0"/>
+ <pt x="541" y="703" on="1"/>
+ <pt x="444" y="703" on="1"/>
+ </contour>
+ <contour>
+ <pt x="444" y="827" on="1"/>
+ <pt x="542" y="827" on="1"/>
+ <pt x="855" y="827" on="0"/>
+ <pt x="855" y="1139" on="1"/>
+ <pt x="855" y="1357" on="0"/>
+ <pt x="644" y="1357" on="1"/>
+ <pt x="444" y="1357" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 29 28 27 26 10 5 1 0 3 0 0 34 33 2 1 6 3 3 20 19 18 0 6 3 16
+ 2 4 48 200 17 16 1 0 4 3 0 14 0 0 31 39 6 22 39 14 48 200 33 29 26
+ 20 16 10 4 7 13 14 6 19 18 17 3 2 4 13 0 0 0 34 28 27 19 10 3 0
+ 1 4 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="C" xMin="123" yMin="-37" xMax="1127" yMax="1517">
+ <contour>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="450" y="-37" on="0"/>
+ <pt x="287" y="169" on="1"/>
+ <pt x="123" y="375" on="0"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="123" y="1117" on="0"/>
+ <pt x="279" y="1317" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1110" on="1"/>
+ <pt x="983" y="1110" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="730" y="1394" on="1"/>
+ <pt x="543" y="1394" on="0"/>
+ <pt x="439" y="1218" on="1"/>
+ <pt x="336" y="1043" on="0"/>
+ <pt x="336" y="734" on="1"/>
+ <pt x="336" y="435" on="0"/>
+ <pt x="450" y="267" on="1"/>
+ <pt x="563" y="99" on="0"/>
+ <pt x="763" y="99" on="1"/>
+ <pt x="941" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 55 values pushed */
+ 0 0 25 20 2 17 5 10 48 200 10 0 2 2 1 1 27 15 14 13 12 0 6 0 2
+ 3 0 0 14 0 0 21 39 6 48 200 15 14 6 12 0 0 13 12 29 1 0 1 5 48
+ 200 27 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Cacute" xMin="123" yMin="-37" xMax="1127" yMax="1925">
+ <contour>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="450" y="-37" on="0"/>
+ <pt x="287" y="169" on="1"/>
+ <pt x="123" y="375" on="0"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="123" y="1117" on="0"/>
+ <pt x="279" y="1317" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1110" on="1"/>
+ <pt x="983" y="1110" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="730" y="1394" on="1"/>
+ <pt x="543" y="1394" on="0"/>
+ <pt x="439" y="1218" on="1"/>
+ <pt x="336" y="1043" on="0"/>
+ <pt x="336" y="734" on="1"/>
+ <pt x="336" y="435" on="0"/>
+ <pt x="450" y="267" on="1"/>
+ <pt x="563" y="99" on="0"/>
+ <pt x="763" y="99" on="1"/>
+ <pt x="941" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ </contour>
+ <contour>
+ <pt x="591" y="1604" on="1"/>
+ <pt x="807" y="1925" on="1"/>
+ <pt x="1035" y="1925" on="1"/>
+ <pt x="714" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 0 0 25 20 2 17 5 10 48 200 10 0 2 2 1 31 28 2 29 0 3 0 1 1 27
+ 15 14 13 12 0 6 0 2 3 0 0 30 29 1 0 14 0 0 21 39 6 48 200 31 30
+ 29 28 15 14 6 13 6 12 0 0 13 12 29 1 0 1 5 48 200 27 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccaron" xMin="123" yMin="-37" xMax="1127" yMax="1925">
+ <contour>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="450" y="-37" on="0"/>
+ <pt x="287" y="169" on="1"/>
+ <pt x="123" y="375" on="0"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="123" y="1117" on="0"/>
+ <pt x="279" y="1317" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1110" on="1"/>
+ <pt x="983" y="1110" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="730" y="1394" on="1"/>
+ <pt x="543" y="1394" on="0"/>
+ <pt x="439" y="1218" on="1"/>
+ <pt x="336" y="1043" on="0"/>
+ <pt x="336" y="734" on="1"/>
+ <pt x="336" y="435" on="0"/>
+ <pt x="450" y="267" on="1"/>
+ <pt x="563" y="99" on="0"/>
+ <pt x="763" y="99" on="1"/>
+ <pt x="941" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1080" y="1925" on="1"/>
+ <pt x="823" y="1604" on="1"/>
+ <pt x="605" y="1604" on="1"/>
+ <pt x="348" y="1925" on="1"/>
+ <pt x="472" y="1925" on="1"/>
+ <pt x="713" y="1723" on="1"/>
+ <pt x="715" y="1723" on="1"/>
+ <pt x="957" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 78 values pushed */
+ 0 0 25 20 2 17 5 10 48 200 10 0 2 2 1 1 27 15 14 13 12 0 6 0 2
+ 3 0 0 35 34 33 32 31 28 6 13 29 30 29 1 0 14 0 0 21 39 6 48 200 35
+ 34 33 32 31 30 29 28 15 14 10 13 6 12 0 0 13 12 29 1 0 1 5 48 200 27
+ 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccedilla" xMin="123" yMin="-432" xMax="1127" yMax="1517">
+ <contour>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="450" y="-37" on="0"/>
+ <pt x="287" y="169" on="1"/>
+ <pt x="123" y="375" on="0"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="123" y="1117" on="0"/>
+ <pt x="279" y="1317" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1110" on="1"/>
+ <pt x="983" y="1110" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="730" y="1394" on="1"/>
+ <pt x="542" y="1394" on="0"/>
+ <pt x="439" y="1218" on="1"/>
+ <pt x="336" y="1042" on="0"/>
+ <pt x="336" y="734" on="1"/>
+ <pt x="336" y="436" on="0"/>
+ <pt x="450" y="267" on="1"/>
+ <pt x="563" y="99" on="0"/>
+ <pt x="763" y="99" on="1"/>
+ <pt x="941" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ </contour>
+ <contour>
+ <pt x="669" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="706" y="-109" on="1"/>
+ <pt x="778" y="-111" on="0"/>
+ <pt x="830" y="-148" on="1"/>
+ <pt x="900" y="-197" on="0"/>
+ <pt x="900" y="-269" on="1"/>
+ <pt x="900" y="-337" on="0"/>
+ <pt x="841" y="-384" on="1"/>
+ <pt x="782" y="-432" on="0"/>
+ <pt x="697" y="-432" on="1"/>
+ <pt x="630" y="-432" on="0"/>
+ <pt x="553" y="-411" on="1"/>
+ <pt x="553" y="-330" on="1"/>
+ <pt x="603" y="-345" on="0"/>
+ <pt x="657" y="-345" on="1"/>
+ <pt x="761" y="-345" on="0"/>
+ <pt x="761" y="-271" on="1"/>
+ <pt x="761" y="-178" on="0"/>
+ <pt x="574" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 43 32 38 25 20 2 17 5 10 48 200 10 0 2 2 1 1 27 15 14 13 12 0
+ 6 0 2 3 0 0 1 47 41 40 30 29 28 6 13 38 2 0 14 0 0 45 20 34 21
+ 39 6 48 200 47 41 40 30 29 28 15 14 8 13 34 6 12 0 0 13 12 29 1 0 1
+ 5 48 200 27 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccircumflex" xMin="123" yMin="-37" xMax="1127" yMax="1925">
+ <contour>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="450" y="-37" on="0"/>
+ <pt x="287" y="169" on="1"/>
+ <pt x="123" y="375" on="0"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="123" y="1117" on="0"/>
+ <pt x="279" y="1317" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1110" on="1"/>
+ <pt x="983" y="1110" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="730" y="1394" on="1"/>
+ <pt x="543" y="1394" on="0"/>
+ <pt x="439" y="1218" on="1"/>
+ <pt x="336" y="1043" on="0"/>
+ <pt x="336" y="734" on="1"/>
+ <pt x="336" y="435" on="0"/>
+ <pt x="450" y="267" on="1"/>
+ <pt x="563" y="99" on="0"/>
+ <pt x="763" y="99" on="1"/>
+ <pt x="941" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ </contour>
+ <contour>
+ <pt x="348" y="1604" on="1"/>
+ <pt x="604" y="1925" on="1"/>
+ <pt x="823" y="1925" on="1"/>
+ <pt x="1079" y="1604" on="1"/>
+ <pt x="956" y="1604" on="1"/>
+ <pt x="715" y="1806" on="1"/>
+ <pt x="712" y="1806" on="1"/>
+ <pt x="471" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 25 20 2 17 5 10 48 200 10 0 2 2 1 35 34 33 32 31 28 6 29 0 3
+ 0 1 1 27 15 14 13 12 0 6 0 2 3 0 0 30 29 1 0 14 0 0 21 39 6
+ 48 200 35 34 33 32 31 30 29 28 15 14 10 13 6 12 0 0 13 12 29 1 0 1 5
+ 48 200 27 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Cdotaccent" xMin="123" yMin="-37" xMax="1127" yMax="1801">
+ <contour>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="450" y="-37" on="0"/>
+ <pt x="287" y="169" on="1"/>
+ <pt x="123" y="375" on="0"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="123" y="1117" on="0"/>
+ <pt x="279" y="1317" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1110" on="1"/>
+ <pt x="983" y="1110" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="730" y="1394" on="1"/>
+ <pt x="543" y="1394" on="0"/>
+ <pt x="439" y="1218" on="1"/>
+ <pt x="336" y="1043" on="0"/>
+ <pt x="336" y="734" on="1"/>
+ <pt x="336" y="435" on="0"/>
+ <pt x="450" y="267" on="1"/>
+ <pt x="563" y="99" on="0"/>
+ <pt x="763" y="99" on="1"/>
+ <pt x="941" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1604" on="1"/>
+ <pt x="615" y="1801" on="1"/>
+ <pt x="812" y="1801" on="1"/>
+ <pt x="812" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 25 20 2 17 5 10 48 200 10 0 2 2 1 1 27 15 14 13 12 0 6 0 2
+ 3 0 0 0 0 31 28 10 1 29 1 4 48 200 30 29 1 0 14 0 0 21 39 6 48
+ 200 15 14 2 12 30 3 6 28 0 0 31 30 10 1 28 1 4 13 12 29 1 0 1 5
+ 48 200 29 28 1 27 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="D" xMin="49" yMin="0" xMax="1167" yMax="1480">
+ <contour>
+ <pt x="49" y="0" on="1"/>
+ <pt x="49" y="123" on="1"/>
+ <pt x="197" y="123" on="1"/>
+ <pt x="197" y="1357" on="1"/>
+ <pt x="49" y="1357" on="1"/>
+ <pt x="49" y="1480" on="1"/>
+ <pt x="559" y="1480" on="1"/>
+ <pt x="1167" y="1480" on="0"/>
+ <pt x="1167" y="775" on="1"/>
+ <pt x="1167" y="419" on="0"/>
+ <pt x="1007" y="209" on="1"/>
+ <pt x="847" y="0" on="0"/>
+ <pt x="577" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="395" y="123" on="1"/>
+ <pt x="513" y="123" on="1"/>
+ <pt x="954" y="123" on="0"/>
+ <pt x="954" y="754" on="1"/>
+ <pt x="954" y="1063" on="0"/>
+ <pt x="843" y="1210" on="1"/>
+ <pt x="731" y="1357" on="0"/>
+ <pt x="499" y="1357" on="1"/>
+ <pt x="395" y="1357" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 21 20 4 3 6 3 5 14 13 2 1 6 3 0 2 4 48 200 12 0 1 0 6
+ 5 0 14 0 0 16 39 8 48 200 20 14 12 6 4 13 8 13 5 4 1 0 4 13 2
+ 0 0 21 13 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Dcaron" xMin="49" yMin="0" xMax="1167" yMax="1925">
+ <contour>
+ <pt x="49" y="0" on="1"/>
+ <pt x="49" y="123" on="1"/>
+ <pt x="197" y="123" on="1"/>
+ <pt x="197" y="1357" on="1"/>
+ <pt x="49" y="1357" on="1"/>
+ <pt x="49" y="1480" on="1"/>
+ <pt x="559" y="1480" on="1"/>
+ <pt x="1167" y="1480" on="0"/>
+ <pt x="1167" y="775" on="1"/>
+ <pt x="1167" y="419" on="0"/>
+ <pt x="1007" y="209" on="1"/>
+ <pt x="847" y="0" on="0"/>
+ <pt x="577" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="395" y="123" on="1"/>
+ <pt x="513" y="123" on="1"/>
+ <pt x="954" y="123" on="0"/>
+ <pt x="954" y="754" on="1"/>
+ <pt x="954" y="1063" on="0"/>
+ <pt x="843" y="1210" on="1"/>
+ <pt x="731" y="1357" on="0"/>
+ <pt x="499" y="1357" on="1"/>
+ <pt x="395" y="1357" on="1"/>
+ </contour>
+ <contour>
+ <pt x="919" y="1925" on="1"/>
+ <pt x="662" y="1604" on="1"/>
+ <pt x="444" y="1604" on="1"/>
+ <pt x="187" y="1925" on="1"/>
+ <pt x="311" y="1925" on="1"/>
+ <pt x="552" y="1723" on="1"/>
+ <pt x="554" y="1723" on="1"/>
+ <pt x="796" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 29 28 27 26 25 22 6 13 23 0 0 21 20 4 3 6 3 5 14 13 2 1 6 3 0
+ 2 4 48 200 24 23 1 12 0 1 2 0 6 5 0 14 0 0 16 39 8 48 200 26 13
+ 2 2 29 28 27 24 23 22 20 14 12 6 10 13 8 13 25 5 4 1 0 5 13 2 0
+ 0 21 13 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Dcroat" xMin="49" yMin="0" xMax="1167" yMax="1480">
+ <contour>
+ <pt x="49" y="0" on="1"/>
+ <pt x="49" y="123" on="1"/>
+ <pt x="197" y="123" on="1"/>
+ <pt x="197" y="716" on="1"/>
+ <pt x="49" y="716" on="1"/>
+ <pt x="49" y="839" on="1"/>
+ <pt x="197" y="839" on="1"/>
+ <pt x="197" y="1357" on="1"/>
+ <pt x="49" y="1357" on="1"/>
+ <pt x="49" y="1480" on="1"/>
+ <pt x="558" y="1480" on="1"/>
+ <pt x="1167" y="1480" on="0"/>
+ <pt x="1167" y="776" on="1"/>
+ <pt x="1167" y="419" on="0"/>
+ <pt x="1007" y="209" on="1"/>
+ <pt x="847" y="0" on="0"/>
+ <pt x="577" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="394" y="1357" on="1"/>
+ <pt x="394" y="839" on="1"/>
+ <pt x="666" y="839" on="1"/>
+ <pt x="666" y="716" on="1"/>
+ <pt x="394" y="716" on="1"/>
+ <pt x="394" y="123" on="1"/>
+ <pt x="513" y="123" on="1"/>
+ <pt x="954" y="123" on="0"/>
+ <pt x="954" y="754" on="1"/>
+ <pt x="954" y="1062" on="0"/>
+ <pt x="842" y="1210" on="1"/>
+ <pt x="730" y="1357" on="0"/>
+ <pt x="499" y="1357" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 29 17 8 7 6 3 9 21 20 4 3 6 3 5 23 22 2 1 6 3 0 3 4
+ 48 200 19 18 6 5 3 16 0 1 2 0 10 9 0 14 0 0 25 39 12 48 200 29 23
+ 20 19 16 10 6 13 12 17 9 8 5 4 1 0 6 13 2 0 0 22 21 18 17 10 3
+ 2 1 4 48 200 7 6 3 2 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="E" xMin="74" yMin="0" xMax="1106" yMax="1480">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 0 0 10 9 4 3 6 3 5
+ 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0 4 4 48 200 12 11 1 23 0 1
+ 2 0 6 5 0 14 17 16 13 12 4 14 10 3 5 4 1 0 4 13 2 0 0 21 20
+ 6 1 22 9 8 6 1 6 19 18 11 10 10 3 2 3 4 48 200 23 22 1 7 6 1
+ 15 14 1 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eacute" xMin="74" yMin="0" xMax="1106" yMax="1925">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="481" y="1604" on="1"/>
+ <pt x="697" y="1925" on="1"/>
+ <pt x="925" y="1925" on="1"/>
+ <pt x="604" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 124 values pushed */
+ 27 24 2 25 5 3 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 0 0 10
+ 9 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0 4 4 48 200
+ 26 25 1 12 11 1 23 0 1 3 0 6 5 0 14 26 8 14 2 27 25 24 17 16 13
+ 12 7 14 10 3 5 4 1 0 4 13 2 0 0 21 20 6 1 22 9 8 6 1 6 19
+ 18 11 10 10 3 2 3 4 48 200 23 22 1 7 6 1 15 14 1 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ebreve" xMin="74" yMin="0" xMax="1106" yMax="1925">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="259" y="1925" on="1"/>
+ <pt x="382" y="1925" on="1"/>
+ <pt x="430" y="1777" on="0"/>
+ <pt x="604" y="1777" on="1"/>
+ <pt x="779" y="1777" on="0"/>
+ <pt x="827" y="1925" on="1"/>
+ <pt x="950" y="1925" on="1"/>
+ <pt x="927" y="1836" on="0"/>
+ <pt x="901" y="1790" on="1"/>
+ <pt x="810" y="1635" on="0"/>
+ <pt x="608" y="1635" on="1"/>
+ <pt x="456" y="1635" on="0"/>
+ <pt x="367" y="1716" on="1"/>
+ <pt x="312" y="1765" on="0"/>
+ <pt x="284" y="1837" on="1"/>
+ <pt x="273" y="1866" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 133 values pushed */
+ 0 0 27 14 34 48 200 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 30 29
+ 25 24 4 13 34 5 0 0 10 9 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0
+ 2 1 6 1 0 4 4 48 200 12 11 1 23 0 1 2 0 6 5 0 14 30 20 8 2
+ 29 17 16 13 12 5 14 10 3 25 10 2 2 5 4 1 0 4 13 2 0 0 21 20 6
+ 1 22 9 8 6 1 6 19 18 11 10 10 3 2 3 4 48 200 23 22 1 7 6 1 15
+ 14 1 24 3 2 2 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ecaron" xMin="74" yMin="0" xMax="1106" yMax="1925">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="957" y="1925" on="1"/>
+ <pt x="700" y="1604" on="1"/>
+ <pt x="482" y="1604" on="1"/>
+ <pt x="225" y="1925" on="1"/>
+ <pt x="349" y="1925" on="1"/>
+ <pt x="590" y="1723" on="1"/>
+ <pt x="592" y="1723" on="1"/>
+ <pt x="834" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 134 values pushed */
+ 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 31 30 29 28 27 24 6 13 25
+ 0 0 10 9 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0 4
+ 4 48 200 26 25 1 12 11 1 23 0 1 3 0 6 5 0 14 24 20 8 2 31 30 29
+ 26 25 17 16 13 12 9 14 10 3 28 10 2 2 27 5 4 1 0 5 13 2 0 0 21
+ 20 6 1 22 9 8 6 1 6 19 18 11 10 10 3 2 3 4 48 200 23 22 1 7 6
+ 1 15 14 1 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ecircumflex" xMin="74" yMin="0" xMax="1106" yMax="1925">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="259" y="1604" on="1"/>
+ <pt x="515" y="1925" on="1"/>
+ <pt x="734" y="1925" on="1"/>
+ <pt x="990" y="1604" on="1"/>
+ <pt x="867" y="1604" on="1"/>
+ <pt x="626" y="1806" on="1"/>
+ <pt x="623" y="1806" on="1"/>
+ <pt x="382" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 135 values pushed */
+ 31 30 29 28 27 24 6 25 5 3 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19
+ 3 0 0 10 9 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0
+ 4 4 48 200 26 25 1 12 11 1 23 0 1 3 0 6 5 0 14 27 6 20 2 30 29
+ 28 26 25 17 16 13 12 9 14 10 3 31 10 2 2 5 4 1 0 4 13 2 0 0 21
+ 20 6 1 22 9 8 6 1 6 19 18 11 10 10 3 2 3 4 48 200 23 22 1 7 6
+ 1 15 14 1 24 3 2 2 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Edieresis" xMin="74" yMin="0" xMax="1106" yMax="1801">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="259" y="1604" on="1"/>
+ <pt x="259" y="1801" on="1"/>
+ <pt x="456" y="1801" on="1"/>
+ <pt x="456" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="728" y="1604" on="1"/>
+ <pt x="728" y="1801" on="1"/>
+ <pt x="925" y="1801" on="1"/>
+ <pt x="925" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 135 values pushed */
+ 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 0 0 31 28 27 24 10 3 25
+ 10 9 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0 5 4 48
+ 200 30 29 26 25 3 12 11 1 23 0 1 3 0 6 5 0 14 17 16 13 12 4 14 28
+ 3 5 4 1 0 4 13 2 0 0 29 28 10 1 30 27 26 10 1 2 21 20 6 1 22
+ 9 8 6 1 6 19 18 11 10 10 3 2 5 4 48 200 31 30 1 23 22 1 7 6 1
+ 15 14 1 25 24 3 2 3 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Edotaccent" xMin="74" yMin="0" xMax="1106" yMax="1801">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="543" y="1604" on="1"/>
+ <pt x="543" y="1801" on="1"/>
+ <pt x="740" y="1801" on="1"/>
+ <pt x="740" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 124 values pushed */
+ 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 0 0 27 24 10 1 25 10 9
+ 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0 5 4 48 200 26
+ 25 1 12 11 1 23 0 1 3 0 6 5 0 14 17 16 13 12 4 14 26 3 5 4 1
+ 0 4 13 2 0 0 27 26 10 1 24 21 20 6 1 22 9 8 6 1 6 19 18 11 10
+ 10 3 2 4 4 48 200 25 24 1 23 22 1 7 6 1 15 14 1 3 2 1 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Egrave" xMin="74" yMin="0" xMax="1106" yMax="1925">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="740" y="1604" on="1"/>
+ <pt x="617" y="1604" on="1"/>
+ <pt x="296" y="1925" on="1"/>
+ <pt x="524" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 124 values pushed */
+ 25 24 2 26 5 3 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 0 0 10
+ 9 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0 4 4 48 200
+ 27 26 1 12 11 1 23 0 1 3 0 6 5 0 14 27 25 24 17 16 13 12 7 14 10
+ 3 26 10 2 2 5 4 1 0 4 13 2 0 0 21 20 6 1 22 9 8 6 1 6 19
+ 18 11 10 10 3 2 3 4 48 200 23 22 1 7 6 1 15 14 1 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Emacron" xMin="74" yMin="0" xMax="1106" yMax="1728">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="284" y="1604" on="1"/>
+ <pt x="284" y="1728" on="1"/>
+ <pt x="975" y="1728" on="1"/>
+ <pt x="975" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 128 values pushed */
+ 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 0 0 27 24 6 1 25 10 9
+ 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1 0 5 4 48 200 26
+ 25 1 12 11 1 23 0 1 3 0 6 5 0 14 27 26 2 20 8 3 17 16 13 12 4
+ 14 10 3 25 24 2 10 2 3 5 4 1 0 4 13 2 0 0 21 20 6 1 22 9 8
+ 6 1 6 19 18 11 10 10 3 2 3 4 48 200 23 22 1 7 6 1 15 14 1 3 2
+ 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eng" xMin="74" yMin="-296" xMax="1155" yMax="1480">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="185" y="123" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="308" y="1480" on="1"/>
+ <pt x="918" y="405" on="1"/>
+ <pt x="920" y="405" on="1"/>
+ <pt x="920" y="1357" on="1"/>
+ <pt x="810" y="1357" on="1"/>
+ <pt x="810" y="1480" on="1"/>
+ <pt x="1155" y="1480" on="1"/>
+ <pt x="1155" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="0" on="1"/>
+ <pt x="1044" y="-134" on="0"/>
+ <pt x="964" y="-215" on="1"/>
+ <pt x="885" y="-296" on="0"/>
+ <pt x="752" y="-296" on="1"/>
+ <pt x="664" y="-296" on="0"/>
+ <pt x="536" y="-259" on="1"/>
+ <pt x="536" y="-49" on="1"/>
+ <pt x="659" y="-49" on="1"/>
+ <pt x="672" y="-167" on="1"/>
+ <pt x="736" y="-198" on="0"/>
+ <pt x="783" y="-198" on="1"/>
+ <pt x="845" y="-198" on="0"/>
+ <pt x="880" y="-158" on="1"/>
+ <pt x="922" y="-111" on="0"/>
+ <pt x="922" y="-26" on="1"/>
+ <pt x="922" y="-19" on="0"/>
+ <pt x="921" y="-10" on="1"/>
+ <pt x="920" y="0" on="1"/>
+ <pt x="311" y="1076" on="1"/>
+ <pt x="308" y="1076" on="1"/>
+ <pt x="308" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 0 0 26 17 19 48 200 37 36 35 34 14 13 10 9 8 7 4 3 2 1 14 5 0 3
+ 24 23 22 21 4 13 19 0 38 33 15 0 3 0 12 11 6 5 0 3 14 30 30 14 8
+ 2 24 23 11 10 7 5 8 21 3 38 37 34 3 21 6 3 13 12 2 13 14 5 4 1
+ 0 4 13 2 0 0 33 9 8 6 2 14 36 35 6 6 2 2 2 4 48 200 15 14 1
+ 22 21 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eogonek" xMin="74" yMin="-370" xMax="1106" yMax="1480">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="259" y="123" on="1"/>
+ <pt x="259" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="1056" y="1480" on="1"/>
+ <pt x="1056" y="1123" on="1"/>
+ <pt x="933" y="1123" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="457" y="1357" on="1"/>
+ <pt x="457" y="814" on="1"/>
+ <pt x="748" y="814" on="1"/>
+ <pt x="748" y="938" on="1"/>
+ <pt x="871" y="938" on="1"/>
+ <pt x="871" y="567" on="1"/>
+ <pt x="748" y="567" on="1"/>
+ <pt x="748" y="691" on="1"/>
+ <pt x="457" y="691" on="1"/>
+ <pt x="457" y="136" on="1"/>
+ <pt x="982" y="136" on="1"/>
+ <pt x="982" y="383" on="1"/>
+ <pt x="1106" y="383" on="1"/>
+ <pt x="1106" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="860" y="0" on="1"/>
+ <pt x="967" y="0" on="1"/>
+ <pt x="838" y="-81" on="0"/>
+ <pt x="838" y="-179" on="1"/>
+ <pt x="838" y="-275" on="0"/>
+ <pt x="953" y="-275" on="1"/>
+ <pt x="1007" y="-275" on="0"/>
+ <pt x="1044" y="-260" on="1"/>
+ <pt x="1044" y="-341" on="1"/>
+ <pt x="982" y="-370" on="0"/>
+ <pt x="904" y="-370" on="1"/>
+ <pt x="702" y="-370" on="0"/>
+ <pt x="702" y="-213" on="1"/>
+ <pt x="702" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 141 values pushed */
+ 0 0 29 17 34 48 200 14 13 8 7 4 3 11 3 22 21 16 15 4 17 19 3 32 31
+ 34 0 0 0 10 9 4 3 6 3 5 18 17 6 1 11 20 19 20 1 0 2 1 6 1
+ 0 4 4 48 200 12 11 1 25 24 23 0 3 2 0 6 5 0 14 0 0 27 20 36 48
+ 200 32 31 2 6 20 3 25 20 8 2 36 36 24 17 16 13 12 6 14 10 3 5 4 1
+ 0 4 13 2 0 0 21 20 6 1 22 9 8 6 1 6 19 18 11 10 10 3 2 3 4
+ 48 200 23 22 1 7 6 1 15 14 1 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eth" xMin="49" yMin="0" xMax="1167" yMax="1480">
+ <contour>
+ <pt x="49" y="0" on="1"/>
+ <pt x="49" y="123" on="1"/>
+ <pt x="197" y="123" on="1"/>
+ <pt x="197" y="716" on="1"/>
+ <pt x="49" y="716" on="1"/>
+ <pt x="49" y="839" on="1"/>
+ <pt x="197" y="839" on="1"/>
+ <pt x="197" y="1357" on="1"/>
+ <pt x="49" y="1357" on="1"/>
+ <pt x="49" y="1480" on="1"/>
+ <pt x="558" y="1480" on="1"/>
+ <pt x="1167" y="1480" on="0"/>
+ <pt x="1167" y="776" on="1"/>
+ <pt x="1167" y="419" on="0"/>
+ <pt x="1007" y="209" on="1"/>
+ <pt x="847" y="0" on="0"/>
+ <pt x="577" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="394" y="1357" on="1"/>
+ <pt x="394" y="839" on="1"/>
+ <pt x="666" y="839" on="1"/>
+ <pt x="666" y="716" on="1"/>
+ <pt x="394" y="716" on="1"/>
+ <pt x="394" y="123" on="1"/>
+ <pt x="513" y="123" on="1"/>
+ <pt x="954" y="123" on="0"/>
+ <pt x="954" y="754" on="1"/>
+ <pt x="954" y="1062" on="0"/>
+ <pt x="842" y="1210" on="1"/>
+ <pt x="730" y="1357" on="0"/>
+ <pt x="499" y="1357" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 29 17 8 7 6 3 9 21 20 4 3 6 3 5 23 22 2 1 6 3 0 3 4
+ 48 200 19 18 6 5 3 16 0 1 2 0 10 9 0 14 0 0 25 39 12 48 200 29 23
+ 20 19 16 10 6 13 12 17 9 8 5 4 1 0 6 13 2 0 0 22 21 18 17 10 3
+ 2 1 4 48 200 7 6 3 2 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Euro" xMin="6" yMin="-37" xMax="1127" yMax="1517">
+ <contour>
+ <pt x="127" y="857" on="1"/>
+ <pt x="6" y="857" on="1"/>
+ <pt x="57" y="981" on="1"/>
+ <pt x="143" y="981" on="1"/>
+ <pt x="182" y="1150" on="0"/>
+ <pt x="230" y="1236" on="1"/>
+ <pt x="385" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1172" on="1"/>
+ <pt x="983" y="1172" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="729" y="1394" on="1"/>
+ <pt x="536" y="1394" on="0"/>
+ <pt x="438" y="1222" on="1"/>
+ <pt x="389" y="1137" on="0"/>
+ <pt x="359" y="981" on="1"/>
+ <pt x="1027" y="981" on="1"/>
+ <pt x="976" y="857" on="1"/>
+ <pt x="341" y="857" on="1"/>
+ <pt x="337" y="802" on="0"/>
+ <pt x="337" y="785" on="1"/>
+ <pt x="336" y="761" on="0"/>
+ <pt x="335" y="757" on="1"/>
+ <pt x="334" y="743" on="0"/>
+ <pt x="335" y="739" on="1"/>
+ <pt x="336" y="734" on="0"/>
+ <pt x="336" y="733" on="1"/>
+ <pt x="338" y="660" on="1"/>
+ <pt x="894" y="660" on="1"/>
+ <pt x="843" y="537" on="1"/>
+ <pt x="351" y="537" on="1"/>
+ <pt x="377" y="399" on="0"/>
+ <pt x="415" y="320" on="1"/>
+ <pt x="521" y="99" on="0"/>
+ <pt x="762" y="99" on="1"/>
+ <pt x="942" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="740" y="-37" on="1"/>
+ <pt x="501" y="-37" on="0"/>
+ <pt x="348" y="104" on="1"/>
+ <pt x="242" y="202" on="0"/>
+ <pt x="186" y="357" on="1"/>
+ <pt x="165" y="416" on="0"/>
+ <pt x="139" y="537" on="1"/>
+ <pt x="6" y="537" on="1"/>
+ <pt x="57" y="660" on="1"/>
+ <pt x="125" y="660" on="1"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="121" y="759" on="1"/>
+ <pt x="121" y="760" on="0"/>
+ <pt x="123" y="768" on="1"/>
+ <pt x="124" y="772" on="0"/>
+ <pt x="124" y="791" on="1"/>
+ <pt x="123" y="797" on="0"/>
+ <pt x="125" y="815" on="1"/>
+ <pt x="126" y="840" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 114 values pushed */
+ 0 0 37 20 42 14 5 7 48 200 42 2 7 0 1 12 11 10 9 4 0 2 3 0 52
+ 0 30 2 1 40 39 2 32 2 3 0 0 0 21 20 1 0 6 3 2 49 48 33 32 6
+ 3 30 2 4 48 200 19 18 3 2 3 51 50 31 30 3 2 0 14 0 0 27 36 53 48
+ 200 52 51 50 49 48 33 32 31 30 21 20 19 18 12 11 3 2 1 0 19 13 53 9 0
+ 0 10 9 29 1 39 1 5 48 200 40 39 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Euro#1" xMin="6" yMin="-37" xMax="1127" yMax="1517">
+ <contour>
+ <pt x="127" y="857" on="1"/>
+ <pt x="6" y="857" on="1"/>
+ <pt x="57" y="981" on="1"/>
+ <pt x="143" y="981" on="1"/>
+ <pt x="182" y="1150" on="0"/>
+ <pt x="230" y="1236" on="1"/>
+ <pt x="385" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="889" y="1517" on="0"/>
+ <pt x="1106" y="1453" on="1"/>
+ <pt x="1106" y="1172" on="1"/>
+ <pt x="983" y="1172" on="1"/>
+ <pt x="954" y="1341" on="1"/>
+ <pt x="841" y="1394" on="0"/>
+ <pt x="729" y="1394" on="1"/>
+ <pt x="536" y="1394" on="0"/>
+ <pt x="438" y="1222" on="1"/>
+ <pt x="389" y="1137" on="0"/>
+ <pt x="359" y="981" on="1"/>
+ <pt x="1027" y="981" on="1"/>
+ <pt x="976" y="857" on="1"/>
+ <pt x="341" y="857" on="1"/>
+ <pt x="337" y="802" on="0"/>
+ <pt x="337" y="785" on="1"/>
+ <pt x="336" y="761" on="0"/>
+ <pt x="335" y="757" on="1"/>
+ <pt x="334" y="743" on="0"/>
+ <pt x="335" y="739" on="1"/>
+ <pt x="336" y="734" on="0"/>
+ <pt x="336" y="733" on="1"/>
+ <pt x="338" y="660" on="1"/>
+ <pt x="894" y="660" on="1"/>
+ <pt x="843" y="537" on="1"/>
+ <pt x="351" y="537" on="1"/>
+ <pt x="377" y="399" on="0"/>
+ <pt x="415" y="320" on="1"/>
+ <pt x="521" y="99" on="0"/>
+ <pt x="762" y="99" on="1"/>
+ <pt x="942" y="99" on="0"/>
+ <pt x="1127" y="234" on="1"/>
+ <pt x="1127" y="74" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="740" y="-37" on="1"/>
+ <pt x="501" y="-37" on="0"/>
+ <pt x="348" y="104" on="1"/>
+ <pt x="242" y="202" on="0"/>
+ <pt x="186" y="357" on="1"/>
+ <pt x="165" y="416" on="0"/>
+ <pt x="139" y="537" on="1"/>
+ <pt x="6" y="537" on="1"/>
+ <pt x="57" y="660" on="1"/>
+ <pt x="125" y="660" on="1"/>
+ <pt x="123" y="748" on="1"/>
+ <pt x="121" y="759" on="1"/>
+ <pt x="121" y="760" on="0"/>
+ <pt x="123" y="768" on="1"/>
+ <pt x="124" y="772" on="0"/>
+ <pt x="124" y="791" on="1"/>
+ <pt x="123" y="797" on="0"/>
+ <pt x="125" y="815" on="1"/>
+ <pt x="126" y="840" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 114 values pushed */
+ 0 0 37 20 42 14 5 7 48 200 42 2 7 0 1 12 11 10 9 4 0 2 3 0 52
+ 0 30 2 1 40 39 2 32 2 3 0 0 0 21 20 1 0 6 3 2 49 48 33 32 6
+ 3 30 2 4 48 200 19 18 3 2 3 51 50 31 30 3 2 0 14 0 0 27 36 53 48
+ 200 52 51 50 49 48 33 32 31 30 21 20 19 18 12 11 3 2 1 0 19 13 53 9 0
+ 0 10 9 29 1 39 1 5 48 200 40 39 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="F" xMin="111" yMin="0" xMax="1136" yMax="1480">
+ <contour>
+ <pt x="530" y="123" on="1"/>
+ <pt x="802" y="123" on="1"/>
+ <pt x="802" y="0" on="1"/>
+ <pt x="111" y="0" on="1"/>
+ <pt x="111" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="1357" on="1"/>
+ <pt x="111" y="1357" on="1"/>
+ <pt x="111" y="1480" on="1"/>
+ <pt x="1136" y="1480" on="1"/>
+ <pt x="1136" y="1110" on="1"/>
+ <pt x="1013" y="1110" on="1"/>
+ <pt x="1013" y="1357" on="1"/>
+ <pt x="530" y="1357" on="1"/>
+ <pt x="530" y="777" on="1"/>
+ <pt x="828" y="777" on="1"/>
+ <pt x="828" y="901" on="1"/>
+ <pt x="951" y="901" on="1"/>
+ <pt x="951" y="530" on="1"/>
+ <pt x="828" y="530" on="1"/>
+ <pt x="828" y="654" on="1"/>
+ <pt x="530" y="654" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 17 16 11 10 4 6 14 3 19 18 2 20 0 3 0 0 13 12 7 6 6 3 8 21 20
+ 6 1 14 5 4 1 0 6 3 2 3 4 48 200 15 14 1 3 2 1 2 0 9 8 0
+ 14 20 19 16 15 2 1 6 17 0 3 8 7 4 3 4 13 5 0 0 12 11 6 1 9
+ 21 14 13 0 10 3 5 2 4 48 200 10 9 1 18 17 1 6 5 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="G" xMin="74" yMin="-37" xMax="1081" yMax="1518">
+ <contour>
+ <pt x="1081" y="74" on="1"/>
+ <pt x="899" y="-37" on="0"/>
+ <pt x="698" y="-37" on="1"/>
+ <pt x="402" y="-37" on="0"/>
+ <pt x="238" y="169" on="1"/>
+ <pt x="74" y="374" on="0"/>
+ <pt x="74" y="747" on="1"/>
+ <pt x="74" y="1120" on="0"/>
+ <pt x="231" y="1319" on="1"/>
+ <pt x="389" y="1518" on="0"/>
+ <pt x="688" y="1518" on="1"/>
+ <pt x="861" y="1518" on="0"/>
+ <pt x="1057" y="1456" on="1"/>
+ <pt x="1057" y="1110" on="1"/>
+ <pt x="934" y="1110" on="1"/>
+ <pt x="905" y="1341" on="1"/>
+ <pt x="791" y="1395" on="0"/>
+ <pt x="692" y="1395" on="1"/>
+ <pt x="287" y="1395" on="0"/>
+ <pt x="287" y="737" on="1"/>
+ <pt x="287" y="430" on="0"/>
+ <pt x="402" y="264" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="721" y="99" on="1"/>
+ <pt x="799" y="99" on="0"/>
+ <pt x="883" y="131" on="1"/>
+ <pt x="883" y="537" on="1"/>
+ <pt x="711" y="537" on="1"/>
+ <pt x="711" y="660" on="1"/>
+ <pt x="1081" y="660" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 0 0 23 20 2 17 5 10 48 200 10 0 2 2 1 15 14 13 12 4 0 28 3 0 1
+ 25 0 2 26 2 3 0 0 0 27 26 6 1 28 1 4 48 200 29 28 1 0 14 0 0
+ 19 39 6 48 200 15 14 2 12 25 3 28 27 6 25 0 0 26 25 10 1 0 1 4 48
+ 200 29 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gbreve" xMin="74" yMin="-37" xMax="1081" yMax="1925">
+ <contour>
+ <pt x="1081" y="74" on="1"/>
+ <pt x="899" y="-37" on="0"/>
+ <pt x="698" y="-37" on="1"/>
+ <pt x="402" y="-37" on="0"/>
+ <pt x="238" y="169" on="1"/>
+ <pt x="74" y="374" on="0"/>
+ <pt x="74" y="747" on="1"/>
+ <pt x="74" y="1120" on="0"/>
+ <pt x="231" y="1319" on="1"/>
+ <pt x="389" y="1518" on="0"/>
+ <pt x="688" y="1518" on="1"/>
+ <pt x="861" y="1518" on="0"/>
+ <pt x="1057" y="1456" on="1"/>
+ <pt x="1057" y="1110" on="1"/>
+ <pt x="934" y="1110" on="1"/>
+ <pt x="905" y="1341" on="1"/>
+ <pt x="791" y="1395" on="0"/>
+ <pt x="692" y="1395" on="1"/>
+ <pt x="287" y="1395" on="0"/>
+ <pt x="287" y="737" on="1"/>
+ <pt x="287" y="430" on="0"/>
+ <pt x="402" y="264" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="721" y="99" on="1"/>
+ <pt x="799" y="99" on="0"/>
+ <pt x="883" y="131" on="1"/>
+ <pt x="883" y="537" on="1"/>
+ <pt x="711" y="537" on="1"/>
+ <pt x="711" y="660" on="1"/>
+ <pt x="1081" y="660" on="1"/>
+ </contour>
+ <contour>
+ <pt x="320" y="1925" on="1"/>
+ <pt x="443" y="1925" on="1"/>
+ <pt x="491" y="1777" on="0"/>
+ <pt x="665" y="1777" on="1"/>
+ <pt x="840" y="1777" on="0"/>
+ <pt x="888" y="1925" on="1"/>
+ <pt x="1011" y="1925" on="1"/>
+ <pt x="988" y="1836" on="0"/>
+ <pt x="962" y="1790" on="1"/>
+ <pt x="871" y="1635" on="0"/>
+ <pt x="670" y="1635" on="1"/>
+ <pt x="517" y="1635" on="0"/>
+ <pt x="428" y="1716" on="1"/>
+ <pt x="373" y="1765" on="0"/>
+ <pt x="345" y="1837" on="1"/>
+ <pt x="334" y="1866" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 33 14 40 23 20 2 17 5 10 48 200 10 0 2 2 1 15 14 13 12 4 0 28
+ 3 0 1 25 0 2 26 2 3 0 1 36 35 31 30 4 13 40 0 0 0 0 27 26 6
+ 1 28 1 4 48 200 29 28 1 0 14 0 0 19 39 6 48 200 36 35 15 14 4 12 25
+ 3 31 30 28 27 4 13 6 25 0 0 26 25 10 1 0 1 4 48 200 29 0 1 13 12
+ 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gcircumflex" xMin="74" yMin="-37" xMax="1081" yMax="1925">
+ <contour>
+ <pt x="1081" y="74" on="1"/>
+ <pt x="899" y="-37" on="0"/>
+ <pt x="698" y="-37" on="1"/>
+ <pt x="402" y="-37" on="0"/>
+ <pt x="238" y="169" on="1"/>
+ <pt x="74" y="374" on="0"/>
+ <pt x="74" y="747" on="1"/>
+ <pt x="74" y="1120" on="0"/>
+ <pt x="231" y="1319" on="1"/>
+ <pt x="389" y="1518" on="0"/>
+ <pt x="688" y="1518" on="1"/>
+ <pt x="861" y="1518" on="0"/>
+ <pt x="1057" y="1456" on="1"/>
+ <pt x="1057" y="1110" on="1"/>
+ <pt x="934" y="1110" on="1"/>
+ <pt x="905" y="1341" on="1"/>
+ <pt x="791" y="1395" on="0"/>
+ <pt x="692" y="1395" on="1"/>
+ <pt x="287" y="1395" on="0"/>
+ <pt x="287" y="737" on="1"/>
+ <pt x="287" y="430" on="0"/>
+ <pt x="402" y="264" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="721" y="99" on="1"/>
+ <pt x="799" y="99" on="0"/>
+ <pt x="883" y="131" on="1"/>
+ <pt x="883" y="537" on="1"/>
+ <pt x="711" y="537" on="1"/>
+ <pt x="711" y="660" on="1"/>
+ <pt x="1081" y="660" on="1"/>
+ </contour>
+ <contour>
+ <pt x="299" y="1604" on="1"/>
+ <pt x="555" y="1925" on="1"/>
+ <pt x="774" y="1925" on="1"/>
+ <pt x="1030" y="1604" on="1"/>
+ <pt x="907" y="1604" on="1"/>
+ <pt x="666" y="1806" on="1"/>
+ <pt x="663" y="1806" on="1"/>
+ <pt x="422" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 110 values pushed */
+ 0 0 23 20 2 17 5 10 48 200 10 0 2 2 1 37 36 35 34 33 30 6 31 0 3
+ 0 1 15 14 13 12 4 0 28 3 0 1 25 0 2 26 2 3 0 0 0 27 26 6 1
+ 28 1 4 48 200 32 31 1 29 28 1 2 0 14 0 0 19 39 6 48 200 34 33 15 14
+ 4 12 25 3 37 36 35 32 31 30 28 27 8 13 6 25 0 0 26 25 10 1 0 1 4
+ 48 200 29 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gcommaaccent" xMin="74" yMin="-432" xMax="1081" yMax="1518">
+ <contour>
+ <pt x="1081" y="74" on="1"/>
+ <pt x="899" y="-37" on="0"/>
+ <pt x="698" y="-37" on="1"/>
+ <pt x="402" y="-37" on="0"/>
+ <pt x="238" y="169" on="1"/>
+ <pt x="74" y="374" on="0"/>
+ <pt x="74" y="747" on="1"/>
+ <pt x="74" y="1120" on="0"/>
+ <pt x="231" y="1319" on="1"/>
+ <pt x="389" y="1518" on="0"/>
+ <pt x="688" y="1518" on="1"/>
+ <pt x="860" y="1518" on="0"/>
+ <pt x="1057" y="1456" on="1"/>
+ <pt x="1057" y="1110" on="1"/>
+ <pt x="934" y="1110" on="1"/>
+ <pt x="905" y="1341" on="1"/>
+ <pt x="791" y="1395" on="0"/>
+ <pt x="691" y="1395" on="1"/>
+ <pt x="287" y="1395" on="0"/>
+ <pt x="287" y="737" on="1"/>
+ <pt x="287" y="430" on="0"/>
+ <pt x="402" y="264" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="721" y="99" on="1"/>
+ <pt x="799" y="99" on="0"/>
+ <pt x="883" y="131" on="1"/>
+ <pt x="883" y="537" on="1"/>
+ <pt x="711" y="537" on="1"/>
+ <pt x="711" y="660" on="1"/>
+ <pt x="1081" y="660" on="1"/>
+ </contour>
+ <contour>
+ <pt x="528" y="-421" on="1"/>
+ <pt x="528" y="-336" on="1"/>
+ <pt x="585" y="-345" on="0"/>
+ <pt x="625" y="-345" on="1"/>
+ <pt x="734" y="-345" on="0"/>
+ <pt x="734" y="-278" on="1"/>
+ <pt x="734" y="-204" on="0"/>
+ <pt x="577" y="-188" on="1"/>
+ <pt x="577" y="-111" on="1"/>
+ <pt x="711" y="-114" on="0"/>
+ <pt x="777" y="-143" on="1"/>
+ <pt x="870" y="-185" on="0"/>
+ <pt x="870" y="-280" on="1"/>
+ <pt x="870" y="-432" on="0"/>
+ <pt x="652" y="-432" on="1"/>
+ <pt x="594" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 107 values pushed */
+ 0 0 33 32 44 23 20 2 17 5 10 48 200 10 0 2 2 1 15 14 13 12 4 0 28
+ 3 0 1 25 0 2 26 2 3 0 1 38 37 31 30 4 13 44 2 0 0 0 27 26 6
+ 1 28 1 4 48 200 29 28 1 0 14 0 0 35 20 42 19 39 6 48 200 15 14 2 12
+ 25 3 38 37 31 30 28 27 6 13 42 6 25 0 0 26 25 10 1 0 1 4 48 200 29
+ 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gdotaccent" xMin="74" yMin="-37" xMax="1081" yMax="1801">
+ <contour>
+ <pt x="1081" y="74" on="1"/>
+ <pt x="899" y="-37" on="0"/>
+ <pt x="698" y="-37" on="1"/>
+ <pt x="402" y="-37" on="0"/>
+ <pt x="238" y="169" on="1"/>
+ <pt x="74" y="374" on="0"/>
+ <pt x="74" y="747" on="1"/>
+ <pt x="74" y="1120" on="0"/>
+ <pt x="231" y="1319" on="1"/>
+ <pt x="389" y="1518" on="0"/>
+ <pt x="688" y="1518" on="1"/>
+ <pt x="861" y="1518" on="0"/>
+ <pt x="1057" y="1456" on="1"/>
+ <pt x="1057" y="1110" on="1"/>
+ <pt x="934" y="1110" on="1"/>
+ <pt x="905" y="1341" on="1"/>
+ <pt x="791" y="1395" on="0"/>
+ <pt x="692" y="1395" on="1"/>
+ <pt x="287" y="1395" on="0"/>
+ <pt x="287" y="737" on="1"/>
+ <pt x="287" y="430" on="0"/>
+ <pt x="402" y="264" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="721" y="99" on="1"/>
+ <pt x="799" y="99" on="0"/>
+ <pt x="883" y="131" on="1"/>
+ <pt x="883" y="537" on="1"/>
+ <pt x="711" y="537" on="1"/>
+ <pt x="711" y="660" on="1"/>
+ <pt x="1081" y="660" on="1"/>
+ </contour>
+ <contour>
+ <pt x="566" y="1604" on="1"/>
+ <pt x="566" y="1801" on="1"/>
+ <pt x="763" y="1801" on="1"/>
+ <pt x="763" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 105 values pushed */
+ 0 0 23 20 2 17 5 10 48 200 10 0 2 2 1 15 14 13 12 4 0 28 3 0 1
+ 25 0 2 26 2 3 0 0 0 33 30 10 1 31 27 26 6 1 28 2 4 48 200 32 31
+ 1 29 28 1 2 0 14 0 0 19 39 6 48 200 15 14 2 12 25 3 28 27 2 32 30
+ 3 6 30 0 0 33 32 10 1 30 26 25 10 1 0 2 4 48 200 31 30 1 29 0 1
+ 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="H" xMin="62" yMin="0" xMax="1168" yMax="1480">
+ <contour>
+ <pt x="370" y="703" on="1"/>
+ <pt x="370" y="123" on="1"/>
+ <pt x="469" y="123" on="1"/>
+ <pt x="469" y="0" on="1"/>
+ <pt x="62" y="0" on="1"/>
+ <pt x="62" y="123" on="1"/>
+ <pt x="173" y="123" on="1"/>
+ <pt x="173" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="469" y="1480" on="1"/>
+ <pt x="469" y="1357" on="1"/>
+ <pt x="370" y="1357" on="1"/>
+ <pt x="370" y="827" on="1"/>
+ <pt x="859" y="827" on="1"/>
+ <pt x="859" y="1357" on="1"/>
+ <pt x="760" y="1357" on="1"/>
+ <pt x="760" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1057" y="1357" on="1"/>
+ <pt x="1057" y="123" on="1"/>
+ <pt x="1168" y="123" on="1"/>
+ <pt x="1168" y="0" on="1"/>
+ <pt x="760" y="0" on="1"/>
+ <pt x="760" y="123" on="1"/>
+ <pt x="859" y="123" on="1"/>
+ <pt x="859" y="703" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 106 values pushed */
+ 20 19 16 15 12 11 8 7 8 9 13 3 26 25 22 21 6 5 2 1 8 0 3 3 0
+ 0 27 0 6 1 13 1 4 48 200 14 13 1 24 23 4 3 3 2 0 18 17 10 9 0
+ 3 14 25 24 17 16 11 10 3 2 8 14 0 3 23 22 19 18 4 13 20 9 8 5 4
+ 4 13 6 0 0 27 26 15 14 10 3 20 13 12 1 0 10 3 6 2 4 48 200 21 20
+ 1 7 6 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Hbar" xMin="37" yMin="0" xMax="1192" yMax="1480">
+ <contour>
+ <pt x="370" y="827" on="1"/>
+ <pt x="859" y="827" on="1"/>
+ <pt x="859" y="1086" on="1"/>
+ <pt x="370" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="62" y="0" on="1"/>
+ <pt x="62" y="123" on="1"/>
+ <pt x="173" y="123" on="1"/>
+ <pt x="173" y="1086" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="37" y="1184" on="1"/>
+ <pt x="173" y="1184" on="1"/>
+ <pt x="173" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="469" y="1480" on="1"/>
+ <pt x="469" y="1357" on="1"/>
+ <pt x="370" y="1357" on="1"/>
+ <pt x="370" y="1185" on="1"/>
+ <pt x="859" y="1185" on="1"/>
+ <pt x="859" y="1357" on="1"/>
+ <pt x="760" y="1357" on="1"/>
+ <pt x="760" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1057" y="1357" on="1"/>
+ <pt x="1057" y="1184" on="1"/>
+ <pt x="1192" y="1184" on="1"/>
+ <pt x="1192" y="1086" on="1"/>
+ <pt x="1057" y="1086" on="1"/>
+ <pt x="1057" y="123" on="1"/>
+ <pt x="1168" y="123" on="1"/>
+ <pt x="1168" y="0" on="1"/>
+ <pt x="760" y="0" on="1"/>
+ <pt x="760" y="123" on="1"/>
+ <pt x="859" y="123" on="1"/>
+ <pt x="859" y="703" on="1"/>
+ <pt x="370" y="703" on="1"/>
+ <pt x="370" y="123" on="1"/>
+ <pt x="469" y="123" on="1"/>
+ <pt x="469" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 143 values pushed */
+ 24 23 20 19 16 15 12 11 8 13 17 3 26 25 10 9 4 17 2 3 38 37 34 33 30
+ 29 6 5 8 35 4 3 18 17 1 36 35 1 39 32 31 4 3 1 0 1 4 0 22 21
+ 14 13 0 3 28 27 8 7 3 2 1 5 14 39 38 33 32 21 20 15 14 8 1 0 3
+ 31 30 27 26 23 22 6 13 24 13 12 9 8 5 4 6 13 6 0 0 35 34 19 18 2
+ 1 10 5 24 37 36 17 16 3 0 10 5 6 2 4 48 200 29 28 25 24 3 11 10 7
+ 6 3 35 34 19 18 2 1 5 37 36 17 16 3 0 5 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Hcircumflex" xMin="62" yMin="0" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="370" y="703" on="1"/>
+ <pt x="370" y="123" on="1"/>
+ <pt x="469" y="123" on="1"/>
+ <pt x="469" y="0" on="1"/>
+ <pt x="62" y="0" on="1"/>
+ <pt x="62" y="123" on="1"/>
+ <pt x="173" y="123" on="1"/>
+ <pt x="173" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="469" y="1480" on="1"/>
+ <pt x="469" y="1357" on="1"/>
+ <pt x="370" y="1357" on="1"/>
+ <pt x="370" y="827" on="1"/>
+ <pt x="859" y="827" on="1"/>
+ <pt x="859" y="1357" on="1"/>
+ <pt x="760" y="1357" on="1"/>
+ <pt x="760" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1057" y="1357" on="1"/>
+ <pt x="1057" y="123" on="1"/>
+ <pt x="1168" y="123" on="1"/>
+ <pt x="1168" y="0" on="1"/>
+ <pt x="760" y="0" on="1"/>
+ <pt x="760" y="123" on="1"/>
+ <pt x="859" y="123" on="1"/>
+ <pt x="859" y="703" on="1"/>
+ </contour>
+ <contour>
+ <pt x="249" y="1604" on="1"/>
+ <pt x="505" y="1925" on="1"/>
+ <pt x="724" y="1925" on="1"/>
+ <pt x="980" y="1604" on="1"/>
+ <pt x="857" y="1604" on="1"/>
+ <pt x="616" y="1806" on="1"/>
+ <pt x="613" y="1806" on="1"/>
+ <pt x="372" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 133 values pushed */
+ 35 34 33 32 31 28 6 29 9 3 20 19 16 15 12 11 8 7 8 9 13 3 26 25 22
+ 21 6 5 2 1 8 0 3 3 0 0 27 0 6 1 13 1 4 48 200 30 29 1 14 13
+ 1 24 23 4 3 3 3 0 18 17 10 9 0 3 14 31 20 14 2 35 34 33 32 30 29
+ 25 24 17 16 11 10 3 2 14 14 0 3 28 0 6 2 23 22 19 18 4 13 20 9 8
+ 5 4 4 13 6 0 0 27 26 15 14 10 3 20 13 12 1 0 10 3 6 2 4 48 200
+ 21 20 1 7 6 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="I" xMin="160" yMin="0" xMax="1068" yMax="1480">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 0 0 8 7 4 3 6 3 5 10 9 2 1 6 3 0 2 4 48 200 11 0 1 0 6
+ 5 0 14 11 10 7 6 4 13 8 5 4 1 0 4 13 2 0 0 9 8 10 1 2 1
+ 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="IJ" xMin="45" yMin="-37" xMax="1131" yMax="1480">
+ <contour>
+ <pt x="45" y="0" on="1"/>
+ <pt x="45" y="123" on="1"/>
+ <pt x="144" y="123" on="1"/>
+ <pt x="144" y="1357" on="1"/>
+ <pt x="45" y="1357" on="1"/>
+ <pt x="45" y="1480" on="1"/>
+ <pt x="440" y="1480" on="1"/>
+ <pt x="440" y="1357" on="1"/>
+ <pt x="341" y="1357" on="1"/>
+ <pt x="341" y="123" on="1"/>
+ <pt x="440" y="123" on="1"/>
+ <pt x="440" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="563" y="-19" on="1"/>
+ <pt x="563" y="197" on="1"/>
+ <pt x="687" y="197" on="1"/>
+ <pt x="699" y="108" on="1"/>
+ <pt x="729" y="86" on="0"/>
+ <pt x="762" y="86" on="1"/>
+ <pt x="933" y="86" on="0"/>
+ <pt x="933" y="410" on="1"/>
+ <pt x="933" y="1357" on="1"/>
+ <pt x="736" y="1357" on="1"/>
+ <pt x="736" y="1480" on="1"/>
+ <pt x="1131" y="1480" on="1"/>
+ <pt x="1131" y="533" on="1"/>
+ <pt x="1131" y="226" on="0"/>
+ <pt x="1034" y="105" on="1"/>
+ <pt x="920" y="-37" on="0"/>
+ <pt x="711" y="-37" on="1"/>
+ <pt x="652" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 100 values pushed */
+ 0 0 17 5 28 48 200 28 2 24 19 15 14 13 10 9 2 1 9 3 0 3 12 0 0
+ 0 21 20 8 7 4 3 6 5 5 1 4 48 200 11 0 1 0 23 22 6 5 0 3 14
+ 22 21 15 14 4 19 12 3 11 10 7 6 4 12 8 3 5 4 1 0 4 13 2 0 0
+ 20 19 10 1 23 9 8 10 1 2 2 4 48 200 24 23 1 13 12 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Iacute" xMin="160" yMin="0" xMax="1068" yMax="1925">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="515" y="1604" on="1"/>
+ <pt x="731" y="1925" on="1"/>
+ <pt x="959" y="1925" on="1"/>
+ <pt x="638" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 15 12 2 13 5 3 0 0 8 7 4 3 6 3 5 10 9 2 1 6 3 0 2 4 48
+ 200 14 13 1 11 0 1 2 0 6 5 0 14 15 8 2 2 14 13 11 10 7 6 6 13
+ 8 5 4 1 0 4 13 2 0 0 9 8 10 1 2 1 4 48 200 12 3 2 2 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ibreve" xMin="160" yMin="0" xMax="1068" yMax="1925">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="269" y="1925" on="1"/>
+ <pt x="392" y="1925" on="1"/>
+ <pt x="440" y="1777" on="0"/>
+ <pt x="614" y="1777" on="1"/>
+ <pt x="789" y="1777" on="0"/>
+ <pt x="837" y="1925" on="1"/>
+ <pt x="960" y="1925" on="1"/>
+ <pt x="937" y="1836" on="0"/>
+ <pt x="911" y="1790" on="1"/>
+ <pt x="820" y="1635" on="0"/>
+ <pt x="618" y="1635" on="1"/>
+ <pt x="466" y="1635" on="0"/>
+ <pt x="377" y="1716" on="1"/>
+ <pt x="322" y="1765" on="0"/>
+ <pt x="294" y="1837" on="1"/>
+ <pt x="283" y="1866" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 0 0 15 14 22 48 200 18 17 13 12 4 13 22 5 0 0 8 7 4 3 6 3 5 10
+ 9 2 1 6 3 0 2 4 48 200 11 0 1 0 6 5 0 14 18 17 11 10 7 6 6
+ 13 8 13 12 5 4 1 0 6 13 2 0 0 9 8 10 1 2 1 4 48 200 3 2 1
+ 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Icircumflex" xMin="160" yMin="0" xMax="1068" yMax="1925">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="248" y="1604" on="1"/>
+ <pt x="504" y="1925" on="1"/>
+ <pt x="723" y="1925" on="1"/>
+ <pt x="979" y="1604" on="1"/>
+ <pt x="856" y="1604" on="1"/>
+ <pt x="615" y="1806" on="1"/>
+ <pt x="612" y="1806" on="1"/>
+ <pt x="371" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 19 18 17 16 15 12 6 13 5 3 0 0 8 7 4 3 6 3 5 10 9 2 1 6 3
+ 0 2 4 48 200 14 13 1 11 0 1 2 0 6 5 0 14 18 17 2 8 2 3 16 15
+ 14 11 10 7 6 7 13 8 19 13 12 5 4 1 0 7 13 2 0 0 9 8 10 1 2
+ 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Idieresis" xMin="160" yMin="0" xMax="1068" yMax="1801">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="281" y="1604" on="1"/>
+ <pt x="281" y="1801" on="1"/>
+ <pt x="478" y="1801" on="1"/>
+ <pt x="478" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="750" y="1604" on="1"/>
+ <pt x="750" y="1801" on="1"/>
+ <pt x="947" y="1801" on="1"/>
+ <pt x="947" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 19 16 15 12 10 3 13 8 7 4 3 6 3 5 10 9 2 1 6 3 0 3 4
+ 48 200 18 17 14 13 3 11 0 1 2 0 6 5 0 14 11 10 7 6 4 13 18 5 4
+ 1 0 4 13 12 0 0 17 16 10 1 18 15 14 10 1 12 9 8 10 1 2 3 4 48
+ 200 19 18 1 13 12 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Idotaccent" xMin="160" yMin="0" xMax="1068" yMax="1801">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="515" y="1604" on="1"/>
+ <pt x="515" y="1801" on="1"/>
+ <pt x="712" y="1801" on="1"/>
+ <pt x="712" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 0 0 15 12 10 1 13 8 7 4 3 6 3 5 10 9 2 1 6 3 0 3 4 48 200
+ 14 13 1 11 0 1 2 0 6 5 0 14 11 10 7 6 4 13 8 5 4 1 0 4 13
+ 2 0 0 15 14 10 1 2 9 8 10 1 2 2 4 48 200 13 12 3 2 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Igrave" xMin="160" yMin="0" xMax="1068" yMax="1925">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="712" y="1604" on="1"/>
+ <pt x="589" y="1604" on="1"/>
+ <pt x="268" y="1925" on="1"/>
+ <pt x="496" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 13 12 2 14 5 3 0 0 8 7 4 3 6 3 5 10 9 2 1 6 3 0 2 4 48
+ 200 15 14 1 11 0 1 2 0 6 5 0 14 13 12 2 8 2 3 11 10 7 6 4 13
+ 8 15 14 5 4 1 0 6 13 2 0 0 9 8 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Imacron" xMin="160" yMin="0" xMax="1068" yMax="1728">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="269" y="1604" on="1"/>
+ <pt x="269" y="1728" on="1"/>
+ <pt x="960" y="1728" on="1"/>
+ <pt x="960" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 15 12 6 1 13 8 7 4 3 6 3 5 10 9 2 1 6 3 0 3 4 48 200
+ 14 13 1 11 0 1 2 0 6 5 0 14 15 14 11 10 7 6 6 13 8 13 12 5 4
+ 1 0 6 13 2 0 0 9 8 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Iogonek" xMin="160" yMin="-370" xMax="1068" yMax="1480">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="785" y="0" on="1"/>
+ <pt x="892" y="0" on="1"/>
+ <pt x="763" y="-81" on="0"/>
+ <pt x="763" y="-179" on="1"/>
+ <pt x="763" y="-275" on="0"/>
+ <pt x="878" y="-275" on="1"/>
+ <pt x="932" y="-275" on="0"/>
+ <pt x="969" y="-260" on="1"/>
+ <pt x="969" y="-341" on="1"/>
+ <pt x="907" y="-370" on="0"/>
+ <pt x="830" y="-370" on="1"/>
+ <pt x="627" y="-370" on="0"/>
+ <pt x="627" y="-213" on="1"/>
+ <pt x="627" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 17 17 22 48 200 20 19 22 0 0 0 8 7 4 3 6 3 5 10 9 2 1 6
+ 3 0 2 4 48 200 13 12 11 0 3 0 6 5 0 14 0 0 15 20 24 48 200 24 24
+ 8 2 2 20 19 13 12 11 10 7 6 8 13 8 5 4 1 0 4 13 2 0 0 9 8
+ 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Itilde" xMin="160" yMin="0" xMax="1068" yMax="1839">
+ <contour>
+ <pt x="160" y="0" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="515" y="123" on="1"/>
+ <pt x="515" y="1357" on="1"/>
+ <pt x="160" y="1357" on="1"/>
+ <pt x="160" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="713" y="1357" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1068" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="281" y="1604" on="1"/>
+ <pt x="287" y="1699" on="0"/>
+ <pt x="312" y="1749" on="1"/>
+ <pt x="357" y="1839" on="0"/>
+ <pt x="466" y="1839" on="1"/>
+ <pt x="538" y="1839" on="0"/>
+ <pt x="601" y="1800" on="1"/>
+ <pt x="661" y="1763" on="1"/>
+ <pt x="723" y="1725" on="0"/>
+ <pt x="757" y="1725" on="1"/>
+ <pt x="825" y="1725" on="0"/>
+ <pt x="836" y="1839" on="1"/>
+ <pt x="947" y="1839" on="1"/>
+ <pt x="940" y="1745" on="0"/>
+ <pt x="915" y="1695" on="1"/>
+ <pt x="869" y="1604" on="0"/>
+ <pt x="762" y="1604" on="1"/>
+ <pt x="689" y="1604" on="0"/>
+ <pt x="626" y="1643" on="1"/>
+ <pt x="566" y="1680" on="1"/>
+ <pt x="506" y="1717" on="0"/>
+ <pt x="470" y="1717" on="1"/>
+ <pt x="402" y="1717" on="0"/>
+ <pt x="391" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 33 5 16 21 5 28 48 200 35 24 23 12 4 13 28 16 5 0 0 8 7 4 3
+ 6 3 5 10 9 2 1 6 3 0 2 4 48 200 11 0 1 0 6 5 0 14 24 23 11
+ 10 7 6 6 13 8 35 12 5 4 1 0 6 13 2 0 0 9 8 10 1 2 1 4 48
+ 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="J" xMin="111" yMin="-37" xMax="1143" yMax="1480">
+ <contour>
+ <pt x="111" y="31" on="1"/>
+ <pt x="111" y="444" on="1"/>
+ <pt x="234" y="444" on="1"/>
+ <pt x="273" y="135" on="1"/>
+ <pt x="386" y="86" on="0"/>
+ <pt x="467" y="86" on="1"/>
+ <pt x="583" y="86" on="0"/>
+ <pt x="634" y="141" on="1"/>
+ <pt x="686" y="195" on="0"/>
+ <pt x="686" y="322" on="1"/>
+ <pt x="686" y="1357" on="1"/>
+ <pt x="291" y="1357" on="1"/>
+ <pt x="291" y="1480" on="1"/>
+ <pt x="1143" y="1480" on="1"/>
+ <pt x="1143" y="1357" on="1"/>
+ <pt x="883" y="1357" on="1"/>
+ <pt x="883" y="362" on="1"/>
+ <pt x="883" y="148" on="0"/>
+ <pt x="791" y="56" on="1"/>
+ <pt x="699" y="-37" on="0"/>
+ <pt x="487" y="-37" on="1"/>
+ <pt x="329" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 5 5 20 48 200 20 2 1 16 9 3 2 1 0 6 10 2 3 0 0 0 15 14
+ 11 10 6 3 12 1 4 48 200 13 12 0 14 12 11 3 2 4 9 0 3 14 13 2 13
+ 15 0 0 10 9 10 1 15 1 4 48 200 16 15 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Jcircumflex" xMin="111" yMin="-37" xMax="1143" yMax="1925">
+ <contour>
+ <pt x="111" y="31" on="1"/>
+ <pt x="111" y="444" on="1"/>
+ <pt x="234" y="444" on="1"/>
+ <pt x="273" y="135" on="1"/>
+ <pt x="386" y="86" on="0"/>
+ <pt x="467" y="86" on="1"/>
+ <pt x="583" y="86" on="0"/>
+ <pt x="634" y="141" on="1"/>
+ <pt x="686" y="195" on="0"/>
+ <pt x="686" y="322" on="1"/>
+ <pt x="686" y="1357" on="1"/>
+ <pt x="291" y="1357" on="1"/>
+ <pt x="291" y="1480" on="1"/>
+ <pt x="1143" y="1480" on="1"/>
+ <pt x="1143" y="1357" on="1"/>
+ <pt x="883" y="1357" on="1"/>
+ <pt x="883" y="362" on="1"/>
+ <pt x="883" y="148" on="0"/>
+ <pt x="791" y="56" on="1"/>
+ <pt x="699" y="-37" on="0"/>
+ <pt x="487" y="-37" on="1"/>
+ <pt x="329" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="351" y="1604" on="1"/>
+ <pt x="607" y="1925" on="1"/>
+ <pt x="826" y="1925" on="1"/>
+ <pt x="1082" y="1604" on="1"/>
+ <pt x="959" y="1604" on="1"/>
+ <pt x="718" y="1806" on="1"/>
+ <pt x="715" y="1806" on="1"/>
+ <pt x="474" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 96 values pushed */
+ 0 0 5 5 20 48 200 20 2 29 28 27 26 25 22 6 23 12 3 1 16 9 3 2 1
+ 0 6 10 2 3 0 0 0 15 14 11 10 6 3 12 1 4 48 200 24 23 1 0 13 12
+ 0 14 28 27 24 3 15 9 3 29 23 22 12 11 3 2 7 9 0 3 26 25 14 13 4
+ 13 15 0 0 10 9 10 1 15 1 4 48 200 16 15 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="K" xMin="74" yMin="0" xMax="1197" yMax="1480">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="204" y="123" on="1"/>
+ <pt x="204" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="506" y="1480" on="1"/>
+ <pt x="506" y="1357" on="1"/>
+ <pt x="401" y="1357" on="1"/>
+ <pt x="401" y="756" on="1"/>
+ <pt x="408" y="756" on="1"/>
+ <pt x="838" y="1357" on="1"/>
+ <pt x="727" y="1357" on="1"/>
+ <pt x="727" y="1480" on="1"/>
+ <pt x="1083" y="1480" on="1"/>
+ <pt x="1083" y="1357" on="1"/>
+ <pt x="991" y="1357" on="1"/>
+ <pt x="594" y="811" on="1"/>
+ <pt x="1123" y="123" on="1"/>
+ <pt x="1197" y="123" on="1"/>
+ <pt x="1197" y="0" on="1"/>
+ <pt x="772" y="0" on="1"/>
+ <pt x="772" y="123" on="1"/>
+ <pt x="883" y="123" on="1"/>
+ <pt x="408" y="740" on="1"/>
+ <pt x="401" y="740" on="1"/>
+ <pt x="401" y="123" on="1"/>
+ <pt x="524" y="123" on="1"/>
+ <pt x="524" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 27 26 25 24 23 22 19 18 17 16 15 12 11 10 9 8 7 4 3 2 1 21 5 0 3
+ 28 21 20 0 3 0 14 13 6 5 0 3 14 28 27 24 23 22 21 20 19 18 17 16 15
+ 14 13 12 11 10 7 6 19 13 8 5 4 1 0 4 13 2 0 0 26 25 9 8 10 3
+ 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Kcommaaccent" xMin="74" yMin="-432" xMax="1197" yMax="1480">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="204" y="123" on="1"/>
+ <pt x="204" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="506" y="1480" on="1"/>
+ <pt x="506" y="1357" on="1"/>
+ <pt x="401" y="1357" on="1"/>
+ <pt x="401" y="756" on="1"/>
+ <pt x="408" y="756" on="1"/>
+ <pt x="838" y="1357" on="1"/>
+ <pt x="727" y="1357" on="1"/>
+ <pt x="727" y="1480" on="1"/>
+ <pt x="1083" y="1480" on="1"/>
+ <pt x="1083" y="1357" on="1"/>
+ <pt x="991" y="1357" on="1"/>
+ <pt x="594" y="811" on="1"/>
+ <pt x="1123" y="123" on="1"/>
+ <pt x="1197" y="123" on="1"/>
+ <pt x="1197" y="0" on="1"/>
+ <pt x="772" y="0" on="1"/>
+ <pt x="772" y="123" on="1"/>
+ <pt x="883" y="123" on="1"/>
+ <pt x="408" y="740" on="1"/>
+ <pt x="401" y="740" on="1"/>
+ <pt x="401" y="123" on="1"/>
+ <pt x="524" y="123" on="1"/>
+ <pt x="524" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="512" y="-421" on="1"/>
+ <pt x="512" y="-336" on="1"/>
+ <pt x="569" y="-345" on="0"/>
+ <pt x="609" y="-345" on="1"/>
+ <pt x="718" y="-345" on="0"/>
+ <pt x="718" y="-278" on="1"/>
+ <pt x="718" y="-205" on="0"/>
+ <pt x="561" y="-188" on="1"/>
+ <pt x="561" y="-111" on="1"/>
+ <pt x="695" y="-114" on="0"/>
+ <pt x="761" y="-143" on="1"/>
+ <pt x="854" y="-185" on="0"/>
+ <pt x="854" y="-280" on="1"/>
+ <pt x="854" y="-432" on="0"/>
+ <pt x="636" y="-432" on="1"/>
+ <pt x="578" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 111 values pushed */
+ 0 0 32 32 43 48 200 27 26 25 24 23 22 19 18 17 16 15 12 11 10 9 8 7 4
+ 3 2 1 21 5 0 3 37 36 30 29 4 13 43 0 28 21 20 0 3 0 14 13 6 5
+ 0 3 14 0 0 34 20 41 48 200 37 36 30 29 28 27 24 23 22 21 20 19 18 17 16
+ 15 14 13 12 11 10 7 6 23 13 41 8 5 4 1 0 4 13 2 0 0 26 25 9 8
+ 10 3 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="L" xMin="86" yMin="0" xMax="1151" yMax="1480">
+ <contour>
+ <pt x="1151" y="0" on="1"/>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="765" y="1480" on="1"/>
+ <pt x="765" y="1357" on="1"/>
+ <pt x="530" y="1357" on="1"/>
+ <pt x="530" y="136" on="1"/>
+ <pt x="1028" y="136" on="1"/>
+ <pt x="1028" y="481" on="1"/>
+ <pt x="1151" y="481" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 13 12 2 4 10 3 0 0 9 8 5 4 6 3 6 11 10 20 1 0 3 2 6 1 0
+ 3 4 48 200 1 0 1 0 7 6 0 14 8 7 2 11 9 3 6 5 2 1 4 13 3
+ 0 0 12 11 6 1 0 10 9 10 1 3 2 4 48 200 13 0 1 4 3 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lacute" xMin="86" yMin="0" xMax="1151" yMax="1925">
+ <contour>
+ <pt x="1151" y="0" on="1"/>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="765" y="1480" on="1"/>
+ <pt x="765" y="1357" on="1"/>
+ <pt x="530" y="1357" on="1"/>
+ <pt x="530" y="136" on="1"/>
+ <pt x="1028" y="136" on="1"/>
+ <pt x="1028" y="481" on="1"/>
+ <pt x="1151" y="481" on="1"/>
+ </contour>
+ <contour>
+ <pt x="407" y="1604" on="1"/>
+ <pt x="623" y="1925" on="1"/>
+ <pt x="851" y="1925" on="1"/>
+ <pt x="530" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 17 14 2 15 6 3 13 12 2 4 10 3 0 0 9 8 5 4 6 3 6 11 10 20 1
+ 0 3 2 6 1 0 3 4 48 200 16 15 1 1 0 1 2 0 7 6 0 14 16 15 8
+ 7 4 11 9 3 14 9 3 2 6 5 2 1 4 13 3 0 0 12 11 6 1 0 17 10
+ 9 10 2 3 2 4 48 200 13 0 1 4 3 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lcaron" xMin="86" yMin="0" xMax="1151" yMax="1480">
+ <contour>
+ <pt x="1151" y="0" on="1"/>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="765" y="1480" on="1"/>
+ <pt x="765" y="1357" on="1"/>
+ <pt x="530" y="1357" on="1"/>
+ <pt x="530" y="136" on="1"/>
+ <pt x="1028" y="136" on="1"/>
+ <pt x="1028" y="481" on="1"/>
+ <pt x="1151" y="481" on="1"/>
+ </contour>
+ <contour>
+ <pt x="937" y="1026" on="1"/>
+ <pt x="937" y="1085" on="1"/>
+ <pt x="1013" y="1106" on="0"/>
+ <pt x="1013" y="1266" on="1"/>
+ <pt x="1013" y="1283" on="1"/>
+ <pt x="937" y="1283" on="1"/>
+ <pt x="937" y="1480" on="1"/>
+ <pt x="1134" y="1480" on="1"/>
+ <pt x="1134" y="1309" on="1"/>
+ <pt x="1133" y="1047" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 99 values pushed */
+ 22 19 18 17 15 14 13 12 8 4 10 3 0 0 9 8 5 4 6 3 6 11 10 20 1
+ 0 3 2 6 1 0 3 4 48 200 1 0 1 0 21 20 7 6 0 3 14 18 17 2 11
+ 14 3 8 7 2 14 9 3 6 5 2 1 4 13 3 0 0 20 19 15 14 10 3 21 12
+ 11 6 1 0 10 9 10 1 3 3 4 48 200 22 21 1 13 0 1 4 3 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lcommaaccent" xMin="86" yMin="-432" xMax="1151" yMax="1480">
+ <contour>
+ <pt x="1151" y="0" on="1"/>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="765" y="1480" on="1"/>
+ <pt x="765" y="1357" on="1"/>
+ <pt x="530" y="1357" on="1"/>
+ <pt x="530" y="136" on="1"/>
+ <pt x="1028" y="136" on="1"/>
+ <pt x="1028" y="481" on="1"/>
+ <pt x="1151" y="481" on="1"/>
+ </contour>
+ <contour>
+ <pt x="518" y="-421" on="1"/>
+ <pt x="518" y="-336" on="1"/>
+ <pt x="575" y="-345" on="0"/>
+ <pt x="615" y="-345" on="1"/>
+ <pt x="724" y="-345" on="0"/>
+ <pt x="724" y="-278" on="1"/>
+ <pt x="724" y="-205" on="0"/>
+ <pt x="567" y="-188" on="1"/>
+ <pt x="567" y="-111" on="1"/>
+ <pt x="701" y="-114" on="0"/>
+ <pt x="767" y="-143" on="1"/>
+ <pt x="860" y="-185" on="0"/>
+ <pt x="860" y="-280" on="1"/>
+ <pt x="860" y="-432" on="0"/>
+ <pt x="642" y="-432" on="1"/>
+ <pt x="584" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 106 values pushed */
+ 0 0 17 32 28 48 200 13 12 2 4 10 3 22 21 15 14 4 13 28 0 0 0 9 8
+ 5 4 6 3 6 11 10 20 1 0 3 2 6 1 0 3 4 48 200 1 0 1 0 7 6
+ 0 14 0 0 19 20 26 48 200 26 26 22 21 8 7 5 11 9 3 15 14 2 9 3 3
+ 6 5 2 1 4 13 3 0 0 12 11 6 1 0 10 9 10 1 3 2 4 48 200 13 0
+ 1 4 3 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ldot" xMin="86" yMin="0" xMax="1151" yMax="1480">
+ <contour>
+ <pt x="1151" y="0" on="1"/>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="765" y="1480" on="1"/>
+ <pt x="765" y="1357" on="1"/>
+ <pt x="530" y="1357" on="1"/>
+ <pt x="530" y="136" on="1"/>
+ <pt x="1028" y="136" on="1"/>
+ <pt x="1028" y="481" on="1"/>
+ <pt x="1151" y="481" on="1"/>
+ </contour>
+ <contour>
+ <pt x="954" y="740" on="1"/>
+ <pt x="954" y="937" on="1"/>
+ <pt x="1151" y="937" on="1"/>
+ <pt x="1151" y="740" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 13 12 2 14 10 3 0 0 17 14 10 1 15 9 8 5 4 6 3 6 11 10 20 1 0
+ 3 2 6 1 0 4 4 48 200 16 15 1 1 0 1 2 0 7 6 0 14 8 7 2 14
+ 9 3 6 5 2 1 4 13 3 0 0 15 14 10 1 0 12 11 6 1 0 10 9 10 1
+ 3 3 4 48 200 17 16 13 0 3 4 3 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lslash" xMin="86" yMin="0" xMax="1151" yMax="1480">
+ <contour>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="652" on="1"/>
+ <pt x="86" y="528" on="1"/>
+ <pt x="86" y="666" on="1"/>
+ <pt x="333" y="790" on="1"/>
+ <pt x="333" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="765" y="1480" on="1"/>
+ <pt x="765" y="1357" on="1"/>
+ <pt x="530" y="1357" on="1"/>
+ <pt x="530" y="888" on="1"/>
+ <pt x="826" y="1036" on="1"/>
+ <pt x="826" y="899" on="1"/>
+ <pt x="530" y="750" on="1"/>
+ <pt x="530" y="136" on="1"/>
+ <pt x="1028" y="136" on="1"/>
+ <pt x="1028" y="481" on="1"/>
+ <pt x="1151" y="481" on="1"/>
+ <pt x="1151" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 20 19 16 15 14 13 6 5 4 3 10 7 17 3 0 0 12 11 8 7 6 3 9 18 17
+ 20 1 0 2 1 6 1 0 3 4 48 200 21 0 1 0 10 9 0 14 11 10 2 14 12
+ 3 0 0 19 18 6 1 20 17 16 13 12 10 3 2 2 4 48 200 21 20 1 15 14 1
+ 7 6 3 2 3 9 8 5 4 1 0 5 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="M" xMin="25" yMin="0" xMax="1204" yMax="1480">
+ <contour>
+ <pt x="25" y="0" on="1"/>
+ <pt x="25" y="123" on="1"/>
+ <pt x="111" y="123" on="1"/>
+ <pt x="111" y="1357" on="1"/>
+ <pt x="25" y="1357" on="1"/>
+ <pt x="25" y="1480" on="1"/>
+ <pt x="310" y="1480" on="1"/>
+ <pt x="616" y="462" on="1"/>
+ <pt x="618" y="462" on="1"/>
+ <pt x="935" y="1480" on="1"/>
+ <pt x="1204" y="1480" on="1"/>
+ <pt x="1204" y="1357" on="1"/>
+ <pt x="1118" y="1357" on="1"/>
+ <pt x="1118" y="123" on="1"/>
+ <pt x="1204" y="123" on="1"/>
+ <pt x="1204" y="0" on="1"/>
+ <pt x="884" y="0" on="1"/>
+ <pt x="884" y="123" on="1"/>
+ <pt x="956" y="123" on="1"/>
+ <pt x="956" y="1128" on="1"/>
+ <pt x="954" y="1128" on="1"/>
+ <pt x="663" y="194" on="1"/>
+ <pt x="528" y="194" on="1"/>
+ <pt x="237" y="1166" on="1"/>
+ <pt x="235" y="1166" on="1"/>
+ <pt x="235" y="123" on="1"/>
+ <pt x="321" y="123" on="1"/>
+ <pt x="321" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 26 25 24 23 22 21 20 19 18 17 14 13 12 11 8 7 4 3 2 1 20 5 0 3 27
+ 16 15 0 3 0 10 9 6 5 0 3 14 27 26 23 22 21 20 17 16 9 8 7 6 12
+ 18 24 3 15 14 11 10 4 13 12 5 4 1 0 4 13 2 0 0 19 18 34 1 12 25
+ 24 6 1 2 2 4 48 200 13 12 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="N" xMin="74" yMin="0" xMax="1155" yMax="1480">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="185" y="123" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="308" y="1480" on="1"/>
+ <pt x="918" y="405" on="1"/>
+ <pt x="920" y="405" on="1"/>
+ <pt x="920" y="1357" on="1"/>
+ <pt x="810" y="1357" on="1"/>
+ <pt x="810" y="1480" on="1"/>
+ <pt x="1155" y="1480" on="1"/>
+ <pt x="1155" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="0" on="1"/>
+ <pt x="920" y="0" on="1"/>
+ <pt x="311" y="1076" on="1"/>
+ <pt x="308" y="1076" on="1"/>
+ <pt x="308" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 20 19 18 17 14 13 10 9 8 7 4 3 2 1 14 5 0 3 21 16 15 0 3 0 12
+ 11 6 5 0 3 14 21 20 17 11 10 7 6 8 6 3 13 12 2 13 14 5 4 1 0
+ 4 13 2 0 0 16 9 8 6 2 14 19 18 6 6 2 2 2 4 48 200 15 14 1 3
+ 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Nacute" xMin="74" yMin="0" xMax="1155" yMax="1925">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="185" y="123" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="308" y="1480" on="1"/>
+ <pt x="918" y="405" on="1"/>
+ <pt x="920" y="405" on="1"/>
+ <pt x="920" y="1357" on="1"/>
+ <pt x="810" y="1357" on="1"/>
+ <pt x="810" y="1480" on="1"/>
+ <pt x="1155" y="1480" on="1"/>
+ <pt x="1155" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="0" on="1"/>
+ <pt x="920" y="0" on="1"/>
+ <pt x="311" y="1076" on="1"/>
+ <pt x="308" y="1076" on="1"/>
+ <pt x="308" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="493" y="1604" on="1"/>
+ <pt x="709" y="1925" on="1"/>
+ <pt x="937" y="1925" on="1"/>
+ <pt x="616" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 96 values pushed */
+ 25 22 2 23 5 3 20 19 18 17 14 13 10 9 8 7 4 3 2 1 14 5 0 3 24
+ 23 1 21 16 15 0 3 2 0 12 11 6 5 0 3 14 24 14 8 2 25 23 22 21 20
+ 17 11 10 7 9 8 6 3 13 12 2 13 14 5 4 1 0 4 13 2 0 0 16 9 8
+ 6 2 14 19 18 6 6 2 2 2 4 48 200 15 14 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ncaron" xMin="74" yMin="0" xMax="1155" yMax="1925">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="185" y="123" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="308" y="1480" on="1"/>
+ <pt x="918" y="405" on="1"/>
+ <pt x="920" y="405" on="1"/>
+ <pt x="920" y="1357" on="1"/>
+ <pt x="810" y="1357" on="1"/>
+ <pt x="810" y="1480" on="1"/>
+ <pt x="1155" y="1480" on="1"/>
+ <pt x="1155" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="0" on="1"/>
+ <pt x="920" y="0" on="1"/>
+ <pt x="311" y="1076" on="1"/>
+ <pt x="308" y="1076" on="1"/>
+ <pt x="308" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="981" y="1925" on="1"/>
+ <pt x="724" y="1604" on="1"/>
+ <pt x="506" y="1604" on="1"/>
+ <pt x="249" y="1925" on="1"/>
+ <pt x="373" y="1925" on="1"/>
+ <pt x="614" y="1723" on="1"/>
+ <pt x="616" y="1723" on="1"/>
+ <pt x="858" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 106 values pushed */
+ 20 19 18 17 14 13 10 9 8 7 4 3 2 1 14 5 0 3 29 28 27 26 25 22 6
+ 13 23 24 23 1 21 16 15 0 3 2 0 12 11 6 5 0 3 14 22 14 8 2 29 28
+ 27 26 24 23 21 20 17 11 10 7 12 8 6 3 25 6 2 2 13 12 2 13 14 5 4
+ 1 0 4 13 2 0 0 16 9 8 6 2 14 19 18 6 6 2 2 2 4 48 200 15 14
+ 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ncommaaccent" xMin="74" yMin="-432" xMax="1155" yMax="1480">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="185" y="123" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="308" y="1480" on="1"/>
+ <pt x="918" y="405" on="1"/>
+ <pt x="920" y="405" on="1"/>
+ <pt x="920" y="1357" on="1"/>
+ <pt x="810" y="1357" on="1"/>
+ <pt x="810" y="1480" on="1"/>
+ <pt x="1155" y="1480" on="1"/>
+ <pt x="1155" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="0" on="1"/>
+ <pt x="920" y="0" on="1"/>
+ <pt x="311" y="1076" on="1"/>
+ <pt x="308" y="1076" on="1"/>
+ <pt x="308" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="481" y="-421" on="1"/>
+ <pt x="481" y="-336" on="1"/>
+ <pt x="538" y="-345" on="0"/>
+ <pt x="578" y="-345" on="1"/>
+ <pt x="687" y="-345" on="0"/>
+ <pt x="687" y="-278" on="1"/>
+ <pt x="687" y="-205" on="0"/>
+ <pt x="530" y="-188" on="1"/>
+ <pt x="530" y="-111" on="1"/>
+ <pt x="664" y="-114" on="0"/>
+ <pt x="730" y="-143" on="1"/>
+ <pt x="823" y="-185" on="0"/>
+ <pt x="823" y="-280" on="1"/>
+ <pt x="823" y="-432" on="0"/>
+ <pt x="605" y="-432" on="1"/>
+ <pt x="547" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 107 values pushed */
+ 0 0 25 32 36 48 200 20 19 18 17 14 13 10 9 8 7 4 3 2 1 14 5 0 3
+ 30 29 23 22 4 13 36 0 21 16 15 0 3 0 12 11 6 5 0 3 14 0 0 27 20
+ 34 48 200 34 34 30 29 23 22 21 20 17 11 10 7 11 8 6 3 13 12 2 13 14 5
+ 4 1 0 4 13 2 0 0 16 9 8 6 2 14 19 18 6 6 2 2 2 4 48 200 15
+ 14 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ntilde" xMin="74" yMin="0" xMax="1155" yMax="1839">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="185" y="123" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="74" y="1357" on="1"/>
+ <pt x="74" y="1480" on="1"/>
+ <pt x="308" y="1480" on="1"/>
+ <pt x="918" y="405" on="1"/>
+ <pt x="920" y="405" on="1"/>
+ <pt x="920" y="1357" on="1"/>
+ <pt x="810" y="1357" on="1"/>
+ <pt x="810" y="1480" on="1"/>
+ <pt x="1155" y="1480" on="1"/>
+ <pt x="1155" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="0" on="1"/>
+ <pt x="920" y="0" on="1"/>
+ <pt x="311" y="1076" on="1"/>
+ <pt x="308" y="1076" on="1"/>
+ <pt x="308" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="271" y="1604" on="1"/>
+ <pt x="277" y="1699" on="0"/>
+ <pt x="302" y="1749" on="1"/>
+ <pt x="347" y="1839" on="0"/>
+ <pt x="456" y="1839" on="1"/>
+ <pt x="528" y="1839" on="0"/>
+ <pt x="591" y="1800" on="1"/>
+ <pt x="651" y="1763" on="1"/>
+ <pt x="713" y="1725" on="0"/>
+ <pt x="747" y="1725" on="1"/>
+ <pt x="816" y="1725" on="0"/>
+ <pt x="826" y="1839" on="1"/>
+ <pt x="937" y="1839" on="1"/>
+ <pt x="930" y="1745" on="0"/>
+ <pt x="905" y="1695" on="1"/>
+ <pt x="859" y="1604" on="0"/>
+ <pt x="752" y="1604" on="1"/>
+ <pt x="679" y="1604" on="0"/>
+ <pt x="616" y="1643" on="1"/>
+ <pt x="556" y="1680" on="1"/>
+ <pt x="496" y="1717" on="0"/>
+ <pt x="460" y="1717" on="1"/>
+ <pt x="392" y="1717" on="0"/>
+ <pt x="381" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 0 0 43 5 26 31 5 38 48 200 20 19 18 17 14 13 10 9 8 7 4 3 2 1 14
+ 5 0 3 45 34 33 22 4 13 38 26 5 21 16 15 0 3 0 12 11 6 5 0 3 14
+ 34 14 8 2 45 33 21 20 17 11 10 7 8 8 6 3 22 6 2 2 13 12 2 13 14
+ 5 4 1 0 4 13 2 0 0 16 9 8 6 2 14 19 18 6 6 2 2 2 4 48 200
+ 15 14 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="O" xMin="62" yMin="-37" xMax="1168" yMax="1517">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 14 0 0 28 39 4 20 39 12 48 200
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="OE" xMin="37" yMin="-37" xMax="1167" yMax="1518">
+ <contour>
+ <pt x="609" y="0" on="1"/>
+ <pt x="609" y="74" on="1"/>
+ <pt x="549" y="-37" on="0"/>
+ <pt x="436" y="-37" on="1"/>
+ <pt x="252" y="-37" on="0"/>
+ <pt x="145" y="170" on="1"/>
+ <pt x="37" y="377" on="0"/>
+ <pt x="37" y="740" on="1"/>
+ <pt x="37" y="1101" on="0"/>
+ <pt x="144" y="1310" on="1"/>
+ <pt x="251" y="1518" on="0"/>
+ <pt x="435" y="1518" on="1"/>
+ <pt x="552" y="1518" on="0"/>
+ <pt x="609" y="1406" on="1"/>
+ <pt x="609" y="1480" on="1"/>
+ <pt x="1142" y="1480" on="1"/>
+ <pt x="1142" y="1166" on="1"/>
+ <pt x="1019" y="1166" on="1"/>
+ <pt x="1019" y="1357" on="1"/>
+ <pt x="800" y="1357" on="1"/>
+ <pt x="800" y="827" on="1"/>
+ <pt x="945" y="827" on="1"/>
+ <pt x="945" y="950" on="1"/>
+ <pt x="1056" y="950" on="1"/>
+ <pt x="1056" y="580" on="1"/>
+ <pt x="945" y="580" on="1"/>
+ <pt x="945" y="703" on="1"/>
+ <pt x="800" y="703" on="1"/>
+ <pt x="800" y="136" on="1"/>
+ <pt x="1044" y="136" on="1"/>
+ <pt x="1044" y="370" on="1"/>
+ <pt x="1167" y="370" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="609" y="364" on="1"/>
+ <pt x="609" y="1117" on="1"/>
+ <pt x="609" y="1395" on="0"/>
+ <pt x="460" y="1395" on="1"/>
+ <pt x="237" y="1395" on="0"/>
+ <pt x="237" y="746" on="1"/>
+ <pt x="237" y="396" on="0"/>
+ <pt x="289" y="240" on="1"/>
+ <pt x="340" y="86" on="0"/>
+ <pt x="457" y="86" on="1"/>
+ <pt x="609" y="86" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 131 values pushed */
+ 0 0 42 5 3 36 5 11 48 200 11 0 3 2 13 14 18 2 34 23 22 17 16 5 18
+ 20 3 33 31 30 25 24 5 26 28 3 1 28 0 2 0 0 19 18 6 1 14 27 26 6
+ 1 20 29 28 20 1 0 3 4 48 200 21 20 1 32 0 1 2 0 15 14 0 14 0 0
+ 38 24 7 48 200 26 25 22 21 4 17 19 3 7 0 0 0 30 29 6 1 31 18 17 6
+ 1 15 34 33 14 13 1 0 19 5 19 3 4 48 200 32 31 1 16 15 1 24 23 1 28
+ 27 20 19 3 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Oacute" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="491" y="1604" on="1"/>
+ <pt x="707" y="1925" on="1"/>
+ <pt x="935" y="1925" on="1"/>
+ <pt x="614" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 1 35 32 2 33 0 3 0 34 33 1
+ 0 14 0 0 28 39 4 20 39 12 48 200 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Obreve" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="269" y="1925" on="1"/>
+ <pt x="392" y="1925" on="1"/>
+ <pt x="440" y="1777" on="0"/>
+ <pt x="614" y="1777" on="1"/>
+ <pt x="789" y="1777" on="0"/>
+ <pt x="837" y="1925" on="1"/>
+ <pt x="960" y="1925" on="1"/>
+ <pt x="937" y="1836" on="0"/>
+ <pt x="911" y="1790" on="1"/>
+ <pt x="820" y="1635" on="0"/>
+ <pt x="618" y="1635" on="1"/>
+ <pt x="466" y="1635" on="0"/>
+ <pt x="377" y="1716" on="1"/>
+ <pt x="322" y="1765" on="0"/>
+ <pt x="294" y="1837" on="1"/>
+ <pt x="283" y="1866" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 35 14 42 24 5 8 16 5 0 48 200 8 2 0 0 1 38 37 33 32 4 13 42
+ 0 0 14 0 0 28 36 4 20 36 12 48 200 38 37 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ocircumflex" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="249" y="1604" on="1"/>
+ <pt x="505" y="1925" on="1"/>
+ <pt x="724" y="1925" on="1"/>
+ <pt x="980" y="1604" on="1"/>
+ <pt x="857" y="1604" on="1"/>
+ <pt x="616" y="1806" on="1"/>
+ <pt x="613" y="1806" on="1"/>
+ <pt x="372" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 51 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 1 39 38 37 36 35 32 6 33 0 3
+ 0 34 33 1 0 14 0 0 28 39 4 20 39 12 48 200 39 38 37 36 35 34 33 32 12
+ 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Odieresis" xMin="62" yMin="-37" xMax="1168" yMax="1801">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="282" y="1604" on="1"/>
+ <pt x="282" y="1801" on="1"/>
+ <pt x="479" y="1801" on="1"/>
+ <pt x="479" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="751" y="1604" on="1"/>
+ <pt x="751" y="1801" on="1"/>
+ <pt x="948" y="1801" on="1"/>
+ <pt x="948" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 0 0 39 36 35 32 10 3 33 1 4
+ 48 200 38 37 34 33 3 0 14 0 0 28 39 4 20 39 12 48 200 4 38 12 32 0 0
+ 37 36 10 1 38 35 34 10 1 32 2 4 48 200 39 38 1 33 32 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ograve" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="738" y="1604" on="1"/>
+ <pt x="615" y="1604" on="1"/>
+ <pt x="294" y="1925" on="1"/>
+ <pt x="522" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 1 33 32 2 34 0 3 0 35 34 1
+ 0 14 0 0 28 39 4 20 39 12 48 200 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ohungarumlaut" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="313" y="1604" on="1"/>
+ <pt x="553" y="1925" on="1"/>
+ <pt x="745" y="1925" on="1"/>
+ <pt x="424" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="664" y="1604" on="1"/>
+ <pt x="905" y="1925" on="1"/>
+ <pt x="1096" y="1925" on="1"/>
+ <pt x="775" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 51 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 1 39 36 35 32 4 33 0 3 0 38
+ 37 34 33 3 0 14 0 0 28 39 4 20 39 12 48 200 39 38 37 36 35 34 33 32 12
+ 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Omacron" xMin="62" yMin="-37" xMax="1168" yMax="1728">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="269" y="1604" on="1"/>
+ <pt x="269" y="1728" on="1"/>
+ <pt x="960" y="1728" on="1"/>
+ <pt x="960" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 0 0 35 32 6 1 33 1 4 48 200
+ 34 33 1 0 14 0 0 28 39 4 20 39 12 48 200 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Oslash" xMin="62" yMin="-37" xMax="1168" yMax="1517">
+ <contour>
+ <pt x="321" y="371" on="1"/>
+ <pt x="865" y="1225" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ <pt x="616" y="1394" on="1"/>
+ <pt x="453" y="1394" on="0"/>
+ <pt x="364" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="742" on="1"/>
+ <pt x="275" y="545" on="0"/>
+ </contour>
+ <contour>
+ <pt x="364" y="254" on="1"/>
+ <pt x="457" y="86" on="0"/>
+ <pt x="613" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="865" y="258" on="1"/>
+ <pt x="955" y="431" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="937" on="0"/>
+ <pt x="908" y="1110" on="1"/>
+ </contour>
+ <contour>
+ <pt x="62" y="-37" on="1"/>
+ <pt x="206" y="190" on="1"/>
+ <pt x="62" y="432" on="0"/>
+ <pt x="62" y="739" on="1"/>
+ <pt x="62" y="1083" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="370" y="1517" on="0"/>
+ <pt x="613" y="1517" on="1"/>
+ <pt x="799" y="1517" on="0"/>
+ <pt x="958" y="1371" on="1"/>
+ <pt x="1051" y="1517" on="1"/>
+ <pt x="1168" y="1517" on="1"/>
+ <pt x="1023" y="1290" on="1"/>
+ <pt x="1168" y="1048" on="0"/>
+ <pt x="1168" y="740" on="1"/>
+ <pt x="1168" y="398" on="0"/>
+ <pt x="1014" y="181" on="1"/>
+ <pt x="860" y="-37" on="0"/>
+ <pt x="616" y="-37" on="1"/>
+ <pt x="431" y="-37" on="0"/>
+ <pt x="272" y="110" on="1"/>
+ <pt x="179" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 61 values pushed */
+ 36 2 25 0 3 1 1 30 27 17 3 1 5 0 1 3 0 0 11 1 1 38 19 11 9
+ 0 5 1 2 3 0 0 1 29 28 2 13 0 0 1 39 18 2 0 14 39 38 32 30 29
+ 28 27 21 19 18 17 15 9 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Otilde" xMin="62" yMin="-37" xMax="1168" yMax="1839">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="858" y="1517" on="0"/>
+ <pt x="1013" y="1301" on="1"/>
+ <pt x="1168" y="1085" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="394" on="0"/>
+ <pt x="1013" y="179" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="608" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="249" y="138" on="1"/>
+ <pt x="62" y="363" on="0"/>
+ <pt x="62" y="741" on="1"/>
+ <pt x="62" y="1084" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="371" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1049" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1222" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <contour>
+ <pt x="282" y="1604" on="1"/>
+ <pt x="288" y="1699" on="0"/>
+ <pt x="313" y="1749" on="1"/>
+ <pt x="358" y="1839" on="0"/>
+ <pt x="467" y="1839" on="1"/>
+ <pt x="539" y="1839" on="0"/>
+ <pt x="602" y="1800" on="1"/>
+ <pt x="662" y="1763" on="1"/>
+ <pt x="724" y="1725" on="0"/>
+ <pt x="758" y="1725" on="1"/>
+ <pt x="826" y="1725" on="0"/>
+ <pt x="837" y="1839" on="1"/>
+ <pt x="948" y="1839" on="1"/>
+ <pt x="941" y="1745" on="0"/>
+ <pt x="916" y="1695" on="1"/>
+ <pt x="870" y="1604" on="0"/>
+ <pt x="763" y="1604" on="1"/>
+ <pt x="690" y="1604" on="0"/>
+ <pt x="627" y="1643" on="1"/>
+ <pt x="567" y="1680" on="1"/>
+ <pt x="507" y="1717" on="0"/>
+ <pt x="471" y="1717" on="1"/>
+ <pt x="403" y="1717" on="0"/>
+ <pt x="392" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 0 0 53 5 36 41 5 48 24 5 8 16 5 0 48 200 8 2 0 0 1 55 44 43 32
+ 4 13 48 36 0 0 14 0 0 28 39 4 20 39 12 48 200 55 44 43 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="P" xMin="86" yMin="0" xMax="1124" yMax="1480">
+ <contour>
+ <pt x="481" y="598" on="1"/>
+ <pt x="481" y="123" on="1"/>
+ <pt x="765" y="123" on="1"/>
+ <pt x="765" y="0" on="1"/>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="283" y="123" on="1"/>
+ <pt x="283" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="747" y="1480" on="1"/>
+ <pt x="1124" y="1480" on="0"/>
+ <pt x="1124" y="1119" on="1"/>
+ <pt x="1124" y="878" on="0"/>
+ <pt x="984" y="738" on="1"/>
+ <pt x="844" y="598" on="0"/>
+ <pt x="599" y="598" on="1"/>
+ </contour>
+ <contour>
+ <pt x="481" y="722" on="1"/>
+ <pt x="592" y="722" on="1"/>
+ <pt x="914" y="722" on="0"/>
+ <pt x="914" y="1089" on="1"/>
+ <pt x="914" y="1357" on="0"/>
+ <pt x="682" y="1357" on="1"/>
+ <pt x="481" y="1357" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 18 17 16 0 4 7 1 3 0 0 23 22 8 7 6 3 9 6 5 2 1 6 3 3 2
+ 4 48 200 4 3 1 0 10 9 0 14 0 0 20 39 12 48 200 22 18 16 10 3 2 6
+ 13 12 0 9 8 5 4 4 13 6 0 0 23 17 1 0 10 3 6 1 4 48 200 7 6
+ 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Q" xMin="62" yMin="-321" xMax="1223" yMax="1517">
+ <contour>
+ <pt x="615" y="-37" on="1"/>
+ <pt x="459" y="-12" on="0"/>
+ <pt x="376" y="29" on="1"/>
+ <pt x="276" y="78" on="0"/>
+ <pt x="198" y="205" on="1"/>
+ <pt x="62" y="428" on="0"/>
+ <pt x="62" y="740" on="1"/>
+ <pt x="62" y="1083" on="0"/>
+ <pt x="216" y="1300" on="1"/>
+ <pt x="370" y="1517" on="0"/>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="859" y="1517" on="0"/>
+ <pt x="1013" y="1300" on="1"/>
+ <pt x="1168" y="1083" on="0"/>
+ <pt x="1168" y="741" on="1"/>
+ <pt x="1168" y="421" on="0"/>
+ <pt x="1034" y="209" on="1"/>
+ <pt x="943" y="66" on="0"/>
+ <pt x="789" y="-2" on="1"/>
+ <pt x="951" y="-103" on="0"/>
+ <pt x="1223" y="-163" on="1"/>
+ <pt x="1154" y="-248" on="0"/>
+ <pt x="1055" y="-321" on="1"/>
+ <pt x="846" y="-242" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1394" on="1"/>
+ <pt x="454" y="1394" on="0"/>
+ <pt x="365" y="1222" on="1"/>
+ <pt x="275" y="1050" on="0"/>
+ <pt x="275" y="740" on="1"/>
+ <pt x="275" y="434" on="0"/>
+ <pt x="364" y="260" on="1"/>
+ <pt x="452" y="86" on="0"/>
+ <pt x="614" y="86" on="1"/>
+ <pt x="776" y="86" on="0"/>
+ <pt x="860" y="236" on="1"/>
+ <pt x="955" y="405" on="0"/>
+ <pt x="955" y="738" on="1"/>
+ <pt x="955" y="1051" on="0"/>
+ <pt x="865" y="1223" on="1"/>
+ <pt x="774" y="1394" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 36 values pushed */
+ 0 0 24 5 10 48 200 10 0 1 22 20 18 0 4 13 32 0 0 14 0 0 36 39 14
+ 28 39 6 48 200 22 20 18 14 6 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="R" xMin="86" yMin="0" xMax="1204" yMax="1480">
+ <contour>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="216" y="123" on="1"/>
+ <pt x="216" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="673" y="1480" on="1"/>
+ <pt x="849" y="1480" on="0"/>
+ <pt x="950" y="1383" on="1"/>
+ <pt x="1052" y="1286" on="0"/>
+ <pt x="1052" y="1118" on="1"/>
+ <pt x="1052" y="965" on="0"/>
+ <pt x="960" y="847" on="1"/>
+ <pt x="906" y="779" on="0"/>
+ <pt x="803" y="709" on="1"/>
+ <pt x="1116" y="123" on="1"/>
+ <pt x="1204" y="123" on="1"/>
+ <pt x="1204" y="0" on="1"/>
+ <pt x="951" y="0" on="1"/>
+ <pt x="612" y="648" on="1"/>
+ <pt x="413" y="648" on="1"/>
+ <pt x="413" y="123" on="1"/>
+ <pt x="543" y="123" on="1"/>
+ <pt x="543" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="413" y="771" on="1"/>
+ <pt x="512" y="771" on="1"/>
+ <pt x="842" y="771" on="0"/>
+ <pt x="842" y="1096" on="1"/>
+ <pt x="842" y="1357" on="0"/>
+ <pt x="592" y="1357" on="1"/>
+ <pt x="413" y="1357" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 25 24 14 3 3 19 3 22 21 16 15 2 1 6 19 0 3 0 0 30 29 4 3 6 3
+ 5 1 4 48 200 20 19 1 23 18 17 0 3 2 0 6 5 0 14 0 0 27 39 10 48
+ 200 29 25 23 22 19 18 17 16 15 14 6 11 13 10 20 5 4 1 0 4 13 2 0 0
+ 30 24 21 20 10 3 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Racute" xMin="86" yMin="0" xMax="1204" yMax="1925">
+ <contour>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="216" y="123" on="1"/>
+ <pt x="216" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="673" y="1480" on="1"/>
+ <pt x="849" y="1480" on="0"/>
+ <pt x="950" y="1383" on="1"/>
+ <pt x="1052" y="1286" on="0"/>
+ <pt x="1052" y="1118" on="1"/>
+ <pt x="1052" y="965" on="0"/>
+ <pt x="960" y="847" on="1"/>
+ <pt x="906" y="779" on="0"/>
+ <pt x="803" y="709" on="1"/>
+ <pt x="1116" y="123" on="1"/>
+ <pt x="1204" y="123" on="1"/>
+ <pt x="1204" y="0" on="1"/>
+ <pt x="951" y="0" on="1"/>
+ <pt x="612" y="648" on="1"/>
+ <pt x="413" y="648" on="1"/>
+ <pt x="413" y="123" on="1"/>
+ <pt x="543" y="123" on="1"/>
+ <pt x="543" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="413" y="771" on="1"/>
+ <pt x="512" y="771" on="1"/>
+ <pt x="842" y="771" on="0"/>
+ <pt x="842" y="1096" on="1"/>
+ <pt x="842" y="1357" on="0"/>
+ <pt x="592" y="1357" on="1"/>
+ <pt x="413" y="1357" on="1"/>
+ </contour>
+ <contour>
+ <pt x="450" y="1604" on="1"/>
+ <pt x="666" y="1925" on="1"/>
+ <pt x="894" y="1925" on="1"/>
+ <pt x="573" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 34 31 2 32 5 3 25 24 14 3 3 19 3 22 21 16 15 2 1 6 19 0 3 0 0
+ 30 29 4 3 6 3 5 1 4 48 200 33 32 1 20 19 1 23 18 17 0 3 3 0 6
+ 5 0 14 0 0 27 39 10 48 200 34 33 32 31 29 25 23 22 19 18 17 16 15 14 6
+ 15 13 10 20 5 4 1 0 4 13 2 0 0 30 24 21 20 10 3 2 1 4 48 200 3
+ 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Rcaron" xMin="86" yMin="0" xMax="1204" yMax="1925">
+ <contour>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="216" y="123" on="1"/>
+ <pt x="216" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="673" y="1480" on="1"/>
+ <pt x="849" y="1480" on="0"/>
+ <pt x="950" y="1383" on="1"/>
+ <pt x="1052" y="1286" on="0"/>
+ <pt x="1052" y="1118" on="1"/>
+ <pt x="1052" y="965" on="0"/>
+ <pt x="960" y="847" on="1"/>
+ <pt x="906" y="779" on="0"/>
+ <pt x="803" y="709" on="1"/>
+ <pt x="1116" y="123" on="1"/>
+ <pt x="1204" y="123" on="1"/>
+ <pt x="1204" y="0" on="1"/>
+ <pt x="951" y="0" on="1"/>
+ <pt x="612" y="648" on="1"/>
+ <pt x="413" y="648" on="1"/>
+ <pt x="413" y="123" on="1"/>
+ <pt x="543" y="123" on="1"/>
+ <pt x="543" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="413" y="771" on="1"/>
+ <pt x="512" y="771" on="1"/>
+ <pt x="842" y="771" on="0"/>
+ <pt x="842" y="1096" on="1"/>
+ <pt x="842" y="1357" on="0"/>
+ <pt x="592" y="1357" on="1"/>
+ <pt x="413" y="1357" on="1"/>
+ </contour>
+ <contour>
+ <pt x="925" y="1925" on="1"/>
+ <pt x="668" y="1604" on="1"/>
+ <pt x="450" y="1604" on="1"/>
+ <pt x="193" y="1925" on="1"/>
+ <pt x="317" y="1925" on="1"/>
+ <pt x="558" y="1723" on="1"/>
+ <pt x="560" y="1723" on="1"/>
+ <pt x="802" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 113 values pushed */
+ 25 24 14 3 3 19 3 22 21 16 15 2 1 6 19 0 3 38 37 36 35 34 31 6 13
+ 32 0 0 30 29 4 3 6 3 5 1 4 48 200 33 32 1 20 19 1 23 18 17 0 3
+ 3 0 6 5 0 14 0 0 27 39 10 48 200 35 20 2 2 38 37 36 33 32 31 29 25
+ 23 22 19 18 17 16 15 14 6 17 13 10 20 34 5 4 1 0 5 13 2 0 0 30 24
+ 21 20 10 3 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Rcommaaccent" xMin="86" yMin="-432" xMax="1204" yMax="1480">
+ <contour>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="216" y="123" on="1"/>
+ <pt x="216" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="673" y="1480" on="1"/>
+ <pt x="849" y="1480" on="0"/>
+ <pt x="950" y="1383" on="1"/>
+ <pt x="1052" y="1286" on="0"/>
+ <pt x="1052" y="1118" on="1"/>
+ <pt x="1052" y="965" on="0"/>
+ <pt x="960" y="847" on="1"/>
+ <pt x="906" y="779" on="0"/>
+ <pt x="803" y="709" on="1"/>
+ <pt x="1116" y="123" on="1"/>
+ <pt x="1204" y="123" on="1"/>
+ <pt x="1204" y="0" on="1"/>
+ <pt x="951" y="0" on="1"/>
+ <pt x="612" y="648" on="1"/>
+ <pt x="413" y="648" on="1"/>
+ <pt x="413" y="123" on="1"/>
+ <pt x="543" y="123" on="1"/>
+ <pt x="543" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="413" y="771" on="1"/>
+ <pt x="512" y="771" on="1"/>
+ <pt x="842" y="771" on="0"/>
+ <pt x="842" y="1096" on="1"/>
+ <pt x="842" y="1357" on="0"/>
+ <pt x="592" y="1357" on="1"/>
+ <pt x="413" y="1357" on="1"/>
+ </contour>
+ <contour>
+ <pt x="542" y="-421" on="1"/>
+ <pt x="542" y="-336" on="1"/>
+ <pt x="599" y="-345" on="0"/>
+ <pt x="639" y="-345" on="1"/>
+ <pt x="748" y="-345" on="0"/>
+ <pt x="748" y="-278" on="1"/>
+ <pt x="748" y="-205" on="0"/>
+ <pt x="591" y="-188" on="1"/>
+ <pt x="591" y="-111" on="1"/>
+ <pt x="725" y="-114" on="0"/>
+ <pt x="791" y="-143" on="1"/>
+ <pt x="884" y="-185" on="0"/>
+ <pt x="884" y="-280" on="1"/>
+ <pt x="884" y="-432" on="0"/>
+ <pt x="666" y="-432" on="1"/>
+ <pt x="607" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 113 values pushed */
+ 0 0 34 32 45 48 200 25 24 14 3 3 19 3 22 21 16 15 2 1 6 19 0 3 39
+ 38 32 31 4 13 45 0 0 0 30 29 4 3 6 3 5 1 4 48 200 20 19 1 23 18
+ 17 0 3 2 0 6 5 0 14 0 0 36 20 43 27 39 10 48 200 39 38 32 31 29 25
+ 23 22 19 18 17 16 15 14 6 15 13 43 10 20 5 4 1 0 4 13 2 0 0 30 24
+ 21 20 10 3 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="S" xMin="151" yMin="-37" xMax="1091" yMax="1517">
+ <contour>
+ <pt x="151" y="61" on="1"/>
+ <pt x="151" y="419" on="1"/>
+ <pt x="275" y="419" on="1"/>
+ <pt x="299" y="185" on="1"/>
+ <pt x="486" y="86" on="0"/>
+ <pt x="610" y="86" on="1"/>
+ <pt x="737" y="86" on="0"/>
+ <pt x="816" y="165" on="1"/>
+ <pt x="895" y="243" on="0"/>
+ <pt x="895" y="365" on="1"/>
+ <pt x="895" y="522" on="0"/>
+ <pt x="695" y="626" on="1"/>
+ <pt x="505" y="725" on="1"/>
+ <pt x="316" y="823" on="0"/>
+ <pt x="249" y="906" on="1"/>
+ <pt x="183" y="986" on="0"/>
+ <pt x="183" y="1123" on="1"/>
+ <pt x="183" y="1517" on="0"/>
+ <pt x="631" y="1517" on="1"/>
+ <pt x="814" y="1517" on="0"/>
+ <pt x="1006" y="1444" on="1"/>
+ <pt x="1006" y="1086" on="1"/>
+ <pt x="883" y="1086" on="1"/>
+ <pt x="858" y="1320" on="1"/>
+ <pt x="733" y="1394" on="0"/>
+ <pt x="616" y="1394" on="1"/>
+ <pt x="375" y="1394" on="0"/>
+ <pt x="375" y="1148" on="1"/>
+ <pt x="375" y="1047" on="0"/>
+ <pt x="431" y="999" on="1"/>
+ <pt x="480" y="957" on="0"/>
+ <pt x="606" y="889" on="1"/>
+ <pt x="775" y="798" on="1"/>
+ <pt x="970" y="693" on="0"/>
+ <pt x="1030" y="620" on="1"/>
+ <pt x="1091" y="546" on="0"/>
+ <pt x="1091" y="413" on="1"/>
+ <pt x="1091" y="209" on="0"/>
+ <pt x="957" y="86" on="1"/>
+ <pt x="822" y="-37" on="0"/>
+ <pt x="598" y="-37" on="1"/>
+ <pt x="393" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 61 values pushed */
+ 0 0 25 5 18 5 5 40 48 200 40 2 18 0 1 1 23 22 21 20 3 2 1 0 8
+ 0 2 3 0 0 14 0 0 27 19 16 9 28 36 48 200 16 23 22 16 3 2 5 20 0
+ 3 36 20 21 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Sacute" xMin="151" yMin="-37" xMax="1091" yMax="1925">
+ <contour>
+ <pt x="151" y="61" on="1"/>
+ <pt x="151" y="419" on="1"/>
+ <pt x="275" y="419" on="1"/>
+ <pt x="299" y="185" on="1"/>
+ <pt x="486" y="86" on="0"/>
+ <pt x="610" y="86" on="1"/>
+ <pt x="737" y="86" on="0"/>
+ <pt x="816" y="165" on="1"/>
+ <pt x="895" y="243" on="0"/>
+ <pt x="895" y="365" on="1"/>
+ <pt x="895" y="522" on="0"/>
+ <pt x="695" y="626" on="1"/>
+ <pt x="505" y="725" on="1"/>
+ <pt x="316" y="823" on="0"/>
+ <pt x="249" y="906" on="1"/>
+ <pt x="183" y="986" on="0"/>
+ <pt x="183" y="1123" on="1"/>
+ <pt x="183" y="1517" on="0"/>
+ <pt x="631" y="1517" on="1"/>
+ <pt x="814" y="1517" on="0"/>
+ <pt x="1006" y="1444" on="1"/>
+ <pt x="1006" y="1086" on="1"/>
+ <pt x="883" y="1086" on="1"/>
+ <pt x="858" y="1320" on="1"/>
+ <pt x="733" y="1394" on="0"/>
+ <pt x="616" y="1394" on="1"/>
+ <pt x="375" y="1394" on="0"/>
+ <pt x="375" y="1148" on="1"/>
+ <pt x="375" y="1047" on="0"/>
+ <pt x="431" y="999" on="1"/>
+ <pt x="480" y="957" on="0"/>
+ <pt x="606" y="889" on="1"/>
+ <pt x="775" y="798" on="1"/>
+ <pt x="970" y="693" on="0"/>
+ <pt x="1030" y="620" on="1"/>
+ <pt x="1091" y="546" on="0"/>
+ <pt x="1091" y="413" on="1"/>
+ <pt x="1091" y="209" on="0"/>
+ <pt x="957" y="86" on="1"/>
+ <pt x="822" y="-37" on="0"/>
+ <pt x="598" y="-37" on="1"/>
+ <pt x="393" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="509" y="1604" on="1"/>
+ <pt x="725" y="1925" on="1"/>
+ <pt x="953" y="1925" on="1"/>
+ <pt x="632" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 25 5 18 5 5 40 48 200 40 2 18 0 1 45 42 2 43 0 3 0 1 1 23
+ 22 21 20 3 2 1 0 8 0 2 3 0 0 44 43 1 0 14 0 0 27 19 16 9 28
+ 36 48 200 16 45 44 43 42 23 22 16 3 2 9 20 0 3 36 20 21 20 1 1 0 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scaron" xMin="151" yMin="-37" xMax="1091" yMax="1925">
+ <contour>
+ <pt x="151" y="61" on="1"/>
+ <pt x="151" y="419" on="1"/>
+ <pt x="275" y="419" on="1"/>
+ <pt x="299" y="185" on="1"/>
+ <pt x="486" y="86" on="0"/>
+ <pt x="610" y="86" on="1"/>
+ <pt x="737" y="86" on="0"/>
+ <pt x="816" y="165" on="1"/>
+ <pt x="895" y="243" on="0"/>
+ <pt x="895" y="365" on="1"/>
+ <pt x="895" y="522" on="0"/>
+ <pt x="695" y="626" on="1"/>
+ <pt x="505" y="725" on="1"/>
+ <pt x="316" y="823" on="0"/>
+ <pt x="249" y="906" on="1"/>
+ <pt x="183" y="986" on="0"/>
+ <pt x="183" y="1123" on="1"/>
+ <pt x="183" y="1517" on="0"/>
+ <pt x="631" y="1517" on="1"/>
+ <pt x="814" y="1517" on="0"/>
+ <pt x="1006" y="1444" on="1"/>
+ <pt x="1006" y="1086" on="1"/>
+ <pt x="883" y="1086" on="1"/>
+ <pt x="858" y="1320" on="1"/>
+ <pt x="733" y="1394" on="0"/>
+ <pt x="616" y="1394" on="1"/>
+ <pt x="375" y="1394" on="0"/>
+ <pt x="375" y="1148" on="1"/>
+ <pt x="375" y="1047" on="0"/>
+ <pt x="431" y="999" on="1"/>
+ <pt x="480" y="957" on="0"/>
+ <pt x="606" y="889" on="1"/>
+ <pt x="775" y="798" on="1"/>
+ <pt x="970" y="693" on="0"/>
+ <pt x="1030" y="620" on="1"/>
+ <pt x="1091" y="546" on="0"/>
+ <pt x="1091" y="413" on="1"/>
+ <pt x="1091" y="209" on="0"/>
+ <pt x="957" y="86" on="1"/>
+ <pt x="822" y="-37" on="0"/>
+ <pt x="598" y="-37" on="1"/>
+ <pt x="393" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="999" y="1925" on="1"/>
+ <pt x="742" y="1604" on="1"/>
+ <pt x="524" y="1604" on="1"/>
+ <pt x="267" y="1925" on="1"/>
+ <pt x="391" y="1925" on="1"/>
+ <pt x="632" y="1723" on="1"/>
+ <pt x="634" y="1723" on="1"/>
+ <pt x="876" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 25 5 18 5 5 40 48 200 40 2 18 0 1 1 23 22 21 20 3 2 1 0 8
+ 0 2 3 0 0 49 48 47 46 45 42 6 13 43 44 43 1 0 14 0 0 27 19 16 9
+ 28 36 48 200 16 49 48 47 46 45 44 43 42 23 22 16 3 2 13 20 0 3 36 20 21
+ 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scedilla" xMin="151" yMin="-432" xMax="1091" yMax="1517">
+ <contour>
+ <pt x="151" y="61" on="1"/>
+ <pt x="151" y="419" on="1"/>
+ <pt x="275" y="419" on="1"/>
+ <pt x="299" y="185" on="1"/>
+ <pt x="486" y="86" on="0"/>
+ <pt x="610" y="86" on="1"/>
+ <pt x="737" y="86" on="0"/>
+ <pt x="816" y="165" on="1"/>
+ <pt x="895" y="243" on="0"/>
+ <pt x="895" y="365" on="1"/>
+ <pt x="895" y="522" on="0"/>
+ <pt x="695" y="626" on="1"/>
+ <pt x="505" y="725" on="1"/>
+ <pt x="316" y="823" on="0"/>
+ <pt x="249" y="906" on="1"/>
+ <pt x="183" y="986" on="0"/>
+ <pt x="183" y="1123" on="1"/>
+ <pt x="183" y="1517" on="0"/>
+ <pt x="632" y="1517" on="1"/>
+ <pt x="814" y="1517" on="0"/>
+ <pt x="1006" y="1444" on="1"/>
+ <pt x="1006" y="1086" on="1"/>
+ <pt x="883" y="1086" on="1"/>
+ <pt x="858" y="1320" on="1"/>
+ <pt x="733" y="1394" on="0"/>
+ <pt x="616" y="1394" on="1"/>
+ <pt x="375" y="1394" on="0"/>
+ <pt x="375" y="1148" on="1"/>
+ <pt x="375" y="1047" on="0"/>
+ <pt x="431" y="999" on="1"/>
+ <pt x="480" y="957" on="0"/>
+ <pt x="606" y="889" on="1"/>
+ <pt x="775" y="798" on="1"/>
+ <pt x="970" y="693" on="0"/>
+ <pt x="1030" y="620" on="1"/>
+ <pt x="1091" y="546" on="0"/>
+ <pt x="1091" y="413" on="1"/>
+ <pt x="1091" y="209" on="0"/>
+ <pt x="957" y="86" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="598" y="-37" on="1"/>
+ <pt x="393" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="554" y="0" on="1"/>
+ <pt x="651" y="0" on="1"/>
+ <pt x="591" y="-109" on="1"/>
+ <pt x="663" y="-111" on="0"/>
+ <pt x="715" y="-148" on="1"/>
+ <pt x="785" y="-197" on="0"/>
+ <pt x="785" y="-269" on="1"/>
+ <pt x="785" y="-337" on="0"/>
+ <pt x="726" y="-384" on="1"/>
+ <pt x="668" y="-432" on="0"/>
+ <pt x="581" y="-432" on="1"/>
+ <pt x="514" y="-432" on="0"/>
+ <pt x="438" y="-411" on="1"/>
+ <pt x="438" y="-330" on="1"/>
+ <pt x="488" y="-345" on="0"/>
+ <pt x="542" y="-345" on="1"/>
+ <pt x="646" y="-345" on="0"/>
+ <pt x="646" y="-271" on="1"/>
+ <pt x="646" y="-178" on="0"/>
+ <pt x="459" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 57 32 52 25 5 18 5 5 40 48 200 40 2 18 0 1 1 23 22 21 20 3 2
+ 1 0 8 0 2 3 0 0 1 61 55 54 44 43 42 6 13 52 2 0 14 0 0 59 20
+ 48 27 19 16 9 28 36 48 200 48 16 61 55 54 48 44 43 42 23 22 16 3 2 12 20
+ 0 3 36 20 21 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scircumflex" xMin="151" yMin="-37" xMax="1091" yMax="1925">
+ <contour>
+ <pt x="151" y="61" on="1"/>
+ <pt x="151" y="419" on="1"/>
+ <pt x="275" y="419" on="1"/>
+ <pt x="299" y="185" on="1"/>
+ <pt x="486" y="86" on="0"/>
+ <pt x="610" y="86" on="1"/>
+ <pt x="737" y="86" on="0"/>
+ <pt x="816" y="165" on="1"/>
+ <pt x="895" y="243" on="0"/>
+ <pt x="895" y="365" on="1"/>
+ <pt x="895" y="522" on="0"/>
+ <pt x="695" y="626" on="1"/>
+ <pt x="505" y="725" on="1"/>
+ <pt x="316" y="823" on="0"/>
+ <pt x="249" y="906" on="1"/>
+ <pt x="183" y="986" on="0"/>
+ <pt x="183" y="1123" on="1"/>
+ <pt x="183" y="1517" on="0"/>
+ <pt x="631" y="1517" on="1"/>
+ <pt x="814" y="1517" on="0"/>
+ <pt x="1006" y="1444" on="1"/>
+ <pt x="1006" y="1086" on="1"/>
+ <pt x="883" y="1086" on="1"/>
+ <pt x="858" y="1320" on="1"/>
+ <pt x="733" y="1394" on="0"/>
+ <pt x="616" y="1394" on="1"/>
+ <pt x="375" y="1394" on="0"/>
+ <pt x="375" y="1148" on="1"/>
+ <pt x="375" y="1047" on="0"/>
+ <pt x="431" y="999" on="1"/>
+ <pt x="480" y="957" on="0"/>
+ <pt x="606" y="889" on="1"/>
+ <pt x="775" y="798" on="1"/>
+ <pt x="970" y="693" on="0"/>
+ <pt x="1030" y="620" on="1"/>
+ <pt x="1091" y="546" on="0"/>
+ <pt x="1091" y="413" on="1"/>
+ <pt x="1091" y="209" on="0"/>
+ <pt x="957" y="86" on="1"/>
+ <pt x="822" y="-37" on="0"/>
+ <pt x="598" y="-37" on="1"/>
+ <pt x="393" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="267" y="1604" on="1"/>
+ <pt x="523" y="1925" on="1"/>
+ <pt x="742" y="1925" on="1"/>
+ <pt x="998" y="1604" on="1"/>
+ <pt x="875" y="1604" on="1"/>
+ <pt x="634" y="1806" on="1"/>
+ <pt x="631" y="1806" on="1"/>
+ <pt x="390" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 25 5 18 5 5 40 48 200 40 2 18 0 1 49 48 47 46 45 42 6 43 0 3
+ 0 1 1 23 22 21 20 3 2 1 0 8 0 2 3 0 0 44 43 1 0 14 0 0 27
+ 19 16 9 28 36 48 200 16 49 48 47 46 45 44 43 42 23 22 16 3 2 13 20 0 3
+ 36 20 21 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scommaaccent" xMin="151" yMin="-432" xMax="1091" yMax="1517">
+ <contour>
+ <pt x="151" y="61" on="1"/>
+ <pt x="151" y="419" on="1"/>
+ <pt x="275" y="419" on="1"/>
+ <pt x="299" y="185" on="1"/>
+ <pt x="486" y="86" on="0"/>
+ <pt x="610" y="86" on="1"/>
+ <pt x="737" y="86" on="0"/>
+ <pt x="816" y="165" on="1"/>
+ <pt x="895" y="243" on="0"/>
+ <pt x="895" y="365" on="1"/>
+ <pt x="895" y="522" on="0"/>
+ <pt x="695" y="626" on="1"/>
+ <pt x="505" y="725" on="1"/>
+ <pt x="316" y="823" on="0"/>
+ <pt x="249" y="906" on="1"/>
+ <pt x="183" y="986" on="0"/>
+ <pt x="183" y="1123" on="1"/>
+ <pt x="183" y="1517" on="0"/>
+ <pt x="632" y="1517" on="1"/>
+ <pt x="814" y="1517" on="0"/>
+ <pt x="1006" y="1444" on="1"/>
+ <pt x="1006" y="1086" on="1"/>
+ <pt x="883" y="1086" on="1"/>
+ <pt x="858" y="1320" on="1"/>
+ <pt x="733" y="1394" on="0"/>
+ <pt x="616" y="1394" on="1"/>
+ <pt x="375" y="1394" on="0"/>
+ <pt x="375" y="1148" on="1"/>
+ <pt x="375" y="1047" on="0"/>
+ <pt x="431" y="999" on="1"/>
+ <pt x="480" y="957" on="0"/>
+ <pt x="606" y="889" on="1"/>
+ <pt x="775" y="798" on="1"/>
+ <pt x="970" y="693" on="0"/>
+ <pt x="1030" y="620" on="1"/>
+ <pt x="1091" y="546" on="0"/>
+ <pt x="1091" y="413" on="1"/>
+ <pt x="1091" y="209" on="0"/>
+ <pt x="957" y="86" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="598" y="-37" on="1"/>
+ <pt x="393" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="484" y="-421" on="1"/>
+ <pt x="484" y="-336" on="1"/>
+ <pt x="541" y="-345" on="0"/>
+ <pt x="581" y="-345" on="1"/>
+ <pt x="690" y="-345" on="0"/>
+ <pt x="690" y="-278" on="1"/>
+ <pt x="690" y="-205" on="0"/>
+ <pt x="533" y="-188" on="1"/>
+ <pt x="533" y="-111" on="1"/>
+ <pt x="667" y="-114" on="0"/>
+ <pt x="733" y="-143" on="1"/>
+ <pt x="826" y="-185" on="0"/>
+ <pt x="826" y="-280" on="1"/>
+ <pt x="826" y="-432" on="0"/>
+ <pt x="608" y="-432" on="1"/>
+ <pt x="550" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 45 32 56 25 5 18 5 5 40 48 200 40 2 18 0 1 1 23 22 21 20 3 2
+ 1 0 8 0 2 3 0 0 1 50 49 43 42 4 13 56 2 0 14 0 0 47 20 54 27
+ 19 16 9 28 36 48 200 54 16 54 50 49 43 42 23 22 16 3 2 10 20 0 3 36 20
+ 21 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="T" xMin="62" yMin="0" xMax="1168" yMax="1480">
+ <contour>
+ <pt x="257" y="0" on="1"/>
+ <pt x="257" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="1357" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="185" y="1086" on="1"/>
+ <pt x="62" y="1086" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1086" on="1"/>
+ <pt x="1044" y="1086" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="714" y="1357" on="1"/>
+ <pt x="714" y="123" on="1"/>
+ <pt x="973" y="123" on="1"/>
+ <pt x="973" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 10 9 6 5 4 3 1 3 0 0 12 11 4 3 6 3 7 14 13 2 1 6 3 0 2
+ 4 48 200 15 0 1 0 8 7 0 14 15 14 2 10 12 3 1 0 2 2 4 3 0 0
+ 11 10 6 1 8 13 12 10 1 2 5 4 6 1 6 3 4 48 200 9 8 1 3 2 1
+ 7 6 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tbar" xMin="62" yMin="0" xMax="1168" yMax="1480">
+ <contour>
+ <pt x="257" y="0" on="1"/>
+ <pt x="257" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="716" on="1"/>
+ <pt x="220" y="716" on="1"/>
+ <pt x="220" y="814" on="1"/>
+ <pt x="516" y="814" on="1"/>
+ <pt x="516" y="1357" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="185" y="1086" on="1"/>
+ <pt x="62" y="1086" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1086" on="1"/>
+ <pt x="1044" y="1086" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="714" y="1357" on="1"/>
+ <pt x="714" y="814" on="1"/>
+ <pt x="1010" y="814" on="1"/>
+ <pt x="1010" y="716" on="1"/>
+ <pt x="714" y="716" on="1"/>
+ <pt x="714" y="123" on="1"/>
+ <pt x="973" y="123" on="1"/>
+ <pt x="973" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 101 values pushed */
+ 14 13 10 9 4 7 5 3 0 0 16 15 8 7 6 3 11 20 19 4 3 33 3 5 22
+ 21 2 1 6 3 0 3 4 48 200 18 17 6 5 3 23 0 1 2 0 12 11 0 14 23
+ 22 19 18 4 14 16 3 5 4 1 0 4 2 8 3 0 0 15 14 6 1 12 21 20 17
+ 16 10 3 2 9 8 6 1 10 3 4 48 200 13 12 1 7 6 3 2 3 11 10 1 3
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcaron" xMin="62" yMin="0" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="257" y="0" on="1"/>
+ <pt x="257" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="1357" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="185" y="1086" on="1"/>
+ <pt x="62" y="1086" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1086" on="1"/>
+ <pt x="1044" y="1086" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="714" y="1357" on="1"/>
+ <pt x="714" y="123" on="1"/>
+ <pt x="973" y="123" on="1"/>
+ <pt x="973" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="981" y="1925" on="1"/>
+ <pt x="724" y="1604" on="1"/>
+ <pt x="506" y="1604" on="1"/>
+ <pt x="249" y="1925" on="1"/>
+ <pt x="373" y="1925" on="1"/>
+ <pt x="614" y="1723" on="1"/>
+ <pt x="616" y="1723" on="1"/>
+ <pt x="858" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 105 values pushed */
+ 10 9 6 5 4 3 1 3 23 22 21 20 19 16 6 13 17 0 0 12 11 4 3 6 3
+ 7 14 13 2 1 6 3 0 2 4 48 200 18 17 1 15 0 1 2 0 8 7 0 14 23
+ 17 16 15 14 5 10 12 3 22 21 2 12 2 3 20 19 18 1 0 5 2 4 3 0 0
+ 11 10 6 1 8 13 12 10 1 2 5 4 6 1 6 3 4 48 200 9 8 1 3 2 1
+ 7 6 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcommaaccent" xMin="62" yMin="-432" xMax="1168" yMax="1480">
+ <contour>
+ <pt x="257" y="0" on="1"/>
+ <pt x="257" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="1357" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="185" y="1086" on="1"/>
+ <pt x="62" y="1086" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1086" on="1"/>
+ <pt x="1044" y="1086" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="714" y="1357" on="1"/>
+ <pt x="714" y="123" on="1"/>
+ <pt x="973" y="123" on="1"/>
+ <pt x="973" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="592" y="0" on="1"/>
+ <pt x="689" y="0" on="1"/>
+ <pt x="629" y="-109" on="1"/>
+ <pt x="701" y="-111" on="0"/>
+ <pt x="753" y="-148" on="1"/>
+ <pt x="823" y="-197" on="0"/>
+ <pt x="823" y="-269" on="1"/>
+ <pt x="823" y="-337" on="0"/>
+ <pt x="764" y="-384" on="1"/>
+ <pt x="705" y="-432" on="0"/>
+ <pt x="620" y="-432" on="1"/>
+ <pt x="552" y="-432" on="0"/>
+ <pt x="476" y="-411" on="1"/>
+ <pt x="476" y="-330" on="1"/>
+ <pt x="526" y="-345" on="0"/>
+ <pt x="580" y="-345" on="1"/>
+ <pt x="684" y="-345" on="0"/>
+ <pt x="684" y="-271" on="1"/>
+ <pt x="684" y="-178" on="0"/>
+ <pt x="497" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 116 values pushed */
+ 0 0 31 32 26 48 200 10 9 6 5 4 3 1 3 35 29 28 18 4 13 26 0 0 0
+ 12 11 4 3 6 3 7 14 13 2 1 6 3 0 2 4 48 200 17 16 15 0 3 0 8
+ 7 0 14 0 0 33 20 22 48 200 22 22 15 14 3 10 12 3 18 17 16 3 12 2 3
+ 35 29 28 1 0 5 2 4 3 0 0 11 10 6 1 8 13 12 10 1 2 5 4 6 1
+ 6 3 4 48 200 9 8 1 3 2 1 7 6 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcommabelow" xMin="62" yMin="-432" xMax="1168" yMax="1480">
+ <contour>
+ <pt x="257" y="0" on="1"/>
+ <pt x="257" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="1357" on="1"/>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="185" y="1086" on="1"/>
+ <pt x="62" y="1086" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1086" on="1"/>
+ <pt x="1044" y="1086" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="714" y="1357" on="1"/>
+ <pt x="714" y="123" on="1"/>
+ <pt x="973" y="123" on="1"/>
+ <pt x="973" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="472" y="-421" on="1"/>
+ <pt x="472" y="-336" on="1"/>
+ <pt x="529" y="-345" on="0"/>
+ <pt x="569" y="-345" on="1"/>
+ <pt x="678" y="-345" on="0"/>
+ <pt x="678" y="-278" on="1"/>
+ <pt x="678" y="-205" on="0"/>
+ <pt x="521" y="-188" on="1"/>
+ <pt x="521" y="-111" on="1"/>
+ <pt x="655" y="-114" on="0"/>
+ <pt x="721" y="-143" on="1"/>
+ <pt x="814" y="-185" on="0"/>
+ <pt x="814" y="-280" on="1"/>
+ <pt x="814" y="-432" on="0"/>
+ <pt x="596" y="-432" on="1"/>
+ <pt x="538" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 112 values pushed */
+ 0 0 19 32 30 48 200 10 9 6 5 4 3 1 3 24 23 17 16 4 13 30 0 0 0
+ 12 11 4 3 6 3 7 14 13 2 1 6 3 0 2 4 48 200 15 0 1 0 8 7 0
+ 14 0 0 21 20 28 48 200 28 28 15 14 3 10 12 3 24 23 2 12 2 3 17 16 1
+ 0 4 2 4 3 0 0 11 10 6 1 8 13 12 10 1 2 5 4 6 1 6 3 4 48
+ 200 9 8 1 3 2 1 7 6 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Thorn" xMin="86" yMin="0" xMax="1124" yMax="1480">
+ <contour>
+ <pt x="481" y="1191" on="1"/>
+ <pt x="670" y="1191" on="1"/>
+ <pt x="1124" y="1191" on="0"/>
+ <pt x="1124" y="829" on="1"/>
+ <pt x="1124" y="588" on="0"/>
+ <pt x="955" y="449" on="1"/>
+ <pt x="787" y="309" on="0"/>
+ <pt x="492" y="309" on="1"/>
+ <pt x="481" y="309" on="1"/>
+ <pt x="481" y="123" on="1"/>
+ <pt x="678" y="123" on="1"/>
+ <pt x="678" y="0" on="1"/>
+ <pt x="86" y="0" on="1"/>
+ <pt x="86" y="123" on="1"/>
+ <pt x="283" y="123" on="1"/>
+ <pt x="283" y="1357" on="1"/>
+ <pt x="86" y="1357" on="1"/>
+ <pt x="86" y="1480" on="1"/>
+ <pt x="678" y="1480" on="1"/>
+ <pt x="678" y="1357" on="1"/>
+ <pt x="481" y="1357" on="1"/>
+ </contour>
+ <contour>
+ <pt x="481" y="432" on="1"/>
+ <pt x="493" y="432" on="1"/>
+ <pt x="694" y="432" on="0"/>
+ <pt x="804" y="528" on="1"/>
+ <pt x="914" y="623" on="0"/>
+ <pt x="914" y="796" on="1"/>
+ <pt x="914" y="1067" on="0"/>
+ <pt x="592" y="1067" on="1"/>
+ <pt x="481" y="1067" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 29 28 22 21 8 7 6 0 9 3 0 0 20 19 16 15 6 3 17 14 13 10 9 6 3
+ 11 2 4 48 200 1 0 1 12 11 1 2 0 18 17 0 14 0 0 26 39 3 48 200 28
+ 22 19 18 11 10 7 1 8 13 3 0 17 16 13 12 4 13 14 0 0 29 21 20 9 8
+ 0 10 5 14 1 4 48 200 15 14 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="U" xMin="62" yMin="-37" xMax="1168" yMax="1480">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 0 0 10 5 23 48 200 23 2 1 25 19 18 17 14 13 12 6 5 4 1 0 12 2 2
+ 3 0 16 15 3 2 0 3 14 15 14 4 3 4 12 5 3 17 16 2 13 18 2 1 0
+ 0 0 13 12 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uacute" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="528" y="1604" on="1"/>
+ <pt x="744" y="1925" on="1"/>
+ <pt x="972" y="1925" on="1"/>
+ <pt x="651" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 0 0 10 5 23 48 200 23 2 29 26 2 27 2 3 1 25 19 18 17 14 13 12 6 5
+ 4 1 0 12 2 2 3 0 28 27 1 0 16 15 3 2 0 3 14 28 18 12 2 29 27
+ 26 15 14 4 3 7 12 5 3 17 16 2 13 18 2 1 0 0 0 13 12 6 1 18 6
+ 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ubreve" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="306" y="1925" on="1"/>
+ <pt x="429" y="1925" on="1"/>
+ <pt x="477" y="1777" on="0"/>
+ <pt x="651" y="1777" on="1"/>
+ <pt x="826" y="1777" on="0"/>
+ <pt x="874" y="1925" on="1"/>
+ <pt x="997" y="1925" on="1"/>
+ <pt x="974" y="1836" on="0"/>
+ <pt x="948" y="1790" on="1"/>
+ <pt x="857" y="1635" on="0"/>
+ <pt x="655" y="1635" on="1"/>
+ <pt x="503" y="1635" on="0"/>
+ <pt x="414" y="1716" on="1"/>
+ <pt x="359" y="1765" on="0"/>
+ <pt x="331" y="1837" on="1"/>
+ <pt x="320" y="1866" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 95 values pushed */
+ 0 0 29 14 36 10 5 23 48 200 23 2 1 25 19 18 17 14 13 12 6 5 4 1 0
+ 12 2 2 3 0 32 31 27 26 4 13 36 2 16 15 3 2 0 3 14 32 18 12 2 31
+ 27 15 14 4 3 6 12 5 3 26 5 0 2 17 16 2 13 18 2 1 0 0 0 13 12
+ 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ucircumflex" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="286" y="1604" on="1"/>
+ <pt x="542" y="1925" on="1"/>
+ <pt x="761" y="1925" on="1"/>
+ <pt x="1017" y="1604" on="1"/>
+ <pt x="894" y="1604" on="1"/>
+ <pt x="653" y="1806" on="1"/>
+ <pt x="650" y="1806" on="1"/>
+ <pt x="409" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 102 values pushed */
+ 0 0 10 5 23 48 200 23 2 33 32 31 30 29 26 6 27 2 3 1 25 19 18 17 14
+ 13 12 6 5 4 1 0 12 2 2 3 0 28 27 1 0 16 15 3 2 0 3 14 29 18
+ 12 2 33 32 31 30 28 27 15 14 4 3 10 12 5 3 26 5 0 2 17 16 2 13 18
+ 2 1 0 0 0 13 12 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1
+ 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Udieresis" xMin="62" yMin="-37" xMax="1168" yMax="1801">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="319" y="1604" on="1"/>
+ <pt x="319" y="1801" on="1"/>
+ <pt x="516" y="1801" on="1"/>
+ <pt x="516" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="788" y="1604" on="1"/>
+ <pt x="788" y="1801" on="1"/>
+ <pt x="985" y="1801" on="1"/>
+ <pt x="985" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 10 5 23 48 200 23 2 1 25 19 18 17 14 13 12 6 5 4 1 0 12 2 2
+ 3 0 0 0 33 30 29 26 10 3 27 1 4 48 200 32 31 28 27 3 0 16 15 3 2
+ 0 3 14 15 14 4 3 4 30 28 3 17 16 2 13 18 2 1 0 0 0 31 30 10 1
+ 32 29 28 10 1 26 13 12 6 1 18 6 5 10 1 0 4 4 48 200 33 32 1 27 26
+ 1 19 18 1 25 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ugrave" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="775" y="1604" on="1"/>
+ <pt x="652" y="1604" on="1"/>
+ <pt x="331" y="1925" on="1"/>
+ <pt x="559" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 0 0 10 5 23 48 200 23 2 27 26 2 28 2 3 1 25 19 18 17 14 13 12 6 5
+ 4 1 0 12 2 2 3 0 29 28 1 0 16 15 3 2 0 3 14 29 27 26 15 14 4
+ 3 7 12 5 3 28 5 0 2 17 16 2 13 18 2 1 0 0 0 13 12 6 1 18 6
+ 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uhungarumlaut" xMin="62" yMin="-37" xMax="1168" yMax="1925">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="384" y="1604" on="1"/>
+ <pt x="624" y="1925" on="1"/>
+ <pt x="816" y="1925" on="1"/>
+ <pt x="495" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="735" y="1604" on="1"/>
+ <pt x="976" y="1925" on="1"/>
+ <pt x="1167" y="1925" on="1"/>
+ <pt x="846" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 99 values pushed */
+ 0 0 10 5 23 48 200 23 2 33 30 29 26 4 27 2 3 1 25 19 18 17 14 13 12
+ 6 5 4 1 0 12 2 2 3 0 32 31 28 27 3 0 16 15 3 2 0 3 14 31 18
+ 12 2 33 30 29 28 27 26 15 14 4 3 10 12 5 3 32 17 16 3 13 18 2 1 0
+ 0 0 13 12 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Umacron" xMin="62" yMin="-37" xMax="1168" yMax="1728">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="303" y="1604" on="1"/>
+ <pt x="303" y="1728" on="1"/>
+ <pt x="994" y="1728" on="1"/>
+ <pt x="994" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 101 values pushed */
+ 0 0 10 5 23 48 200 23 2 1 25 19 18 17 14 13 12 6 5 4 1 0 12 2 2
+ 3 0 0 0 29 26 6 1 27 1 4 48 200 28 27 1 0 16 15 3 2 0 3 14 29
+ 28 2 18 12 3 15 14 4 3 4 12 5 3 27 26 2 5 0 3 17 16 2 13 18 2
+ 1 0 0 0 13 12 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Unterkomma" xMin="464" yMin="-432" xMax="806" yMax="-111">
+ <contour>
+ <pt x="464" y="-421" on="1"/>
+ <pt x="464" y="-336" on="1"/>
+ <pt x="521" y="-345" on="0"/>
+ <pt x="561" y="-345" on="1"/>
+ <pt x="670" y="-345" on="0"/>
+ <pt x="670" y="-278" on="1"/>
+ <pt x="670" y="-205" on="0"/>
+ <pt x="513" y="-188" on="1"/>
+ <pt x="513" y="-111" on="1"/>
+ <pt x="647" y="-114" on="0"/>
+ <pt x="713" y="-143" on="1"/>
+ <pt x="806" y="-185" on="0"/>
+ <pt x="806" y="-280" on="1"/>
+ <pt x="806" y="-432" on="0"/>
+ <pt x="588" y="-432" on="1"/>
+ <pt x="530" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 3 32 14 48 200 14 8 7 1 0 14 0 0 5 20 12 48 200 12 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uogonek" xMin="62" yMin="-370" xMax="1168" yMax="1480">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="686" y="0" on="1"/>
+ <pt x="793" y="0" on="1"/>
+ <pt x="664" y="-81" on="0"/>
+ <pt x="664" y="-179" on="1"/>
+ <pt x="664" y="-275" on="0"/>
+ <pt x="779" y="-275" on="1"/>
+ <pt x="833" y="-275" on="0"/>
+ <pt x="870" y="-260" on="1"/>
+ <pt x="870" y="-341" on="1"/>
+ <pt x="808" y="-370" on="0"/>
+ <pt x="730" y="-370" on="1"/>
+ <pt x="528" y="-370" on="0"/>
+ <pt x="528" y="-213" on="1"/>
+ <pt x="528" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 100 values pushed */
+ 0 0 31 17 36 10 5 23 48 200 23 2 1 25 19 18 17 14 13 12 6 5 4 1 0
+ 12 2 2 3 0 1 34 33 27 26 4 13 36 2 0 16 15 3 2 0 3 14 0 0 29
+ 20 38 48 200 38 38 34 33 27 26 15 14 4 3 9 12 5 3 17 16 2 13 18 2 1
+ 0 0 0 13 12 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uring" xMin="62" yMin="-37" xMax="1168" yMax="2033">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="606" y="2033" on="1"/>
+ <pt x="700" y="2033" on="0"/>
+ <pt x="766" y="1967" on="1"/>
+ <pt x="833" y="1901" on="0"/>
+ <pt x="833" y="1807" on="1"/>
+ <pt x="833" y="1710" on="0"/>
+ <pt x="766" y="1645" on="1"/>
+ <pt x="700" y="1579" on="0"/>
+ <pt x="604" y="1579" on="1"/>
+ <pt x="521" y="1579" on="0"/>
+ <pt x="459" y="1633" on="1"/>
+ <pt x="379" y="1703" on="0"/>
+ <pt x="379" y="1806" on="1"/>
+ <pt x="379" y="1900" on="0"/>
+ <pt x="446" y="1966" on="1"/>
+ <pt x="512" y="2033" on="0"/>
+ </contour>
+ <contour>
+ <pt x="606" y="1946" on="1"/>
+ <pt x="549" y="1946" on="0"/>
+ <pt x="507" y="1905" on="1"/>
+ <pt x="465" y="1865" on="0"/>
+ <pt x="465" y="1806" on="1"/>
+ <pt x="465" y="1748" on="0"/>
+ <pt x="506" y="1707" on="1"/>
+ <pt x="548" y="1665" on="0"/>
+ <pt x="604" y="1665" on="1"/>
+ <pt x="658" y="1665" on="0"/>
+ <pt x="697" y="1698" on="1"/>
+ <pt x="747" y="1741" on="0"/>
+ <pt x="747" y="1807" on="1"/>
+ <pt x="747" y="1865" on="0"/>
+ <pt x="705" y="1905" on="1"/>
+ <pt x="664" y="1946" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 100 values pushed */
+ 0 0 50 32 34 42 32 26 10 5 23 48 200 23 2 1 25 19 18 17 14 13 12 6 5
+ 4 1 0 12 2 2 3 0 34 26 2 16 15 3 2 0 3 14 0 0 54 32 30 46 32
+ 38 48 200 30 30 15 14 4 3 5 12 5 3 38 38 5 0 2 17 16 2 13 18 2 1
+ 0 0 0 13 12 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Utilde" xMin="62" yMin="-37" xMax="1168" yMax="1839">
+ <contour>
+ <pt x="185" y="1357" on="1"/>
+ <pt x="62" y="1357" on="1"/>
+ <pt x="62" y="1480" on="1"/>
+ <pt x="519" y="1480" on="1"/>
+ <pt x="519" y="1357" on="1"/>
+ <pt x="383" y="1357" on="1"/>
+ <pt x="383" y="523" on="1"/>
+ <pt x="383" y="313" on="0"/>
+ <pt x="455" y="200" on="1"/>
+ <pt x="526" y="86" on="0"/>
+ <pt x="656" y="86" on="1"/>
+ <pt x="921" y="86" on="0"/>
+ <pt x="921" y="532" on="1"/>
+ <pt x="921" y="1357" on="1"/>
+ <pt x="785" y="1357" on="1"/>
+ <pt x="785" y="1480" on="1"/>
+ <pt x="1168" y="1480" on="1"/>
+ <pt x="1168" y="1357" on="1"/>
+ <pt x="1044" y="1357" on="1"/>
+ <pt x="1044" y="496" on="1"/>
+ <pt x="1044" y="244" on="0"/>
+ <pt x="933" y="104" on="1"/>
+ <pt x="823" y="-37" on="0"/>
+ <pt x="621" y="-37" on="1"/>
+ <pt x="185" y="-37" on="0"/>
+ <pt x="185" y="550" on="1"/>
+ </contour>
+ <contour>
+ <pt x="284" y="1604" on="1"/>
+ <pt x="290" y="1699" on="0"/>
+ <pt x="315" y="1749" on="1"/>
+ <pt x="360" y="1839" on="0"/>
+ <pt x="469" y="1839" on="1"/>
+ <pt x="541" y="1839" on="0"/>
+ <pt x="604" y="1800" on="1"/>
+ <pt x="664" y="1763" on="1"/>
+ <pt x="726" y="1725" on="0"/>
+ <pt x="760" y="1725" on="1"/>
+ <pt x="828" y="1725" on="0"/>
+ <pt x="839" y="1839" on="1"/>
+ <pt x="950" y="1839" on="1"/>
+ <pt x="943" y="1745" on="0"/>
+ <pt x="918" y="1695" on="1"/>
+ <pt x="872" y="1604" on="0"/>
+ <pt x="765" y="1604" on="1"/>
+ <pt x="692" y="1604" on="0"/>
+ <pt x="629" y="1643" on="1"/>
+ <pt x="569" y="1680" on="1"/>
+ <pt x="509" y="1717" on="0"/>
+ <pt x="473" y="1717" on="1"/>
+ <pt x="405" y="1717" on="0"/>
+ <pt x="394" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 99 values pushed */
+ 0 0 47 5 30 35 5 42 10 5 23 48 200 23 2 1 25 19 18 17 14 13 12 6 5
+ 4 1 0 12 2 2 3 0 49 38 37 26 4 13 42 30 2 16 15 3 2 0 3 14 38
+ 18 12 2 49 37 15 14 4 3 6 12 5 3 26 5 0 2 17 16 2 13 18 2 1 0
+ 0 0 13 12 6 1 18 6 5 10 1 0 2 4 48 200 19 18 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="V" xMin="26" yMin="0" xMax="1204" yMax="1480">
+ <contour>
+ <pt x="520" y="0" on="1"/>
+ <pt x="100" y="1357" on="1"/>
+ <pt x="26" y="1357" on="1"/>
+ <pt x="26" y="1480" on="1"/>
+ <pt x="463" y="1480" on="1"/>
+ <pt x="463" y="1357" on="1"/>
+ <pt x="306" y="1357" on="1"/>
+ <pt x="652" y="237" on="1"/>
+ <pt x="654" y="237" on="1"/>
+ <pt x="1001" y="1357" on="1"/>
+ <pt x="858" y="1357" on="1"/>
+ <pt x="858" y="1480" on="1"/>
+ <pt x="1204" y="1480" on="1"/>
+ <pt x="1204" y="1357" on="1"/>
+ <pt x="1130" y="1357" on="1"/>
+ <pt x="709" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 8 7 2 1 0 3 0 0 14 13 10 9 6 5 2 1 6 7 3 1 4 48 200 15 0
+ 1 0 12 11 4 3 0 3 14 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="W" xMin="23" yMin="0" xMax="1207" yMax="1480">
+ <contour>
+ <pt x="242" y="0" on="1"/>
+ <pt x="72" y="1357" on="1"/>
+ <pt x="23" y="1357" on="1"/>
+ <pt x="23" y="1480" on="1"/>
+ <pt x="332" y="1480" on="1"/>
+ <pt x="332" y="1357" on="1"/>
+ <pt x="234" y="1357" on="1"/>
+ <pt x="368" y="281" on="1"/>
+ <pt x="370" y="281" on="1"/>
+ <pt x="556" y="1258" on="1"/>
+ <pt x="712" y="1258" on="1"/>
+ <pt x="896" y="285" on="1"/>
+ <pt x="899" y="285" on="1"/>
+ <pt x="1033" y="1357" on="1"/>
+ <pt x="934" y="1357" on="1"/>
+ <pt x="934" y="1480" on="1"/>
+ <pt x="1207" y="1480" on="1"/>
+ <pt x="1207" y="1357" on="1"/>
+ <pt x="1157" y="1357" on="1"/>
+ <pt x="987" y="0" on="1"/>
+ <pt x="799" y="0" on="1"/>
+ <pt x="617" y="974" on="1"/>
+ <pt x="615" y="974" on="1"/>
+ <pt x="431" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 18 17 14 13 6 5 2 1 8 3 9 3 22 21 12 11 8 7 6 9 0 3 10 9 1
+ 23 20 19 0 3 2 0 16 15 4 3 0 3 14 23 22 21 20 19 18 17 16 15 14 13
+ 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Wcircumflex" xMin="23" yMin="0" xMax="1207" yMax="1925">
+ <contour>
+ <pt x="242" y="0" on="1"/>
+ <pt x="72" y="1357" on="1"/>
+ <pt x="23" y="1357" on="1"/>
+ <pt x="23" y="1480" on="1"/>
+ <pt x="332" y="1480" on="1"/>
+ <pt x="332" y="1357" on="1"/>
+ <pt x="234" y="1357" on="1"/>
+ <pt x="368" y="281" on="1"/>
+ <pt x="370" y="281" on="1"/>
+ <pt x="556" y="1258" on="1"/>
+ <pt x="712" y="1258" on="1"/>
+ <pt x="896" y="285" on="1"/>
+ <pt x="899" y="285" on="1"/>
+ <pt x="1033" y="1357" on="1"/>
+ <pt x="934" y="1357" on="1"/>
+ <pt x="934" y="1480" on="1"/>
+ <pt x="1207" y="1480" on="1"/>
+ <pt x="1207" y="1357" on="1"/>
+ <pt x="1157" y="1357" on="1"/>
+ <pt x="987" y="0" on="1"/>
+ <pt x="799" y="0" on="1"/>
+ <pt x="617" y="974" on="1"/>
+ <pt x="615" y="974" on="1"/>
+ <pt x="431" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="267" y="1604" on="1"/>
+ <pt x="523" y="1925" on="1"/>
+ <pt x="742" y="1925" on="1"/>
+ <pt x="998" y="1604" on="1"/>
+ <pt x="875" y="1604" on="1"/>
+ <pt x="634" y="1806" on="1"/>
+ <pt x="631" y="1806" on="1"/>
+ <pt x="390" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 31 30 29 28 27 24 6 25 3 3 18 17 14 13 6 5 2 1 8 3 9 3 22 21 12
+ 11 8 7 6 9 0 3 26 25 1 10 9 1 23 20 19 0 3 3 0 16 15 4 3 0
+ 3 14 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9
+ 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="X" xMin="49" yMin="0" xMax="1179" yMax="1480">
+ <contour>
+ <pt x="49" y="0" on="1"/>
+ <pt x="49" y="123" on="1"/>
+ <pt x="160" y="123" on="1"/>
+ <pt x="510" y="730" on="1"/>
+ <pt x="148" y="1357" on="1"/>
+ <pt x="49" y="1357" on="1"/>
+ <pt x="49" y="1480" on="1"/>
+ <pt x="469" y="1480" on="1"/>
+ <pt x="469" y="1357" on="1"/>
+ <pt x="369" y="1357" on="1"/>
+ <pt x="657" y="857" on="1"/>
+ <pt x="946" y="1357" on="1"/>
+ <pt x="818" y="1357" on="1"/>
+ <pt x="818" y="1480" on="1"/>
+ <pt x="1179" y="1480" on="1"/>
+ <pt x="1179" y="1357" on="1"/>
+ <pt x="1074" y="1357" on="1"/>
+ <pt x="721" y="746" on="1"/>
+ <pt x="1081" y="123" on="1"/>
+ <pt x="1179" y="123" on="1"/>
+ <pt x="1179" y="0" on="1"/>
+ <pt x="736" y="0" on="1"/>
+ <pt x="736" y="123" on="1"/>
+ <pt x="860" y="123" on="1"/>
+ <pt x="574" y="619" on="1"/>
+ <pt x="288" y="123" on="1"/>
+ <pt x="442" y="123" on="1"/>
+ <pt x="442" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 24 17 16 15 12 11 10 9 8 5 4 3 12 6 1 3 0 0 26 25 23 22 19 18 2
+ 1 6 7 0 1 4 48 200 27 21 20 0 3 0 14 13 7 6 0 3 14 27 26 25 24
+ 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Y" xMin="27" yMin="0" xMax="1201" yMax="1480">
+ <contour>
+ <pt x="294" y="0" on="1"/>
+ <pt x="294" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="660" on="1"/>
+ <pt x="113" y="1357" on="1"/>
+ <pt x="27" y="1357" on="1"/>
+ <pt x="27" y="1480" on="1"/>
+ <pt x="490" y="1480" on="1"/>
+ <pt x="490" y="1357" on="1"/>
+ <pt x="341" y="1357" on="1"/>
+ <pt x="656" y="813" on="1"/>
+ <pt x="658" y="813" on="1"/>
+ <pt x="973" y="1357" on="1"/>
+ <pt x="825" y="1357" on="1"/>
+ <pt x="825" y="1480" on="1"/>
+ <pt x="1201" y="1480" on="1"/>
+ <pt x="1201" y="1357" on="1"/>
+ <pt x="1115" y="1357" on="1"/>
+ <pt x="713" y="661" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="935" y="123" on="1"/>
+ <pt x="935" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 18 11 10 3 4 4 1 3 0 0 17 16 13 12 9 8 5 4 6 7 6 20 19 2 1
+ 6 3 0 2 4 48 200 21 0 1 0 15 14 7 6 0 3 14 11 10 2 18 2 3 21
+ 20 17 16 15 14 13 12 8 13 18 9 8 7 6 5 4 1 0 8 13 2 0 0 19 18
+ 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Yacute" xMin="27" yMin="0" xMax="1201" yMax="1925">
+ <contour>
+ <pt x="294" y="0" on="1"/>
+ <pt x="294" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="660" on="1"/>
+ <pt x="113" y="1357" on="1"/>
+ <pt x="27" y="1357" on="1"/>
+ <pt x="27" y="1480" on="1"/>
+ <pt x="490" y="1480" on="1"/>
+ <pt x="490" y="1357" on="1"/>
+ <pt x="341" y="1357" on="1"/>
+ <pt x="656" y="813" on="1"/>
+ <pt x="658" y="813" on="1"/>
+ <pt x="973" y="1357" on="1"/>
+ <pt x="825" y="1357" on="1"/>
+ <pt x="825" y="1480" on="1"/>
+ <pt x="1201" y="1480" on="1"/>
+ <pt x="1201" y="1357" on="1"/>
+ <pt x="1115" y="1357" on="1"/>
+ <pt x="713" y="661" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="935" y="123" on="1"/>
+ <pt x="935" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="534" y="1604" on="1"/>
+ <pt x="750" y="1925" on="1"/>
+ <pt x="978" y="1925" on="1"/>
+ <pt x="657" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 100 values pushed */
+ 25 22 2 23 6 3 18 11 10 3 4 4 1 3 0 0 17 16 13 12 9 8 5 4 6
+ 7 6 20 19 2 1 6 3 0 2 4 48 200 24 23 1 21 0 1 2 0 15 14 7 6
+ 0 3 14 25 22 11 10 4 18 2 3 24 23 21 20 17 16 15 14 13 12 10 13 18 9
+ 8 7 6 5 4 1 0 8 13 2 0 0 19 18 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ycircumflex" xMin="27" yMin="0" xMax="1201" yMax="1925">
+ <contour>
+ <pt x="294" y="0" on="1"/>
+ <pt x="294" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="660" on="1"/>
+ <pt x="113" y="1357" on="1"/>
+ <pt x="27" y="1357" on="1"/>
+ <pt x="27" y="1480" on="1"/>
+ <pt x="490" y="1480" on="1"/>
+ <pt x="490" y="1357" on="1"/>
+ <pt x="341" y="1357" on="1"/>
+ <pt x="656" y="813" on="1"/>
+ <pt x="658" y="813" on="1"/>
+ <pt x="973" y="1357" on="1"/>
+ <pt x="825" y="1357" on="1"/>
+ <pt x="825" y="1480" on="1"/>
+ <pt x="1201" y="1480" on="1"/>
+ <pt x="1201" y="1357" on="1"/>
+ <pt x="1115" y="1357" on="1"/>
+ <pt x="713" y="661" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="935" y="123" on="1"/>
+ <pt x="935" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="291" y="1604" on="1"/>
+ <pt x="547" y="1925" on="1"/>
+ <pt x="766" y="1925" on="1"/>
+ <pt x="1022" y="1604" on="1"/>
+ <pt x="899" y="1604" on="1"/>
+ <pt x="658" y="1806" on="1"/>
+ <pt x="655" y="1806" on="1"/>
+ <pt x="414" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 29 28 27 26 25 22 6 23 6 3 18 11 10 3 4 4 1 3 0 0 17 16 13 12 9
+ 8 5 4 6 7 6 20 19 2 1 6 3 0 2 4 48 200 24 23 1 21 0 1 2 0
+ 15 14 7 6 0 3 14 28 27 23 11 10 5 18 2 3 26 25 24 21 20 17 16 15 14
+ 13 12 11 13 18 29 22 9 8 7 6 5 4 1 0 10 13 2 0 0 19 18 10 1 2
+ 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ydieresis" xMin="27" yMin="0" xMax="1201" yMax="1801">
+ <contour>
+ <pt x="294" y="0" on="1"/>
+ <pt x="294" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="660" on="1"/>
+ <pt x="113" y="1357" on="1"/>
+ <pt x="27" y="1357" on="1"/>
+ <pt x="27" y="1480" on="1"/>
+ <pt x="490" y="1480" on="1"/>
+ <pt x="490" y="1357" on="1"/>
+ <pt x="341" y="1357" on="1"/>
+ <pt x="656" y="813" on="1"/>
+ <pt x="658" y="813" on="1"/>
+ <pt x="973" y="1357" on="1"/>
+ <pt x="825" y="1357" on="1"/>
+ <pt x="825" y="1480" on="1"/>
+ <pt x="1201" y="1480" on="1"/>
+ <pt x="1201" y="1357" on="1"/>
+ <pt x="1115" y="1357" on="1"/>
+ <pt x="713" y="661" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="935" y="123" on="1"/>
+ <pt x="935" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="324" y="1604" on="1"/>
+ <pt x="324" y="1801" on="1"/>
+ <pt x="521" y="1801" on="1"/>
+ <pt x="521" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="793" y="1604" on="1"/>
+ <pt x="793" y="1801" on="1"/>
+ <pt x="990" y="1801" on="1"/>
+ <pt x="990" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 124 values pushed */
+ 18 11 10 3 4 4 1 3 0 0 29 26 25 22 10 3 23 17 16 13 12 9 8 5 4
+ 6 7 6 20 19 2 1 6 3 0 3 4 48 200 28 27 24 23 3 21 0 1 2 0 15
+ 14 7 6 0 3 14 21 20 14 13 12 5 28 26 3 11 10 2 18 24 3 9 8 7 3
+ 2 22 3 17 16 15 3 13 28 6 5 4 1 0 5 13 22 0 0 27 26 10 1 28 25
+ 24 10 1 22 19 18 10 1 2 3 4 48 200 29 28 1 23 22 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Z" xMin="148" yMin="0" xMax="1081" yMax="1480">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="136" on="1"/>
+ <pt x="848" y="1357" on="1"/>
+ <pt x="290" y="1357" on="1"/>
+ <pt x="290" y="1086" on="1"/>
+ <pt x="167" y="1086" on="1"/>
+ <pt x="167" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="368" y="136" on="1"/>
+ <pt x="957" y="136" on="1"/>
+ <pt x="957" y="432" on="1"/>
+ <pt x="1081" y="432" on="1"/>
+ <pt x="1081" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 12 11 5 4 4 2 1 3 0 0 8 3 2 6 2 6 10 9 1 20 2 0 2 4 48
+ 200 13 0 1 0 7 6 0 14 8 7 2 12 10 3 9 2 2 10 3 3 1 0 5 0
+ 0 11 10 6 1 12 4 3 6 1 5 2 4 48 200 13 12 1 6 5 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zacute" xMin="148" yMin="0" xMax="1081" yMax="1925">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="136" on="1"/>
+ <pt x="848" y="1357" on="1"/>
+ <pt x="290" y="1357" on="1"/>
+ <pt x="290" y="1086" on="1"/>
+ <pt x="167" y="1086" on="1"/>
+ <pt x="167" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="368" y="136" on="1"/>
+ <pt x="957" y="136" on="1"/>
+ <pt x="957" y="432" on="1"/>
+ <pt x="1081" y="432" on="1"/>
+ <pt x="1081" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="491" y="1604" on="1"/>
+ <pt x="707" y="1925" on="1"/>
+ <pt x="935" y="1925" on="1"/>
+ <pt x="614" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 17 14 2 15 6 3 12 11 5 4 4 2 1 3 0 0 8 3 2 6 2 6 10 9 1
+ 20 2 0 2 4 48 200 16 15 1 13 0 1 2 0 7 6 0 14 8 7 2 12 10 3
+ 17 16 15 14 9 2 6 10 3 3 1 0 5 0 0 11 10 6 1 12 4 3 6 1 5
+ 2 4 48 200 13 12 1 6 5 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zcaron" xMin="148" yMin="0" xMax="1081" yMax="1925">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="136" on="1"/>
+ <pt x="848" y="1357" on="1"/>
+ <pt x="290" y="1357" on="1"/>
+ <pt x="290" y="1086" on="1"/>
+ <pt x="167" y="1086" on="1"/>
+ <pt x="167" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="368" y="136" on="1"/>
+ <pt x="957" y="136" on="1"/>
+ <pt x="957" y="432" on="1"/>
+ <pt x="1081" y="432" on="1"/>
+ <pt x="1081" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="980" y="1925" on="1"/>
+ <pt x="723" y="1604" on="1"/>
+ <pt x="505" y="1604" on="1"/>
+ <pt x="248" y="1925" on="1"/>
+ <pt x="372" y="1925" on="1"/>
+ <pt x="613" y="1723" on="1"/>
+ <pt x="615" y="1723" on="1"/>
+ <pt x="857" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 12 11 5 4 4 2 1 3 21 20 19 18 17 14 6 13 15 0 0 8 3 2 6 2 6
+ 10 9 1 20 2 0 2 4 48 200 16 15 1 13 0 1 2 0 7 6 0 14 14 8 7
+ 3 12 10 3 21 20 19 18 16 15 9 2 8 10 3 3 17 3 5 2 1 0 5 0 0
+ 11 10 6 1 12 4 3 6 1 5 2 4 48 200 13 12 1 6 5 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zdotaccent" xMin="148" yMin="0" xMax="1081" yMax="1801">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="136" on="1"/>
+ <pt x="848" y="1357" on="1"/>
+ <pt x="290" y="1357" on="1"/>
+ <pt x="290" y="1086" on="1"/>
+ <pt x="167" y="1086" on="1"/>
+ <pt x="167" y="1480" on="1"/>
+ <pt x="1068" y="1480" on="1"/>
+ <pt x="1068" y="1357" on="1"/>
+ <pt x="368" y="136" on="1"/>
+ <pt x="957" y="136" on="1"/>
+ <pt x="957" y="432" on="1"/>
+ <pt x="1081" y="432" on="1"/>
+ <pt x="1081" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="516" y="1604" on="1"/>
+ <pt x="516" y="1801" on="1"/>
+ <pt x="713" y="1801" on="1"/>
+ <pt x="713" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 12 11 5 4 4 2 1 3 0 0 17 14 10 1 15 8 3 2 6 2 6 10 9 1 20
+ 2 0 3 4 48 200 16 15 1 13 0 1 2 0 7 6 0 14 8 7 2 12 10 3 2
+ 10 16 2 9 14 3 2 1 0 5 0 0 17 16 10 1 14 11 10 6 1 12 4 3 6
+ 1 5 3 4 48 200 15 14 1 13 12 1 6 5 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="a" xMin="148" yMin="-25" xMax="1167" yMax="1111">
+ <contour>
+ <pt x="834" y="119" on="1"/>
+ <pt x="661" y="-25" on="0"/>
+ <pt x="483" y="-25" on="1"/>
+ <pt x="330" y="-25" on="0"/>
+ <pt x="239" y="61" on="1"/>
+ <pt x="148" y="146" on="0"/>
+ <pt x="148" y="293" on="1"/>
+ <pt x="148" y="483" on="0"/>
+ <pt x="290" y="569" on="1"/>
+ <pt x="432" y="654" on="0"/>
+ <pt x="749" y="654" on="1"/>
+ <pt x="834" y="654" on="1"/>
+ <pt x="834" y="822" on="1"/>
+ <pt x="834" y="987" on="0"/>
+ <pt x="630" y="987" on="1"/>
+ <pt x="527" y="987" on="0"/>
+ <pt x="373" y="929" on="1"/>
+ <pt x="348" y="802" on="1"/>
+ <pt x="225" y="802" on="1"/>
+ <pt x="225" y="1018" on="1"/>
+ <pt x="454" y="1111" on="0"/>
+ <pt x="692" y="1111" on="1"/>
+ <pt x="881" y="1111" on="0"/>
+ <pt x="956" y="1046" on="1"/>
+ <pt x="1031" y="980" on="0"/>
+ <pt x="1031" y="819" on="1"/>
+ <pt x="1031" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="854" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="834" y="278" on="1"/>
+ <pt x="834" y="531" on="1"/>
+ <pt x="781" y="531" on="1"/>
+ <pt x="551" y="531" on="0"/>
+ <pt x="454" y="479" on="1"/>
+ <pt x="358" y="427" on="0"/>
+ <pt x="358" y="301" on="1"/>
+ <pt x="358" y="123" on="0"/>
+ <pt x="544" y="123" on="1"/>
+ <pt x="691" y="123" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 38 14 2 14 5 21 48 200 21 1 2 2 1 32 31 30 27 26 25 19 18 17 16
+ 12 11 10 0 14 1 28 3 0 29 28 1 0 14 0 0 36 39 6 48 200 29 25 0 2
+ 32 17 16 10 4 0 18 3 28 27 2 13 25 6 18 0 0 31 30 12 11 0 10 4 25
+ 1 4 48 200 26 25 1 19 18 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="aacute" xMin="148" yMin="-25" xMax="1167" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="160" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="abreve" xMin="148" yMin="-25" xMax="1167" yMax="1579">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="breve" x="12" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="acircumflex" xMin="148" yMin="-25" xMax="1167" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="27" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="acute" xMin="392" yMin="1283" xMax="836" yMax="1604">
+ <contour>
+ <pt x="392" y="1283" on="1"/>
+ <pt x="608" y="1604" on="1"/>
+ <pt x="836" y="1604" on="1"/>
+ <pt x="515" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 12 values pushed */
+ 3 0 1 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="adieresis" xMin="148" yMin="-25" xMax="1167" yMax="1480">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="35" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ae" xMin="37" yMin="-25" xMax="1192" yMax="1110">
+ <contour>
+ <pt x="589" y="154" on="1"/>
+ <pt x="552" y="73" on="0"/>
+ <pt x="508" y="33" on="1"/>
+ <pt x="443" y="-25" on="0"/>
+ <pt x="347" y="-25" on="1"/>
+ <pt x="216" y="-25" on="0"/>
+ <pt x="127" y="70" on="1"/>
+ <pt x="37" y="164" on="0"/>
+ <pt x="37" y="307" on="1"/>
+ <pt x="37" y="475" on="0"/>
+ <pt x="154" y="571" on="1"/>
+ <pt x="270" y="666" on="0"/>
+ <pt x="476" y="666" on="1"/>
+ <pt x="519" y="666" on="1"/>
+ <pt x="519" y="807" on="1"/>
+ <pt x="519" y="917" on="0"/>
+ <pt x="498" y="952" on="1"/>
+ <pt x="476" y="987" on="0"/>
+ <pt x="408" y="987" on="1"/>
+ <pt x="345" y="987" on="0"/>
+ <pt x="284" y="947" on="1"/>
+ <pt x="259" y="811" on="1"/>
+ <pt x="136" y="811" on="1"/>
+ <pt x="136" y="1043" on="1"/>
+ <pt x="289" y="1110" on="0"/>
+ <pt x="434" y="1110" on="1"/>
+ <pt x="531" y="1110" on="0"/>
+ <pt x="592" y="1062" on="1"/>
+ <pt x="628" y="1033" on="0"/>
+ <pt x="658" y="979" on="1"/>
+ <pt x="736" y="1110" on="0"/>
+ <pt x="879" y="1110" on="1"/>
+ <pt x="1025" y="1110" on="0"/>
+ <pt x="1106" y="974" on="1"/>
+ <pt x="1186" y="838" on="0"/>
+ <pt x="1186" y="592" on="1"/>
+ <pt x="1186" y="543" on="1"/>
+ <pt x="704" y="543" on="1"/>
+ <pt x="707" y="492" on="1"/>
+ <pt x="729" y="123" on="0"/>
+ <pt x="948" y="123" on="1"/>
+ <pt x="1032" y="123" on="0"/>
+ <pt x="1192" y="191" on="1"/>
+ <pt x="1192" y="43" on="1"/>
+ <pt x="1016" y="-25" on="0"/>
+ <pt x="885" y="-25" on="1"/>
+ <pt x="719" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="519" y="228" on="1"/>
+ <pt x="519" y="543" on="1"/>
+ <pt x="488" y="543" on="1"/>
+ <pt x="241" y="543" on="0"/>
+ <pt x="241" y="315" on="1"/>
+ <pt x="241" y="136" on="0"/>
+ <pt x="382" y="136" on="1"/>
+ <pt x="467" y="136" on="0"/>
+ </contour>
+ <contour>
+ <pt x="704" y="666" on="1"/>
+ <pt x="984" y="666" on="1"/>
+ <pt x="981" y="844" on="0"/>
+ <pt x="949" y="916" on="1"/>
+ <pt x="918" y="987" on="0"/>
+ <pt x="859" y="987" on="1"/>
+ <pt x="725" y="987" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 111 values pushed */
+ 0 0 60 5 31 53 30 4 40 14 45 18 5 25 48 200 45 2 31 1 25 1 4 2 1
+ 29 23 22 21 20 14 6 1 12 3 0 35 12 36 2 1 47 43 42 0 4 36 2 3 0
+ 0 0 49 48 37 36 6 3 12 1 4 48 200 56 55 13 12 3 0 14 0 0 51 24 8
+ 48 200 56 55 37 36 35 29 0 7 42 13 3 49 21 20 12 4 13 22 3 8 22 43 42
+ 1 48 47 14 13 3 23 22 1 3 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="afii00208" xMin="0" yMin="543" xMax="1229" yMax="666">
+ <contour>
+ <pt x="0" y="543" on="1"/>
+ <pt x="0" y="666" on="1"/>
+ <pt x="1229" y="666" on="1"/>
+ <pt x="1229" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 200 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="agrave" xMin="148" yMin="-25" xMax="1167" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="-38" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="amacron" xMin="148" yMin="-25" xMax="1167" yMax="1407">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="22" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ampersand" xMin="57" yMin="-37" xMax="1192" yMax="1518">
+ <contour>
+ <pt x="928" y="0" on="1"/>
+ <pt x="834" y="110" on="1"/>
+ <pt x="653" y="-37" on="0"/>
+ <pt x="478" y="-37" on="1"/>
+ <pt x="290" y="-37" on="0"/>
+ <pt x="174" y="88" on="1"/>
+ <pt x="57" y="213" on="0"/>
+ <pt x="57" y="413" on="1"/>
+ <pt x="57" y="591" on="0"/>
+ <pt x="164" y="728" on="1"/>
+ <pt x="226" y="808" on="0"/>
+ <pt x="345" y="889" on="1"/>
+ <pt x="273" y="1056" on="0"/>
+ <pt x="273" y="1188" on="1"/>
+ <pt x="273" y="1340" on="0"/>
+ <pt x="357" y="1429" on="1"/>
+ <pt x="441" y="1518" on="0"/>
+ <pt x="588" y="1518" on="1"/>
+ <pt x="740" y="1518" on="0"/>
+ <pt x="814" y="1436" on="1"/>
+ <pt x="878" y="1365" on="0"/>
+ <pt x="878" y="1240" on="1"/>
+ <pt x="878" y="1095" on="0"/>
+ <pt x="767" y="979" on="1"/>
+ <pt x="700" y="909" on="0"/>
+ <pt x="572" y="836" on="1"/>
+ <pt x="745" y="504" on="0"/>
+ <pt x="879" y="332" on="1"/>
+ <pt x="968" y="451" on="0"/>
+ <pt x="969" y="632" on="1"/>
+ <pt x="967" y="691" on="1"/>
+ <pt x="868" y="691" on="1"/>
+ <pt x="868" y="814" on="1"/>
+ <pt x="1192" y="814" on="1"/>
+ <pt x="1192" y="691" on="1"/>
+ <pt x="1120" y="691" on="1"/>
+ <pt x="1111" y="527" on="0"/>
+ <pt x="1079" y="440" on="1"/>
+ <pt x="1048" y="352" on="0"/>
+ <pt x="958" y="240" on="1"/>
+ <pt x="1068" y="123" on="1"/>
+ <pt x="1192" y="123" on="1"/>
+ <pt x="1192" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="757" y="208" on="1"/>
+ <pt x="580" y="433" on="0"/>
+ <pt x="405" y="785" on="1"/>
+ <pt x="236" y="654" on="0"/>
+ <pt x="236" y="441" on="1"/>
+ <pt x="236" y="287" on="0"/>
+ <pt x="311" y="199" on="1"/>
+ <pt x="386" y="110" on="0"/>
+ <pt x="515" y="110" on="1"/>
+ <pt x="639" y="110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="518" y="938" on="1"/>
+ <pt x="599" y="992" on="0"/>
+ <pt x="640" y="1047" on="1"/>
+ <pt x="699" y="1127" on="0"/>
+ <pt x="699" y="1232" on="1"/>
+ <pt x="699" y="1394" on="0"/>
+ <pt x="584" y="1394" on="1"/>
+ <pt x="452" y="1394" on="0"/>
+ <pt x="452" y="1198" on="1"/>
+ <pt x="452" y="1059" on="0"/>
+ <pt x="511" y="950" on="1"/>
+ <pt x="513" y="946" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 59 5 17 51 14 3 48 200 17 0 3 2 1 53 25 11 3 0 32 3 0 45 43
+ 41 40 39 35 34 31 30 29 27 1 12 32 0 3 33 32 1 42 0 1 2 0 14 0 0
+ 61 13 13 57 13 21 47 13 7 48 200 53 45 43 42 41 40 39 35 34 33 32 31 30 29
+ 27 25 21 13 11 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="anoteleia" xMin="491" yMin="419" xMax="738" yMax="666">
+ <contour>
+ <pt x="491" y="419" on="1"/>
+ <pt x="491" y="666" on="1"/>
+ <pt x="738" y="666" on="1"/>
+ <pt x="738" y="419" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 2 1 4 1 0 1 4 48 200 3 0 1 0 14 0 0 3 2 4 1 0 1 4
+ 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="aogonek" xMin="148" yMin="-370" xMax="1167" yMax="1111">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="282" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="aring" xMin="148" yMin="-25" xMax="1167" yMax="1737">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="ring" x="61" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="asciicircum" xMin="146" yMin="543" xMax="1084" yMax="1480">
+ <contour>
+ <pt x="146" y="543" on="1"/>
+ <pt x="615" y="1480" on="1"/>
+ <pt x="1084" y="543" on="1"/>
+ <pt x="918" y="543" on="1"/>
+ <pt x="615" y="1149" on="1"/>
+ <pt x="311" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 18 values pushed */
+ 4 1 2 13 0 5 3 2 0 3 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="asciitilde" xMin="121" yMin="412" xMax="1108" yMax="772">
+ <contour>
+ <pt x="269" y="444" on="1"/>
+ <pt x="121" y="444" on="1"/>
+ <pt x="124" y="550" on="0"/>
+ <pt x="143" y="605" on="1"/>
+ <pt x="201" y="772" on="0"/>
+ <pt x="386" y="772" on="1"/>
+ <pt x="484" y="772" on="0"/>
+ <pt x="585" y="703" on="1"/>
+ <pt x="697" y="626" on="1"/>
+ <pt x="764" y="580" on="1"/>
+ <pt x="793" y="560" on="0"/>
+ <pt x="839" y="560" on="1"/>
+ <pt x="956" y="560" on="0"/>
+ <pt x="960" y="740" on="1"/>
+ <pt x="1108" y="740" on="1"/>
+ <pt x="1105" y="634" on="0"/>
+ <pt x="1086" y="579" on="1"/>
+ <pt x="1028" y="412" on="0"/>
+ <pt x="843" y="412" on="1"/>
+ <pt x="744" y="412" on="0"/>
+ <pt x="644" y="481" on="1"/>
+ <pt x="532" y="558" on="1"/>
+ <pt x="465" y="604" on="1"/>
+ <pt x="436" y="624" on="0"/>
+ <pt x="389" y="624" on="1"/>
+ <pt x="273" y="624" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 24 16 5 11 16 18 48 200 5 13 18 0 14 13 1 1 0 1 2 0 14 14 13
+ 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="asterisk" xMin="161" yMin="614" xMax="1068" yMax="1480">
+ <contour>
+ <pt x="459" y="615" on="1"/>
+ <pt x="288" y="720" on="1"/>
+ <pt x="523" y="991" on="1"/>
+ <pt x="545" y="951" on="0"/>
+ <pt x="599" y="937" on="1"/>
+ </contour>
+ <contour>
+ <pt x="161" y="1073" on="1"/>
+ <pt x="219" y="1263" on="1"/>
+ <pt x="541" y="1112" on="1"/>
+ <pt x="511" y="1080" on="0"/>
+ <pt x="511" y="1044" on="1"/>
+ <pt x="511" y="1036" on="0"/>
+ <pt x="513" y="1021" on="1"/>
+ </contour>
+ <contour>
+ <pt x="563" y="1129" on="1"/>
+ <pt x="518" y="1480" on="1"/>
+ <pt x="715" y="1480" on="1"/>
+ <pt x="664" y="1129" on="1"/>
+ <pt x="629" y="1142" on="0"/>
+ <pt x="614" y="1142" on="1"/>
+ <pt x="597" y="1142" on="0"/>
+ </contour>
+ <contour>
+ <pt x="687" y="1111" on="1"/>
+ <pt x="1011" y="1264" on="1"/>
+ <pt x="1068" y="1071" on="1"/>
+ <pt x="716" y="1023" on="1"/>
+ <pt x="716" y="1026" on="0"/>
+ <pt x="717" y="1031" on="1"/>
+ <pt x="717" y="1034" on="1"/>
+ <pt x="717" y="1037" on="1"/>
+ <pt x="717" y="1081" on="0"/>
+ </contour>
+ <contour>
+ <pt x="783" y="614" on="1"/>
+ <pt x="622" y="936" on="1"/>
+ <pt x="673" y="942" on="0"/>
+ <pt x="702" y="986" on="1"/>
+ <pt x="946" y="728" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 17 1 32 31 29 28 26 25 24 22 21 20 19 17 15 12 11 7 6 5 4 2 1 0 22
+ 13 2 3 0 14 13 0 14 32 31 29 28 26 25 24 22 21 20 19 15 14 13 12 11 9
+ 7 6 5 4 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="at" xMin="87" yMin="-37" xMax="1186" yMax="1517">
+ <contour>
+ <pt x="945" y="12" on="1"/>
+ <pt x="794" y="-37" on="0"/>
+ <pt x="691" y="-37" on="1"/>
+ <pt x="415" y="-37" on="0"/>
+ <pt x="251" y="166" on="1"/>
+ <pt x="87" y="369" on="0"/>
+ <pt x="87" y="719" on="1"/>
+ <pt x="87" y="1074" on="0"/>
+ <pt x="249" y="1296" on="1"/>
+ <pt x="411" y="1517" on="0"/>
+ <pt x="675" y="1517" on="1"/>
+ <pt x="1068" y="1517" on="0"/>
+ <pt x="1068" y="1042" on="1"/>
+ <pt x="1068" y="414" on="1"/>
+ <pt x="1186" y="414" on="1"/>
+ <pt x="1186" y="291" on="1"/>
+ <pt x="945" y="291" on="1"/>
+ <pt x="945" y="658" on="1"/>
+ <pt x="920" y="658" on="1"/>
+ <pt x="882" y="499" on="0"/>
+ <pt x="816" y="406" on="1"/>
+ <pt x="730" y="284" on="0"/>
+ <pt x="621" y="284" on="1"/>
+ <pt x="517" y="284" on="0"/>
+ <pt x="451" y="388" on="1"/>
+ <pt x="384" y="492" on="0"/>
+ <pt x="384" y="654" on="1"/>
+ <pt x="384" y="873" on="0"/>
+ <pt x="498" y="1025" on="1"/>
+ <pt x="612" y="1178" on="0"/>
+ <pt x="776" y="1178" on="1"/>
+ <pt x="840" y="1178" on="0"/>
+ <pt x="936" y="1152" on="1"/>
+ <pt x="907" y="1287" on="0"/>
+ <pt x="833" y="1343" on="1"/>
+ <pt x="767" y="1394" on="0"/>
+ <pt x="663" y="1394" on="1"/>
+ <pt x="459" y="1394" on="0"/>
+ <pt x="335" y="1212" on="1"/>
+ <pt x="210" y="1029" on="0"/>
+ <pt x="210" y="733" on="1"/>
+ <pt x="210" y="436" on="0"/>
+ <pt x="343" y="261" on="1"/>
+ <pt x="475" y="86" on="0"/>
+ <pt x="694" y="86" on="1"/>
+ <pt x="811" y="86" on="0"/>
+ <pt x="945" y="150" on="1"/>
+ </contour>
+ <contour>
+ <pt x="945" y="927" on="1"/>
+ <pt x="945" y="1038" on="1"/>
+ <pt x="862" y="1086" on="0"/>
+ <pt x="794" y="1086" on="1"/>
+ <pt x="673" y="1086" on="0"/>
+ <pt x="603" y="974" on="1"/>
+ <pt x="532" y="862" on="0"/>
+ <pt x="532" y="674" on="1"/>
+ <pt x="532" y="565" on="0"/>
+ <pt x="563" y="495" on="1"/>
+ <pt x="593" y="426" on="0"/>
+ <pt x="639" y="426" on="1"/>
+ <pt x="709" y="426" on="0"/>
+ <pt x="783" y="551" on="1"/>
+ <pt x="855" y="672" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 0 0 58 14 22 50 17 30 44 5 2 36 5 10 48 200 10 0 2 2 30 1 48 47 32
+ 30 18 17 14 13 12 9 0 15 3 0 22 1 46 22 0 3 15 2 3 0 16 15 1 0
+ 14 0 0 54 16 26 40 6 6 48 200 15 14 2 13 12 32 18 26 6 0 0 0 48 47
+ 46 17 16 0 6 5 12 1 4 48 200 13 12 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="atilde" xMin="148" yMin="-25" xMax="1167" yMax="1518">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="22" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="b" xMin="62" yMin="-25" xMax="1118" yMax="1579">
+ <contour>
+ <pt x="383" y="0" on="1"/>
+ <pt x="185" y="0" on="1"/>
+ <pt x="185" y="1456" on="1"/>
+ <pt x="62" y="1456" on="1"/>
+ <pt x="62" y="1579" on="1"/>
+ <pt x="383" y="1579" on="1"/>
+ <pt x="383" y="864" on="1"/>
+ <pt x="458" y="975" on="0"/>
+ <pt x="529" y="1030" on="1"/>
+ <pt x="631" y="1110" on="0"/>
+ <pt x="749" y="1110" on="1"/>
+ <pt x="914" y="1110" on="0"/>
+ <pt x="1016" y="967" on="1"/>
+ <pt x="1118" y="823" on="0"/>
+ <pt x="1118" y="588" on="1"/>
+ <pt x="1118" y="302" on="0"/>
+ <pt x="983" y="139" on="1"/>
+ <pt x="849" y="-25" on="0"/>
+ <pt x="614" y="-25" on="1"/>
+ <pt x="526" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="383" y="146" on="1"/>
+ <pt x="519" y="123" on="0"/>
+ <pt x="595" y="123" on="1"/>
+ <pt x="762" y="123" on="0"/>
+ <pt x="835" y="230" on="1"/>
+ <pt x="908" y="337" on="0"/>
+ <pt x="908" y="578" on="1"/>
+ <pt x="908" y="950" on="0"/>
+ <pt x="694" y="950" on="1"/>
+ <pt x="530" y="950" on="0"/>
+ <pt x="383" y="716" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 28 30 10 22 14 18 48 200 18 2 10 1 1 3 2 2 4 1 3 0 1 30 20
+ 6 3 1 0 3 0 5 4 1 1 0 1 2 0 14 0 0 26 39 14 48 200 14 0 4
+ 3 1 0 0 30 20 6 5 0 10 4 1 1 4 48 200 2 1 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="backslash" xMin="99" yMin="-296" xMax="1131" yMax="1579">
+ <contour>
+ <pt x="1131" y="-296" on="1"/>
+ <pt x="967" y="-296" on="1"/>
+ <pt x="99" y="1579" on="1"/>
+ <pt x="262" y="1579" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 3 2 1 1 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bar" xMin="540" yMin="-296" xMax="688" yMax="1579">
+ <contour>
+ <pt x="540" y="-296" on="1"/>
+ <pt x="540" y="1579" on="1"/>
+ <pt x="688" y="1579" on="1"/>
+ <pt x="688" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 2 1 1 3 0 1 2 0 14 0 0 3 2 16 1 0 1 4 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="braceleft" xMin="183" yMin="-296" xMax="1002" yMax="1579">
+ <contour>
+ <pt x="1002" y="-296" on="1"/>
+ <pt x="871" y="-296" on="1"/>
+ <pt x="699" y="-296" on="0"/>
+ <pt x="590" y="-201" on="1"/>
+ <pt x="480" y="-106" on="0"/>
+ <pt x="480" y="47" on="1"/>
+ <pt x="480" y="100" on="0"/>
+ <pt x="493" y="176" on="1"/>
+ <pt x="514" y="297" on="1"/>
+ <pt x="522" y="344" on="0"/>
+ <pt x="522" y="387" on="1"/>
+ <pt x="522" y="580" on="0"/>
+ <pt x="295" y="580" on="1"/>
+ <pt x="183" y="580" on="1"/>
+ <pt x="183" y="703" on="1"/>
+ <pt x="295" y="703" on="1"/>
+ <pt x="522" y="703" on="0"/>
+ <pt x="522" y="900" on="1"/>
+ <pt x="522" y="939" on="0"/>
+ <pt x="514" y="986" on="1"/>
+ <pt x="493" y="1107" on="1"/>
+ <pt x="480" y="1183" on="0"/>
+ <pt x="480" y="1241" on="1"/>
+ <pt x="480" y="1390" on="0"/>
+ <pt x="591" y="1485" on="1"/>
+ <pt x="701" y="1579" on="0"/>
+ <pt x="871" y="1579" on="1"/>
+ <pt x="1002" y="1579" on="1"/>
+ <pt x="1002" y="1456" on="1"/>
+ <pt x="943" y="1456" on="1"/>
+ <pt x="665" y="1456" on="0"/>
+ <pt x="665" y="1249" on="1"/>
+ <pt x="665" y="1209" on="0"/>
+ <pt x="673" y="1163" on="1"/>
+ <pt x="695" y="1038" on="1"/>
+ <pt x="703" y="992" on="0"/>
+ <pt x="703" y="954" on="1"/>
+ <pt x="703" y="825" on="0"/>
+ <pt x="625" y="737" on="1"/>
+ <pt x="579" y="686" on="0"/>
+ <pt x="493" y="642" on="1"/>
+ <pt x="587" y="594" on="0"/>
+ <pt x="634" y="536" on="1"/>
+ <pt x="702" y="451" on="0"/>
+ <pt x="702" y="326" on="1"/>
+ <pt x="702" y="285" on="0"/>
+ <pt x="695" y="245" on="1"/>
+ <pt x="673" y="120" on="1"/>
+ <pt x="665" y="74" on="0"/>
+ <pt x="665" y="29" on="1"/>
+ <pt x="665" y="-173" on="0"/>
+ <pt x="943" y="-173" on="1"/>
+ <pt x="1002" y="-173" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 52 51 40 29 28 27 26 15 14 13 12 1 0 14 0 0 49 19 5 31 19 22 17 13 36
+ 10 13 44 48 200 52 51 44 40 36 29 28 27 26 22 15 14 13 12 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="braceright" xMin="227" yMin="-296" xMax="1046" yMax="1579">
+ <contour>
+ <pt x="227" y="1579" on="1"/>
+ <pt x="358" y="1579" on="1"/>
+ <pt x="530" y="1579" on="0"/>
+ <pt x="639" y="1484" on="1"/>
+ <pt x="749" y="1388" on="0"/>
+ <pt x="749" y="1237" on="1"/>
+ <pt x="749" y="1182" on="0"/>
+ <pt x="736" y="1107" on="1"/>
+ <pt x="715" y="986" on="1"/>
+ <pt x="707" y="940" on="0"/>
+ <pt x="707" y="896" on="1"/>
+ <pt x="707" y="703" on="0"/>
+ <pt x="934" y="703" on="1"/>
+ <pt x="1046" y="703" on="1"/>
+ <pt x="1046" y="580" on="1"/>
+ <pt x="934" y="580" on="1"/>
+ <pt x="707" y="580" on="0"/>
+ <pt x="707" y="383" on="1"/>
+ <pt x="707" y="342" on="0"/>
+ <pt x="715" y="297" on="1"/>
+ <pt x="736" y="177" on="1"/>
+ <pt x="749" y="103" on="0"/>
+ <pt x="749" y="42" on="1"/>
+ <pt x="749" y="-106" on="0"/>
+ <pt x="638" y="-201" on="1"/>
+ <pt x="528" y="-296" on="0"/>
+ <pt x="358" y="-296" on="1"/>
+ <pt x="227" y="-296" on="1"/>
+ <pt x="227" y="-173" on="1"/>
+ <pt x="286" y="-173" on="1"/>
+ <pt x="564" y="-173" on="0"/>
+ <pt x="564" y="33" on="1"/>
+ <pt x="564" y="75" on="0"/>
+ <pt x="556" y="120" on="1"/>
+ <pt x="534" y="245" on="1"/>
+ <pt x="527" y="285" on="0"/>
+ <pt x="527" y="330" on="1"/>
+ <pt x="527" y="458" on="0"/>
+ <pt x="604" y="546" on="1"/>
+ <pt x="649" y="597" on="0"/>
+ <pt x="736" y="642" on="1"/>
+ <pt x="643" y="690" on="0"/>
+ <pt x="596" y="748" on="1"/>
+ <pt x="527" y="833" on="0"/>
+ <pt x="527" y="957" on="1"/>
+ <pt x="527" y="998" on="0"/>
+ <pt x="534" y="1038" on="1"/>
+ <pt x="556" y="1163" on="1"/>
+ <pt x="564" y="1208" on="0"/>
+ <pt x="564" y="1254" on="1"/>
+ <pt x="564" y="1456" on="0"/>
+ <pt x="286" y="1456" on="1"/>
+ <pt x="227" y="1456" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 52 51 40 29 28 27 26 15 14 13 12 1 0 14 0 0 49 19 5 31 19 22 17 13 36
+ 10 13 44 48 200 52 51 44 40 36 29 28 27 26 22 15 14 13 12 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bracketleft" xMin="395" yMin="-296" xMax="938" yMax="1579">
+ <contour>
+ <pt x="395" y="-296" on="1"/>
+ <pt x="395" y="1579" on="1"/>
+ <pt x="938" y="1579" on="1"/>
+ <pt x="938" y="1456" on="1"/>
+ <pt x="568" y="1456" on="1"/>
+ <pt x="568" y="-173" on="1"/>
+ <pt x="938" y="-173" on="1"/>
+ <pt x="938" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 4 3 6 1 1 6 5 6 1 0 2 4 48 200 2 1 1 7 0 1 2 0 14
+ 7 6 3 2 4 13 4 0 0 5 4 12 1 0 1 4 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bracketright" xMin="291" yMin="-296" xMax="834" yMax="1579">
+ <contour>
+ <pt x="834" y="-296" on="1"/>
+ <pt x="291" y="-296" on="1"/>
+ <pt x="291" y="-173" on="1"/>
+ <pt x="661" y="-173" on="1"/>
+ <pt x="661" y="1456" on="1"/>
+ <pt x="291" y="1456" on="1"/>
+ <pt x="291" y="1579" on="1"/>
+ <pt x="834" y="1579" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 5 4 6 1 6 3 2 6 1 0 2 4 48 200 7 6 1 1 0 1 2 0 14
+ 6 5 2 1 4 13 3 0 0 4 3 12 1 0 1 4 48 200 7 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="breve" xMin="269" yMin="1289" xMax="960" yMax="1579">
+ <contour>
+ <pt x="269" y="1579" on="1"/>
+ <pt x="392" y="1579" on="1"/>
+ <pt x="440" y="1431" on="0"/>
+ <pt x="614" y="1431" on="1"/>
+ <pt x="789" y="1431" on="0"/>
+ <pt x="837" y="1579" on="1"/>
+ <pt x="960" y="1579" on="1"/>
+ <pt x="937" y="1490" on="0"/>
+ <pt x="911" y="1444" on="1"/>
+ <pt x="820" y="1289" on="0"/>
+ <pt x="618" y="1289" on="1"/>
+ <pt x="466" y="1289" on="0"/>
+ <pt x="377" y="1370" on="1"/>
+ <pt x="322" y="1419" on="0"/>
+ <pt x="294" y="1491" on="1"/>
+ <pt x="283" y="1520" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 0 0 3 14 10 48 200 10 6 5 1 0 14 6 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="brokenbar" xMin="540" yMin="-296" xMax="688" yMax="1579">
+ <contour>
+ <pt x="540" y="-296" on="1"/>
+ <pt x="540" y="444" on="1"/>
+ <pt x="688" y="444" on="1"/>
+ <pt x="688" y="-296" on="1"/>
+ </contour>
+ <contour>
+ <pt x="540" y="839" on="1"/>
+ <pt x="540" y="1579" on="1"/>
+ <pt x="688" y="1579" on="1"/>
+ <pt x="688" y="839" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 34 values pushed */
+ 6 5 1 7 4 1 2 1 1 3 0 1 4 0 14 0 0 7 6 3 2 16 3 0 1
+ 4 48 200 5 4 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bullet" xMin="318" yMin="518" xMax="910" yMax="1110">
+ <contour>
+ <pt x="614" y="1110" on="1"/>
+ <pt x="737" y="1110" on="0"/>
+ <pt x="823" y="1023" on="1"/>
+ <pt x="910" y="937" on="0"/>
+ <pt x="910" y="815" on="1"/>
+ <pt x="910" y="690" on="0"/>
+ <pt x="823" y="604" on="1"/>
+ <pt x="737" y="518" on="0"/>
+ <pt x="612" y="518" on="1"/>
+ <pt x="503" y="518" on="0"/>
+ <pt x="423" y="588" on="1"/>
+ <pt x="318" y="679" on="0"/>
+ <pt x="318" y="814" on="1"/>
+ <pt x="318" y="937" on="0"/>
+ <pt x="405" y="1023" on="1"/>
+ <pt x="492" y="1110" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 0 0 0 8 48 200 8 14 0 0 4 12 48 200 12
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="c" xMin="148" yMin="-25" xMax="1031" yMax="1110">
+ <contour>
+ <pt x="1031" y="46" on="1"/>
+ <pt x="883" y="-25" on="0"/>
+ <pt x="693" y="-25" on="1"/>
+ <pt x="441" y="-25" on="0"/>
+ <pt x="294" y="133" on="1"/>
+ <pt x="148" y="291" on="0"/>
+ <pt x="148" y="555" on="1"/>
+ <pt x="148" y="815" on="0"/>
+ <pt x="291" y="962" on="1"/>
+ <pt x="434" y="1110" on="0"/>
+ <pt x="690" y="1110" on="1"/>
+ <pt x="862" y="1110" on="0"/>
+ <pt x="1019" y="1056" on="1"/>
+ <pt x="1019" y="711" on="1"/>
+ <pt x="895" y="711" on="1"/>
+ <pt x="863" y="943" on="1"/>
+ <pt x="753" y="987" on="0"/>
+ <pt x="680" y="987" on="1"/>
+ <pt x="534" y="987" on="0"/>
+ <pt x="448" y="869" on="1"/>
+ <pt x="361" y="751" on="0"/>
+ <pt x="361" y="552" on="1"/>
+ <pt x="361" y="349" on="0"/>
+ <pt x="459" y="236" on="1"/>
+ <pt x="556" y="123" on="0"/>
+ <pt x="729" y="123" on="1"/>
+ <pt x="866" y="123" on="0"/>
+ <pt x="1031" y="200" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 0 0 25 14 2 17 5 10 48 200 10 1 2 2 1 1 27 15 14 13 12 0 6 1 2
+ 3 0 0 14 0 0 21 39 6 48 200 15 14 6 12 27 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cacute" xMin="148" yMin="-25" xMax="1031" yMax="1604">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="164" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="caron" xMin="248" yMin="1283" xMax="980" yMax="1604">
+ <contour>
+ <pt x="980" y="1604" on="1"/>
+ <pt x="723" y="1283" on="1"/>
+ <pt x="505" y="1283" on="1"/>
+ <pt x="248" y="1604" on="1"/>
+ <pt x="372" y="1604" on="1"/>
+ <pt x="613" y="1402" on="1"/>
+ <pt x="615" y="1402" on="1"/>
+ <pt x="857" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 7 6 5 4 3 0 6 13 1 2 1 1 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ccaron" xMin="148" yMin="-25" xMax="1046" yMax="1604">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="66" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ccedilla" xMin="148" yMin="-432" xMax="1031" yMax="1110">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="cedilla" x="53" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ccircumflex" xMin="148" yMin="-25" xMax="1045" yMax="1604">
+ <contour>
+ <pt x="1031" y="46" on="1"/>
+ <pt x="883" y="-25" on="0"/>
+ <pt x="693" y="-25" on="1"/>
+ <pt x="441" y="-25" on="0"/>
+ <pt x="294" y="133" on="1"/>
+ <pt x="148" y="291" on="0"/>
+ <pt x="148" y="555" on="1"/>
+ <pt x="148" y="815" on="0"/>
+ <pt x="291" y="962" on="1"/>
+ <pt x="434" y="1110" on="0"/>
+ <pt x="690" y="1110" on="1"/>
+ <pt x="862" y="1110" on="0"/>
+ <pt x="1019" y="1056" on="1"/>
+ <pt x="1019" y="711" on="1"/>
+ <pt x="895" y="711" on="1"/>
+ <pt x="863" y="943" on="1"/>
+ <pt x="753" y="987" on="0"/>
+ <pt x="680" y="987" on="1"/>
+ <pt x="534" y="987" on="0"/>
+ <pt x="448" y="869" on="1"/>
+ <pt x="361" y="751" on="0"/>
+ <pt x="361" y="552" on="1"/>
+ <pt x="361" y="349" on="0"/>
+ <pt x="459" y="236" on="1"/>
+ <pt x="556" y="123" on="0"/>
+ <pt x="729" y="123" on="1"/>
+ <pt x="866" y="123" on="0"/>
+ <pt x="1031" y="200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="314" y="1283" on="1"/>
+ <pt x="570" y="1604" on="1"/>
+ <pt x="789" y="1604" on="1"/>
+ <pt x="1045" y="1283" on="1"/>
+ <pt x="922" y="1283" on="1"/>
+ <pt x="681" y="1485" on="1"/>
+ <pt x="678" y="1485" on="1"/>
+ <pt x="437" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 25 14 2 17 5 10 48 200 10 1 2 2 1 35 34 33 32 31 28 6 29 1 3
+ 0 1 1 27 15 14 13 12 0 6 1 2 3 0 0 30 29 1 0 14 0 0 21 39 6
+ 48 200 31 0 35 34 33 32 30 29 28 15 14 9 13 6 12 27 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cdotaccent" xMin="148" yMin="-25" xMax="1031" yMax="1480">
+ <contour>
+ <pt x="1031" y="46" on="1"/>
+ <pt x="883" y="-25" on="0"/>
+ <pt x="693" y="-25" on="1"/>
+ <pt x="441" y="-25" on="0"/>
+ <pt x="294" y="133" on="1"/>
+ <pt x="148" y="291" on="0"/>
+ <pt x="148" y="555" on="1"/>
+ <pt x="148" y="815" on="0"/>
+ <pt x="291" y="962" on="1"/>
+ <pt x="434" y="1110" on="0"/>
+ <pt x="690" y="1110" on="1"/>
+ <pt x="862" y="1110" on="0"/>
+ <pt x="1019" y="1056" on="1"/>
+ <pt x="1019" y="711" on="1"/>
+ <pt x="895" y="711" on="1"/>
+ <pt x="863" y="943" on="1"/>
+ <pt x="753" y="987" on="0"/>
+ <pt x="680" y="987" on="1"/>
+ <pt x="534" y="987" on="0"/>
+ <pt x="448" y="869" on="1"/>
+ <pt x="361" y="751" on="0"/>
+ <pt x="361" y="552" on="1"/>
+ <pt x="361" y="349" on="0"/>
+ <pt x="459" y="236" on="1"/>
+ <pt x="556" y="123" on="0"/>
+ <pt x="729" y="123" on="1"/>
+ <pt x="866" y="123" on="0"/>
+ <pt x="1031" y="200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="581" y="1283" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="778" y="1480" on="1"/>
+ <pt x="778" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 25 14 2 17 5 10 48 200 10 1 2 2 1 1 27 15 14 13 12 0 6 1 2
+ 3 0 0 0 0 31 28 10 1 29 1 4 48 200 30 29 0 14 0 0 21 39 6 48 200
+ 15 14 2 12 30 3 6 28 0 0 31 30 10 1 28 1 4 48 200 29 28 1 27 0 1
+ 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cedilla" xMin="441" yMin="-432" xMax="788" yMax="0">
+ <contour>
+ <pt x="557" y="0" on="1"/>
+ <pt x="654" y="0" on="1"/>
+ <pt x="594" y="-109" on="1"/>
+ <pt x="666" y="-111" on="0"/>
+ <pt x="718" y="-148" on="1"/>
+ <pt x="788" y="-197" on="0"/>
+ <pt x="788" y="-269" on="1"/>
+ <pt x="788" y="-337" on="0"/>
+ <pt x="729" y="-384" on="1"/>
+ <pt x="671" y="-432" on="0"/>
+ <pt x="584" y="-432" on="1"/>
+ <pt x="517" y="-432" on="0"/>
+ <pt x="441" y="-411" on="1"/>
+ <pt x="441" y="-330" on="1"/>
+ <pt x="491" y="-345" on="0"/>
+ <pt x="545" y="-345" on="1"/>
+ <pt x="649" y="-345" on="0"/>
+ <pt x="649" y="-271" on="1"/>
+ <pt x="649" y="-178" on="0"/>
+ <pt x="462" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 15 32 10 48 200 19 13 12 10 2 1 0 14 0 0 17 20 6 48 200 19 13 12
+ 6 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cent" xMin="173" yMin="0" xMax="1061" yMax="1480">
+ <contour>
+ <pt x="629" y="0" on="1"/>
+ <pt x="629" y="179" on="1"/>
+ <pt x="428" y="204" on="0"/>
+ <pt x="317" y="320" on="1"/>
+ <pt x="173" y="469" on="0"/>
+ <pt x="173" y="737" on="1"/>
+ <pt x="173" y="1020" on="0"/>
+ <pt x="330" y="1172" on="1"/>
+ <pt x="439" y="1278" on="0"/>
+ <pt x="629" y="1305" on="1"/>
+ <pt x="629" y="1480" on="1"/>
+ <pt x="753" y="1480" on="1"/>
+ <pt x="753" y="1308" on="1"/>
+ <pt x="909" y="1295" on="0"/>
+ <pt x="1049" y="1258" on="1"/>
+ <pt x="1049" y="938" on="1"/>
+ <pt x="926" y="938" on="1"/>
+ <pt x="901" y="1147" on="1"/>
+ <pt x="830" y="1184" on="0"/>
+ <pt x="753" y="1184" on="1"/>
+ <pt x="753" y="305" on="1"/>
+ <pt x="869" y="305" on="0"/>
+ <pt x="1061" y="376" on="1"/>
+ <pt x="1061" y="234" on="1"/>
+ <pt x="915" y="183" on="0"/>
+ <pt x="753" y="173" on="1"/>
+ <pt x="753" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="629" y="317" on="1"/>
+ <pt x="629" y="1179" on="1"/>
+ <pt x="563" y="1157" on="0"/>
+ <pt x="529" y="1131" on="1"/>
+ <pt x="383" y="1021" on="0"/>
+ <pt x="383" y="734" on="1"/>
+ <pt x="383" y="512" on="0"/>
+ <pt x="474" y="406" on="1"/>
+ <pt x="512" y="361" on="0"/>
+ <pt x="560" y="339" on="1"/>
+ <pt x="583" y="329" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 64 values pushed */
+ 28 27 26 25 23 22 20 19 17 16 15 14 12 11 10 9 1 0 14 0 0 32 39 5 48
+ 200 17 16 2 14 11 3 5 0 0 0 28 27 10 9 1 0 6 5 11 1 4 48 200 23
+ 22 1 15 14 1 26 25 20 19 12 11 5 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="circumflex" xMin="248" yMin="1283" xMax="979" yMax="1604">
+ <contour>
+ <pt x="248" y="1283" on="1"/>
+ <pt x="504" y="1604" on="1"/>
+ <pt x="723" y="1604" on="1"/>
+ <pt x="979" y="1283" on="1"/>
+ <pt x="856" y="1283" on="1"/>
+ <pt x="615" y="1485" on="1"/>
+ <pt x="612" y="1485" on="1"/>
+ <pt x="371" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 7 6 5 4 3 0 6 13 1 2 1 1 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="colon" xMin="466" yMin="0" xMax="762" yMax="1086">
+ <contour>
+ <pt x="466" y="0" on="1"/>
+ <pt x="466" y="296" on="1"/>
+ <pt x="762" y="296" on="1"/>
+ <pt x="762" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="466" y="790" on="1"/>
+ <pt x="466" y="1086" on="1"/>
+ <pt x="762" y="1086" on="1"/>
+ <pt x="762" y="790" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 7 4 8 1 5 2 1 8 1 0 2 4 48 200 3 0 1 0 6 5 1 14 0
+ 0 7 6 3 2 8 3 0 1 4 48 200 5 4 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="comma" xMin="466" yMin="-321" xMax="762" yMax="296">
+ <contour>
+ <pt x="466" y="0" on="1"/>
+ <pt x="466" y="296" on="1"/>
+ <pt x="762" y="296" on="1"/>
+ <pt x="762" y="116" on="1"/>
+ <pt x="760" y="-302" on="0"/>
+ <pt x="466" y="-321" on="1"/>
+ <pt x="466" y="-222" on="1"/>
+ <pt x="541" y="-210" on="0"/>
+ <pt x="563" y="-155" on="1"/>
+ <pt x="583" y="-107" on="0"/>
+ <pt x="589" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 34 values pushed */
+ 10 6 5 3 0 5 13 1 2 1 1 0 14 10 2 0 2 0 0 3 2 8 1 0 1
+ 4 48 200 6 5 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="copyright" xMin="62" yMin="-37" xMax="1168" yMax="1517">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="864" y="1517" on="0"/>
+ <pt x="1016" y="1304" on="1"/>
+ <pt x="1168" y="1091" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="386" on="0"/>
+ <pt x="1016" y="175" on="1"/>
+ <pt x="864" y="-37" on="0"/>
+ <pt x="606" y="-37" on="1"/>
+ <pt x="388" y="-37" on="0"/>
+ <pt x="245" y="136" on="1"/>
+ <pt x="62" y="357" on="0"/>
+ <pt x="62" y="740" on="1"/>
+ <pt x="62" y="1092" on="0"/>
+ <pt x="214" y="1304" on="1"/>
+ <pt x="366" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1406" on="1"/>
+ <pt x="423" y="1406" on="0"/>
+ <pt x="304" y="1222" on="1"/>
+ <pt x="185" y="1038" on="0"/>
+ <pt x="185" y="741" on="1"/>
+ <pt x="185" y="445" on="0"/>
+ <pt x="303" y="260" on="1"/>
+ <pt x="421" y="74" on="0"/>
+ <pt x="611" y="74" on="1"/>
+ <pt x="785" y="74" on="0"/>
+ <pt x="899" y="221" on="1"/>
+ <pt x="1044" y="407" on="0"/>
+ <pt x="1044" y="742" on="1"/>
+ <pt x="1044" y="1039" on="0"/>
+ <pt x="925" y="1222" on="1"/>
+ <pt x="805" y="1406" on="0"/>
+ </contour>
+ <contour>
+ <pt x="872" y="344" on="1"/>
+ <pt x="852" y="336" on="1"/>
+ <pt x="737" y="290" on="0"/>
+ <pt x="651" y="290" on="1"/>
+ <pt x="491" y="290" on="0"/>
+ <pt x="389" y="413" on="1"/>
+ <pt x="286" y="536" on="0"/>
+ <pt x="286" y="733" on="1"/>
+ <pt x="286" y="932" on="0"/>
+ <pt x="386" y="1055" on="1"/>
+ <pt x="485" y="1178" on="0"/>
+ <pt x="650" y="1178" on="1"/>
+ <pt x="743" y="1178" on="0"/>
+ <pt x="852" y="1151" on="1"/>
+ <pt x="868" y="1147" on="1"/>
+ <pt x="868" y="962" on="1"/>
+ <pt x="783" y="962" on="1"/>
+ <pt x="783" y="1055" on="1"/>
+ <pt x="710" y="1080" on="0"/>
+ <pt x="654" y="1080" on="1"/>
+ <pt x="544" y="1080" on="0"/>
+ <pt x="477" y="986" on="1"/>
+ <pt x="409" y="892" on="0"/>
+ <pt x="409" y="741" on="1"/>
+ <pt x="409" y="586" on="0"/>
+ <pt x="482" y="494" on="1"/>
+ <pt x="555" y="401" on="0"/>
+ <pt x="679" y="401" on="1"/>
+ <pt x="776" y="401" on="0"/>
+ <pt x="872" y="451" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 59 40 35 51 17 43 24 40 8 16 40 0 48 200 8 2 0 0 43 35 1 1 61
+ 49 48 47 46 43 35 32 8 0 2 3 0 0 14 0 0 55 6 39 28 6 4 20 6 12
+ 48 200 61 32 2 13 4 46 49 48 39 12 46 47 46 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="currency" xMin="85" yMin="141" xMax="1143" yMax="1200">
+ <contour>
+ <pt x="347" y="316" on="1"/>
+ <pt x="172" y="141" on="1"/>
+ <pt x="85" y="228" on="1"/>
+ <pt x="259" y="403" on="1"/>
+ <pt x="170" y="528" on="0"/>
+ <pt x="170" y="670" on="1"/>
+ <pt x="170" y="814" on="0"/>
+ <pt x="259" y="938" on="1"/>
+ <pt x="85" y="1112" on="1"/>
+ <pt x="172" y="1200" on="1"/>
+ <pt x="347" y="1025" on="1"/>
+ <pt x="477" y="1115" on="0"/>
+ <pt x="614" y="1115" on="1"/>
+ <pt x="751" y="1115" on="0"/>
+ <pt x="881" y="1025" on="1"/>
+ <pt x="1056" y="1200" on="1"/>
+ <pt x="1143" y="1112" on="1"/>
+ <pt x="968" y="938" on="1"/>
+ <pt x="1058" y="813" on="0"/>
+ <pt x="1058" y="670" on="1"/>
+ <pt x="1058" y="528" on="0"/>
+ <pt x="968" y="403" on="1"/>
+ <pt x="1143" y="229" on="1"/>
+ <pt x="1056" y="141" on="1"/>
+ <pt x="881" y="316" on="1"/>
+ <pt x="751" y="226" on="0"/>
+ <pt x="614" y="226" on="1"/>
+ <pt x="477" y="226" on="0"/>
+ </contour>
+ <contour>
+ <pt x="614" y="967" on="1"/>
+ <pt x="490" y="967" on="0"/>
+ <pt x="404" y="881" on="1"/>
+ <pt x="318" y="796" on="0"/>
+ <pt x="318" y="674" on="1"/>
+ <pt x="318" y="559" on="0"/>
+ <pt x="387" y="477" on="1"/>
+ <pt x="475" y="374" on="0"/>
+ <pt x="615" y="374" on="1"/>
+ <pt x="739" y="374" on="0"/>
+ <pt x="824" y="460" on="1"/>
+ <pt x="910" y="546" on="0"/>
+ <pt x="910" y="671" on="1"/>
+ <pt x="910" y="795" on="0"/>
+ <pt x="824" y="881" on="1"/>
+ <pt x="739" y="967" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 0 36 14 26 28 14 12 48 200 12 1 1 16 15 9 8 4 13 1 0 1 24 23 22
+ 21 17 14 10 7 3 2 1 0 12 13 26 1 0 14 0 0 40 16 19 32 16 5 48 200
+ 24 23 22 21 19 17 16 15 14 10 9 8 7 5 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="d" xMin="111" yMin="-25" xMax="1167" yMax="1579">
+ <contour>
+ <pt x="846" y="1456" on="1"/>
+ <pt x="600" y="1456" on="1"/>
+ <pt x="600" y="1579" on="1"/>
+ <pt x="1044" y="1579" on="1"/>
+ <pt x="1044" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="846" y="0" on="1"/>
+ <pt x="846" y="222" on="1"/>
+ <pt x="771" y="111" on="0"/>
+ <pt x="701" y="55" on="1"/>
+ <pt x="599" y="-25" on="0"/>
+ <pt x="480" y="-25" on="1"/>
+ <pt x="315" y="-25" on="0"/>
+ <pt x="213" y="119" on="1"/>
+ <pt x="111" y="262" on="0"/>
+ <pt x="111" y="498" on="1"/>
+ <pt x="111" y="783" on="0"/>
+ <pt x="246" y="946" on="1"/>
+ <pt x="380" y="1110" on="0"/>
+ <pt x="618" y="1110" on="1"/>
+ <pt x="705" y="1110" on="0"/>
+ <pt x="846" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="846" y="939" on="1"/>
+ <pt x="710" y="962" on="0"/>
+ <pt x="633" y="962" on="1"/>
+ <pt x="468" y="962" on="0"/>
+ <pt x="394" y="855" on="1"/>
+ <pt x="321" y="748" on="0"/>
+ <pt x="321" y="510" on="1"/>
+ <pt x="321" y="136" on="0"/>
+ <pt x="535" y="136" on="1"/>
+ <pt x="699" y="136" on="0"/>
+ <pt x="846" y="370" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 31 30 12 25 14 20 48 200 20 1 12 2 1 33 23 22 8 5 4 6 1 6 3
+ 0 0 0 1 0 6 1 2 1 4 48 200 3 2 1 7 6 1 2 0 14 0 0 29 39
+ 16 48 200 6 5 2 13 3 2 1 16 0 0 0 33 23 22 8 7 0 10 5 3 1 4
+ 48 200 4 3 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dagger" xMin="170" yMin="-296" xMax="1058" yMax="1480">
+ <contour>
+ <pt x="515" y="-296" on="1"/>
+ <pt x="540" y="827" on="1"/>
+ <pt x="170" y="814" on="1"/>
+ <pt x="170" y="962" on="1"/>
+ <pt x="540" y="950" on="1"/>
+ <pt x="515" y="1480" on="1"/>
+ <pt x="713" y="1480" on="1"/>
+ <pt x="688" y="950" on="1"/>
+ <pt x="1058" y="962" on="1"/>
+ <pt x="1058" y="814" on="1"/>
+ <pt x="688" y="827" on="1"/>
+ <pt x="713" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 42 values pushed */
+ 1 10 9 8 7 4 3 2 1 8 5 2 3 0 11 0 1 0 6 5 0 14 11 10 7
+ 6 5 4 1 0 8 8 2 3 9 8 1 3 2 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="daggerdbl" xMin="170" yMin="-296" xMax="1058" yMax="1480">
+ <contour>
+ <pt x="515" y="-296" on="1"/>
+ <pt x="540" y="234" on="1"/>
+ <pt x="170" y="222" on="1"/>
+ <pt x="170" y="370" on="1"/>
+ <pt x="540" y="358" on="1"/>
+ <pt x="540" y="827" on="1"/>
+ <pt x="170" y="814" on="1"/>
+ <pt x="170" y="962" on="1"/>
+ <pt x="540" y="950" on="1"/>
+ <pt x="515" y="1480" on="1"/>
+ <pt x="713" y="1480" on="1"/>
+ <pt x="688" y="950" on="1"/>
+ <pt x="1058" y="962" on="1"/>
+ <pt x="1058" y="814" on="1"/>
+ <pt x="688" y="827" on="1"/>
+ <pt x="688" y="358" on="1"/>
+ <pt x="1058" y="370" on="1"/>
+ <pt x="1058" y="222" on="1"/>
+ <pt x="688" y="234" on="1"/>
+ <pt x="713" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 1 18 17 16 15 14 13 12 11 8 7 6 5 4 3 2 1 16 9 2 3 0 19 0 1
+ 0 10 9 0 14 19 10 2 12 11 3 9 0 2 1 2 3 0 0 18 15 14 11 14 3
+ 1 1 4 48 200 17 16 13 12 3 8 5 4 1 3 7 6 3 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dcaron" xMin="111" yMin="-25" xMax="1229" yMax="1579">
+ <contour>
+ <pt x="753" y="0" on="1"/>
+ <pt x="753" y="222" on="1"/>
+ <pt x="691" y="111" on="0"/>
+ <pt x="630" y="55" on="1"/>
+ <pt x="542" y="-25" on="0"/>
+ <pt x="435" y="-25" on="1"/>
+ <pt x="290" y="-25" on="0"/>
+ <pt x="201" y="119" on="1"/>
+ <pt x="111" y="263" on="0"/>
+ <pt x="111" y="498" on="1"/>
+ <pt x="111" y="782" on="0"/>
+ <pt x="229" y="946" on="1"/>
+ <pt x="346" y="1110" on="0"/>
+ <pt x="554" y="1110" on="1"/>
+ <pt x="634" y="1110" on="0"/>
+ <pt x="753" y="1086" on="1"/>
+ <pt x="753" y="1456" on="1"/>
+ <pt x="537" y="1456" on="1"/>
+ <pt x="537" y="1579" on="1"/>
+ <pt x="950" y="1579" on="1"/>
+ <pt x="950" y="123" on="1"/>
+ <pt x="1058" y="123" on="1"/>
+ <pt x="1058" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="753" y="939" on="1"/>
+ <pt x="645" y="963" on="0"/>
+ <pt x="574" y="963" on="1"/>
+ <pt x="433" y="963" on="0"/>
+ <pt x="376" y="858" on="1"/>
+ <pt x="318" y="751" on="0"/>
+ <pt x="318" y="502" on="1"/>
+ <pt x="318" y="136" on="0"/>
+ <pt x="490" y="136" on="1"/>
+ <pt x="644" y="136" on="0"/>
+ <pt x="753" y="370" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1031" y="1125" on="1"/>
+ <pt x="1031" y="1184" on="1"/>
+ <pt x="1108" y="1205" on="0"/>
+ <pt x="1108" y="1365" on="1"/>
+ <pt x="1108" y="1382" on="1"/>
+ <pt x="1031" y="1382" on="1"/>
+ <pt x="1031" y="1579" on="1"/>
+ <pt x="1229" y="1579" on="1"/>
+ <pt x="1229" y="1408" on="1"/>
+ <pt x="1228" y="1146" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 31 30 5 25 14 13 48 200 13 1 5 2 1 42 39 38 37 35 34 6 16 1 3
+ 0 1 33 23 21 20 15 1 6 1 0 3 0 0 0 17 16 6 1 18 1 4 48 200 41
+ 40 19 18 3 22 0 1 2 0 14 0 0 29 39 9 48 200 38 37 22 21 4 41 34 3
+ 18 17 9 0 0 0 40 39 35 34 10 3 41 33 23 16 15 1 0 10 5 19 2 4 48
+ 200 42 41 1 20 19 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dcroat" xMin="111" yMin="-25" xMax="1167" yMax="1579">
+ <contour>
+ <pt x="846" y="0" on="1"/>
+ <pt x="846" y="222" on="1"/>
+ <pt x="771" y="111" on="0"/>
+ <pt x="701" y="55" on="1"/>
+ <pt x="599" y="-25" on="0"/>
+ <pt x="480" y="-25" on="1"/>
+ <pt x="315" y="-25" on="0"/>
+ <pt x="213" y="119" on="1"/>
+ <pt x="111" y="262" on="0"/>
+ <pt x="111" y="498" on="1"/>
+ <pt x="111" y="783" on="0"/>
+ <pt x="246" y="946" on="1"/>
+ <pt x="380" y="1110" on="0"/>
+ <pt x="618" y="1110" on="1"/>
+ <pt x="705" y="1110" on="0"/>
+ <pt x="846" y="1086" on="1"/>
+ <pt x="846" y="1221" on="1"/>
+ <pt x="526" y="1221" on="1"/>
+ <pt x="526" y="1345" on="1"/>
+ <pt x="846" y="1345" on="1"/>
+ <pt x="846" y="1456" on="1"/>
+ <pt x="600" y="1456" on="1"/>
+ <pt x="600" y="1579" on="1"/>
+ <pt x="1044" y="1579" on="1"/>
+ <pt x="1044" y="1345" on="1"/>
+ <pt x="1167" y="1345" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1044" y="1221" on="1"/>
+ <pt x="1044" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="846" y="939" on="1"/>
+ <pt x="710" y="962" on="0"/>
+ <pt x="633" y="962" on="1"/>
+ <pt x="468" y="962" on="0"/>
+ <pt x="394" y="855" on="1"/>
+ <pt x="321" y="748" on="0"/>
+ <pt x="321" y="510" on="1"/>
+ <pt x="321" y="136" on="0"/>
+ <pt x="535" y="136" on="1"/>
+ <pt x="699" y="136" on="0"/>
+ <pt x="846" y="370" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 39 30 5 33 14 13 48 200 13 1 5 2 1 41 31 29 28 15 1 6 1 0 3
+ 0 0 0 21 20 6 1 22 27 26 17 16 6 3 18 2 4 48 200 23 22 1 25 24 19
+ 18 3 30 0 1 3 0 14 0 0 37 39 9 48 200 30 29 26 25 4 13 23 22 21 18
+ 17 4 13 9 0 0 0 41 31 20 19 16 15 1 0 10 7 23 1 4 48 200 28 27 24
+ 23 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="degree" xMin="318" yMin="925" xMax="910" yMax="1517">
+ <contour>
+ <pt x="614" y="1517" on="1"/>
+ <pt x="735" y="1517" on="0"/>
+ <pt x="823" y="1430" on="1"/>
+ <pt x="910" y="1344" on="0"/>
+ <pt x="910" y="1222" on="1"/>
+ <pt x="910" y="1098" on="0"/>
+ <pt x="823" y="1012" on="1"/>
+ <pt x="735" y="925" on="0"/>
+ <pt x="610" y="925" on="1"/>
+ <pt x="504" y="925" on="0"/>
+ <pt x="423" y="995" on="1"/>
+ <pt x="318" y="1087" on="0"/>
+ <pt x="318" y="1221" on="1"/>
+ <pt x="318" y="1344" on="0"/>
+ <pt x="405" y="1430" on="1"/>
+ <pt x="493" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="614" y="1394" on="1"/>
+ <pt x="543" y="1394" on="0"/>
+ <pt x="492" y="1343" on="1"/>
+ <pt x="441" y="1293" on="0"/>
+ <pt x="441" y="1222" on="1"/>
+ <pt x="441" y="1151" on="0"/>
+ <pt x="492" y="1100" on="1"/>
+ <pt x="542" y="1049" on="0"/>
+ <pt x="612" y="1049" on="1"/>
+ <pt x="677" y="1049" on="0"/>
+ <pt x="725" y="1090" on="1"/>
+ <pt x="787" y="1142" on="0"/>
+ <pt x="787" y="1222" on="1"/>
+ <pt x="787" y="1293" on="0"/>
+ <pt x="736" y="1343" on="1"/>
+ <pt x="685" y="1394" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 0 0 1 8 0 0 14 0 0 28 6 4 20 6 12
+ 48 200 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dieresis" xMin="281" yMin="1283" xMax="947" yMax="1480">
+ <contour>
+ <pt x="281" y="1283" on="1"/>
+ <pt x="281" y="1480" on="1"/>
+ <pt x="478" y="1480" on="1"/>
+ <pt x="478" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="750" y="1283" on="1"/>
+ <pt x="750" y="1480" on="1"/>
+ <pt x="947" y="1480" on="1"/>
+ <pt x="947" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 7 4 3 0 10 3 1 1 4 48 200 6 5 2 1 0 3 14 0 0 5 4 10
+ 1 6 3 2 10 1 0 2 4 48 200 7 6 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="divide" xMin="99" yMin="0" xMax="1130" yMax="1234">
+ <contour>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="691" on="1"/>
+ <pt x="1130" y="691" on="1"/>
+ <pt x="1130" y="543" on="1"/>
+ </contour>
+ <contour>
+ <pt x="491" y="0" on="1"/>
+ <pt x="491" y="247" on="1"/>
+ <pt x="738" y="247" on="1"/>
+ <pt x="738" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="491" y="987" on="1"/>
+ <pt x="491" y="1234" on="1"/>
+ <pt x="738" y="1234" on="1"/>
+ <pt x="738" y="987" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 0 0 11 8 4 1 9 6 5 4 1 4 3 0 7 1 1 3 4 48 200 10 9 1 7
+ 4 1 2 1 1 3 0 14 0 0 11 10 7 6 4 3 4 1 4 48 200 9 8 5 4
+ 3 3 2 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dollar" xMin="143" yMin="-123" xMax="1031" yMax="1604">
+ <contour>
+ <pt x="525" y="-123" on="1"/>
+ <pt x="525" y="0" on="1"/>
+ <pt x="323" y="16" on="0"/>
+ <pt x="143" y="86" on="1"/>
+ <pt x="143" y="385" on="1"/>
+ <pt x="266" y="385" on="1"/>
+ <pt x="291" y="187" on="1"/>
+ <pt x="415" y="131" on="0"/>
+ <pt x="525" y="123" on="1"/>
+ <pt x="525" y="698" on="1"/>
+ <pt x="435" y="751" on="1"/>
+ <pt x="180" y="901" on="0"/>
+ <pt x="180" y="1123" on="1"/>
+ <pt x="180" y="1297" on="0"/>
+ <pt x="309" y="1396" on="1"/>
+ <pt x="399" y="1465" on="0"/>
+ <pt x="550" y="1480" on="1"/>
+ <pt x="550" y="1604" on="1"/>
+ <pt x="674" y="1604" on="1"/>
+ <pt x="674" y="1480" on="1"/>
+ <pt x="835" y="1479" on="0"/>
+ <pt x="1002" y="1408" on="1"/>
+ <pt x="1002" y="1124" on="1"/>
+ <pt x="879" y="1124" on="1"/>
+ <pt x="854" y="1322" on="1"/>
+ <pt x="767" y="1357" on="0"/>
+ <pt x="695" y="1357" on="1"/>
+ <pt x="674" y="1357" on="1"/>
+ <pt x="674" y="823" on="1"/>
+ <pt x="761" y="776" on="1"/>
+ <pt x="911" y="695" on="0"/>
+ <pt x="971" y="613" on="1"/>
+ <pt x="1031" y="531" on="0"/>
+ <pt x="1031" y="409" on="1"/>
+ <pt x="1031" y="212" on="0"/>
+ <pt x="893" y="95" on="1"/>
+ <pt x="800" y="15" on="0"/>
+ <pt x="649" y="0" on="1"/>
+ <pt x="649" y="-123" on="1"/>
+ </contour>
+ <contour>
+ <pt x="649" y="123" on="1"/>
+ <pt x="730" y="132" on="0"/>
+ <pt x="782" y="192" on="1"/>
+ <pt x="852" y="272" on="0"/>
+ <pt x="852" y="388" on="1"/>
+ <pt x="852" y="520" on="0"/>
+ <pt x="716" y="597" on="1"/>
+ <pt x="649" y="635" on="1"/>
+ </contour>
+ <contour>
+ <pt x="550" y="891" on="1"/>
+ <pt x="550" y="1357" on="1"/>
+ <pt x="445" y="1331" on="0"/>
+ <pt x="400" y="1271" on="1"/>
+ <pt x="358" y="1216" on="0"/>
+ <pt x="358" y="1133" on="1"/>
+ <pt x="358" y="1003" on="0"/>
+ <pt x="497" y="922" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 48 47 46 39 38 37 28 27 26 24 23 22 21 19 18 17 16 9 8 6 5 4 3 1 0
+ 14 0 0 52 13 12 43 13 33 48 200 26 24 23 3 21 18 3 12 12 6 5 3 0 3
+ 3 33 21 0 0 28 27 19 18 6 3 16 46 39 38 37 6 3 0 2 4 48 200 22 21
+ 1 48 47 17 16 3 9 8 1 0 3 4 3 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotaccent" xMin="516" yMin="1283" xMax="713" yMax="1480">
+ <contour>
+ <pt x="516" y="1283" on="1"/>
+ <pt x="516" y="1480" on="1"/>
+ <pt x="713" y="1480" on="1"/>
+ <pt x="713" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 0 0 3 0 10 1 1 1 4 48 200 2 1 0 14 0 0 3 2 10 1 0 1 4 48
+ 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotlessi" xMin="148" yMin="0" xMax="1105" yMax="1086">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="538" y="123" on="1"/>
+ <pt x="538" y="962" on="1"/>
+ <pt x="148" y="962" on="1"/>
+ <pt x="148" y="1086" on="1"/>
+ <pt x="735" y="1086" on="1"/>
+ <pt x="735" y="123" on="1"/>
+ <pt x="1105" y="123" on="1"/>
+ <pt x="1105" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 53 values pushed */
+ 0 0 4 3 6 1 5 8 7 2 1 6 3 0 2 4 48 200 9 0 1 0 6 5 1
+ 14 9 8 2 13 6 5 4 1 0 4 13 2 0 0 7 6 10 1 2 1 4 48 200 3
+ 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotlessj" xMin="159" yMin="-420" xMax="903" yMax="1086">
+ <contour>
+ <pt x="159" y="-344" on="1"/>
+ <pt x="159" y="-25" on="1"/>
+ <pt x="282" y="-25" on="1"/>
+ <pt x="313" y="-243" on="1"/>
+ <pt x="381" y="-296" on="0"/>
+ <pt x="460" y="-296" on="1"/>
+ <pt x="592" y="-296" on="0"/>
+ <pt x="648" y="-200" on="1"/>
+ <pt x="705" y="-104" on="0"/>
+ <pt x="705" y="127" on="1"/>
+ <pt x="705" y="962" on="1"/>
+ <pt x="261" y="962" on="1"/>
+ <pt x="261" y="1086" on="1"/>
+ <pt x="903" y="1086" on="1"/>
+ <pt x="903" y="66" on="1"/>
+ <pt x="903" y="-164" on="0"/>
+ <pt x="790" y="-292" on="1"/>
+ <pt x="677" y="-420" on="0"/>
+ <pt x="476" y="-420" on="1"/>
+ <pt x="337" y="-420" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 5 5 18 48 200 1 14 9 2 10 2 3 0 1 3 2 1 0 4 13 18 2 0
+ 0 0 11 10 6 1 12 1 4 48 200 13 12 1 14 12 11 3 2 4 9 0 3 0 0
+ 10 9 10 1 13 1 4 48 200 14 13 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotmath" xMin="491" yMin="419" xMax="738" yMax="666">
+ <contour>
+ <pt x="491" y="419" on="1"/>
+ <pt x="491" y="666" on="1"/>
+ <pt x="738" y="666" on="1"/>
+ <pt x="738" y="419" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 2 1 4 1 0 1 4 48 200 3 0 1 0 14 0 0 3 2 4 1 0 1 4
+ 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="e" xMin="123" yMin="-25" xMax="1105" yMax="1110">
+ <contour>
+ <pt x="1105" y="506" on="1"/>
+ <pt x="334" y="506" on="1"/>
+ <pt x="348" y="389" on="0"/>
+ <pt x="375" y="329" on="1"/>
+ <pt x="466" y="123" on="0"/>
+ <pt x="727" y="123" on="1"/>
+ <pt x="888" y="123" on="0"/>
+ <pt x="1076" y="210" on="1"/>
+ <pt x="1076" y="62" on="1"/>
+ <pt x="901" y="-25" on="0"/>
+ <pt x="701" y="-25" on="1"/>
+ <pt x="442" y="-25" on="0"/>
+ <pt x="282" y="134" on="1"/>
+ <pt x="123" y="293" on="0"/>
+ <pt x="123" y="551" on="1"/>
+ <pt x="123" y="802" on="0"/>
+ <pt x="271" y="956" on="1"/>
+ <pt x="418" y="1110" on="0"/>
+ <pt x="660" y="1110" on="1"/>
+ <pt x="1105" y="1110" on="0"/>
+ <pt x="1105" y="567" on="1"/>
+ </contour>
+ <contour>
+ <pt x="336" y="629" on="1"/>
+ <pt x="895" y="629" on="1"/>
+ <pt x="895" y="675" on="1"/>
+ <pt x="895" y="987" on="0"/>
+ <pt x="646" y="987" on="1"/>
+ <pt x="492" y="987" on="0"/>
+ <pt x="408" y="864" on="1"/>
+ <pt x="349" y="778" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 25 5 18 5 14 10 48 200 18 1 10 2 1 23 1 21 2 0 20 21 0 2 1
+ 8 7 2 0 2 3 0 0 0 1 0 6 1 21 1 4 48 200 22 21 1 0 14 20 0
+ 2 13 7 23 22 21 1 4 13 14 7 8 7 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eacute" xMin="123" yMin="-25" xMax="1105" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="133" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ebreve" xMin="123" yMin="-25" xMax="1105" yMax="1579">
+ <contour>
+ <pt x="1105" y="506" on="1"/>
+ <pt x="334" y="506" on="1"/>
+ <pt x="348" y="389" on="0"/>
+ <pt x="375" y="329" on="1"/>
+ <pt x="466" y="123" on="0"/>
+ <pt x="727" y="123" on="1"/>
+ <pt x="888" y="123" on="0"/>
+ <pt x="1076" y="210" on="1"/>
+ <pt x="1076" y="62" on="1"/>
+ <pt x="901" y="-25" on="0"/>
+ <pt x="701" y="-25" on="1"/>
+ <pt x="442" y="-25" on="0"/>
+ <pt x="282" y="134" on="1"/>
+ <pt x="123" y="293" on="0"/>
+ <pt x="123" y="551" on="1"/>
+ <pt x="123" y="802" on="0"/>
+ <pt x="271" y="956" on="1"/>
+ <pt x="418" y="1110" on="0"/>
+ <pt x="660" y="1110" on="1"/>
+ <pt x="1105" y="1110" on="0"/>
+ <pt x="1105" y="567" on="1"/>
+ </contour>
+ <contour>
+ <pt x="336" y="629" on="1"/>
+ <pt x="895" y="629" on="1"/>
+ <pt x="895" y="675" on="1"/>
+ <pt x="895" y="987" on="0"/>
+ <pt x="646" y="987" on="1"/>
+ <pt x="492" y="987" on="0"/>
+ <pt x="408" y="864" on="1"/>
+ <pt x="349" y="778" on="0"/>
+ </contour>
+ <contour>
+ <pt x="303" y="1579" on="1"/>
+ <pt x="426" y="1579" on="1"/>
+ <pt x="474" y="1431" on="0"/>
+ <pt x="648" y="1431" on="1"/>
+ <pt x="823" y="1431" on="0"/>
+ <pt x="871" y="1579" on="1"/>
+ <pt x="994" y="1579" on="1"/>
+ <pt x="971" y="1490" on="0"/>
+ <pt x="945" y="1444" on="1"/>
+ <pt x="854" y="1289" on="0"/>
+ <pt x="652" y="1289" on="1"/>
+ <pt x="500" y="1289" on="0"/>
+ <pt x="411" y="1370" on="1"/>
+ <pt x="356" y="1419" on="0"/>
+ <pt x="328" y="1491" on="1"/>
+ <pt x="317" y="1520" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 32 14 39 25 5 18 5 14 10 48 200 18 1 10 2 1 23 1 21 2 0 20 21
+ 0 2 1 8 7 2 0 2 3 0 1 35 34 30 29 4 13 39 1 0 0 0 1 0 6
+ 1 21 1 4 48 200 22 21 1 0 14 20 0 2 13 7 35 34 30 29 23 22 21 1 8
+ 13 14 7 8 7 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ecaron" xMin="123" yMin="-25" xMax="1105" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="35" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ecircumflex" xMin="123" yMin="-25" xMax="1105" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="35" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="edieresis" xMin="123" yMin="-25" xMax="1105" yMax="1480">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="34" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="edotaccent" xMin="123" yMin="-25" xMax="1105" yMax="1480">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="dotaccent" x="34" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="egrave" xMin="123" yMin="-25" xMax="1105" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="-64" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="eight" xMin="120" yMin="-37" xMax="1113" yMax="1517">
+ <contour>
+ <pt x="413" y="803" on="1"/>
+ <pt x="360" y="843" on="1"/>
+ <pt x="188" y="973" on="0"/>
+ <pt x="188" y="1145" on="1"/>
+ <pt x="188" y="1307" on="0"/>
+ <pt x="313" y="1412" on="1"/>
+ <pt x="437" y="1517" on="0"/>
+ <pt x="634" y="1517" on="1"/>
+ <pt x="821" y="1517" on="0"/>
+ <pt x="936" y="1426" on="1"/>
+ <pt x="1051" y="1335" on="0"/>
+ <pt x="1051" y="1185" on="1"/>
+ <pt x="1051" y="1067" on="0"/>
+ <pt x="993" y="988" on="1"/>
+ <pt x="949" y="929" on="0"/>
+ <pt x="844" y="835" on="1"/>
+ <pt x="797" y="793" on="1"/>
+ <pt x="865" y="747" on="1"/>
+ <pt x="1009" y="650" on="0"/>
+ <pt x="1061" y="572" on="1"/>
+ <pt x="1113" y="495" on="0"/>
+ <pt x="1113" y="381" on="1"/>
+ <pt x="1113" y="195" on="0"/>
+ <pt x="974" y="79" on="1"/>
+ <pt x="835" y="-37" on="0"/>
+ <pt x="611" y="-37" on="1"/>
+ <pt x="387" y="-37" on="0"/>
+ <pt x="254" y="75" on="1"/>
+ <pt x="120" y="187" on="0"/>
+ <pt x="120" y="372" on="1"/>
+ <pt x="120" y="596" on="0"/>
+ <pt x="358" y="764" on="1"/>
+ </contour>
+ <contour>
+ <pt x="682" y="862" on="1"/>
+ <pt x="866" y="1031" on="0"/>
+ <pt x="866" y="1174" on="1"/>
+ <pt x="866" y="1280" on="0"/>
+ <pt x="802" y="1337" on="1"/>
+ <pt x="737" y="1394" on="0"/>
+ <pt x="612" y="1394" on="1"/>
+ <pt x="503" y="1394" on="0"/>
+ <pt x="437" y="1334" on="1"/>
+ <pt x="372" y="1275" on="0"/>
+ <pt x="372" y="1184" on="1"/>
+ <pt x="372" y="1087" on="0"/>
+ <pt x="499" y="990" on="1"/>
+ <pt x="597" y="915" on="1"/>
+ </contour>
+ <contour>
+ <pt x="512" y="743" on="1"/>
+ <pt x="399" y="620" on="0"/>
+ <pt x="360" y="552" on="1"/>
+ <pt x="317" y="477" on="0"/>
+ <pt x="317" y="377" on="1"/>
+ <pt x="317" y="249" on="0"/>
+ <pt x="404" y="168" on="1"/>
+ <pt x="491" y="86" on="0"/>
+ <pt x="626" y="86" on="1"/>
+ <pt x="751" y="86" on="0"/>
+ <pt x="827" y="158" on="1"/>
+ <pt x="903" y="229" on="0"/>
+ <pt x="903" y="345" on="1"/>
+ <pt x="903" y="427" on="0"/>
+ <pt x="864" y="480" on="1"/>
+ <pt x="827" y="532" on="0"/>
+ <pt x="714" y="608" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 53 values pushed */
+ 0 0 54 5 25 38 5 7 48 200 25 2 7 0 1 1 46 45 32 16 0 5 0 2 3
+ 0 0 14 0 0 58 39 21 50 28 29 42 19 3 34 19 11 48 200 46 45 32 29 21 16
+ 11 3 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ellipsis" xMin="81" yMin="0" xMax="1147" yMax="247">
+ <contour>
+ <pt x="81" y="0" on="1"/>
+ <pt x="81" y="247" on="1"/>
+ <pt x="328" y="247" on="1"/>
+ <pt x="328" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="491" y="0" on="1"/>
+ <pt x="491" y="247" on="1"/>
+ <pt x="737" y="247" on="1"/>
+ <pt x="737" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="900" y="0" on="1"/>
+ <pt x="900" y="247" on="1"/>
+ <pt x="1147" y="247" on="1"/>
+ <pt x="1147" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 10 9 6 5 2 1 4 5 0 1 4 48 200 11 8 7 4 3 0 5 0 14 0
+ 0 9 8 4 1 10 7 6 4 1 4 3 2 4 1 0 3 4 48 200 11 10 1 5 4
+ 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="emacron" xMin="123" yMin="-25" xMax="1105" yMax="1407">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="34" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="emdash" xMin="0" yMin="543" xMax="1229" yMax="666">
+ <contour>
+ <pt x="0" y="543" on="1"/>
+ <pt x="0" y="666" on="1"/>
+ <pt x="1229" y="666" on="1"/>
+ <pt x="1229" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 200 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="endash" xMin="121" yMin="543" xMax="1108" yMax="691">
+ <contour>
+ <pt x="121" y="543" on="1"/>
+ <pt x="121" y="691" on="1"/>
+ <pt x="1108" y="691" on="1"/>
+ <pt x="1108" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 200 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eng" xMin="69" yMin="-420" xMax="1045" yMax="1110">
+ <contour>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="962" on="1"/>
+ <pt x="69" y="962" on="1"/>
+ <pt x="69" y="1086" on="1"/>
+ <pt x="390" y="1086" on="1"/>
+ <pt x="390" y="876" on="1"/>
+ <pt x="459" y="981" on="0"/>
+ <pt x="527" y="1034" on="1"/>
+ <pt x="623" y="1110" on="0"/>
+ <pt x="742" y="1110" on="1"/>
+ <pt x="1043" y="1110" on="0"/>
+ <pt x="1043" y="722" on="1"/>
+ <pt x="1044" y="11" on="1"/>
+ <pt x="1045" y="-420" on="0"/>
+ <pt x="681" y="-420" on="1"/>
+ <pt x="585" y="-420" on="0"/>
+ <pt x="458" y="-383" on="1"/>
+ <pt x="458" y="-173" on="1"/>
+ <pt x="581" y="-173" on="1"/>
+ <pt x="593" y="-290" on="1"/>
+ <pt x="657" y="-321" on="0"/>
+ <pt x="704" y="-321" on="1"/>
+ <pt x="846" y="-321" on="0"/>
+ <pt x="846" y="-82" on="1"/>
+ <pt x="846" y="701" on="1"/>
+ <pt x="846" y="956" on="0"/>
+ <pt x="683" y="956" on="1"/>
+ <pt x="533" y="956" on="0"/>
+ <pt x="390" y="704" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 28 30 11 23 17 16 48 200 11 1 32 31 30 26 7 4 3 2 1 9 5 0 3
+ 25 21 20 19 18 5 13 16 0 33 0 1 0 6 5 1 14 33 32 21 20 4 25 18 3
+ 5 4 1 0 4 13 2 0 0 31 30 7 6 10 3 2 1 4 48 200 26 25 1 19 18
+ 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eogonek" xMin="123" yMin="-370" xMax="1105" yMax="1110">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="148" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="equal" xMin="99" yMin="346" xMax="1130" yMax="888">
+ <contour>
+ <pt x="99" y="346" on="1"/>
+ <pt x="99" y="494" on="1"/>
+ <pt x="1130" y="494" on="1"/>
+ <pt x="1130" y="346" on="1"/>
+ </contour>
+ <contour>
+ <pt x="99" y="740" on="1"/>
+ <pt x="99" y="888" on="1"/>
+ <pt x="1130" y="888" on="1"/>
+ <pt x="1130" y="740" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 0 0 7 4 7 1 5 2 1 7 1 0 2 4 48 200 6 5 1 3 0 1 2 0 14
+ 7 6 3 2 3 5 4 1 0 3 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="estimated" xMin="123" yMin="-25" xMax="1105" yMax="1110">
+ <contour>
+ <pt x="1105" y="506" on="1"/>
+ <pt x="334" y="506" on="1"/>
+ <pt x="348" y="389" on="0"/>
+ <pt x="375" y="329" on="1"/>
+ <pt x="466" y="123" on="0"/>
+ <pt x="727" y="123" on="1"/>
+ <pt x="888" y="123" on="0"/>
+ <pt x="1076" y="210" on="1"/>
+ <pt x="1076" y="62" on="1"/>
+ <pt x="901" y="-25" on="0"/>
+ <pt x="701" y="-25" on="1"/>
+ <pt x="442" y="-25" on="0"/>
+ <pt x="282" y="134" on="1"/>
+ <pt x="123" y="293" on="0"/>
+ <pt x="123" y="551" on="1"/>
+ <pt x="123" y="802" on="0"/>
+ <pt x="271" y="956" on="1"/>
+ <pt x="418" y="1110" on="0"/>
+ <pt x="660" y="1110" on="1"/>
+ <pt x="1105" y="1110" on="0"/>
+ <pt x="1105" y="567" on="1"/>
+ </contour>
+ <contour>
+ <pt x="336" y="629" on="1"/>
+ <pt x="895" y="629" on="1"/>
+ <pt x="895" y="675" on="1"/>
+ <pt x="895" y="987" on="0"/>
+ <pt x="646" y="987" on="1"/>
+ <pt x="492" y="987" on="0"/>
+ <pt x="408" y="864" on="1"/>
+ <pt x="349" y="778" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 25 5 18 5 14 10 48 200 18 1 10 2 1 23 1 21 2 0 20 21 0 2 1
+ 8 7 2 0 2 3 0 0 0 1 0 6 1 21 1 4 48 200 22 21 1 0 14 20 0
+ 2 13 7 23 22 21 1 4 13 14 7 8 7 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eth" xMin="111" yMin="-25" xMax="1119" yMax="1614">
+ <contour>
+ <pt x="779" y="1039" on="1"/>
+ <pt x="658" y="1216" on="0"/>
+ <pt x="552" y="1291" on="1"/>
+ <pt x="271" y="1098" on="1"/>
+ <pt x="197" y="1202" on="1"/>
+ <pt x="440" y="1366" on="1"/>
+ <pt x="308" y="1456" on="0"/>
+ <pt x="114" y="1456" on="1"/>
+ <pt x="114" y="1579" on="1"/>
+ <pt x="141" y="1579" on="1"/>
+ <pt x="395" y="1579" on="0"/>
+ <pt x="588" y="1467" on="1"/>
+ <pt x="811" y="1614" on="1"/>
+ <pt x="882" y="1514" on="1"/>
+ <pt x="707" y="1395" on="1"/>
+ <pt x="877" y="1258" on="0"/>
+ <pt x="982" y="1068" on="1"/>
+ <pt x="1119" y="819" on="0"/>
+ <pt x="1119" y="568" on="1"/>
+ <pt x="1119" y="306" on="0"/>
+ <pt x="980" y="141" on="1"/>
+ <pt x="841" y="-25" on="0"/>
+ <pt x="618" y="-25" on="1"/>
+ <pt x="399" y="-25" on="0"/>
+ <pt x="255" y="133" on="1"/>
+ <pt x="111" y="291" on="0"/>
+ <pt x="111" y="532" on="1"/>
+ <pt x="111" y="771" on="0"/>
+ <pt x="250" y="928" on="1"/>
+ <pt x="388" y="1086" on="0"/>
+ <pt x="592" y="1086" on="1"/>
+ <pt x="687" y="1086" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="962" on="1"/>
+ <pt x="488" y="962" on="0"/>
+ <pt x="405" y="839" on="1"/>
+ <pt x="321" y="715" on="0"/>
+ <pt x="321" y="531" on="1"/>
+ <pt x="321" y="346" on="0"/>
+ <pt x="405" y="222" on="1"/>
+ <pt x="488" y="99" on="0"/>
+ <pt x="615" y="99" on="1"/>
+ <pt x="740" y="99" on="0"/>
+ <pt x="824" y="221" on="1"/>
+ <pt x="909" y="344" on="0"/>
+ <pt x="909" y="526" on="1"/>
+ <pt x="909" y="696" on="0"/>
+ <pt x="840" y="814" on="1"/>
+ <pt x="754" y="962" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 40 5 22 32 5 30 48 200 30 1 22 2 1 1 14 11 7 5 4 3 2 7 0
+ 1 3 0 0 1 1 0 1 2 2 0 0 1 13 12 9 8 4 13 0 0 14 0 0 44
+ 39 18 36 39 26 48 200 26 18 14 13 12 11 9 8 7 5 4 3 2 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="exclam" xMin="491" yMin="0" xMax="738" yMax="1480">
+ <contour>
+ <pt x="491" y="0" on="1"/>
+ <pt x="491" y="222" on="1"/>
+ <pt x="738" y="222" on="1"/>
+ <pt x="738" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="553" y="419" on="1"/>
+ <pt x="516" y="1086" on="1"/>
+ <pt x="516" y="1480" on="1"/>
+ <pt x="713" y="1480" on="1"/>
+ <pt x="713" y="1086" on="1"/>
+ <pt x="676" y="419" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 9 8 5 4 4 6 1 3 0 0 2 1 9 1 0 1 4 48 200 3 0 1 0 7 6
+ 0 14 9 4 2 7 5 3 0 0 8 7 10 1 5 3 2 4 1 0 2 4 48 200 6
+ 5 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="exclamdown" xMin="491" yMin="-395" xMax="738" yMax="1086">
+ <contour>
+ <pt x="738" y="1086" on="1"/>
+ <pt x="738" y="864" on="1"/>
+ <pt x="491" y="864" on="1"/>
+ <pt x="491" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="676" y="666" on="1"/>
+ <pt x="713" y="0" on="1"/>
+ <pt x="713" y="-395" on="1"/>
+ <pt x="516" y="-395" on="1"/>
+ <pt x="516" y="0" on="1"/>
+ <pt x="553" y="666" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 1 9 4 2 1 2 3 0 1 8 5 2 2 6 3 0 0 0 2 1 9 1 0 1 4
+ 48 200 7 6 1 0 3 0 1 14 9 4 2 5 7 3 0 0 6 5 10 1 7 1 0
+ 4 1 2 2 4 48 200 8 7 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="f" xMin="148" yMin="0" xMax="1167" yMax="1604">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="925" on="1"/>
+ <pt x="148" y="925" on="1"/>
+ <pt x="148" y="1061" on="1"/>
+ <pt x="419" y="1061" on="1"/>
+ <pt x="419" y="1179" on="1"/>
+ <pt x="419" y="1404" on="0"/>
+ <pt x="510" y="1504" on="1"/>
+ <pt x="601" y="1604" on="0"/>
+ <pt x="803" y="1604" on="1"/>
+ <pt x="974" y="1604" on="0"/>
+ <pt x="1167" y="1524" on="1"/>
+ <pt x="1167" y="1277" on="1"/>
+ <pt x="1044" y="1277" on="1"/>
+ <pt x="1013" y="1433" on="1"/>
+ <pt x="912" y="1480" on="0"/>
+ <pt x="829" y="1480" on="1"/>
+ <pt x="710" y="1480" on="0"/>
+ <pt x="664" y="1420" on="1"/>
+ <pt x="617" y="1360" on="0"/>
+ <pt x="617" y="1201" on="1"/>
+ <pt x="617" y="1061" on="1"/>
+ <pt x="1061" y="1061" on="1"/>
+ <pt x="1061" y="925" on="1"/>
+ <pt x="617" y="925" on="1"/>
+ <pt x="617" y="123" on="1"/>
+ <pt x="987" y="123" on="1"/>
+ <pt x="987" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 88 values pushed */
+ 0 0 18 5 11 48 200 22 16 15 14 13 7 6 13 11 5 0 0 26 25 4 3 20 3
+ 5 28 27 2 1 6 3 0 2 4 48 200 24 23 6 5 3 29 0 1 2 0 14 29 28
+ 25 24 16 15 6 13 22 3 5 4 1 0 4 13 2 0 0 27 26 23 22 10 3 2 1
+ 4 48 200 14 13 1 7 6 3 2 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fi" xMin="69" yMin="0" xMax="1167" yMax="1604">
+ <contour>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="938" on="1"/>
+ <pt x="75" y="938" on="1"/>
+ <pt x="75" y="1073" on="1"/>
+ <pt x="192" y="1073" on="1"/>
+ <pt x="192" y="1247" on="1"/>
+ <pt x="192" y="1410" on="0"/>
+ <pt x="278" y="1507" on="1"/>
+ <pt x="365" y="1604" on="0"/>
+ <pt x="508" y="1604" on="1"/>
+ <pt x="602" y="1604" on="0"/>
+ <pt x="723" y="1555" on="1"/>
+ <pt x="723" y="1345" on="1"/>
+ <pt x="600" y="1345" on="1"/>
+ <pt x="575" y="1468" on="1"/>
+ <pt x="539" y="1487" on="0"/>
+ <pt x="510" y="1487" on="1"/>
+ <pt x="390" y="1487" on="0"/>
+ <pt x="390" y="1301" on="1"/>
+ <pt x="390" y="1073" on="1"/>
+ <pt x="1044" y="1073" on="1"/>
+ <pt x="1044" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="748" y="0" on="1"/>
+ <pt x="748" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="938" on="1"/>
+ <pt x="390" y="938" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="846" y="1345" on="1"/>
+ <pt x="846" y="1542" on="1"/>
+ <pt x="1044" y="1542" on="1"/>
+ <pt x="1044" y="1345" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 129 values pushed */
+ 0 0 18 40 11 48 200 16 35 14 2 20 7 2 14 5 3 32 31 28 27 24 23 2 1
+ 8 3 0 3 13 11 35 0 0 37 34 15 14 10 3 35 30 29 4 3 20 3 5 2 4
+ 48 200 36 35 1 22 21 6 5 3 33 26 25 0 3 3 0 14 27 26 2 28 13 3 33
+ 32 16 15 4 13 20 3 25 24 2 13 22 5 4 1 0 4 13 2 0 0 35 34 29 28
+ 10 3 22 31 30 21 20 10 3 2 2 4 48 200 37 36 23 22 3 14 13 1 7 6 3
+ 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fi#1" xMin="69" yMin="0" xMax="1167" yMax="1604">
+ <contour>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="938" on="1"/>
+ <pt x="75" y="938" on="1"/>
+ <pt x="75" y="1073" on="1"/>
+ <pt x="192" y="1073" on="1"/>
+ <pt x="192" y="1247" on="1"/>
+ <pt x="192" y="1410" on="0"/>
+ <pt x="278" y="1507" on="1"/>
+ <pt x="365" y="1604" on="0"/>
+ <pt x="508" y="1604" on="1"/>
+ <pt x="602" y="1604" on="0"/>
+ <pt x="723" y="1555" on="1"/>
+ <pt x="723" y="1345" on="1"/>
+ <pt x="600" y="1345" on="1"/>
+ <pt x="575" y="1468" on="1"/>
+ <pt x="539" y="1487" on="0"/>
+ <pt x="510" y="1487" on="1"/>
+ <pt x="390" y="1487" on="0"/>
+ <pt x="390" y="1301" on="1"/>
+ <pt x="390" y="1073" on="1"/>
+ <pt x="1044" y="1073" on="1"/>
+ <pt x="1044" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="748" y="0" on="1"/>
+ <pt x="748" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="938" on="1"/>
+ <pt x="390" y="938" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="846" y="1345" on="1"/>
+ <pt x="846" y="1542" on="1"/>
+ <pt x="1044" y="1542" on="1"/>
+ <pt x="1044" y="1345" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 129 values pushed */
+ 0 0 18 40 11 48 200 16 35 14 2 20 7 2 14 5 3 32 31 28 27 24 23 2 1
+ 8 3 0 3 13 11 35 0 0 37 34 15 14 10 3 35 30 29 4 3 20 3 5 2 4
+ 48 200 36 35 1 22 21 6 5 3 33 26 25 0 3 3 0 14 27 26 2 28 13 3 33
+ 32 16 15 4 13 20 3 25 24 2 13 22 5 4 1 0 4 13 2 0 0 35 34 29 28
+ 10 3 22 31 30 21 20 10 3 2 2 4 48 200 37 36 23 22 3 14 13 1 7 6 3
+ 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="figuredash" xMin="121" yMin="543" xMax="1108" yMax="691">
+ <contour>
+ <pt x="121" y="543" on="1"/>
+ <pt x="121" y="691" on="1"/>
+ <pt x="1108" y="691" on="1"/>
+ <pt x="1108" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 200 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="five" xMin="249" yMin="-37" xMax="1076" yMax="1480">
+ <contour>
+ <pt x="249" y="0" on="1"/>
+ <pt x="249" y="321" on="1"/>
+ <pt x="372" y="321" on="1"/>
+ <pt x="397" y="123" on="1"/>
+ <pt x="489" y="86" on="0"/>
+ <pt x="556" y="86" on="1"/>
+ <pt x="689" y="86" on="0"/>
+ <pt x="777" y="184" on="1"/>
+ <pt x="866" y="283" on="0"/>
+ <pt x="866" y="433" on="1"/>
+ <pt x="866" y="600" on="0"/>
+ <pt x="747" y="699" on="1"/>
+ <pt x="628" y="797" on="0"/>
+ <pt x="427" y="797" on="1"/>
+ <pt x="362" y="797" on="0"/>
+ <pt x="280" y="783" on="1"/>
+ <pt x="280" y="1480" on="1"/>
+ <pt x="1045" y="1480" on="1"/>
+ <pt x="1045" y="1308" on="1"/>
+ <pt x="425" y="1308" on="1"/>
+ <pt x="425" y="916" on="1"/>
+ <pt x="474" y="919" on="0"/>
+ <pt x="500" y="919" on="1"/>
+ <pt x="761" y="919" on="0"/>
+ <pt x="918" y="788" on="1"/>
+ <pt x="1076" y="658" on="0"/>
+ <pt x="1076" y="440" on="1"/>
+ <pt x="1076" y="232" on="0"/>
+ <pt x="930" y="98" on="1"/>
+ <pt x="784" y="-37" on="0"/>
+ <pt x="559" y="-37" on="1"/>
+ <pt x="444" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 13 5 22 5 5 30 48 200 30 2 22 1 22 20 15 3 2 1 6 18 2 3 0
+ 1 0 2 0 0 0 19 18 22 1 16 1 4 48 200 17 16 0 14 0 0 9 39 26 48
+ 200 3 2 2 19 15 3 26 17 0 0 20 19 14 1 15 1 4 48 200 18 17 1 16 15
+ 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fl" xMin="69" yMin="0" xMax="1167" yMax="1604">
+ <contour>
+ <pt x="390" y="1061" on="1"/>
+ <pt x="686" y="1061" on="1"/>
+ <pt x="686" y="925" on="1"/>
+ <pt x="390" y="925" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="925" on="1"/>
+ <pt x="75" y="925" on="1"/>
+ <pt x="75" y="1061" on="1"/>
+ <pt x="192" y="1061" on="1"/>
+ <pt x="192" y="1247" on="1"/>
+ <pt x="192" y="1604" on="0"/>
+ <pt x="588" y="1604" on="1"/>
+ <pt x="674" y="1604" on="0"/>
+ <pt x="784" y="1588" on="1"/>
+ <pt x="846" y="1579" on="1"/>
+ <pt x="1043" y="1579" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="748" y="0" on="1"/>
+ <pt x="748" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="1450" on="1"/>
+ <pt x="711" y="1487" on="0"/>
+ <pt x="597" y="1487" on="1"/>
+ <pt x="480" y="1487" on="0"/>
+ <pt x="434" y="1447" on="1"/>
+ <pt x="390" y="1407" on="0"/>
+ <pt x="390" y="1301" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 0 0 29 40 16 48 200 33 27 14 3 19 0 3 26 25 22 21 9 8 5 4 8 2 6
+ 3 16 19 0 0 11 10 3 2 20 3 0 1 4 48 200 20 19 1 13 12 1 0 3 24
+ 23 7 6 3 3 0 14 25 24 6 5 2 1 6 19 0 3 23 22 2 13 20 12 11 8
+ 7 4 13 9 0 0 27 26 19 10 2 20 33 4 3 0 10 3 9 2 4 48 200 21 20
+ 1 14 13 10 9 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fl#1" xMin="69" yMin="0" xMax="1167" yMax="1604">
+ <contour>
+ <pt x="390" y="1061" on="1"/>
+ <pt x="686" y="1061" on="1"/>
+ <pt x="686" y="925" on="1"/>
+ <pt x="390" y="925" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="925" on="1"/>
+ <pt x="75" y="925" on="1"/>
+ <pt x="75" y="1061" on="1"/>
+ <pt x="192" y="1061" on="1"/>
+ <pt x="192" y="1247" on="1"/>
+ <pt x="192" y="1604" on="0"/>
+ <pt x="588" y="1604" on="1"/>
+ <pt x="674" y="1604" on="0"/>
+ <pt x="784" y="1588" on="1"/>
+ <pt x="846" y="1579" on="1"/>
+ <pt x="1043" y="1579" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="748" y="0" on="1"/>
+ <pt x="748" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="1450" on="1"/>
+ <pt x="711" y="1487" on="0"/>
+ <pt x="597" y="1487" on="1"/>
+ <pt x="480" y="1487" on="0"/>
+ <pt x="434" y="1447" on="1"/>
+ <pt x="390" y="1407" on="0"/>
+ <pt x="390" y="1301" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 0 0 29 40 16 48 200 33 27 14 3 19 0 3 26 25 22 21 9 8 5 4 8 2 6
+ 3 16 19 0 0 11 10 3 2 20 3 0 1 4 48 200 20 19 1 13 12 1 0 3 24
+ 23 7 6 3 3 0 14 25 24 6 5 2 1 6 19 0 3 23 22 2 13 20 12 11 8
+ 7 4 13 9 0 0 27 26 19 10 2 20 33 4 3 0 10 3 9 2 4 48 200 21 20
+ 1 14 13 10 9 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="florin" xMin="84" yMin="-296" xMax="1081" yMax="1517">
+ <contour>
+ <pt x="84" y="-296" on="1"/>
+ <pt x="288" y="728" on="1"/>
+ <pt x="116" y="728" on="1"/>
+ <pt x="116" y="851" on="1"/>
+ <pt x="313" y="851" on="1"/>
+ <pt x="340" y="990" on="1"/>
+ <pt x="443" y="1517" on="0"/>
+ <pt x="892" y="1517" on="1"/>
+ <pt x="971" y="1517" on="0"/>
+ <pt x="1081" y="1499" on="1"/>
+ <pt x="1081" y="1166" on="1"/>
+ <pt x="958" y="1166" on="1"/>
+ <pt x="933" y="1363" on="1"/>
+ <pt x="853" y="1388" on="0"/>
+ <pt x="805" y="1388" on="1"/>
+ <pt x="618" y="1388" on="0"/>
+ <pt x="555" y="1076" on="1"/>
+ <pt x="510" y="851" on="1"/>
+ <pt x="754" y="851" on="1"/>
+ <pt x="754" y="728" on="1"/>
+ <pt x="486" y="728" on="1"/>
+ <pt x="282" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 14 25 7 48 200 7 0 1 12 11 10 3 0 3 3 0 1 9 0 0 0 0 20
+ 19 2 1 6 3 3 1 4 48 200 18 17 4 3 3 21 0 1 2 0 14 21 20 19 18
+ 17 12 11 4 3 2 1 0 12 13 9 10 9 1 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="84" yMin="0" xMax="1132" yMax="1480">
+ <contour>
+ <pt x="738" y="419" on="1"/>
+ <pt x="84" y="419" on="1"/>
+ <pt x="84" y="568" on="1"/>
+ <pt x="713" y="1480" on="1"/>
+ <pt x="910" y="1480" on="1"/>
+ <pt x="910" y="568" on="1"/>
+ <pt x="1132" y="568" on="1"/>
+ <pt x="1132" y="419" on="1"/>
+ <pt x="910" y="419" on="1"/>
+ <pt x="910" y="123" on="1"/>
+ <pt x="1108" y="123" on="1"/>
+ <pt x="1108" y="0" on="1"/>
+ <pt x="466" y="0" on="1"/>
+ <pt x="466" y="123" on="1"/>
+ <pt x="738" y="123" on="1"/>
+ </contour>
+ <contour>
+ <pt x="238" y="568" on="1"/>
+ <pt x="738" y="568" on="1"/>
+ <pt x="738" y="1292" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 17 3 2 2 0 0 16 15 6 5 2 7 4 0 14 13 10 9 6 3 11 2 4 48 200
+ 8 7 1 0 3 12 11 1 2 0 4 3 0 14 11 10 2 6 4 3 15 13 12 3 4
+ 0 1 3 0 0 17 16 14 0 12 3 4 1 4 48 200 7 6 1 9 8 5 4 3 2
+ 1 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="foursuperiour" xMin="284" yMin="728" xMax="918" yMax="1517">
+ <contour>
+ <pt x="807" y="728" on="1"/>
+ <pt x="659" y="728" on="1"/>
+ <pt x="659" y="907" on="1"/>
+ <pt x="284" y="907" on="1"/>
+ <pt x="284" y="1030" on="1"/>
+ <pt x="654" y="1517" on="1"/>
+ <pt x="807" y="1517" on="1"/>
+ <pt x="807" y="1030" on="1"/>
+ <pt x="918" y="1030" on="1"/>
+ <pt x="918" y="907" on="1"/>
+ <pt x="807" y="907" on="1"/>
+ </contour>
+ <contour>
+ <pt x="422" y="1030" on="1"/>
+ <pt x="659" y="1030" on="1"/>
+ <pt x="659" y="1339" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 13 5 4 2 0 0 10 9 3 2 6 3 4 1 4 48 200 6 5 1 12 11 8 7 4
+ 4 1 0 1 3 0 14 9 8 2 13 0 11 5 4 3 4 13 1 0 0 13 12 2 1
+ 16 3 0 1 4 48 200 10 7 6 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="foursuperiour#1" xMin="155" yMin="-37" xMax="1073" yMax="1517">
+ <contour>
+ <pt x="155" y="-37" on="1"/>
+ <pt x="932" y="1517" on="1"/>
+ <pt x="1073" y="1517" on="1"/>
+ <pt x="293" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 2 1 1 3 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fraction" xMin="155" yMin="-37" xMax="1073" yMax="1517">
+ <contour>
+ <pt x="155" y="-37" on="1"/>
+ <pt x="932" y="1517" on="1"/>
+ <pt x="1073" y="1517" on="1"/>
+ <pt x="293" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 2 1 1 3 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fraction#1" xMin="155" yMin="-37" xMax="1073" yMax="1517">
+ <contour>
+ <pt x="155" y="-37" on="1"/>
+ <pt x="932" y="1517" on="1"/>
+ <pt x="1073" y="1517" on="1"/>
+ <pt x="293" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 2 1 1 3 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="g" xMin="86" yMin="-420" xMax="1160" yMax="1111">
+ <contour>
+ <pt x="266" y="13" on="1"/>
+ <pt x="172" y="72" on="0"/>
+ <pt x="172" y="152" on="1"/>
+ <pt x="172" y="239" on="0"/>
+ <pt x="288" y="345" on="1"/>
+ <pt x="324" y="378" on="1"/>
+ <pt x="233" y="433" on="0"/>
+ <pt x="187" y="495" on="1"/>
+ <pt x="120" y="587" on="0"/>
+ <pt x="120" y="713" on="1"/>
+ <pt x="120" y="893" on="0"/>
+ <pt x="243" y="1001" on="1"/>
+ <pt x="365" y="1110" on="0"/>
+ <pt x="565" y="1110" on="1"/>
+ <pt x="663" y="1110" on="0"/>
+ <pt x="752" y="1078" on="1"/>
+ <pt x="1160" y="1111" on="1"/>
+ <pt x="1101" y="933" on="1"/>
+ <pt x="897" y="965" on="1"/>
+ <pt x="1000" y="833" on="0"/>
+ <pt x="1000" y="704" on="1"/>
+ <pt x="1000" y="538" on="0"/>
+ <pt x="875" y="428" on="1"/>
+ <pt x="749" y="318" on="0"/>
+ <pt x="561" y="318" on="1"/>
+ <pt x="508" y="318" on="0"/>
+ <pt x="441" y="331" on="1"/>
+ <pt x="402" y="297" on="1"/>
+ <pt x="342" y="245" on="0"/>
+ <pt x="342" y="204" on="1"/>
+ <pt x="342" y="148" on="0"/>
+ <pt x="481" y="148" on="1"/>
+ <pt x="794" y="148" on="1"/>
+ <pt x="1104" y="148" on="0"/>
+ <pt x="1104" y="-86" on="1"/>
+ <pt x="1104" y="-420" on="0"/>
+ <pt x="539" y="-420" on="1"/>
+ <pt x="86" y="-420" on="0"/>
+ <pt x="86" y="-203" on="1"/>
+ <pt x="86" y="-106" on="0"/>
+ <pt x="210" y="-24" on="1"/>
+ </contour>
+ <contour>
+ <pt x="404" y="0" on="1"/>
+ <pt x="364" y="-30" on="1"/>
+ <pt x="283" y="-91" on="0"/>
+ <pt x="283" y="-165" on="1"/>
+ <pt x="283" y="-296" on="0"/>
+ <pt x="564" y="-296" on="1"/>
+ <pt x="720" y="-296" on="0"/>
+ <pt x="813" y="-247" on="1"/>
+ <pt x="906" y="-199" on="0"/>
+ <pt x="906" y="-119" on="1"/>
+ <pt x="906" y="0" on="0"/>
+ <pt x="728" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="567" y="987" on="1"/>
+ <pt x="458" y="987" on="0"/>
+ <pt x="388" y="906" on="1"/>
+ <pt x="317" y="825" on="0"/>
+ <pt x="317" y="703" on="1"/>
+ <pt x="317" y="586" on="0"/>
+ <pt x="386" y="514" on="1"/>
+ <pt x="455" y="441" on="0"/>
+ <pt x="564" y="441" on="1"/>
+ <pt x="673" y="441" on="0"/>
+ <pt x="744" y="516" on="1"/>
+ <pt x="815" y="590" on="0"/>
+ <pt x="815" y="708" on="1"/>
+ <pt x="815" y="819" on="0"/>
+ <pt x="759" y="893" on="1"/>
+ <pt x="687" y="987" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 0 0 61 5 24 53 5 13 46 5 36 48 200 13 1 24 1 26 24 18 17 15 5 6 1
+ 31 3 0 0 31 41 2 1 16 1 0 36 41 0 0 32 31 7 1 41 1 4 48 200 52
+ 41 1 0 14 0 0 65 19 20 57 28 9 50 28 34 44 28 38 29 15 2 48 200 52 41
+ 38 34 32 31 26 20 18 17 16 15 9 5 2 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gbreve" xMin="86" yMin="-420" xMax="1160" yMax="1579">
+ <component glyphName="g" x="0" y="0" flags="0x4"/>
+ <component glyphName="breve" x="-54" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="gcircumflex" xMin="86" yMin="-420" xMax="1160" yMax="1604">
+ <contour>
+ <pt x="266" y="13" on="1"/>
+ <pt x="172" y="72" on="0"/>
+ <pt x="172" y="152" on="1"/>
+ <pt x="172" y="239" on="0"/>
+ <pt x="288" y="345" on="1"/>
+ <pt x="324" y="378" on="1"/>
+ <pt x="233" y="433" on="0"/>
+ <pt x="187" y="495" on="1"/>
+ <pt x="120" y="587" on="0"/>
+ <pt x="120" y="713" on="1"/>
+ <pt x="120" y="893" on="0"/>
+ <pt x="243" y="1001" on="1"/>
+ <pt x="365" y="1110" on="0"/>
+ <pt x="565" y="1110" on="1"/>
+ <pt x="663" y="1110" on="0"/>
+ <pt x="752" y="1078" on="1"/>
+ <pt x="1160" y="1111" on="1"/>
+ <pt x="1101" y="933" on="1"/>
+ <pt x="897" y="965" on="1"/>
+ <pt x="1000" y="833" on="0"/>
+ <pt x="1000" y="704" on="1"/>
+ <pt x="1000" y="538" on="0"/>
+ <pt x="875" y="428" on="1"/>
+ <pt x="749" y="318" on="0"/>
+ <pt x="561" y="318" on="1"/>
+ <pt x="508" y="318" on="0"/>
+ <pt x="441" y="331" on="1"/>
+ <pt x="402" y="297" on="1"/>
+ <pt x="342" y="245" on="0"/>
+ <pt x="342" y="204" on="1"/>
+ <pt x="342" y="148" on="0"/>
+ <pt x="481" y="148" on="1"/>
+ <pt x="794" y="148" on="1"/>
+ <pt x="1104" y="148" on="0"/>
+ <pt x="1104" y="-86" on="1"/>
+ <pt x="1104" y="-420" on="0"/>
+ <pt x="539" y="-420" on="1"/>
+ <pt x="86" y="-420" on="0"/>
+ <pt x="86" y="-203" on="1"/>
+ <pt x="86" y="-106" on="0"/>
+ <pt x="210" y="-24" on="1"/>
+ </contour>
+ <contour>
+ <pt x="404" y="0" on="1"/>
+ <pt x="364" y="-30" on="1"/>
+ <pt x="283" y="-91" on="0"/>
+ <pt x="283" y="-165" on="1"/>
+ <pt x="283" y="-296" on="0"/>
+ <pt x="564" y="-296" on="1"/>
+ <pt x="720" y="-296" on="0"/>
+ <pt x="813" y="-247" on="1"/>
+ <pt x="906" y="-199" on="0"/>
+ <pt x="906" y="-119" on="1"/>
+ <pt x="906" y="0" on="0"/>
+ <pt x="728" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="567" y="987" on="1"/>
+ <pt x="458" y="987" on="0"/>
+ <pt x="388" y="906" on="1"/>
+ <pt x="317" y="825" on="0"/>
+ <pt x="317" y="703" on="1"/>
+ <pt x="317" y="586" on="0"/>
+ <pt x="386" y="514" on="1"/>
+ <pt x="455" y="441" on="0"/>
+ <pt x="564" y="441" on="1"/>
+ <pt x="673" y="441" on="0"/>
+ <pt x="744" y="516" on="1"/>
+ <pt x="815" y="590" on="0"/>
+ <pt x="815" y="708" on="1"/>
+ <pt x="815" y="819" on="0"/>
+ <pt x="759" y="893" on="1"/>
+ <pt x="687" y="987" on="0"/>
+ </contour>
+ <contour>
+ <pt x="202" y="1283" on="1"/>
+ <pt x="458" y="1604" on="1"/>
+ <pt x="677" y="1604" on="1"/>
+ <pt x="933" y="1283" on="1"/>
+ <pt x="810" y="1283" on="1"/>
+ <pt x="569" y="1485" on="1"/>
+ <pt x="566" y="1485" on="1"/>
+ <pt x="325" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 110 values pushed */
+ 0 0 61 5 24 53 5 13 46 5 36 48 200 13 1 1 76 75 74 73 72 69 16 7 70
+ 1 3 0 24 1 26 24 18 17 15 5 6 1 31 3 0 0 31 41 2 36 41 0 0 32
+ 31 7 1 41 1 4 48 200 71 70 1 52 41 1 2 0 14 0 0 65 19 20 57 28 9
+ 50 28 34 44 28 38 29 15 2 48 200 76 75 74 73 72 71 70 69 52 41 38 34 32 31
+ 26 20 18 17 16 15 9 5 2 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gcommaaccent" xMin="86" yMin="-420" xMax="1160" yMax="1737">
+ <contour>
+ <pt x="266" y="13" on="1"/>
+ <pt x="172" y="72" on="0"/>
+ <pt x="172" y="152" on="1"/>
+ <pt x="172" y="239" on="0"/>
+ <pt x="288" y="345" on="1"/>
+ <pt x="324" y="378" on="1"/>
+ <pt x="233" y="433" on="0"/>
+ <pt x="187" y="495" on="1"/>
+ <pt x="120" y="587" on="0"/>
+ <pt x="120" y="713" on="1"/>
+ <pt x="120" y="893" on="0"/>
+ <pt x="243" y="1001" on="1"/>
+ <pt x="365" y="1110" on="0"/>
+ <pt x="565" y="1110" on="1"/>
+ <pt x="663" y="1110" on="0"/>
+ <pt x="752" y="1078" on="1"/>
+ <pt x="1160" y="1111" on="1"/>
+ <pt x="1101" y="933" on="1"/>
+ <pt x="897" y="965" on="1"/>
+ <pt x="1000" y="833" on="0"/>
+ <pt x="1000" y="704" on="1"/>
+ <pt x="1000" y="538" on="0"/>
+ <pt x="875" y="428" on="1"/>
+ <pt x="749" y="318" on="0"/>
+ <pt x="561" y="318" on="1"/>
+ <pt x="508" y="318" on="0"/>
+ <pt x="441" y="331" on="1"/>
+ <pt x="402" y="297" on="1"/>
+ <pt x="342" y="245" on="0"/>
+ <pt x="342" y="204" on="1"/>
+ <pt x="342" y="148" on="0"/>
+ <pt x="481" y="148" on="1"/>
+ <pt x="794" y="148" on="1"/>
+ <pt x="1104" y="148" on="0"/>
+ <pt x="1104" y="-86" on="1"/>
+ <pt x="1104" y="-420" on="0"/>
+ <pt x="539" y="-420" on="1"/>
+ <pt x="86" y="-420" on="0"/>
+ <pt x="86" y="-203" on="1"/>
+ <pt x="86" y="-106" on="0"/>
+ <pt x="210" y="-24" on="1"/>
+ </contour>
+ <contour>
+ <pt x="404" y="0" on="1"/>
+ <pt x="364" y="-30" on="1"/>
+ <pt x="283" y="-91" on="0"/>
+ <pt x="283" y="-165" on="1"/>
+ <pt x="283" y="-296" on="0"/>
+ <pt x="564" y="-296" on="1"/>
+ <pt x="720" y="-296" on="0"/>
+ <pt x="813" y="-247" on="1"/>
+ <pt x="906" y="-199" on="0"/>
+ <pt x="906" y="-119" on="1"/>
+ <pt x="906" y="0" on="0"/>
+ <pt x="728" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="567" y="987" on="1"/>
+ <pt x="458" y="987" on="0"/>
+ <pt x="388" y="906" on="1"/>
+ <pt x="317" y="825" on="0"/>
+ <pt x="317" y="703" on="1"/>
+ <pt x="317" y="586" on="0"/>
+ <pt x="386" y="514" on="1"/>
+ <pt x="455" y="441" on="0"/>
+ <pt x="564" y="441" on="1"/>
+ <pt x="673" y="441" on="0"/>
+ <pt x="744" y="516" on="1"/>
+ <pt x="815" y="590" on="0"/>
+ <pt x="815" y="708" on="1"/>
+ <pt x="815" y="819" on="0"/>
+ <pt x="759" y="893" on="1"/>
+ <pt x="687" y="987" on="0"/>
+ </contour>
+ <contour>
+ <pt x="659" y="1737" on="1"/>
+ <pt x="659" y="1678" on="1"/>
+ <pt x="582" y="1657" on="0"/>
+ <pt x="582" y="1497" on="1"/>
+ <pt x="582" y="1480" on="1"/>
+ <pt x="659" y="1480" on="1"/>
+ <pt x="659" y="1283" on="1"/>
+ <pt x="461" y="1283" on="1"/>
+ <pt x="461" y="1454" on="1"/>
+ <pt x="462" y="1716" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 135 values pushed */
+ 0 0 61 5 24 53 5 13 46 5 36 48 200 13 1 1 16 75 1 2 0 24 1 26 24
+ 18 17 15 5 6 1 31 3 0 0 31 41 2 77 74 73 72 70 69 6 13 75 36 41 0
+ 0 32 31 7 1 41 1 4 48 200 76 75 1 52 41 1 2 0 14 0 0 65 19 20 57
+ 28 9 50 28 34 44 28 38 29 15 2 48 200 73 72 31 3 69 76 3 52 32 18 17 16
+ 15 6 13 34 20 69 41 26 5 0 4 13 38 9 2 3 12 76 0 0 75 74 70 69 10
+ 3 76 1 4 48 200 77 76 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gdotaccent" xMin="86" yMin="-420" xMax="1160" yMax="1480">
+ <contour>
+ <pt x="266" y="13" on="1"/>
+ <pt x="172" y="72" on="0"/>
+ <pt x="172" y="152" on="1"/>
+ <pt x="172" y="239" on="0"/>
+ <pt x="288" y="345" on="1"/>
+ <pt x="324" y="378" on="1"/>
+ <pt x="233" y="433" on="0"/>
+ <pt x="187" y="495" on="1"/>
+ <pt x="120" y="587" on="0"/>
+ <pt x="120" y="713" on="1"/>
+ <pt x="120" y="893" on="0"/>
+ <pt x="243" y="1001" on="1"/>
+ <pt x="365" y="1110" on="0"/>
+ <pt x="565" y="1110" on="1"/>
+ <pt x="663" y="1110" on="0"/>
+ <pt x="752" y="1078" on="1"/>
+ <pt x="1160" y="1111" on="1"/>
+ <pt x="1101" y="933" on="1"/>
+ <pt x="897" y="965" on="1"/>
+ <pt x="1000" y="833" on="0"/>
+ <pt x="1000" y="704" on="1"/>
+ <pt x="1000" y="538" on="0"/>
+ <pt x="875" y="428" on="1"/>
+ <pt x="749" y="318" on="0"/>
+ <pt x="561" y="318" on="1"/>
+ <pt x="508" y="318" on="0"/>
+ <pt x="441" y="331" on="1"/>
+ <pt x="402" y="297" on="1"/>
+ <pt x="342" y="245" on="0"/>
+ <pt x="342" y="204" on="1"/>
+ <pt x="342" y="148" on="0"/>
+ <pt x="481" y="148" on="1"/>
+ <pt x="794" y="148" on="1"/>
+ <pt x="1104" y="148" on="0"/>
+ <pt x="1104" y="-86" on="1"/>
+ <pt x="1104" y="-420" on="0"/>
+ <pt x="539" y="-420" on="1"/>
+ <pt x="86" y="-420" on="0"/>
+ <pt x="86" y="-203" on="1"/>
+ <pt x="86" y="-106" on="0"/>
+ <pt x="210" y="-24" on="1"/>
+ </contour>
+ <contour>
+ <pt x="404" y="0" on="1"/>
+ <pt x="364" y="-30" on="1"/>
+ <pt x="283" y="-91" on="0"/>
+ <pt x="283" y="-165" on="1"/>
+ <pt x="283" y="-296" on="0"/>
+ <pt x="564" y="-296" on="1"/>
+ <pt x="720" y="-296" on="0"/>
+ <pt x="813" y="-247" on="1"/>
+ <pt x="906" y="-199" on="0"/>
+ <pt x="906" y="-119" on="1"/>
+ <pt x="906" y="0" on="0"/>
+ <pt x="728" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="567" y="987" on="1"/>
+ <pt x="458" y="987" on="0"/>
+ <pt x="388" y="906" on="1"/>
+ <pt x="317" y="825" on="0"/>
+ <pt x="317" y="703" on="1"/>
+ <pt x="317" y="586" on="0"/>
+ <pt x="386" y="514" on="1"/>
+ <pt x="455" y="441" on="0"/>
+ <pt x="564" y="441" on="1"/>
+ <pt x="673" y="441" on="0"/>
+ <pt x="744" y="516" on="1"/>
+ <pt x="815" y="590" on="0"/>
+ <pt x="815" y="708" on="1"/>
+ <pt x="815" y="819" on="0"/>
+ <pt x="759" y="893" on="1"/>
+ <pt x="687" y="987" on="0"/>
+ </contour>
+ <contour>
+ <pt x="461" y="1283" on="1"/>
+ <pt x="461" y="1480" on="1"/>
+ <pt x="658" y="1480" on="1"/>
+ <pt x="658" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 125 values pushed */
+ 0 0 61 5 24 53 5 13 46 5 36 48 200 13 1 1 16 69 1 2 0 24 1 26 24
+ 18 17 15 5 6 1 31 3 0 0 31 41 2 36 41 0 0 72 69 10 1 70 32 31 7
+ 1 41 2 4 48 200 52 41 1 0 71 70 0 14 0 0 65 19 20 57 28 9 50 28 34
+ 44 28 38 29 15 2 48 200 31 71 69 2 52 32 18 17 16 15 6 13 34 20 71 41 26
+ 5 0 4 13 38 9 2 3 12 69 0 0 72 71 10 1 69 1 4 48 200 70 69 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="germandbls" xMin="62" yMin="-25" xMax="1193" yMax="1604">
+ <contour>
+ <pt x="62" y="0" on="1"/>
+ <pt x="62" y="123" on="1"/>
+ <pt x="197" y="123" on="1"/>
+ <pt x="197" y="1103" on="1"/>
+ <pt x="197" y="1293" on="0"/>
+ <pt x="219" y="1373" on="1"/>
+ <pt x="241" y="1453" on="0"/>
+ <pt x="309" y="1512" on="1"/>
+ <pt x="415" y="1604" on="0"/>
+ <pt x="609" y="1604" on="1"/>
+ <pt x="789" y="1604" on="0"/>
+ <pt x="897" y="1539" on="1"/>
+ <pt x="1005" y="1474" on="0"/>
+ <pt x="1005" y="1363" on="1"/>
+ <pt x="1005" y="1245" on="0"/>
+ <pt x="880" y="1142" on="1"/>
+ <pt x="750" y="1035" on="1"/>
+ <pt x="682" y="979" on="0"/>
+ <pt x="682" y="913" on="1"/>
+ <pt x="682" y="844" on="0"/>
+ <pt x="806" y="751" on="1"/>
+ <pt x="941" y="650" on="1"/>
+ <pt x="1104" y="528" on="0"/>
+ <pt x="1147" y="468" on="1"/>
+ <pt x="1193" y="403" on="0"/>
+ <pt x="1193" y="300" on="1"/>
+ <pt x="1193" y="155" on="0"/>
+ <pt x="1099" y="65" on="1"/>
+ <pt x="1005" y="-25" on="0"/>
+ <pt x="847" y="-25" on="1"/>
+ <pt x="733" y="-25" on="0"/>
+ <pt x="604" y="12" on="1"/>
+ <pt x="604" y="290" on="1"/>
+ <pt x="715" y="290" on="1"/>
+ <pt x="740" y="142" on="1"/>
+ <pt x="812" y="99" on="0"/>
+ <pt x="875" y="99" on="1"/>
+ <pt x="1026" y="99" on="0"/>
+ <pt x="1026" y="250" on="1"/>
+ <pt x="1026" y="357" on="0"/>
+ <pt x="916" y="439" on="1"/>
+ <pt x="817" y="513" on="1"/>
+ <pt x="693" y="606" on="1"/>
+ <pt x="572" y="697" on="0"/>
+ <pt x="538" y="742" on="1"/>
+ <pt x="503" y="789" on="0"/>
+ <pt x="503" y="854" on="1"/>
+ <pt x="503" y="961" on="0"/>
+ <pt x="606" y="1065" on="1"/>
+ <pt x="704" y="1164" on="1"/>
+ <pt x="808" y="1269" on="0"/>
+ <pt x="808" y="1359" on="1"/>
+ <pt x="808" y="1481" on="0"/>
+ <pt x="618" y="1481" on="1"/>
+ <pt x="496" y="1481" on="0"/>
+ <pt x="445" y="1430" on="1"/>
+ <pt x="395" y="1380" on="0"/>
+ <pt x="395" y="1256" on="1"/>
+ <pt x="395" y="123" on="1"/>
+ <pt x="518" y="123" on="1"/>
+ <pt x="518" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 53 5 9 36 5 29 48 200 29 2 59 58 57 34 33 32 31 3 2 1 10 13 9
+ 0 60 0 1 0 14 0 0 51 28 13 38 15 25 18 13 46 48 200 46 60 59 46 3 31
+ 57 3 34 33 2 13 25 13 31 1 0 2 0 0 58 57 10 1 2 1 4 48 200 32 31
+ 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="grave" xMin="392" yMin="1283" xMax="836" yMax="1604">
+ <contour>
+ <pt x="836" y="1283" on="1"/>
+ <pt x="713" y="1283" on="1"/>
+ <pt x="392" y="1604" on="1"/>
+ <pt x="620" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 12 values pushed */
+ 1 0 2 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="greater" xMin="99" yMin="0" xMax="1131" yMax="1234">
+ <contour>
+ <pt x="99" y="0" on="1"/>
+ <pt x="99" y="173" on="1"/>
+ <pt x="842" y="617" on="1"/>
+ <pt x="99" y="1061" on="1"/>
+ <pt x="99" y="1234" on="1"/>
+ <pt x="1131" y="617" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 18 values pushed */
+ 5 4 3 2 1 0 14 5 2 2 13 0 4 3 1 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guillemotleft" xMin="82" yMin="99" xMax="1106" yMax="987">
+ <contour>
+ <pt x="1106" y="185" on="1"/>
+ <pt x="1020" y="99" on="1"/>
+ <pt x="575" y="543" on="1"/>
+ <pt x="1020" y="987" on="1"/>
+ <pt x="1106" y="901" on="1"/>
+ <pt x="822" y="543" on="1"/>
+ </contour>
+ <contour>
+ <pt x="613" y="185" on="1"/>
+ <pt x="526" y="99" on="1"/>
+ <pt x="82" y="543" on="1"/>
+ <pt x="526" y="987" on="1"/>
+ <pt x="613" y="901" on="1"/>
+ <pt x="329" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 11 10 9 8 7 6 5 4 3 2 1 0 14 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guillemotright" xMin="123" yMin="99" xMax="1147" yMax="987">
+ <contour>
+ <pt x="123" y="185" on="1"/>
+ <pt x="407" y="543" on="1"/>
+ <pt x="123" y="901" on="1"/>
+ <pt x="209" y="987" on="1"/>
+ <pt x="653" y="543" on="1"/>
+ <pt x="209" y="99" on="1"/>
+ </contour>
+ <contour>
+ <pt x="616" y="185" on="1"/>
+ <pt x="900" y="543" on="1"/>
+ <pt x="616" y="901" on="1"/>
+ <pt x="703" y="987" on="1"/>
+ <pt x="1147" y="543" on="1"/>
+ <pt x="703" y="99" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 11 10 9 8 7 6 5 4 3 2 1 0 14 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guilsinglleft" xMin="234" yMin="99" xMax="946" yMax="987">
+ <contour>
+ <pt x="946" y="901" on="1"/>
+ <pt x="508" y="543" on="1"/>
+ <pt x="946" y="185" on="1"/>
+ <pt x="860" y="99" on="1"/>
+ <pt x="234" y="543" on="1"/>
+ <pt x="860" y="987" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 5 4 3 2 1 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guilsinglright" xMin="283" yMin="99" xMax="995" yMax="987">
+ <contour>
+ <pt x="283" y="185" on="1"/>
+ <pt x="721" y="543" on="1"/>
+ <pt x="283" y="901" on="1"/>
+ <pt x="369" y="987" on="1"/>
+ <pt x="995" y="543" on="1"/>
+ <pt x="369" y="99" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 5 4 3 2 1 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="h" xMin="69" yMin="0" xMax="1167" yMax="1579">
+ <contour>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="1456" on="1"/>
+ <pt x="69" y="1456" on="1"/>
+ <pt x="69" y="1579" on="1"/>
+ <pt x="390" y="1579" on="1"/>
+ <pt x="390" y="876" on="1"/>
+ <pt x="459" y="981" on="0"/>
+ <pt x="527" y="1034" on="1"/>
+ <pt x="623" y="1110" on="0"/>
+ <pt x="742" y="1110" on="1"/>
+ <pt x="1043" y="1110" on="0"/>
+ <pt x="1043" y="722" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="747" y="0" on="1"/>
+ <pt x="747" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="701" on="1"/>
+ <pt x="846" y="956" on="0"/>
+ <pt x="683" y="956" on="1"/>
+ <pt x="533" y="956" on="0"/>
+ <pt x="390" y="704" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 0 0 22 30 11 48 200 11 1 1 4 3 2 5 1 3 0 1 26 25 24 20 19 18 15
+ 14 13 7 2 1 12 1 0 3 0 6 5 1 27 17 16 0 3 2 0 14 27 26 18 17
+ 4 19 6 3 16 15 2 13 13 5 4 1 0 4 13 2 0 0 20 19 10 1 13 25 24
+ 7 6 10 3 2 2 4 48 200 14 13 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hbar" xMin="69" yMin="0" xMax="1167" yMax="1579">
+ <contour>
+ <pt x="390" y="876" on="1"/>
+ <pt x="459" y="981" on="0"/>
+ <pt x="527" y="1034" on="1"/>
+ <pt x="623" y="1110" on="0"/>
+ <pt x="742" y="1110" on="1"/>
+ <pt x="1043" y="1110" on="0"/>
+ <pt x="1043" y="722" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="747" y="0" on="1"/>
+ <pt x="747" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="701" on="1"/>
+ <pt x="846" y="956" on="0"/>
+ <pt x="683" y="956" on="1"/>
+ <pt x="533" y="956" on="0"/>
+ <pt x="390" y="704" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="1234" on="1"/>
+ <pt x="69" y="1234" on="1"/>
+ <pt x="69" y="1332" on="1"/>
+ <pt x="192" y="1332" on="1"/>
+ <pt x="192" y="1456" on="1"/>
+ <pt x="69" y="1456" on="1"/>
+ <pt x="69" y="1579" on="1"/>
+ <pt x="390" y="1579" on="1"/>
+ <pt x="390" y="1332" on="1"/>
+ <pt x="686" y="1332" on="1"/>
+ <pt x="686" y="1234" on="1"/>
+ <pt x="390" y="1234" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 116 values pushed */
+ 0 0 15 30 4 48 200 4 1 29 28 2 30 26 3 1 23 22 19 18 17 13 12 11 8
+ 7 6 0 12 1 9 3 0 0 0 35 34 25 24 33 3 26 1 4 48 200 31 30 1 33
+ 32 27 26 3 21 20 10 9 3 3 0 14 34 33 20 19 11 10 6 12 0 3 9 8 2
+ 13 6 30 29 26 25 22 21 6 13 23 0 0 13 12 10 1 6 35 32 31 18 17 0 10
+ 5 23 2 4 48 200 7 6 1 28 27 24 23 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hcircumflex" xMin="69" yMin="0" xMax="1167" yMax="1999">
+ <contour>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="1456" on="1"/>
+ <pt x="69" y="1456" on="1"/>
+ <pt x="69" y="1579" on="1"/>
+ <pt x="390" y="1579" on="1"/>
+ <pt x="390" y="876" on="1"/>
+ <pt x="459" y="981" on="0"/>
+ <pt x="527" y="1034" on="1"/>
+ <pt x="623" y="1110" on="0"/>
+ <pt x="742" y="1110" on="1"/>
+ <pt x="1043" y="1110" on="0"/>
+ <pt x="1043" y="722" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="747" y="0" on="1"/>
+ <pt x="747" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="701" on="1"/>
+ <pt x="846" y="956" on="0"/>
+ <pt x="683" y="956" on="1"/>
+ <pt x="533" y="956" on="0"/>
+ <pt x="390" y="704" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="254" y="1678" on="1"/>
+ <pt x="510" y="1999" on="1"/>
+ <pt x="729" y="1999" on="1"/>
+ <pt x="985" y="1678" on="1"/>
+ <pt x="862" y="1678" on="1"/>
+ <pt x="621" y="1880" on="1"/>
+ <pt x="618" y="1880" on="1"/>
+ <pt x="377" y="1678" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 121 values pushed */
+ 0 0 22 35 11 48 200 11 1 35 34 33 32 31 28 6 29 5 3 1 4 3 2 5 1
+ 3 0 1 26 25 24 20 19 18 15 14 13 7 2 1 12 1 0 3 0 30 29 1 6 5
+ 1 27 17 16 0 3 3 0 14 32 31 2 13 19 3 34 33 30 29 27 26 18 17 8 19
+ 6 3 35 28 2 6 2 3 16 15 2 13 13 5 4 1 0 4 13 2 0 0 20 19 10
+ 1 13 25 24 7 6 10 3 2 2 4 48 200 14 13 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hungarumlaut" xMin="223" yMin="1283" xMax="1006" yMax="1604">
+ <contour>
+ <pt x="223" y="1283" on="1"/>
+ <pt x="463" y="1604" on="1"/>
+ <pt x="655" y="1604" on="1"/>
+ <pt x="334" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="574" y="1283" on="1"/>
+ <pt x="815" y="1604" on="1"/>
+ <pt x="1006" y="1604" on="1"/>
+ <pt x="685" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 7 4 3 0 4 13 1 6 5 2 1 3 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hyphen" xMin="148" yMin="543" xMax="1081" yMax="691">
+ <contour>
+ <pt x="148" y="543" on="1"/>
+ <pt x="148" y="691" on="1"/>
+ <pt x="1081" y="691" on="1"/>
+ <pt x="1081" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 200 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hyphen#1" xMin="148" yMin="543" xMax="1081" yMax="691">
+ <contour>
+ <pt x="148" y="543" on="1"/>
+ <pt x="148" y="691" on="1"/>
+ <pt x="1081" y="691" on="1"/>
+ <pt x="1081" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 200 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="i" xMin="148" yMin="0" xMax="1105" yMax="1579">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="538" y="123" on="1"/>
+ <pt x="538" y="962" on="1"/>
+ <pt x="148" y="962" on="1"/>
+ <pt x="148" y="1086" on="1"/>
+ <pt x="735" y="1086" on="1"/>
+ <pt x="735" y="123" on="1"/>
+ <pt x="1105" y="123" on="1"/>
+ <pt x="1105" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="528" y="1332" on="1"/>
+ <pt x="528" y="1579" on="1"/>
+ <pt x="750" y="1579" on="1"/>
+ <pt x="750" y="1332" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 13 10 4 1 11 4 3 6 1 5 8 7 2 1 6 3 0 3 4 48 200 12 11
+ 1 9 0 1 2 0 6 5 1 14 9 8 2 13 12 5 4 1 0 4 13 10 0 0 13
+ 12 9 1 10 7 6 10 1 2 2 4 48 200 11 10 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="iacute" xMin="148" yMin="0" xMax="1105" yMax="1604">
+ <component glyphName="dotlessi" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="146" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ibreve" xMin="148" yMin="0" xMax="1105" yMax="1579">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="538" y="123" on="1"/>
+ <pt x="538" y="962" on="1"/>
+ <pt x="148" y="962" on="1"/>
+ <pt x="148" y="1086" on="1"/>
+ <pt x="735" y="1086" on="1"/>
+ <pt x="735" y="123" on="1"/>
+ <pt x="1105" y="123" on="1"/>
+ <pt x="1105" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="279" y="1579" on="1"/>
+ <pt x="402" y="1579" on="1"/>
+ <pt x="450" y="1431" on="0"/>
+ <pt x="624" y="1431" on="1"/>
+ <pt x="799" y="1431" on="0"/>
+ <pt x="847" y="1579" on="1"/>
+ <pt x="970" y="1579" on="1"/>
+ <pt x="948" y="1490" on="0"/>
+ <pt x="921" y="1444" on="1"/>
+ <pt x="830" y="1289" on="0"/>
+ <pt x="629" y="1289" on="1"/>
+ <pt x="476" y="1289" on="0"/>
+ <pt x="387" y="1370" on="1"/>
+ <pt x="332" y="1419" on="0"/>
+ <pt x="304" y="1491" on="1"/>
+ <pt x="293" y="1520" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 13 14 20 48 200 16 15 11 10 4 13 20 5 0 0 4 3 6 1 5 8 7 2
+ 1 6 3 0 2 4 48 200 9 0 1 0 6 5 1 14 16 15 9 8 4 13 6 11 10
+ 5 4 1 0 6 13 2 0 0 7 6 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="icircumflex" xMin="148" yMin="0" xMax="1105" yMax="1604">
+ <component glyphName="dotlessi" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="23" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="idieresis" xMin="148" yMin="0" xMax="1105" yMax="1480">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="538" y="123" on="1"/>
+ <pt x="538" y="962" on="1"/>
+ <pt x="148" y="962" on="1"/>
+ <pt x="148" y="1086" on="1"/>
+ <pt x="735" y="1086" on="1"/>
+ <pt x="735" y="123" on="1"/>
+ <pt x="1105" y="123" on="1"/>
+ <pt x="1105" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="303" y="1283" on="1"/>
+ <pt x="303" y="1480" on="1"/>
+ <pt x="500" y="1480" on="1"/>
+ <pt x="500" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="772" y="1283" on="1"/>
+ <pt x="772" y="1480" on="1"/>
+ <pt x="969" y="1480" on="1"/>
+ <pt x="969" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 17 14 13 10 10 3 11 4 3 6 1 5 8 7 2 1 6 3 0 3 4 48 200
+ 9 0 1 0 16 15 12 11 0 3 6 5 1 14 9 8 2 13 16 5 4 1 0 4 13
+ 10 0 0 15 14 10 1 16 13 12 10 1 10 7 6 10 1 2 3 4 48 200 17 16 1
+ 11 10 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="igrave" xMin="148" yMin="0" xMax="1105" yMax="1604">
+ <component glyphName="dotlessi" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="-101" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ij" xMin="57" yMin="-420" xMax="1056" yMax="1579">
+ <contour>
+ <pt x="57" y="0" on="1"/>
+ <pt x="57" y="123" on="1"/>
+ <pt x="205" y="123" on="1"/>
+ <pt x="205" y="962" on="1"/>
+ <pt x="57" y="962" on="1"/>
+ <pt x="57" y="1086" on="1"/>
+ <pt x="402" y="1086" on="1"/>
+ <pt x="402" y="123" on="1"/>
+ <pt x="550" y="123" on="1"/>
+ <pt x="550" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1056" y="1086" on="1"/>
+ <pt x="1056" y="11" on="1"/>
+ <pt x="1056" y="-420" on="0"/>
+ <pt x="693" y="-420" on="1"/>
+ <pt x="599" y="-420" on="0"/>
+ <pt x="470" y="-383" on="1"/>
+ <pt x="470" y="-173" on="1"/>
+ <pt x="594" y="-173" on="1"/>
+ <pt x="606" y="-290" on="1"/>
+ <pt x="669" y="-321" on="0"/>
+ <pt x="716" y="-321" on="1"/>
+ <pt x="859" y="-321" on="0"/>
+ <pt x="859" y="-82" on="1"/>
+ <pt x="859" y="962" on="1"/>
+ <pt x="662" y="962" on="1"/>
+ <pt x="662" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="180" y="1332" on="1"/>
+ <pt x="180" y="1579" on="1"/>
+ <pt x="402" y="1579" on="1"/>
+ <pt x="402" y="1332" on="1"/>
+ </contour>
+ <contour>
+ <pt x="834" y="1332" on="1"/>
+ <pt x="834" y="1579" on="1"/>
+ <pt x="1056" y="1579" on="1"/>
+ <pt x="1056" y="1332" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 120 values pushed */
+ 0 0 20 17 13 48 200 11 1 0 2 22 18 17 16 15 5 13 13 0 0 0 33 30 29
+ 26 4 3 27 24 23 4 3 6 3 5 8 7 2 1 6 3 0 3 4 48 200 32 31 28
+ 27 3 9 0 1 2 0 25 10 6 5 1 3 14 25 24 18 17 9 8 6 30 15 3 5
+ 4 1 0 4 13 26 0 0 31 30 9 1 10 23 22 10 1 10 29 28 7 6 10 3 2
+ 3 4 48 200 27 26 1 33 32 11 10 3 16 15 1 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="imacron" xMin="148" yMin="0" xMax="1105" yMax="1407">
+ <component glyphName="dotlessi" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="-22" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="iogonek" xMin="148" yMin="-370" xMax="1105" yMax="1579">
+ <component glyphName="i" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="221" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="itilde" xMin="148" yMin="0" xMax="1105" yMax="1518">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="538" y="123" on="1"/>
+ <pt x="538" y="962" on="1"/>
+ <pt x="148" y="962" on="1"/>
+ <pt x="148" y="1086" on="1"/>
+ <pt x="735" y="1086" on="1"/>
+ <pt x="735" y="123" on="1"/>
+ <pt x="1105" y="123" on="1"/>
+ <pt x="1105" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="247" y="1283" on="1"/>
+ <pt x="253" y="1377" on="0"/>
+ <pt x="278" y="1427" on="1"/>
+ <pt x="323" y="1518" on="0"/>
+ <pt x="432" y="1518" on="1"/>
+ <pt x="504" y="1518" on="0"/>
+ <pt x="567" y="1479" on="1"/>
+ <pt x="627" y="1442" on="1"/>
+ <pt x="689" y="1404" on="0"/>
+ <pt x="723" y="1404" on="1"/>
+ <pt x="791" y="1404" on="0"/>
+ <pt x="802" y="1518" on="1"/>
+ <pt x="913" y="1518" on="1"/>
+ <pt x="906" y="1424" on="0"/>
+ <pt x="881" y="1374" on="1"/>
+ <pt x="835" y="1283" on="0"/>
+ <pt x="728" y="1283" on="1"/>
+ <pt x="655" y="1283" on="0"/>
+ <pt x="592" y="1322" on="1"/>
+ <pt x="532" y="1359" on="1"/>
+ <pt x="472" y="1396" on="0"/>
+ <pt x="436" y="1396" on="1"/>
+ <pt x="368" y="1396" on="0"/>
+ <pt x="357" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 31 5 14 19 5 26 48 200 14 0 26 1 33 26 10 3 0 5 3 0 1 22 21
+ 2 13 0 0 0 0 4 3 6 1 5 8 7 2 1 6 3 0 2 4 48 200 9 0 1
+ 0 6 5 1 14 22 21 9 8 4 13 6 33 10 5 4 1 0 6 13 2 0 0 7 6
+ 10 1 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="j" xMin="159" yMin="-420" xMax="915" yMax="1579">
+ <contour>
+ <pt x="159" y="-344" on="1"/>
+ <pt x="159" y="-25" on="1"/>
+ <pt x="282" y="-25" on="1"/>
+ <pt x="313" y="-243" on="1"/>
+ <pt x="381" y="-296" on="0"/>
+ <pt x="460" y="-296" on="1"/>
+ <pt x="592" y="-296" on="0"/>
+ <pt x="648" y="-200" on="1"/>
+ <pt x="705" y="-104" on="0"/>
+ <pt x="705" y="127" on="1"/>
+ <pt x="705" y="962" on="1"/>
+ <pt x="261" y="962" on="1"/>
+ <pt x="261" y="1086" on="1"/>
+ <pt x="903" y="1086" on="1"/>
+ <pt x="903" y="66" on="1"/>
+ <pt x="903" y="-164" on="0"/>
+ <pt x="790" y="-292" on="1"/>
+ <pt x="677" y="-420" on="0"/>
+ <pt x="476" y="-420" on="1"/>
+ <pt x="337" y="-420" on="0"/>
+ </contour>
+ <contour>
+ <pt x="693" y="1332" on="1"/>
+ <pt x="693" y="1579" on="1"/>
+ <pt x="915" y="1579" on="1"/>
+ <pt x="915" y="1332" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 0 0 5 5 18 48 200 1 14 9 2 10 2 3 0 1 3 2 1 0 4 13 18 2 0
+ 0 0 23 20 4 1 21 11 10 6 1 12 2 4 48 200 22 21 1 0 13 12 1 14 12
+ 11 3 2 4 20 0 3 0 0 21 20 9 1 22 10 9 10 1 13 2 4 48 200 23 22
+ 1 14 13 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="jcircumflex" xMin="159" yMin="-420" xMax="1092" yMax="1604">
+ <contour>
+ <pt x="159" y="-344" on="1"/>
+ <pt x="159" y="-25" on="1"/>
+ <pt x="282" y="-25" on="1"/>
+ <pt x="313" y="-243" on="1"/>
+ <pt x="381" y="-296" on="0"/>
+ <pt x="460" y="-296" on="1"/>
+ <pt x="592" y="-296" on="0"/>
+ <pt x="648" y="-200" on="1"/>
+ <pt x="705" y="-104" on="0"/>
+ <pt x="705" y="127" on="1"/>
+ <pt x="705" y="962" on="1"/>
+ <pt x="261" y="962" on="1"/>
+ <pt x="261" y="1086" on="1"/>
+ <pt x="903" y="1086" on="1"/>
+ <pt x="903" y="66" on="1"/>
+ <pt x="903" y="-164" on="0"/>
+ <pt x="790" y="-292" on="1"/>
+ <pt x="677" y="-420" on="0"/>
+ <pt x="476" y="-420" on="1"/>
+ <pt x="337" y="-420" on="0"/>
+ </contour>
+ <contour>
+ <pt x="360" y="1283" on="1"/>
+ <pt x="617" y="1604" on="1"/>
+ <pt x="835" y="1604" on="1"/>
+ <pt x="1092" y="1283" on="1"/>
+ <pt x="968" y="1283" on="1"/>
+ <pt x="727" y="1485" on="1"/>
+ <pt x="725" y="1485" on="1"/>
+ <pt x="484" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 96 values pushed */
+ 0 0 5 5 18 48 200 27 26 25 24 23 20 6 21 12 3 1 14 9 2 10 2 3 0
+ 1 3 2 1 0 4 13 18 2 0 0 0 11 10 6 1 12 1 4 48 200 22 21 1 0
+ 13 12 1 14 26 25 22 3 13 9 3 27 21 20 12 11 3 2 7 9 0 3 24 23 2
+ 13 13 0 0 10 9 10 1 13 1 4 48 200 14 13 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="k" xMin="74" yMin="0" xMax="1176" yMax="1579">
+ <contour>
+ <pt x="821" y="0" on="1"/>
+ <pt x="821" y="123" on="1"/>
+ <pt x="419" y="524" on="1"/>
+ <pt x="395" y="524" on="1"/>
+ <pt x="395" y="123" on="1"/>
+ <pt x="494" y="123" on="1"/>
+ <pt x="494" y="0" on="1"/>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="197" y="123" on="1"/>
+ <pt x="197" y="1456" on="1"/>
+ <pt x="74" y="1456" on="1"/>
+ <pt x="74" y="1579" on="1"/>
+ <pt x="395" y="1579" on="1"/>
+ <pt x="395" y="592" on="1"/>
+ <pt x="419" y="592" on="1"/>
+ <pt x="777" y="962" on="1"/>
+ <pt x="661" y="962" on="1"/>
+ <pt x="661" y="1086" on="1"/>
+ <pt x="1093" y="1086" on="1"/>
+ <pt x="1093" y="962" on="1"/>
+ <pt x="952" y="962" on="1"/>
+ <pt x="589" y="600" on="1"/>
+ <pt x="1077" y="123" on="1"/>
+ <pt x="1176" y="123" on="1"/>
+ <pt x="1176" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 11 10 2 12 18 3 24 23 22 15 14 9 8 5 4 3 2 1 12 16 0 3 0 0 21
+ 20 17 16 6 3 18 1 4 48 200 13 12 1 25 7 6 0 3 2 0 19 18 1 14 25
+ 24 23 22 21 20 19 18 17 16 15 6 5 2 1 0 16 13 3 12 11 8 7 4 13 9
+ 0 0 14 13 4 3 10 3 9 1 4 48 200 10 9 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="kcommaaccent" xMin="74" yMin="-432" xMax="1176" yMax="1579">
+ <component glyphName="k" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="29" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="kgreenlandic" xMin="74" yMin="0" xMax="1176" yMax="1086">
+ <contour>
+ <pt x="821" y="0" on="1"/>
+ <pt x="821" y="123" on="1"/>
+ <pt x="419" y="524" on="1"/>
+ <pt x="395" y="524" on="1"/>
+ <pt x="395" y="123" on="1"/>
+ <pt x="494" y="123" on="1"/>
+ <pt x="494" y="0" on="1"/>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="197" y="123" on="1"/>
+ <pt x="197" y="962" on="1"/>
+ <pt x="74" y="962" on="1"/>
+ <pt x="74" y="1086" on="1"/>
+ <pt x="395" y="1086" on="1"/>
+ <pt x="395" y="592" on="1"/>
+ <pt x="419" y="592" on="1"/>
+ <pt x="777" y="962" on="1"/>
+ <pt x="661" y="962" on="1"/>
+ <pt x="661" y="1086" on="1"/>
+ <pt x="1093" y="1086" on="1"/>
+ <pt x="1093" y="962" on="1"/>
+ <pt x="952" y="962" on="1"/>
+ <pt x="589" y="600" on="1"/>
+ <pt x="1077" y="123" on="1"/>
+ <pt x="1176" y="123" on="1"/>
+ <pt x="1176" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 24 23 22 15 14 9 8 5 4 3 2 1 12 10 0 3 0 0 21 20 17 16 11 10 6
+ 5 12 1 4 48 200 25 7 6 0 3 0 19 18 13 12 1 3 14 25 24 23 22 21 20
+ 19 18 17 16 15 6 5 2 1 0 16 13 3 12 11 8 7 4 13 9 0 0 14 13 4
+ 3 10 3 9 1 4 48 200 10 9 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="l" xMin="148" yMin="0" xMax="1105" yMax="1579">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="538" y="123" on="1"/>
+ <pt x="538" y="1456" on="1"/>
+ <pt x="148" y="1456" on="1"/>
+ <pt x="148" y="1579" on="1"/>
+ <pt x="735" y="1579" on="1"/>
+ <pt x="735" y="123" on="1"/>
+ <pt x="1105" y="123" on="1"/>
+ <pt x="1105" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 0 0 4 3 6 1 5 8 7 2 1 6 3 0 2 4 48 200 6 5 1 9 0 1 2
+ 0 14 9 8 2 13 6 5 4 1 0 4 13 2 0 0 7 6 10 1 2 1 4 48 200
+ 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lacute" xMin="148" yMin="0" xMax="1105" yMax="1999">
+ <component glyphName="l" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="146" y="395" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="lcaron" xMin="123" yMin="0" xMax="1105" yMax="1579">
+ <contour>
+ <pt x="123" y="0" on="1"/>
+ <pt x="123" y="123" on="1"/>
+ <pt x="513" y="123" on="1"/>
+ <pt x="513" y="1456" on="1"/>
+ <pt x="123" y="1456" on="1"/>
+ <pt x="123" y="1579" on="1"/>
+ <pt x="710" y="1579" on="1"/>
+ <pt x="710" y="123" on="1"/>
+ <pt x="1080" y="123" on="1"/>
+ <pt x="1080" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="908" y="1125" on="1"/>
+ <pt x="908" y="1184" on="1"/>
+ <pt x="984" y="1205" on="0"/>
+ <pt x="984" y="1365" on="1"/>
+ <pt x="984" y="1382" on="1"/>
+ <pt x="908" y="1382" on="1"/>
+ <pt x="908" y="1579" on="1"/>
+ <pt x="1105" y="1579" on="1"/>
+ <pt x="1105" y="1408" on="1"/>
+ <pt x="1104" y="1146" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 18 15 14 13 11 10 6 3 1 3 0 0 4 3 6 1 5 8 7 2 1 6 3 0 2
+ 4 48 200 17 16 6 5 3 9 0 1 2 0 14 14 13 9 8 4 17 10 3 5 4 1
+ 0 4 13 2 0 0 16 15 11 10 10 3 17 7 6 10 1 2 2 4 48 200 18 17 1
+ 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lcommaaccent" xMin="148" yMin="-432" xMax="1105" yMax="1579">
+ <component glyphName="l" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="37" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ldot" xMin="123" yMin="0" xMax="1228" yMax="1579">
+ <contour>
+ <pt x="123" y="0" on="1"/>
+ <pt x="123" y="123" on="1"/>
+ <pt x="513" y="123" on="1"/>
+ <pt x="513" y="1456" on="1"/>
+ <pt x="123" y="1456" on="1"/>
+ <pt x="123" y="1579" on="1"/>
+ <pt x="710" y="1579" on="1"/>
+ <pt x="710" y="123" on="1"/>
+ <pt x="1080" y="123" on="1"/>
+ <pt x="1080" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1031" y="666" on="1"/>
+ <pt x="1031" y="863" on="1"/>
+ <pt x="1228" y="863" on="1"/>
+ <pt x="1228" y="666" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 13 10 10 1 11 4 3 6 1 5 8 7 2 1 6 3 0 3 4 48 200 12 11
+ 1 6 5 1 9 0 1 3 0 14 9 8 2 12 10 3 5 4 1 0 4 13 2 0 0
+ 11 10 10 1 12 7 6 10 1 2 2 4 48 200 13 12 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="less" xMin="99" yMin="0" xMax="1131" yMax="1234">
+ <contour>
+ <pt x="1131" y="0" on="1"/>
+ <pt x="99" y="617" on="1"/>
+ <pt x="1131" y="1234" on="1"/>
+ <pt x="1131" y="1061" on="1"/>
+ <pt x="388" y="617" on="1"/>
+ <pt x="1131" y="173" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 16 values pushed */
+ 5 4 3 2 1 0 14 4 1 0 5 3 2 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="logicalnot" xMin="99" yMin="197" xMax="1130" yMax="691">
+ <contour>
+ <pt x="982" y="197" on="1"/>
+ <pt x="982" y="543" on="1"/>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="691" on="1"/>
+ <pt x="1130" y="691" on="1"/>
+ <pt x="1130" y="543" on="1"/>
+ <pt x="1130" y="543" on="1"/>
+ <pt x="1130" y="197" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 6 5 2 1 16 3 3 1 4 48 200 4 3 1 7 0 1 2 0 14 0 0 1
+ 0 16 1 4 1 4 48 200 7 6 5 4 3 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="longs" xMin="148" yMin="0" xMax="1167" yMax="1604">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="419" y="123" on="1"/>
+ <pt x="419" y="925" on="1"/>
+ <pt x="148" y="925" on="1"/>
+ <pt x="148" y="1061" on="1"/>
+ <pt x="419" y="1061" on="1"/>
+ <pt x="419" y="1179" on="1"/>
+ <pt x="419" y="1404" on="0"/>
+ <pt x="510" y="1504" on="1"/>
+ <pt x="601" y="1604" on="0"/>
+ <pt x="803" y="1604" on="1"/>
+ <pt x="974" y="1604" on="0"/>
+ <pt x="1167" y="1524" on="1"/>
+ <pt x="1167" y="1277" on="1"/>
+ <pt x="1044" y="1277" on="1"/>
+ <pt x="1013" y="1433" on="1"/>
+ <pt x="912" y="1480" on="0"/>
+ <pt x="829" y="1480" on="1"/>
+ <pt x="710" y="1480" on="0"/>
+ <pt x="664" y="1420" on="1"/>
+ <pt x="617" y="1360" on="0"/>
+ <pt x="617" y="1201" on="1"/>
+ <pt x="617" y="123" on="1"/>
+ <pt x="987" y="123" on="1"/>
+ <pt x="987" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 18 5 11 48 200 22 16 15 14 13 7 6 13 11 5 0 0 4 3 20 1 5 24
+ 23 2 1 6 3 0 2 4 48 200 6 5 1 25 0 1 2 0 14 25 24 16 15 4 13
+ 22 3 5 4 1 0 4 13 2 0 0 23 22 10 1 2 1 4 48 200 14 13 1 7 6
+ 3 2 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lslash" xMin="148" yMin="0" xMax="1105" yMax="1579">
+ <contour>
+ <pt x="148" y="0" on="1"/>
+ <pt x="148" y="123" on="1"/>
+ <pt x="538" y="123" on="1"/>
+ <pt x="538" y="728" on="1"/>
+ <pt x="247" y="583" on="1"/>
+ <pt x="247" y="721" on="1"/>
+ <pt x="538" y="866" on="1"/>
+ <pt x="538" y="1456" on="1"/>
+ <pt x="148" y="1456" on="1"/>
+ <pt x="148" y="1579" on="1"/>
+ <pt x="735" y="1579" on="1"/>
+ <pt x="735" y="965" on="1"/>
+ <pt x="1026" y="1110" on="1"/>
+ <pt x="1026" y="973" on="1"/>
+ <pt x="735" y="827" on="1"/>
+ <pt x="735" y="123" on="1"/>
+ <pt x="1105" y="123" on="1"/>
+ <pt x="1105" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 14 13 12 11 6 5 4 3 8 7 1 3 0 0 8 7 6 1 9 16 15 2 1 6 3
+ 0 2 4 48 200 10 9 1 17 0 1 2 0 14 17 16 2 13 12 9 8 1 0 4 13
+ 4 0 0 15 14 11 10 10 3 2 1 4 48 200 13 12 1 7 6 3 2 3 5 4 1
+ 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="m" xMin="26" yMin="0" xMax="1204" yMax="1110">
+ <contour>
+ <pt x="26" y="0" on="1"/>
+ <pt x="26" y="123" on="1"/>
+ <pt x="100" y="123" on="1"/>
+ <pt x="100" y="962" on="1"/>
+ <pt x="26" y="962" on="1"/>
+ <pt x="26" y="1086" on="1"/>
+ <pt x="279" y="1086" on="1"/>
+ <pt x="279" y="879" on="1"/>
+ <pt x="346" y="1009" on="0"/>
+ <pt x="389" y="1055" on="1"/>
+ <pt x="441" y="1110" on="0"/>
+ <pt x="517" y="1110" on="1"/>
+ <pt x="617" y="1110" on="0"/>
+ <pt x="663" y="1017" on="1"/>
+ <pt x="687" y="969" on="0"/>
+ <pt x="698" y="879" on="1"/>
+ <pt x="740" y="983" on="0"/>
+ <pt x="787" y="1035" on="1"/>
+ <pt x="853" y="1110" on="0"/>
+ <pt x="943" y="1110" on="1"/>
+ <pt x="1130" y="1110" on="0"/>
+ <pt x="1130" y="837" on="1"/>
+ <pt x="1130" y="123" on="1"/>
+ <pt x="1204" y="123" on="1"/>
+ <pt x="1204" y="0" on="1"/>
+ <pt x="951" y="0" on="1"/>
+ <pt x="951" y="752" on="1"/>
+ <pt x="951" y="956" on="0"/>
+ <pt x="886" y="956" on="1"/>
+ <pt x="838" y="956" on="0"/>
+ <pt x="779" y="870" on="1"/>
+ <pt x="748" y="825" on="0"/>
+ <pt x="731" y="783" on="1"/>
+ <pt x="705" y="718" on="0"/>
+ <pt x="705" y="691" on="1"/>
+ <pt x="705" y="123" on="1"/>
+ <pt x="779" y="123" on="1"/>
+ <pt x="779" y="0" on="1"/>
+ <pt x="526" y="0" on="1"/>
+ <pt x="526" y="798" on="1"/>
+ <pt x="526" y="956" on="0"/>
+ <pt x="460" y="956" on="1"/>
+ <pt x="373" y="956" on="0"/>
+ <pt x="279" y="691" on="1"/>
+ <pt x="279" y="123" on="1"/>
+ <pt x="353" y="123" on="1"/>
+ <pt x="353" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 41 30 11 28 30 19 48 200 19 1 11 1 45 44 43 39 36 35 34 26 23 22 21
+ 15 7 4 3 2 1 17 5 0 3 46 38 37 25 24 0 5 0 6 5 1 14 37 36 2
+ 25 34 3 15 34 38 2 46 45 2 38 6 3 24 23 2 13 21 5 4 1 0 4 13 2
+ 0 0 26 25 12 1 21 35 34 12 1 38 44 43 7 6 12 3 2 3 4 48 200 22 21
+ 1 39 38 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="macron" xMin="269" yMin="1283" xMax="960" yMax="1407">
+ <contour>
+ <pt x="269" y="1283" on="1"/>
+ <pt x="269" y="1407" on="1"/>
+ <pt x="960" y="1407" on="1"/>
+ <pt x="960" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 200 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="macron#1" xMin="0" yMin="1456" xMax="1229" yMax="1604">
+ <contour>
+ <pt x="0" y="1604" on="1"/>
+ <pt x="1229" y="1604" on="1"/>
+ <pt x="1229" y="1456" on="1"/>
+ <pt x="0" y="1456" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 2 16 1 0 1 4 48 200 1 0 1 0 14 2 1 1 3 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="minus" xMin="99" yMin="543" xMax="1130" yMax="691">
+ <contour>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="691" on="1"/>
+ <pt x="1130" y="691" on="1"/>
+ <pt x="1130" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 200 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="mu" xMin="68" yMin="-395" xMax="1166" yMax="1086">
+ <contour>
+ <pt x="191" y="962" on="1"/>
+ <pt x="68" y="962" on="1"/>
+ <pt x="68" y="1086" on="1"/>
+ <pt x="389" y="1086" on="1"/>
+ <pt x="389" y="385" on="1"/>
+ <pt x="389" y="130" on="0"/>
+ <pt x="552" y="130" on="1"/>
+ <pt x="701" y="130" on="0"/>
+ <pt x="845" y="382" on="1"/>
+ <pt x="845" y="962" on="1"/>
+ <pt x="734" y="962" on="1"/>
+ <pt x="734" y="1086" on="1"/>
+ <pt x="1043" y="1086" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1166" y="123" on="1"/>
+ <pt x="1166" y="0" on="1"/>
+ <pt x="845" y="0" on="1"/>
+ <pt x="845" y="209" on="1"/>
+ <pt x="767" y="89" on="0"/>
+ <pt x="700" y="37" on="1"/>
+ <pt x="620" y="-25" on="0"/>
+ <pt x="499" y="-25" on="1"/>
+ <pt x="449" y="-25" on="0"/>
+ <pt x="389" y="-10" on="1"/>
+ <pt x="389" y="-395" on="1"/>
+ <pt x="191" y="-395" on="1"/>
+ <pt x="191" y="363" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 6 30 21 48 200 21 2 26 17 14 13 10 9 8 4 1 0 10 2 15 3 23 15
+ 24 2 16 15 1 25 24 1 2 0 12 11 3 2 1 3 14 11 10 2 8 3 3 15 14
+ 2 13 12 2 1 0 0 0 17 16 9 8 10 3 12 24 23 4 3 10 3 0 2 4 48
+ 200 13 12 1 26 25 0 2 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="multiply" xMin="99" yMin="0" xMax="1131" yMax="1032">
+ <contour>
+ <pt x="99" y="105" on="1"/>
+ <pt x="510" y="516" on="1"/>
+ <pt x="99" y="927" on="1"/>
+ <pt x="204" y="1032" on="1"/>
+ <pt x="615" y="620" on="1"/>
+ <pt x="1026" y="1032" on="1"/>
+ <pt x="1131" y="927" on="1"/>
+ <pt x="719" y="516" on="1"/>
+ <pt x="1131" y="105" on="1"/>
+ <pt x="1026" y="0" on="1"/>
+ <pt x="615" y="411" on="1"/>
+ <pt x="204" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 33 values pushed */
+ 1 10 8 7 6 5 4 3 2 1 0 10 13 2 0 1 11 9 2 0 14 11 10 9 8
+ 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="n" xMin="69" yMin="0" xMax="1167" yMax="1110">
+ <contour>
+ <pt x="69" y="0" on="1"/>
+ <pt x="69" y="123" on="1"/>
+ <pt x="192" y="123" on="1"/>
+ <pt x="192" y="962" on="1"/>
+ <pt x="69" y="962" on="1"/>
+ <pt x="69" y="1086" on="1"/>
+ <pt x="390" y="1086" on="1"/>
+ <pt x="390" y="876" on="1"/>
+ <pt x="459" y="981" on="0"/>
+ <pt x="527" y="1034" on="1"/>
+ <pt x="623" y="1110" on="0"/>
+ <pt x="742" y="1110" on="1"/>
+ <pt x="1043" y="1110" on="0"/>
+ <pt x="1043" y="722" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1167" y="123" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ <pt x="747" y="0" on="1"/>
+ <pt x="747" y="123" on="1"/>
+ <pt x="846" y="123" on="1"/>
+ <pt x="846" y="701" on="1"/>
+ <pt x="846" y="956" on="0"/>
+ <pt x="683" y="956" on="1"/>
+ <pt x="533" y="956" on="0"/>
+ <pt x="390" y="704" on="1"/>
+ <pt x="390" y="123" on="1"/>
+ <pt x="501" y="123" on="1"/>
+ <pt x="501" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 22 30 11 48 200 11 1 26 25 24 20 19 18 15 14 13 7 4 3 2 1 14 5
+ 0 3 27 17 16 0 3 0 6 5 1 14 27 26 18 17 4 19 6 3 16 15 2 13 13
+ 5 4 1 0 4 13 2 0 0 20 19 10 1 13 25 24 7 6 10 3 2 2 4 48 200
+ 14 13 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nacute" xMin="69" yMin="0" xMax="1167" yMax="1604">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="96" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="napostrophe" xMin="8" yMin="0" xMax="1168" yMax="1579">
+ <contour>
+ <pt x="70" y="0" on="1"/>
+ <pt x="70" y="123" on="1"/>
+ <pt x="193" y="123" on="1"/>
+ <pt x="193" y="962" on="1"/>
+ <pt x="70" y="962" on="1"/>
+ <pt x="70" y="1086" on="1"/>
+ <pt x="391" y="1086" on="1"/>
+ <pt x="391" y="876" on="1"/>
+ <pt x="460" y="981" on="0"/>
+ <pt x="528" y="1034" on="1"/>
+ <pt x="624" y="1110" on="0"/>
+ <pt x="743" y="1110" on="1"/>
+ <pt x="1044" y="1110" on="0"/>
+ <pt x="1044" y="722" on="1"/>
+ <pt x="1044" y="123" on="1"/>
+ <pt x="1168" y="123" on="1"/>
+ <pt x="1168" y="0" on="1"/>
+ <pt x="748" y="0" on="1"/>
+ <pt x="748" y="123" on="1"/>
+ <pt x="847" y="123" on="1"/>
+ <pt x="847" y="701" on="1"/>
+ <pt x="847" y="956" on="0"/>
+ <pt x="684" y="956" on="1"/>
+ <pt x="534" y="956" on="0"/>
+ <pt x="391" y="704" on="1"/>
+ <pt x="391" y="123" on="1"/>
+ <pt x="502" y="123" on="1"/>
+ <pt x="502" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="8" y="1125" on="1"/>
+ <pt x="8" y="1184" on="1"/>
+ <pt x="84" y="1205" on="0"/>
+ <pt x="84" y="1365" on="1"/>
+ <pt x="84" y="1382" on="1"/>
+ <pt x="8" y="1382" on="1"/>
+ <pt x="8" y="1579" on="1"/>
+ <pt x="205" y="1579" on="1"/>
+ <pt x="205" y="1408" on="1"/>
+ <pt x="204" y="1146" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 110 values pushed */
+ 0 0 22 30 11 48 200 11 1 36 33 32 31 29 28 6 34 5 3 26 25 24 20 19 18
+ 15 14 13 7 4 3 2 1 14 5 0 3 35 34 1 27 17 16 0 3 2 0 6 5 1
+ 14 27 26 18 17 4 19 6 3 32 31 5 4 1 0 6 2 28 3 16 15 2 13 13 0
+ 0 36 35 10 1 28 20 19 10 1 13 25 24 7 6 10 3 2 3 4 48 200 34 33 29
+ 28 3 14 13 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nbhyphen" xMin="148" yMin="543" xMax="1081" yMax="691">
+ <contour>
+ <pt x="148" y="543" on="1"/>
+ <pt x="148" y="691" on="1"/>
+ <pt x="1081" y="691" on="1"/>
+ <pt x="1081" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 200 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ncaron" xMin="69" yMin="0" xMax="1167" yMax="1604">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="-16" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ncommaaccent" xMin="69" yMin="-432" xMax="1167" yMax="1110">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="24" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="nine" xMin="96" yMin="-37" xMax="1106" yMax="1517">
+ <contour>
+ <pt x="893" y="707" on="1"/>
+ <pt x="829" y="620" on="0"/>
+ <pt x="759" y="576" on="1"/>
+ <pt x="656" y="512" on="0"/>
+ <pt x="521" y="512" on="1"/>
+ <pt x="331" y="512" on="0"/>
+ <pt x="214" y="646" on="1"/>
+ <pt x="96" y="779" on="0"/>
+ <pt x="96" y="994" on="1"/>
+ <pt x="96" y="1226" on="0"/>
+ <pt x="233" y="1371" on="1"/>
+ <pt x="370" y="1517" on="0"/>
+ <pt x="586" y="1517" on="1"/>
+ <pt x="830" y="1517" on="0"/>
+ <pt x="968" y="1319" on="1"/>
+ <pt x="1106" y="1121" on="0"/>
+ <pt x="1106" y="770" on="1"/>
+ <pt x="1106" y="385" on="0"/>
+ <pt x="943" y="174" on="1"/>
+ <pt x="780" y="-37" on="0"/>
+ <pt x="490" y="-37" on="1"/>
+ <pt x="362" y="-37" on="0"/>
+ <pt x="164" y="34" on="1"/>
+ <pt x="164" y="351" on="1"/>
+ <pt x="287" y="351" on="1"/>
+ <pt x="311" y="141" on="1"/>
+ <pt x="397" y="86" on="0"/>
+ <pt x="489" y="86" on="1"/>
+ <pt x="703" y="86" on="0"/>
+ <pt x="813" y="302" on="1"/>
+ <pt x="890" y="453" on="0"/>
+ </contour>
+ <contour>
+ <pt x="560" y="1394" on="1"/>
+ <pt x="450" y="1394" on="0"/>
+ <pt x="382" y="1315" on="1"/>
+ <pt x="296" y="1215" on="0"/>
+ <pt x="296" y="1017" on="1"/>
+ <pt x="296" y="641" on="0"/>
+ <pt x="559" y="641" on="1"/>
+ <pt x="693" y="641" on="0"/>
+ <pt x="786" y="744" on="1"/>
+ <pt x="878" y="846" on="0"/>
+ <pt x="878" y="1000" on="1"/>
+ <pt x="878" y="1160" on="0"/>
+ <pt x="784" y="1277" on="1"/>
+ <pt x="690" y="1394" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 37 25 4 31 5 12 27 5 20 48 200 20 2 12 0 4 1 1 25 24 23 22 4
+ 0 6 0 2 3 0 0 14 0 0 41 26 16 35 24 8 48 200 25 24 0 3 13 16 22
+ 8 22 23 22 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nonbreakingspace"/><!-- contains no outline data -->
+
+ <TTGlyph name="ntilde" xMin="69" yMin="0" xMax="1167" yMax="1518">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="-2" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="numbersign" xMin="41" yMin="0" xMax="1189" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="276" y="444" on="1"/>
+ <pt x="41" y="444" on="1"/>
+ <pt x="72" y="568" on="1"/>
+ <pt x="307" y="568" on="1"/>
+ <pt x="393" y="913" on="1"/>
+ <pt x="109" y="913" on="1"/>
+ <pt x="140" y="1036" on="1"/>
+ <pt x="424" y="1036" on="1"/>
+ <pt x="535" y="1480" on="1"/>
+ <pt x="671" y="1480" on="1"/>
+ <pt x="560" y="1036" on="1"/>
+ <pt x="819" y="1036" on="1"/>
+ <pt x="930" y="1480" on="1"/>
+ <pt x="1066" y="1480" on="1"/>
+ <pt x="955" y="1036" on="1"/>
+ <pt x="1189" y="1036" on="1"/>
+ <pt x="1158" y="913" on="1"/>
+ <pt x="924" y="913" on="1"/>
+ <pt x="837" y="568" on="1"/>
+ <pt x="1121" y="568" on="1"/>
+ <pt x="1090" y="444" on="1"/>
+ <pt x="807" y="444" on="1"/>
+ <pt x="696" y="0" on="1"/>
+ <pt x="560" y="0" on="1"/>
+ <pt x="671" y="444" on="1"/>
+ <pt x="412" y="444" on="1"/>
+ <pt x="301" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="442" y="568" on="1"/>
+ <pt x="702" y="568" on="1"/>
+ <pt x="788" y="913" on="1"/>
+ <pt x="529" y="913" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 14 13 10 9 4 13 7 27 24 23 0 4 13 1 0 0 31 30 18 17 6 5 6 5 7
+ 29 28 20 19 4 3 6 5 1 2 4 48 200 16 15 12 11 8 7 5 26 25 22 21 2
+ 1 5 2 0 14 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
+ 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="o" xMin="111" yMin="-25" xMax="1118" yMax="1110">
+ <contour>
+ <pt x="614" y="1110" on="1"/>
+ <pt x="849" y="1110" on="0"/>
+ <pt x="983" y="959" on="1"/>
+ <pt x="1118" y="808" on="0"/>
+ <pt x="1118" y="544" on="1"/>
+ <pt x="1118" y="276" on="0"/>
+ <pt x="983" y="126" on="1"/>
+ <pt x="848" y="-25" on="0"/>
+ <pt x="606" y="-25" on="1"/>
+ <pt x="401" y="-25" on="0"/>
+ <pt x="272" y="100" on="1"/>
+ <pt x="111" y="255" on="0"/>
+ <pt x="111" y="543" on="1"/>
+ <pt x="111" y="808" on="0"/>
+ <pt x="246" y="959" on="1"/>
+ <pt x="381" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="614" y="987" on="1"/>
+ <pt x="324" y="987" on="0"/>
+ <pt x="324" y="545" on="1"/>
+ <pt x="324" y="99" on="0"/>
+ <pt x="614" y="99" on="1"/>
+ <pt x="905" y="99" on="0"/>
+ <pt x="905" y="545" on="1"/>
+ <pt x="905" y="987" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 20 5 8 16 5 0 48 200 8 2 0 1 14 0 0 22 39 4 18 39 12 48 200
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="oacute" xMin="111" yMin="-25" xMax="1118" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="99" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="obreve" xMin="111" yMin="-25" xMax="1118" yMax="1579">
+ <contour>
+ <pt x="614" y="1110" on="1"/>
+ <pt x="849" y="1110" on="0"/>
+ <pt x="983" y="959" on="1"/>
+ <pt x="1118" y="808" on="0"/>
+ <pt x="1118" y="544" on="1"/>
+ <pt x="1118" y="276" on="0"/>
+ <pt x="983" y="126" on="1"/>
+ <pt x="848" y="-25" on="0"/>
+ <pt x="606" y="-25" on="1"/>
+ <pt x="401" y="-25" on="0"/>
+ <pt x="272" y="100" on="1"/>
+ <pt x="111" y="255" on="0"/>
+ <pt x="111" y="543" on="1"/>
+ <pt x="111" y="808" on="0"/>
+ <pt x="246" y="959" on="1"/>
+ <pt x="381" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="614" y="987" on="1"/>
+ <pt x="324" y="987" on="0"/>
+ <pt x="324" y="545" on="1"/>
+ <pt x="324" y="99" on="0"/>
+ <pt x="614" y="99" on="1"/>
+ <pt x="905" y="99" on="0"/>
+ <pt x="905" y="545" on="1"/>
+ <pt x="905" y="987" on="0"/>
+ </contour>
+ <contour>
+ <pt x="269" y="1579" on="1"/>
+ <pt x="392" y="1579" on="1"/>
+ <pt x="440" y="1431" on="0"/>
+ <pt x="614" y="1431" on="1"/>
+ <pt x="789" y="1431" on="0"/>
+ <pt x="837" y="1579" on="1"/>
+ <pt x="960" y="1579" on="1"/>
+ <pt x="937" y="1490" on="0"/>
+ <pt x="911" y="1444" on="1"/>
+ <pt x="820" y="1289" on="0"/>
+ <pt x="618" y="1289" on="1"/>
+ <pt x="466" y="1289" on="0"/>
+ <pt x="377" y="1370" on="1"/>
+ <pt x="322" y="1419" on="0"/>
+ <pt x="294" y="1491" on="1"/>
+ <pt x="283" y="1520" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 27 14 34 20 5 8 16 5 0 48 200 8 2 0 1 1 30 29 25 24 4 13 34
+ 1 0 14 0 0 22 36 4 18 36 12 48 200 30 29 25 24 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ocircumflex" xMin="111" yMin="-25" xMax="1118" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="1" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="odieresis" xMin="111" yMin="-25" xMax="1118" yMax="1480">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="0" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="oe" xMin="49" yMin="-25" xMax="1179" yMax="1111">
+ <contour>
+ <pt x="647" y="118" on="1"/>
+ <pt x="564" y="-25" on="0"/>
+ <pt x="413" y="-25" on="1"/>
+ <pt x="249" y="-25" on="0"/>
+ <pt x="149" y="131" on="1"/>
+ <pt x="49" y="287" on="0"/>
+ <pt x="49" y="542" on="1"/>
+ <pt x="49" y="797" on="0"/>
+ <pt x="150" y="954" on="1"/>
+ <pt x="250" y="1110" on="0"/>
+ <pt x="416" y="1110" on="1"/>
+ <pt x="574" y="1110" on="0"/>
+ <pt x="663" y="951" on="1"/>
+ <pt x="749" y="1111" on="0"/>
+ <pt x="893" y="1111" on="1"/>
+ <pt x="1179" y="1111" on="0"/>
+ <pt x="1179" y="607" on="1"/>
+ <pt x="1179" y="531" on="1"/>
+ <pt x="735" y="531" on="1"/>
+ <pt x="735" y="515" on="1"/>
+ <pt x="735" y="123" on="0"/>
+ <pt x="951" y="123" on="1"/>
+ <pt x="1051" y="123" on="0"/>
+ <pt x="1179" y="210" on="1"/>
+ <pt x="1179" y="56" on="1"/>
+ <pt x="1027" y="-25" on="0"/>
+ <pt x="903" y="-25" on="1"/>
+ <pt x="745" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="421" y="987" on="1"/>
+ <pt x="240" y="987" on="0"/>
+ <pt x="240" y="541" on="1"/>
+ <pt x="240" y="99" on="0"/>
+ <pt x="421" y="99" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="542" y="224" on="1"/>
+ <pt x="562" y="324" on="0"/>
+ <pt x="562" y="538" on="1"/>
+ <pt x="562" y="785" on="0"/>
+ <pt x="537" y="882" on="1"/>
+ <pt x="511" y="987" on="0"/>
+ </contour>
+ <contour>
+ <pt x="736" y="654" on="1"/>
+ <pt x="994" y="654" on="1"/>
+ <pt x="994" y="716" on="1"/>
+ <pt x="994" y="987" on="0"/>
+ <pt x="882" y="987" on="1"/>
+ <pt x="741" y="987" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 44 5 14 32 5 2 28 5 10 21 14 26 48 200 26 2 14 1 10 1 2 2 1
+ 42 12 2 1 40 3 0 16 40 17 2 1 24 23 19 0 4 17 2 3 0 0 0 18 17
+ 6 1 40 1 4 48 200 41 40 1 0 14 0 0 30 19 6 48 200 42 41 40 19 18 12
+ 0 7 13 36 6 16 24 23 17 16 3 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ogonek" xMin="444" yMin="-370" xMax="786" yMax="0">
+ <contour>
+ <pt x="602" y="0" on="1"/>
+ <pt x="709" y="0" on="1"/>
+ <pt x="580" y="-81" on="0"/>
+ <pt x="580" y="-179" on="1"/>
+ <pt x="580" y="-275" on="0"/>
+ <pt x="695" y="-275" on="1"/>
+ <pt x="749" y="-275" on="0"/>
+ <pt x="786" y="-260" on="1"/>
+ <pt x="786" y="-341" on="1"/>
+ <pt x="724" y="-370" on="0"/>
+ <pt x="646" y="-370" on="1"/>
+ <pt x="444" y="-370" on="0"/>
+ <pt x="444" y="-213" on="1"/>
+ <pt x="444" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 5 17 10 48 200 10 8 7 1 0 14 0 0 3 20 12 48 200 12 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ograve" xMin="111" yMin="-25" xMax="1118" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="-98" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ohungarumlaut" xMin="111" yMin="-25" xMax="1118" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="hungarumlaut" x="102" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="omacron" xMin="111" yMin="-25" xMax="1118" yMax="1407">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="0" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="112" yMin="0" xMax="1198" yMax="1517">
+ <contour>
+ <pt x="112" y="0" on="1"/>
+ <pt x="112" y="123" on="1"/>
+ <pt x="556" y="123" on="1"/>
+ <pt x="556" y="1313" on="1"/>
+ <pt x="112" y="1202" on="1"/>
+ <pt x="112" y="1325" on="1"/>
+ <pt x="753" y="1517" on="1"/>
+ <pt x="754" y="123" on="1"/>
+ <pt x="1198" y="123" on="1"/>
+ <pt x="1198" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 6 5 4 3 4 13 1 0 0 8 7 2 1 6 3 0 1 4 48 200 9 0 1 0 14
+ 9 8 7 6 4 13 2 5 4 1 0 4 13 2 3 2 1 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onehalf" xMin="43" yMin="-37" xMax="1167" yMax="1517">
+ <contour>
+ <pt x="73" y="-37" on="1"/>
+ <pt x="851" y="1517" on="1"/>
+ <pt x="992" y="1517" on="1"/>
+ <pt x="211" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="661" y="0" on="1"/>
+ <pt x="661" y="154" on="1"/>
+ <pt x="705" y="242" on="0"/>
+ <pt x="823" y="328" on="1"/>
+ <pt x="853" y="350" on="0"/>
+ <pt x="868" y="362" on="1"/>
+ <pt x="901" y="393" on="1"/>
+ <pt x="957" y="440" on="1"/>
+ <pt x="1006" y="481" on="0"/>
+ <pt x="1006" y="556" on="1"/>
+ <pt x="1006" y="679" on="0"/>
+ <pt x="878" y="679" on="1"/>
+ <pt x="834" y="679" on="0"/>
+ <pt x="772" y="650" on="1"/>
+ <pt x="772" y="582" on="1"/>
+ <pt x="661" y="582" on="1"/>
+ <pt x="661" y="740" on="1"/>
+ <pt x="769" y="790" on="0"/>
+ <pt x="890" y="790" on="1"/>
+ <pt x="1167" y="790" on="0"/>
+ <pt x="1167" y="575" on="1"/>
+ <pt x="1167" y="449" on="0"/>
+ <pt x="1029" y="344" on="1"/>
+ <pt x="996" y="319" on="1"/>
+ <pt x="996" y="319" on="1"/>
+ <pt x="995" y="318" on="1"/>
+ <pt x="995" y="318" on="0"/>
+ <pt x="993" y="317" on="1"/>
+ <pt x="991" y="316" on="0"/>
+ <pt x="987" y="313" on="1"/>
+ <pt x="979" y="307" on="0"/>
+ <pt x="960" y="294" on="1"/>
+ <pt x="850" y="223" on="0"/>
+ <pt x="824" y="148" on="1"/>
+ <pt x="1167" y="148" on="1"/>
+ <pt x="1167" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="203" y="728" on="1"/>
+ <pt x="203" y="1345" on="1"/>
+ <pt x="43" y="1291" on="1"/>
+ <pt x="43" y="1415" on="1"/>
+ <pt x="351" y="1517" on="1"/>
+ <pt x="351" y="728" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 0 0 15 22 48 200 22 43 42 41 22 20 5 1 40 3 28 27 19 18 17 10 5 7 40
+ 37 3 0 0 38 37 16 1 4 1 4 48 200 45 40 1 39 4 1 44 2 1 2 3 0
+ 1 4 0 14 0 0 13 34 24 48 200 37 28 27 18 17 10 2 1 8 24 4 3 3 44
+ 40 2 43 42 0 3 13 40 0 0 45 44 16 1 40 1 4 48 200 41 40 1 39 38 24
+ 2 20 19 5 4 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onequarter" xMin="43" yMin="-37" xMax="1167" yMax="1517">
+ <contour>
+ <pt x="203" y="728" on="1"/>
+ <pt x="203" y="1345" on="1"/>
+ <pt x="43" y="1291" on="1"/>
+ <pt x="43" y="1415" on="1"/>
+ <pt x="351" y="1517" on="1"/>
+ <pt x="351" y="728" on="1"/>
+ </contour>
+ <contour>
+ <pt x="86" y="-37" on="1"/>
+ <pt x="863" y="1517" on="1"/>
+ <pt x="1004" y="1517" on="1"/>
+ <pt x="223" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1056" y="0" on="1"/>
+ <pt x="907" y="0" on="1"/>
+ <pt x="907" y="179" on="1"/>
+ <pt x="533" y="179" on="1"/>
+ <pt x="533" y="302" on="1"/>
+ <pt x="903" y="790" on="1"/>
+ <pt x="1056" y="790" on="1"/>
+ <pt x="1056" y="302" on="1"/>
+ <pt x="1167" y="302" on="1"/>
+ <pt x="1167" y="179" on="1"/>
+ <pt x="1056" y="179" on="1"/>
+ </contour>
+ <contour>
+ <pt x="671" y="302" on="1"/>
+ <pt x="907" y="302" on="1"/>
+ <pt x="907" y="611" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 105 values pushed */
+ 3 2 1 3 4 15 3 23 0 14 2 0 0 22 21 18 17 14 6 4 12 1 4 48 200
+ 16 15 1 20 19 13 12 3 11 10 1 8 7 4 2 9 6 1 5 0 1 6 0 14 8
+ 10 11 2 21 15 14 13 7 5 11 4 3 9 4 0 2 19 18 2 13 10 6 3 2 3
+ 13 0 0 0 23 22 12 11 16 3 10 5 4 16 1 0 2 4 48 200 20 17 16 10 3
+ 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onesuperior" xMin="266" yMin="728" xMax="963" yMax="1517">
+ <contour>
+ <pt x="266" y="728" on="1"/>
+ <pt x="266" y="851" on="1"/>
+ <pt x="528" y="851" on="1"/>
+ <pt x="528" y="1345" on="1"/>
+ <pt x="266" y="1295" on="1"/>
+ <pt x="266" y="1419" on="1"/>
+ <pt x="701" y="1517" on="1"/>
+ <pt x="701" y="851" on="1"/>
+ <pt x="963" y="851" on="1"/>
+ <pt x="963" y="728" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 6 5 4 3 4 13 1 0 0 9 0 6 1 1 1 4 48 200 8 7 2 1 3 0 14
+ 9 8 2 13 6 5 4 1 0 4 13 2 0 0 7 6 37 1 2 1 4 48 200 3 2
+ 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onesuperiour" xMin="407" yMin="728" xMax="715" yMax="1517">
+ <contour>
+ <pt x="567" y="728" on="1"/>
+ <pt x="567" y="1345" on="1"/>
+ <pt x="407" y="1291" on="1"/>
+ <pt x="407" y="1415" on="1"/>
+ <pt x="715" y="1517" on="1"/>
+ <pt x="715" y="728" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 4 3 2 1 4 13 0 5 0 1 0 14 3 2 0 0 0 1 0 16 1 4 1 4 48
+ 200 5 4 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ordfeminine" xMin="136" yMin="715" xMax="1116" yMax="1517">
+ <contour>
+ <pt x="765" y="817" on="1"/>
+ <pt x="606" y="715" on="0"/>
+ <pt x="455" y="715" on="1"/>
+ <pt x="312" y="715" on="0"/>
+ <pt x="224" y="774" on="1"/>
+ <pt x="136" y="833" on="0"/>
+ <pt x="136" y="932" on="1"/>
+ <pt x="136" y="1195" on="0"/>
+ <pt x="687" y="1195" on="1"/>
+ <pt x="765" y="1195" on="1"/>
+ <pt x="765" y="1250" on="1"/>
+ <pt x="765" y="1328" on="0"/>
+ <pt x="718" y="1361" on="1"/>
+ <pt x="672" y="1394" on="0"/>
+ <pt x="565" y="1394" on="1"/>
+ <pt x="478" y="1394" on="0"/>
+ <pt x="353" y="1352" on="1"/>
+ <pt x="353" y="1269" on="1"/>
+ <pt x="204" y="1269" on="1"/>
+ <pt x="204" y="1458" on="1"/>
+ <pt x="455" y="1517" on="0"/>
+ <pt x="597" y="1517" on="1"/>
+ <pt x="774" y="1517" on="0"/>
+ <pt x="856" y="1463" on="1"/>
+ <pt x="938" y="1409" on="0"/>
+ <pt x="938" y="1287" on="1"/>
+ <pt x="938" y="856" on="1"/>
+ <pt x="1116" y="856" on="1"/>
+ <pt x="1116" y="733" on="1"/>
+ <pt x="790" y="733" on="1"/>
+ </contour>
+ <contour>
+ <pt x="765" y="933" on="1"/>
+ <pt x="765" y="1078" on="1"/>
+ <pt x="725" y="1078" on="1"/>
+ <pt x="322" y="1078" on="0"/>
+ <pt x="322" y="937" on="1"/>
+ <pt x="322" y="839" on="0"/>
+ <pt x="491" y="839" on="1"/>
+ <pt x="627" y="839" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 105 values pushed */
+ 0 0 36 5 2 14 5 21 48 200 21 0 1 25 19 16 3 0 17 3 0 32 31 30 10
+ 9 8 6 17 26 3 0 26 28 2 2 28 0 0 29 28 6 1 26 1 4 48 200 18 17
+ 1 27 26 1 2 0 14 0 0 34 19 6 48 200 29 25 0 2 32 17 16 8 4 0 18
+ 3 28 27 2 13 25 6 18 0 0 31 30 10 9 0 12 4 25 1 4 48 200 26 25 1
+ 19 18 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ordmasculine" xMin="148" yMin="716" xMax="1081" yMax="1517">
+ <contour>
+ <pt x="614" y="1517" on="1"/>
+ <pt x="829" y="1517" on="0"/>
+ <pt x="955" y="1409" on="1"/>
+ <pt x="1081" y="1301" on="0"/>
+ <pt x="1081" y="1116" on="1"/>
+ <pt x="1081" y="930" on="0"/>
+ <pt x="955" y="823" on="1"/>
+ <pt x="828" y="716" on="0"/>
+ <pt x="607" y="716" on="1"/>
+ <pt x="418" y="716" on="0"/>
+ <pt x="298" y="805" on="1"/>
+ <pt x="148" y="916" on="0"/>
+ <pt x="148" y="1117" on="1"/>
+ <pt x="148" y="1301" on="0"/>
+ <pt x="274" y="1409" on="1"/>
+ <pt x="400" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="614" y="1394" on="1"/>
+ <pt x="491" y="1394" on="0"/>
+ <pt x="412" y="1316" on="1"/>
+ <pt x="333" y="1237" on="0"/>
+ <pt x="333" y="1117" on="1"/>
+ <pt x="333" y="996" on="0"/>
+ <pt x="412" y="918" on="1"/>
+ <pt x="490" y="839" on="0"/>
+ <pt x="612" y="839" on="1"/>
+ <pt x="724" y="839" on="0"/>
+ <pt x="800" y="902" on="1"/>
+ <pt x="896" y="982" on="0"/>
+ <pt x="896" y="1117" on="1"/>
+ <pt x="896" y="1238" on="0"/>
+ <pt x="816" y="1316" on="1"/>
+ <pt x="736" y="1394" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 0 0 1 8 0 0 14 0 0 28 19 4 20 19 12
+ 48 200 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="oslash" xMin="111" yMin="-25" xMax="1118" yMax="1110">
+ <contour>
+ <pt x="111" y="-25" on="1"/>
+ <pt x="238" y="139" on="1"/>
+ <pt x="111" y="311" on="0"/>
+ <pt x="111" y="545" on="1"/>
+ <pt x="111" y="809" on="0"/>
+ <pt x="246" y="960" on="1"/>
+ <pt x="381" y="1110" on="0"/>
+ <pt x="620" y="1110" on="1"/>
+ <pt x="799" y="1110" on="0"/>
+ <pt x="921" y="1018" on="1"/>
+ <pt x="993" y="1110" on="1"/>
+ <pt x="1118" y="1110" on="1"/>
+ <pt x="991" y="947" on="1"/>
+ <pt x="1118" y="775" on="0"/>
+ <pt x="1118" y="540" on="1"/>
+ <pt x="1118" y="276" on="0"/>
+ <pt x="983" y="126" on="1"/>
+ <pt x="848" y="-25" on="0"/>
+ <pt x="608" y="-25" on="1"/>
+ <pt x="428" y="-25" on="0"/>
+ <pt x="308" y="68" on="1"/>
+ <pt x="236" y="-25" on="1"/>
+ </contour>
+ <contour>
+ <pt x="822" y="891" on="1"/>
+ <pt x="727" y="987" on="0"/>
+ <pt x="614" y="987" on="1"/>
+ <pt x="324" y="987" on="0"/>
+ <pt x="324" y="542" on="1"/>
+ <pt x="324" y="392" on="0"/>
+ <pt x="357" y="292" on="1"/>
+ </contour>
+ <contour>
+ <pt x="408" y="196" on="1"/>
+ <pt x="494" y="99" on="0"/>
+ <pt x="614" y="99" on="1"/>
+ <pt x="905" y="99" on="0"/>
+ <pt x="905" y="542" on="1"/>
+ <pt x="905" y="690" on="0"/>
+ <pt x="872" y="794" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 31 5 18 24 5 7 48 200 18 2 7 1 1 1 35 29 28 22 20 12 9 1 8
+ 1 2 3 0 0 1 11 10 2 13 1 0 1 21 0 2 0 14 0 0 33 39 14 26 39
+ 3 48 200 35 29 28 22 21 20 14 12 11 10 9 3 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="otilde" xMin="111" yMin="-25" xMax="1118" yMax="1518">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="1" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="p" xMin="62" yMin="-395" xMax="1118" yMax="1110">
+ <contour>
+ <pt x="383" y="-272" on="1"/>
+ <pt x="630" y="-272" on="1"/>
+ <pt x="630" y="-395" on="1"/>
+ <pt x="62" y="-395" on="1"/>
+ <pt x="62" y="-272" on="1"/>
+ <pt x="185" y="-272" on="1"/>
+ <pt x="185" y="962" on="1"/>
+ <pt x="62" y="962" on="1"/>
+ <pt x="62" y="1086" on="1"/>
+ <pt x="383" y="1086" on="1"/>
+ <pt x="383" y="864" on="1"/>
+ <pt x="458" y="975" on="0"/>
+ <pt x="529" y="1030" on="1"/>
+ <pt x="631" y="1110" on="0"/>
+ <pt x="749" y="1110" on="1"/>
+ <pt x="914" y="1110" on="0"/>
+ <pt x="1016" y="967" on="1"/>
+ <pt x="1118" y="823" on="0"/>
+ <pt x="1118" y="588" on="1"/>
+ <pt x="1118" y="302" on="0"/>
+ <pt x="983" y="139" on="1"/>
+ <pt x="849" y="-25" on="0"/>
+ <pt x="614" y="-25" on="1"/>
+ <pt x="526" y="-25" on="0"/>
+ <pt x="383" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="383" y="146" on="1"/>
+ <pt x="519" y="123" on="0"/>
+ <pt x="595" y="123" on="1"/>
+ <pt x="762" y="123" on="0"/>
+ <pt x="835" y="230" on="1"/>
+ <pt x="908" y="337" on="0"/>
+ <pt x="908" y="577" on="1"/>
+ <pt x="908" y="950" on="0"/>
+ <pt x="694" y="950" on="1"/>
+ <pt x="530" y="950" on="0"/>
+ <pt x="383" y="716" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 0 0 33 30 14 27 14 22 48 200 22 2 14 1 1 35 25 10 7 6 5 8 2 3 0
+ 1 24 2 0 2 0 0 0 5 4 1 0 6 3 2 1 4 48 200 3 2 1 0 9 8
+ 1 14 0 0 31 39 18 48 200 2 1 2 13 18 0 8 7 4 3 4 13 5 0 0 35
+ 25 24 10 9 0 10 5 5 1 4 48 200 6 5 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="paragraph" xMin="100" yMin="-296" xMax="970" yMax="1493">
+ <contour>
+ <pt x="550" y="-296" on="1"/>
+ <pt x="550" y="740" on="1"/>
+ <pt x="406" y="757" on="0"/>
+ <pt x="331" y="790" on="1"/>
+ <pt x="100" y="889" on="0"/>
+ <pt x="100" y="1154" on="1"/>
+ <pt x="100" y="1493" on="0"/>
+ <pt x="457" y="1493" on="1"/>
+ <pt x="495" y="1493" on="0"/>
+ <pt x="554" y="1488" on="1"/>
+ <pt x="624" y="1482" on="1"/>
+ <pt x="644" y="1480" on="0"/>
+ <pt x="679" y="1480" on="1"/>
+ <pt x="970" y="1480" on="1"/>
+ <pt x="970" y="-296" on="1"/>
+ <pt x="846" y="-296" on="1"/>
+ <pt x="846" y="1357" on="1"/>
+ <pt x="674" y="1357" on="1"/>
+ <pt x="674" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 7 0 1 1 16 2 2 0 1 18 15 14 0 4 13 2 0 0 0 17 16 6 1 12 1
+ 4 48 200 13 12 0 14 12 15 17 2 5 0 0 0 16 15 6 1 13 1 0 6 1 17
+ 2 4 48 200 14 13 1 18 17 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="parenleft" xMin="321" yMin="-296" xMax="982" yMax="1579">
+ <contour>
+ <pt x="982" y="-296" on="1"/>
+ <pt x="830" y="-266" on="0"/>
+ <pt x="720" y="-194" on="1"/>
+ <pt x="537" y="-74" on="0"/>
+ <pt x="426" y="155" on="1"/>
+ <pt x="321" y="372" on="0"/>
+ <pt x="321" y="642" on="1"/>
+ <pt x="321" y="1061" on="0"/>
+ <pt x="569" y="1344" on="1"/>
+ <pt x="668" y="1457" on="0"/>
+ <pt x="794" y="1519" on="1"/>
+ <pt x="872" y="1557" on="0"/>
+ <pt x="982" y="1579" on="1"/>
+ <pt x="982" y="1456" on="1"/>
+ <pt x="790" y="1398" on="0"/>
+ <pt x="678" y="1224" on="1"/>
+ <pt x="531" y="996" on="0"/>
+ <pt x="531" y="642" on="1"/>
+ <pt x="531" y="269" on="0"/>
+ <pt x="692" y="38" on="1"/>
+ <pt x="801" y="-118" on="0"/>
+ <pt x="982" y="-173" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 21 13 12 0 14 0 0 17 39 6 48 200 21 13 12 6 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="parenright" xMin="247" yMin="-296" xMax="908" yMax="1579">
+ <contour>
+ <pt x="247" y="-296" on="1"/>
+ <pt x="247" y="-173" on="1"/>
+ <pt x="440" y="-115" on="0"/>
+ <pt x="552" y="59" on="1"/>
+ <pt x="699" y="287" on="0"/>
+ <pt x="699" y="642" on="1"/>
+ <pt x="699" y="1014" on="0"/>
+ <pt x="538" y="1245" on="1"/>
+ <pt x="429" y="1401" on="0"/>
+ <pt x="247" y="1456" on="1"/>
+ <pt x="247" y="1579" on="1"/>
+ <pt x="400" y="1549" on="0"/>
+ <pt x="510" y="1477" on="1"/>
+ <pt x="693" y="1357" on="0"/>
+ <pt x="803" y="1128" on="1"/>
+ <pt x="908" y="912" on="0"/>
+ <pt x="908" y="642" on="1"/>
+ <pt x="908" y="221" on="0"/>
+ <pt x="661" y="-61" on="1"/>
+ <pt x="561" y="-174" on="0"/>
+ <pt x="436" y="-236" on="1"/>
+ <pt x="358" y="-274" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 10 9 1 0 14 0 0 5 39 16 48 200 16 10 9 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="percent" xMin="21" yMin="-37" xMax="1207" yMax="1517">
+ <contour>
+ <pt x="61" y="-37" on="1"/>
+ <pt x="1034" y="1517" on="1"/>
+ <pt x="1166" y="1517" on="1"/>
+ <pt x="190" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="285" y="1480" on="1"/>
+ <pt x="404" y="1480" on="0"/>
+ <pt x="476" y="1379" on="1"/>
+ <pt x="549" y="1277" on="0"/>
+ <pt x="549" y="1111" on="1"/>
+ <pt x="549" y="942" on="0"/>
+ <pt x="476" y="841" on="1"/>
+ <pt x="404" y="740" on="0"/>
+ <pt x="281" y="740" on="1"/>
+ <pt x="177" y="740" on="0"/>
+ <pt x="108" y="823" on="1"/>
+ <pt x="21" y="928" on="0"/>
+ <pt x="21" y="1110" on="1"/>
+ <pt x="21" y="1278" on="0"/>
+ <pt x="94" y="1379" on="1"/>
+ <pt x="166" y="1480" on="0"/>
+ </contour>
+ <contour>
+ <pt x="285" y="1357" on="1"/>
+ <pt x="157" y="1357" on="0"/>
+ <pt x="157" y="1110" on="1"/>
+ <pt x="157" y="864" on="0"/>
+ <pt x="285" y="864" on="1"/>
+ <pt x="413" y="864" on="0"/>
+ <pt x="413" y="1111" on="1"/>
+ <pt x="413" y="1357" on="0"/>
+ </contour>
+ <contour>
+ <pt x="943" y="740" on="1"/>
+ <pt x="1062" y="740" on="0"/>
+ <pt x="1134" y="639" on="1"/>
+ <pt x="1207" y="538" on="0"/>
+ <pt x="1207" y="372" on="1"/>
+ <pt x="1207" y="202" on="0"/>
+ <pt x="1134" y="101" on="1"/>
+ <pt x="1061" y="0" on="0"/>
+ <pt x="941" y="0" on="1"/>
+ <pt x="835" y="0" on="0"/>
+ <pt x="766" y="82" on="1"/>
+ <pt x="679" y="187" on="0"/>
+ <pt x="679" y="371" on="1"/>
+ <pt x="679" y="538" on="0"/>
+ <pt x="752" y="639" on="1"/>
+ <pt x="824" y="740" on="0"/>
+ </contour>
+ <contour>
+ <pt x="943" y="617" on="1"/>
+ <pt x="815" y="617" on="0"/>
+ <pt x="815" y="372" on="1"/>
+ <pt x="815" y="123" on="0"/>
+ <pt x="943" y="123" on="1"/>
+ <pt x="1072" y="123" on="0"/>
+ <pt x="1072" y="370" on="1"/>
+ <pt x="1072" y="617" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 69 values pushed */
+ 0 0 48 5 36 44 5 28 24 5 12 20 5 4 48 200 36 2 4 0 28 12 1 1 28
+ 12 2 0 2 3 0 0 1 2 1 2 13 0 0 1 3 0 2 0 14 0 0 50 20 32
+ 46 20 40 26 20 8 22 20 16 48 200 40 32 16 8 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="period" xMin="466" yMin="0" xMax="762" yMax="296">
+ <contour>
+ <pt x="466" y="0" on="1"/>
+ <pt x="466" y="296" on="1"/>
+ <pt x="762" y="296" on="1"/>
+ <pt x="762" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 2 1 8 1 0 1 4 48 200 3 0 1 0 14 0 0 3 2 8 1 0 1 4
+ 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="periodcentered" xMin="491" yMin="419" xMax="738" yMax="666">
+ <contour>
+ <pt x="491" y="419" on="1"/>
+ <pt x="491" y="666" on="1"/>
+ <pt x="738" y="666" on="1"/>
+ <pt x="738" y="419" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 2 1 4 1 0 1 4 48 200 3 0 1 0 14 0 0 3 2 4 1 0 1 4
+ 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="periodcentered#1" xMin="491" yMin="419" xMax="738" yMax="666">
+ <contour>
+ <pt x="491" y="419" on="1"/>
+ <pt x="491" y="666" on="1"/>
+ <pt x="738" y="666" on="1"/>
+ <pt x="738" y="419" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 2 1 4 1 0 1 4 48 200 3 0 1 0 14 0 0 3 2 4 1 0 1 4
+ 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="perthousand" xMin="12" yMin="0" xMax="1217" yMax="1480">
+ <contour>
+ <pt x="196" y="1476" on="1"/>
+ <pt x="279" y="1476" on="0"/>
+ <pt x="329" y="1391" on="1"/>
+ <pt x="380" y="1307" on="0"/>
+ <pt x="380" y="1169" on="1"/>
+ <pt x="380" y="1027" on="0"/>
+ <pt x="329" y="943" on="1"/>
+ <pt x="279" y="859" on="0"/>
+ <pt x="194" y="859" on="1"/>
+ <pt x="121" y="859" on="0"/>
+ <pt x="73" y="927" on="1"/>
+ <pt x="12" y="1014" on="0"/>
+ <pt x="12" y="1168" on="1"/>
+ <pt x="12" y="1306" on="0"/>
+ <pt x="63" y="1391" on="1"/>
+ <pt x="113" y="1476" on="0"/>
+ </contour>
+ <contour>
+ <pt x="196" y="1383" on="1"/>
+ <pt x="108" y="1383" on="0"/>
+ <pt x="108" y="1168" on="1"/>
+ <pt x="108" y="952" on="0"/>
+ <pt x="199" y="952" on="1"/>
+ <pt x="285" y="952" on="0"/>
+ <pt x="285" y="1168" on="1"/>
+ <pt x="285" y="1383" on="0"/>
+ </contour>
+ <contour>
+ <pt x="28" y="0" on="1"/>
+ <pt x="645" y="1480" on="1"/>
+ <pt x="748" y="1480" on="1"/>
+ <pt x="129" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="578" y="617" on="1"/>
+ <pt x="661" y="617" on="0"/>
+ <pt x="711" y="532" on="1"/>
+ <pt x="762" y="448" on="0"/>
+ <pt x="762" y="309" on="1"/>
+ <pt x="762" y="168" on="0"/>
+ <pt x="711" y="84" on="1"/>
+ <pt x="661" y="0" on="0"/>
+ <pt x="576" y="0" on="1"/>
+ <pt x="503" y="0" on="0"/>
+ <pt x="455" y="68" on="1"/>
+ <pt x="394" y="155" on="0"/>
+ <pt x="394" y="309" on="1"/>
+ <pt x="394" y="448" on="0"/>
+ <pt x="445" y="532" on="1"/>
+ <pt x="495" y="617" on="0"/>
+ </contour>
+ <contour>
+ <pt x="578" y="524" on="1"/>
+ <pt x="489" y="524" on="0"/>
+ <pt x="489" y="309" on="1"/>
+ <pt x="489" y="93" on="0"/>
+ <pt x="580" y="93" on="1"/>
+ <pt x="666" y="93" on="0"/>
+ <pt x="666" y="310" on="1"/>
+ <pt x="666" y="524" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1033" y="617" on="1"/>
+ <pt x="1115" y="617" on="0"/>
+ <pt x="1166" y="532" on="1"/>
+ <pt x="1217" y="448" on="0"/>
+ <pt x="1217" y="309" on="1"/>
+ <pt x="1217" y="168" on="0"/>
+ <pt x="1166" y="84" on="1"/>
+ <pt x="1116" y="0" on="0"/>
+ <pt x="1031" y="0" on="1"/>
+ <pt x="958" y="0" on="0"/>
+ <pt x="910" y="68" on="1"/>
+ <pt x="849" y="155" on="0"/>
+ <pt x="849" y="309" on="1"/>
+ <pt x="849" y="448" on="0"/>
+ <pt x="900" y="532" on="1"/>
+ <pt x="951" y="617" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1033" y="524" on="1"/>
+ <pt x="944" y="524" on="0"/>
+ <pt x="944" y="310" on="1"/>
+ <pt x="944" y="93" on="0"/>
+ <pt x="1035" y="93" on="1"/>
+ <pt x="1121" y="93" on="0"/>
+ <pt x="1121" y="309" on="1"/>
+ <pt x="1121" y="524" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 72 17 60 68 17 52 48 17 36 44 17 28 20 17 8 16 17 0 48 200 60 2 36
+ 2 0 0 52 28 8 1 1 52 28 26 25 8 5 0 2 3 0 0 1 27 24 2 0 14
+ 0 0 74 21 56 70 21 64 50 21 32 46 21 40 22 21 4 18 21 12 48 200 64 56 40
+ 32 27 26 25 24 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="plus" xMin="99" yMin="101" xMax="1130" yMax="1133">
+ <contour>
+ <pt x="541" y="101" on="1"/>
+ <pt x="541" y="543" on="1"/>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="691" on="1"/>
+ <pt x="541" y="691" on="1"/>
+ <pt x="541" y="1133" on="1"/>
+ <pt x="689" y="1133" on="1"/>
+ <pt x="689" y="691" on="1"/>
+ <pt x="1130" y="691" on="1"/>
+ <pt x="1130" y="543" on="1"/>
+ <pt x="689" y="543" on="1"/>
+ <pt x="689" y="101" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 53 values pushed */
+ 0 0 10 9 2 1 7 3 3 1 4 48 200 6 5 1 8 7 4 3 3 11 0 1 3
+ 0 14 0 0 11 10 7 6 14 3 0 1 4 48 200 9 8 1 5 4 1 0 3 3 2
+ 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="plusminus" xMin="99" yMin="0" xMax="1130" yMax="1234">
+ <contour>
+ <pt x="541" y="296" on="1"/>
+ <pt x="541" y="691" on="1"/>
+ <pt x="99" y="691" on="1"/>
+ <pt x="99" y="839" on="1"/>
+ <pt x="541" y="839" on="1"/>
+ <pt x="541" y="1234" on="1"/>
+ <pt x="689" y="1234" on="1"/>
+ <pt x="689" y="839" on="1"/>
+ <pt x="1130" y="839" on="1"/>
+ <pt x="1130" y="691" on="1"/>
+ <pt x="689" y="691" on="1"/>
+ <pt x="689" y="296" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1130" y="0" on="1"/>
+ <pt x="99" y="0" on="1"/>
+ <pt x="99" y="148" on="1"/>
+ <pt x="1130" y="148" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 15 14 7 1 12 10 9 2 1 7 3 3 2 4 48 200 13 12 1 6 5 1 8
+ 7 4 3 3 11 0 1 4 0 14 0 0 11 10 7 6 14 3 0 1 4 48 200 15 12
+ 9 8 3 5 4 1 0 3 14 13 3 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="q" xMin="111" yMin="-395" xMax="1167" yMax="1110">
+ <contour>
+ <pt x="846" y="222" on="1"/>
+ <pt x="771" y="111" on="0"/>
+ <pt x="701" y="55" on="1"/>
+ <pt x="599" y="-25" on="0"/>
+ <pt x="480" y="-25" on="1"/>
+ <pt x="315" y="-25" on="0"/>
+ <pt x="213" y="119" on="1"/>
+ <pt x="111" y="262" on="0"/>
+ <pt x="111" y="498" on="1"/>
+ <pt x="111" y="783" on="0"/>
+ <pt x="246" y="946" on="1"/>
+ <pt x="380" y="1110" on="0"/>
+ <pt x="619" y="1110" on="1"/>
+ <pt x="846" y="1086" on="1"/>
+ <pt x="1044" y="1086" on="1"/>
+ <pt x="1044" y="-272" on="1"/>
+ <pt x="1167" y="-272" on="1"/>
+ <pt x="1167" y="-395" on="1"/>
+ <pt x="600" y="-395" on="1"/>
+ <pt x="600" y="-271" on="1"/>
+ <pt x="846" y="-271" on="1"/>
+ </contour>
+ <contour>
+ <pt x="846" y="939" on="1"/>
+ <pt x="710" y="962" on="0"/>
+ <pt x="633" y="962" on="1"/>
+ <pt x="468" y="962" on="0"/>
+ <pt x="394" y="855" on="1"/>
+ <pt x="321" y="748" on="0"/>
+ <pt x="321" y="509" on="1"/>
+ <pt x="321" y="136" on="0"/>
+ <pt x="535" y="136" on="1"/>
+ <pt x="699" y="136" on="0"/>
+ <pt x="846" y="370" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 29 30 4 23 14 12 48 200 12 1 4 2 1 31 21 0 3 13 2 3 0 16 15
+ 2 19 17 3 0 0 20 19 6 1 17 1 4 48 200 18 17 1 0 14 13 1 14 0 0
+ 27 39 8 48 200 17 16 2 13 14 19 18 8 0 0 0 31 21 20 13 0 10 4 14 1
+ 4 48 200 15 14 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="question" xMin="202" yMin="0" xMax="1079" yMax="1517">
+ <contour>
+ <pt x="415" y="0" on="1"/>
+ <pt x="415" y="222" on="1"/>
+ <pt x="662" y="222" on="1"/>
+ <pt x="662" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="440" y="419" on="1"/>
+ <pt x="440" y="478" on="1"/>
+ <pt x="440" y="720" on="0"/>
+ <pt x="659" y="876" on="1"/>
+ <pt x="726" y="923" on="1"/>
+ <pt x="869" y="1023" on="0"/>
+ <pt x="869" y="1162" on="1"/>
+ <pt x="869" y="1268" on="0"/>
+ <pt x="798" y="1331" on="1"/>
+ <pt x="728" y="1394" on="0"/>
+ <pt x="604" y="1394" on="1"/>
+ <pt x="480" y="1394" on="0"/>
+ <pt x="350" y="1332" on="1"/>
+ <pt x="326" y="1073" on="1"/>
+ <pt x="202" y="1073" on="1"/>
+ <pt x="202" y="1450" on="1"/>
+ <pt x="420" y="1517" on="0"/>
+ <pt x="613" y="1517" on="1"/>
+ <pt x="1079" y="1517" on="0"/>
+ <pt x="1079" y="1180" on="1"/>
+ <pt x="1079" y="1014" on="0"/>
+ <pt x="932" y="904" on="1"/>
+ <pt x="876" y="862" on="1"/>
+ <pt x="873" y="860" on="0"/>
+ <pt x="864" y="853" on="1"/>
+ <pt x="855" y="847" on="0"/>
+ <pt x="847" y="841" on="1"/>
+ <pt x="834" y="833" on="0"/>
+ <pt x="814" y="819" on="1"/>
+ <pt x="719" y="754" on="0"/>
+ <pt x="682" y="703" on="1"/>
+ <pt x="637" y="647" on="0"/>
+ <pt x="637" y="481" on="1"/>
+ <pt x="637" y="419" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 14 5 21 48 200 21 0 1 36 34 19 18 17 16 5 7 0 4 3 0 0 0 2
+ 1 9 1 0 1 4 48 200 37 4 1 3 0 1 2 0 14 0 0 10 39 23 48 200 37
+ 36 5 4 4 2 0 3 17 16 2 0 18 3 34 23 2 0 0 3 2 4 1 0 1 4
+ 48 200 19 18 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="questiondown" xMin="151" yMin="-432" xMax="1027" yMax="1086">
+ <contour>
+ <pt x="814" y="1086" on="1"/>
+ <pt x="814" y="863" on="1"/>
+ <pt x="568" y="863" on="1"/>
+ <pt x="568" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="790" y="666" on="1"/>
+ <pt x="790" y="607" on="1"/>
+ <pt x="790" y="367" on="0"/>
+ <pt x="570" y="210" on="1"/>
+ <pt x="503" y="162" on="1"/>
+ <pt x="361" y="61" on="0"/>
+ <pt x="361" y="-76" on="1"/>
+ <pt x="361" y="-183" on="0"/>
+ <pt x="432" y="-246" on="1"/>
+ <pt x="502" y="-309" on="0"/>
+ <pt x="626" y="-309" on="1"/>
+ <pt x="750" y="-309" on="0"/>
+ <pt x="879" y="-247" on="1"/>
+ <pt x="904" y="12" on="1"/>
+ <pt x="1027" y="12" on="1"/>
+ <pt x="1027" y="-364" on="1"/>
+ <pt x="807" y="-432" on="0"/>
+ <pt x="618" y="-432" on="1"/>
+ <pt x="151" y="-432" on="0"/>
+ <pt x="151" y="-94" on="1"/>
+ <pt x="151" y="71" on="0"/>
+ <pt x="297" y="181" on="1"/>
+ <pt x="354" y="224" on="1"/>
+ <pt x="371" y="237" on="0"/>
+ <pt x="416" y="267" on="1"/>
+ <pt x="509" y="331" on="0"/>
+ <pt x="547" y="383" on="1"/>
+ <pt x="592" y="439" on="0"/>
+ <pt x="592" y="604" on="1"/>
+ <pt x="592" y="666" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 14 5 21 48 200 1 32 30 18 17 5 5 4 2 3 0 1 19 16 21 2 0 0
+ 0 2 1 9 1 0 1 4 48 200 33 4 1 0 3 0 1 14 0 0 10 39 23 48 200
+ 17 16 2 18 0 3 33 32 5 4 4 0 2 3 30 23 2 0 0 1 0 4 1 2 1
+ 4 48 200 19 18 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedbl" xMin="244" yMin="1036" xMax="984" yMax="1579">
+ <contour>
+ <pt x="293" y="1036" on="1"/>
+ <pt x="244" y="1579" on="1"/>
+ <pt x="491" y="1579" on="1"/>
+ <pt x="441" y="1036" on="1"/>
+ </contour>
+ <contour>
+ <pt x="787" y="1036" on="1"/>
+ <pt x="738" y="1579" on="1"/>
+ <pt x="984" y="1579" on="1"/>
+ <pt x="935" y="1036" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 21 values pushed */
+ 6 5 2 1 3 7 4 3 0 3 2 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblbase" xMin="257" yMin="-296" xMax="997" yMax="247">
+ <contour>
+ <pt x="997" y="247" on="1"/>
+ <pt x="997" y="-2" on="1"/>
+ <pt x="996" y="-283" on="0"/>
+ <pt x="750" y="-296" on="1"/>
+ <pt x="750" y="-197" on="1"/>
+ <pt x="855" y="-176" on="0"/>
+ <pt x="855" y="-56" on="1"/>
+ <pt x="855" y="0" on="1"/>
+ <pt x="750" y="0" on="1"/>
+ <pt x="750" y="247" on="1"/>
+ </contour>
+ <contour>
+ <pt x="504" y="247" on="1"/>
+ <pt x="504" y="-2" on="1"/>
+ <pt x="503" y="-283" on="0"/>
+ <pt x="257" y="-296" on="1"/>
+ <pt x="257" y="-197" on="1"/>
+ <pt x="362" y="-176" on="0"/>
+ <pt x="362" y="-56" on="1"/>
+ <pt x="362" y="0" on="1"/>
+ <pt x="257" y="0" on="1"/>
+ <pt x="257" y="247" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 18 17 16 14 13 11 8 7 6 4 3 1 12 13 0 19 10 9 0 3 0 14 7 6 2
+ 0 3 3 17 16 2 10 13 3 0 0 11 10 4 1 13 9 8 4 3 4 3 0 2 4
+ 48 200 19 18 14 13 3 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblleft" xMin="232" yMin="1036" xMax="972" yMax="1579">
+ <contour>
+ <pt x="232" y="1036" on="1"/>
+ <pt x="232" y="1285" on="1"/>
+ <pt x="233" y="1566" on="0"/>
+ <pt x="479" y="1579" on="1"/>
+ <pt x="479" y="1480" on="1"/>
+ <pt x="374" y="1459" on="0"/>
+ <pt x="374" y="1339" on="1"/>
+ <pt x="374" y="1283" on="1"/>
+ <pt x="479" y="1283" on="1"/>
+ <pt x="479" y="1036" on="1"/>
+ </contour>
+ <contour>
+ <pt x="726" y="1036" on="1"/>
+ <pt x="726" y="1285" on="1"/>
+ <pt x="727" y="1566" on="0"/>
+ <pt x="972" y="1579" on="1"/>
+ <pt x="972" y="1480" on="1"/>
+ <pt x="867" y="1459" on="0"/>
+ <pt x="867" y="1339" on="1"/>
+ <pt x="867" y="1283" on="1"/>
+ <pt x="972" y="1283" on="1"/>
+ <pt x="972" y="1036" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 18 17 16 14 13 11 8 7 6 4 3 1 12 13 0 19 10 9 0 3 0 14 17 16 2
+ 13 10 3 7 6 2 3 0 3 0 0 11 10 4 1 13 9 8 4 3 4 3 0 2 4
+ 48 200 19 18 14 13 3 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblright" xMin="257" yMin="1036" xMax="997" yMax="1579">
+ <contour>
+ <pt x="997" y="1579" on="1"/>
+ <pt x="997" y="1330" on="1"/>
+ <pt x="996" y="1049" on="0"/>
+ <pt x="750" y="1036" on="1"/>
+ <pt x="750" y="1135" on="1"/>
+ <pt x="855" y="1156" on="0"/>
+ <pt x="855" y="1276" on="1"/>
+ <pt x="855" y="1332" on="1"/>
+ <pt x="750" y="1332" on="1"/>
+ <pt x="750" y="1579" on="1"/>
+ </contour>
+ <contour>
+ <pt x="504" y="1579" on="1"/>
+ <pt x="504" y="1330" on="1"/>
+ <pt x="503" y="1049" on="0"/>
+ <pt x="257" y="1036" on="1"/>
+ <pt x="257" y="1135" on="1"/>
+ <pt x="362" y="1156" on="0"/>
+ <pt x="362" y="1276" on="1"/>
+ <pt x="362" y="1332" on="1"/>
+ <pt x="257" y="1332" on="1"/>
+ <pt x="257" y="1579" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 18 17 16 14 13 11 8 7 6 4 3 1 12 13 0 19 10 9 0 3 0 14 7 6 2
+ 0 3 3 17 16 2 10 13 3 0 0 11 10 4 1 13 9 8 4 3 4 3 0 2 4
+ 48 200 19 18 14 13 3 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quoteleft" xMin="454" yMin="962" xMax="750" yMax="1579">
+ <contour>
+ <pt x="750" y="1258" on="1"/>
+ <pt x="750" y="962" on="1"/>
+ <pt x="454" y="962" on="1"/>
+ <pt x="454" y="1142" on="1"/>
+ <pt x="456" y="1560" on="0"/>
+ <pt x="750" y="1579" on="1"/>
+ <pt x="750" y="1480" on="1"/>
+ <pt x="675" y="1468" on="0"/>
+ <pt x="653" y="1413" on="1"/>
+ <pt x="633" y="1365" on="0"/>
+ <pt x="627" y="1258" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 34 values pushed */
+ 10 6 5 3 0 5 13 1 2 1 1 0 14 10 0 2 2 0 0 6 5 1 0 8 3
+ 2 1 4 48 200 3 2 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotereversed"/><!-- contains no outline data -->
+
+ <TTGlyph name="quoteright" xMin="479" yMin="962" xMax="775" yMax="1579">
+ <contour>
+ <pt x="479" y="1283" on="1"/>
+ <pt x="479" y="1579" on="1"/>
+ <pt x="775" y="1579" on="1"/>
+ <pt x="775" y="1399" on="1"/>
+ <pt x="773" y="980" on="0"/>
+ <pt x="479" y="962" on="1"/>
+ <pt x="479" y="1061" on="1"/>
+ <pt x="554" y="1073" on="0"/>
+ <pt x="576" y="1128" on="1"/>
+ <pt x="596" y="1176" on="0"/>
+ <pt x="602" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 34 values pushed */
+ 10 6 5 3 0 5 13 1 2 1 1 0 14 10 2 0 2 0 0 3 2 8 1 0 1
+ 4 48 200 6 5 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotesinglbase" xMin="479" yMin="-321" xMax="775" yMax="296">
+ <contour>
+ <pt x="479" y="0" on="1"/>
+ <pt x="479" y="296" on="1"/>
+ <pt x="775" y="296" on="1"/>
+ <pt x="775" y="116" on="1"/>
+ <pt x="773" y="-302" on="0"/>
+ <pt x="479" y="-321" on="1"/>
+ <pt x="479" y="-222" on="1"/>
+ <pt x="554" y="-210" on="0"/>
+ <pt x="576" y="-155" on="1"/>
+ <pt x="596" y="-107" on="0"/>
+ <pt x="602" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 34 values pushed */
+ 10 6 5 3 0 5 13 1 2 1 1 0 14 10 2 0 2 0 0 3 2 8 1 0 1
+ 4 48 200 6 5 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotesingle" xMin="466" yMin="962" xMax="762" yMax="1579">
+ <contour>
+ <pt x="540" y="962" on="1"/>
+ <pt x="466" y="1579" on="1"/>
+ <pt x="762" y="1579" on="1"/>
+ <pt x="688" y="962" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 2 1 1 3 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="r" xMin="74" yMin="0" xMax="1106" yMax="1110">
+ <contour>
+ <pt x="530" y="702" on="1"/>
+ <pt x="530" y="123" on="1"/>
+ <pt x="899" y="123" on="1"/>
+ <pt x="899" y="0" on="1"/>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="123" on="1"/>
+ <pt x="333" y="123" on="1"/>
+ <pt x="333" y="962" on="1"/>
+ <pt x="74" y="962" on="1"/>
+ <pt x="74" y="1086" on="1"/>
+ <pt x="530" y="1086" on="1"/>
+ <pt x="530" y="875" on="1"/>
+ <pt x="604" y="981" on="0"/>
+ <pt x="671" y="1034" on="1"/>
+ <pt x="767" y="1110" on="0"/>
+ <pt x="878" y="1110" on="1"/>
+ <pt x="996" y="1110" on="0"/>
+ <pt x="1106" y="1042" on="1"/>
+ <pt x="1106" y="714" on="1"/>
+ <pt x="982" y="714" on="1"/>
+ <pt x="962" y="902" on="1"/>
+ <pt x="906" y="938" on="0"/>
+ <pt x="844" y="938" on="1"/>
+ <pt x="660" y="938" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 0 0 22 22 15 48 200 15 1 17 9 7 2 20 19 18 11 0 5 7 1 3 0 0 8
+ 7 6 1 9 6 5 2 1 6 3 3 2 4 48 200 4 3 1 0 10 9 1 14 20 19
+ 3 2 4 17 0 3 9 8 5 4 4 13 6 0 0 11 10 1 0 10 3 6 1 4 48
+ 200 18 17 1 7 6 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="racute" xMin="74" yMin="0" xMax="1106" yMax="1604">
+ <component glyphName="r" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="40" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="radicalex" xMin="0" yMin="1456" xMax="1229" yMax="1604">
+ <contour>
+ <pt x="0" y="1604" on="1"/>
+ <pt x="1229" y="1604" on="1"/>
+ <pt x="1229" y="1456" on="1"/>
+ <pt x="0" y="1456" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 2 16 1 0 1 4 48 200 1 0 1 0 14 2 1 1 3 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="rcaron" xMin="74" yMin="0" xMax="1106" yMax="1604">
+ <component glyphName="r" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="-24" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="rcommaaccent" xMin="74" yMin="-432" xMax="1106" yMax="1110">
+ <component glyphName="r" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="-32" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="registered" xMin="62" yMin="-37" xMax="1168" yMax="1517">
+ <contour>
+ <pt x="615" y="1517" on="1"/>
+ <pt x="864" y="1517" on="0"/>
+ <pt x="1016" y="1304" on="1"/>
+ <pt x="1168" y="1091" on="0"/>
+ <pt x="1168" y="742" on="1"/>
+ <pt x="1168" y="386" on="0"/>
+ <pt x="1016" y="175" on="1"/>
+ <pt x="864" y="-37" on="0"/>
+ <pt x="606" y="-37" on="1"/>
+ <pt x="388" y="-37" on="0"/>
+ <pt x="245" y="136" on="1"/>
+ <pt x="62" y="357" on="0"/>
+ <pt x="62" y="740" on="1"/>
+ <pt x="62" y="1092" on="0"/>
+ <pt x="214" y="1304" on="1"/>
+ <pt x="366" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1406" on="1"/>
+ <pt x="423" y="1406" on="0"/>
+ <pt x="304" y="1222" on="1"/>
+ <pt x="185" y="1038" on="0"/>
+ <pt x="185" y="741" on="1"/>
+ <pt x="185" y="445" on="0"/>
+ <pt x="303" y="260" on="1"/>
+ <pt x="421" y="74" on="0"/>
+ <pt x="611" y="74" on="1"/>
+ <pt x="785" y="74" on="0"/>
+ <pt x="899" y="221" on="1"/>
+ <pt x="1044" y="407" on="0"/>
+ <pt x="1044" y="742" on="1"/>
+ <pt x="1044" y="1039" on="0"/>
+ <pt x="925" y="1222" on="1"/>
+ <pt x="805" y="1406" on="0"/>
+ </contour>
+ <contour>
+ <pt x="364" y="317" on="1"/>
+ <pt x="364" y="388" on="1"/>
+ <pt x="426" y="388" on="1"/>
+ <pt x="426" y="1093" on="1"/>
+ <pt x="364" y="1093" on="1"/>
+ <pt x="364" y="1163" on="1"/>
+ <pt x="636" y="1163" on="1"/>
+ <pt x="853" y="1163" on="0"/>
+ <pt x="853" y="957" on="1"/>
+ <pt x="853" y="804" on="0"/>
+ <pt x="704" y="723" on="1"/>
+ <pt x="889" y="388" on="1"/>
+ <pt x="914" y="388" on="1"/>
+ <pt x="914" y="317" on="1"/>
+ <pt x="795" y="317" on="1"/>
+ <pt x="601" y="687" on="1"/>
+ <pt x="537" y="687" on="1"/>
+ <pt x="537" y="388" on="1"/>
+ <pt x="611" y="388" on="1"/>
+ <pt x="611" y="317" on="1"/>
+ </contour>
+ <contour>
+ <pt x="537" y="758" on="1"/>
+ <pt x="544" y="758" on="1"/>
+ <pt x="729" y="758" on="0"/>
+ <pt x="729" y="946" on="1"/>
+ <pt x="729" y="1028" on="0"/>
+ <pt x="695" y="1060" on="1"/>
+ <pt x="661" y="1093" on="0"/>
+ <pt x="574" y="1093" on="1"/>
+ <pt x="537" y="1093" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 0 0 24 40 8 16 40 0 48 200 8 2 0 0 60 59 53 52 50 49 48 47 44 43 42
+ 36 35 34 33 15 37 32 3 38 37 1 51 46 45 32 3 2 0 14 0 0 55 6 40 28
+ 6 4 20 6 12 48 200 59 53 51 50 47 46 45 44 43 42 38 11 13 40 4 48 37 36
+ 33 32 4 13 12 34 0 0 60 52 49 48 3 34 1 6 48 200 35 34 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ring" xMin="388" yMin="1283" xMax="842" yMax="1737">
+ <contour>
+ <pt x="615" y="1737" on="1"/>
+ <pt x="709" y="1737" on="0"/>
+ <pt x="775" y="1671" on="1"/>
+ <pt x="842" y="1605" on="0"/>
+ <pt x="842" y="1511" on="1"/>
+ <pt x="842" y="1414" on="0"/>
+ <pt x="775" y="1349" on="1"/>
+ <pt x="709" y="1283" on="0"/>
+ <pt x="613" y="1283" on="1"/>
+ <pt x="530" y="1283" on="0"/>
+ <pt x="468" y="1337" on="1"/>
+ <pt x="388" y="1406" on="0"/>
+ <pt x="388" y="1510" on="1"/>
+ <pt x="388" y="1604" on="0"/>
+ <pt x="455" y="1670" on="1"/>
+ <pt x="522" y="1737" on="0"/>
+ </contour>
+ <contour>
+ <pt x="615" y="1650" on="1"/>
+ <pt x="557" y="1650" on="0"/>
+ <pt x="516" y="1609" on="1"/>
+ <pt x="474" y="1569" on="0"/>
+ <pt x="474" y="1510" on="1"/>
+ <pt x="474" y="1452" on="0"/>
+ <pt x="515" y="1411" on="1"/>
+ <pt x="556" y="1369" on="0"/>
+ <pt x="614" y="1369" on="1"/>
+ <pt x="667" y="1369" on="0"/>
+ <pt x="706" y="1402" on="1"/>
+ <pt x="756" y="1445" on="0"/>
+ <pt x="756" y="1511" on="1"/>
+ <pt x="756" y="1569" on="0"/>
+ <pt x="714" y="1609" on="1"/>
+ <pt x="672" y="1650" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 24 32 8 16 32 0 48 200 8 0 14 0 0 28 32 4 20 32 12 48 200 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="s" xMin="173" yMin="-25" xMax="1088" yMax="1111">
+ <contour>
+ <pt x="173" y="61" on="1"/>
+ <pt x="173" y="358" on="1"/>
+ <pt x="296" y="358" on="1"/>
+ <pt x="321" y="175" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="654" y="99" on="1"/>
+ <pt x="892" y="99" on="0"/>
+ <pt x="892" y="267" on="1"/>
+ <pt x="892" y="333" on="0"/>
+ <pt x="852" y="369" on="1"/>
+ <pt x="812" y="406" on="0"/>
+ <pt x="709" y="433" on="1"/>
+ <pt x="505" y="487" on="1"/>
+ <pt x="334" y="532" on="0"/>
+ <pt x="256" y="605" on="1"/>
+ <pt x="179" y="676" on="0"/>
+ <pt x="179" y="794" on="1"/>
+ <pt x="179" y="1111" on="0"/>
+ <pt x="611" y="1111" on="1"/>
+ <pt x="832" y="1111" on="0"/>
+ <pt x="1013" y="1039" on="1"/>
+ <pt x="1013" y="753" on="1"/>
+ <pt x="890" y="753" on="1"/>
+ <pt x="865" y="934" on="1"/>
+ <pt x="756" y="987" on="0"/>
+ <pt x="610" y="987" on="1"/>
+ <pt x="500" y="987" on="0"/>
+ <pt x="439" y="952" on="1"/>
+ <pt x="367" y="911" on="0"/>
+ <pt x="367" y="826" on="1"/>
+ <pt x="367" y="714" on="0"/>
+ <pt x="573" y="660" on="1"/>
+ <pt x="775" y="607" on="1"/>
+ <pt x="943" y="563" on="0"/>
+ <pt x="1016" y="495" on="1"/>
+ <pt x="1088" y="428" on="0"/>
+ <pt x="1088" y="313" on="1"/>
+ <pt x="1088" y="156" on="0"/>
+ <pt x="965" y="66" on="1"/>
+ <pt x="842" y="-25" on="0"/>
+ <pt x="622" y="-25" on="1"/>
+ <pt x="396" y="-25" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 61 values pushed */
+ 0 0 25 5 18 5 5 40 48 200 40 2 18 1 1 1 23 22 21 20 3 2 1 0 8
+ 1 2 3 0 0 14 0 0 29 19 16 7 28 36 48 200 16 23 22 16 3 2 5 20 0
+ 3 36 20 21 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="sacute" xMin="173" yMin="-25" xMax="1088" yMax="1604">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="113" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scaron" xMin="173" yMin="-25" xMax="1088" yMax="1604">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="15" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scedilla" xMin="173" yMin="-432" xMax="1088" yMax="1111">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="cedilla" x="26" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scircumflex" xMin="173" yMin="-25" xMax="1088" yMax="1604">
+ <contour>
+ <pt x="173" y="61" on="1"/>
+ <pt x="173" y="358" on="1"/>
+ <pt x="296" y="358" on="1"/>
+ <pt x="321" y="175" on="1"/>
+ <pt x="517" y="99" on="0"/>
+ <pt x="654" y="99" on="1"/>
+ <pt x="892" y="99" on="0"/>
+ <pt x="892" y="267" on="1"/>
+ <pt x="892" y="333" on="0"/>
+ <pt x="852" y="369" on="1"/>
+ <pt x="812" y="406" on="0"/>
+ <pt x="709" y="433" on="1"/>
+ <pt x="505" y="487" on="1"/>
+ <pt x="334" y="532" on="0"/>
+ <pt x="256" y="605" on="1"/>
+ <pt x="179" y="676" on="0"/>
+ <pt x="179" y="794" on="1"/>
+ <pt x="179" y="1111" on="0"/>
+ <pt x="611" y="1111" on="1"/>
+ <pt x="832" y="1111" on="0"/>
+ <pt x="1013" y="1039" on="1"/>
+ <pt x="1013" y="753" on="1"/>
+ <pt x="890" y="753" on="1"/>
+ <pt x="865" y="934" on="1"/>
+ <pt x="756" y="987" on="0"/>
+ <pt x="610" y="987" on="1"/>
+ <pt x="500" y="987" on="0"/>
+ <pt x="439" y="952" on="1"/>
+ <pt x="367" y="911" on="0"/>
+ <pt x="367" y="826" on="1"/>
+ <pt x="367" y="714" on="0"/>
+ <pt x="573" y="660" on="1"/>
+ <pt x="775" y="607" on="1"/>
+ <pt x="943" y="563" on="0"/>
+ <pt x="1016" y="495" on="1"/>
+ <pt x="1088" y="428" on="0"/>
+ <pt x="1088" y="313" on="1"/>
+ <pt x="1088" y="156" on="0"/>
+ <pt x="965" y="66" on="1"/>
+ <pt x="842" y="-25" on="0"/>
+ <pt x="622" y="-25" on="1"/>
+ <pt x="396" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="263" y="1283" on="1"/>
+ <pt x="519" y="1604" on="1"/>
+ <pt x="738" y="1604" on="1"/>
+ <pt x="994" y="1283" on="1"/>
+ <pt x="871" y="1283" on="1"/>
+ <pt x="630" y="1485" on="1"/>
+ <pt x="627" y="1485" on="1"/>
+ <pt x="386" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 25 5 18 5 5 40 48 200 40 2 18 1 1 49 48 47 46 45 42 6 43 1 3
+ 0 1 1 23 22 21 20 3 2 1 0 8 1 2 3 0 0 44 43 1 0 14 0 0 29
+ 19 16 7 28 36 48 200 16 49 48 47 46 45 44 43 42 23 22 16 3 2 13 20 0 3
+ 36 20 21 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="scommaaccent" xMin="173" yMin="-432" xMax="1088" yMax="1111">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="42" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="section" xMin="154" yMin="-333" xMax="1073" yMax="1518">
+ <contour>
+ <pt x="154" y="-259" on="1"/>
+ <pt x="154" y="62" on="1"/>
+ <pt x="277" y="62" on="1"/>
+ <pt x="302" y="-148" on="1"/>
+ <pt x="462" y="-210" on="0"/>
+ <pt x="617" y="-210" on="1"/>
+ <pt x="749" y="-210" on="0"/>
+ <pt x="825" y="-154" on="1"/>
+ <pt x="900" y="-99" on="0"/>
+ <pt x="900" y="-6" on="1"/>
+ <pt x="900" y="77" on="0"/>
+ <pt x="831" y="125" on="1"/>
+ <pt x="778" y="163" on="0"/>
+ <pt x="668" y="206" on="1"/>
+ <pt x="422" y="302" on="1"/>
+ <pt x="160" y="404" on="0"/>
+ <pt x="160" y="622" on="1"/>
+ <pt x="160" y="776" on="0"/>
+ <pt x="304" y="912" on="1"/>
+ <pt x="166" y="1013" on="0"/>
+ <pt x="166" y="1158" on="1"/>
+ <pt x="166" y="1330" on="0"/>
+ <pt x="298" y="1424" on="1"/>
+ <pt x="429" y="1518" on="0"/>
+ <pt x="673" y="1518" on="1"/>
+ <pt x="830" y="1518" on="0"/>
+ <pt x="1018" y="1474" on="1"/>
+ <pt x="1018" y="1154" on="1"/>
+ <pt x="894" y="1154" on="1"/>
+ <pt x="870" y="1357" on="1"/>
+ <pt x="740" y="1394" on="0"/>
+ <pt x="630" y="1394" on="1"/>
+ <pt x="498" y="1394" on="0"/>
+ <pt x="424" y="1352" on="1"/>
+ <pt x="339" y="1303" on="0"/>
+ <pt x="339" y="1202" on="1"/>
+ <pt x="339" y="1118" on="0"/>
+ <pt x="426" y="1054" on="1"/>
+ <pt x="477" y="1018" on="0"/>
+ <pt x="565" y="984" on="1"/>
+ <pt x="771" y="905" on="1"/>
+ <pt x="1048" y="799" on="0"/>
+ <pt x="1048" y="571" on="1"/>
+ <pt x="1048" y="426" on="0"/>
+ <pt x="919" y="281" on="1"/>
+ <pt x="1073" y="170" on="0"/>
+ <pt x="1073" y="13" on="1"/>
+ <pt x="1073" y="-145" on="0"/>
+ <pt x="945" y="-239" on="1"/>
+ <pt x="817" y="-333" on="0"/>
+ <pt x="590" y="-333" on="1"/>
+ <pt x="360" y="-333" on="0"/>
+ </contour>
+ <contour>
+ <pt x="811" y="344" on="1"/>
+ <pt x="900" y="442" on="0"/>
+ <pt x="900" y="533" on="1"/>
+ <pt x="900" y="664" on="0"/>
+ <pt x="714" y="732" on="1"/>
+ <pt x="458" y="826" on="1"/>
+ <pt x="410" y="845" on="1"/>
+ <pt x="327" y="757" on="0"/>
+ <pt x="327" y="672" on="1"/>
+ <pt x="327" y="541" on="0"/>
+ <pt x="491" y="474" on="1"/>
+ <pt x="760" y="365" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 0 0 31 5 24 5 5 50 48 200 24 0 1 58 52 44 29 28 27 26 18 3 2 1 0
+ 12 13 50 0 0 14 0 0 60 15 16 54 16 42 35 15 20 9 15 46 48 200 20 16 58
+ 52 44 29 28 20 18 16 3 2 10 26 0 3 46 42 26 27 26 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="semicolon" xMin="466" yMin="-321" xMax="762" yMax="1086">
+ <contour>
+ <pt x="466" y="0" on="1"/>
+ <pt x="466" y="296" on="1"/>
+ <pt x="762" y="296" on="1"/>
+ <pt x="762" y="116" on="1"/>
+ <pt x="760" y="-302" on="0"/>
+ <pt x="466" y="-321" on="1"/>
+ <pt x="466" y="-222" on="1"/>
+ <pt x="541" y="-210" on="0"/>
+ <pt x="563" y="-155" on="1"/>
+ <pt x="583" y="-107" on="0"/>
+ <pt x="589" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="466" y="790" on="1"/>
+ <pt x="466" y="1086" on="1"/>
+ <pt x="762" y="1086" on="1"/>
+ <pt x="762" y="790" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 1 3 1 2 2 0 1 10 6 5 0 4 13 2 0 0 0 14 11 8 1 12 1 4 48
+ 200 2 1 1 0 13 12 1 14 10 2 0 2 0 0 14 13 3 2 8 3 0 1 4 48
+ 200 12 11 6 5 1 0 5 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="semicolon#1" xMin="466" yMin="-321" xMax="762" yMax="1086">
+ <contour>
+ <pt x="466" y="0" on="1"/>
+ <pt x="466" y="296" on="1"/>
+ <pt x="762" y="296" on="1"/>
+ <pt x="762" y="116" on="1"/>
+ <pt x="760" y="-302" on="0"/>
+ <pt x="466" y="-321" on="1"/>
+ <pt x="466" y="-222" on="1"/>
+ <pt x="541" y="-210" on="0"/>
+ <pt x="563" y="-155" on="1"/>
+ <pt x="583" y="-107" on="0"/>
+ <pt x="589" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="466" y="790" on="1"/>
+ <pt x="466" y="1086" on="1"/>
+ <pt x="762" y="1086" on="1"/>
+ <pt x="762" y="790" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 1 3 1 2 2 0 1 10 6 5 0 4 13 2 0 0 0 14 11 8 1 12 1 4 48
+ 200 2 1 1 0 13 12 1 14 10 2 0 2 0 0 14 13 3 2 8 3 0 1 4 48
+ 200 12 11 6 5 1 0 5 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="145" yMin="0" xMax="1058" yMax="1480">
+ <contour>
+ <pt x="264" y="0" on="1"/>
+ <pt x="325" y="432" on="0"/>
+ <pt x="671" y="949" on="1"/>
+ <pt x="796" y="1133" on="1"/>
+ <pt x="905" y="1295" on="1"/>
+ <pt x="145" y="1295" on="1"/>
+ <pt x="145" y="1480" on="1"/>
+ <pt x="1058" y="1480" on="1"/>
+ <pt x="1058" y="1295" on="1"/>
+ <pt x="971" y="1176" on="1"/>
+ <pt x="716" y="824" on="0"/>
+ <pt x="595" y="465" on="1"/>
+ <pt x="512" y="215" on="0"/>
+ <pt x="511" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 35 values pushed */
+ 0 0 8 5 4 27 2 6 1 4 48 200 13 0 1 0 7 6 0 14 13 4 0 3 7
+ 5 3 8 7 1 6 5 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="sfthyphen" xMin="148" yMin="543" xMax="1081" yMax="691">
+ <contour>
+ <pt x="148" y="543" on="1"/>
+ <pt x="148" y="691" on="1"/>
+ <pt x="1081" y="691" on="1"/>
+ <pt x="1081" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 200 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="122" yMin="-37" xMax="1132" yMax="1517">
+ <contour>
+ <pt x="335" y="773" on="1"/>
+ <pt x="399" y="861" on="0"/>
+ <pt x="469" y="905" on="1"/>
+ <pt x="572" y="969" on="0"/>
+ <pt x="706" y="969" on="1"/>
+ <pt x="896" y="969" on="0"/>
+ <pt x="1014" y="835" on="1"/>
+ <pt x="1132" y="702" on="0"/>
+ <pt x="1132" y="486" on="1"/>
+ <pt x="1132" y="255" on="0"/>
+ <pt x="995" y="109" on="1"/>
+ <pt x="858" y="-37" on="0"/>
+ <pt x="642" y="-37" on="1"/>
+ <pt x="398" y="-37" on="0"/>
+ <pt x="260" y="161" on="1"/>
+ <pt x="122" y="360" on="0"/>
+ <pt x="122" y="710" on="1"/>
+ <pt x="122" y="1095" on="0"/>
+ <pt x="285" y="1306" on="1"/>
+ <pt x="448" y="1517" on="0"/>
+ <pt x="738" y="1517" on="1"/>
+ <pt x="866" y="1517" on="0"/>
+ <pt x="1064" y="1446" on="1"/>
+ <pt x="1064" y="1129" on="1"/>
+ <pt x="940" y="1129" on="1"/>
+ <pt x="917" y="1339" on="1"/>
+ <pt x="830" y="1394" on="0"/>
+ <pt x="739" y="1394" on="1"/>
+ <pt x="524" y="1394" on="0"/>
+ <pt x="415" y="1178" on="1"/>
+ <pt x="338" y="1027" on="0"/>
+ </contour>
+ <contour>
+ <pt x="669" y="839" on="1"/>
+ <pt x="534" y="839" on="0"/>
+ <pt x="442" y="736" on="1"/>
+ <pt x="350" y="634" on="0"/>
+ <pt x="350" y="480" on="1"/>
+ <pt x="350" y="320" on="0"/>
+ <pt x="443" y="203" on="1"/>
+ <pt x="536" y="86" on="0"/>
+ <pt x="667" y="86" on="1"/>
+ <pt x="778" y="86" on="0"/>
+ <pt x="846" y="165" on="1"/>
+ <pt x="932" y="265" on="0"/>
+ <pt x="932" y="463" on="1"/>
+ <pt x="932" y="839" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 39 5 12 31 25 4 27 5 20 48 200 20 0 12 2 4 1 1 25 24 23 22 4
+ 0 6 0 2 3 0 0 14 0 0 43 24 8 35 26 16 48 200 8 22 25 24 0 3 13
+ 16 22 23 22 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="slash" xMin="99" yMin="-296" xMax="1131" yMax="1579">
+ <contour>
+ <pt x="99" y="-296" on="1"/>
+ <pt x="967" y="1579" on="1"/>
+ <pt x="1131" y="1579" on="1"/>
+ <pt x="262" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 2 1 1 3 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="space"/><!-- contains no outline data -->
+
+ <TTGlyph name="sterling" xMin="149" yMin="0" xMax="1043" yMax="1517">
+ <contour>
+ <pt x="149" y="0" on="1"/>
+ <pt x="149" y="179" on="1"/>
+ <pt x="351" y="249" on="0"/>
+ <pt x="353" y="511" on="1"/>
+ <pt x="353" y="728" on="1"/>
+ <pt x="180" y="728" on="1"/>
+ <pt x="180" y="851" on="1"/>
+ <pt x="353" y="851" on="1"/>
+ <pt x="353" y="1110" on="1"/>
+ <pt x="353" y="1298" on="0"/>
+ <pt x="458" y="1407" on="1"/>
+ <pt x="563" y="1517" on="0"/>
+ <pt x="746" y="1517" on="1"/>
+ <pt x="874" y="1517" on="0"/>
+ <pt x="1028" y="1468" on="1"/>
+ <pt x="1028" y="1160" on="1"/>
+ <pt x="905" y="1160" on="1"/>
+ <pt x="880" y="1369" on="1"/>
+ <pt x="800" y="1394" on="0"/>
+ <pt x="740" y="1394" on="1"/>
+ <pt x="550" y="1394" on="0"/>
+ <pt x="550" y="1191" on="1"/>
+ <pt x="550" y="851" on="1"/>
+ <pt x="815" y="851" on="1"/>
+ <pt x="815" y="728" on="1"/>
+ <pt x="550" y="728" on="1"/>
+ <pt x="550" y="559" on="1"/>
+ <pt x="549" y="305" on="0"/>
+ <pt x="368" y="173" on="1"/>
+ <pt x="1043" y="173" on="1"/>
+ <pt x="1043" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 104 values pushed */
+ 0 0 19 5 12 48 200 12 0 1 21 17 16 15 14 8 6 0 6 3 0 26 3 1 3
+ 4 28 3 0 0 25 24 5 4 6 3 6 29 28 22 1 0 2 4 48 200 23 22 7 6
+ 3 30 0 1 2 0 14 24 23 17 16 4 14 21 3 28 21 3 2 6 5 2 3 0 3
+ 0 0 26 25 22 21 10 3 3 1 4 48 200 30 29 1 15 14 1 8 7 4 3 3 1
+ 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="t" xMin="119" yMin="-25" xMax="1032" yMax="1332">
+ <contour>
+ <pt x="1032" y="61" on="1"/>
+ <pt x="867" y="-25" on="0"/>
+ <pt x="696" y="-25" on="1"/>
+ <pt x="535" y="-25" on="0"/>
+ <pt x="466" y="50" on="1"/>
+ <pt x="397" y="124" on="0"/>
+ <pt x="397" y="299" on="1"/>
+ <pt x="397" y="925" on="1"/>
+ <pt x="119" y="925" on="1"/>
+ <pt x="119" y="1061" on="1"/>
+ <pt x="397" y="1061" on="1"/>
+ <pt x="397" y="1332" on="1"/>
+ <pt x="594" y="1332" on="1"/>
+ <pt x="594" y="1061" on="1"/>
+ <pt x="1020" y="1061" on="1"/>
+ <pt x="1020" y="925" on="1"/>
+ <pt x="594" y="925" on="1"/>
+ <pt x="594" y="388" on="1"/>
+ <pt x="594" y="228" on="0"/>
+ <pt x="626" y="176" on="1"/>
+ <pt x="658" y="123" on="0"/>
+ <pt x="753" y="123" on="1"/>
+ <pt x="859" y="123" on="0"/>
+ <pt x="1032" y="200" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 21 14 2 48 200 2 2 1 23 17 6 0 4 7 2 3 0 0 0 16 15 8 7
+ 20 3 9 1 4 48 200 12 11 1 14 13 10 9 3 2 0 14 15 14 2 0 12 3 9
+ 8 6 0 0 17 16 13 12 10 3 6 1 4 48 200 23 0 1 11 10 7 6 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tbar" xMin="119" yMin="-25" xMax="1032" yMax="1332">
+ <contour>
+ <pt x="1032" y="200" on="1"/>
+ <pt x="1032" y="61" on="1"/>
+ <pt x="867" y="-25" on="0"/>
+ <pt x="696" y="-25" on="1"/>
+ <pt x="535" y="-25" on="0"/>
+ <pt x="466" y="50" on="1"/>
+ <pt x="397" y="124" on="0"/>
+ <pt x="397" y="299" on="1"/>
+ <pt x="397" y="605" on="1"/>
+ <pt x="168" y="605" on="1"/>
+ <pt x="168" y="703" on="1"/>
+ <pt x="397" y="703" on="1"/>
+ <pt x="397" y="925" on="1"/>
+ <pt x="119" y="925" on="1"/>
+ <pt x="119" y="1061" on="1"/>
+ <pt x="397" y="1061" on="1"/>
+ <pt x="397" y="1332" on="1"/>
+ <pt x="594" y="1332" on="1"/>
+ <pt x="594" y="1061" on="1"/>
+ <pt x="1020" y="1061" on="1"/>
+ <pt x="1020" y="925" on="1"/>
+ <pt x="594" y="925" on="1"/>
+ <pt x="594" y="703" on="1"/>
+ <pt x="896" y="703" on="1"/>
+ <pt x="896" y="605" on="1"/>
+ <pt x="594" y="605" on="1"/>
+ <pt x="594" y="388" on="1"/>
+ <pt x="594" y="228" on="0"/>
+ <pt x="626" y="176" on="1"/>
+ <pt x="658" y="123" on="0"/>
+ <pt x="753" y="123" on="1"/>
+ <pt x="859" y="123" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 0 0 30 14 3 48 200 3 2 1 26 7 1 0 4 8 2 3 0 0 0 21 20 13 12
+ 20 3 14 25 24 9 8 33 3 10 2 4 48 200 17 16 1 19 18 15 14 3 23 22 11
+ 10 3 3 0 14 24 23 20 19 4 0 17 3 14 13 10 9 4 13 7 0 0 26 25 22
+ 21 18 17 10 5 7 1 4 48 200 1 0 1 16 15 12 11 8 7 5 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcaron" xMin="119" yMin="-25" xMax="1032" yMax="1688">
+ <contour>
+ <pt x="1032" y="61" on="1"/>
+ <pt x="867" y="-25" on="0"/>
+ <pt x="696" y="-25" on="1"/>
+ <pt x="535" y="-25" on="0"/>
+ <pt x="466" y="50" on="1"/>
+ <pt x="397" y="124" on="0"/>
+ <pt x="397" y="299" on="1"/>
+ <pt x="397" y="925" on="1"/>
+ <pt x="119" y="925" on="1"/>
+ <pt x="119" y="1061" on="1"/>
+ <pt x="397" y="1061" on="1"/>
+ <pt x="397" y="1332" on="1"/>
+ <pt x="594" y="1332" on="1"/>
+ <pt x="594" y="1061" on="1"/>
+ <pt x="1020" y="1061" on="1"/>
+ <pt x="1020" y="925" on="1"/>
+ <pt x="594" y="925" on="1"/>
+ <pt x="594" y="388" on="1"/>
+ <pt x="594" y="228" on="0"/>
+ <pt x="626" y="176" on="1"/>
+ <pt x="658" y="123" on="0"/>
+ <pt x="753" y="123" on="1"/>
+ <pt x="859" y="123" on="0"/>
+ <pt x="1032" y="200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="767" y="1234" on="1"/>
+ <pt x="767" y="1293" on="1"/>
+ <pt x="843" y="1314" on="0"/>
+ <pt x="843" y="1474" on="1"/>
+ <pt x="843" y="1491" on="1"/>
+ <pt x="767" y="1491" on="1"/>
+ <pt x="767" y="1688" on="1"/>
+ <pt x="964" y="1688" on="1"/>
+ <pt x="964" y="1517" on="1"/>
+ <pt x="963" y="1255" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 0 0 21 14 2 48 200 2 2 32 29 28 27 4 30 11 3 25 24 2 11 9 3 1 23
+ 17 6 0 4 7 2 3 0 0 0 16 15 8 7 20 3 9 1 4 48 200 31 30 1 12
+ 11 1 14 13 10 9 3 3 0 14 15 14 2 0 31 3 28 27 2 31 24 3 9 8 6
+ 0 0 30 29 25 24 10 3 31 17 16 13 12 10 3 6 2 4 48 200 32 31 1 23 0
+ 1 11 10 7 6 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcommaaccent" xMin="119" yMin="-432" xMax="1032" yMax="1332">
+ <contour>
+ <pt x="1032" y="61" on="1"/>
+ <pt x="867" y="-25" on="0"/>
+ <pt x="696" y="-25" on="1"/>
+ <pt x="535" y="-25" on="0"/>
+ <pt x="466" y="50" on="1"/>
+ <pt x="397" y="124" on="0"/>
+ <pt x="397" y="299" on="1"/>
+ <pt x="397" y="925" on="1"/>
+ <pt x="119" y="925" on="1"/>
+ <pt x="119" y="1061" on="1"/>
+ <pt x="397" y="1061" on="1"/>
+ <pt x="397" y="1332" on="1"/>
+ <pt x="594" y="1332" on="1"/>
+ <pt x="594" y="1061" on="1"/>
+ <pt x="1020" y="1061" on="1"/>
+ <pt x="1020" y="925" on="1"/>
+ <pt x="594" y="925" on="1"/>
+ <pt x="594" y="388" on="1"/>
+ <pt x="594" y="228" on="0"/>
+ <pt x="626" y="176" on="1"/>
+ <pt x="658" y="123" on="0"/>
+ <pt x="753" y="123" on="1"/>
+ <pt x="860" y="123" on="0"/>
+ <pt x="1032" y="200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="627" y="0" on="1"/>
+ <pt x="724" y="0" on="1"/>
+ <pt x="664" y="-109" on="1"/>
+ <pt x="736" y="-111" on="0"/>
+ <pt x="788" y="-148" on="1"/>
+ <pt x="858" y="-197" on="0"/>
+ <pt x="858" y="-269" on="1"/>
+ <pt x="858" y="-337" on="0"/>
+ <pt x="799" y="-384" on="1"/>
+ <pt x="741" y="-432" on="0"/>
+ <pt x="654" y="-432" on="1"/>
+ <pt x="587" y="-432" on="0"/>
+ <pt x="511" y="-411" on="1"/>
+ <pt x="511" y="-330" on="1"/>
+ <pt x="561" y="-345" on="0"/>
+ <pt x="615" y="-345" on="1"/>
+ <pt x="719" y="-345" on="0"/>
+ <pt x="719" y="-271" on="1"/>
+ <pt x="719" y="-178" on="0"/>
+ <pt x="532" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 39 32 34 21 14 2 48 200 2 2 1 23 17 6 0 4 7 2 3 0 1 43 37
+ 36 26 25 24 6 13 34 2 0 0 0 16 15 8 7 20 3 9 1 4 48 200 12 11 1
+ 14 13 10 9 3 2 0 14 0 0 41 20 30 48 200 30 30 26 25 24 15 14 6 0 12
+ 3 43 37 36 3 12 6 3 9 8 6 0 0 17 16 13 12 10 3 6 1 4 48 200 23
+ 0 1 11 10 7 6 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcommabelow" xMin="119" yMin="-432" xMax="1032" yMax="1332">
+ <component glyphName="t" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="62" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="thorn" xMin="62" yMin="-395" xMax="1118" yMax="1579">
+ <contour>
+ <pt x="185" y="-272" on="1"/>
+ <pt x="185" y="1456" on="1"/>
+ <pt x="62" y="1456" on="1"/>
+ <pt x="62" y="1579" on="1"/>
+ <pt x="383" y="1579" on="1"/>
+ <pt x="383" y="864" on="1"/>
+ <pt x="458" y="975" on="0"/>
+ <pt x="529" y="1030" on="1"/>
+ <pt x="631" y="1110" on="0"/>
+ <pt x="749" y="1110" on="1"/>
+ <pt x="914" y="1110" on="0"/>
+ <pt x="1016" y="967" on="1"/>
+ <pt x="1118" y="823" on="0"/>
+ <pt x="1118" y="588" on="1"/>
+ <pt x="1118" y="302" on="0"/>
+ <pt x="983" y="139" on="1"/>
+ <pt x="849" y="-25" on="0"/>
+ <pt x="614" y="-25" on="1"/>
+ <pt x="526" y="-25" on="0"/>
+ <pt x="383" y="0" on="1"/>
+ <pt x="383" y="-272" on="1"/>
+ <pt x="630" y="-272" on="1"/>
+ <pt x="630" y="-395" on="1"/>
+ <pt x="62" y="-395" on="1"/>
+ <pt x="62" y="-272" on="1"/>
+ </contour>
+ <contour>
+ <pt x="383" y="146" on="1"/>
+ <pt x="518" y="123" on="0"/>
+ <pt x="591" y="123" on="1"/>
+ <pt x="908" y="123" on="0"/>
+ <pt x="908" y="591" on="1"/>
+ <pt x="908" y="950" on="0"/>
+ <pt x="694" y="950" on="1"/>
+ <pt x="530" y="950" on="0"/>
+ <pt x="383" y="716" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 100 values pushed */
+ 0 0 31 30 9 27 14 17 48 200 17 2 9 1 1 2 1 2 3 1 3 0 1 1 33
+ 25 5 3 1 2 3 0 0 1 19 2 0 2 0 0 0 24 21 20 0 6 3 22 1 4
+ 48 200 4 3 1 23 22 1 2 0 14 0 0 29 39 13 48 200 22 21 2 13 13 4 24
+ 23 3 2 4 13 0 0 0 33 25 20 19 5 4 10 5 0 1 4 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="185" yMin="-37" xMax="1081" yMax="1517">
+ <contour>
+ <pt x="185" y="10" on="1"/>
+ <pt x="185" y="384" on="1"/>
+ <pt x="308" y="384" on="1"/>
+ <pt x="333" y="138" on="1"/>
+ <pt x="419" y="86" on="0"/>
+ <pt x="538" y="86" on="1"/>
+ <pt x="691" y="86" on="0"/>
+ <pt x="781" y="173" on="1"/>
+ <pt x="871" y="260" on="0"/>
+ <pt x="871" y="409" on="1"/>
+ <pt x="871" y="728" on="0"/>
+ <pt x="455" y="728" on="1"/>
+ <pt x="320" y="728" on="1"/>
+ <pt x="320" y="851" on="1"/>
+ <pt x="434" y="851" on="1"/>
+ <pt x="829" y="851" on="0"/>
+ <pt x="829" y="1147" on="1"/>
+ <pt x="829" y="1261" on="0"/>
+ <pt x="756" y="1327" on="1"/>
+ <pt x="684" y="1394" on="0"/>
+ <pt x="557" y="1394" on="1"/>
+ <pt x="439" y="1394" on="0"/>
+ <pt x="355" y="1355" on="1"/>
+ <pt x="343" y="1146" on="1"/>
+ <pt x="219" y="1146" on="1"/>
+ <pt x="219" y="1464" on="1"/>
+ <pt x="412" y="1517" on="0"/>
+ <pt x="577" y="1517" on="1"/>
+ <pt x="1030" y="1517" on="0"/>
+ <pt x="1030" y="1164" on="1"/>
+ <pt x="1030" y="1001" on="0"/>
+ <pt x="925" y="901" on="1"/>
+ <pt x="861" y="842" on="0"/>
+ <pt x="742" y="798" on="1"/>
+ <pt x="847" y="767" on="0"/>
+ <pt x="902" y="733" on="1"/>
+ <pt x="1081" y="622" on="0"/>
+ <pt x="1081" y="399" on="1"/>
+ <pt x="1081" y="205" on="0"/>
+ <pt x="943" y="84" on="1"/>
+ <pt x="805" y="-37" on="0"/>
+ <pt x="576" y="-37" on="1"/>
+ <pt x="421" y="-37" on="0"/>
+ <pt x="270" y="-7" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 20 5 27 5 5 41 48 200 41 2 27 0 1 1 33 25 24 23 22 14 13 12 11
+ 3 2 1 0 13 0 2 3 0 0 14 0 0 16 24 29 9 39 37 48 200 33 23 22 14
+ 13 12 11 3 2 9 13 37 29 24 0 0 25 24 23 1 0 1 5 48 200 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="threequarters" xMin="37" yMin="-37" xMax="1205" yMax="1518">
+ <contour>
+ <pt x="173" y="-37" on="1"/>
+ <pt x="950" y="1517" on="1"/>
+ <pt x="1091" y="1517" on="1"/>
+ <pt x="311" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="37" y="752" on="1"/>
+ <pt x="37" y="916" on="1"/>
+ <pt x="148" y="916" on="1"/>
+ <pt x="148" y="854" on="1"/>
+ <pt x="195" y="827" on="0"/>
+ <pt x="256" y="827" on="1"/>
+ <pt x="380" y="827" on="0"/>
+ <pt x="380" y="946" on="1"/>
+ <pt x="380" y="1076" on="0"/>
+ <pt x="197" y="1076" on="1"/>
+ <pt x="161" y="1076" on="1"/>
+ <pt x="161" y="1187" on="1"/>
+ <pt x="200" y="1187" on="1"/>
+ <pt x="380" y="1187" on="0"/>
+ <pt x="380" y="1304" on="1"/>
+ <pt x="380" y="1406" on="0"/>
+ <pt x="260" y="1406" on="1"/>
+ <pt x="198" y="1406" on="0"/>
+ <pt x="148" y="1375" on="1"/>
+ <pt x="148" y="1313" on="1"/>
+ <pt x="37" y="1313" on="1"/>
+ <pt x="37" y="1469" on="1"/>
+ <pt x="177" y="1518" on="0"/>
+ <pt x="283" y="1518" on="1"/>
+ <pt x="531" y="1518" on="0"/>
+ <pt x="531" y="1334" on="1"/>
+ <pt x="531" y="1204" on="0"/>
+ <pt x="355" y="1129" on="1"/>
+ <pt x="529" y="1084" on="0"/>
+ <pt x="529" y="941" on="1"/>
+ <pt x="529" y="836" on="0"/>
+ <pt x="452" y="776" on="1"/>
+ <pt x="375" y="715" on="0"/>
+ <pt x="244" y="715" on="1"/>
+ <pt x="165" y="715" on="0"/>
+ <pt x="61" y="745" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1094" y="0" on="1"/>
+ <pt x="945" y="0" on="1"/>
+ <pt x="945" y="179" on="1"/>
+ <pt x="571" y="179" on="1"/>
+ <pt x="571" y="302" on="1"/>
+ <pt x="941" y="790" on="1"/>
+ <pt x="1094" y="790" on="1"/>
+ <pt x="1094" y="302" on="1"/>
+ <pt x="1205" y="302" on="1"/>
+ <pt x="1205" y="179" on="1"/>
+ <pt x="1094" y="179" on="1"/>
+ </contour>
+ <contour>
+ <pt x="709" y="302" on="1"/>
+ <pt x="945" y="302" on="1"/>
+ <pt x="945" y="611" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 139 values pushed */
+ 0 0 20 31 27 9 31 37 48 200 31 25 24 23 22 16 15 14 13 7 6 5 12 1 45
+ 3 37 53 37 4 3 45 44 3 27 1 0 0 52 51 48 47 44 6 4 42 1 4 48 200
+ 46 45 1 50 49 43 42 3 41 40 1 2 1 1 3 0 1 5 0 14 0 0 18 38 29
+ 11 38 33 48 200 2 1 2 40 41 3 33 29 51 45 44 43 33 31 29 23 22 16 15 14
+ 13 7 6 3 0 17 41 4 3 49 48 2 13 40 0 0 53 52 42 41 16 3 40 1 4
+ 48 200 50 47 46 40 3 25 24 5 4 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="threesuperior" xMin="263" yMin="715" xMax="966" yMax="1518">
+ <contour>
+ <pt x="263" y="752" on="1"/>
+ <pt x="263" y="925" on="1"/>
+ <pt x="386" y="925" on="1"/>
+ <pt x="398" y="857" on="1"/>
+ <pt x="468" y="839" on="0"/>
+ <pt x="561" y="839" on="1"/>
+ <pt x="787" y="839" on="0"/>
+ <pt x="787" y="943" on="1"/>
+ <pt x="787" y="1027" on="0"/>
+ <pt x="691" y="1050" on="1"/>
+ <pt x="618" y="1067" on="0"/>
+ <pt x="465" y="1067" on="1"/>
+ <pt x="374" y="1067" on="1"/>
+ <pt x="374" y="1191" on="1"/>
+ <pt x="469" y="1191" on="1"/>
+ <pt x="659" y="1191" on="0"/>
+ <pt x="723" y="1213" on="1"/>
+ <pt x="787" y="1234" on="0"/>
+ <pt x="787" y="1296" on="1"/>
+ <pt x="787" y="1394" on="0"/>
+ <pt x="595" y="1394" on="1"/>
+ <pt x="477" y="1394" on="0"/>
+ <pt x="398" y="1364" on="1"/>
+ <pt x="386" y="1283" on="1"/>
+ <pt x="263" y="1283" on="1"/>
+ <pt x="263" y="1468" on="1"/>
+ <pt x="433" y="1518" on="0"/>
+ <pt x="606" y="1518" on="1"/>
+ <pt x="966" y="1518" on="0"/>
+ <pt x="966" y="1326" on="1"/>
+ <pt x="966" y="1196" on="0"/>
+ <pt x="754" y="1126" on="1"/>
+ <pt x="966" y="1080" on="0"/>
+ <pt x="966" y="933" on="1"/>
+ <pt x="966" y="715" on="0"/>
+ <pt x="577" y="715" on="1"/>
+ <pt x="431" y="715" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 20 6 27 5 6 35 48 200 35 31 27 25 24 23 22 14 13 12 11 3 2 1 0
+ 14 0 0 18 13 29 7 13 33 48 200 31 23 22 14 13 12 11 3 2 9 13 33 29 0
+ 25 24 1 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="threesuperiour" xMin="365" yMin="715" xMax="858" yMax="1518">
+ <contour>
+ <pt x="365" y="752" on="1"/>
+ <pt x="365" y="916" on="1"/>
+ <pt x="476" y="916" on="1"/>
+ <pt x="476" y="854" on="1"/>
+ <pt x="524" y="827" on="0"/>
+ <pt x="583" y="827" on="1"/>
+ <pt x="707" y="827" on="0"/>
+ <pt x="707" y="946" on="1"/>
+ <pt x="707" y="1076" on="0"/>
+ <pt x="525" y="1076" on="1"/>
+ <pt x="488" y="1076" on="1"/>
+ <pt x="488" y="1187" on="1"/>
+ <pt x="528" y="1187" on="1"/>
+ <pt x="707" y="1187" on="0"/>
+ <pt x="707" y="1303" on="1"/>
+ <pt x="707" y="1406" on="0"/>
+ <pt x="588" y="1406" on="1"/>
+ <pt x="527" y="1406" on="0"/>
+ <pt x="476" y="1375" on="1"/>
+ <pt x="476" y="1313" on="1"/>
+ <pt x="365" y="1313" on="1"/>
+ <pt x="365" y="1469" on="1"/>
+ <pt x="505" y="1518" on="0"/>
+ <pt x="611" y="1518" on="1"/>
+ <pt x="858" y="1518" on="0"/>
+ <pt x="858" y="1334" on="1"/>
+ <pt x="858" y="1204" on="0"/>
+ <pt x="682" y="1129" on="1"/>
+ <pt x="785" y="1102" on="0"/>
+ <pt x="825" y="1048" on="1"/>
+ <pt x="857" y="1004" on="0"/>
+ <pt x="857" y="941" on="1"/>
+ <pt x="857" y="836" on="0"/>
+ <pt x="780" y="776" on="1"/>
+ <pt x="704" y="715" on="0"/>
+ <pt x="572" y="715" on="1"/>
+ <pt x="487" y="715" on="0"/>
+ <pt x="388" y="745" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 16 31 23 5 31 35 48 200 35 27 23 21 20 19 18 12 11 10 9 3 2 1 0
+ 14 0 0 14 38 25 7 38 31 48 200 27 19 18 12 11 10 9 3 2 9 13 31 25 0
+ 21 20 1 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tilde" xMin="281" yMin="1283" xMax="947" yMax="1518">
+ <contour>
+ <pt x="281" y="1283" on="1"/>
+ <pt x="287" y="1377" on="0"/>
+ <pt x="312" y="1428" on="1"/>
+ <pt x="357" y="1518" on="0"/>
+ <pt x="466" y="1518" on="1"/>
+ <pt x="538" y="1518" on="0"/>
+ <pt x="601" y="1479" on="1"/>
+ <pt x="661" y="1442" on="1"/>
+ <pt x="723" y="1404" on="0"/>
+ <pt x="757" y="1404" on="1"/>
+ <pt x="825" y="1404" on="0"/>
+ <pt x="836" y="1518" on="1"/>
+ <pt x="947" y="1518" on="1"/>
+ <pt x="940" y="1424" on="0"/>
+ <pt x="915" y="1374" on="1"/>
+ <pt x="869" y="1283" on="0"/>
+ <pt x="762" y="1283" on="1"/>
+ <pt x="689" y="1283" on="0"/>
+ <pt x="626" y="1322" on="1"/>
+ <pt x="566" y="1359" on="1"/>
+ <pt x="506" y="1396" on="0"/>
+ <pt x="470" y="1396" on="1"/>
+ <pt x="402" y="1396" on="0"/>
+ <pt x="391" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 0 0 21 5 4 9 5 16 48 200 4 0 1 12 11 2 13 0 0 1 23 0 16 0 0
+ 14 23 12 11 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="trademark" xMin="43" yMin="740" xMax="1196" yMax="1480">
+ <contour>
+ <pt x="142" y="740" on="1"/>
+ <pt x="142" y="833" on="1"/>
+ <pt x="219" y="833" on="1"/>
+ <pt x="219" y="1388" on="1"/>
+ <pt x="132" y="1388" on="1"/>
+ <pt x="132" y="1289" on="1"/>
+ <pt x="43" y="1289" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ <pt x="506" y="1480" on="1"/>
+ <pt x="506" y="1289" on="1"/>
+ <pt x="417" y="1289" on="1"/>
+ <pt x="417" y="1388" on="1"/>
+ <pt x="330" y="1388" on="1"/>
+ <pt x="330" y="833" on="1"/>
+ <pt x="407" y="833" on="1"/>
+ <pt x="407" y="740" on="1"/>
+ </contour>
+ <contour>
+ <pt x="555" y="740" on="1"/>
+ <pt x="555" y="833" on="1"/>
+ <pt x="613" y="833" on="1"/>
+ <pt x="613" y="1388" on="1"/>
+ <pt x="555" y="1388" on="1"/>
+ <pt x="555" y="1480" on="1"/>
+ <pt x="767" y="1480" on="1"/>
+ <pt x="889" y="1037" on="1"/>
+ <pt x="995" y="1480" on="1"/>
+ <pt x="1196" y="1480" on="1"/>
+ <pt x="1196" y="1388" on="1"/>
+ <pt x="1138" y="1388" on="1"/>
+ <pt x="1138" y="833" on="1"/>
+ <pt x="1196" y="833" on="1"/>
+ <pt x="1196" y="740" on="1"/>
+ <pt x="1033" y="740" on="1"/>
+ <pt x="1033" y="1319" on="1"/>
+ <pt x="1032" y="1319" on="1"/>
+ <pt x="916" y="876" on="1"/>
+ <pt x="829" y="876" on="1"/>
+ <pt x="714" y="1289" on="1"/>
+ <pt x="712" y="1289" on="1"/>
+ <pt x="712" y="740" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 129 values pushed */
+ 37 36 35 34 33 32 29 28 27 26 23 20 19 18 17 14 13 12 11 10 9 6 5 4 3
+ 2 1 27 7 0 3 38 31 30 16 15 0 5 0 25 24 22 21 8 7 0 5 14 36 35
+ 34 33 24 23 22 7 31 37 3 21 20 17 16 4 18 8 3 15 14 11 10 4 8 12 3
+ 5 4 1 0 4 2 6 3 30 29 26 25 4 13 27 0 0 32 31 18 1 27 38 37 18
+ 1 18 2 4 13 12 1 2 1 6 48 200 28 27 1 19 18 1 9 8 1 3 2 1 7
+ 6 1 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="133" yMin="0" xMax="1108" yMax="1517">
+ <contour>
+ <pt x="133" y="0" on="1"/>
+ <pt x="133" y="173" on="1"/>
+ <pt x="243" y="359" on="0"/>
+ <pt x="391" y="493" on="1"/>
+ <pt x="494" y="586" on="1"/>
+ <pt x="616" y="698" on="1"/>
+ <pt x="854" y="916" on="0"/>
+ <pt x="854" y="1119" on="1"/>
+ <pt x="854" y="1244" on="0"/>
+ <pt x="778" y="1319" on="1"/>
+ <pt x="703" y="1394" on="0"/>
+ <pt x="577" y="1394" on="1"/>
+ <pt x="459" y="1394" on="0"/>
+ <pt x="318" y="1308" on="1"/>
+ <pt x="294" y="1073" on="1"/>
+ <pt x="170" y="1073" on="1"/>
+ <pt x="170" y="1423" on="1"/>
+ <pt x="416" y="1517" on="0"/>
+ <pt x="616" y="1517" on="1"/>
+ <pt x="823" y="1517" on="0"/>
+ <pt x="944" y="1409" on="1"/>
+ <pt x="1064" y="1302" on="0"/>
+ <pt x="1064" y="1118" on="1"/>
+ <pt x="1064" y="986" on="0"/>
+ <pt x="1009" y="889" on="1"/>
+ <pt x="952" y="788" on="0"/>
+ <pt x="808" y="668" on="1"/>
+ <pt x="723" y="597" on="1"/>
+ <pt x="503" y="411" on="0"/>
+ <pt x="441" y="329" on="1"/>
+ <pt x="385" y="257" on="0"/>
+ <pt x="356" y="173" on="1"/>
+ <pt x="1108" y="173" on="1"/>
+ <pt x="1108" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 0 0 11 5 18 48 200 18 0 1 16 15 14 13 4 0 1 3 0 0 0 32 31 1 22
+ 2 0 1 4 48 200 33 0 1 0 14 0 0 7 39 22 48 200 22 31 22 14 13 4 32
+ 15 3 33 32 1 16 15 1 1 0 1 3 0
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="twosuperior" xMin="257" yMin="728" xMax="972" yMax="1518">
+ <contour>
+ <pt x="257" y="728" on="1"/>
+ <pt x="257" y="876" on="1"/>
+ <pt x="298" y="971" on="0"/>
+ <pt x="364" y="1015" on="1"/>
+ <pt x="424" y="1055" on="0"/>
+ <pt x="551" y="1105" on="1"/>
+ <pt x="647" y="1143" on="1"/>
+ <pt x="781" y="1196" on="0"/>
+ <pt x="781" y="1278" on="1"/>
+ <pt x="781" y="1394" on="0"/>
+ <pt x="589" y="1394" on="1"/>
+ <pt x="475" y="1394" on="0"/>
+ <pt x="392" y="1357" on="1"/>
+ <pt x="380" y="1265" on="1"/>
+ <pt x="257" y="1265" on="1"/>
+ <pt x="257" y="1468" on="1"/>
+ <pt x="294" y="1477" on="1"/>
+ <pt x="462" y="1518" on="0"/>
+ <pt x="592" y="1518" on="1"/>
+ <pt x="960" y="1518" on="0"/>
+ <pt x="960" y="1295" on="1"/>
+ <pt x="960" y="1138" on="0"/>
+ <pt x="752" y="1062" on="1"/>
+ <pt x="670" y="1032" on="1"/>
+ <pt x="490" y="966" on="0"/>
+ <pt x="460" y="876" on="1"/>
+ <pt x="972" y="876" on="1"/>
+ <pt x="972" y="728" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 0 10 6 18 48 200 15 14 13 12 4 13 18 1 0 0 27 0 16 1 1 1 4 48
+ 200 26 25 1 2 0 14 0 0 8 13 20 48 200 20 25 20 13 12 4 26 0 3 27 26
+ 1 15 14 1 0 3 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="twosuperiour" xMin="361" yMin="728" xMax="867" yMax="1517">
+ <contour>
+ <pt x="361" y="728" on="1"/>
+ <pt x="361" y="882" on="1"/>
+ <pt x="405" y="970" on="0"/>
+ <pt x="523" y="1056" on="1"/>
+ <pt x="553" y="1078" on="0"/>
+ <pt x="568" y="1090" on="1"/>
+ <pt x="601" y="1120" on="1"/>
+ <pt x="657" y="1167" on="1"/>
+ <pt x="706" y="1208" on="0"/>
+ <pt x="706" y="1283" on="1"/>
+ <pt x="706" y="1406" on="0"/>
+ <pt x="578" y="1406" on="1"/>
+ <pt x="534" y="1406" on="0"/>
+ <pt x="472" y="1377" on="1"/>
+ <pt x="472" y="1310" on="1"/>
+ <pt x="361" y="1310" on="1"/>
+ <pt x="361" y="1468" on="1"/>
+ <pt x="471" y="1517" on="0"/>
+ <pt x="590" y="1517" on="1"/>
+ <pt x="867" y="1517" on="0"/>
+ <pt x="867" y="1302" on="1"/>
+ <pt x="867" y="1173" on="0"/>
+ <pt x="730" y="1072" on="1"/>
+ <pt x="696" y="1047" on="1"/>
+ <pt x="696" y="1047" on="1"/>
+ <pt x="695" y="1046" on="1"/>
+ <pt x="693" y="1045" on="1"/>
+ <pt x="691" y="1044" on="0"/>
+ <pt x="679" y="1035" on="1"/>
+ <pt x="660" y="1022" on="1"/>
+ <pt x="550" y="948" on="0"/>
+ <pt x="524" y="876" on="1"/>
+ <pt x="867" y="876" on="1"/>
+ <pt x="867" y="728" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 0 0 11 18 48 200 24 23 16 15 14 13 1 7 13 18 31 0 0 33 0 16 1 31 1
+ 4 48 200 32 31 1 0 14 0 0 9 34 20 48 200 31 24 23 14 13 5 20 0 3 33
+ 32 20 2 16 15 1 0 3 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="u" xMin="68" yMin="-25" xMax="1166" yMax="1086">
+ <contour>
+ <pt x="734" y="1086" on="1"/>
+ <pt x="1043" y="1086" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1166" y="123" on="1"/>
+ <pt x="1166" y="0" on="1"/>
+ <pt x="845" y="0" on="1"/>
+ <pt x="845" y="209" on="1"/>
+ <pt x="776" y="104" on="0"/>
+ <pt x="708" y="51" on="1"/>
+ <pt x="612" y="-25" on="0"/>
+ <pt x="493" y="-25" on="1"/>
+ <pt x="191" y="-25" on="0"/>
+ <pt x="191" y="363" on="1"/>
+ <pt x="191" y="962" on="1"/>
+ <pt x="68" y="962" on="1"/>
+ <pt x="68" y="1086" on="1"/>
+ <pt x="389" y="1086" on="1"/>
+ <pt x="389" y="385" on="1"/>
+ <pt x="389" y="130" on="0"/>
+ <pt x="552" y="130" on="1"/>
+ <pt x="701" y="130" on="0"/>
+ <pt x="845" y="382" on="1"/>
+ <pt x="845" y="962" on="1"/>
+ <pt x="734" y="962" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 0 0 19 30 10 48 200 10 2 23 22 21 17 14 13 12 6 3 2 10 0 4 3 5 4
+ 1 0 16 15 1 0 1 3 14 23 0 2 5 16 3 4 3 2 13 1 15 14 12 0 0
+ 22 21 6 5 10 3 1 17 16 10 1 12 2 4 48 200 2 1 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="uacute" xMin="68" yMin="-25" xMax="1166" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="101" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ubreve" xMin="68" yMin="-25" xMax="1166" yMax="1579">
+ <contour>
+ <pt x="734" y="1086" on="1"/>
+ <pt x="1043" y="1086" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1166" y="123" on="1"/>
+ <pt x="1166" y="0" on="1"/>
+ <pt x="845" y="0" on="1"/>
+ <pt x="845" y="209" on="1"/>
+ <pt x="776" y="104" on="0"/>
+ <pt x="708" y="51" on="1"/>
+ <pt x="612" y="-25" on="0"/>
+ <pt x="493" y="-25" on="1"/>
+ <pt x="191" y="-25" on="0"/>
+ <pt x="191" y="363" on="1"/>
+ <pt x="191" y="962" on="1"/>
+ <pt x="68" y="962" on="1"/>
+ <pt x="68" y="1086" on="1"/>
+ <pt x="389" y="1086" on="1"/>
+ <pt x="389" y="385" on="1"/>
+ <pt x="389" y="130" on="0"/>
+ <pt x="552" y="130" on="1"/>
+ <pt x="701" y="130" on="0"/>
+ <pt x="845" y="382" on="1"/>
+ <pt x="845" y="962" on="1"/>
+ <pt x="734" y="962" on="1"/>
+ </contour>
+ <contour>
+ <pt x="265" y="1579" on="1"/>
+ <pt x="388" y="1579" on="1"/>
+ <pt x="436" y="1431" on="0"/>
+ <pt x="610" y="1431" on="1"/>
+ <pt x="785" y="1431" on="0"/>
+ <pt x="833" y="1579" on="1"/>
+ <pt x="956" y="1579" on="1"/>
+ <pt x="933" y="1490" on="0"/>
+ <pt x="907" y="1444" on="1"/>
+ <pt x="816" y="1289" on="0"/>
+ <pt x="615" y="1289" on="1"/>
+ <pt x="462" y="1289" on="0"/>
+ <pt x="373" y="1370" on="1"/>
+ <pt x="318" y="1419" on="0"/>
+ <pt x="290" y="1491" on="1"/>
+ <pt x="279" y="1520" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 96 values pushed */
+ 0 0 27 14 34 19 30 10 48 200 10 2 23 22 21 17 14 13 12 6 3 2 10 0 4
+ 3 30 29 25 24 4 13 34 0 5 4 1 0 16 15 1 0 1 3 14 30 1 5 2 29
+ 23 0 3 5 16 3 25 24 2 16 12 3 4 3 2 13 1 15 14 12 0 0 22 21 6
+ 5 10 3 1 17 16 10 1 12 2 4 48 200 2 1 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ucircumflex" xMin="68" yMin="-25" xMax="1166" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="3" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="udieresis" xMin="68" yMin="-25" xMax="1166" yMax="1480">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="3" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ugrave" xMin="68" yMin="-25" xMax="1166" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="-96" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="uhungarumlaut" xMin="68" yMin="-25" xMax="1166" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="hungarumlaut" x="92" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="umacron" xMin="68" yMin="-25" xMax="1166" yMax="1407">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="-4" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="underscore" xMin="0" yMin="-148" xMax="1229" yMax="0">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="1229" y="0" on="1"/>
+ <pt x="1229" y="-148" on="1"/>
+ <pt x="0" y="-148" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 2 16 1 0 1 4 48 200 1 0 1 0 14 2 1 1 3 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="uogonek" xMin="68" yMin="-370" xMax="1166" yMax="1086">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="331" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="uring" xMin="68" yMin="-25" xMax="1166" yMax="1737">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="ring" x="-4" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="utilde" xMin="68" yMin="-25" xMax="1166" yMax="1518">
+ <contour>
+ <pt x="734" y="1086" on="1"/>
+ <pt x="1043" y="1086" on="1"/>
+ <pt x="1043" y="123" on="1"/>
+ <pt x="1166" y="123" on="1"/>
+ <pt x="1166" y="0" on="1"/>
+ <pt x="845" y="0" on="1"/>
+ <pt x="845" y="209" on="1"/>
+ <pt x="776" y="104" on="0"/>
+ <pt x="708" y="51" on="1"/>
+ <pt x="612" y="-25" on="0"/>
+ <pt x="493" y="-25" on="1"/>
+ <pt x="191" y="-25" on="0"/>
+ <pt x="191" y="363" on="1"/>
+ <pt x="191" y="962" on="1"/>
+ <pt x="68" y="962" on="1"/>
+ <pt x="68" y="1086" on="1"/>
+ <pt x="389" y="1086" on="1"/>
+ <pt x="389" y="385" on="1"/>
+ <pt x="389" y="130" on="0"/>
+ <pt x="552" y="130" on="1"/>
+ <pt x="701" y="130" on="0"/>
+ <pt x="845" y="382" on="1"/>
+ <pt x="845" y="962" on="1"/>
+ <pt x="734" y="962" on="1"/>
+ </contour>
+ <contour>
+ <pt x="278" y="1283" on="1"/>
+ <pt x="284" y="1378" on="0"/>
+ <pt x="309" y="1428" on="1"/>
+ <pt x="354" y="1518" on="0"/>
+ <pt x="463" y="1518" on="1"/>
+ <pt x="535" y="1518" on="0"/>
+ <pt x="598" y="1479" on="1"/>
+ <pt x="658" y="1442" on="1"/>
+ <pt x="720" y="1404" on="0"/>
+ <pt x="754" y="1404" on="1"/>
+ <pt x="822" y="1404" on="0"/>
+ <pt x="833" y="1518" on="1"/>
+ <pt x="944" y="1518" on="1"/>
+ <pt x="937" y="1424" on="0"/>
+ <pt x="912" y="1374" on="1"/>
+ <pt x="866" y="1283" on="0"/>
+ <pt x="759" y="1283" on="1"/>
+ <pt x="686" y="1283" on="0"/>
+ <pt x="623" y="1322" on="1"/>
+ <pt x="563" y="1359" on="1"/>
+ <pt x="503" y="1396" on="0"/>
+ <pt x="467" y="1396" on="1"/>
+ <pt x="399" y="1396" on="0"/>
+ <pt x="388" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 110 values pushed */
+ 0 0 45 5 28 33 5 40 19 30 10 48 200 28 0 10 2 40 1 47 40 24 3 0 0
+ 3 0 23 22 21 17 14 13 12 6 3 2 10 0 4 3 1 36 35 2 13 0 0 5 4
+ 1 0 16 15 1 0 1 3 14 36 1 5 2 35 23 0 3 5 16 3 47 24 2 16 12
+ 3 4 3 2 13 1 15 14 12 0 0 22 21 6 5 10 3 1 17 16 10 1 12 2 4
+ 48 200 2 1 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="v" xMin="55" yMin="0" xMax="1173" yMax="1086">
+ <contour>
+ <pt x="514" y="0" on="1"/>
+ <pt x="129" y="962" on="1"/>
+ <pt x="55" y="962" on="1"/>
+ <pt x="55" y="1086" on="1"/>
+ <pt x="502" y="1086" on="1"/>
+ <pt x="502" y="962" on="1"/>
+ <pt x="342" y="962" on="1"/>
+ <pt x="653" y="184" on="1"/>
+ <pt x="655" y="184" on="1"/>
+ <pt x="966" y="962" on="1"/>
+ <pt x="806" y="962" on="1"/>
+ <pt x="806" y="1086" on="1"/>
+ <pt x="1173" y="1086" on="1"/>
+ <pt x="1173" y="962" on="1"/>
+ <pt x="1099" y="962" on="1"/>
+ <pt x="714" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 8 7 2 1 0 3 0 0 14 13 10 9 6 5 2 1 6 7 3 1 4 48 200 15 0
+ 1 0 12 11 4 3 1 3 14 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="w" xMin="23" yMin="0" xMax="1207" yMax="1086">
+ <contour>
+ <pt x="242" y="0" on="1"/>
+ <pt x="72" y="962" on="1"/>
+ <pt x="23" y="962" on="1"/>
+ <pt x="23" y="1086" on="1"/>
+ <pt x="334" y="1086" on="1"/>
+ <pt x="334" y="962" on="1"/>
+ <pt x="248" y="962" on="1"/>
+ <pt x="377" y="238" on="1"/>
+ <pt x="379" y="238" on="1"/>
+ <pt x="556" y="923" on="1"/>
+ <pt x="723" y="923" on="1"/>
+ <pt x="901" y="235" on="1"/>
+ <pt x="903" y="235" on="1"/>
+ <pt x="1033" y="962" on="1"/>
+ <pt x="935" y="962" on="1"/>
+ <pt x="935" y="1086" on="1"/>
+ <pt x="1207" y="1086" on="1"/>
+ <pt x="1207" y="962" on="1"/>
+ <pt x="1158" y="962" on="1"/>
+ <pt x="988" y="0" on="1"/>
+ <pt x="795" y="0" on="1"/>
+ <pt x="616" y="703" on="1"/>
+ <pt x="614" y="703" on="1"/>
+ <pt x="432" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 18 17 14 13 6 5 2 1 8 3 9 3 22 21 12 11 8 7 6 9 0 3 10 9 1
+ 23 20 19 0 3 2 0 16 15 4 3 1 3 14 23 22 21 20 19 18 17 16 15 14 13
+ 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="wcircumflex" xMin="23" yMin="0" xMax="1207" yMax="1604">
+ <contour>
+ <pt x="242" y="0" on="1"/>
+ <pt x="72" y="962" on="1"/>
+ <pt x="23" y="962" on="1"/>
+ <pt x="23" y="1086" on="1"/>
+ <pt x="334" y="1086" on="1"/>
+ <pt x="334" y="962" on="1"/>
+ <pt x="248" y="962" on="1"/>
+ <pt x="377" y="238" on="1"/>
+ <pt x="379" y="238" on="1"/>
+ <pt x="556" y="923" on="1"/>
+ <pt x="723" y="923" on="1"/>
+ <pt x="901" y="235" on="1"/>
+ <pt x="903" y="235" on="1"/>
+ <pt x="1033" y="962" on="1"/>
+ <pt x="935" y="962" on="1"/>
+ <pt x="935" y="1086" on="1"/>
+ <pt x="1207" y="1086" on="1"/>
+ <pt x="1207" y="962" on="1"/>
+ <pt x="1158" y="962" on="1"/>
+ <pt x="988" y="0" on="1"/>
+ <pt x="795" y="0" on="1"/>
+ <pt x="616" y="703" on="1"/>
+ <pt x="614" y="703" on="1"/>
+ <pt x="432" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="268" y="1283" on="1"/>
+ <pt x="524" y="1604" on="1"/>
+ <pt x="743" y="1604" on="1"/>
+ <pt x="999" y="1283" on="1"/>
+ <pt x="876" y="1283" on="1"/>
+ <pt x="635" y="1485" on="1"/>
+ <pt x="632" y="1485" on="1"/>
+ <pt x="391" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 31 30 29 28 27 24 6 25 3 3 18 17 14 13 6 5 2 1 8 3 9 3 22 21 12
+ 11 8 7 6 9 0 3 26 25 1 10 9 1 23 20 19 0 3 3 0 16 15 4 3 1
+ 3 14 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9
+ 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="x" xMin="59" yMin="0" xMax="1189" yMax="1086">
+ <contour>
+ <pt x="59" y="0" on="1"/>
+ <pt x="59" y="123" on="1"/>
+ <pt x="182" y="123" on="1"/>
+ <pt x="513" y="543" on="1"/>
+ <pt x="182" y="962" on="1"/>
+ <pt x="59" y="962" on="1"/>
+ <pt x="59" y="1086" on="1"/>
+ <pt x="497" y="1086" on="1"/>
+ <pt x="497" y="962" on="1"/>
+ <pt x="410" y="962" on="1"/>
+ <pt x="671" y="631" on="1"/>
+ <pt x="931" y="962" on="1"/>
+ <pt x="828" y="962" on="1"/>
+ <pt x="828" y="1086" on="1"/>
+ <pt x="1189" y="1086" on="1"/>
+ <pt x="1189" y="962" on="1"/>
+ <pt x="1072" y="962" on="1"/>
+ <pt x="741" y="542" on="1"/>
+ <pt x="1071" y="123" on="1"/>
+ <pt x="1189" y="123" on="1"/>
+ <pt x="1189" y="0" on="1"/>
+ <pt x="744" y="0" on="1"/>
+ <pt x="744" y="123" on="1"/>
+ <pt x="843" y="123" on="1"/>
+ <pt x="590" y="444" on="1"/>
+ <pt x="338" y="123" on="1"/>
+ <pt x="438" y="123" on="1"/>
+ <pt x="438" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 26 25 24 23 22 19 18 17 16 15 12 11 10 9 8 5 4 3 2 1 20 6 0 3 27
+ 21 20 0 3 0 14 13 7 6 1 3 14 27 26 25 24 23 22 21 20 19 18 17 16 15
+ 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="y" xMin="55" yMin="-395" xMax="1173" yMax="1086">
+ <contour>
+ <pt x="514" y="0" on="1"/>
+ <pt x="129" y="962" on="1"/>
+ <pt x="55" y="962" on="1"/>
+ <pt x="55" y="1086" on="1"/>
+ <pt x="502" y="1086" on="1"/>
+ <pt x="502" y="962" on="1"/>
+ <pt x="342" y="962" on="1"/>
+ <pt x="653" y="184" on="1"/>
+ <pt x="655" y="184" on="1"/>
+ <pt x="966" y="962" on="1"/>
+ <pt x="806" y="962" on="1"/>
+ <pt x="806" y="1086" on="1"/>
+ <pt x="1173" y="1086" on="1"/>
+ <pt x="1173" y="962" on="1"/>
+ <pt x="1099" y="962" on="1"/>
+ <pt x="714" y="0" on="1"/>
+ <pt x="606" y="-271" on="1"/>
+ <pt x="754" y="-271" on="1"/>
+ <pt x="754" y="-395" on="1"/>
+ <pt x="275" y="-395" on="1"/>
+ <pt x="275" y="-271" on="1"/>
+ <pt x="473" y="-271" on="1"/>
+ <pt x="581" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 1 8 7 2 1 2 3 0 1 22 0 2 2 16 3 0 0 0 14 13 10 9 6 5 2
+ 1 6 7 3 21 20 17 16 6 3 18 2 4 48 200 19 18 1 0 12 11 4 3 1 3
+ 14 22 21 20 19 18 17 16 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="yacute" xMin="55" yMin="-395" xMax="1173" yMax="1604">
+ <component glyphName="y" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="139" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ycircumflex" xMin="55" yMin="-395" xMax="1173" yMax="1604">
+ <contour>
+ <pt x="514" y="0" on="1"/>
+ <pt x="129" y="962" on="1"/>
+ <pt x="55" y="962" on="1"/>
+ <pt x="55" y="1086" on="1"/>
+ <pt x="502" y="1086" on="1"/>
+ <pt x="502" y="962" on="1"/>
+ <pt x="342" y="962" on="1"/>
+ <pt x="653" y="184" on="1"/>
+ <pt x="655" y="184" on="1"/>
+ <pt x="966" y="962" on="1"/>
+ <pt x="806" y="962" on="1"/>
+ <pt x="806" y="1086" on="1"/>
+ <pt x="1173" y="1086" on="1"/>
+ <pt x="1173" y="962" on="1"/>
+ <pt x="1099" y="962" on="1"/>
+ <pt x="714" y="0" on="1"/>
+ <pt x="606" y="-271" on="1"/>
+ <pt x="754" y="-271" on="1"/>
+ <pt x="754" y="-395" on="1"/>
+ <pt x="275" y="-395" on="1"/>
+ <pt x="275" y="-271" on="1"/>
+ <pt x="473" y="-271" on="1"/>
+ <pt x="581" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="288" y="1283" on="1"/>
+ <pt x="544" y="1604" on="1"/>
+ <pt x="763" y="1604" on="1"/>
+ <pt x="1019" y="1283" on="1"/>
+ <pt x="896" y="1283" on="1"/>
+ <pt x="655" y="1485" on="1"/>
+ <pt x="652" y="1485" on="1"/>
+ <pt x="411" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 95 values pushed */
+ 30 29 28 27 26 23 6 24 3 3 1 8 7 2 1 2 3 0 1 22 0 2 2 16 3
+ 0 0 0 14 13 10 9 6 5 2 1 6 7 3 21 20 17 16 6 3 18 2 4 48 200
+ 25 24 1 19 18 1 2 0 12 11 4 3 1 3 14 30 29 28 27 26 25 24 23 22 21
+ 20 19 18 17 16 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ydieresis" xMin="55" yMin="-395" xMax="1173" yMax="1480">
+ <component glyphName="y" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="40" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="yen" xMin="49" yMin="0" xMax="1179" yMax="1480">
+ <contour>
+ <pt x="294" y="0" on="1"/>
+ <pt x="294" y="123" on="1"/>
+ <pt x="516" y="123" on="1"/>
+ <pt x="516" y="407" on="1"/>
+ <pt x="171" y="407" on="1"/>
+ <pt x="171" y="531" on="1"/>
+ <pt x="516" y="531" on="1"/>
+ <pt x="516" y="660" on="1"/>
+ <pt x="470" y="740" on="1"/>
+ <pt x="171" y="740" on="1"/>
+ <pt x="171" y="864" on="1"/>
+ <pt x="400" y="864" on="1"/>
+ <pt x="115" y="1357" on="1"/>
+ <pt x="49" y="1357" on="1"/>
+ <pt x="49" y="1480" on="1"/>
+ <pt x="490" y="1480" on="1"/>
+ <pt x="490" y="1357" on="1"/>
+ <pt x="341" y="1357" on="1"/>
+ <pt x="656" y="813" on="1"/>
+ <pt x="658" y="813" on="1"/>
+ <pt x="973" y="1357" on="1"/>
+ <pt x="825" y="1357" on="1"/>
+ <pt x="825" y="1480" on="1"/>
+ <pt x="1179" y="1480" on="1"/>
+ <pt x="1179" y="1357" on="1"/>
+ <pt x="1115" y="1357" on="1"/>
+ <pt x="830" y="864" on="1"/>
+ <pt x="1059" y="864" on="1"/>
+ <pt x="1059" y="740" on="1"/>
+ <pt x="759" y="740" on="1"/>
+ <pt x="713" y="661" on="1"/>
+ <pt x="713" y="531" on="1"/>
+ <pt x="1059" y="531" on="1"/>
+ <pt x="1059" y="407" on="1"/>
+ <pt x="713" y="407" on="1"/>
+ <pt x="713" y="123" on="1"/>
+ <pt x="935" y="123" on="1"/>
+ <pt x="935" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 131 values pushed */
+ 19 18 2 10 8 3 30 7 2 8 5 3 0 0 25 24 21 20 17 16 13 12 6 7 14
+ 29 28 9 8 6 3 10 32 31 6 5 6 3 3 36 35 2 1 6 3 0 4 4 48 200
+ 27 26 11 10 3 34 33 4 3 3 37 0 1 3 0 23 22 15 14 0 3 14 19 18 2
+ 30 2 3 37 36 33 32 29 28 27 26 25 24 23 22 21 20 14 13 30 17 16 15 14 13
+ 12 11 10 9 8 5 4 1 0 14 13 2 0 0 35 34 31 30 10 3 2 1 4 48 200
+ 7 6 3 2 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="z" xMin="123" yMin="0" xMax="1093" yMax="1086">
+ <contour>
+ <pt x="123" y="0" on="1"/>
+ <pt x="123" y="142" on="1"/>
+ <pt x="818" y="962" on="1"/>
+ <pt x="283" y="962" on="1"/>
+ <pt x="283" y="765" on="1"/>
+ <pt x="160" y="765" on="1"/>
+ <pt x="160" y="1086" on="1"/>
+ <pt x="1056" y="1086" on="1"/>
+ <pt x="1056" y="962" on="1"/>
+ <pt x="361" y="142" on="1"/>
+ <pt x="969" y="142" on="1"/>
+ <pt x="969" y="345" on="1"/>
+ <pt x="1093" y="345" on="1"/>
+ <pt x="1093" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 12 11 5 4 4 2 1 3 0 0 8 3 2 6 2 6 10 9 1 7 2 0 2 4 48
+ 200 13 0 1 0 7 6 1 14 8 7 2 12 10 3 9 2 2 10 3 3 0 0 11 10
+ 6 1 12 4 3 6 1 5 2 4 48 200 13 12 1 6 5 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="zacute" xMin="123" yMin="0" xMax="1093" yMax="1604">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="93" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zcaron" xMin="123" yMin="0" xMax="1093" yMax="1604">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="-6" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zdotaccent" xMin="123" yMin="0" xMax="1093" yMax="1480">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="dotaccent" x="-7" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="96" yMin="-37" xMax="1132" yMax="1517">
+ <contour>
+ <pt x="614" y="1517" on="1"/>
+ <pt x="854" y="1517" on="0"/>
+ <pt x="993" y="1309" on="1"/>
+ <pt x="1132" y="1102" on="0"/>
+ <pt x="1132" y="742" on="1"/>
+ <pt x="1132" y="376" on="0"/>
+ <pt x="993" y="170" on="1"/>
+ <pt x="854" y="-37" on="0"/>
+ <pt x="606" y="-37" on="1"/>
+ <pt x="395" y="-37" on="0"/>
+ <pt x="263" y="132" on="1"/>
+ <pt x="96" y="346" on="0"/>
+ <pt x="96" y="741" on="1"/>
+ <pt x="96" y="1102" on="0"/>
+ <pt x="235" y="1309" on="1"/>
+ <pt x="374" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="614" y="1394" on="1"/>
+ <pt x="467" y="1394" on="0"/>
+ <pt x="388" y="1224" on="1"/>
+ <pt x="309" y="1053" on="0"/>
+ <pt x="309" y="742" on="1"/>
+ <pt x="309" y="431" on="0"/>
+ <pt x="388" y="258" on="1"/>
+ <pt x="466" y="86" on="0"/>
+ <pt x="613" y="86" on="1"/>
+ <pt x="920" y="86" on="0"/>
+ <pt x="920" y="740" on="1"/>
+ <pt x="920" y="1057" on="0"/>
+ <pt x="841" y="1225" on="1"/>
+ <pt x="761" y="1394" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 24 5 8 16 5 0 48 200 8 2 0 0 14 0 0 26 39 4 20 39 12 48 200
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="0" platformID="1" platEncID="0" langID="0x0">
+ Copyright (c) 2001 by Bigelow &amp; Holmes Inc. Instructions copyright (c) 2001 by URW++.
+ </namerecord>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0">
+ Luxi Mono
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0">
+ Regular
+ </namerecord>
+ <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0">
+ Luxi Mono Regular: B&amp;H
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0">
+ Luxi Mono Regular
+ </namerecord>
+ <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0">
+ 1.2 : October 12, 2001
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0">
+ LuxiMono
+ </namerecord>
+ <namerecord nameID="7" platformID="1" platEncID="0" langID="0x0">
+ Luxi is a registered trademark of Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="8" platformID="1" platEncID="0" langID="0x0">
+ Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="9" platformID="1" platEncID="0" langID="0x0">
+ Kris Holmes and Charles Bigelow
+ </namerecord>
+ <namerecord nameID="11" platformID="1" platEncID="0" langID="0x0">
+ http://www.urwpp.de
+ </namerecord>
+ <namerecord nameID="12" platformID="1" platEncID="0" langID="0x0">
+ design@bigelowandholmes.com
+ </namerecord>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (c) 2001 by Bigelow &amp; Holmes Inc. Instructions copyright (c) 2001 by URW++.
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Luxi Mono
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
+ Luxi Mono Regular: B&amp;H
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Luxi Mono Regular
+ </namerecord>
+ <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
+ 1.2 : October 12, 2001
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ LuxiMono
+ </namerecord>
+ <namerecord nameID="7" platformID="3" platEncID="1" langID="0x409">
+ Luxi is a registered trademark of Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="8" platformID="3" platEncID="1" langID="0x409">
+ Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="9" platformID="3" platEncID="1" langID="0x409">
+ Kris Holmes and Charles Bigelow
+ </namerecord>
+ <namerecord nameID="11" platformID="3" platEncID="1" langID="0x409">
+ http://www.urwpp.de
+ </namerecord>
+ <namerecord nameID="12" platformID="3" platEncID="1" langID="0x409">
+ design@bigelowandholmes.com
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="2.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="1"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ <psNames>
+ <!-- This file uses unique glyph names based on the information
+ found in the 'post' table. Since these names might not be unique,
+ we have to invent artificial names in case of clashes. In order to
+ be able to retain the original information, we need a name to
+ ps name mapping for those cases where they differ. That's what
+ you see below.
+ -->
+ <psName name=".notdef#1" psName=".notdef"/>
+ <psName name=".notdef#10" psName=".notdef"/>
+ <psName name=".notdef#11" psName=".notdef"/>
+ <psName name=".notdef#12" psName=".notdef"/>
+ <psName name=".notdef#13" psName=".notdef"/>
+ <psName name=".notdef#14" psName=".notdef"/>
+ <psName name=".notdef#15" psName=".notdef"/>
+ <psName name=".notdef#16" psName=".notdef"/>
+ <psName name=".notdef#17" psName=".notdef"/>
+ <psName name=".notdef#18" psName=".notdef"/>
+ <psName name=".notdef#2" psName=".notdef"/>
+ <psName name=".notdef#3" psName=".notdef"/>
+ <psName name=".notdef#4" psName=".notdef"/>
+ <psName name=".notdef#5" psName=".notdef"/>
+ <psName name=".notdef#6" psName=".notdef"/>
+ <psName name=".notdef#7" psName=".notdef"/>
+ <psName name=".notdef#8" psName=".notdef"/>
+ <psName name=".notdef#9" psName=".notdef"/>
+ <psName name="Euro#1" psName="Euro"/>
+ <psName name="fi#1" psName="fi"/>
+ <psName name="fl#1" psName="fl"/>
+ <psName name="foursuperiour#1" psName="foursuperiour"/>
+ <psName name="fraction#1" psName="fraction"/>
+ <psName name="hyphen#1" psName="hyphen"/>
+ <psName name="macron#1" psName="macron"/>
+ <psName name="periodcentered#1" psName="periodcentered"/>
+ <psName name="semicolon#1" psName="semicolon"/>
+ </psNames>
+ <extraNames>
+ <!-- following are the name that are not taken from the standard Mac glyph order -->
+ <psName name="fraction"/>
+ <psName name="fl"/>
+ <psName name="Euro"/>
+ <psName name="tilde"/>
+ <psName name="macron"/>
+ <psName name="Euro"/>
+ <psName name="sfthyphen"/>
+ <psName name="periodcentered"/>
+ <psName name="Amacron"/>
+ <psName name="amacron"/>
+ <psName name="Abreve"/>
+ <psName name="abreve"/>
+ <psName name="Aogonek"/>
+ <psName name="aogonek"/>
+ <psName name="Ccircumflex"/>
+ <psName name="ccircumflex"/>
+ <psName name="Cdotaccent"/>
+ <psName name="cdotaccent"/>
+ <psName name="Dcaron"/>
+ <psName name="dcaron"/>
+ <psName name="Dcroat"/>
+ <psName name="dcroat"/>
+ <psName name="Emacron"/>
+ <psName name="emacron"/>
+ <psName name="Ebreve"/>
+ <psName name="ebreve"/>
+ <psName name="Edotaccent"/>
+ <psName name="edotaccent"/>
+ <psName name="Eogonek"/>
+ <psName name="eogonek"/>
+ <psName name="Ecaron"/>
+ <psName name="ecaron"/>
+ <psName name="Gcircumflex"/>
+ <psName name="gcircumflex"/>
+ <psName name="Gdotaccent"/>
+ <psName name="gdotaccent"/>
+ <psName name="Gcommaaccent"/>
+ <psName name="gcommaaccent"/>
+ <psName name="Hcircumflex"/>
+ <psName name="hcircumflex"/>
+ <psName name="Hbar"/>
+ <psName name="hbar"/>
+ <psName name="Itilde"/>
+ <psName name="itilde"/>
+ <psName name="Imacron"/>
+ <psName name="imacron"/>
+ <psName name="Ibreve"/>
+ <psName name="ibreve"/>
+ <psName name="Iogonek"/>
+ <psName name="iogonek"/>
+ <psName name="IJ"/>
+ <psName name="ij"/>
+ <psName name="Jcircumflex"/>
+ <psName name="jcircumflex"/>
+ <psName name="Kcommaaccent"/>
+ <psName name="kcommaaccent"/>
+ <psName name="kgreenlandic"/>
+ <psName name="Lacute"/>
+ <psName name="lacute"/>
+ <psName name="Lcommaaccent"/>
+ <psName name="lcommaaccent"/>
+ <psName name="Lcaron"/>
+ <psName name="lcaron"/>
+ <psName name="Ldot"/>
+ <psName name="ldot"/>
+ <psName name="Nacute"/>
+ <psName name="nacute"/>
+ <psName name="Ncommaaccent"/>
+ <psName name="ncommaaccent"/>
+ <psName name="Ncaron"/>
+ <psName name="ncaron"/>
+ <psName name="napostrophe"/>
+ <psName name="Eng"/>
+ <psName name="eng"/>
+ <psName name="Omacron"/>
+ <psName name="omacron"/>
+ <psName name="Obreve"/>
+ <psName name="obreve"/>
+ <psName name="Ohungarumlaut"/>
+ <psName name="ohungarumlaut"/>
+ <psName name="Racute"/>
+ <psName name="racute"/>
+ <psName name="Rcommaaccent"/>
+ <psName name="rcommaaccent"/>
+ <psName name="Rcaron"/>
+ <psName name="rcaron"/>
+ <psName name="Sacute"/>
+ <psName name="sacute"/>
+ <psName name="Scircumflex"/>
+ <psName name="scircumflex"/>
+ <psName name="Tcommaaccent"/>
+ <psName name="tcommaaccent"/>
+ <psName name="Tcaron"/>
+ <psName name="tcaron"/>
+ <psName name="Tbar"/>
+ <psName name="tbar"/>
+ <psName name="Utilde"/>
+ <psName name="utilde"/>
+ <psName name="Umacron"/>
+ <psName name="umacron"/>
+ <psName name="Ubreve"/>
+ <psName name="ubreve"/>
+ <psName name="Uring"/>
+ <psName name="uring"/>
+ <psName name="Uhungarumlaut"/>
+ <psName name="uhungarumlaut"/>
+ <psName name="Uogonek"/>
+ <psName name="uogonek"/>
+ <psName name="Wcircumflex"/>
+ <psName name="wcircumflex"/>
+ <psName name="Ycircumflex"/>
+ <psName name="ycircumflex"/>
+ <psName name="Zacute"/>
+ <psName name="zacute"/>
+ <psName name="Zdotaccent"/>
+ <psName name="zdotaccent"/>
+ <psName name="longs"/>
+ <psName name="Scommaaccent"/>
+ <psName name="scommaaccent"/>
+ <psName name="Tcommabelow"/>
+ <psName name="tcommabelow"/>
+ <psName name="Unterkomma"/>
+ <psName name="semicolon"/>
+ <psName name="anoteleia"/>
+ <psName name="hyphen"/>
+ <psName name="nbhyphen"/>
+ <psName name="figuredash"/>
+ <psName name="afii00208"/>
+ <psName name="quotereversed"/>
+ <psName name="radicalex"/>
+ <psName name="estimated"/>
+ <psName name="dotmath"/>
+ <psName name="fi"/>
+ <psName name="fl"/>
+ <psName name="foursuperiour"/>
+ <psName name="onesuperiour"/>
+ <psName name="twosuperiour"/>
+ <psName name="threesuperiour"/>
+ <psName name="foursuperiour"/>
+ <psName name="dotlessj"/>
+ </extraNames>
+ </post>
+
+ <gasp>
+ <gaspRange rangeMaxPPEM="8" rangeGaspBehavior="2"/>
+ <gaspRange rangeMaxPPEM="16" rangeGaspBehavior="1"/>
+ <gaspRange rangeMaxPPEM="65535" rangeGaspBehavior="3"/>
+ </gasp>
+
+ <vhea>
+ <tableVersion value="1.0"/>
+ <ascent value="2033"/>
+ <descent value="432"/>
+ <lineGap value="0"/>
+ <advanceHeightMax value="2465"/>
+ <minTopSideBearing value="0"/>
+ <minBottomSideBearing value="0"/>
+ <yMaxExtent value="2465"/>
+ <caretSlopeRise value="0"/>
+ <caretSlopeRun value="1"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <reserved4 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfVMetrics value="395"/>
+ </vhea>
+
+ <vmtx>
+ <mtx name=".notdef" height="2465" tsb="553"/>
+ <mtx name=".notdef#1" height="0" tsb="0"/>
+ <mtx name=".notdef#10" height="2465" tsb="0"/>
+ <mtx name=".notdef#11" height="2465" tsb="0"/>
+ <mtx name=".notdef#12" height="2465" tsb="0"/>
+ <mtx name=".notdef#13" height="2465" tsb="0"/>
+ <mtx name=".notdef#14" height="2465" tsb="0"/>
+ <mtx name=".notdef#15" height="2465" tsb="0"/>
+ <mtx name=".notdef#16" height="1229" tsb="0"/>
+ <mtx name=".notdef#17" height="2465" tsb="0"/>
+ <mtx name=".notdef#18" height="2465" tsb="0"/>
+ <mtx name=".notdef#2" height="2465" tsb="0"/>
+ <mtx name=".notdef#3" height="2465" tsb="0"/>
+ <mtx name=".notdef#4" height="2465" tsb="0"/>
+ <mtx name=".notdef#5" height="2465" tsb="0"/>
+ <mtx name=".notdef#6" height="2465" tsb="0"/>
+ <mtx name=".notdef#7" height="2465" tsb="0"/>
+ <mtx name=".notdef#8" height="2465" tsb="0"/>
+ <mtx name=".notdef#9" height="2465" tsb="0"/>
+ <mtx name="A" height="2465" tsb="553"/>
+ <mtx name="AE" height="2465" tsb="553"/>
+ <mtx name="Aacute" height="2465" tsb="108"/>
+ <mtx name="Abreve" height="2465" tsb="108"/>
+ <mtx name="Acircumflex" height="2465" tsb="108"/>
+ <mtx name="Adieresis" height="2465" tsb="232"/>
+ <mtx name="Agrave" height="2465" tsb="108"/>
+ <mtx name="Amacron" height="2465" tsb="305"/>
+ <mtx name="Aogonek" height="2465" tsb="553"/>
+ <mtx name="Aring" height="2465" tsb="98"/>
+ <mtx name="Atilde" height="2465" tsb="194"/>
+ <mtx name="B" height="2465" tsb="553"/>
+ <mtx name="C" height="2465" tsb="516"/>
+ <mtx name="Cacute" height="2465" tsb="108"/>
+ <mtx name="Ccaron" height="2465" tsb="108"/>
+ <mtx name="Ccedilla" height="2465" tsb="516"/>
+ <mtx name="Ccircumflex" height="2465" tsb="108"/>
+ <mtx name="Cdotaccent" height="2465" tsb="232"/>
+ <mtx name="D" height="2465" tsb="553"/>
+ <mtx name="Dcaron" height="2465" tsb="108"/>
+ <mtx name="Dcroat" height="2465" tsb="553"/>
+ <mtx name="E" height="2465" tsb="553"/>
+ <mtx name="Eacute" height="2465" tsb="108"/>
+ <mtx name="Ebreve" height="2465" tsb="108"/>
+ <mtx name="Ecaron" height="2465" tsb="108"/>
+ <mtx name="Ecircumflex" height="2465" tsb="108"/>
+ <mtx name="Edieresis" height="2465" tsb="232"/>
+ <mtx name="Edotaccent" height="2465" tsb="232"/>
+ <mtx name="Egrave" height="2465" tsb="108"/>
+ <mtx name="Emacron" height="2465" tsb="305"/>
+ <mtx name="Eng" height="2465" tsb="553"/>
+ <mtx name="Eogonek" height="2465" tsb="553"/>
+ <mtx name="Eth" height="2465" tsb="553"/>
+ <mtx name="Euro" height="2465" tsb="516"/>
+ <mtx name="Euro#1" height="2465" tsb="516"/>
+ <mtx name="F" height="2465" tsb="553"/>
+ <mtx name="G" height="2465" tsb="515"/>
+ <mtx name="Gbreve" height="2465" tsb="108"/>
+ <mtx name="Gcircumflex" height="2465" tsb="108"/>
+ <mtx name="Gcommaaccent" height="2465" tsb="515"/>
+ <mtx name="Gdotaccent" height="2465" tsb="232"/>
+ <mtx name="H" height="2465" tsb="553"/>
+ <mtx name="Hbar" height="2465" tsb="553"/>
+ <mtx name="Hcircumflex" height="2465" tsb="108"/>
+ <mtx name="I" height="2465" tsb="553"/>
+ <mtx name="IJ" height="2465" tsb="553"/>
+ <mtx name="Iacute" height="2465" tsb="108"/>
+ <mtx name="Ibreve" height="2465" tsb="108"/>
+ <mtx name="Icircumflex" height="2465" tsb="108"/>
+ <mtx name="Idieresis" height="2465" tsb="232"/>
+ <mtx name="Idotaccent" height="2465" tsb="232"/>
+ <mtx name="Igrave" height="2465" tsb="108"/>
+ <mtx name="Imacron" height="2465" tsb="305"/>
+ <mtx name="Iogonek" height="2465" tsb="553"/>
+ <mtx name="Itilde" height="2465" tsb="194"/>
+ <mtx name="J" height="2465" tsb="553"/>
+ <mtx name="Jcircumflex" height="2465" tsb="108"/>
+ <mtx name="K" height="2465" tsb="553"/>
+ <mtx name="Kcommaaccent" height="2465" tsb="553"/>
+ <mtx name="L" height="2465" tsb="553"/>
+ <mtx name="Lacute" height="2465" tsb="108"/>
+ <mtx name="Lcaron" height="2465" tsb="553"/>
+ <mtx name="Lcommaaccent" height="2465" tsb="553"/>
+ <mtx name="Ldot" height="2465" tsb="553"/>
+ <mtx name="Lslash" height="2465" tsb="553"/>
+ <mtx name="M" height="2465" tsb="553"/>
+ <mtx name="N" height="2465" tsb="553"/>
+ <mtx name="Nacute" height="2465" tsb="108"/>
+ <mtx name="Ncaron" height="2465" tsb="108"/>
+ <mtx name="Ncommaaccent" height="2465" tsb="553"/>
+ <mtx name="Ntilde" height="2465" tsb="194"/>
+ <mtx name="O" height="2465" tsb="516"/>
+ <mtx name="OE" height="2465" tsb="515"/>
+ <mtx name="Oacute" height="2465" tsb="108"/>
+ <mtx name="Obreve" height="2465" tsb="108"/>
+ <mtx name="Ocircumflex" height="2465" tsb="108"/>
+ <mtx name="Odieresis" height="2465" tsb="232"/>
+ <mtx name="Ograve" height="2465" tsb="108"/>
+ <mtx name="Ohungarumlaut" height="2465" tsb="108"/>
+ <mtx name="Omacron" height="2465" tsb="305"/>
+ <mtx name="Oslash" height="2465" tsb="516"/>
+ <mtx name="Otilde" height="2465" tsb="194"/>
+ <mtx name="P" height="2465" tsb="553"/>
+ <mtx name="Q" height="2465" tsb="516"/>
+ <mtx name="R" height="2465" tsb="553"/>
+ <mtx name="Racute" height="2465" tsb="108"/>
+ <mtx name="Rcaron" height="2465" tsb="108"/>
+ <mtx name="Rcommaaccent" height="2465" tsb="553"/>
+ <mtx name="S" height="2465" tsb="516"/>
+ <mtx name="Sacute" height="2465" tsb="108"/>
+ <mtx name="Scaron" height="2465" tsb="108"/>
+ <mtx name="Scedilla" height="2465" tsb="516"/>
+ <mtx name="Scircumflex" height="2465" tsb="108"/>
+ <mtx name="Scommaaccent" height="2465" tsb="516"/>
+ <mtx name="T" height="2465" tsb="553"/>
+ <mtx name="Tbar" height="2465" tsb="553"/>
+ <mtx name="Tcaron" height="2465" tsb="108"/>
+ <mtx name="Tcommaaccent" height="2465" tsb="553"/>
+ <mtx name="Tcommabelow" height="2465" tsb="553"/>
+ <mtx name="Thorn" height="2465" tsb="553"/>
+ <mtx name="U" height="2465" tsb="553"/>
+ <mtx name="Uacute" height="2465" tsb="108"/>
+ <mtx name="Ubreve" height="2465" tsb="108"/>
+ <mtx name="Ucircumflex" height="2465" tsb="108"/>
+ <mtx name="Udieresis" height="2465" tsb="232"/>
+ <mtx name="Ugrave" height="2465" tsb="108"/>
+ <mtx name="Uhungarumlaut" height="2465" tsb="108"/>
+ <mtx name="Umacron" height="2465" tsb="305"/>
+ <mtx name="Unterkomma" height="2465" tsb="2144"/>
+ <mtx name="Uogonek" height="2465" tsb="553"/>
+ <mtx name="Uring" height="2465" tsb="0"/>
+ <mtx name="Utilde" height="2465" tsb="194"/>
+ <mtx name="V" height="2465" tsb="553"/>
+ <mtx name="W" height="2465" tsb="553"/>
+ <mtx name="Wcircumflex" height="2465" tsb="108"/>
+ <mtx name="X" height="2465" tsb="553"/>
+ <mtx name="Y" height="2465" tsb="553"/>
+ <mtx name="Yacute" height="2465" tsb="108"/>
+ <mtx name="Ycircumflex" height="2465" tsb="108"/>
+ <mtx name="Ydieresis" height="2465" tsb="232"/>
+ <mtx name="Z" height="2465" tsb="553"/>
+ <mtx name="Zacute" height="2465" tsb="108"/>
+ <mtx name="Zcaron" height="2465" tsb="108"/>
+ <mtx name="Zdotaccent" height="2465" tsb="232"/>
+ <mtx name="a" height="2465" tsb="922"/>
+ <mtx name="aacute" height="2465" tsb="429"/>
+ <mtx name="abreve" height="2465" tsb="454"/>
+ <mtx name="acircumflex" height="2465" tsb="429"/>
+ <mtx name="acute" height="2465" tsb="429"/>
+ <mtx name="adieresis" height="2465" tsb="553"/>
+ <mtx name="ae" height="2465" tsb="923"/>
+ <mtx name="afii00208" height="2465" tsb="1367"/>
+ <mtx name="agrave" height="2465" tsb="429"/>
+ <mtx name="amacron" height="2465" tsb="626"/>
+ <mtx name="ampersand" height="2465" tsb="515"/>
+ <mtx name="anoteleia" height="2465" tsb="1367"/>
+ <mtx name="aogonek" height="2465" tsb="922"/>
+ <mtx name="aring" height="2465" tsb="296"/>
+ <mtx name="asciicircum" height="2465" tsb="553"/>
+ <mtx name="asciitilde" height="2465" tsb="1261"/>
+ <mtx name="asterisk" height="2465" tsb="553"/>
+ <mtx name="at" height="2465" tsb="516"/>
+ <mtx name="atilde" height="2465" tsb="515"/>
+ <mtx name="b" height="2465" tsb="454"/>
+ <mtx name="backslash" height="2465" tsb="454"/>
+ <mtx name="bar" height="2465" tsb="454"/>
+ <mtx name="braceleft" height="2465" tsb="454"/>
+ <mtx name="braceright" height="2465" tsb="454"/>
+ <mtx name="bracketleft" height="2465" tsb="454"/>
+ <mtx name="bracketright" height="2465" tsb="454"/>
+ <mtx name="breve" height="2465" tsb="454"/>
+ <mtx name="brokenbar" height="2465" tsb="454"/>
+ <mtx name="bullet" height="2465" tsb="923"/>
+ <mtx name="c" height="2465" tsb="923"/>
+ <mtx name="cacute" height="2465" tsb="429"/>
+ <mtx name="caron" height="2465" tsb="429"/>
+ <mtx name="ccaron" height="2465" tsb="429"/>
+ <mtx name="ccedilla" height="2465" tsb="923"/>
+ <mtx name="ccircumflex" height="2465" tsb="429"/>
+ <mtx name="cdotaccent" height="2465" tsb="553"/>
+ <mtx name="cedilla" height="2465" tsb="2033"/>
+ <mtx name="cent" height="2465" tsb="553"/>
+ <mtx name="circumflex" height="2465" tsb="429"/>
+ <mtx name="colon" height="2465" tsb="947"/>
+ <mtx name="comma" height="2465" tsb="1737"/>
+ <mtx name="copyright" height="2465" tsb="516"/>
+ <mtx name="currency" height="2465" tsb="833"/>
+ <mtx name="d" height="2465" tsb="454"/>
+ <mtx name="dagger" height="2465" tsb="553"/>
+ <mtx name="daggerdbl" height="2465" tsb="553"/>
+ <mtx name="dcaron" height="2465" tsb="454"/>
+ <mtx name="dcroat" height="2465" tsb="454"/>
+ <mtx name="degree" height="2465" tsb="516"/>
+ <mtx name="dieresis" height="2465" tsb="553"/>
+ <mtx name="divide" height="2465" tsb="799"/>
+ <mtx name="dollar" height="2465" tsb="429"/>
+ <mtx name="dotaccent" height="2465" tsb="553"/>
+ <mtx name="dotlessi" height="2465" tsb="947"/>
+ <mtx name="dotlessj" height="2465" tsb="947"/>
+ <mtx name="dotmath" height="2465" tsb="1367"/>
+ <mtx name="e" height="2465" tsb="923"/>
+ <mtx name="eacute" height="2465" tsb="429"/>
+ <mtx name="ebreve" height="2465" tsb="454"/>
+ <mtx name="ecaron" height="2465" tsb="429"/>
+ <mtx name="ecircumflex" height="2465" tsb="429"/>
+ <mtx name="edieresis" height="2465" tsb="553"/>
+ <mtx name="edotaccent" height="2465" tsb="553"/>
+ <mtx name="egrave" height="2465" tsb="429"/>
+ <mtx name="eight" height="2465" tsb="516"/>
+ <mtx name="ellipsis" height="2465" tsb="1786"/>
+ <mtx name="emacron" height="2465" tsb="626"/>
+ <mtx name="emdash" height="2465" tsb="1367"/>
+ <mtx name="endash" height="2465" tsb="1342"/>
+ <mtx name="eng" height="2465" tsb="923"/>
+ <mtx name="eogonek" height="2465" tsb="923"/>
+ <mtx name="equal" height="2465" tsb="1145"/>
+ <mtx name="estimated" height="2465" tsb="923"/>
+ <mtx name="eth" height="2465" tsb="419"/>
+ <mtx name="exclam" height="2465" tsb="553"/>
+ <mtx name="exclamdown" height="2465" tsb="947"/>
+ <mtx name="f" height="2465" tsb="429"/>
+ <mtx name="fi" height="2465" tsb="429"/>
+ <mtx name="fi#1" height="2465" tsb="429"/>
+ <mtx name="figuredash" height="2465" tsb="1342"/>
+ <mtx name="five" height="2465" tsb="553"/>
+ <mtx name="fl" height="2465" tsb="429"/>
+ <mtx name="fl#1" height="2465" tsb="429"/>
+ <mtx name="florin" height="2465" tsb="516"/>
+ <mtx name="four" height="2465" tsb="553"/>
+ <mtx name="foursuperiour" height="2465" tsb="516"/>
+ <mtx name="foursuperiour#1" height="2465" tsb="516"/>
+ <mtx name="fraction" height="2465" tsb="516"/>
+ <mtx name="fraction#1" height="2465" tsb="516"/>
+ <mtx name="g" height="2465" tsb="922"/>
+ <mtx name="gbreve" height="2465" tsb="454"/>
+ <mtx name="gcircumflex" height="2465" tsb="429"/>
+ <mtx name="gcommaaccent" height="2465" tsb="296"/>
+ <mtx name="gdotaccent" height="2465" tsb="553"/>
+ <mtx name="germandbls" height="2465" tsb="429"/>
+ <mtx name="grave" height="2465" tsb="429"/>
+ <mtx name="greater" height="2465" tsb="799"/>
+ <mtx name="guillemotleft" height="2465" tsb="1046"/>
+ <mtx name="guillemotright" height="2465" tsb="1046"/>
+ <mtx name="guilsinglleft" height="2465" tsb="1046"/>
+ <mtx name="guilsinglright" height="2465" tsb="1046"/>
+ <mtx name="h" height="2465" tsb="454"/>
+ <mtx name="hbar" height="2465" tsb="454"/>
+ <mtx name="hcircumflex" height="2465" tsb="34"/>
+ <mtx name="hungarumlaut" height="2465" tsb="429"/>
+ <mtx name="hyphen" height="2465" tsb="1342"/>
+ <mtx name="hyphen#1" height="2465" tsb="1342"/>
+ <mtx name="i" height="2465" tsb="454"/>
+ <mtx name="iacute" height="2465" tsb="429"/>
+ <mtx name="ibreve" height="2465" tsb="454"/>
+ <mtx name="icircumflex" height="2465" tsb="429"/>
+ <mtx name="idieresis" height="2465" tsb="553"/>
+ <mtx name="igrave" height="2465" tsb="429"/>
+ <mtx name="ij" height="2465" tsb="454"/>
+ <mtx name="imacron" height="2465" tsb="626"/>
+ <mtx name="iogonek" height="2465" tsb="454"/>
+ <mtx name="itilde" height="2465" tsb="515"/>
+ <mtx name="j" height="2465" tsb="454"/>
+ <mtx name="jcircumflex" height="2465" tsb="429"/>
+ <mtx name="k" height="2465" tsb="454"/>
+ <mtx name="kcommaaccent" height="2465" tsb="454"/>
+ <mtx name="kgreenlandic" height="2465" tsb="947"/>
+ <mtx name="l" height="2465" tsb="454"/>
+ <mtx name="lacute" height="2465" tsb="34"/>
+ <mtx name="lcaron" height="2465" tsb="454"/>
+ <mtx name="lcommaaccent" height="2465" tsb="454"/>
+ <mtx name="ldot" height="2465" tsb="454"/>
+ <mtx name="less" height="2465" tsb="799"/>
+ <mtx name="logicalnot" height="2465" tsb="1342"/>
+ <mtx name="longs" height="2465" tsb="429"/>
+ <mtx name="lslash" height="2465" tsb="454"/>
+ <mtx name="m" height="2465" tsb="923"/>
+ <mtx name="macron" height="2465" tsb="626"/>
+ <mtx name="macron#1" height="2465" tsb="429"/>
+ <mtx name="minus" height="2465" tsb="1342"/>
+ <mtx name="mu" height="2465" tsb="947"/>
+ <mtx name="multiply" height="2465" tsb="1001"/>
+ <mtx name="n" height="2465" tsb="923"/>
+ <mtx name="nacute" height="2465" tsb="429"/>
+ <mtx name="napostrophe" height="2465" tsb="454"/>
+ <mtx name="nbhyphen" height="2465" tsb="1342"/>
+ <mtx name="ncaron" height="2465" tsb="429"/>
+ <mtx name="ncommaaccent" height="2465" tsb="923"/>
+ <mtx name="nine" height="2465" tsb="516"/>
+ <mtx name="nonbreakingspace" height="2465" tsb="2033"/>
+ <mtx name="ntilde" height="2465" tsb="515"/>
+ <mtx name="numbersign" height="2465" tsb="553"/>
+ <mtx name="o" height="2465" tsb="923"/>
+ <mtx name="oacute" height="2465" tsb="429"/>
+ <mtx name="obreve" height="2465" tsb="454"/>
+ <mtx name="ocircumflex" height="2465" tsb="429"/>
+ <mtx name="odieresis" height="2465" tsb="553"/>
+ <mtx name="oe" height="2465" tsb="922"/>
+ <mtx name="ogonek" height="2465" tsb="2033"/>
+ <mtx name="ograve" height="2465" tsb="429"/>
+ <mtx name="ohungarumlaut" height="2465" tsb="429"/>
+ <mtx name="omacron" height="2465" tsb="626"/>
+ <mtx name="one" height="2465" tsb="516"/>
+ <mtx name="onehalf" height="2465" tsb="516"/>
+ <mtx name="onequarter" height="2465" tsb="516"/>
+ <mtx name="onesuperior" height="2465" tsb="516"/>
+ <mtx name="onesuperiour" height="2465" tsb="516"/>
+ <mtx name="ordfeminine" height="2465" tsb="516"/>
+ <mtx name="ordmasculine" height="2465" tsb="516"/>
+ <mtx name="oslash" height="2465" tsb="923"/>
+ <mtx name="otilde" height="2465" tsb="515"/>
+ <mtx name="p" height="2465" tsb="923"/>
+ <mtx name="paragraph" height="2465" tsb="540"/>
+ <mtx name="parenleft" height="2465" tsb="454"/>
+ <mtx name="parenright" height="2465" tsb="454"/>
+ <mtx name="percent" height="2465" tsb="516"/>
+ <mtx name="period" height="2465" tsb="1737"/>
+ <mtx name="periodcentered" height="2465" tsb="1367"/>
+ <mtx name="periodcentered#1" height="2465" tsb="1367"/>
+ <mtx name="perthousand" height="2465" tsb="553"/>
+ <mtx name="plus" height="2465" tsb="900"/>
+ <mtx name="plusminus" height="2465" tsb="799"/>
+ <mtx name="q" height="2465" tsb="923"/>
+ <mtx name="question" height="2465" tsb="516"/>
+ <mtx name="questiondown" height="2465" tsb="947"/>
+ <mtx name="quotedbl" height="2465" tsb="454"/>
+ <mtx name="quotedblbase" height="2465" tsb="1786"/>
+ <mtx name="quotedblleft" height="2465" tsb="454"/>
+ <mtx name="quotedblright" height="2465" tsb="454"/>
+ <mtx name="quoteleft" height="2465" tsb="454"/>
+ <mtx name="quotereversed" height="2465" tsb="2033"/>
+ <mtx name="quoteright" height="2465" tsb="454"/>
+ <mtx name="quotesinglbase" height="2465" tsb="1737"/>
+ <mtx name="quotesingle" height="2465" tsb="454"/>
+ <mtx name="r" height="2465" tsb="923"/>
+ <mtx name="racute" height="2465" tsb="429"/>
+ <mtx name="radicalex" height="2465" tsb="429"/>
+ <mtx name="rcaron" height="2465" tsb="429"/>
+ <mtx name="rcommaaccent" height="2465" tsb="923"/>
+ <mtx name="registered" height="2465" tsb="516"/>
+ <mtx name="ring" height="2465" tsb="296"/>
+ <mtx name="s" height="2465" tsb="922"/>
+ <mtx name="sacute" height="2465" tsb="429"/>
+ <mtx name="scaron" height="2465" tsb="429"/>
+ <mtx name="scedilla" height="2465" tsb="922"/>
+ <mtx name="scircumflex" height="2465" tsb="429"/>
+ <mtx name="scommaaccent" height="2465" tsb="922"/>
+ <mtx name="section" height="2465" tsb="515"/>
+ <mtx name="semicolon" height="2465" tsb="947"/>
+ <mtx name="semicolon#1" height="2465" tsb="947"/>
+ <mtx name="seven" height="2465" tsb="553"/>
+ <mtx name="sfthyphen" height="2465" tsb="1342"/>
+ <mtx name="six" height="2465" tsb="516"/>
+ <mtx name="slash" height="2465" tsb="454"/>
+ <mtx name="space" height="2465" tsb="2033"/>
+ <mtx name="sterling" height="2465" tsb="516"/>
+ <mtx name="t" height="2465" tsb="701"/>
+ <mtx name="tbar" height="2465" tsb="701"/>
+ <mtx name="tcaron" height="2465" tsb="345"/>
+ <mtx name="tcommaaccent" height="2465" tsb="701"/>
+ <mtx name="tcommabelow" height="2465" tsb="701"/>
+ <mtx name="thorn" height="2465" tsb="454"/>
+ <mtx name="three" height="2465" tsb="516"/>
+ <mtx name="threequarters" height="2465" tsb="515"/>
+ <mtx name="threesuperior" height="2465" tsb="515"/>
+ <mtx name="threesuperiour" height="2465" tsb="515"/>
+ <mtx name="tilde" height="2465" tsb="515"/>
+ <mtx name="trademark" height="2465" tsb="553"/>
+ <mtx name="two" height="2465" tsb="516"/>
+ <mtx name="twosuperior" height="2465" tsb="515"/>
+ <mtx name="twosuperiour" height="2465" tsb="516"/>
+ <mtx name="u" height="2465" tsb="947"/>
+ <mtx name="uacute" height="2465" tsb="429"/>
+ <mtx name="ubreve" height="2465" tsb="454"/>
+ <mtx name="ucircumflex" height="2465" tsb="429"/>
+ <mtx name="udieresis" height="2465" tsb="553"/>
+ <mtx name="ugrave" height="2465" tsb="429"/>
+ <mtx name="uhungarumlaut" height="2465" tsb="429"/>
+ <mtx name="umacron" height="2465" tsb="626"/>
+ <mtx name="underscore" height="2465" tsb="2033"/>
+ <mtx name="uogonek" height="2465" tsb="947"/>
+ <mtx name="uring" height="2465" tsb="296"/>
+ <mtx name="utilde" height="2465" tsb="515"/>
+ <mtx name="v" height="2465" tsb="947"/>
+ <mtx name="w" height="2465" tsb="947"/>
+ <mtx name="wcircumflex" height="2465" tsb="429"/>
+ <mtx name="x" height="2465" tsb="947"/>
+ <mtx name="y" height="2465" tsb="947"/>
+ <mtx name="yacute" height="2465" tsb="429"/>
+ <mtx name="ycircumflex" height="2465" tsb="429"/>
+ <mtx name="ydieresis" height="2465" tsb="553"/>
+ <mtx name="yen" height="2465" tsb="553"/>
+ <mtx name="z" height="2465" tsb="947"/>
+ <mtx name="zacute" height="2465" tsb="429"/>
+ <mtx name="zcaron" height="2465" tsb="429"/>
+ <mtx name="zdotaccent" height="2465" tsb="553"/>
+ <mtx name="zero" height="2465" tsb="516"/>
+ </vmtx>
+
+</ttFont>
diff --git a/vendor/github.com/golang/freetype/testdata/luxirr.ttf b/vendor/github.com/golang/freetype/testdata/luxirr.ttf
new file mode 100644
index 000000000..daa8ad8cc
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luxirr.ttf
Binary files differ
diff --git a/vendor/github.com/golang/freetype/testdata/luxirr.ttx b/vendor/github.com/golang/freetype/testdata/luxirr.ttx
new file mode 100644
index 000000000..27191d0a7
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luxirr.ttx
@@ -0,0 +1,30264 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="2.4">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name=".notdef#1"/>
+ <GlyphID id="2" name=".notdef#2"/>
+ <GlyphID id="3" name="space"/>
+ <GlyphID id="4" name="exclam"/>
+ <GlyphID id="5" name="quotedbl"/>
+ <GlyphID id="6" name="numbersign"/>
+ <GlyphID id="7" name="dollar"/>
+ <GlyphID id="8" name="percent"/>
+ <GlyphID id="9" name="ampersand"/>
+ <GlyphID id="10" name="quotesingle"/>
+ <GlyphID id="11" name="parenleft"/>
+ <GlyphID id="12" name="parenright"/>
+ <GlyphID id="13" name="asterisk"/>
+ <GlyphID id="14" name="plus"/>
+ <GlyphID id="15" name="comma"/>
+ <GlyphID id="16" name="hyphen"/>
+ <GlyphID id="17" name="period"/>
+ <GlyphID id="18" name="slash"/>
+ <GlyphID id="19" name="zero"/>
+ <GlyphID id="20" name="one"/>
+ <GlyphID id="21" name="two"/>
+ <GlyphID id="22" name="three"/>
+ <GlyphID id="23" name="four"/>
+ <GlyphID id="24" name="five"/>
+ <GlyphID id="25" name="six"/>
+ <GlyphID id="26" name="seven"/>
+ <GlyphID id="27" name="eight"/>
+ <GlyphID id="28" name="nine"/>
+ <GlyphID id="29" name="colon"/>
+ <GlyphID id="30" name="semicolon"/>
+ <GlyphID id="31" name="less"/>
+ <GlyphID id="32" name="equal"/>
+ <GlyphID id="33" name="greater"/>
+ <GlyphID id="34" name="question"/>
+ <GlyphID id="35" name="at"/>
+ <GlyphID id="36" name="A"/>
+ <GlyphID id="37" name="B"/>
+ <GlyphID id="38" name="C"/>
+ <GlyphID id="39" name="D"/>
+ <GlyphID id="40" name="E"/>
+ <GlyphID id="41" name="F"/>
+ <GlyphID id="42" name="G"/>
+ <GlyphID id="43" name="H"/>
+ <GlyphID id="44" name="I"/>
+ <GlyphID id="45" name="J"/>
+ <GlyphID id="46" name="K"/>
+ <GlyphID id="47" name="L"/>
+ <GlyphID id="48" name="M"/>
+ <GlyphID id="49" name="N"/>
+ <GlyphID id="50" name="O"/>
+ <GlyphID id="51" name="P"/>
+ <GlyphID id="52" name="Q"/>
+ <GlyphID id="53" name="R"/>
+ <GlyphID id="54" name="S"/>
+ <GlyphID id="55" name="T"/>
+ <GlyphID id="56" name="U"/>
+ <GlyphID id="57" name="V"/>
+ <GlyphID id="58" name="W"/>
+ <GlyphID id="59" name="X"/>
+ <GlyphID id="60" name="Y"/>
+ <GlyphID id="61" name="Z"/>
+ <GlyphID id="62" name="bracketleft"/>
+ <GlyphID id="63" name="backslash"/>
+ <GlyphID id="64" name="bracketright"/>
+ <GlyphID id="65" name="asciicircum"/>
+ <GlyphID id="66" name="underscore"/>
+ <GlyphID id="67" name="grave"/>
+ <GlyphID id="68" name="a"/>
+ <GlyphID id="69" name="b"/>
+ <GlyphID id="70" name="c"/>
+ <GlyphID id="71" name="d"/>
+ <GlyphID id="72" name="e"/>
+ <GlyphID id="73" name="f"/>
+ <GlyphID id="74" name="g"/>
+ <GlyphID id="75" name="h"/>
+ <GlyphID id="76" name="i"/>
+ <GlyphID id="77" name="j"/>
+ <GlyphID id="78" name="k"/>
+ <GlyphID id="79" name="l"/>
+ <GlyphID id="80" name="m"/>
+ <GlyphID id="81" name="n"/>
+ <GlyphID id="82" name="o"/>
+ <GlyphID id="83" name="p"/>
+ <GlyphID id="84" name="q"/>
+ <GlyphID id="85" name="r"/>
+ <GlyphID id="86" name="s"/>
+ <GlyphID id="87" name="t"/>
+ <GlyphID id="88" name="u"/>
+ <GlyphID id="89" name="v"/>
+ <GlyphID id="90" name="w"/>
+ <GlyphID id="91" name="x"/>
+ <GlyphID id="92" name="y"/>
+ <GlyphID id="93" name="z"/>
+ <GlyphID id="94" name="braceleft"/>
+ <GlyphID id="95" name="bar"/>
+ <GlyphID id="96" name="braceright"/>
+ <GlyphID id="97" name="asciitilde"/>
+ <GlyphID id="98" name="Adieresis"/>
+ <GlyphID id="99" name="Aring"/>
+ <GlyphID id="100" name="Ccedilla"/>
+ <GlyphID id="101" name="Eacute"/>
+ <GlyphID id="102" name="Ntilde"/>
+ <GlyphID id="103" name="Odieresis"/>
+ <GlyphID id="104" name="Udieresis"/>
+ <GlyphID id="105" name="aacute"/>
+ <GlyphID id="106" name="agrave"/>
+ <GlyphID id="107" name="acircumflex"/>
+ <GlyphID id="108" name="adieresis"/>
+ <GlyphID id="109" name="atilde"/>
+ <GlyphID id="110" name="aring"/>
+ <GlyphID id="111" name="ccedilla"/>
+ <GlyphID id="112" name="eacute"/>
+ <GlyphID id="113" name="egrave"/>
+ <GlyphID id="114" name="ecircumflex"/>
+ <GlyphID id="115" name="edieresis"/>
+ <GlyphID id="116" name="iacute"/>
+ <GlyphID id="117" name="igrave"/>
+ <GlyphID id="118" name="icircumflex"/>
+ <GlyphID id="119" name="idieresis"/>
+ <GlyphID id="120" name="ntilde"/>
+ <GlyphID id="121" name="oacute"/>
+ <GlyphID id="122" name="ograve"/>
+ <GlyphID id="123" name="ocircumflex"/>
+ <GlyphID id="124" name="odieresis"/>
+ <GlyphID id="125" name="otilde"/>
+ <GlyphID id="126" name="uacute"/>
+ <GlyphID id="127" name="ugrave"/>
+ <GlyphID id="128" name="ucircumflex"/>
+ <GlyphID id="129" name="udieresis"/>
+ <GlyphID id="130" name="dagger"/>
+ <GlyphID id="131" name="degree"/>
+ <GlyphID id="132" name="cent"/>
+ <GlyphID id="133" name="sterling"/>
+ <GlyphID id="134" name="section"/>
+ <GlyphID id="135" name="bullet"/>
+ <GlyphID id="136" name="paragraph"/>
+ <GlyphID id="137" name="germandbls"/>
+ <GlyphID id="138" name="registered"/>
+ <GlyphID id="139" name="copyright"/>
+ <GlyphID id="140" name="trademark"/>
+ <GlyphID id="141" name="acute"/>
+ <GlyphID id="142" name="dieresis"/>
+ <GlyphID id="143" name=".notdef#3"/>
+ <GlyphID id="144" name="AE"/>
+ <GlyphID id="145" name="Oslash"/>
+ <GlyphID id="146" name=".notdef#4"/>
+ <GlyphID id="147" name="plusminus"/>
+ <GlyphID id="148" name=".notdef#5"/>
+ <GlyphID id="149" name=".notdef#6"/>
+ <GlyphID id="150" name="yen"/>
+ <GlyphID id="151" name="mu"/>
+ <GlyphID id="152" name=".notdef#7"/>
+ <GlyphID id="153" name=".notdef#8"/>
+ <GlyphID id="154" name=".notdef#9"/>
+ <GlyphID id="155" name=".notdef#10"/>
+ <GlyphID id="156" name=".notdef#11"/>
+ <GlyphID id="157" name="ordfeminine"/>
+ <GlyphID id="158" name="ordmasculine"/>
+ <GlyphID id="159" name=".notdef#12"/>
+ <GlyphID id="160" name="ae"/>
+ <GlyphID id="161" name="oslash"/>
+ <GlyphID id="162" name="questiondown"/>
+ <GlyphID id="163" name="exclamdown"/>
+ <GlyphID id="164" name="logicalnot"/>
+ <GlyphID id="165" name=".notdef#13"/>
+ <GlyphID id="166" name="florin"/>
+ <GlyphID id="167" name=".notdef#14"/>
+ <GlyphID id="168" name=".notdef#15"/>
+ <GlyphID id="169" name="guillemotleft"/>
+ <GlyphID id="170" name="guillemotright"/>
+ <GlyphID id="171" name="ellipsis"/>
+ <GlyphID id="172" name=".notdef#16"/>
+ <GlyphID id="173" name="Agrave"/>
+ <GlyphID id="174" name="Atilde"/>
+ <GlyphID id="175" name="Otilde"/>
+ <GlyphID id="176" name="OE"/>
+ <GlyphID id="177" name="oe"/>
+ <GlyphID id="178" name="endash"/>
+ <GlyphID id="179" name="emdash"/>
+ <GlyphID id="180" name="quotedblleft"/>
+ <GlyphID id="181" name="quotedblright"/>
+ <GlyphID id="182" name="quoteleft"/>
+ <GlyphID id="183" name="quoteright"/>
+ <GlyphID id="184" name="divide"/>
+ <GlyphID id="185" name=".notdef#17"/>
+ <GlyphID id="186" name="ydieresis"/>
+ <GlyphID id="187" name="Ydieresis"/>
+ <GlyphID id="188" name="fraction"/>
+ <GlyphID id="189" name="currency"/>
+ <GlyphID id="190" name="guilsinglleft"/>
+ <GlyphID id="191" name="guilsinglright"/>
+ <GlyphID id="192" name="fi"/>
+ <GlyphID id="193" name="fl"/>
+ <GlyphID id="194" name="daggerdbl"/>
+ <GlyphID id="195" name="periodcentered"/>
+ <GlyphID id="196" name="quotesinglbase"/>
+ <GlyphID id="197" name="quotedblbase"/>
+ <GlyphID id="198" name="perthousand"/>
+ <GlyphID id="199" name="Acircumflex"/>
+ <GlyphID id="200" name="Ecircumflex"/>
+ <GlyphID id="201" name="Aacute"/>
+ <GlyphID id="202" name="Edieresis"/>
+ <GlyphID id="203" name="Egrave"/>
+ <GlyphID id="204" name="Iacute"/>
+ <GlyphID id="205" name="Icircumflex"/>
+ <GlyphID id="206" name="Idieresis"/>
+ <GlyphID id="207" name="Igrave"/>
+ <GlyphID id="208" name="Oacute"/>
+ <GlyphID id="209" name="Ocircumflex"/>
+ <GlyphID id="210" name="Euro"/>
+ <GlyphID id="211" name="Ograve"/>
+ <GlyphID id="212" name="Uacute"/>
+ <GlyphID id="213" name="Ucircumflex"/>
+ <GlyphID id="214" name="Ugrave"/>
+ <GlyphID id="215" name="dotlessi"/>
+ <GlyphID id="216" name="circumflex"/>
+ <GlyphID id="217" name="tilde"/>
+ <GlyphID id="218" name="macron"/>
+ <GlyphID id="219" name="breve"/>
+ <GlyphID id="220" name="dotaccent"/>
+ <GlyphID id="221" name="ring"/>
+ <GlyphID id="222" name="cedilla"/>
+ <GlyphID id="223" name="hungarumlaut"/>
+ <GlyphID id="224" name="ogonek"/>
+ <GlyphID id="225" name="caron"/>
+ <GlyphID id="226" name="Euro#1"/>
+ <GlyphID id="227" name="nonbreakingspace"/>
+ <GlyphID id="228" name="brokenbar"/>
+ <GlyphID id="229" name="sfthyphen"/>
+ <GlyphID id="230" name="macron#1"/>
+ <GlyphID id="231" name="twosuperior"/>
+ <GlyphID id="232" name="threesuperior"/>
+ <GlyphID id="233" name="periodcentered#1"/>
+ <GlyphID id="234" name="onesuperior"/>
+ <GlyphID id="235" name="onequarter"/>
+ <GlyphID id="236" name="onehalf"/>
+ <GlyphID id="237" name="threequarters"/>
+ <GlyphID id="238" name="Eth"/>
+ <GlyphID id="239" name="multiply"/>
+ <GlyphID id="240" name="Yacute"/>
+ <GlyphID id="241" name="Thorn"/>
+ <GlyphID id="242" name="eth"/>
+ <GlyphID id="243" name="yacute"/>
+ <GlyphID id="244" name="thorn"/>
+ <GlyphID id="245" name="Amacron"/>
+ <GlyphID id="246" name="amacron"/>
+ <GlyphID id="247" name="Abreve"/>
+ <GlyphID id="248" name="abreve"/>
+ <GlyphID id="249" name="Aogonek"/>
+ <GlyphID id="250" name="aogonek"/>
+ <GlyphID id="251" name="Cacute"/>
+ <GlyphID id="252" name="cacute"/>
+ <GlyphID id="253" name="Ccircumflex"/>
+ <GlyphID id="254" name="ccircumflex"/>
+ <GlyphID id="255" name="Cdotaccent"/>
+ <GlyphID id="256" name="cdotaccent"/>
+ <GlyphID id="257" name="Ccaron"/>
+ <GlyphID id="258" name="ccaron"/>
+ <GlyphID id="259" name="Dcaron"/>
+ <GlyphID id="260" name="dcaron"/>
+ <GlyphID id="261" name="Dcroat"/>
+ <GlyphID id="262" name="dcroat"/>
+ <GlyphID id="263" name="Emacron"/>
+ <GlyphID id="264" name="emacron"/>
+ <GlyphID id="265" name="Ebreve"/>
+ <GlyphID id="266" name="ebreve"/>
+ <GlyphID id="267" name="Edotaccent"/>
+ <GlyphID id="268" name="edotaccent"/>
+ <GlyphID id="269" name="Eogonek"/>
+ <GlyphID id="270" name="eogonek"/>
+ <GlyphID id="271" name="Ecaron"/>
+ <GlyphID id="272" name="ecaron"/>
+ <GlyphID id="273" name="Gcircumflex"/>
+ <GlyphID id="274" name="gcircumflex"/>
+ <GlyphID id="275" name="Gbreve"/>
+ <GlyphID id="276" name="gbreve"/>
+ <GlyphID id="277" name="Gdotaccent"/>
+ <GlyphID id="278" name="gdotaccent"/>
+ <GlyphID id="279" name="Gcommaaccent"/>
+ <GlyphID id="280" name="gcommaaccent"/>
+ <GlyphID id="281" name="Hcircumflex"/>
+ <GlyphID id="282" name="hcircumflex"/>
+ <GlyphID id="283" name="Hbar"/>
+ <GlyphID id="284" name="hbar"/>
+ <GlyphID id="285" name="Itilde"/>
+ <GlyphID id="286" name="itilde"/>
+ <GlyphID id="287" name="Imacron"/>
+ <GlyphID id="288" name="imacron"/>
+ <GlyphID id="289" name="Ibreve"/>
+ <GlyphID id="290" name="ibreve"/>
+ <GlyphID id="291" name="Iogonek"/>
+ <GlyphID id="292" name="iogonek"/>
+ <GlyphID id="293" name="Idotaccent"/>
+ <GlyphID id="294" name="IJ"/>
+ <GlyphID id="295" name="ij"/>
+ <GlyphID id="296" name="Jcircumflex"/>
+ <GlyphID id="297" name="jcircumflex"/>
+ <GlyphID id="298" name="Kcommaaccent"/>
+ <GlyphID id="299" name="kcommaaccent"/>
+ <GlyphID id="300" name="kgreenlandic"/>
+ <GlyphID id="301" name="Lacute"/>
+ <GlyphID id="302" name="lacute"/>
+ <GlyphID id="303" name="Lcommaaccent"/>
+ <GlyphID id="304" name="lcommaaccent"/>
+ <GlyphID id="305" name="Lcaron"/>
+ <GlyphID id="306" name="lcaron"/>
+ <GlyphID id="307" name="Ldot"/>
+ <GlyphID id="308" name="ldot"/>
+ <GlyphID id="309" name="Lslash"/>
+ <GlyphID id="310" name="lslash"/>
+ <GlyphID id="311" name="Nacute"/>
+ <GlyphID id="312" name="nacute"/>
+ <GlyphID id="313" name="Ncommaaccent"/>
+ <GlyphID id="314" name="ncommaaccent"/>
+ <GlyphID id="315" name="Ncaron"/>
+ <GlyphID id="316" name="ncaron"/>
+ <GlyphID id="317" name="napostrophe"/>
+ <GlyphID id="318" name="Eng"/>
+ <GlyphID id="319" name="eng"/>
+ <GlyphID id="320" name="Omacron"/>
+ <GlyphID id="321" name="omacron"/>
+ <GlyphID id="322" name="Obreve"/>
+ <GlyphID id="323" name="obreve"/>
+ <GlyphID id="324" name="Ohungarumlaut"/>
+ <GlyphID id="325" name="ohungarumlaut"/>
+ <GlyphID id="326" name="Racute"/>
+ <GlyphID id="327" name="racute"/>
+ <GlyphID id="328" name="Rcommaaccent"/>
+ <GlyphID id="329" name="rcommaaccent"/>
+ <GlyphID id="330" name="Rcaron"/>
+ <GlyphID id="331" name="rcaron"/>
+ <GlyphID id="332" name="Sacute"/>
+ <GlyphID id="333" name="sacute"/>
+ <GlyphID id="334" name="Scircumflex"/>
+ <GlyphID id="335" name="scircumflex"/>
+ <GlyphID id="336" name="Scedilla"/>
+ <GlyphID id="337" name="scedilla"/>
+ <GlyphID id="338" name="Scaron"/>
+ <GlyphID id="339" name="scaron"/>
+ <GlyphID id="340" name="Tcommaaccent"/>
+ <GlyphID id="341" name="tcommaaccent"/>
+ <GlyphID id="342" name="Tcaron"/>
+ <GlyphID id="343" name="tcaron"/>
+ <GlyphID id="344" name="Tbar"/>
+ <GlyphID id="345" name="tbar"/>
+ <GlyphID id="346" name="Utilde"/>
+ <GlyphID id="347" name="utilde"/>
+ <GlyphID id="348" name="Umacron"/>
+ <GlyphID id="349" name="umacron"/>
+ <GlyphID id="350" name="Ubreve"/>
+ <GlyphID id="351" name="ubreve"/>
+ <GlyphID id="352" name="Uring"/>
+ <GlyphID id="353" name="uring"/>
+ <GlyphID id="354" name="Uhungarumlaut"/>
+ <GlyphID id="355" name="uhungarumlaut"/>
+ <GlyphID id="356" name="Uogonek"/>
+ <GlyphID id="357" name="uogonek"/>
+ <GlyphID id="358" name="Wcircumflex"/>
+ <GlyphID id="359" name="wcircumflex"/>
+ <GlyphID id="360" name="Ycircumflex"/>
+ <GlyphID id="361" name="ycircumflex"/>
+ <GlyphID id="362" name="Zacute"/>
+ <GlyphID id="363" name="zacute"/>
+ <GlyphID id="364" name="Zdotaccent"/>
+ <GlyphID id="365" name="zdotaccent"/>
+ <GlyphID id="366" name="Zcaron"/>
+ <GlyphID id="367" name="zcaron"/>
+ <GlyphID id="368" name="longs"/>
+ <GlyphID id="369" name="Scommaaccent"/>
+ <GlyphID id="370" name="scommaaccent"/>
+ <GlyphID id="371" name="Tcommabelow"/>
+ <GlyphID id="372" name="tcommabelow"/>
+ <GlyphID id="373" name="Unterkomma"/>
+ <GlyphID id="374" name="semicolon#1"/>
+ <GlyphID id="375" name="anoteleia"/>
+ <GlyphID id="376" name="hyphen#1"/>
+ <GlyphID id="377" name="nbhyphen"/>
+ <GlyphID id="378" name="figuredash"/>
+ <GlyphID id="379" name="afii00208"/>
+ <GlyphID id="380" name="quotereversed"/>
+ <GlyphID id="381" name="radicalex"/>
+ <GlyphID id="382" name="estimated"/>
+ <GlyphID id="383" name="minus"/>
+ <GlyphID id="384" name="fraction#1"/>
+ <GlyphID id="385" name="dotmath"/>
+ <GlyphID id="386" name="fi#1"/>
+ <GlyphID id="387" name="fl#1"/>
+ <GlyphID id="388" name="foursuperiour"/>
+ <GlyphID id="389" name="dotlessj"/>
+ <GlyphID id="390" name=".notdef#18"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.19999694824"/>
+ <checkSumAdjustment value="0xc0d96d6c"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00001111"/>
+ <unitsPerEm value="2048"/>
+ <created value="Fri Oct 12 14:06:14 2001"/>
+ <modified value="Fri Oct 12 10:57:50 2001"/>
+ <xMin value="-416"/>
+ <yMin value="-432"/>
+ <xMax value="2014"/>
+ <yMax value="2033"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="12"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="2033"/>
+ <descent value="-432"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="2048"/>
+ <minLeftSideBearing value="-416"/>
+ <minRightSideBearing value="-417"/>
+ <xMaxExtent value="2014"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="391"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="391"/>
+ <maxPoints value="90"/>
+ <maxContours value="7"/>
+ <maxCompositePoints value="86"/>
+ <maxCompositeContours value="4"/>
+ <maxZones value="2"/>
+ <maxTwilightPoints value="4"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="15"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="2048"/>
+ <maxSizeOfInstructions value="204"/>
+ <maxComponentElements value="2"/>
+ <maxComponentDepth value="1"/>
+ </maxp>
+
+ <OS_2>
+ <version value="2"/>
+ <xAvgCharWidth value="821"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000000"/>
+ <ySubscriptXSize value="1434"/>
+ <ySubscriptYSize value="1331"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="283"/>
+ <ySuperscriptXSize value="1434"/>
+ <ySuperscriptYSize value="1331"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="977"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="0"/>
+ <sFamilyClass value="5"/>
+ <panose>
+ <bFamilyType value="2"/>
+ <bSerifStyle value="2"/>
+ <bWeight value="6"/>
+ <bProportion value="3"/>
+ <bContrast value="7"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000111"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="B&amp;H "/>
+ <fsSelection value="00000000 01000000"/>
+ <fsFirstCharIndex value="32"/>
+ <fsLastCharIndex value="64258"/>
+ <sTypoAscender value="1604"/>
+ <sTypoDescender value="-420"/>
+ <sTypoLineGap value="167"/>
+ <usWinAscent value="1934"/>
+ <usWinDescent value="432"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 10010011"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="0"/>
+ <sCapHeight value="0"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="0"/>
+ <usMaxContex value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="512" lsb="51"/>
+ <mtx name=".notdef#1" width="0" lsb="0"/>
+ <mtx name=".notdef#10" width="512" lsb="0"/>
+ <mtx name=".notdef#11" width="512" lsb="0"/>
+ <mtx name=".notdef#12" width="512" lsb="0"/>
+ <mtx name=".notdef#13" width="512" lsb="0"/>
+ <mtx name=".notdef#14" width="512" lsb="0"/>
+ <mtx name=".notdef#15" width="512" lsb="0"/>
+ <mtx name=".notdef#16" width="1024" lsb="0"/>
+ <mtx name=".notdef#17" width="512" lsb="0"/>
+ <mtx name=".notdef#18" width="512" lsb="0"/>
+ <mtx name=".notdef#2" width="512" lsb="0"/>
+ <mtx name=".notdef#3" width="512" lsb="0"/>
+ <mtx name=".notdef#4" width="512" lsb="0"/>
+ <mtx name=".notdef#5" width="512" lsb="0"/>
+ <mtx name=".notdef#6" width="512" lsb="0"/>
+ <mtx name=".notdef#7" width="512" lsb="0"/>
+ <mtx name=".notdef#8" width="512" lsb="0"/>
+ <mtx name=".notdef#9" width="512" lsb="0"/>
+ <mtx name="A" width="1479" lsb="0"/>
+ <mtx name="AE" width="1821" lsb="0"/>
+ <mtx name="Aacute" width="1479" lsb="0"/>
+ <mtx name="Abreve" width="1479" lsb="0"/>
+ <mtx name="Acircumflex" width="1479" lsb="0"/>
+ <mtx name="Adieresis" width="1479" lsb="0"/>
+ <mtx name="Agrave" width="1479" lsb="0"/>
+ <mtx name="Amacron" width="1479" lsb="0"/>
+ <mtx name="Aogonek" width="1479" lsb="0"/>
+ <mtx name="Aring" width="1479" lsb="0"/>
+ <mtx name="Atilde" width="1479" lsb="0"/>
+ <mtx name="B" width="1366" lsb="47"/>
+ <mtx name="C" width="1366" lsb="80"/>
+ <mtx name="Cacute" width="1366" lsb="80"/>
+ <mtx name="Ccaron" width="1366" lsb="80"/>
+ <mtx name="Ccedilla" width="1366" lsb="80"/>
+ <mtx name="Ccircumflex" width="1366" lsb="80"/>
+ <mtx name="Cdotaccent" width="1366" lsb="80"/>
+ <mtx name="D" width="1479" lsb="41"/>
+ <mtx name="Dcaron" width="1479" lsb="41"/>
+ <mtx name="Dcroat" width="1479" lsb="41"/>
+ <mtx name="E" width="1251" lsb="43"/>
+ <mtx name="Eacute" width="1251" lsb="43"/>
+ <mtx name="Ebreve" width="1251" lsb="43"/>
+ <mtx name="Ecaron" width="1251" lsb="43"/>
+ <mtx name="Ecircumflex" width="1251" lsb="43"/>
+ <mtx name="Edieresis" width="1251" lsb="43"/>
+ <mtx name="Edotaccent" width="1251" lsb="43"/>
+ <mtx name="Egrave" width="1251" lsb="43"/>
+ <mtx name="Emacron" width="1251" lsb="43"/>
+ <mtx name="Eng" width="1479" lsb="43"/>
+ <mtx name="Eogonek" width="1251" lsb="43"/>
+ <mtx name="Eth" width="1479" lsb="41"/>
+ <mtx name="Euro" width="1024" lsb="0"/>
+ <mtx name="Euro#1" width="1024" lsb="0"/>
+ <mtx name="F" width="1139" lsb="43"/>
+ <mtx name="G" width="1479" lsb="85"/>
+ <mtx name="Gbreve" width="1479" lsb="85"/>
+ <mtx name="Gcircumflex" width="1479" lsb="85"/>
+ <mtx name="Gcommaaccent" width="1479" lsb="85"/>
+ <mtx name="Gdotaccent" width="1479" lsb="85"/>
+ <mtx name="H" width="1479" lsb="41"/>
+ <mtx name="Hbar" width="1479" lsb="41"/>
+ <mtx name="Hcircumflex" width="1479" lsb="41"/>
+ <mtx name="I" width="682" lsb="51"/>
+ <mtx name="IJ" width="1451" lsb="51"/>
+ <mtx name="Iacute" width="682" lsb="51"/>
+ <mtx name="Ibreve" width="682" lsb="8"/>
+ <mtx name="Icircumflex" width="682" lsb="-11"/>
+ <mtx name="Idieresis" width="682" lsb="51"/>
+ <mtx name="Idotaccent" width="682" lsb="51"/>
+ <mtx name="Igrave" width="682" lsb="39"/>
+ <mtx name="Imacron" width="682" lsb="20"/>
+ <mtx name="Iogonek" width="682" lsb="51"/>
+ <mtx name="Itilde" width="682" lsb="8"/>
+ <mtx name="J" width="797" lsb="0"/>
+ <mtx name="Jcircumflex" width="797" lsb="0"/>
+ <mtx name="K" width="1479" lsb="56"/>
+ <mtx name="Kcommaaccent" width="1479" lsb="56"/>
+ <mtx name="L" width="1251" lsb="56"/>
+ <mtx name="Lacute" width="1251" lsb="56"/>
+ <mtx name="Lcaron" width="1251" lsb="56"/>
+ <mtx name="Lcommaaccent" width="1251" lsb="56"/>
+ <mtx name="Ldot" width="1251" lsb="56"/>
+ <mtx name="Lslash" width="1251" lsb="56"/>
+ <mtx name="M" width="1821" lsb="48"/>
+ <mtx name="N" width="1479" lsb="43"/>
+ <mtx name="Nacute" width="1479" lsb="43"/>
+ <mtx name="Ncaron" width="1479" lsb="43"/>
+ <mtx name="Ncommaaccent" width="1479" lsb="43"/>
+ <mtx name="Ntilde" width="1479" lsb="43"/>
+ <mtx name="O" width="1479" lsb="80"/>
+ <mtx name="OE" width="1821" lsb="80"/>
+ <mtx name="Oacute" width="1479" lsb="80"/>
+ <mtx name="Obreve" width="1479" lsb="80"/>
+ <mtx name="Ocircumflex" width="1479" lsb="80"/>
+ <mtx name="Odieresis" width="1479" lsb="80"/>
+ <mtx name="Ograve" width="1479" lsb="80"/>
+ <mtx name="Ohungarumlaut" width="1479" lsb="80"/>
+ <mtx name="Omacron" width="1479" lsb="80"/>
+ <mtx name="Oslash" width="1479" lsb="80"/>
+ <mtx name="Otilde" width="1479" lsb="80"/>
+ <mtx name="P" width="1139" lsb="31"/>
+ <mtx name="Q" width="1479" lsb="80"/>
+ <mtx name="R" width="1366" lsb="31"/>
+ <mtx name="Racute" width="1366" lsb="31"/>
+ <mtx name="Rcaron" width="1366" lsb="31"/>
+ <mtx name="Rcommaaccent" width="1366" lsb="31"/>
+ <mtx name="S" width="1139" lsb="119"/>
+ <mtx name="Sacute" width="1139" lsb="119"/>
+ <mtx name="Scaron" width="1139" lsb="119"/>
+ <mtx name="Scedilla" width="1139" lsb="119"/>
+ <mtx name="Scircumflex" width="1139" lsb="119"/>
+ <mtx name="Scommaaccent" width="1139" lsb="119"/>
+ <mtx name="T" width="1251" lsb="31"/>
+ <mtx name="Tbar" width="1251" lsb="31"/>
+ <mtx name="Tcaron" width="1251" lsb="31"/>
+ <mtx name="Tcommaaccent" width="1251" lsb="31"/>
+ <mtx name="Tcommabelow" width="1251" lsb="31"/>
+ <mtx name="Thorn" width="1139" lsb="43"/>
+ <mtx name="U" width="1479" lsb="19"/>
+ <mtx name="Uacute" width="1479" lsb="19"/>
+ <mtx name="Ubreve" width="1479" lsb="19"/>
+ <mtx name="Ucircumflex" width="1479" lsb="19"/>
+ <mtx name="Udieresis" width="1479" lsb="19"/>
+ <mtx name="Ugrave" width="1479" lsb="19"/>
+ <mtx name="Uhungarumlaut" width="1479" lsb="19"/>
+ <mtx name="Umacron" width="1479" lsb="19"/>
+ <mtx name="Unterkomma" width="682" lsb="170"/>
+ <mtx name="Uogonek" width="1479" lsb="19"/>
+ <mtx name="Uring" width="1479" lsb="19"/>
+ <mtx name="Utilde" width="1479" lsb="19"/>
+ <mtx name="V" width="1479" lsb="0"/>
+ <mtx name="W" width="1933" lsb="0"/>
+ <mtx name="Wcircumflex" width="1933" lsb="0"/>
+ <mtx name="X" width="1479" lsb="12"/>
+ <mtx name="Y" width="1479" lsb="0"/>
+ <mtx name="Yacute" width="1479" lsb="0"/>
+ <mtx name="Ycircumflex" width="1479" lsb="0"/>
+ <mtx name="Ydieresis" width="1479" lsb="0"/>
+ <mtx name="Z" width="1251" lsb="92"/>
+ <mtx name="Zacute" width="1251" lsb="92"/>
+ <mtx name="Zcaron" width="1251" lsb="92"/>
+ <mtx name="Zdotaccent" width="1251" lsb="92"/>
+ <mtx name="a" width="909" lsb="75"/>
+ <mtx name="aacute" width="909" lsb="75"/>
+ <mtx name="abreve" width="909" lsb="75"/>
+ <mtx name="acircumflex" width="909" lsb="75"/>
+ <mtx name="acute" width="682" lsb="91"/>
+ <mtx name="adieresis" width="909" lsb="75"/>
+ <mtx name="ae" width="1366" lsb="75"/>
+ <mtx name="afii00208" width="2048" lsb="99"/>
+ <mtx name="agrave" width="909" lsb="75"/>
+ <mtx name="amacron" width="909" lsb="75"/>
+ <mtx name="ampersand" width="1593" lsb="99"/>
+ <mtx name="anoteleia" width="512" lsb="133"/>
+ <mtx name="aogonek" width="909" lsb="75"/>
+ <mtx name="aring" width="909" lsb="75"/>
+ <mtx name="asciicircum" width="960" lsb="36"/>
+ <mtx name="asciitilde" width="1108" lsb="60"/>
+ <mtx name="asterisk" width="1024" lsb="120"/>
+ <mtx name="at" width="1886" lsb="140"/>
+ <mtx name="atilde" width="909" lsb="75"/>
+ <mtx name="b" width="1024" lsb="0"/>
+ <mtx name="backslash" width="569" lsb="-30"/>
+ <mtx name="bar" width="410" lsb="156"/>
+ <mtx name="braceleft" width="983" lsb="148"/>
+ <mtx name="braceright" width="983" lsb="222"/>
+ <mtx name="bracketleft" width="682" lsb="185"/>
+ <mtx name="bracketright" width="682" lsb="93"/>
+ <mtx name="breve" width="682" lsb="8"/>
+ <mtx name="brokenbar" width="410" lsb="156"/>
+ <mtx name="bullet" width="717" lsb="81"/>
+ <mtx name="c" width="909" lsb="68"/>
+ <mtx name="cacute" width="909" lsb="68"/>
+ <mtx name="caron" width="682" lsb="-10"/>
+ <mtx name="ccaron" width="909" lsb="68"/>
+ <mtx name="ccedilla" width="909" lsb="68"/>
+ <mtx name="ccircumflex" width="909" lsb="68"/>
+ <mtx name="cdotaccent" width="909" lsb="68"/>
+ <mtx name="cedilla" width="682" lsb="168"/>
+ <mtx name="cent" width="1024" lsb="123"/>
+ <mtx name="circumflex" width="682" lsb="-10"/>
+ <mtx name="colon" width="569" lsb="161"/>
+ <mtx name="comma" width="512" lsb="133"/>
+ <mtx name="copyright" width="1556" lsb="87"/>
+ <mtx name="currency" width="1024" lsb="130"/>
+ <mtx name="d" width="1024" lsb="68"/>
+ <mtx name="dagger" width="1024" lsb="80"/>
+ <mtx name="daggerdbl" width="1024" lsb="80"/>
+ <mtx name="dcaron" width="1324" lsb="68"/>
+ <mtx name="dcroat" width="1024" lsb="68"/>
+ <mtx name="degree" width="819" lsb="114"/>
+ <mtx name="dieresis" width="682" lsb="57"/>
+ <mtx name="divide" width="1155" lsb="84"/>
+ <mtx name="dollar" width="1024" lsb="80"/>
+ <mtx name="dotaccent" width="682" lsb="242"/>
+ <mtx name="dotlessi" width="569" lsb="47"/>
+ <mtx name="dotlessj" width="569" lsb="-78"/>
+ <mtx name="dotmath" width="512" lsb="133"/>
+ <mtx name="e" width="909" lsb="68"/>
+ <mtx name="eacute" width="909" lsb="68"/>
+ <mtx name="ebreve" width="909" lsb="68"/>
+ <mtx name="ecaron" width="909" lsb="68"/>
+ <mtx name="ecircumflex" width="909" lsb="68"/>
+ <mtx name="edieresis" width="909" lsb="68"/>
+ <mtx name="edotaccent" width="909" lsb="68"/>
+ <mtx name="egrave" width="909" lsb="68"/>
+ <mtx name="eight" width="1024" lsb="40"/>
+ <mtx name="ellipsis" width="2048" lsb="243"/>
+ <mtx name="emacron" width="909" lsb="68"/>
+ <mtx name="emdash" width="2048" lsb="99"/>
+ <mtx name="endash" width="1024" lsb="86"/>
+ <mtx name="eng" width="1024" lsb="37"/>
+ <mtx name="eogonek" width="909" lsb="68"/>
+ <mtx name="equal" width="1155" lsb="84"/>
+ <mtx name="estimated" width="909" lsb="68"/>
+ <mtx name="eth" width="1024" lsb="17"/>
+ <mtx name="exclam" width="682" lsb="242"/>
+ <mtx name="exclamdown" width="682" lsb="242"/>
+ <mtx name="f" width="682" lsb="37"/>
+ <mtx name="fi" width="1139" lsb="37"/>
+ <mtx name="fi#1" width="1139" lsb="37"/>
+ <mtx name="figuredash" width="1024" lsb="86"/>
+ <mtx name="five" width="1024" lsb="130"/>
+ <mtx name="fl" width="1139" lsb="37"/>
+ <mtx name="fl#1" width="1139" lsb="37"/>
+ <mtx name="florin" width="1024" lsb="12"/>
+ <mtx name="four" width="1024" lsb="25"/>
+ <mtx name="foursuperiour" width="614" lsb="31"/>
+ <mtx name="fraction" width="342" lsb="-416"/>
+ <mtx name="fraction#1" width="342" lsb="-416"/>
+ <mtx name="g" width="1024" lsb="53"/>
+ <mtx name="gbreve" width="1024" lsb="53"/>
+ <mtx name="gcircumflex" width="1024" lsb="53"/>
+ <mtx name="gcommaaccent" width="1024" lsb="53"/>
+ <mtx name="gdotaccent" width="1024" lsb="53"/>
+ <mtx name="germandbls" width="1024" lsb="27"/>
+ <mtx name="grave" width="682" lsb="91"/>
+ <mtx name="greater" width="1155" lsb="84"/>
+ <mtx name="guillemotleft" width="1024" lsb="74"/>
+ <mtx name="guillemotright" width="1024" lsb="86"/>
+ <mtx name="guilsinglleft" width="682" lsb="86"/>
+ <mtx name="guilsinglright" width="682" lsb="123"/>
+ <mtx name="h" width="1024" lsb="37"/>
+ <mtx name="hbar" width="1024" lsb="37"/>
+ <mtx name="hcircumflex" width="1024" lsb="37"/>
+ <mtx name="hungarumlaut" width="682" lsb="-5"/>
+ <mtx name="hyphen" width="682" lsb="82"/>
+ <mtx name="hyphen#1" width="682" lsb="82"/>
+ <mtx name="i" width="569" lsb="47"/>
+ <mtx name="iacute" width="569" lsb="47"/>
+ <mtx name="ibreve" width="569" lsb="-42"/>
+ <mtx name="icircumflex" width="569" lsb="-61"/>
+ <mtx name="idieresis" width="569" lsb="7"/>
+ <mtx name="igrave" width="569" lsb="7"/>
+ <mtx name="ij" width="1131" lsb="47"/>
+ <mtx name="imacron" width="569" lsb="-40"/>
+ <mtx name="iogonek" width="569" lsb="47"/>
+ <mtx name="itilde" width="569" lsb="-55"/>
+ <mtx name="j" width="569" lsb="-78"/>
+ <mtx name="jcircumflex" width="569" lsb="-78"/>
+ <mtx name="k" width="1024" lsb="31"/>
+ <mtx name="kcommaaccent" width="1024" lsb="31"/>
+ <mtx name="kgreenlandic" width="1024" lsb="37"/>
+ <mtx name="l" width="569" lsb="47"/>
+ <mtx name="lacute" width="569" lsb="47"/>
+ <mtx name="lcaron" width="832" lsb="47"/>
+ <mtx name="lcommaaccent" width="569" lsb="47"/>
+ <mtx name="ldot" width="704" lsb="47"/>
+ <mtx name="less" width="1155" lsb="84"/>
+ <mtx name="logicalnot" width="1155" lsb="84"/>
+ <mtx name="longs" width="569" lsb="37"/>
+ <mtx name="lslash" width="569" lsb="47"/>
+ <mtx name="m" width="1593" lsb="37"/>
+ <mtx name="macron" width="682" lsb="20"/>
+ <mtx name="macron#1" width="1024" lsb="99"/>
+ <mtx name="minus" width="1628" lsb="222"/>
+ <mtx name="mu" width="1024" lsb="12"/>
+ <mtx name="multiply" width="1155" lsb="84"/>
+ <mtx name="n" width="1024" lsb="37"/>
+ <mtx name="nacute" width="1024" lsb="37"/>
+ <mtx name="napostrophe" width="1237" lsb="25"/>
+ <mtx name="nbhyphen" width="682" lsb="82"/>
+ <mtx name="ncaron" width="1024" lsb="37"/>
+ <mtx name="ncommaaccent" width="1024" lsb="37"/>
+ <mtx name="nine" width="1024" lsb="37"/>
+ <mtx name="nonbreakingspace" width="512" lsb="0"/>
+ <mtx name="ntilde" width="1024" lsb="37"/>
+ <mtx name="numbersign" width="1024" lsb="0"/>
+ <mtx name="o" width="1024" lsb="62"/>
+ <mtx name="oacute" width="1024" lsb="62"/>
+ <mtx name="obreve" width="1024" lsb="62"/>
+ <mtx name="ocircumflex" width="1024" lsb="62"/>
+ <mtx name="odieresis" width="1024" lsb="62"/>
+ <mtx name="oe" width="1479" lsb="62"/>
+ <mtx name="ogonek" width="682" lsb="156"/>
+ <mtx name="ograve" width="1024" lsb="62"/>
+ <mtx name="ohungarumlaut" width="1024" lsb="62"/>
+ <mtx name="omacron" width="1024" lsb="62"/>
+ <mtx name="one" width="1024" lsb="130"/>
+ <mtx name="onehalf" width="1536" lsb="173"/>
+ <mtx name="onequarter" width="1536" lsb="173"/>
+ <mtx name="onesuperior" width="614" lsb="136"/>
+ <mtx name="ordfeminine" width="565" lsb="25"/>
+ <mtx name="ordmasculine" width="635" lsb="25"/>
+ <mtx name="oslash" width="1024" lsb="62"/>
+ <mtx name="otilde" width="1024" lsb="62"/>
+ <mtx name="p" width="1024" lsb="0"/>
+ <mtx name="paragraph" width="928" lsb="15"/>
+ <mtx name="parenleft" width="682" lsb="116"/>
+ <mtx name="parenright" width="682" lsb="104"/>
+ <mtx name="percent" width="1706" lsb="120"/>
+ <mtx name="period" width="512" lsb="133"/>
+ <mtx name="periodcentered" width="512" lsb="133"/>
+ <mtx name="periodcentered#1" width="512" lsb="133"/>
+ <mtx name="perthousand" width="2048" lsb="34"/>
+ <mtx name="plus" width="1155" lsb="84"/>
+ <mtx name="plusminus" width="1155" lsb="84"/>
+ <mtx name="q" width="1024" lsb="68"/>
+ <mtx name="question" width="909" lsb="51"/>
+ <mtx name="questiondown" width="909" lsb="51"/>
+ <mtx name="quotedbl" width="836" lsb="146"/>
+ <mtx name="quotedblbase" width="909" lsb="146"/>
+ <mtx name="quotedblleft" width="909" lsb="122"/>
+ <mtx name="quotedblright" width="909" lsb="146"/>
+ <mtx name="quoteleft" width="682" lsb="205"/>
+ <mtx name="quotereversed" width="512" lsb="0"/>
+ <mtx name="quoteright" width="682" lsb="230"/>
+ <mtx name="quotesinglbase" width="682" lsb="230"/>
+ <mtx name="quotesingle" width="369" lsb="61"/>
+ <mtx name="r" width="682" lsb="31"/>
+ <mtx name="racute" width="682" lsb="31"/>
+ <mtx name="radicalex" width="1024" lsb="99"/>
+ <mtx name="rcaron" width="682" lsb="-12"/>
+ <mtx name="rcommaaccent" width="682" lsb="31"/>
+ <mtx name="registered" width="1556" lsb="87"/>
+ <mtx name="ring" width="682" lsb="114"/>
+ <mtx name="s" width="797" lsb="95"/>
+ <mtx name="sacute" width="797" lsb="95"/>
+ <mtx name="scaron" width="797" lsb="66"/>
+ <mtx name="scedilla" width="797" lsb="95"/>
+ <mtx name="scircumflex" width="797" lsb="62"/>
+ <mtx name="scommaaccent" width="797" lsb="95"/>
+ <mtx name="section" width="1024" lsb="75"/>
+ <mtx name="semicolon" width="569" lsb="161"/>
+ <mtx name="semicolon#1" width="569" lsb="161"/>
+ <mtx name="seven" width="1024" lsb="108"/>
+ <mtx name="sfthyphen" width="682" lsb="82"/>
+ <mtx name="six" width="1024" lsb="49"/>
+ <mtx name="slash" width="569" lsb="-30"/>
+ <mtx name="space" width="512" lsb="0"/>
+ <mtx name="sterling" width="1024" lsb="74"/>
+ <mtx name="t" width="569" lsb="25"/>
+ <mtx name="tbar" width="569" lsb="25"/>
+ <mtx name="tcaron" width="666" lsb="25"/>
+ <mtx name="tcommaaccent" width="569" lsb="25"/>
+ <mtx name="tcommabelow" width="569" lsb="25"/>
+ <mtx name="thorn" width="1024" lsb="0"/>
+ <mtx name="three" width="1024" lsb="93"/>
+ <mtx name="threequarters" width="1536" lsb="173"/>
+ <mtx name="threesuperior" width="614" lsb="86"/>
+ <mtx name="tilde" width="682" lsb="8"/>
+ <mtx name="trademark" width="2007" lsb="140"/>
+ <mtx name="two" width="1024" lsb="68"/>
+ <mtx name="twosuperior" width="614" lsb="86"/>
+ <mtx name="u" width="1024" lsb="12"/>
+ <mtx name="uacute" width="1024" lsb="12"/>
+ <mtx name="ubreve" width="1024" lsb="12"/>
+ <mtx name="ucircumflex" width="1024" lsb="12"/>
+ <mtx name="udieresis" width="1024" lsb="12"/>
+ <mtx name="ugrave" width="1024" lsb="12"/>
+ <mtx name="uhungarumlaut" width="1024" lsb="12"/>
+ <mtx name="umacron" width="1024" lsb="12"/>
+ <mtx name="underscore" width="1024" lsb="0"/>
+ <mtx name="uogonek" width="1024" lsb="12"/>
+ <mtx name="uring" width="1024" lsb="12"/>
+ <mtx name="utilde" width="1024" lsb="12"/>
+ <mtx name="v" width="1024" lsb="0"/>
+ <mtx name="w" width="1479" lsb="0"/>
+ <mtx name="wcircumflex" width="1479" lsb="0"/>
+ <mtx name="x" width="1024" lsb="0"/>
+ <mtx name="y" width="1024" lsb="0"/>
+ <mtx name="yacute" width="1024" lsb="0"/>
+ <mtx name="ycircumflex" width="1024" lsb="0"/>
+ <mtx name="ydieresis" width="1024" lsb="0"/>
+ <mtx name="yen" width="1024" lsb="0"/>
+ <mtx name="z" width="909" lsb="62"/>
+ <mtx name="zacute" width="909" lsb="62"/>
+ <mtx name="zcaron" width="909" lsb="62"/>
+ <mtx name="zdotaccent" width="909" lsb="62"/>
+ <mtx name="zero" width="1024" lsb="56"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_0 platformID="1" platEncID="0" language="0">
+ <map code="0x0" name=".notdef#1"/>
+ <map code="0x1" name=".notdef"/>
+ <map code="0x2" name=".notdef"/>
+ <map code="0x3" name=".notdef"/>
+ <map code="0x4" name=".notdef"/>
+ <map code="0x5" name=".notdef"/>
+ <map code="0x6" name=".notdef"/>
+ <map code="0x7" name=".notdef"/>
+ <map code="0x8" name=".notdef#1"/>
+ <map code="0x9" name="space"/>
+ <map code="0xa" name=".notdef"/>
+ <map code="0xb" name=".notdef"/>
+ <map code="0xc" name=".notdef"/>
+ <map code="0xd" name=".notdef#2"/>
+ <map code="0xe" name=".notdef"/>
+ <map code="0xf" name=".notdef"/>
+ <map code="0x10" name=".notdef"/>
+ <map code="0x11" name=".notdef"/>
+ <map code="0x12" name=".notdef"/>
+ <map code="0x13" name=".notdef"/>
+ <map code="0x14" name=".notdef"/>
+ <map code="0x15" name=".notdef"/>
+ <map code="0x16" name=".notdef"/>
+ <map code="0x17" name=".notdef"/>
+ <map code="0x18" name=".notdef"/>
+ <map code="0x19" name=".notdef"/>
+ <map code="0x1a" name=".notdef"/>
+ <map code="0x1b" name=".notdef"/>
+ <map code="0x1c" name=".notdef"/>
+ <map code="0x1d" name=".notdef#1"/>
+ <map code="0x1e" name=".notdef"/>
+ <map code="0x1f" name=".notdef"/>
+ <map code="0x20" name="space"/>
+ <map code="0x21" name="exclam"/>
+ <map code="0x22" name="quotedbl"/>
+ <map code="0x23" name="numbersign"/>
+ <map code="0x24" name="dollar"/>
+ <map code="0x25" name="percent"/>
+ <map code="0x26" name="ampersand"/>
+ <map code="0x27" name="quotesingle"/>
+ <map code="0x28" name="parenleft"/>
+ <map code="0x29" name="parenright"/>
+ <map code="0x2a" name="asterisk"/>
+ <map code="0x2b" name="plus"/>
+ <map code="0x2c" name="comma"/>
+ <map code="0x2d" name="hyphen"/>
+ <map code="0x2e" name="period"/>
+ <map code="0x2f" name="slash"/>
+ <map code="0x30" name="zero"/>
+ <map code="0x31" name="one"/>
+ <map code="0x32" name="two"/>
+ <map code="0x33" name="three"/>
+ <map code="0x34" name="four"/>
+ <map code="0x35" name="five"/>
+ <map code="0x36" name="six"/>
+ <map code="0x37" name="seven"/>
+ <map code="0x38" name="eight"/>
+ <map code="0x39" name="nine"/>
+ <map code="0x3a" name="colon"/>
+ <map code="0x3b" name="semicolon"/>
+ <map code="0x3c" name="less"/>
+ <map code="0x3d" name="equal"/>
+ <map code="0x3e" name="greater"/>
+ <map code="0x3f" name="question"/>
+ <map code="0x40" name="at"/>
+ <map code="0x41" name="A"/>
+ <map code="0x42" name="B"/>
+ <map code="0x43" name="C"/>
+ <map code="0x44" name="D"/>
+ <map code="0x45" name="E"/>
+ <map code="0x46" name="F"/>
+ <map code="0x47" name="G"/>
+ <map code="0x48" name="H"/>
+ <map code="0x49" name="I"/>
+ <map code="0x4a" name="J"/>
+ <map code="0x4b" name="K"/>
+ <map code="0x4c" name="L"/>
+ <map code="0x4d" name="M"/>
+ <map code="0x4e" name="N"/>
+ <map code="0x4f" name="O"/>
+ <map code="0x50" name="P"/>
+ <map code="0x51" name="Q"/>
+ <map code="0x52" name="R"/>
+ <map code="0x53" name="S"/>
+ <map code="0x54" name="T"/>
+ <map code="0x55" name="U"/>
+ <map code="0x56" name="V"/>
+ <map code="0x57" name="W"/>
+ <map code="0x58" name="X"/>
+ <map code="0x59" name="Y"/>
+ <map code="0x5a" name="Z"/>
+ <map code="0x5b" name="bracketleft"/>
+ <map code="0x5c" name="backslash"/>
+ <map code="0x5d" name="bracketright"/>
+ <map code="0x5e" name="asciicircum"/>
+ <map code="0x5f" name="underscore"/>
+ <map code="0x60" name="grave"/>
+ <map code="0x61" name="a"/>
+ <map code="0x62" name="b"/>
+ <map code="0x63" name="c"/>
+ <map code="0x64" name="d"/>
+ <map code="0x65" name="e"/>
+ <map code="0x66" name="f"/>
+ <map code="0x67" name="g"/>
+ <map code="0x68" name="h"/>
+ <map code="0x69" name="i"/>
+ <map code="0x6a" name="j"/>
+ <map code="0x6b" name="k"/>
+ <map code="0x6c" name="l"/>
+ <map code="0x6d" name="m"/>
+ <map code="0x6e" name="n"/>
+ <map code="0x6f" name="o"/>
+ <map code="0x70" name="p"/>
+ <map code="0x71" name="q"/>
+ <map code="0x72" name="r"/>
+ <map code="0x73" name="s"/>
+ <map code="0x74" name="t"/>
+ <map code="0x75" name="u"/>
+ <map code="0x76" name="v"/>
+ <map code="0x77" name="w"/>
+ <map code="0x78" name="x"/>
+ <map code="0x79" name="y"/>
+ <map code="0x7a" name="z"/>
+ <map code="0x7b" name="braceleft"/>
+ <map code="0x7c" name="bar"/>
+ <map code="0x7d" name="braceright"/>
+ <map code="0x7e" name="asciitilde"/>
+ <map code="0x7f" name=".notdef"/>
+ <map code="0x80" name="Adieresis"/>
+ <map code="0x81" name="Aring"/>
+ <map code="0x82" name="Ccedilla"/>
+ <map code="0x83" name="Eacute"/>
+ <map code="0x84" name="Ntilde"/>
+ <map code="0x85" name="Odieresis"/>
+ <map code="0x86" name="Udieresis"/>
+ <map code="0x87" name="aacute"/>
+ <map code="0x88" name="agrave"/>
+ <map code="0x89" name="acircumflex"/>
+ <map code="0x8a" name="adieresis"/>
+ <map code="0x8b" name="atilde"/>
+ <map code="0x8c" name="aring"/>
+ <map code="0x8d" name="ccedilla"/>
+ <map code="0x8e" name="eacute"/>
+ <map code="0x8f" name="egrave"/>
+ <map code="0x90" name="ecircumflex"/>
+ <map code="0x91" name="edieresis"/>
+ <map code="0x92" name="iacute"/>
+ <map code="0x93" name="igrave"/>
+ <map code="0x94" name="icircumflex"/>
+ <map code="0x95" name="idieresis"/>
+ <map code="0x96" name="ntilde"/>
+ <map code="0x97" name="oacute"/>
+ <map code="0x98" name="ograve"/>
+ <map code="0x99" name="ocircumflex"/>
+ <map code="0x9a" name="odieresis"/>
+ <map code="0x9b" name="otilde"/>
+ <map code="0x9c" name="uacute"/>
+ <map code="0x9d" name="ugrave"/>
+ <map code="0x9e" name="ucircumflex"/>
+ <map code="0x9f" name="udieresis"/>
+ <map code="0xa0" name="dagger"/>
+ <map code="0xa1" name="degree"/>
+ <map code="0xa2" name="cent"/>
+ <map code="0xa3" name="sterling"/>
+ <map code="0xa4" name="section"/>
+ <map code="0xa5" name="bullet"/>
+ <map code="0xa6" name="paragraph"/>
+ <map code="0xa7" name="germandbls"/>
+ <map code="0xa8" name="registered"/>
+ <map code="0xa9" name="copyright"/>
+ <map code="0xaa" name="trademark"/>
+ <map code="0xab" name="acute"/>
+ <map code="0xac" name="dieresis"/>
+ <map code="0xad" name=".notdef"/>
+ <map code="0xae" name="AE"/>
+ <map code="0xaf" name="Oslash"/>
+ <map code="0xb0" name=".notdef"/>
+ <map code="0xb1" name="plusminus"/>
+ <map code="0xb2" name=".notdef"/>
+ <map code="0xb3" name=".notdef"/>
+ <map code="0xb4" name="yen"/>
+ <map code="0xb5" name="mu"/>
+ <map code="0xb6" name=".notdef"/>
+ <map code="0xb7" name=".notdef"/>
+ <map code="0xb8" name=".notdef"/>
+ <map code="0xb9" name=".notdef"/>
+ <map code="0xba" name=".notdef"/>
+ <map code="0xbb" name="ordfeminine"/>
+ <map code="0xbc" name="ordmasculine"/>
+ <map code="0xbd" name=".notdef"/>
+ <map code="0xbe" name="ae"/>
+ <map code="0xbf" name="oslash"/>
+ <map code="0xc0" name="questiondown"/>
+ <map code="0xc1" name="exclamdown"/>
+ <map code="0xc2" name="logicalnot"/>
+ <map code="0xc3" name=".notdef"/>
+ <map code="0xc4" name="florin"/>
+ <map code="0xc5" name=".notdef"/>
+ <map code="0xc6" name=".notdef"/>
+ <map code="0xc7" name="guillemotleft"/>
+ <map code="0xc8" name="guillemotright"/>
+ <map code="0xc9" name="ellipsis"/>
+ <map code="0xca" name=".notdef#16"/>
+ <map code="0xcb" name="Agrave"/>
+ <map code="0xcc" name="Atilde"/>
+ <map code="0xcd" name="Otilde"/>
+ <map code="0xce" name="OE"/>
+ <map code="0xcf" name="oe"/>
+ <map code="0xd0" name="endash"/>
+ <map code="0xd1" name="emdash"/>
+ <map code="0xd2" name="quotedblleft"/>
+ <map code="0xd3" name="quotedblright"/>
+ <map code="0xd4" name="quoteleft"/>
+ <map code="0xd5" name="quoteright"/>
+ <map code="0xd6" name="divide"/>
+ <map code="0xd7" name=".notdef"/>
+ <map code="0xd8" name="ydieresis"/>
+ <map code="0xd9" name="Ydieresis"/>
+ <map code="0xda" name="fraction"/>
+ <map code="0xdb" name="currency"/>
+ <map code="0xdc" name="guilsinglleft"/>
+ <map code="0xdd" name="guilsinglright"/>
+ <map code="0xde" name="fi"/>
+ <map code="0xdf" name="fl"/>
+ <map code="0xe0" name="daggerdbl"/>
+ <map code="0xe1" name="periodcentered"/>
+ <map code="0xe2" name="quotesinglbase"/>
+ <map code="0xe3" name="quotedblbase"/>
+ <map code="0xe4" name="perthousand"/>
+ <map code="0xe5" name="Acircumflex"/>
+ <map code="0xe6" name="Ecircumflex"/>
+ <map code="0xe7" name="Aacute"/>
+ <map code="0xe8" name="Edieresis"/>
+ <map code="0xe9" name="Egrave"/>
+ <map code="0xea" name="Iacute"/>
+ <map code="0xeb" name="Icircumflex"/>
+ <map code="0xec" name="Idieresis"/>
+ <map code="0xed" name="Igrave"/>
+ <map code="0xee" name="Oacute"/>
+ <map code="0xef" name="Ocircumflex"/>
+ <map code="0xf0" name="Euro"/>
+ <map code="0xf1" name="Ograve"/>
+ <map code="0xf2" name="Uacute"/>
+ <map code="0xf3" name="Ucircumflex"/>
+ <map code="0xf4" name="Ugrave"/>
+ <map code="0xf5" name="dotlessi"/>
+ <map code="0xf6" name="circumflex"/>
+ <map code="0xf7" name="tilde"/>
+ <map code="0xf8" name="macron"/>
+ <map code="0xf9" name="breve"/>
+ <map code="0xfa" name="dotaccent"/>
+ <map code="0xfb" name="ring"/>
+ <map code="0xfc" name="cedilla"/>
+ <map code="0xfd" name="hungarumlaut"/>
+ <map code="0xfe" name="ogonek"/>
+ <map code="0xff" name="caron"/>
+ </cmap_format_0>
+ <cmap_format_4 platformID="3" platEncID="1" language="0">
+ <map code="0x20" name="space"/><!-- SPACE -->
+ <map code="0x21" name="exclam"/><!-- EXCLAMATION MARK -->
+ <map code="0x22" name="quotedbl"/><!-- QUOTATION MARK -->
+ <map code="0x23" name="numbersign"/><!-- NUMBER SIGN -->
+ <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
+ <map code="0x25" name="percent"/><!-- PERCENT SIGN -->
+ <map code="0x26" name="ampersand"/><!-- AMPERSAND -->
+ <map code="0x27" name="quotesingle"/><!-- APOSTROPHE -->
+ <map code="0x28" name="parenleft"/><!-- LEFT PARENTHESIS -->
+ <map code="0x29" name="parenright"/><!-- RIGHT PARENTHESIS -->
+ <map code="0x2a" name="asterisk"/><!-- ASTERISK -->
+ <map code="0x2b" name="plus"/><!-- PLUS SIGN -->
+ <map code="0x2c" name="comma"/><!-- COMMA -->
+ <map code="0x2d" name="hyphen"/><!-- HYPHEN-MINUS -->
+ <map code="0x2e" name="period"/><!-- FULL STOP -->
+ <map code="0x2f" name="slash"/><!-- SOLIDUS -->
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
+ <map code="0x39" name="nine"/><!-- DIGIT NINE -->
+ <map code="0x3a" name="colon"/><!-- COLON -->
+ <map code="0x3b" name="semicolon"/><!-- SEMICOLON -->
+ <map code="0x3c" name="less"/><!-- LESS-THAN SIGN -->
+ <map code="0x3d" name="equal"/><!-- EQUALS SIGN -->
+ <map code="0x3e" name="greater"/><!-- GREATER-THAN SIGN -->
+ <map code="0x3f" name="question"/><!-- QUESTION MARK -->
+ <map code="0x40" name="at"/><!-- COMMERCIAL AT -->
+ <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
+ <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
+ <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
+ <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
+ <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
+ <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
+ <map code="0x47" name="G"/><!-- LATIN CAPITAL LETTER G -->
+ <map code="0x48" name="H"/><!-- LATIN CAPITAL LETTER H -->
+ <map code="0x49" name="I"/><!-- LATIN CAPITAL LETTER I -->
+ <map code="0x4a" name="J"/><!-- LATIN CAPITAL LETTER J -->
+ <map code="0x4b" name="K"/><!-- LATIN CAPITAL LETTER K -->
+ <map code="0x4c" name="L"/><!-- LATIN CAPITAL LETTER L -->
+ <map code="0x4d" name="M"/><!-- LATIN CAPITAL LETTER M -->
+ <map code="0x4e" name="N"/><!-- LATIN CAPITAL LETTER N -->
+ <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
+ <map code="0x50" name="P"/><!-- LATIN CAPITAL LETTER P -->
+ <map code="0x51" name="Q"/><!-- LATIN CAPITAL LETTER Q -->
+ <map code="0x52" name="R"/><!-- LATIN CAPITAL LETTER R -->
+ <map code="0x53" name="S"/><!-- LATIN CAPITAL LETTER S -->
+ <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
+ <map code="0x55" name="U"/><!-- LATIN CAPITAL LETTER U -->
+ <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
+ <map code="0x57" name="W"/><!-- LATIN CAPITAL LETTER W -->
+ <map code="0x58" name="X"/><!-- LATIN CAPITAL LETTER X -->
+ <map code="0x59" name="Y"/><!-- LATIN CAPITAL LETTER Y -->
+ <map code="0x5a" name="Z"/><!-- LATIN CAPITAL LETTER Z -->
+ <map code="0x5b" name="bracketleft"/><!-- LEFT SQUARE BRACKET -->
+ <map code="0x5c" name="backslash"/><!-- REVERSE SOLIDUS -->
+ <map code="0x5d" name="bracketright"/><!-- RIGHT SQUARE BRACKET -->
+ <map code="0x5e" name="asciicircum"/><!-- CIRCUMFLEX ACCENT -->
+ <map code="0x5f" name="underscore"/><!-- LOW LINE -->
+ <map code="0x60" name="grave"/><!-- GRAVE ACCENT -->
+ <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
+ <map code="0x62" name="b"/><!-- LATIN SMALL LETTER B -->
+ <map code="0x63" name="c"/><!-- LATIN SMALL LETTER C -->
+ <map code="0x64" name="d"/><!-- LATIN SMALL LETTER D -->
+ <map code="0x65" name="e"/><!-- LATIN SMALL LETTER E -->
+ <map code="0x66" name="f"/><!-- LATIN SMALL LETTER F -->
+ <map code="0x67" name="g"/><!-- LATIN SMALL LETTER G -->
+ <map code="0x68" name="h"/><!-- LATIN SMALL LETTER H -->
+ <map code="0x69" name="i"/><!-- LATIN SMALL LETTER I -->
+ <map code="0x6a" name="j"/><!-- LATIN SMALL LETTER J -->
+ <map code="0x6b" name="k"/><!-- LATIN SMALL LETTER K -->
+ <map code="0x6c" name="l"/><!-- LATIN SMALL LETTER L -->
+ <map code="0x6d" name="m"/><!-- LATIN SMALL LETTER M -->
+ <map code="0x6e" name="n"/><!-- LATIN SMALL LETTER N -->
+ <map code="0x6f" name="o"/><!-- LATIN SMALL LETTER O -->
+ <map code="0x70" name="p"/><!-- LATIN SMALL LETTER P -->
+ <map code="0x71" name="q"/><!-- LATIN SMALL LETTER Q -->
+ <map code="0x72" name="r"/><!-- LATIN SMALL LETTER R -->
+ <map code="0x73" name="s"/><!-- LATIN SMALL LETTER S -->
+ <map code="0x74" name="t"/><!-- LATIN SMALL LETTER T -->
+ <map code="0x75" name="u"/><!-- LATIN SMALL LETTER U -->
+ <map code="0x76" name="v"/><!-- LATIN SMALL LETTER V -->
+ <map code="0x77" name="w"/><!-- LATIN SMALL LETTER W -->
+ <map code="0x78" name="x"/><!-- LATIN SMALL LETTER X -->
+ <map code="0x79" name="y"/><!-- LATIN SMALL LETTER Y -->
+ <map code="0x7a" name="z"/><!-- LATIN SMALL LETTER Z -->
+ <map code="0x7b" name="braceleft"/><!-- LEFT CURLY BRACKET -->
+ <map code="0x7c" name="bar"/><!-- VERTICAL LINE -->
+ <map code="0x7d" name="braceright"/><!-- RIGHT CURLY BRACKET -->
+ <map code="0x7e" name="asciitilde"/><!-- TILDE -->
+ <map code="0x80" name="Euro#1"/><!-- &lt;control> -->
+ <map code="0xa0" name="nonbreakingspace"/><!-- NO-BREAK SPACE -->
+ <map code="0xa1" name="exclamdown"/><!-- INVERTED EXCLAMATION MARK -->
+ <map code="0xa2" name="cent"/><!-- CENT SIGN -->
+ <map code="0xa3" name="sterling"/><!-- POUND SIGN -->
+ <map code="0xa4" name="currency"/><!-- CURRENCY SIGN -->
+ <map code="0xa5" name="yen"/><!-- YEN SIGN -->
+ <map code="0xa6" name="brokenbar"/><!-- BROKEN BAR -->
+ <map code="0xa7" name="section"/><!-- SECTION SIGN -->
+ <map code="0xa8" name="dieresis"/><!-- DIAERESIS -->
+ <map code="0xa9" name="copyright"/><!-- COPYRIGHT SIGN -->
+ <map code="0xaa" name="ordfeminine"/><!-- FEMININE ORDINAL INDICATOR -->
+ <map code="0xab" name="guillemotleft"/><!-- LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <map code="0xac" name="logicalnot"/><!-- NOT SIGN -->
+ <map code="0xad" name="sfthyphen"/><!-- SOFT HYPHEN -->
+ <map code="0xae" name="registered"/><!-- REGISTERED SIGN -->
+ <map code="0xaf" name="macron#1"/><!-- MACRON -->
+ <map code="0xb0" name="degree"/><!-- DEGREE SIGN -->
+ <map code="0xb1" name="plusminus"/><!-- PLUS-MINUS SIGN -->
+ <map code="0xb2" name="twosuperior"/><!-- SUPERSCRIPT TWO -->
+ <map code="0xb3" name="threesuperior"/><!-- SUPERSCRIPT THREE -->
+ <map code="0xb4" name="acute"/><!-- ACUTE ACCENT -->
+ <map code="0xb5" name="mu"/><!-- MICRO SIGN -->
+ <map code="0xb6" name="paragraph"/><!-- PILCROW SIGN -->
+ <map code="0xb7" name="periodcentered#1"/><!-- MIDDLE DOT -->
+ <map code="0xb8" name="cedilla"/><!-- CEDILLA -->
+ <map code="0xb9" name="onesuperior"/><!-- SUPERSCRIPT ONE -->
+ <map code="0xba" name="ordmasculine"/><!-- MASCULINE ORDINAL INDICATOR -->
+ <map code="0xbb" name="guillemotright"/><!-- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <map code="0xbc" name="onequarter"/><!-- VULGAR FRACTION ONE QUARTER -->
+ <map code="0xbd" name="onehalf"/><!-- VULGAR FRACTION ONE HALF -->
+ <map code="0xbe" name="threequarters"/><!-- VULGAR FRACTION THREE QUARTERS -->
+ <map code="0xbf" name="questiondown"/><!-- INVERTED QUESTION MARK -->
+ <map code="0xc0" name="Agrave"/><!-- LATIN CAPITAL LETTER A WITH GRAVE -->
+ <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
+ <map code="0xc2" name="Acircumflex"/><!-- LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+ <map code="0xc3" name="Atilde"/><!-- LATIN CAPITAL LETTER A WITH TILDE -->
+ <map code="0xc4" name="Adieresis"/><!-- LATIN CAPITAL LETTER A WITH DIAERESIS -->
+ <map code="0xc5" name="Aring"/><!-- LATIN CAPITAL LETTER A WITH RING ABOVE -->
+ <map code="0xc6" name="AE"/><!-- LATIN CAPITAL LETTER AE -->
+ <map code="0xc7" name="Ccedilla"/><!-- LATIN CAPITAL LETTER C WITH CEDILLA -->
+ <map code="0xc8" name="Egrave"/><!-- LATIN CAPITAL LETTER E WITH GRAVE -->
+ <map code="0xc9" name="Eacute"/><!-- LATIN CAPITAL LETTER E WITH ACUTE -->
+ <map code="0xca" name="Ecircumflex"/><!-- LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+ <map code="0xcb" name="Edieresis"/><!-- LATIN CAPITAL LETTER E WITH DIAERESIS -->
+ <map code="0xcc" name="Igrave"/><!-- LATIN CAPITAL LETTER I WITH GRAVE -->
+ <map code="0xcd" name="Iacute"/><!-- LATIN CAPITAL LETTER I WITH ACUTE -->
+ <map code="0xce" name="Icircumflex"/><!-- LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+ <map code="0xcf" name="Idieresis"/><!-- LATIN CAPITAL LETTER I WITH DIAERESIS -->
+ <map code="0xd0" name="Eth"/><!-- LATIN CAPITAL LETTER ETH -->
+ <map code="0xd1" name="Ntilde"/><!-- LATIN CAPITAL LETTER N WITH TILDE -->
+ <map code="0xd2" name="Ograve"/><!-- LATIN CAPITAL LETTER O WITH GRAVE -->
+ <map code="0xd3" name="Oacute"/><!-- LATIN CAPITAL LETTER O WITH ACUTE -->
+ <map code="0xd4" name="Ocircumflex"/><!-- LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+ <map code="0xd5" name="Otilde"/><!-- LATIN CAPITAL LETTER O WITH TILDE -->
+ <map code="0xd6" name="Odieresis"/><!-- LATIN CAPITAL LETTER O WITH DIAERESIS -->
+ <map code="0xd7" name="multiply"/><!-- MULTIPLICATION SIGN -->
+ <map code="0xd8" name="Oslash"/><!-- LATIN CAPITAL LETTER O WITH STROKE -->
+ <map code="0xd9" name="Ugrave"/><!-- LATIN CAPITAL LETTER U WITH GRAVE -->
+ <map code="0xda" name="Uacute"/><!-- LATIN CAPITAL LETTER U WITH ACUTE -->
+ <map code="0xdb" name="Ucircumflex"/><!-- LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+ <map code="0xdc" name="Udieresis"/><!-- LATIN CAPITAL LETTER U WITH DIAERESIS -->
+ <map code="0xdd" name="Yacute"/><!-- LATIN CAPITAL LETTER Y WITH ACUTE -->
+ <map code="0xde" name="Thorn"/><!-- LATIN CAPITAL LETTER THORN -->
+ <map code="0xdf" name="germandbls"/><!-- LATIN SMALL LETTER SHARP S -->
+ <map code="0xe0" name="agrave"/><!-- LATIN SMALL LETTER A WITH GRAVE -->
+ <map code="0xe1" name="aacute"/><!-- LATIN SMALL LETTER A WITH ACUTE -->
+ <map code="0xe2" name="acircumflex"/><!-- LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+ <map code="0xe3" name="atilde"/><!-- LATIN SMALL LETTER A WITH TILDE -->
+ <map code="0xe4" name="adieresis"/><!-- LATIN SMALL LETTER A WITH DIAERESIS -->
+ <map code="0xe5" name="aring"/><!-- LATIN SMALL LETTER A WITH RING ABOVE -->
+ <map code="0xe6" name="ae"/><!-- LATIN SMALL LETTER AE -->
+ <map code="0xe7" name="ccedilla"/><!-- LATIN SMALL LETTER C WITH CEDILLA -->
+ <map code="0xe8" name="egrave"/><!-- LATIN SMALL LETTER E WITH GRAVE -->
+ <map code="0xe9" name="eacute"/><!-- LATIN SMALL LETTER E WITH ACUTE -->
+ <map code="0xea" name="ecircumflex"/><!-- LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+ <map code="0xeb" name="edieresis"/><!-- LATIN SMALL LETTER E WITH DIAERESIS -->
+ <map code="0xec" name="igrave"/><!-- LATIN SMALL LETTER I WITH GRAVE -->
+ <map code="0xed" name="iacute"/><!-- LATIN SMALL LETTER I WITH ACUTE -->
+ <map code="0xee" name="icircumflex"/><!-- LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+ <map code="0xef" name="idieresis"/><!-- LATIN SMALL LETTER I WITH DIAERESIS -->
+ <map code="0xf0" name="eth"/><!-- LATIN SMALL LETTER ETH -->
+ <map code="0xf1" name="ntilde"/><!-- LATIN SMALL LETTER N WITH TILDE -->
+ <map code="0xf2" name="ograve"/><!-- LATIN SMALL LETTER O WITH GRAVE -->
+ <map code="0xf3" name="oacute"/><!-- LATIN SMALL LETTER O WITH ACUTE -->
+ <map code="0xf4" name="ocircumflex"/><!-- LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+ <map code="0xf5" name="otilde"/><!-- LATIN SMALL LETTER O WITH TILDE -->
+ <map code="0xf6" name="odieresis"/><!-- LATIN SMALL LETTER O WITH DIAERESIS -->
+ <map code="0xf7" name="divide"/><!-- DIVISION SIGN -->
+ <map code="0xf8" name="oslash"/><!-- LATIN SMALL LETTER O WITH STROKE -->
+ <map code="0xf9" name="ugrave"/><!-- LATIN SMALL LETTER U WITH GRAVE -->
+ <map code="0xfa" name="uacute"/><!-- LATIN SMALL LETTER U WITH ACUTE -->
+ <map code="0xfb" name="ucircumflex"/><!-- LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+ <map code="0xfc" name="udieresis"/><!-- LATIN SMALL LETTER U WITH DIAERESIS -->
+ <map code="0xfd" name="yacute"/><!-- LATIN SMALL LETTER Y WITH ACUTE -->
+ <map code="0xfe" name="thorn"/><!-- LATIN SMALL LETTER THORN -->
+ <map code="0xff" name="ydieresis"/><!-- LATIN SMALL LETTER Y WITH DIAERESIS -->
+ <map code="0x100" name="Amacron"/><!-- LATIN CAPITAL LETTER A WITH MACRON -->
+ <map code="0x101" name="amacron"/><!-- LATIN SMALL LETTER A WITH MACRON -->
+ <map code="0x102" name="Abreve"/><!-- LATIN CAPITAL LETTER A WITH BREVE -->
+ <map code="0x103" name="abreve"/><!-- LATIN SMALL LETTER A WITH BREVE -->
+ <map code="0x104" name="Aogonek"/><!-- LATIN CAPITAL LETTER A WITH OGONEK -->
+ <map code="0x105" name="aogonek"/><!-- LATIN SMALL LETTER A WITH OGONEK -->
+ <map code="0x106" name="Cacute"/><!-- LATIN CAPITAL LETTER C WITH ACUTE -->
+ <map code="0x107" name="cacute"/><!-- LATIN SMALL LETTER C WITH ACUTE -->
+ <map code="0x108" name="Ccircumflex"/><!-- LATIN CAPITAL LETTER C WITH CIRCUMFLEX -->
+ <map code="0x109" name="ccircumflex"/><!-- LATIN SMALL LETTER C WITH CIRCUMFLEX -->
+ <map code="0x10a" name="Cdotaccent"/><!-- LATIN CAPITAL LETTER C WITH DOT ABOVE -->
+ <map code="0x10b" name="cdotaccent"/><!-- LATIN SMALL LETTER C WITH DOT ABOVE -->
+ <map code="0x10c" name="Ccaron"/><!-- LATIN CAPITAL LETTER C WITH CARON -->
+ <map code="0x10d" name="ccaron"/><!-- LATIN SMALL LETTER C WITH CARON -->
+ <map code="0x10e" name="Dcaron"/><!-- LATIN CAPITAL LETTER D WITH CARON -->
+ <map code="0x10f" name="dcaron"/><!-- LATIN SMALL LETTER D WITH CARON -->
+ <map code="0x110" name="Dcroat"/><!-- LATIN CAPITAL LETTER D WITH STROKE -->
+ <map code="0x111" name="dcroat"/><!-- LATIN SMALL LETTER D WITH STROKE -->
+ <map code="0x112" name="Emacron"/><!-- LATIN CAPITAL LETTER E WITH MACRON -->
+ <map code="0x113" name="emacron"/><!-- LATIN SMALL LETTER E WITH MACRON -->
+ <map code="0x114" name="Ebreve"/><!-- LATIN CAPITAL LETTER E WITH BREVE -->
+ <map code="0x115" name="ebreve"/><!-- LATIN SMALL LETTER E WITH BREVE -->
+ <map code="0x116" name="Edotaccent"/><!-- LATIN CAPITAL LETTER E WITH DOT ABOVE -->
+ <map code="0x117" name="edotaccent"/><!-- LATIN SMALL LETTER E WITH DOT ABOVE -->
+ <map code="0x118" name="Eogonek"/><!-- LATIN CAPITAL LETTER E WITH OGONEK -->
+ <map code="0x119" name="eogonek"/><!-- LATIN SMALL LETTER E WITH OGONEK -->
+ <map code="0x11a" name="Ecaron"/><!-- LATIN CAPITAL LETTER E WITH CARON -->
+ <map code="0x11b" name="ecaron"/><!-- LATIN SMALL LETTER E WITH CARON -->
+ <map code="0x11c" name="Gcircumflex"/><!-- LATIN CAPITAL LETTER G WITH CIRCUMFLEX -->
+ <map code="0x11d" name="gcircumflex"/><!-- LATIN SMALL LETTER G WITH CIRCUMFLEX -->
+ <map code="0x11e" name="Gbreve"/><!-- LATIN CAPITAL LETTER G WITH BREVE -->
+ <map code="0x11f" name="gbreve"/><!-- LATIN SMALL LETTER G WITH BREVE -->
+ <map code="0x120" name="Gdotaccent"/><!-- LATIN CAPITAL LETTER G WITH DOT ABOVE -->
+ <map code="0x121" name="gdotaccent"/><!-- LATIN SMALL LETTER G WITH DOT ABOVE -->
+ <map code="0x122" name="Gcommaaccent"/><!-- LATIN CAPITAL LETTER G WITH CEDILLA -->
+ <map code="0x123" name="gcommaaccent"/><!-- LATIN SMALL LETTER G WITH CEDILLA -->
+ <map code="0x124" name="Hcircumflex"/><!-- LATIN CAPITAL LETTER H WITH CIRCUMFLEX -->
+ <map code="0x125" name="hcircumflex"/><!-- LATIN SMALL LETTER H WITH CIRCUMFLEX -->
+ <map code="0x126" name="Hbar"/><!-- LATIN CAPITAL LETTER H WITH STROKE -->
+ <map code="0x127" name="hbar"/><!-- LATIN SMALL LETTER H WITH STROKE -->
+ <map code="0x128" name="Itilde"/><!-- LATIN CAPITAL LETTER I WITH TILDE -->
+ <map code="0x129" name="itilde"/><!-- LATIN SMALL LETTER I WITH TILDE -->
+ <map code="0x12a" name="Imacron"/><!-- LATIN CAPITAL LETTER I WITH MACRON -->
+ <map code="0x12b" name="imacron"/><!-- LATIN SMALL LETTER I WITH MACRON -->
+ <map code="0x12c" name="Ibreve"/><!-- LATIN CAPITAL LETTER I WITH BREVE -->
+ <map code="0x12d" name="ibreve"/><!-- LATIN SMALL LETTER I WITH BREVE -->
+ <map code="0x12e" name="Iogonek"/><!-- LATIN CAPITAL LETTER I WITH OGONEK -->
+ <map code="0x12f" name="iogonek"/><!-- LATIN SMALL LETTER I WITH OGONEK -->
+ <map code="0x130" name="Idotaccent"/><!-- LATIN CAPITAL LETTER I WITH DOT ABOVE -->
+ <map code="0x131" name="dotlessi"/><!-- LATIN SMALL LETTER DOTLESS I -->
+ <map code="0x132" name="IJ"/><!-- LATIN CAPITAL LIGATURE IJ -->
+ <map code="0x133" name="ij"/><!-- LATIN SMALL LIGATURE IJ -->
+ <map code="0x134" name="Jcircumflex"/><!-- LATIN CAPITAL LETTER J WITH CIRCUMFLEX -->
+ <map code="0x135" name="jcircumflex"/><!-- LATIN SMALL LETTER J WITH CIRCUMFLEX -->
+ <map code="0x136" name="Kcommaaccent"/><!-- LATIN CAPITAL LETTER K WITH CEDILLA -->
+ <map code="0x137" name="kcommaaccent"/><!-- LATIN SMALL LETTER K WITH CEDILLA -->
+ <map code="0x138" name="kgreenlandic"/><!-- LATIN SMALL LETTER KRA -->
+ <map code="0x139" name="Lacute"/><!-- LATIN CAPITAL LETTER L WITH ACUTE -->
+ <map code="0x13a" name="lacute"/><!-- LATIN SMALL LETTER L WITH ACUTE -->
+ <map code="0x13b" name="Lcommaaccent"/><!-- LATIN CAPITAL LETTER L WITH CEDILLA -->
+ <map code="0x13c" name="lcommaaccent"/><!-- LATIN SMALL LETTER L WITH CEDILLA -->
+ <map code="0x13d" name="Lcaron"/><!-- LATIN CAPITAL LETTER L WITH CARON -->
+ <map code="0x13e" name="lcaron"/><!-- LATIN SMALL LETTER L WITH CARON -->
+ <map code="0x13f" name="Ldot"/><!-- LATIN CAPITAL LETTER L WITH MIDDLE DOT -->
+ <map code="0x140" name="ldot"/><!-- LATIN SMALL LETTER L WITH MIDDLE DOT -->
+ <map code="0x141" name="Lslash"/><!-- LATIN CAPITAL LETTER L WITH STROKE -->
+ <map code="0x142" name="lslash"/><!-- LATIN SMALL LETTER L WITH STROKE -->
+ <map code="0x143" name="Nacute"/><!-- LATIN CAPITAL LETTER N WITH ACUTE -->
+ <map code="0x144" name="nacute"/><!-- LATIN SMALL LETTER N WITH ACUTE -->
+ <map code="0x145" name="Ncommaaccent"/><!-- LATIN CAPITAL LETTER N WITH CEDILLA -->
+ <map code="0x146" name="ncommaaccent"/><!-- LATIN SMALL LETTER N WITH CEDILLA -->
+ <map code="0x147" name="Ncaron"/><!-- LATIN CAPITAL LETTER N WITH CARON -->
+ <map code="0x148" name="ncaron"/><!-- LATIN SMALL LETTER N WITH CARON -->
+ <map code="0x149" name="napostrophe"/><!-- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE -->
+ <map code="0x14a" name="Eng"/><!-- LATIN CAPITAL LETTER ENG -->
+ <map code="0x14b" name="eng"/><!-- LATIN SMALL LETTER ENG -->
+ <map code="0x14c" name="Omacron"/><!-- LATIN CAPITAL LETTER O WITH MACRON -->
+ <map code="0x14d" name="omacron"/><!-- LATIN SMALL LETTER O WITH MACRON -->
+ <map code="0x14e" name="Obreve"/><!-- LATIN CAPITAL LETTER O WITH BREVE -->
+ <map code="0x14f" name="obreve"/><!-- LATIN SMALL LETTER O WITH BREVE -->
+ <map code="0x150" name="Ohungarumlaut"/><!-- LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -->
+ <map code="0x151" name="ohungarumlaut"/><!-- LATIN SMALL LETTER O WITH DOUBLE ACUTE -->
+ <map code="0x152" name="OE"/><!-- LATIN CAPITAL LIGATURE OE -->
+ <map code="0x153" name="oe"/><!-- LATIN SMALL LIGATURE OE -->
+ <map code="0x154" name="Racute"/><!-- LATIN CAPITAL LETTER R WITH ACUTE -->
+ <map code="0x155" name="racute"/><!-- LATIN SMALL LETTER R WITH ACUTE -->
+ <map code="0x156" name="Rcommaaccent"/><!-- LATIN CAPITAL LETTER R WITH CEDILLA -->
+ <map code="0x157" name="rcommaaccent"/><!-- LATIN SMALL LETTER R WITH CEDILLA -->
+ <map code="0x158" name="Rcaron"/><!-- LATIN CAPITAL LETTER R WITH CARON -->
+ <map code="0x159" name="rcaron"/><!-- LATIN SMALL LETTER R WITH CARON -->
+ <map code="0x15a" name="Sacute"/><!-- LATIN CAPITAL LETTER S WITH ACUTE -->
+ <map code="0x15b" name="sacute"/><!-- LATIN SMALL LETTER S WITH ACUTE -->
+ <map code="0x15c" name="Scircumflex"/><!-- LATIN CAPITAL LETTER S WITH CIRCUMFLEX -->
+ <map code="0x15d" name="scircumflex"/><!-- LATIN SMALL LETTER S WITH CIRCUMFLEX -->
+ <map code="0x15e" name="Scedilla"/><!-- LATIN CAPITAL LETTER S WITH CEDILLA -->
+ <map code="0x15f" name="scedilla"/><!-- LATIN SMALL LETTER S WITH CEDILLA -->
+ <map code="0x160" name="Scaron"/><!-- LATIN CAPITAL LETTER S WITH CARON -->
+ <map code="0x161" name="scaron"/><!-- LATIN SMALL LETTER S WITH CARON -->
+ <map code="0x162" name="Tcommaaccent"/><!-- LATIN CAPITAL LETTER T WITH CEDILLA -->
+ <map code="0x163" name="tcommaaccent"/><!-- LATIN SMALL LETTER T WITH CEDILLA -->
+ <map code="0x164" name="Tcaron"/><!-- LATIN CAPITAL LETTER T WITH CARON -->
+ <map code="0x165" name="tcaron"/><!-- LATIN SMALL LETTER T WITH CARON -->
+ <map code="0x166" name="Tbar"/><!-- LATIN CAPITAL LETTER T WITH STROKE -->
+ <map code="0x167" name="tbar"/><!-- LATIN SMALL LETTER T WITH STROKE -->
+ <map code="0x168" name="Utilde"/><!-- LATIN CAPITAL LETTER U WITH TILDE -->
+ <map code="0x169" name="utilde"/><!-- LATIN SMALL LETTER U WITH TILDE -->
+ <map code="0x16a" name="Umacron"/><!-- LATIN CAPITAL LETTER U WITH MACRON -->
+ <map code="0x16b" name="umacron"/><!-- LATIN SMALL LETTER U WITH MACRON -->
+ <map code="0x16c" name="Ubreve"/><!-- LATIN CAPITAL LETTER U WITH BREVE -->
+ <map code="0x16d" name="ubreve"/><!-- LATIN SMALL LETTER U WITH BREVE -->
+ <map code="0x16e" name="Uring"/><!-- LATIN CAPITAL LETTER U WITH RING ABOVE -->
+ <map code="0x16f" name="uring"/><!-- LATIN SMALL LETTER U WITH RING ABOVE -->
+ <map code="0x170" name="Uhungarumlaut"/><!-- LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -->
+ <map code="0x171" name="uhungarumlaut"/><!-- LATIN SMALL LETTER U WITH DOUBLE ACUTE -->
+ <map code="0x172" name="Uogonek"/><!-- LATIN CAPITAL LETTER U WITH OGONEK -->
+ <map code="0x173" name="uogonek"/><!-- LATIN SMALL LETTER U WITH OGONEK -->
+ <map code="0x174" name="Wcircumflex"/><!-- LATIN CAPITAL LETTER W WITH CIRCUMFLEX -->
+ <map code="0x175" name="wcircumflex"/><!-- LATIN SMALL LETTER W WITH CIRCUMFLEX -->
+ <map code="0x176" name="Ycircumflex"/><!-- LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -->
+ <map code="0x177" name="ycircumflex"/><!-- LATIN SMALL LETTER Y WITH CIRCUMFLEX -->
+ <map code="0x178" name="Ydieresis"/><!-- LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+ <map code="0x179" name="Zacute"/><!-- LATIN CAPITAL LETTER Z WITH ACUTE -->
+ <map code="0x17a" name="zacute"/><!-- LATIN SMALL LETTER Z WITH ACUTE -->
+ <map code="0x17b" name="Zdotaccent"/><!-- LATIN CAPITAL LETTER Z WITH DOT ABOVE -->
+ <map code="0x17c" name="zdotaccent"/><!-- LATIN SMALL LETTER Z WITH DOT ABOVE -->
+ <map code="0x17d" name="Zcaron"/><!-- LATIN CAPITAL LETTER Z WITH CARON -->
+ <map code="0x17e" name="zcaron"/><!-- LATIN SMALL LETTER Z WITH CARON -->
+ <map code="0x17f" name="longs"/><!-- LATIN SMALL LETTER LONG S -->
+ <map code="0x192" name="florin"/><!-- LATIN SMALL LETTER F WITH HOOK -->
+ <map code="0x218" name="Scommaaccent"/><!-- LATIN CAPITAL LETTER S WITH COMMA BELOW -->
+ <map code="0x219" name="scommaaccent"/><!-- LATIN SMALL LETTER S WITH COMMA BELOW -->
+ <map code="0x21a" name="Tcommabelow"/><!-- LATIN CAPITAL LETTER T WITH COMMA BELOW -->
+ <map code="0x21b" name="tcommabelow"/><!-- LATIN SMALL LETTER T WITH COMMA BELOW -->
+ <map code="0x2c6" name="circumflex"/><!-- MODIFIER LETTER CIRCUMFLEX ACCENT -->
+ <map code="0x2c7" name="caron"/><!-- CARON -->
+ <map code="0x2c9" name="macron"/><!-- MODIFIER LETTER MACRON -->
+ <map code="0x2d8" name="breve"/><!-- BREVE -->
+ <map code="0x2d9" name="dotaccent"/><!-- DOT ABOVE -->
+ <map code="0x2da" name="ring"/><!-- RING ABOVE -->
+ <map code="0x2db" name="ogonek"/><!-- OGONEK -->
+ <map code="0x2dc" name="tilde"/><!-- SMALL TILDE -->
+ <map code="0x2dd" name="hungarumlaut"/><!-- DOUBLE ACUTE ACCENT -->
+ <map code="0x326" name="Unterkomma"/><!-- COMBINING COMMA BELOW -->
+ <map code="0x37e" name="semicolon#1"/><!-- GREEK QUESTION MARK -->
+ <map code="0x387" name="anoteleia"/><!-- GREEK ANO TELEIA -->
+ <map code="0x2010" name="hyphen#1"/><!-- HYPHEN -->
+ <map code="0x2011" name="nbhyphen"/><!-- NON-BREAKING HYPHEN -->
+ <map code="0x2012" name="figuredash"/><!-- FIGURE DASH -->
+ <map code="0x2013" name="endash"/><!-- EN DASH -->
+ <map code="0x2014" name="emdash"/><!-- EM DASH -->
+ <map code="0x2015" name="afii00208"/><!-- HORIZONTAL BAR -->
+ <map code="0x2018" name="quoteleft"/><!-- LEFT SINGLE QUOTATION MARK -->
+ <map code="0x2019" name="quoteright"/><!-- RIGHT SINGLE QUOTATION MARK -->
+ <map code="0x201a" name="quotesinglbase"/><!-- SINGLE LOW-9 QUOTATION MARK -->
+ <map code="0x201b" name="quotereversed"/><!-- SINGLE HIGH-REVERSED-9 QUOTATION MARK -->
+ <map code="0x201c" name="quotedblleft"/><!-- LEFT DOUBLE QUOTATION MARK -->
+ <map code="0x201d" name="quotedblright"/><!-- RIGHT DOUBLE QUOTATION MARK -->
+ <map code="0x201e" name="quotedblbase"/><!-- DOUBLE LOW-9 QUOTATION MARK -->
+ <map code="0x2020" name="dagger"/><!-- DAGGER -->
+ <map code="0x2021" name="daggerdbl"/><!-- DOUBLE DAGGER -->
+ <map code="0x2022" name="bullet"/><!-- BULLET -->
+ <map code="0x2026" name="ellipsis"/><!-- HORIZONTAL ELLIPSIS -->
+ <map code="0x2030" name="perthousand"/><!-- PER MILLE SIGN -->
+ <map code="0x2039" name="guilsinglleft"/><!-- SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+ <map code="0x203a" name="guilsinglright"/><!-- SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+ <map code="0x203e" name="radicalex"/><!-- OVERLINE -->
+ <map code="0x2044" name="fraction"/><!-- FRACTION SLASH -->
+ <map code="0x20ac" name="Euro"/><!-- EURO SIGN -->
+ <map code="0x2122" name="trademark"/><!-- TRADE MARK SIGN -->
+ <map code="0x212e" name="estimated"/><!-- ESTIMATED SYMBOL -->
+ <map code="0x2212" name="minus"/><!-- MINUS SIGN -->
+ <map code="0x2215" name="fraction#1"/><!-- DIVISION SLASH -->
+ <map code="0x2219" name="periodcentered"/><!-- BULLET OPERATOR -->
+ <map code="0x22c5" name="dotmath"/><!-- DOT OPERATOR -->
+ <map code="0xea01" name="fi#1"/><!-- Private Use -->
+ <map code="0xea02" name="fl#1"/><!-- Private Use -->
+ <map code="0xf001" name="fi"/><!-- Private Use -->
+ <map code="0xf002" name="fl"/><!-- Private Use -->
+ <map code="0xf004" name="foursuperiour"/><!-- Private Use -->
+ <map code="0xf6be" name="dotlessj"/><!-- Private Use -->
+ <map code="0xfb01" name="fi"/><!-- LATIN SMALL LIGATURE FI -->
+ <map code="0xfb02" name="fl"/><!-- LATIN SMALL LIGATURE FL -->
+ </cmap_format_4>
+ </cmap>
+
+ <fpgm>
+ <assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ FDEF[ ]
+ SLOOP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP1[ ]
+ SRP2[ ]
+ IP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP1[ ]
+ SRP2[ ]
+ SLOOP[ ]
+ IP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MIRP[11101]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MIRP[10100]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MDRP[11101]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MDRP[10100]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MIRP[11101]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MIRP[10100]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MDRP[11101]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MDRP[10100]
+ ENDF[ ]
+ FDEF[ ]
+ MDRP[00100]
+ ENDF[ ]
+ FDEF[ ]
+ MDRP[00000]
+ ENDF[ ]
+ FDEF[ ]
+ SVTCA[0]
+ NPUSHB[ ] /* 10 values pushed */
+ 1 0 0 1 1 2 2 3 3 0
+ SZPS[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SZPS[ ]
+ ENDF[ ]
+ </assembly>
+ </fpgm>
+
+ <prep>
+ <assembly>
+ PUSHB[ ] /* 2 values pushed */
+ 48 1
+ PUSHW[ ] /* 1 value pushed */
+ 329
+ RTG[ ]
+ SCANCTRL[ ]
+ SCANTYPE[ ]
+ SCVTCI[ ]
+ </assembly>
+ </prep>
+
+ <cvt>
+ <cv index="0" value="1480"/>
+ <cv index="1" value="1086"/>
+ <cv index="2" value="0"/>
+ <cv index="3" value="-512"/>
+ <cv index="4" value="196"/>
+ <cv index="5" value="200"/>
+ <cv index="6" value="247"/>
+ <cv index="7" value="84"/>
+ <cv index="8" value="87"/>
+ <cv index="9" value="101"/>
+ <cv index="10" value="212"/>
+ <cv index="11" value="63"/>
+ <cv index="12" value="125"/>
+ <cv index="13" value="172"/>
+ <cv index="14" value="65"/>
+ <cv index="15" value="114"/>
+ <cv index="16" value="183"/>
+ <cv index="17" value="70"/>
+ <cv index="18" value="171"/>
+ <cv index="19" value="149"/>
+ <cv index="20" value="140"/>
+ <cv index="21" value="77"/>
+ <cv index="22" value="121"/>
+ <cv index="23" value="138"/>
+ <cv index="24" value="159"/>
+ <cv index="25" value="53"/>
+ <cv index="26" value="165"/>
+ <cv index="27" value="285"/>
+ <cv index="28" value="186"/>
+ <cv index="29" value="128"/>
+ <cv index="30" value="193"/>
+ <cv index="31" value="145"/>
+ <cv index="32" value="210"/>
+ <cv index="33" value="220"/>
+ <cv index="34" value="230"/>
+ <cv index="35" value="94"/>
+ <cv index="36" value="227"/>
+ <cv index="37" value="213"/>
+ <cv index="38" value="68"/>
+ <cv index="39" value="131"/>
+ <cv index="40" value="217"/>
+ <cv index="41" value="104"/>
+ <cv index="42" value="80"/>
+ <cv index="43" value="108"/>
+ <cv index="44" value="126"/>
+ <cv index="45" value="39"/>
+ <cv index="46" value="90"/>
+ <cv index="47" value="147"/>
+ <cv index="48" value="135"/>
+ </cvt>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef" xMin="51" yMin="0" xMax="461" yMax="1480">
+ <contour>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="461" y="1480" on="1"/>
+ <pt x="461" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="410" y="51" on="1"/>
+ <pt x="410" y="1429" on="1"/>
+ <pt x="102" y="1429" on="1"/>
+ <pt x="102" y="51" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 16 values pushed */
+ 5 6 2 1 4 7 3 0 5 4 2 3 6 7 1 0
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ SVTCA[0]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name=".notdef#1"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#10"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#11"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#12"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#13"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#14"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#15"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#16"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#17"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#18"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#2"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#3"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#4"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#5"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#6"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#7"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#8"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#9"/><!-- contains no outline data -->
+
+ <TTGlyph name="A" xMin="0" yMin="0" xMax="1479" yMax="1499">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 61 values pushed */
+ 33 32 18 17 14 10 7 1 8 23 0 3 37 9 8 3 13 35 0 0 24 23 7 1 35
+ 1 4 48 84 36 35 1 34 16 15 0 3 2 0 14 37 36 35 34 33 32 30 24 23 20
+ 18 17 16 15 14 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="AE" xMin="0" yMin="0" xMax="1771" yMax="1480">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="17" y="63" on="1"/>
+ <pt x="78" y="68" on="0"/>
+ <pt x="128" y="151" on="1"/>
+ <pt x="194" y="258" on="1"/>
+ <pt x="938" y="1480" on="1"/>
+ <pt x="1716" y="1480" on="1"/>
+ <pt x="1716" y="1221" on="1"/>
+ <pt x="1605" y="1221" on="1"/>
+ <pt x="1604" y="1240" on="1"/>
+ <pt x="1598" y="1324" on="1"/>
+ <pt x="1597" y="1380" on="0"/>
+ <pt x="1580" y="1390" on="1"/>
+ <pt x="1563" y="1399" on="0"/>
+ <pt x="1525" y="1399" on="1"/>
+ <pt x="1422" y="1400" on="1"/>
+ <pt x="1151" y="1400" on="1"/>
+ <pt x="1151" y="808" on="1"/>
+ <pt x="1379" y="808" on="1"/>
+ <pt x="1442" y="811" on="1"/>
+ <pt x="1490" y="812" on="0"/>
+ <pt x="1500" y="823" on="1"/>
+ <pt x="1507" y="833" on="0"/>
+ <pt x="1510" y="859" on="1"/>
+ <pt x="1511" y="866" on="1"/>
+ <pt x="1510" y="873" on="1"/>
+ <pt x="1512" y="878" on="0"/>
+ <pt x="1512" y="883" on="1"/>
+ <pt x="1512" y="897" on="1"/>
+ <pt x="1513" y="913" on="1"/>
+ <pt x="1515" y="931" on="1"/>
+ <pt x="1607" y="931" on="1"/>
+ <pt x="1607" y="605" on="1"/>
+ <pt x="1515" y="605" on="1"/>
+ <pt x="1513" y="623" on="1"/>
+ <pt x="1506" y="708" on="0"/>
+ <pt x="1482" y="717" on="1"/>
+ <pt x="1457" y="728" on="0"/>
+ <pt x="1379" y="728" on="1"/>
+ <pt x="1151" y="728" on="1"/>
+ <pt x="1151" y="259" on="1"/>
+ <pt x="1152" y="123" on="0"/>
+ <pt x="1191" y="105" on="1"/>
+ <pt x="1227" y="86" on="0"/>
+ <pt x="1321" y="86" on="1"/>
+ <pt x="1427" y="86" on="1"/>
+ <pt x="1568" y="92" on="1"/>
+ <pt x="1651" y="93" on="0"/>
+ <pt x="1656" y="162" on="1"/>
+ <pt x="1659" y="253" on="1"/>
+ <pt x="1660" y="271" on="1"/>
+ <pt x="1771" y="271" on="1"/>
+ <pt x="1771" y="0" on="1"/>
+ <pt x="756" y="0" on="1"/>
+ <pt x="756" y="62" on="1"/>
+ <pt x="774" y="63" on="1"/>
+ <pt x="842" y="68" on="1"/>
+ <pt x="910" y="73" on="0"/>
+ <pt x="921" y="95" on="1"/>
+ <pt x="932" y="115" on="0"/>
+ <pt x="935" y="160" on="1"/>
+ <pt x="941" y="259" on="1"/>
+ <pt x="941" y="456" on="1"/>
+ <pt x="403" y="456" on="1"/>
+ <pt x="281" y="258" on="1"/>
+ <pt x="255" y="215" on="0"/>
+ <pt x="235" y="179" on="1"/>
+ <pt x="229" y="167" on="1"/>
+ <pt x="219" y="150" on="0"/>
+ <pt x="212" y="138" on="1"/>
+ <pt x="205" y="125" on="1"/>
+ <pt x="204" y="122" on="0"/>
+ <pt x="202" y="120" on="1"/>
+ <pt x="192" y="105" on="0"/>
+ <pt x="192" y="91" on="1"/>
+ <pt x="192" y="65" on="0"/>
+ <pt x="265" y="65" on="1"/>
+ <pt x="269" y="65" on="1"/>
+ <pt x="274" y="65" on="0"/>
+ <pt x="288" y="64" on="1"/>
+ <pt x="306" y="64" on="1"/>
+ <pt x="328" y="63" on="1"/>
+ <pt x="351" y="62" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="455" y="537" on="1"/>
+ <pt x="941" y="537" on="1"/>
+ <pt x="941" y="1338" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 147 values pushed */
+ 87 32 31 29 28 11 9 8 8 16 18 3 34 33 2 39 85 3 83 81 80 78 77 62 55
+ 52 51 49 47 46 45 41 1 15 63 0 3 0 0 17 16 21 1 6 40 39 21 1 18 64
+ 63 7 1 85 3 4 48 84 19 18 1 86 85 1 84 54 53 0 3 3 0 7 6 0 14
+ 51 49 2 7 32 3 26 25 47 46 45 39 34 31 29 28 26 25 19 16 11 9 14 32 17
+ 3 85 84 83 81 80 78 77 64 55 54 6 1 0 13 13 75 62 0 0 87 86 63 62 32
+ 3 17 1 4 48 196 53 52 1 8 7 1 33 32 1 41 40 18 17 3 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aacute" xMin="0" yMin="0" xMax="1479" yMax="1925">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="613" y="1604" on="1"/>
+ <pt x="854" y="1925" on="1"/>
+ <pt x="1113" y="1925" on="1"/>
+ <pt x="706" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 41 38 37 9 8 5 39 35 3 33 32 18 17 14 10 7 1 8 23 0 3 0 0 24 23
+ 7 1 35 1 4 48 84 40 39 1 36 35 1 34 16 15 0 3 3 0 14 41 40 39 38
+ 37 36 35 34 33 32 30 24 23 20 18 17 16 15 14 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Abreve" xMin="0" yMin="0" xMax="1479" yMax="1925">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="408" y="1925" on="1"/>
+ <pt x="473" y="1925" on="1"/>
+ <pt x="500" y="1835" on="0"/>
+ <pt x="560" y="1793" on="1"/>
+ <pt x="628" y="1746" on="0"/>
+ <pt x="741" y="1746" on="1"/>
+ <pt x="867" y="1746" on="0"/>
+ <pt x="937" y="1805" on="1"/>
+ <pt x="985" y="1845" on="0"/>
+ <pt x="1010" y="1925" on="1"/>
+ <pt x="1074" y="1925" on="1"/>
+ <pt x="1055" y="1790" on="0"/>
+ <pt x="983" y="1709" on="1"/>
+ <pt x="889" y="1604" on="0"/>
+ <pt x="741" y="1604" on="1"/>
+ <pt x="587" y="1604" on="0"/>
+ <pt x="492" y="1719" on="1"/>
+ <pt x="427" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 43 20 52 48 84 33 32 18 17 14 10 7 1 8 23 0 3 48 47 39 38 37 9
+ 8 7 13 52 35 0 0 24 23 7 1 35 1 4 48 84 36 35 1 34 16 15 0 3 2
+ 0 14 48 47 39 38 37 36 35 34 33 32 30 24 23 20 18 17 16 15 14 10 9 8 7
+ 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Acircumflex" xMin="0" yMin="0" xMax="1479" yMax="1925">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="389" y="1604" on="1"/>
+ <pt x="630" y="1925" on="1"/>
+ <pt x="852" y="1925" on="1"/>
+ <pt x="1092" y="1604" on="1"/>
+ <pt x="1006" y="1604" on="1"/>
+ <pt x="741" y="1826" on="1"/>
+ <pt x="475" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 44 43 42 41 38 37 9 8 8 39 35 3 33 32 18 17 14 10 7 1 8 23 0 3 0
+ 0 24 23 7 1 35 1 4 48 84 40 39 1 36 35 1 34 16 15 0 3 3 0 14 44
+ 43 42 41 40 39 38 37 36 35 34 33 32 30 24 23 20 18 17 16 15 14 10 9 8 7
+ 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Adieresis" xMin="0" yMin="0" xMax="1479" yMax="1777">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="457" y="1604" on="1"/>
+ <pt x="457" y="1777" on="1"/>
+ <pt x="630" y="1777" on="1"/>
+ <pt x="630" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="852" y="1604" on="1"/>
+ <pt x="852" y="1777" on="1"/>
+ <pt x="1025" y="1777" on="1"/>
+ <pt x="1025" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 112 values pushed */
+ 37 9 8 3 38 35 3 33 32 18 17 14 10 7 1 8 23 0 3 0 0 45 42 41 38
+ 13 3 39 24 23 7 1 35 2 4 48 84 44 43 40 39 3 36 35 1 34 16 15 0 3
+ 3 0 14 36 23 18 17 16 5 44 42 3 37 9 8 3 42 40 3 15 14 10 3 13 20
+ 44 35 34 33 32 24 7 1 0 8 13 30 38 0 0 43 42 13 1 44 41 40 13 1 38
+ 2 4 48 196 45 44 1 39 38 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Agrave" xMin="0" yMin="0" xMax="1479" yMax="1925">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="874" y="1604" on="1"/>
+ <pt x="781" y="1604" on="1"/>
+ <pt x="374" y="1925" on="1"/>
+ <pt x="633" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 39 38 37 9 8 5 40 35 3 33 32 18 17 14 10 7 1 8 23 0 3 0 0 24 23
+ 7 1 35 1 4 48 84 41 40 1 36 35 1 34 16 15 0 3 3 0 14 41 40 39 38
+ 37 36 35 34 33 32 30 24 23 20 18 17 16 15 14 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Amacron" xMin="0" yMin="0" xMax="1479" yMax="1727">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="420" y="1604" on="1"/>
+ <pt x="420" y="1727" on="1"/>
+ <pt x="1062" y="1727" on="1"/>
+ <pt x="1062" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 37 9 8 3 38 35 3 33 32 18 17 14 10 7 1 8 23 0 3 0 0 41 38 12 1
+ 39 24 23 7 1 35 2 4 48 84 40 39 1 36 35 1 34 16 15 0 3 3 0 14 41
+ 40 39 38 37 36 35 34 33 32 30 24 23 20 18 17 16 15 14 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aogonek" xMin="0" yMin="-370" xMax="1479" yMax="1499">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1454" y="-273" on="1"/>
+ <pt x="1454" y="-341" on="1"/>
+ <pt x="1383" y="-370" on="0"/>
+ <pt x="1305" y="-370" on="1"/>
+ <pt x="1085" y="-370" on="0"/>
+ <pt x="1085" y="-211" on="1"/>
+ <pt x="1085" y="-90" on="0"/>
+ <pt x="1243" y="0" on="1"/>
+ <pt x="1350" y="0" on="1"/>
+ <pt x="1221" y="-81" on="0"/>
+ <pt x="1221" y="-182" on="1"/>
+ <pt x="1221" y="-289" on="0"/>
+ <pt x="1354" y="-289" on="1"/>
+ <pt x="1405" y="-289" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 50 7 41 48 84 33 32 18 17 14 10 7 1 8 23 0 3 37 9 8 3 13 35
+ 39 38 41 0 0 0 24 23 7 1 35 1 4 48 84 36 35 1 46 45 34 16 15 0 5
+ 2 0 14 0 0 48 48 43 48 196 46 45 43 39 38 37 36 35 34 33 32 30 24 23 20
+ 18 17 16 15 14 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aring" xMin="0" yMin="0" xMax="1479" yMax="1934">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="741" y="1934" on="1"/>
+ <pt x="835" y="1934" on="0"/>
+ <pt x="901" y="1868" on="1"/>
+ <pt x="968" y="1802" on="0"/>
+ <pt x="968" y="1708" on="1"/>
+ <pt x="968" y="1612" on="0"/>
+ <pt x="901" y="1546" on="1"/>
+ <pt x="835" y="1480" on="0"/>
+ <pt x="739" y="1480" on="1"/>
+ <pt x="656" y="1480" on="0"/>
+ <pt x="594" y="1534" on="1"/>
+ <pt x="514" y="1603" on="0"/>
+ <pt x="514" y="1707" on="1"/>
+ <pt x="514" y="1802" on="0"/>
+ <pt x="580" y="1868" on="1"/>
+ <pt x="646" y="1934" on="0"/>
+ </contour>
+ <contour>
+ <pt x="741" y="1866" on="1"/>
+ <pt x="675" y="1866" on="0"/>
+ <pt x="628" y="1819" on="1"/>
+ <pt x="582" y="1773" on="0"/>
+ <pt x="582" y="1708" on="1"/>
+ <pt x="582" y="1642" on="0"/>
+ <pt x="628" y="1595" on="1"/>
+ <pt x="674" y="1548" on="0"/>
+ <pt x="739" y="1548" on="1"/>
+ <pt x="800" y="1548" on="0"/>
+ <pt x="844" y="1585" on="1"/>
+ <pt x="900" y="1633" on="0"/>
+ <pt x="900" y="1708" on="1"/>
+ <pt x="900" y="1774" on="0"/>
+ <pt x="853" y="1820" on="1"/>
+ <pt x="806" y="1866" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 93 values pushed */
+ 0 0 62 17 46 54 17 38 48 84 46 0 1 37 0 35 2 0 33 32 18 17 14 10 7
+ 1 8 23 0 3 1 9 8 2 13 38 0 0 0 0 24 23 7 1 35 1 4 48 84 36
+ 35 1 34 16 15 0 3 2 0 14 0 0 66 17 42 58 17 50 48 196 50 42 37 36 35
+ 34 33 32 30 24 23 20 18 17 16 15 14 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Atilde" xMin="0" yMin="0" xMax="1479" yMax="1839">
+ <contour>
+ <pt x="0" y="0" on="1"/>
+ <pt x="0" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="67" on="0"/>
+ <pt x="102" y="87" on="1"/>
+ <pt x="117" y="103" on="0"/>
+ <pt x="139" y="154" on="1"/>
+ <pt x="185" y="259" on="1"/>
+ <pt x="706" y="1499" on="1"/>
+ <pt x="776" y="1499" on="1"/>
+ <pt x="1295" y="252" on="1"/>
+ <pt x="1345" y="149" on="1"/>
+ <pt x="1385" y="67" on="0"/>
+ <pt x="1457" y="63" on="1"/>
+ <pt x="1479" y="62" on="1"/>
+ <pt x="1479" y="0" on="1"/>
+ <pt x="990" y="0" on="1"/>
+ <pt x="990" y="62" on="1"/>
+ <pt x="1008" y="62" on="1"/>
+ <pt x="1111" y="62" on="0"/>
+ <pt x="1111" y="106" on="1"/>
+ <pt x="1111" y="160" on="0"/>
+ <pt x="1069" y="259" on="1"/>
+ <pt x="986" y="456" on="1"/>
+ <pt x="352" y="456" on="1"/>
+ <pt x="267" y="259" on="1"/>
+ <pt x="250" y="220" on="0"/>
+ <pt x="245" y="205" on="1"/>
+ <pt x="223" y="135" on="1"/>
+ <pt x="217" y="116" on="0"/>
+ <pt x="217" y="102" on="1"/>
+ <pt x="217" y="62" on="0"/>
+ <pt x="309" y="62" on="1"/>
+ <pt x="325" y="62" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="385" y="537" on="1"/>
+ <pt x="950" y="537" on="1"/>
+ <pt x="669" y="1211" on="1"/>
+ </contour>
+ <contour>
+ <pt x="408" y="1604" on="1"/>
+ <pt x="435" y="1744" on="0"/>
+ <pt x="504" y="1797" on="1"/>
+ <pt x="558" y="1839" on="0"/>
+ <pt x="635" y="1839" on="1"/>
+ <pt x="700" y="1839" on="0"/>
+ <pt x="753" y="1801" on="1"/>
+ <pt x="788" y="1776" on="1"/>
+ <pt x="840" y="1739" on="0"/>
+ <pt x="894" y="1739" on="1"/>
+ <pt x="989" y="1739" on="0"/>
+ <pt x="1012" y="1838" on="1"/>
+ <pt x="1074" y="1838" on="1"/>
+ <pt x="1046" y="1699" on="0"/>
+ <pt x="978" y="1646" on="1"/>
+ <pt x="924" y="1604" on="0"/>
+ <pt x="847" y="1604" on="1"/>
+ <pt x="784" y="1604" on="0"/>
+ <pt x="729" y="1642" on="1"/>
+ <pt x="694" y="1666" on="1"/>
+ <pt x="639" y="1704" on="0"/>
+ <pt x="588" y="1704" on="1"/>
+ <pt x="499" y="1704" on="0"/>
+ <pt x="470" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 59 20 42 47 20 54 48 84 33 32 18 17 14 10 7 1 8 23 0 3 61 50 49
+ 38 37 9 8 7 13 54 42 35 0 0 24 23 7 1 35 1 4 48 84 36 35 1 34 16
+ 15 0 3 2 0 14 61 50 49 38 37 36 35 34 33 32 30 24 23 20 18 17 16 15 14
+ 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="B" xMin="47" yMin="0" xMax="1245" yMax="1480">
+ <contour>
+ <pt x="788" y="767" on="1"/>
+ <pt x="968" y="742" on="0"/>
+ <pt x="1066" y="687" on="1"/>
+ <pt x="1245" y="586" on="0"/>
+ <pt x="1245" y="371" on="1"/>
+ <pt x="1245" y="202" on="0"/>
+ <pt x="1130" y="103" on="1"/>
+ <pt x="1010" y="0" on="0"/>
+ <pt x="676" y="0" on="1"/>
+ <pt x="47" y="0" on="1"/>
+ <pt x="47" y="62" on="1"/>
+ <pt x="66" y="63" on="1"/>
+ <pt x="133" y="68" on="1"/>
+ <pt x="209" y="74" on="0"/>
+ <pt x="219" y="115" on="1"/>
+ <pt x="232" y="177" on="0"/>
+ <pt x="232" y="259" on="1"/>
+ <pt x="232" y="1221" on="1"/>
+ <pt x="232" y="1280" on="0"/>
+ <pt x="225" y="1333" on="1"/>
+ <pt x="219" y="1372" on="0"/>
+ <pt x="211" y="1384" on="1"/>
+ <pt x="193" y="1410" on="0"/>
+ <pt x="133" y="1413" on="1"/>
+ <pt x="66" y="1417" on="1"/>
+ <pt x="47" y="1419" on="1"/>
+ <pt x="47" y="1480" on="1"/>
+ <pt x="705" y="1480" on="1"/>
+ <pt x="932" y="1480" on="0"/>
+ <pt x="1016" y="1437" on="1"/>
+ <pt x="1184" y="1351" on="0"/>
+ <pt x="1184" y="1150" on="1"/>
+ <pt x="1184" y="995" on="0"/>
+ <pt x="1091" y="899" on="1"/>
+ <pt x="1025" y="830" on="0"/>
+ <pt x="913" y="795" on="1"/>
+ <pt x="872" y="782" on="0"/>
+ </contour>
+ <contour>
+ <pt x="439" y="734" on="1"/>
+ <pt x="439" y="259" on="1"/>
+ <pt x="442" y="172" on="1"/>
+ <pt x="445" y="97" on="0"/>
+ <pt x="493" y="82" on="1"/>
+ <pt x="537" y="68" on="0"/>
+ <pt x="637" y="68" on="1"/>
+ <pt x="1026" y="68" on="0"/>
+ <pt x="1026" y="368" on="1"/>
+ <pt x="1026" y="591" on="0"/>
+ <pt x="857" y="670" on="1"/>
+ <pt x="726" y="731" on="0"/>
+ </contour>
+ <contour>
+ <pt x="439" y="802" on="1"/>
+ <pt x="550" y="802" on="1"/>
+ <pt x="775" y="802" on="0"/>
+ <pt x="871" y="877" on="1"/>
+ <pt x="968" y="952" on="0"/>
+ <pt x="968" y="1129" on="1"/>
+ <pt x="968" y="1312" on="0"/>
+ <pt x="853" y="1367" on="1"/>
+ <pt x="757" y="1413" on="0"/>
+ <pt x="539" y="1413" on="1"/>
+ <pt x="439" y="1413" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 17 26 16 9 43 59 58 50 49 43 38 37 0 8 26 8 3 9 8 1 0 27 26 0 14
+ 0 0 54 10 31 45 33 4 48 196 26 17 9 16 58 50 27 8 0 5 13 31 4 37 0
+ 0 59 49 38 37 32 3 16 1 4 48 196 17 16 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="C" xMin="80" yMin="-37" xMax="1269" yMax="1517">
+ <contour>
+ <pt x="1269" y="79" on="1"/>
+ <pt x="1060" y="-37" on="0"/>
+ <pt x="809" y="-37" on="1"/>
+ <pt x="472" y="-37" on="0"/>
+ <pt x="276" y="173" on="1"/>
+ <pt x="80" y="383" on="0"/>
+ <pt x="80" y="745" on="1"/>
+ <pt x="80" y="1105" on="0"/>
+ <pt x="268" y="1311" on="1"/>
+ <pt x="455" y="1517" on="0"/>
+ <pt x="789" y="1517" on="1"/>
+ <pt x="996" y="1517" on="0"/>
+ <pt x="1244" y="1443" on="1"/>
+ <pt x="1244" y="1160" on="1"/>
+ <pt x="1120" y="1160" on="1"/>
+ <pt x="1119" y="1180" on="1"/>
+ <pt x="1119" y="1185" on="0"/>
+ <pt x="1118" y="1212" on="1"/>
+ <pt x="1118" y="1223" on="1"/>
+ <pt x="1118" y="1233" on="1"/>
+ <pt x="1118" y="1239" on="1"/>
+ <pt x="1118" y="1326" on="0"/>
+ <pt x="1049" y="1381" on="1"/>
+ <pt x="963" y="1450" on="0"/>
+ <pt x="806" y="1450" on="1"/>
+ <pt x="573" y="1450" on="0"/>
+ <pt x="440" y="1261" on="1"/>
+ <pt x="308" y="1073" on="0"/>
+ <pt x="308" y="750" on="1"/>
+ <pt x="308" y="425" on="0"/>
+ <pt x="462" y="243" on="1"/>
+ <pt x="615" y="62" on="0"/>
+ <pt x="880" y="62" on="1"/>
+ <pt x="1057" y="62" on="0"/>
+ <pt x="1269" y="175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 0 0 32 9 2 24 17 10 48 84 10 0 2 2 1 1 34 20 19 18 17 14 13 12 0
+ 9 0 2 3 0 0 14 0 0 28 34 6 48 196 34 0 2 13 12 20 19 18 17 14 5
+ 13 6 12 13 12 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Cacute" xMin="80" yMin="-37" xMax="1269" yMax="1925">
+ <contour>
+ <pt x="1269" y="79" on="1"/>
+ <pt x="1060" y="-37" on="0"/>
+ <pt x="809" y="-37" on="1"/>
+ <pt x="472" y="-37" on="0"/>
+ <pt x="276" y="173" on="1"/>
+ <pt x="80" y="383" on="0"/>
+ <pt x="80" y="745" on="1"/>
+ <pt x="80" y="1105" on="0"/>
+ <pt x="268" y="1311" on="1"/>
+ <pt x="455" y="1517" on="0"/>
+ <pt x="789" y="1517" on="1"/>
+ <pt x="996" y="1517" on="0"/>
+ <pt x="1244" y="1443" on="1"/>
+ <pt x="1244" y="1160" on="1"/>
+ <pt x="1120" y="1160" on="1"/>
+ <pt x="1119" y="1180" on="1"/>
+ <pt x="1119" y="1185" on="0"/>
+ <pt x="1118" y="1212" on="1"/>
+ <pt x="1118" y="1223" on="1"/>
+ <pt x="1118" y="1233" on="1"/>
+ <pt x="1118" y="1239" on="1"/>
+ <pt x="1118" y="1326" on="0"/>
+ <pt x="1049" y="1381" on="1"/>
+ <pt x="963" y="1450" on="0"/>
+ <pt x="806" y="1450" on="1"/>
+ <pt x="573" y="1450" on="0"/>
+ <pt x="440" y="1261" on="1"/>
+ <pt x="308" y="1073" on="0"/>
+ <pt x="308" y="750" on="1"/>
+ <pt x="308" y="425" on="0"/>
+ <pt x="462" y="243" on="1"/>
+ <pt x="615" y="62" on="0"/>
+ <pt x="880" y="62" on="1"/>
+ <pt x="1057" y="62" on="0"/>
+ <pt x="1269" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="703" y="1604" on="1"/>
+ <pt x="944" y="1925" on="1"/>
+ <pt x="1203" y="1925" on="1"/>
+ <pt x="796" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 0 0 32 9 2 24 17 10 48 84 10 0 2 2 1 38 35 2 36 0 3 0 1 1 34
+ 20 19 18 17 14 13 12 0 9 0 2 3 0 0 37 36 1 0 14 0 0 28 34 6 48
+ 196 34 0 2 13 12 38 37 36 35 20 19 18 17 14 9 13 6 12 13 12 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccaron" xMin="80" yMin="-37" xMax="1269" yMax="1925">
+ <contour>
+ <pt x="1269" y="79" on="1"/>
+ <pt x="1060" y="-37" on="0"/>
+ <pt x="809" y="-37" on="1"/>
+ <pt x="472" y="-37" on="0"/>
+ <pt x="276" y="173" on="1"/>
+ <pt x="80" y="383" on="0"/>
+ <pt x="80" y="745" on="1"/>
+ <pt x="80" y="1105" on="0"/>
+ <pt x="268" y="1311" on="1"/>
+ <pt x="455" y="1517" on="0"/>
+ <pt x="789" y="1517" on="1"/>
+ <pt x="996" y="1517" on="0"/>
+ <pt x="1244" y="1443" on="1"/>
+ <pt x="1244" y="1160" on="1"/>
+ <pt x="1120" y="1160" on="1"/>
+ <pt x="1119" y="1180" on="1"/>
+ <pt x="1119" y="1185" on="0"/>
+ <pt x="1118" y="1212" on="1"/>
+ <pt x="1118" y="1223" on="1"/>
+ <pt x="1118" y="1233" on="1"/>
+ <pt x="1118" y="1239" on="1"/>
+ <pt x="1118" y="1326" on="0"/>
+ <pt x="1049" y="1381" on="1"/>
+ <pt x="963" y="1450" on="0"/>
+ <pt x="806" y="1450" on="1"/>
+ <pt x="573" y="1450" on="0"/>
+ <pt x="440" y="1261" on="1"/>
+ <pt x="308" y="1073" on="0"/>
+ <pt x="308" y="750" on="1"/>
+ <pt x="308" y="425" on="0"/>
+ <pt x="462" y="243" on="1"/>
+ <pt x="615" y="62" on="0"/>
+ <pt x="880" y="62" on="1"/>
+ <pt x="1057" y="62" on="0"/>
+ <pt x="1269" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1146" y="1925" on="1"/>
+ <pt x="906" y="1604" on="1"/>
+ <pt x="684" y="1604" on="1"/>
+ <pt x="443" y="1925" on="1"/>
+ <pt x="529" y="1925" on="1"/>
+ <pt x="795" y="1703" on="1"/>
+ <pt x="1060" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 0 0 32 9 2 24 17 10 48 84 10 0 2 2 1 1 34 20 19 18 17 14 13 12 0
+ 9 0 2 3 0 0 41 40 39 38 35 5 13 36 37 36 1 0 14 0 0 28 34 6 48
+ 196 34 0 2 13 12 41 40 39 38 37 36 35 20 19 18 17 14 12 13 6 12 13 12 1
+ 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccedilla" xMin="80" yMin="-432" xMax="1269" yMax="1517">
+ <contour>
+ <pt x="1269" y="79" on="1"/>
+ <pt x="1058" y="-37" on="0"/>
+ <pt x="809" y="-37" on="1"/>
+ <pt x="472" y="-37" on="0"/>
+ <pt x="276" y="173" on="1"/>
+ <pt x="80" y="383" on="0"/>
+ <pt x="80" y="745" on="1"/>
+ <pt x="80" y="1105" on="0"/>
+ <pt x="268" y="1311" on="1"/>
+ <pt x="455" y="1517" on="0"/>
+ <pt x="789" y="1517" on="1"/>
+ <pt x="996" y="1517" on="0"/>
+ <pt x="1244" y="1443" on="1"/>
+ <pt x="1244" y="1160" on="1"/>
+ <pt x="1120" y="1160" on="1"/>
+ <pt x="1119" y="1180" on="1"/>
+ <pt x="1119" y="1185" on="0"/>
+ <pt x="1118" y="1212" on="1"/>
+ <pt x="1118" y="1223" on="1"/>
+ <pt x="1118" y="1233" on="1"/>
+ <pt x="1118" y="1239" on="1"/>
+ <pt x="1118" y="1326" on="0"/>
+ <pt x="1049" y="1381" on="1"/>
+ <pt x="963" y="1450" on="0"/>
+ <pt x="806" y="1450" on="1"/>
+ <pt x="572" y="1450" on="0"/>
+ <pt x="440" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="750" on="1"/>
+ <pt x="308" y="425" on="0"/>
+ <pt x="462" y="243" on="1"/>
+ <pt x="615" y="62" on="0"/>
+ <pt x="880" y="62" on="1"/>
+ <pt x="1057" y="62" on="0"/>
+ <pt x="1269" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="619" y="-411" on="1"/>
+ <pt x="619" y="-343" on="1"/>
+ <pt x="681" y="-359" on="0"/>
+ <pt x="720" y="-359" on="1"/>
+ <pt x="827" y="-359" on="0"/>
+ <pt x="827" y="-277" on="1"/>
+ <pt x="827" y="-179" on="0"/>
+ <pt x="640" y="-175" on="1"/>
+ <pt x="735" y="0" on="1"/>
+ <pt x="814" y="0" on="1"/>
+ <pt x="748" y="-119" on="1"/>
+ <pt x="965" y="-138" on="0"/>
+ <pt x="965" y="-266" on="1"/>
+ <pt x="965" y="-336" on="0"/>
+ <pt x="907" y="-384" on="1"/>
+ <pt x="850" y="-432" on="0"/>
+ <pt x="763" y="-432" on="1"/>
+ <pt x="695" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 38 17 51 32 9 2 24 17 10 48 84 10 0 2 2 1 1 34 20 19 18 17 14
+ 13 12 0 9 0 2 3 0 0 1 45 44 43 42 36 35 6 13 51 2 0 14 0 0 40
+ 48 47 28 34 6 48 196 34 0 2 13 12 45 44 43 42 36 35 20 19 18 17 14 11 13
+ 47 6 12 13 12 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccircumflex" xMin="80" yMin="-37" xMax="1269" yMax="1925">
+ <contour>
+ <pt x="1269" y="79" on="1"/>
+ <pt x="1060" y="-37" on="0"/>
+ <pt x="809" y="-37" on="1"/>
+ <pt x="472" y="-37" on="0"/>
+ <pt x="276" y="173" on="1"/>
+ <pt x="80" y="383" on="0"/>
+ <pt x="80" y="745" on="1"/>
+ <pt x="80" y="1105" on="0"/>
+ <pt x="268" y="1311" on="1"/>
+ <pt x="455" y="1517" on="0"/>
+ <pt x="789" y="1517" on="1"/>
+ <pt x="996" y="1517" on="0"/>
+ <pt x="1244" y="1443" on="1"/>
+ <pt x="1244" y="1160" on="1"/>
+ <pt x="1120" y="1160" on="1"/>
+ <pt x="1119" y="1180" on="1"/>
+ <pt x="1119" y="1185" on="0"/>
+ <pt x="1118" y="1212" on="1"/>
+ <pt x="1118" y="1223" on="1"/>
+ <pt x="1118" y="1233" on="1"/>
+ <pt x="1118" y="1239" on="1"/>
+ <pt x="1118" y="1326" on="0"/>
+ <pt x="1049" y="1381" on="1"/>
+ <pt x="963" y="1450" on="0"/>
+ <pt x="806" y="1450" on="1"/>
+ <pt x="573" y="1450" on="0"/>
+ <pt x="440" y="1261" on="1"/>
+ <pt x="308" y="1073" on="0"/>
+ <pt x="308" y="750" on="1"/>
+ <pt x="308" y="425" on="0"/>
+ <pt x="462" y="243" on="1"/>
+ <pt x="615" y="62" on="0"/>
+ <pt x="880" y="62" on="1"/>
+ <pt x="1057" y="62" on="0"/>
+ <pt x="1269" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="443" y="1604" on="1"/>
+ <pt x="684" y="1925" on="1"/>
+ <pt x="906" y="1925" on="1"/>
+ <pt x="1146" y="1604" on="1"/>
+ <pt x="1060" y="1604" on="1"/>
+ <pt x="795" y="1826" on="1"/>
+ <pt x="529" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 0 0 32 9 2 24 17 10 48 84 10 0 2 2 1 41 40 39 38 35 5 36 0 3 0
+ 1 1 34 20 19 18 17 14 13 12 0 9 0 2 3 0 0 37 36 1 0 14 0 0 28
+ 34 6 48 196 34 0 2 13 12 41 40 39 38 37 36 35 20 19 18 17 14 12 13 6 12
+ 13 12 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Cdotaccent" xMin="80" yMin="-37" xMax="1269" yMax="1801">
+ <contour>
+ <pt x="1269" y="79" on="1"/>
+ <pt x="1060" y="-37" on="0"/>
+ <pt x="809" y="-37" on="1"/>
+ <pt x="472" y="-37" on="0"/>
+ <pt x="276" y="173" on="1"/>
+ <pt x="80" y="383" on="0"/>
+ <pt x="80" y="745" on="1"/>
+ <pt x="80" y="1105" on="0"/>
+ <pt x="268" y="1311" on="1"/>
+ <pt x="455" y="1517" on="0"/>
+ <pt x="789" y="1517" on="1"/>
+ <pt x="996" y="1517" on="0"/>
+ <pt x="1244" y="1443" on="1"/>
+ <pt x="1244" y="1160" on="1"/>
+ <pt x="1120" y="1160" on="1"/>
+ <pt x="1119" y="1180" on="1"/>
+ <pt x="1119" y="1185" on="0"/>
+ <pt x="1118" y="1212" on="1"/>
+ <pt x="1118" y="1223" on="1"/>
+ <pt x="1118" y="1233" on="1"/>
+ <pt x="1118" y="1239" on="1"/>
+ <pt x="1118" y="1326" on="0"/>
+ <pt x="1049" y="1381" on="1"/>
+ <pt x="963" y="1450" on="0"/>
+ <pt x="806" y="1450" on="1"/>
+ <pt x="573" y="1450" on="0"/>
+ <pt x="440" y="1261" on="1"/>
+ <pt x="308" y="1073" on="0"/>
+ <pt x="308" y="750" on="1"/>
+ <pt x="308" y="425" on="0"/>
+ <pt x="462" y="243" on="1"/>
+ <pt x="615" y="62" on="0"/>
+ <pt x="880" y="62" on="1"/>
+ <pt x="1057" y="62" on="0"/>
+ <pt x="1269" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="696" y="1604" on="1"/>
+ <pt x="696" y="1801" on="1"/>
+ <pt x="893" y="1801" on="1"/>
+ <pt x="893" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 0 0 32 9 2 24 17 10 48 84 10 0 2 2 1 1 34 20 19 18 17 14 13 12 0
+ 9 0 2 3 0 0 0 0 38 35 5 1 36 1 4 48 84 37 36 1 0 14 0 0 28
+ 34 6 48 196 20 19 18 17 14 5 12 37 3 34 0 2 13 12 6 35 0 0 36 35 4
+ 1 37 1 4 48 196 38 37 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="D" xMin="41" yMin="0" xMax="1399" yMax="1489">
+ <contour>
+ <pt x="465" y="1480" on="1"/>
+ <pt x="536" y="1481" on="1"/>
+ <pt x="608" y="1484" on="1"/>
+ <pt x="680" y="1485" on="1"/>
+ <pt x="989" y="1489" on="0"/>
+ <pt x="1176" y="1335" on="1"/>
+ <pt x="1399" y="1152" on="0"/>
+ <pt x="1399" y="772" on="1"/>
+ <pt x="1399" y="414" on="0"/>
+ <pt x="1208" y="207" on="1"/>
+ <pt x="1017" y="0" on="0"/>
+ <pt x="687" y="0" on="1"/>
+ <pt x="41" y="0" on="1"/>
+ <pt x="41" y="62" on="1"/>
+ <pt x="60" y="63" on="1"/>
+ <pt x="127" y="68" on="1"/>
+ <pt x="203" y="74" on="0"/>
+ <pt x="213" y="115" on="1"/>
+ <pt x="226" y="177" on="0"/>
+ <pt x="226" y="259" on="1"/>
+ <pt x="226" y="1221" on="1"/>
+ <pt x="226" y="1280" on="0"/>
+ <pt x="219" y="1333" on="1"/>
+ <pt x="213" y="1372" on="0"/>
+ <pt x="205" y="1384" on="1"/>
+ <pt x="187" y="1410" on="0"/>
+ <pt x="127" y="1413" on="1"/>
+ <pt x="60" y="1417" on="1"/>
+ <pt x="41" y="1419" on="1"/>
+ <pt x="41" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="436" y="1413" on="1"/>
+ <pt x="436" y="259" on="1"/>
+ <pt x="440" y="181" on="1"/>
+ <pt x="444" y="110" on="0"/>
+ <pt x="498" y="87" on="1"/>
+ <pt x="544" y="68" on="0"/>
+ <pt x="638" y="68" on="1"/>
+ <pt x="894" y="68" on="0"/>
+ <pt x="1032" y="243" on="1"/>
+ <pt x="1171" y="419" on="0"/>
+ <pt x="1171" y="743" on="1"/>
+ <pt x="1171" y="1098" on="0"/>
+ <pt x="1021" y="1256" on="1"/>
+ <pt x="871" y="1413" on="0"/>
+ <pt x="532" y="1413" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 20 29 19 12 36 44 36 31 30 4 0 11 3 12 11 1 0 29 0 0 14 0 0 40 34
+ 7 48 196 29 20 12 19 44 11 0 3 13 7 30 0 0 31 30 32 1 19 1 4 48 196
+ 20 19 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Dcaron" xMin="41" yMin="0" xMax="1399" yMax="1925">
+ <contour>
+ <pt x="465" y="1480" on="1"/>
+ <pt x="536" y="1481" on="1"/>
+ <pt x="608" y="1484" on="1"/>
+ <pt x="680" y="1485" on="1"/>
+ <pt x="989" y="1489" on="0"/>
+ <pt x="1176" y="1335" on="1"/>
+ <pt x="1399" y="1152" on="0"/>
+ <pt x="1399" y="772" on="1"/>
+ <pt x="1399" y="414" on="0"/>
+ <pt x="1208" y="207" on="1"/>
+ <pt x="1017" y="0" on="0"/>
+ <pt x="687" y="0" on="1"/>
+ <pt x="41" y="0" on="1"/>
+ <pt x="41" y="62" on="1"/>
+ <pt x="60" y="63" on="1"/>
+ <pt x="127" y="68" on="1"/>
+ <pt x="203" y="74" on="0"/>
+ <pt x="213" y="115" on="1"/>
+ <pt x="226" y="177" on="0"/>
+ <pt x="226" y="259" on="1"/>
+ <pt x="226" y="1221" on="1"/>
+ <pt x="226" y="1280" on="0"/>
+ <pt x="219" y="1333" on="1"/>
+ <pt x="213" y="1372" on="0"/>
+ <pt x="205" y="1384" on="1"/>
+ <pt x="187" y="1410" on="0"/>
+ <pt x="127" y="1413" on="1"/>
+ <pt x="60" y="1417" on="1"/>
+ <pt x="41" y="1419" on="1"/>
+ <pt x="41" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="436" y="1413" on="1"/>
+ <pt x="436" y="259" on="1"/>
+ <pt x="440" y="181" on="1"/>
+ <pt x="444" y="110" on="0"/>
+ <pt x="498" y="87" on="1"/>
+ <pt x="544" y="68" on="0"/>
+ <pt x="638" y="68" on="1"/>
+ <pt x="894" y="68" on="0"/>
+ <pt x="1032" y="243" on="1"/>
+ <pt x="1171" y="419" on="0"/>
+ <pt x="1171" y="743" on="1"/>
+ <pt x="1171" y="1098" on="0"/>
+ <pt x="1021" y="1256" on="1"/>
+ <pt x="871" y="1413" on="0"/>
+ <pt x="532" y="1413" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1046" y="1925" on="1"/>
+ <pt x="806" y="1604" on="1"/>
+ <pt x="584" y="1604" on="1"/>
+ <pt x="343" y="1925" on="1"/>
+ <pt x="429" y="1925" on="1"/>
+ <pt x="695" y="1703" on="1"/>
+ <pt x="960" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 20 29 19 12 36 44 36 31 30 4 0 11 3 51 50 49 48 45 5 13 46 47 46 1 12
+ 11 1 2 0 29 0 0 14 0 0 40 34 7 48 196 29 20 12 19 49 48 2 30 19 3
+ 51 50 47 46 45 44 11 0 8 13 7 30 0 0 31 30 32 1 19 1 4 48 196 20 19
+ 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Dcroat" xMin="41" yMin="0" xMax="1399" yMax="1489">
+ <contour>
+ <pt x="226" y="716" on="1"/>
+ <pt x="41" y="716" on="1"/>
+ <pt x="41" y="783" on="1"/>
+ <pt x="226" y="783" on="1"/>
+ <pt x="226" y="1221" on="1"/>
+ <pt x="226" y="1280" on="0"/>
+ <pt x="219" y="1333" on="1"/>
+ <pt x="213" y="1372" on="0"/>
+ <pt x="205" y="1384" on="1"/>
+ <pt x="187" y="1410" on="0"/>
+ <pt x="127" y="1413" on="1"/>
+ <pt x="60" y="1417" on="1"/>
+ <pt x="41" y="1419" on="1"/>
+ <pt x="41" y="1480" on="1"/>
+ <pt x="465" y="1480" on="1"/>
+ <pt x="536" y="1481" on="1"/>
+ <pt x="608" y="1484" on="1"/>
+ <pt x="680" y="1485" on="1"/>
+ <pt x="989" y="1489" on="0"/>
+ <pt x="1176" y="1335" on="1"/>
+ <pt x="1399" y="1151" on="0"/>
+ <pt x="1399" y="772" on="1"/>
+ <pt x="1399" y="414" on="0"/>
+ <pt x="1208" y="207" on="1"/>
+ <pt x="1017" y="0" on="0"/>
+ <pt x="687" y="0" on="1"/>
+ <pt x="41" y="0" on="1"/>
+ <pt x="41" y="62" on="1"/>
+ <pt x="60" y="63" on="1"/>
+ <pt x="127" y="68" on="1"/>
+ <pt x="203" y="74" on="0"/>
+ <pt x="213" y="115" on="1"/>
+ <pt x="226" y="177" on="0"/>
+ <pt x="226" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="436" y="716" on="1"/>
+ <pt x="436" y="259" on="1"/>
+ <pt x="440" y="181" on="1"/>
+ <pt x="444" y="110" on="0"/>
+ <pt x="498" y="87" on="1"/>
+ <pt x="544" y="68" on="0"/>
+ <pt x="638" y="68" on="1"/>
+ <pt x="894" y="68" on="0"/>
+ <pt x="1032" y="243" on="1"/>
+ <pt x="1171" y="419" on="0"/>
+ <pt x="1171" y="743" on="1"/>
+ <pt x="1171" y="1098" on="0"/>
+ <pt x="1021" y="1256" on="1"/>
+ <pt x="871" y="1413" on="0"/>
+ <pt x="532" y="1413" on="1"/>
+ <pt x="436" y="1413" on="1"/>
+ <pt x="436" y="783" on="1"/>
+ <pt x="781" y="783" on="1"/>
+ <pt x="781" y="716" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 33 26 4 13 49 48 2 13 2 3 40 40 35 2 0 25 3 0 0 52 34 1 0 14 3
+ 2 1 4 48 84 51 50 3 2 3 26 25 1 2 0 14 13 0 14 0 0 44 34 21 48
+ 196 26 33 13 4 52 51 48 25 14 5 13 21 34 2 1 0 0 0 50 49 35 34 32 3
+ 0 1 4 48 196 33 4 3 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="E" xMin="43" yMin="0" xMax="1202" yMax="1480">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 101 values pushed */
+ 52 61 51 44 21 20 12 11 2 1 6 9 28 3 42 41 30 26 23 22 6 28 34 3 0
+ 0 10 9 21 1 0 35 34 7 1 43 2 4 48 84 29 28 1 44 43 1 2 0 61 0
+ 0 14 61 52 44 51 41 2 2 0 21 3 35 34 28 26 23 20 12 9 8 21 10 3 0
+ 0 30 29 11 10 32 3 51 1 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1 4
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eacute" xMin="43" yMin="0" xMax="1202" yMax="1925">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="413" y="1604" on="1"/>
+ <pt x="654" y="1925" on="1"/>
+ <pt x="913" y="1925" on="1"/>
+ <pt x="506" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 117 values pushed */
+ 52 61 51 44 65 62 2 63 0 3 21 20 12 11 2 1 6 9 28 3 42 41 30 26 23
+ 22 6 28 34 3 0 0 10 9 21 1 0 35 34 7 1 43 2 4 48 84 64 63 1 29
+ 28 1 44 43 1 3 0 61 0 0 14 61 52 44 51 41 2 2 0 21 3 65 64 63 35
+ 34 28 26 23 20 12 9 11 21 10 3 62 10 51 2 0 0 30 29 11 10 32 3 51 1
+ 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ebreve" xMin="43" yMin="0" xMax="1202" yMax="1925">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="315" y="1925" on="1"/>
+ <pt x="380" y="1925" on="1"/>
+ <pt x="407" y="1835" on="0"/>
+ <pt x="467" y="1793" on="1"/>
+ <pt x="535" y="1746" on="0"/>
+ <pt x="648" y="1746" on="1"/>
+ <pt x="774" y="1746" on="0"/>
+ <pt x="844" y="1805" on="1"/>
+ <pt x="893" y="1845" on="0"/>
+ <pt x="917" y="1925" on="1"/>
+ <pt x="981" y="1925" on="1"/>
+ <pt x="962" y="1790" on="0"/>
+ <pt x="890" y="1709" on="1"/>
+ <pt x="796" y="1604" on="0"/>
+ <pt x="648" y="1604" on="1"/>
+ <pt x="494" y="1604" on="0"/>
+ <pt x="399" y="1719" on="1"/>
+ <pt x="334" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 124 values pushed */
+ 0 0 67 20 76 48 84 52 61 51 44 21 20 12 11 2 1 6 9 28 3 42 41 30 26
+ 23 22 6 28 34 3 72 71 63 62 4 13 76 0 0 0 10 9 21 1 0 35 34 7 1
+ 43 2 4 48 84 29 28 1 44 43 1 2 0 61 0 0 14 61 52 44 51 41 2 2 0
+ 21 3 72 71 35 34 28 26 23 20 12 9 10 21 10 3 63 62 2 10 51 3 0 0 30
+ 29 11 10 32 3 51 1 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ecaron" xMin="43" yMin="0" xMax="1202" yMax="1925">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1024" y="1925" on="1"/>
+ <pt x="784" y="1604" on="1"/>
+ <pt x="562" y="1604" on="1"/>
+ <pt x="321" y="1925" on="1"/>
+ <pt x="407" y="1925" on="1"/>
+ <pt x="673" y="1703" on="1"/>
+ <pt x="938" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 123 values pushed */
+ 52 61 51 44 21 20 12 11 2 1 6 9 28 3 42 41 30 26 23 22 6 28 34 3 68
+ 67 66 65 62 5 13 63 0 0 10 9 21 1 0 35 34 7 1 43 2 4 48 84 64 63
+ 1 29 28 1 44 43 1 3 0 61 0 0 14 61 52 44 51 62 41 2 3 0 21 3 68
+ 67 64 63 35 34 28 26 23 20 12 9 12 21 10 3 66 65 2 10 51 3 0 0 30 29
+ 11 10 32 3 51 1 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ecircumflex" xMin="43" yMin="0" xMax="1202" yMax="1925">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="265" y="1604" on="1"/>
+ <pt x="506" y="1925" on="1"/>
+ <pt x="728" y="1925" on="1"/>
+ <pt x="968" y="1604" on="1"/>
+ <pt x="882" y="1604" on="1"/>
+ <pt x="617" y="1826" on="1"/>
+ <pt x="351" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 124 values pushed */
+ 52 61 51 44 68 67 66 65 62 5 63 0 3 21 20 12 11 2 1 6 9 28 3 42 41
+ 30 26 23 22 6 28 34 3 0 0 10 9 21 1 0 35 34 7 1 43 2 4 48 84 64
+ 63 1 29 28 1 44 43 1 3 0 61 0 0 14 61 52 44 51 41 2 2 0 21 3 67
+ 66 65 64 63 35 34 28 26 23 20 12 9 13 21 10 3 68 62 2 10 51 3 0 0 30
+ 29 11 10 32 3 51 1 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Edieresis" xMin="43" yMin="0" xMax="1202" yMax="1777">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="326" y="1604" on="1"/>
+ <pt x="326" y="1777" on="1"/>
+ <pt x="499" y="1777" on="1"/>
+ <pt x="499" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="721" y="1604" on="1"/>
+ <pt x="721" y="1777" on="1"/>
+ <pt x="894" y="1777" on="1"/>
+ <pt x="894" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 136 values pushed */
+ 52 61 51 44 21 20 12 11 2 1 6 9 28 3 42 41 30 26 23 22 6 28 34 3 0
+ 0 69 66 65 62 13 3 63 10 9 21 1 0 35 34 7 1 43 3 4 48 84 68 67 64
+ 63 3 29 28 1 44 43 1 3 0 61 0 0 14 61 52 44 51 41 2 2 0 21 3 26
+ 23 20 3 21 68 3 35 28 12 9 4 68 66 3 34 66 64 2 0 0 67 66 13 1 68
+ 65 64 13 1 62 30 29 11 10 32 3 51 3 4 48 196 69 68 1 63 62 1 43 42 1
+ 1 0 1 22 21 1 52 51 1 6 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Edotaccent" xMin="43" yMin="0" xMax="1202" yMax="1801">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="536" y="1604" on="1"/>
+ <pt x="536" y="1801" on="1"/>
+ <pt x="733" y="1801" on="1"/>
+ <pt x="733" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 120 values pushed */
+ 52 61 51 44 21 20 12 11 2 1 6 9 28 3 42 41 30 26 23 22 6 28 34 3 0
+ 0 65 62 5 1 63 10 9 21 1 0 35 34 7 1 43 3 4 48 84 64 63 1 29 28
+ 1 44 43 1 3 0 61 0 0 14 61 52 44 51 41 2 2 0 21 3 35 28 26 23 20
+ 12 9 7 21 64 3 34 64 62 2 0 0 65 64 4 1 62 30 29 11 10 32 3 51 2
+ 4 48 196 63 62 1 43 42 1 1 0 1 22 21 1 52 51 1 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Egrave" xMin="43" yMin="0" xMax="1202" yMax="1925">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="792" y="1604" on="1"/>
+ <pt x="699" y="1604" on="1"/>
+ <pt x="292" y="1925" on="1"/>
+ <pt x="551" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 117 values pushed */
+ 52 61 51 44 63 62 2 64 0 3 21 20 12 11 2 1 6 9 28 3 42 41 30 26 23
+ 22 6 28 34 3 0 0 10 9 21 1 0 35 34 7 1 43 2 4 48 84 65 64 1 29
+ 28 1 44 43 1 3 0 61 0 0 14 61 52 44 51 41 2 2 0 21 3 65 63 62 35
+ 34 28 26 23 20 12 9 11 21 10 3 64 10 51 2 0 0 30 29 11 10 32 3 51 1
+ 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Emacron" xMin="43" yMin="0" xMax="1202" yMax="1727">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="827" on="1"/>
+ <pt x="933" y="840" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="339" y="1604" on="1"/>
+ <pt x="339" y="1727" on="1"/>
+ <pt x="981" y="1727" on="1"/>
+ <pt x="981" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 117 values pushed */
+ 52 61 51 44 21 20 12 11 2 1 6 9 28 3 42 41 30 26 23 22 6 28 34 3 0
+ 0 65 62 12 1 63 10 9 21 1 0 35 34 7 1 43 3 4 48 84 64 63 1 29 28
+ 1 44 43 1 3 0 61 0 0 14 61 52 44 51 41 2 2 0 21 3 65 64 35 34 28
+ 26 23 20 12 9 10 21 10 3 63 62 2 10 51 3 0 0 30 29 11 10 32 3 51 1
+ 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eng" xMin="43" yMin="-296" xMax="1435" yMax="1480">
+ <contour>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="130" y="68" on="1"/>
+ <pt x="194" y="73" on="0"/>
+ <pt x="229" y="140" on="0"/>
+ <pt x="229" y="259" on="1"/>
+ <pt x="229" y="1221" on="1"/>
+ <pt x="230" y="1335" on="0"/>
+ <pt x="211" y="1377" on="1"/>
+ <pt x="196" y="1409" on="0"/>
+ <pt x="130" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="1159" y="331" on="1"/>
+ <pt x="1159" y="1221" on="1"/>
+ <pt x="1153" y="1320" on="1"/>
+ <pt x="1149" y="1384" on="0"/>
+ <pt x="1130" y="1397" on="1"/>
+ <pt x="1112" y="1410" on="0"/>
+ <pt x="1061" y="1413" on="1"/>
+ <pt x="993" y="1417" on="1"/>
+ <pt x="974" y="1419" on="1"/>
+ <pt x="974" y="1480" on="1"/>
+ <pt x="1435" y="1480" on="1"/>
+ <pt x="1435" y="1419" on="1"/>
+ <pt x="1417" y="1417" on="1"/>
+ <pt x="1349" y="1413" on="1"/>
+ <pt x="1281" y="1408" on="0"/>
+ <pt x="1270" y="1386" on="1"/>
+ <pt x="1259" y="1367" on="0"/>
+ <pt x="1256" y="1320" on="1"/>
+ <pt x="1250" y="1221" on="1"/>
+ <pt x="1250" y="0" on="1"/>
+ <pt x="1250" y="-134" on="0"/>
+ <pt x="1171" y="-215" on="1"/>
+ <pt x="1092" y="-296" on="0"/>
+ <pt x="956" y="-296" on="1"/>
+ <pt x="864" y="-296" on="0"/>
+ <pt x="742" y="-270" on="1"/>
+ <pt x="742" y="-26" on="1"/>
+ <pt x="853" y="-26" on="1"/>
+ <pt x="854" y="-47" on="1"/>
+ <pt x="854" y="-53" on="0"/>
+ <pt x="856" y="-72" on="1"/>
+ <pt x="857" y="-84" on="0"/>
+ <pt x="857" y="-91" on="1"/>
+ <pt x="858" y="-107" on="1"/>
+ <pt x="858" y="-111" on="0"/>
+ <pt x="858" y="-119" on="1"/>
+ <pt x="858" y="-222" on="0"/>
+ <pt x="983" y="-222" on="1"/>
+ <pt x="1152" y="-222" on="0"/>
+ <pt x="1152" y="-10" on="1"/>
+ <pt x="1152" y="0" on="1"/>
+ <pt x="322" y="1220" on="1"/>
+ <pt x="322" y="259" on="1"/>
+ <pt x="321" y="144" on="0"/>
+ <pt x="340" y="104" on="1"/>
+ <pt x="355" y="72" on="0"/>
+ <pt x="421" y="68" on="1"/>
+ <pt x="489" y="63" on="1"/>
+ <pt x="508" y="62" on="1"/>
+ <pt x="508" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 0 0 53 21 39 48 84 7 14 64 58 57 34 27 24 17 16 6 1 10 14 0 3 55 43
+ 42 41 4 13 39 0 65 56 35 0 3 0 26 25 15 14 0 3 14 14 7 56 55 43 25
+ 24 5 16 41 3 65 64 15 3 41 57 3 27 26 2 13 34 1 0 6 0 0 17 16 35
+ 1 34 58 57 35 1 6 2 4 48 196 35 34 1 42 41 1 7 6 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eogonek" xMin="43" yMin="-370" xMax="1202" yMax="1480">
+ <contour>
+ <pt x="1146" y="1480" on="1"/>
+ <pt x="1146" y="1221" on="1"/>
+ <pt x="1035" y="1221" on="1"/>
+ <pt x="1034" y="1240" on="1"/>
+ <pt x="1029" y="1324" on="1"/>
+ <pt x="1028" y="1379" on="0"/>
+ <pt x="1010" y="1390" on="1"/>
+ <pt x="993" y="1399" on="0"/>
+ <pt x="956" y="1399" on="1"/>
+ <pt x="853" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="808" on="1"/>
+ <pt x="801" y="809" on="1"/>
+ <pt x="864" y="811" on="1"/>
+ <pt x="917" y="812" on="0"/>
+ <pt x="925" y="828" on="1"/>
+ <pt x="933" y="841" on="0"/>
+ <pt x="933" y="872" on="1"/>
+ <pt x="933" y="884" on="0"/>
+ <pt x="935" y="913" on="1"/>
+ <pt x="936" y="931" on="1"/>
+ <pt x="1017" y="931" on="1"/>
+ <pt x="1017" y="605" on="1"/>
+ <pt x="936" y="605" on="1"/>
+ <pt x="935" y="623" on="1"/>
+ <pt x="929" y="710" on="0"/>
+ <pt x="905" y="717" on="1"/>
+ <pt x="880" y="728" on="0"/>
+ <pt x="801" y="728" on="1"/>
+ <pt x="438" y="728" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="478" y="105" on="1"/>
+ <pt x="514" y="86" on="0"/>
+ <pt x="608" y="86" on="1"/>
+ <pt x="858" y="86" on="1"/>
+ <pt x="1005" y="86" on="0"/>
+ <pt x="1043" y="100" on="1"/>
+ <pt x="1083" y="113" on="0"/>
+ <pt x="1086" y="162" on="1"/>
+ <pt x="1090" y="253" on="1"/>
+ <pt x="1091" y="271" on="1"/>
+ <pt x="1202" y="271" on="1"/>
+ <pt x="1202" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1140" y="-273" on="1"/>
+ <pt x="1140" y="-341" on="1"/>
+ <pt x="1069" y="-370" on="0"/>
+ <pt x="991" y="-370" on="1"/>
+ <pt x="771" y="-370" on="0"/>
+ <pt x="771" y="-211" on="1"/>
+ <pt x="771" y="-89" on="0"/>
+ <pt x="929" y="0" on="1"/>
+ <pt x="1036" y="0" on="1"/>
+ <pt x="907" y="-80" on="0"/>
+ <pt x="907" y="-182" on="1"/>
+ <pt x="907" y="-289" on="0"/>
+ <pt x="1040" y="-289" on="1"/>
+ <pt x="1091" y="-289" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 127 values pushed */
+ 0 0 74 7 65 48 84 52 61 51 44 21 20 12 11 2 1 6 9 28 3 42 41 30 26
+ 23 22 6 28 34 3 63 62 65 43 0 0 10 9 21 1 0 35 34 7 1 43 2 4 48
+ 84 29 28 1 70 69 44 43 3 2 0 61 0 0 14 0 0 72 48 67 48 196 61 52 44
+ 51 70 63 62 41 2 5 0 21 3 67 69 67 35 34 28 26 23 20 12 9 10 21 10 3
+ 0 0 30 29 11 10 32 3 51 1 4 48 196 43 42 1 1 0 1 22 21 1 52 51 1
+ 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eth" xMin="41" yMin="0" xMax="1399" yMax="1489">
+ <contour>
+ <pt x="226" y="716" on="1"/>
+ <pt x="41" y="716" on="1"/>
+ <pt x="41" y="783" on="1"/>
+ <pt x="226" y="783" on="1"/>
+ <pt x="226" y="1221" on="1"/>
+ <pt x="226" y="1280" on="0"/>
+ <pt x="219" y="1333" on="1"/>
+ <pt x="213" y="1372" on="0"/>
+ <pt x="205" y="1384" on="1"/>
+ <pt x="187" y="1410" on="0"/>
+ <pt x="127" y="1413" on="1"/>
+ <pt x="60" y="1417" on="1"/>
+ <pt x="41" y="1419" on="1"/>
+ <pt x="41" y="1480" on="1"/>
+ <pt x="465" y="1480" on="1"/>
+ <pt x="536" y="1481" on="1"/>
+ <pt x="608" y="1484" on="1"/>
+ <pt x="680" y="1485" on="1"/>
+ <pt x="989" y="1489" on="0"/>
+ <pt x="1176" y="1335" on="1"/>
+ <pt x="1399" y="1151" on="0"/>
+ <pt x="1399" y="772" on="1"/>
+ <pt x="1399" y="414" on="0"/>
+ <pt x="1208" y="207" on="1"/>
+ <pt x="1017" y="0" on="0"/>
+ <pt x="687" y="0" on="1"/>
+ <pt x="41" y="0" on="1"/>
+ <pt x="41" y="62" on="1"/>
+ <pt x="60" y="63" on="1"/>
+ <pt x="127" y="68" on="1"/>
+ <pt x="203" y="74" on="0"/>
+ <pt x="213" y="115" on="1"/>
+ <pt x="226" y="177" on="0"/>
+ <pt x="226" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="436" y="716" on="1"/>
+ <pt x="436" y="259" on="1"/>
+ <pt x="440" y="181" on="1"/>
+ <pt x="444" y="110" on="0"/>
+ <pt x="498" y="87" on="1"/>
+ <pt x="544" y="68" on="0"/>
+ <pt x="638" y="68" on="1"/>
+ <pt x="894" y="68" on="0"/>
+ <pt x="1032" y="243" on="1"/>
+ <pt x="1171" y="419" on="0"/>
+ <pt x="1171" y="743" on="1"/>
+ <pt x="1171" y="1098" on="0"/>
+ <pt x="1021" y="1256" on="1"/>
+ <pt x="871" y="1413" on="0"/>
+ <pt x="532" y="1413" on="1"/>
+ <pt x="436" y="1413" on="1"/>
+ <pt x="436" y="783" on="1"/>
+ <pt x="781" y="783" on="1"/>
+ <pt x="781" y="716" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 33 26 4 13 49 48 2 13 2 3 40 40 35 2 0 25 3 0 0 52 34 1 0 14 3
+ 2 1 4 48 84 51 50 3 2 3 26 25 1 2 0 14 13 0 14 0 0 44 34 21 48
+ 196 26 33 13 4 52 51 48 25 14 5 13 21 34 2 1 0 0 0 50 49 35 34 32 3
+ 0 1 4 48 196 33 4 3 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Euro" xMin="0" yMin="-37" xMax="967" yMax="1517">
+ <contour>
+ <pt x="0" y="580" on="1"/>
+ <pt x="26" y="642" on="1"/>
+ <pt x="122" y="642" on="1"/>
+ <pt x="119" y="698" on="0"/>
+ <pt x="119" y="733" on="1"/>
+ <pt x="119" y="759" on="0"/>
+ <pt x="121" y="809" on="1"/>
+ <pt x="122" y="837" on="0"/>
+ <pt x="123" y="851" on="1"/>
+ <pt x="0" y="851" on="1"/>
+ <pt x="26" y="913" on="1"/>
+ <pt x="130" y="913" on="1"/>
+ <pt x="155" y="1070" on="0"/>
+ <pt x="184" y="1151" on="1"/>
+ <pt x="315" y="1517" on="0"/>
+ <pt x="669" y="1517" on="1"/>
+ <pt x="824" y="1517" on="0"/>
+ <pt x="967" y="1443" on="1"/>
+ <pt x="967" y="1184" on="1"/>
+ <pt x="868" y="1184" on="1"/>
+ <pt x="867" y="1239" on="1"/>
+ <pt x="863" y="1450" on="0"/>
+ <pt x="679" y="1450" on="1"/>
+ <pt x="510" y="1450" on="0"/>
+ <pt x="415" y="1270" on="1"/>
+ <pt x="347" y="1142" on="0"/>
+ <pt x="325" y="913" on="1"/>
+ <pt x="854" y="913" on="1"/>
+ <pt x="828" y="851" on="1"/>
+ <pt x="320" y="851" on="1"/>
+ <pt x="316" y="786" on="0"/>
+ <pt x="316" y="733" on="1"/>
+ <pt x="316" y="724" on="0"/>
+ <pt x="317" y="692" on="1"/>
+ <pt x="318" y="664" on="0"/>
+ <pt x="319" y="642" on="1"/>
+ <pt x="741" y="642" on="1"/>
+ <pt x="716" y="580" on="1"/>
+ <pt x="324" y="580" on="1"/>
+ <pt x="404" y="62" on="0"/>
+ <pt x="719" y="62" on="1"/>
+ <pt x="836" y="62" on="0"/>
+ <pt x="957" y="138" on="1"/>
+ <pt x="957" y="45" on="1"/>
+ <pt x="834" y="-37" on="0"/>
+ <pt x="674" y="-37" on="1"/>
+ <pt x="421" y="-37" on="0"/>
+ <pt x="272" y="174" on="1"/>
+ <pt x="167" y="323" on="0"/>
+ <pt x="129" y="580" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 98 values pushed */
+ 0 0 40 9 45 22 38 15 48 84 45 2 15 0 1 19 18 17 3 0 10 3 0 1 43
+ 42 2 0 2 3 0 0 0 29 28 9 8 11 3 10 49 38 37 0 11 3 1 2 4 48
+ 84 27 26 11 10 3 36 35 2 1 3 2 0 14 0 0 31 5 4 48 196 49 43 42 38
+ 37 36 35 29 28 27 26 19 11 10 9 8 2 1 0 19 13 4 17 18 17 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Euro#1" xMin="0" yMin="-37" xMax="967" yMax="1517">
+ <contour>
+ <pt x="0" y="580" on="1"/>
+ <pt x="26" y="642" on="1"/>
+ <pt x="122" y="642" on="1"/>
+ <pt x="119" y="698" on="0"/>
+ <pt x="119" y="733" on="1"/>
+ <pt x="119" y="759" on="0"/>
+ <pt x="121" y="809" on="1"/>
+ <pt x="122" y="837" on="0"/>
+ <pt x="123" y="851" on="1"/>
+ <pt x="0" y="851" on="1"/>
+ <pt x="26" y="913" on="1"/>
+ <pt x="130" y="913" on="1"/>
+ <pt x="155" y="1070" on="0"/>
+ <pt x="184" y="1151" on="1"/>
+ <pt x="315" y="1517" on="0"/>
+ <pt x="669" y="1517" on="1"/>
+ <pt x="824" y="1517" on="0"/>
+ <pt x="967" y="1443" on="1"/>
+ <pt x="967" y="1184" on="1"/>
+ <pt x="868" y="1184" on="1"/>
+ <pt x="867" y="1239" on="1"/>
+ <pt x="863" y="1450" on="0"/>
+ <pt x="679" y="1450" on="1"/>
+ <pt x="510" y="1450" on="0"/>
+ <pt x="415" y="1270" on="1"/>
+ <pt x="347" y="1142" on="0"/>
+ <pt x="325" y="913" on="1"/>
+ <pt x="854" y="913" on="1"/>
+ <pt x="828" y="851" on="1"/>
+ <pt x="320" y="851" on="1"/>
+ <pt x="316" y="786" on="0"/>
+ <pt x="316" y="733" on="1"/>
+ <pt x="316" y="724" on="0"/>
+ <pt x="317" y="692" on="1"/>
+ <pt x="318" y="664" on="0"/>
+ <pt x="319" y="642" on="1"/>
+ <pt x="741" y="642" on="1"/>
+ <pt x="716" y="580" on="1"/>
+ <pt x="324" y="580" on="1"/>
+ <pt x="404" y="62" on="0"/>
+ <pt x="719" y="62" on="1"/>
+ <pt x="836" y="62" on="0"/>
+ <pt x="957" y="138" on="1"/>
+ <pt x="957" y="45" on="1"/>
+ <pt x="834" y="-37" on="0"/>
+ <pt x="674" y="-37" on="1"/>
+ <pt x="421" y="-37" on="0"/>
+ <pt x="272" y="174" on="1"/>
+ <pt x="167" y="323" on="0"/>
+ <pt x="129" y="580" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 98 values pushed */
+ 0 0 40 9 45 22 38 15 48 84 45 2 15 0 1 19 18 17 3 0 10 3 0 1 43
+ 42 2 0 2 3 0 0 0 29 28 9 8 11 3 10 49 38 37 0 11 3 1 2 4 48
+ 84 27 26 11 10 3 36 35 2 1 3 2 0 14 0 0 31 5 4 48 196 49 43 42 38
+ 37 36 35 29 28 27 26 19 11 10 9 8 2 1 0 19 13 4 17 18 17 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="F" xMin="43" yMin="0" xMax="1058" yMax="1480">
+ <contour>
+ <pt x="1058" y="1480" on="1"/>
+ <pt x="1058" y="1221" on="1"/>
+ <pt x="947" y="1221" on="1"/>
+ <pt x="946" y="1240" on="1"/>
+ <pt x="941" y="1324" on="1"/>
+ <pt x="940" y="1380" on="0"/>
+ <pt x="922" y="1390" on="1"/>
+ <pt x="905" y="1399" on="0"/>
+ <pt x="868" y="1399" on="1"/>
+ <pt x="765" y="1400" on="1"/>
+ <pt x="438" y="1400" on="1"/>
+ <pt x="438" y="799" on="1"/>
+ <pt x="725" y="799" on="1"/>
+ <pt x="788" y="801" on="1"/>
+ <pt x="839" y="802" on="0"/>
+ <pt x="848" y="815" on="1"/>
+ <pt x="855" y="827" on="0"/>
+ <pt x="857" y="857" on="1"/>
+ <pt x="858" y="878" on="1"/>
+ <pt x="860" y="903" on="1"/>
+ <pt x="861" y="921" on="1"/>
+ <pt x="941" y="921" on="1"/>
+ <pt x="941" y="594" on="1"/>
+ <pt x="861" y="594" on="1"/>
+ <pt x="860" y="613" on="1"/>
+ <pt x="854" y="701" on="0"/>
+ <pt x="829" y="708" on="1"/>
+ <pt x="803" y="718" on="0"/>
+ <pt x="725" y="718" on="1"/>
+ <pt x="438" y="718" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="123" on="0"/>
+ <pt x="467" y="95" on="1"/>
+ <pt x="491" y="68" on="0"/>
+ <pt x="551" y="68" on="1"/>
+ <pt x="553" y="68" on="1"/>
+ <pt x="569" y="67" on="0"/>
+ <pt x="629" y="63" on="1"/>
+ <pt x="648" y="62" on="1"/>
+ <pt x="648" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 48 57 47 40 30 39 21 20 2 1 4 9 11 3 23 22 2 28 39 3 0 0 10 9 21
+ 1 0 29 28 7 1 11 2 4 48 84 12 11 1 40 39 1 2 0 57 0 0 14 57 48
+ 40 47 39 30 2 0 21 2 28 23 20 12 9 5 21 10 3 0 0 30 29 11 10 32 3
+ 47 1 4 48 196 1 0 1 22 21 1 48 47 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="G" xMin="85" yMin="-37" xMax="1458" yMax="1518">
+ <contour>
+ <pt x="1285" y="36" on="1"/>
+ <pt x="994" y="-37" on="0"/>
+ <pt x="805" y="-37" on="1"/>
+ <pt x="475" y="-37" on="0"/>
+ <pt x="280" y="175" on="1"/>
+ <pt x="85" y="386" on="0"/>
+ <pt x="85" y="745" on="1"/>
+ <pt x="85" y="1112" on="0"/>
+ <pt x="275" y="1315" on="1"/>
+ <pt x="464" y="1518" on="0"/>
+ <pt x="815" y="1518" on="1"/>
+ <pt x="1047" y="1518" on="0"/>
+ <pt x="1282" y="1441" on="1"/>
+ <pt x="1282" y="1172" on="1"/>
+ <pt x="1171" y="1172" on="1"/>
+ <pt x="1170" y="1192" on="1"/>
+ <pt x="1168" y="1217" on="0"/>
+ <pt x="1168" y="1242" on="1"/>
+ <pt x="1168" y="1249" on="1"/>
+ <pt x="1168" y="1333" on="0"/>
+ <pt x="1094" y="1385" on="1"/>
+ <pt x="1001" y="1450" on="0"/>
+ <pt x="825" y="1450" on="1"/>
+ <pt x="575" y="1450" on="0"/>
+ <pt x="444" y="1263" on="1"/>
+ <pt x="313" y="1077" on="0"/>
+ <pt x="313" y="733" on="1"/>
+ <pt x="313" y="386" on="0"/>
+ <pt x="475" y="214" on="1"/>
+ <pt x="633" y="47" on="0"/>
+ <pt x="864" y="47" on="1"/>
+ <pt x="948" y="47" on="0"/>
+ <pt x="1076" y="80" on="1"/>
+ <pt x="1076" y="371" on="1"/>
+ <pt x="1077" y="487" on="0"/>
+ <pt x="1058" y="527" on="1"/>
+ <pt x="1043" y="557" on="0"/>
+ <pt x="977" y="562" on="1"/>
+ <pt x="909" y="568" on="1"/>
+ <pt x="891" y="569" on="1"/>
+ <pt x="891" y="630" on="1"/>
+ <pt x="1458" y="630" on="1"/>
+ <pt x="1458" y="569" on="1"/>
+ <pt x="1440" y="568" on="1"/>
+ <pt x="1384" y="562" on="1"/>
+ <pt x="1317" y="556" on="0"/>
+ <pt x="1305" y="535" on="1"/>
+ <pt x="1294" y="516" on="0"/>
+ <pt x="1291" y="470" on="1"/>
+ <pt x="1285" y="371" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 0 0 30 7 2 22 17 10 48 84 10 0 2 2 1 18 17 14 13 12 5 0 40 3 0
+ 1 49 42 39 33 32 0 6 40 2 3 0 41 40 1 0 14 0 0 26 34 6 48 196 18
+ 17 14 3 12 32 3 42 41 2 13 0 40 39 6 32 0 0 33 32 32 1 0 1 4 48
+ 196 49 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gbreve" xMin="85" yMin="-37" xMax="1458" yMax="1925">
+ <contour>
+ <pt x="1285" y="36" on="1"/>
+ <pt x="994" y="-37" on="0"/>
+ <pt x="805" y="-37" on="1"/>
+ <pt x="475" y="-37" on="0"/>
+ <pt x="280" y="175" on="1"/>
+ <pt x="85" y="386" on="0"/>
+ <pt x="85" y="745" on="1"/>
+ <pt x="85" y="1112" on="0"/>
+ <pt x="275" y="1315" on="1"/>
+ <pt x="464" y="1518" on="0"/>
+ <pt x="815" y="1518" on="1"/>
+ <pt x="1047" y="1518" on="0"/>
+ <pt x="1282" y="1441" on="1"/>
+ <pt x="1282" y="1172" on="1"/>
+ <pt x="1171" y="1172" on="1"/>
+ <pt x="1170" y="1192" on="1"/>
+ <pt x="1168" y="1217" on="0"/>
+ <pt x="1168" y="1242" on="1"/>
+ <pt x="1168" y="1249" on="1"/>
+ <pt x="1168" y="1333" on="0"/>
+ <pt x="1094" y="1385" on="1"/>
+ <pt x="1001" y="1450" on="0"/>
+ <pt x="825" y="1450" on="1"/>
+ <pt x="575" y="1450" on="0"/>
+ <pt x="444" y="1263" on="1"/>
+ <pt x="313" y="1077" on="0"/>
+ <pt x="313" y="733" on="1"/>
+ <pt x="313" y="386" on="0"/>
+ <pt x="475" y="214" on="1"/>
+ <pt x="633" y="47" on="0"/>
+ <pt x="864" y="47" on="1"/>
+ <pt x="948" y="47" on="0"/>
+ <pt x="1076" y="80" on="1"/>
+ <pt x="1076" y="371" on="1"/>
+ <pt x="1077" y="487" on="0"/>
+ <pt x="1058" y="527" on="1"/>
+ <pt x="1043" y="557" on="0"/>
+ <pt x="977" y="562" on="1"/>
+ <pt x="909" y="568" on="1"/>
+ <pt x="891" y="569" on="1"/>
+ <pt x="891" y="630" on="1"/>
+ <pt x="1458" y="630" on="1"/>
+ <pt x="1458" y="569" on="1"/>
+ <pt x="1440" y="568" on="1"/>
+ <pt x="1384" y="562" on="1"/>
+ <pt x="1317" y="556" on="0"/>
+ <pt x="1305" y="535" on="1"/>
+ <pt x="1294" y="516" on="0"/>
+ <pt x="1291" y="470" on="1"/>
+ <pt x="1285" y="371" on="1"/>
+ </contour>
+ <contour>
+ <pt x="488" y="1925" on="1"/>
+ <pt x="553" y="1925" on="1"/>
+ <pt x="580" y="1835" on="0"/>
+ <pt x="640" y="1793" on="1"/>
+ <pt x="708" y="1746" on="0"/>
+ <pt x="821" y="1746" on="1"/>
+ <pt x="947" y="1746" on="0"/>
+ <pt x="1017" y="1805" on="1"/>
+ <pt x="1066" y="1845" on="0"/>
+ <pt x="1090" y="1925" on="1"/>
+ <pt x="1154" y="1925" on="1"/>
+ <pt x="1135" y="1790" on="0"/>
+ <pt x="1063" y="1709" on="1"/>
+ <pt x="969" y="1604" on="0"/>
+ <pt x="821" y="1604" on="1"/>
+ <pt x="667" y="1604" on="0"/>
+ <pt x="572" y="1719" on="1"/>
+ <pt x="507" y="1796" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 55 20 64 30 7 2 22 17 10 48 84 10 0 2 2 1 18 17 14 13 12 5 0
+ 40 3 0 1 49 42 39 33 32 0 6 40 2 3 0 1 60 59 51 50 4 13 64 0 0
+ 41 40 1 0 14 0 0 26 34 6 48 196 60 59 18 17 14 5 12 32 3 42 41 2 13
+ 0 51 50 40 39 4 13 6 32 0 0 33 32 32 1 0 1 4 48 196 49 0 1 13 12
+ 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gcircumflex" xMin="85" yMin="-37" xMax="1458" yMax="1925">
+ <contour>
+ <pt x="1285" y="36" on="1"/>
+ <pt x="994" y="-37" on="0"/>
+ <pt x="805" y="-37" on="1"/>
+ <pt x="475" y="-37" on="0"/>
+ <pt x="280" y="175" on="1"/>
+ <pt x="85" y="386" on="0"/>
+ <pt x="85" y="745" on="1"/>
+ <pt x="85" y="1112" on="0"/>
+ <pt x="275" y="1315" on="1"/>
+ <pt x="464" y="1518" on="0"/>
+ <pt x="815" y="1518" on="1"/>
+ <pt x="1047" y="1518" on="0"/>
+ <pt x="1282" y="1441" on="1"/>
+ <pt x="1282" y="1172" on="1"/>
+ <pt x="1171" y="1172" on="1"/>
+ <pt x="1170" y="1192" on="1"/>
+ <pt x="1168" y="1217" on="0"/>
+ <pt x="1168" y="1242" on="1"/>
+ <pt x="1168" y="1249" on="1"/>
+ <pt x="1168" y="1333" on="0"/>
+ <pt x="1094" y="1385" on="1"/>
+ <pt x="1001" y="1450" on="0"/>
+ <pt x="825" y="1450" on="1"/>
+ <pt x="575" y="1450" on="0"/>
+ <pt x="444" y="1263" on="1"/>
+ <pt x="313" y="1077" on="0"/>
+ <pt x="313" y="733" on="1"/>
+ <pt x="313" y="386" on="0"/>
+ <pt x="475" y="214" on="1"/>
+ <pt x="633" y="47" on="0"/>
+ <pt x="864" y="47" on="1"/>
+ <pt x="948" y="47" on="0"/>
+ <pt x="1076" y="80" on="1"/>
+ <pt x="1076" y="371" on="1"/>
+ <pt x="1077" y="487" on="0"/>
+ <pt x="1058" y="527" on="1"/>
+ <pt x="1043" y="557" on="0"/>
+ <pt x="977" y="562" on="1"/>
+ <pt x="909" y="568" on="1"/>
+ <pt x="891" y="569" on="1"/>
+ <pt x="891" y="630" on="1"/>
+ <pt x="1458" y="630" on="1"/>
+ <pt x="1458" y="569" on="1"/>
+ <pt x="1440" y="568" on="1"/>
+ <pt x="1384" y="562" on="1"/>
+ <pt x="1317" y="556" on="0"/>
+ <pt x="1305" y="535" on="1"/>
+ <pt x="1294" y="516" on="0"/>
+ <pt x="1291" y="470" on="1"/>
+ <pt x="1285" y="371" on="1"/>
+ </contour>
+ <contour>
+ <pt x="469" y="1604" on="1"/>
+ <pt x="710" y="1925" on="1"/>
+ <pt x="932" y="1925" on="1"/>
+ <pt x="1172" y="1604" on="1"/>
+ <pt x="1086" y="1604" on="1"/>
+ <pt x="821" y="1826" on="1"/>
+ <pt x="555" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 108 values pushed */
+ 0 0 30 7 2 22 17 10 48 84 10 0 2 2 1 56 55 54 53 50 5 51 0 3 0
+ 1 18 17 14 13 12 5 0 40 3 0 1 49 42 39 33 32 0 6 40 2 3 0 52 51
+ 1 41 40 1 2 0 14 0 0 26 34 6 48 196 54 53 18 17 14 5 12 32 3 42 41
+ 2 13 0 56 55 52 51 50 40 39 7 13 6 32 0 0 33 32 32 1 0 1 4 48 196
+ 49 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gcommaaccent" xMin="85" yMin="-432" xMax="1458" yMax="1518">
+ <contour>
+ <pt x="1285" y="36" on="1"/>
+ <pt x="994" y="-37" on="0"/>
+ <pt x="805" y="-37" on="1"/>
+ <pt x="475" y="-37" on="0"/>
+ <pt x="280" y="175" on="1"/>
+ <pt x="85" y="386" on="0"/>
+ <pt x="85" y="745" on="1"/>
+ <pt x="85" y="1112" on="0"/>
+ <pt x="275" y="1315" on="1"/>
+ <pt x="464" y="1518" on="0"/>
+ <pt x="815" y="1518" on="1"/>
+ <pt x="1047" y="1518" on="0"/>
+ <pt x="1282" y="1441" on="1"/>
+ <pt x="1282" y="1172" on="1"/>
+ <pt x="1171" y="1172" on="1"/>
+ <pt x="1170" y="1192" on="1"/>
+ <pt x="1168" y="1217" on="0"/>
+ <pt x="1168" y="1242" on="1"/>
+ <pt x="1168" y="1249" on="1"/>
+ <pt x="1168" y="1333" on="0"/>
+ <pt x="1094" y="1385" on="1"/>
+ <pt x="1001" y="1450" on="0"/>
+ <pt x="825" y="1450" on="1"/>
+ <pt x="575" y="1450" on="0"/>
+ <pt x="444" y="1263" on="1"/>
+ <pt x="313" y="1077" on="0"/>
+ <pt x="313" y="733" on="1"/>
+ <pt x="313" y="386" on="0"/>
+ <pt x="475" y="214" on="1"/>
+ <pt x="633" y="47" on="0"/>
+ <pt x="864" y="47" on="1"/>
+ <pt x="948" y="47" on="0"/>
+ <pt x="1076" y="80" on="1"/>
+ <pt x="1076" y="371" on="1"/>
+ <pt x="1077" y="486" on="0"/>
+ <pt x="1058" y="527" on="1"/>
+ <pt x="1042" y="557" on="0"/>
+ <pt x="977" y="562" on="1"/>
+ <pt x="909" y="568" on="1"/>
+ <pt x="891" y="569" on="1"/>
+ <pt x="891" y="630" on="1"/>
+ <pt x="1458" y="630" on="1"/>
+ <pt x="1458" y="569" on="1"/>
+ <pt x="1440" y="568" on="1"/>
+ <pt x="1384" y="562" on="1"/>
+ <pt x="1317" y="556" on="0"/>
+ <pt x="1305" y="535" on="1"/>
+ <pt x="1294" y="516" on="0"/>
+ <pt x="1291" y="470" on="1"/>
+ <pt x="1285" y="371" on="1"/>
+ </contour>
+ <contour>
+ <pt x="614" y="-421" on="1"/>
+ <pt x="614" y="-349" on="1"/>
+ <pt x="663" y="-359" on="0"/>
+ <pt x="718" y="-359" on="1"/>
+ <pt x="821" y="-359" on="0"/>
+ <pt x="821" y="-279" on="1"/>
+ <pt x="821" y="-190" on="0"/>
+ <pt x="663" y="-175" on="1"/>
+ <pt x="663" y="-111" on="1"/>
+ <pt x="798" y="-114" on="0"/>
+ <pt x="863" y="-143" on="1"/>
+ <pt x="956" y="-185" on="0"/>
+ <pt x="956" y="-280" on="1"/>
+ <pt x="956" y="-432" on="0"/>
+ <pt x="739" y="-432" on="1"/>
+ <pt x="679" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 107 values pushed */
+ 0 0 53 17 64 30 7 2 22 17 10 48 84 10 0 2 2 1 18 17 14 13 12 5 0
+ 40 3 0 1 49 42 39 33 32 0 6 40 2 3 0 1 58 57 51 50 4 13 64 2 0
+ 41 40 1 0 14 0 0 55 48 62 26 34 6 48 196 18 17 14 3 12 32 3 42 41 2
+ 13 0 58 57 51 50 40 39 6 13 62 6 32 0 0 33 32 32 1 0 1 4 48 196 49
+ 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gdotaccent" xMin="85" yMin="-37" xMax="1458" yMax="1801">
+ <contour>
+ <pt x="1285" y="36" on="1"/>
+ <pt x="994" y="-37" on="0"/>
+ <pt x="805" y="-37" on="1"/>
+ <pt x="475" y="-37" on="0"/>
+ <pt x="280" y="175" on="1"/>
+ <pt x="85" y="386" on="0"/>
+ <pt x="85" y="745" on="1"/>
+ <pt x="85" y="1112" on="0"/>
+ <pt x="275" y="1315" on="1"/>
+ <pt x="464" y="1518" on="0"/>
+ <pt x="815" y="1518" on="1"/>
+ <pt x="1047" y="1518" on="0"/>
+ <pt x="1282" y="1441" on="1"/>
+ <pt x="1282" y="1172" on="1"/>
+ <pt x="1171" y="1172" on="1"/>
+ <pt x="1170" y="1192" on="1"/>
+ <pt x="1168" y="1217" on="0"/>
+ <pt x="1168" y="1242" on="1"/>
+ <pt x="1168" y="1249" on="1"/>
+ <pt x="1168" y="1333" on="0"/>
+ <pt x="1094" y="1385" on="1"/>
+ <pt x="1001" y="1450" on="0"/>
+ <pt x="825" y="1450" on="1"/>
+ <pt x="575" y="1450" on="0"/>
+ <pt x="444" y="1263" on="1"/>
+ <pt x="313" y="1077" on="0"/>
+ <pt x="313" y="733" on="1"/>
+ <pt x="313" y="386" on="0"/>
+ <pt x="475" y="214" on="1"/>
+ <pt x="633" y="47" on="0"/>
+ <pt x="864" y="47" on="1"/>
+ <pt x="948" y="47" on="0"/>
+ <pt x="1076" y="80" on="1"/>
+ <pt x="1076" y="371" on="1"/>
+ <pt x="1077" y="487" on="0"/>
+ <pt x="1058" y="527" on="1"/>
+ <pt x="1043" y="557" on="0"/>
+ <pt x="977" y="562" on="1"/>
+ <pt x="909" y="568" on="1"/>
+ <pt x="891" y="569" on="1"/>
+ <pt x="891" y="630" on="1"/>
+ <pt x="1458" y="630" on="1"/>
+ <pt x="1458" y="569" on="1"/>
+ <pt x="1440" y="568" on="1"/>
+ <pt x="1384" y="562" on="1"/>
+ <pt x="1317" y="556" on="0"/>
+ <pt x="1305" y="535" on="1"/>
+ <pt x="1294" y="516" on="0"/>
+ <pt x="1291" y="470" on="1"/>
+ <pt x="1285" y="371" on="1"/>
+ </contour>
+ <contour>
+ <pt x="722" y="1604" on="1"/>
+ <pt x="722" y="1801" on="1"/>
+ <pt x="919" y="1801" on="1"/>
+ <pt x="919" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 111 values pushed */
+ 0 0 30 7 2 22 17 10 48 84 10 0 2 2 1 18 17 14 13 12 5 0 40 3 0
+ 1 49 42 39 33 32 0 6 40 2 3 0 0 0 53 50 5 1 51 1 4 48 84 52 51
+ 1 41 40 1 2 0 14 0 0 26 34 6 48 196 18 17 14 3 12 32 3 40 39 2 52
+ 50 3 42 41 2 13 0 6 50 0 0 53 52 4 1 50 33 32 32 1 0 2 4 48 196
+ 51 50 1 49 0 1 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="H" xMin="41" yMin="0" xMax="1438" yMax="1480">
+ <contour>
+ <pt x="436" y="812" on="1"/>
+ <pt x="1043" y="812" on="1"/>
+ <pt x="1043" y="1221" on="1"/>
+ <pt x="1043" y="1280" on="0"/>
+ <pt x="1036" y="1333" on="1"/>
+ <pt x="1030" y="1372" on="0"/>
+ <pt x="1022" y="1384" on="1"/>
+ <pt x="1003" y="1409" on="0"/>
+ <pt x="945" y="1413" on="1"/>
+ <pt x="877" y="1417" on="1"/>
+ <pt x="858" y="1419" on="1"/>
+ <pt x="858" y="1480" on="1"/>
+ <pt x="1438" y="1480" on="1"/>
+ <pt x="1438" y="1419" on="1"/>
+ <pt x="1420" y="1417" on="1"/>
+ <pt x="1352" y="1413" on="1"/>
+ <pt x="1277" y="1408" on="0"/>
+ <pt x="1267" y="1366" on="1"/>
+ <pt x="1252" y="1305" on="0"/>
+ <pt x="1253" y="1221" on="1"/>
+ <pt x="1253" y="259" on="1"/>
+ <pt x="1253" y="203" on="0"/>
+ <pt x="1261" y="147" on="1"/>
+ <pt x="1268" y="96" on="0"/>
+ <pt x="1293" y="82" on="1"/>
+ <pt x="1314" y="71" on="0"/>
+ <pt x="1352" y="68" on="1"/>
+ <pt x="1420" y="63" on="1"/>
+ <pt x="1438" y="62" on="1"/>
+ <pt x="1438" y="0" on="1"/>
+ <pt x="858" y="0" on="1"/>
+ <pt x="858" y="62" on="1"/>
+ <pt x="877" y="63" on="1"/>
+ <pt x="945" y="68" on="1"/>
+ <pt x="1020" y="74" on="0"/>
+ <pt x="1030" y="115" on="1"/>
+ <pt x="1043" y="177" on="0"/>
+ <pt x="1043" y="259" on="1"/>
+ <pt x="1043" y="726" on="1"/>
+ <pt x="436" y="726" on="1"/>
+ <pt x="436" y="259" on="1"/>
+ <pt x="436" y="200" on="0"/>
+ <pt x="443" y="147" on="1"/>
+ <pt x="449" y="109" on="0"/>
+ <pt x="457" y="97" on="1"/>
+ <pt x="476" y="72" on="0"/>
+ <pt x="534" y="68" on="1"/>
+ <pt x="602" y="63" on="1"/>
+ <pt x="621" y="62" on="1"/>
+ <pt x="621" y="0" on="1"/>
+ <pt x="41" y="0" on="1"/>
+ <pt x="41" y="62" on="1"/>
+ <pt x="60" y="63" on="1"/>
+ <pt x="128" y="68" on="1"/>
+ <pt x="192" y="73" on="0"/>
+ <pt x="226" y="139" on="0"/>
+ <pt x="226" y="259" on="1"/>
+ <pt x="226" y="1221" on="1"/>
+ <pt x="226" y="1280" on="0"/>
+ <pt x="219" y="1333" on="1"/>
+ <pt x="213" y="1372" on="0"/>
+ <pt x="205" y="1384" on="1"/>
+ <pt x="186" y="1409" on="0"/>
+ <pt x="128" y="1413" on="1"/>
+ <pt x="60" y="1417" on="1"/>
+ <pt x="41" y="1419" on="1"/>
+ <pt x="41" y="1480" on="1"/>
+ <pt x="621" y="1480" on="1"/>
+ <pt x="621" y="1419" on="1"/>
+ <pt x="602" y="1417" on="1"/>
+ <pt x="534" y="1413" on="1"/>
+ <pt x="459" y="1408" on="0"/>
+ <pt x="449" y="1366" on="1"/>
+ <pt x="436" y="1302" on="0"/>
+ <pt x="436" y="1221" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 88 values pushed */
+ 74 67 57 66 56 50 40 49 37 30 20 29 19 12 2 11 0 0 39 38 7 1 0 1 4
+ 48 84 1 0 1 50 49 30 29 3 2 0 67 66 12 11 0 3 14 67 74 66 57 50 56
+ 49 40 30 37 29 20 12 19 11 2 0 0 38 37 2 1 32 3 19 74 40 39 0 32 3
+ 56 2 4 48 196 20 19 1 57 56 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Hbar" xMin="41" yMin="0" xMax="1438" yMax="1480">
+ <contour>
+ <pt x="1043" y="726" on="1"/>
+ <pt x="436" y="726" on="1"/>
+ <pt x="436" y="259" on="1"/>
+ <pt x="436" y="200" on="0"/>
+ <pt x="443" y="147" on="1"/>
+ <pt x="449" y="109" on="0"/>
+ <pt x="457" y="97" on="1"/>
+ <pt x="476" y="72" on="0"/>
+ <pt x="534" y="68" on="1"/>
+ <pt x="602" y="63" on="1"/>
+ <pt x="621" y="62" on="1"/>
+ <pt x="621" y="0" on="1"/>
+ <pt x="41" y="0" on="1"/>
+ <pt x="41" y="62" on="1"/>
+ <pt x="60" y="63" on="1"/>
+ <pt x="128" y="68" on="1"/>
+ <pt x="192" y="73" on="0"/>
+ <pt x="226" y="139" on="0"/>
+ <pt x="226" y="259" on="1"/>
+ <pt x="226" y="1086" on="1"/>
+ <pt x="41" y="1086" on="1"/>
+ <pt x="41" y="1160" on="1"/>
+ <pt x="226" y="1160" on="1"/>
+ <pt x="226" y="1221" on="1"/>
+ <pt x="226" y="1280" on="0"/>
+ <pt x="219" y="1333" on="1"/>
+ <pt x="213" y="1372" on="0"/>
+ <pt x="205" y="1384" on="1"/>
+ <pt x="186" y="1409" on="0"/>
+ <pt x="128" y="1413" on="1"/>
+ <pt x="60" y="1417" on="1"/>
+ <pt x="41" y="1419" on="1"/>
+ <pt x="41" y="1480" on="1"/>
+ <pt x="621" y="1480" on="1"/>
+ <pt x="621" y="1419" on="1"/>
+ <pt x="602" y="1417" on="1"/>
+ <pt x="534" y="1413" on="1"/>
+ <pt x="459" y="1408" on="0"/>
+ <pt x="449" y="1366" on="1"/>
+ <pt x="436" y="1302" on="0"/>
+ <pt x="436" y="1221" on="1"/>
+ <pt x="436" y="1160" on="1"/>
+ <pt x="1043" y="1160" on="1"/>
+ <pt x="1043" y="1221" on="1"/>
+ <pt x="1043" y="1280" on="0"/>
+ <pt x="1036" y="1333" on="1"/>
+ <pt x="1030" y="1372" on="0"/>
+ <pt x="1022" y="1384" on="1"/>
+ <pt x="1003" y="1409" on="0"/>
+ <pt x="945" y="1413" on="1"/>
+ <pt x="877" y="1417" on="1"/>
+ <pt x="858" y="1419" on="1"/>
+ <pt x="858" y="1480" on="1"/>
+ <pt x="1438" y="1480" on="1"/>
+ <pt x="1438" y="1419" on="1"/>
+ <pt x="1420" y="1417" on="1"/>
+ <pt x="1352" y="1413" on="1"/>
+ <pt x="1277" y="1408" on="0"/>
+ <pt x="1267" y="1366" on="1"/>
+ <pt x="1252" y="1305" on="0"/>
+ <pt x="1253" y="1221" on="1"/>
+ <pt x="1253" y="1160" on="1"/>
+ <pt x="1438" y="1160" on="1"/>
+ <pt x="1438" y="1086" on="1"/>
+ <pt x="1253" y="1086" on="1"/>
+ <pt x="1253" y="259" on="1"/>
+ <pt x="1253" y="203" on="0"/>
+ <pt x="1261" y="147" on="1"/>
+ <pt x="1268" y="96" on="0"/>
+ <pt x="1293" y="82" on="1"/>
+ <pt x="1314" y="71" on="0"/>
+ <pt x="1352" y="68" on="1"/>
+ <pt x="1420" y="63" on="1"/>
+ <pt x="1438" y="62" on="1"/>
+ <pt x="1438" y="0" on="1"/>
+ <pt x="858" y="0" on="1"/>
+ <pt x="858" y="62" on="1"/>
+ <pt x="877" y="63" on="1"/>
+ <pt x="945" y="68" on="1"/>
+ <pt x="1020" y="74" on="0"/>
+ <pt x="1030" y="115" on="1"/>
+ <pt x="1043" y="177" on="0"/>
+ <pt x="1043" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="436" y="812" on="1"/>
+ <pt x="1043" y="812" on="1"/>
+ <pt x="1043" y="1086" on="1"/>
+ <pt x="436" y="1086" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 121 values pushed */
+ 82 75 65 74 60 53 43 52 40 33 23 32 18 12 2 11 0 0 62 61 42 41 22 21 21
+ 5 19 1 0 7 1 83 2 4 48 84 84 83 1 75 74 12 11 3 2 0 53 52 33 32
+ 0 3 86 85 64 63 20 19 1 5 14 75 82 74 65 53 60 52 43 33 40 32 23 12 18
+ 11 2 63 62 2 13 60 21 20 18 0 0 85 84 82 43 42 0 32 5 60 86 83 41 40
+ 2 1 32 5 18 2 4 48 196 65 64 61 60 3 23 22 19 18 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Hcircumflex" xMin="41" yMin="0" xMax="1438" yMax="1925">
+ <contour>
+ <pt x="436" y="812" on="1"/>
+ <pt x="1043" y="812" on="1"/>
+ <pt x="1043" y="1221" on="1"/>
+ <pt x="1043" y="1280" on="0"/>
+ <pt x="1036" y="1333" on="1"/>
+ <pt x="1030" y="1372" on="0"/>
+ <pt x="1022" y="1384" on="1"/>
+ <pt x="1003" y="1409" on="0"/>
+ <pt x="945" y="1413" on="1"/>
+ <pt x="877" y="1417" on="1"/>
+ <pt x="858" y="1419" on="1"/>
+ <pt x="858" y="1480" on="1"/>
+ <pt x="1438" y="1480" on="1"/>
+ <pt x="1438" y="1419" on="1"/>
+ <pt x="1420" y="1417" on="1"/>
+ <pt x="1352" y="1413" on="1"/>
+ <pt x="1277" y="1408" on="0"/>
+ <pt x="1267" y="1366" on="1"/>
+ <pt x="1252" y="1305" on="0"/>
+ <pt x="1253" y="1221" on="1"/>
+ <pt x="1253" y="259" on="1"/>
+ <pt x="1253" y="203" on="0"/>
+ <pt x="1261" y="147" on="1"/>
+ <pt x="1268" y="96" on="0"/>
+ <pt x="1293" y="82" on="1"/>
+ <pt x="1314" y="71" on="0"/>
+ <pt x="1352" y="68" on="1"/>
+ <pt x="1420" y="63" on="1"/>
+ <pt x="1438" y="62" on="1"/>
+ <pt x="1438" y="0" on="1"/>
+ <pt x="858" y="0" on="1"/>
+ <pt x="858" y="62" on="1"/>
+ <pt x="877" y="63" on="1"/>
+ <pt x="945" y="68" on="1"/>
+ <pt x="1020" y="74" on="0"/>
+ <pt x="1030" y="115" on="1"/>
+ <pt x="1043" y="177" on="0"/>
+ <pt x="1043" y="259" on="1"/>
+ <pt x="1043" y="726" on="1"/>
+ <pt x="436" y="726" on="1"/>
+ <pt x="436" y="259" on="1"/>
+ <pt x="436" y="200" on="0"/>
+ <pt x="443" y="147" on="1"/>
+ <pt x="449" y="109" on="0"/>
+ <pt x="457" y="97" on="1"/>
+ <pt x="476" y="72" on="0"/>
+ <pt x="534" y="68" on="1"/>
+ <pt x="602" y="63" on="1"/>
+ <pt x="621" y="62" on="1"/>
+ <pt x="621" y="0" on="1"/>
+ <pt x="41" y="0" on="1"/>
+ <pt x="41" y="62" on="1"/>
+ <pt x="60" y="63" on="1"/>
+ <pt x="128" y="68" on="1"/>
+ <pt x="192" y="73" on="0"/>
+ <pt x="226" y="139" on="0"/>
+ <pt x="226" y="259" on="1"/>
+ <pt x="226" y="1221" on="1"/>
+ <pt x="226" y="1280" on="0"/>
+ <pt x="219" y="1333" on="1"/>
+ <pt x="213" y="1372" on="0"/>
+ <pt x="205" y="1384" on="1"/>
+ <pt x="186" y="1409" on="0"/>
+ <pt x="128" y="1413" on="1"/>
+ <pt x="60" y="1417" on="1"/>
+ <pt x="41" y="1419" on="1"/>
+ <pt x="41" y="1480" on="1"/>
+ <pt x="621" y="1480" on="1"/>
+ <pt x="621" y="1419" on="1"/>
+ <pt x="602" y="1417" on="1"/>
+ <pt x="534" y="1413" on="1"/>
+ <pt x="459" y="1408" on="0"/>
+ <pt x="449" y="1366" on="1"/>
+ <pt x="436" y="1302" on="0"/>
+ <pt x="436" y="1221" on="1"/>
+ </contour>
+ <contour>
+ <pt x="388" y="1604" on="1"/>
+ <pt x="629" y="1925" on="1"/>
+ <pt x="851" y="1925" on="1"/>
+ <pt x="1091" y="1604" on="1"/>
+ <pt x="1005" y="1604" on="1"/>
+ <pt x="740" y="1826" on="1"/>
+ <pt x="474" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 117 values pushed */
+ 74 67 57 66 56 50 40 49 37 30 20 29 19 12 2 11 81 80 79 78 75 5 76 11 3
+ 0 0 39 38 7 1 0 1 4 48 84 77 76 1 1 0 1 50 49 30 29 3 3 0 67
+ 66 12 11 0 3 14 67 74 66 57 50 56 49 40 30 37 29 20 12 19 11 2 78 19 1
+ 2 81 80 79 77 76 5 1 0 3 75 0 56 2 0 0 38 37 2 1 32 3 19 74 40
+ 39 0 32 3 56 2 4 48 196 20 19 1 57 56 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="I" xMin="51" yMin="0" xMax="631" yMax="1480">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 39 values pushed */
+ 0 29 19 28 18 11 1 10 29 28 1 0 11 10 0 14 29 0 28 19 11 18 10 1 0
+ 0 19 18 32 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="IJ" xMin="51" yMin="-297" xMax="1420" yMax="1480">
+ <component glyphName="I" x="0" y="0" flags="0x4"/>
+ <component glyphName="J" x="654" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="Iacute" xMin="51" yMin="0" xMax="637" yMax="1925">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="137" y="1604" on="1"/>
+ <pt x="378" y="1925" on="1"/>
+ <pt x="637" y="1925" on="1"/>
+ <pt x="230" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 29 19 28 18 11 1 10 39 36 2 37 10 3 38 37 1 29 28 1 2 0 11 10 0
+ 14 29 0 28 19 11 18 10 1 37 18 0 2 38 18 39 36 0 0 0 19 18 32 1 0
+ 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ibreve" xMin="8" yMin="0" xMax="674" yMax="1925">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="8" y="1925" on="1"/>
+ <pt x="73" y="1925" on="1"/>
+ <pt x="100" y="1835" on="0"/>
+ <pt x="160" y="1793" on="1"/>
+ <pt x="228" y="1746" on="0"/>
+ <pt x="341" y="1746" on="1"/>
+ <pt x="467" y="1746" on="0"/>
+ <pt x="537" y="1805" on="1"/>
+ <pt x="586" y="1845" on="0"/>
+ <pt x="610" y="1925" on="1"/>
+ <pt x="674" y="1925" on="1"/>
+ <pt x="655" y="1790" on="0"/>
+ <pt x="583" y="1709" on="1"/>
+ <pt x="489" y="1604" on="0"/>
+ <pt x="341" y="1604" on="1"/>
+ <pt x="187" y="1604" on="0"/>
+ <pt x="92" y="1719" on="1"/>
+ <pt x="27" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 0 0 41 20 50 48 84 0 29 19 28 18 11 1 10 46 45 37 36 4 13 50 10 29 28
+ 1 0 11 10 0 14 29 0 28 19 11 18 10 1 46 45 2 13 18 37 36 0 0 0 19
+ 18 37 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Icircumflex" xMin="-11" yMin="0" xMax="692" yMax="1925">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="-11" y="1604" on="1"/>
+ <pt x="230" y="1925" on="1"/>
+ <pt x="452" y="1925" on="1"/>
+ <pt x="692" y="1604" on="1"/>
+ <pt x="606" y="1604" on="1"/>
+ <pt x="341" y="1826" on="1"/>
+ <pt x="75" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 29 19 28 18 11 1 10 42 41 40 39 36 5 37 10 3 38 37 1 29 28 1 2 0
+ 11 10 0 14 29 0 28 19 11 18 10 1 41 18 0 2 40 39 38 3 13 18 42 37 36
+ 3 13 0 0 0 19 18 32 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Idieresis" xMin="51" yMin="0" xMax="631" yMax="1777">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="57" y="1604" on="1"/>
+ <pt x="57" y="1777" on="1"/>
+ <pt x="230" y="1777" on="1"/>
+ <pt x="230" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="452" y="1604" on="1"/>
+ <pt x="452" y="1777" on="1"/>
+ <pt x="625" y="1777" on="1"/>
+ <pt x="625" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 29 19 28 18 11 1 10 0 0 43 40 39 36 13 3 37 1 4 48 84 42 41 38 37
+ 3 29 28 1 2 0 11 10 0 14 29 0 28 19 11 18 10 1 0 0 41 40 13 1 42
+ 39 38 13 1 36 19 18 32 1 0 3 4 48 196 43 42 1 37 36 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Idotaccent" xMin="51" yMin="0" xMax="631" yMax="1801">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="242" y="1604" on="1"/>
+ <pt x="242" y="1801" on="1"/>
+ <pt x="439" y="1801" on="1"/>
+ <pt x="439" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 0 29 19 28 18 11 1 10 0 0 39 36 5 1 37 1 4 48 84 38 37 1 29 28 1
+ 2 0 11 10 0 14 29 0 28 19 11 18 10 1 0 0 39 38 4 1 36 19 18 32 1
+ 0 2 4 48 196 37 36 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Igrave" xMin="39" yMin="0" xMax="631" yMax="1925">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="539" y="1604" on="1"/>
+ <pt x="446" y="1604" on="1"/>
+ <pt x="39" y="1925" on="1"/>
+ <pt x="298" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 29 19 28 18 11 1 10 37 36 2 38 10 3 39 38 1 29 28 1 2 0 11 10 0
+ 14 29 0 28 19 11 18 10 1 39 18 0 2 36 18 38 0 0 0 37 19 18 32 2 0
+ 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Imacron" xMin="20" yMin="0" xMax="662" yMax="1727">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="20" y="1604" on="1"/>
+ <pt x="20" y="1727" on="1"/>
+ <pt x="662" y="1727" on="1"/>
+ <pt x="662" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 0 29 19 28 18 11 1 10 0 0 39 36 12 1 37 1 4 48 84 38 37 1 29 28 1
+ 2 0 11 10 0 14 29 0 28 19 11 18 10 1 39 38 2 13 18 37 36 0 0 0 19
+ 18 32 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Iogonek" xMin="51" yMin="-370" xMax="631" yMax="1480">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="581" y="-273" on="1"/>
+ <pt x="581" y="-341" on="1"/>
+ <pt x="510" y="-370" on="0"/>
+ <pt x="432" y="-370" on="1"/>
+ <pt x="212" y="-370" on="0"/>
+ <pt x="212" y="-211" on="1"/>
+ <pt x="212" y="-89" on="0"/>
+ <pt x="370" y="0" on="1"/>
+ <pt x="477" y="0" on="1"/>
+ <pt x="348" y="-80" on="0"/>
+ <pt x="348" y="-182" on="1"/>
+ <pt x="348" y="-289" on="0"/>
+ <pt x="481" y="-289" on="1"/>
+ <pt x="532" y="-289" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 48 7 39 48 84 0 29 19 28 18 11 1 10 37 36 39 28 44 43 29 28 3 0
+ 11 10 0 14 0 0 46 48 41 48 196 29 0 28 19 11 18 10 1 43 18 0 2 44 37
+ 36 3 13 18 41 0 0 0 19 18 32 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Itilde" xMin="8" yMin="0" xMax="674" yMax="1839">
+ <contour>
+ <pt x="236" y="259" on="1"/>
+ <pt x="236" y="1221" on="1"/>
+ <pt x="236" y="1280" on="0"/>
+ <pt x="229" y="1333" on="1"/>
+ <pt x="223" y="1372" on="0"/>
+ <pt x="215" y="1384" on="1"/>
+ <pt x="197" y="1410" on="0"/>
+ <pt x="137" y="1413" on="1"/>
+ <pt x="70" y="1417" on="1"/>
+ <pt x="51" y="1419" on="1"/>
+ <pt x="51" y="1480" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1419" on="1"/>
+ <pt x="612" y="1417" on="1"/>
+ <pt x="544" y="1413" on="1"/>
+ <pt x="469" y="1408" on="0"/>
+ <pt x="459" y="1366" on="1"/>
+ <pt x="446" y="1302" on="0"/>
+ <pt x="446" y="1221" on="1"/>
+ <pt x="446" y="259" on="1"/>
+ <pt x="446" y="200" on="0"/>
+ <pt x="453" y="147" on="1"/>
+ <pt x="459" y="109" on="0"/>
+ <pt x="467" y="97" on="1"/>
+ <pt x="486" y="72" on="0"/>
+ <pt x="544" y="68" on="1"/>
+ <pt x="612" y="63" on="1"/>
+ <pt x="631" y="62" on="1"/>
+ <pt x="631" y="0" on="1"/>
+ <pt x="51" y="0" on="1"/>
+ <pt x="51" y="62" on="1"/>
+ <pt x="70" y="63" on="1"/>
+ <pt x="137" y="68" on="1"/>
+ <pt x="213" y="74" on="0"/>
+ <pt x="223" y="115" on="1"/>
+ <pt x="236" y="177" on="0"/>
+ </contour>
+ <contour>
+ <pt x="8" y="1604" on="1"/>
+ <pt x="35" y="1744" on="0"/>
+ <pt x="104" y="1797" on="1"/>
+ <pt x="158" y="1839" on="0"/>
+ <pt x="235" y="1839" on="1"/>
+ <pt x="300" y="1839" on="0"/>
+ <pt x="353" y="1801" on="1"/>
+ <pt x="388" y="1776" on="1"/>
+ <pt x="440" y="1739" on="0"/>
+ <pt x="494" y="1739" on="1"/>
+ <pt x="589" y="1739" on="0"/>
+ <pt x="612" y="1838" on="1"/>
+ <pt x="674" y="1838" on="1"/>
+ <pt x="646" y="1699" on="0"/>
+ <pt x="578" y="1646" on="1"/>
+ <pt x="524" y="1604" on="0"/>
+ <pt x="447" y="1604" on="1"/>
+ <pt x="384" y="1604" on="0"/>
+ <pt x="329" y="1642" on="1"/>
+ <pt x="294" y="1666" on="1"/>
+ <pt x="239" y="1704" on="0"/>
+ <pt x="187" y="1704" on="1"/>
+ <pt x="99" y="1704" on="0"/>
+ <pt x="70" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 57 20 40 45 20 52 48 84 0 29 19 28 18 11 1 10 59 48 47 36 4 13 52
+ 40 10 29 28 1 0 11 10 0 14 29 0 28 19 11 18 10 1 48 47 2 13 18 59 36
+ 0 0 0 19 18 37 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="J" xMin="0" yMin="-297" xMax="766" yMax="1480">
+ <contour>
+ <pt x="0" y="-276" on="1"/>
+ <pt x="0" y="-46" on="1"/>
+ <pt x="117" y="-46" on="1"/>
+ <pt x="119" y="-70" on="1"/>
+ <pt x="127" y="-160" on="0"/>
+ <pt x="147" y="-185" on="1"/>
+ <pt x="171" y="-215" on="0"/>
+ <pt x="234" y="-215" on="1"/>
+ <pt x="333" y="-215" on="0"/>
+ <pt x="353" y="-124" on="1"/>
+ <pt x="371" y="-45" on="0"/>
+ <pt x="371" y="148" on="1"/>
+ <pt x="371" y="1221" on="1"/>
+ <pt x="372" y="1340" on="0"/>
+ <pt x="354" y="1377" on="1"/>
+ <pt x="339" y="1409" on="0"/>
+ <pt x="273" y="1413" on="1"/>
+ <pt x="205" y="1417" on="1"/>
+ <pt x="186" y="1419" on="1"/>
+ <pt x="186" y="1480" on="1"/>
+ <pt x="766" y="1480" on="1"/>
+ <pt x="766" y="1419" on="1"/>
+ <pt x="747" y="1417" on="1"/>
+ <pt x="680" y="1413" on="1"/>
+ <pt x="612" y="1408" on="0"/>
+ <pt x="601" y="1386" on="1"/>
+ <pt x="590" y="1366" on="0"/>
+ <pt x="587" y="1320" on="1"/>
+ <pt x="581" y="1221" on="1"/>
+ <pt x="581" y="270" on="1"/>
+ <pt x="581" y="-35" on="0"/>
+ <pt x="482" y="-156" on="1"/>
+ <pt x="366" y="-297" on="0"/>
+ <pt x="159" y="-297" on="1"/>
+ <pt x="97" y="-297" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 0 0 7 7 33 48 84 12 19 1 29 28 21 11 4 19 2 3 0 1 2 1 0 3 13
+ 33 2 0 20 19 0 14 19 12 2 11 0 2 21 20 2 13 28 0 0 29 28 32 1 11
+ 1 4 48 196 12 11 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Jcircumflex" xMin="0" yMin="-297" xMax="827" yMax="1925">
+ <contour>
+ <pt x="0" y="-276" on="1"/>
+ <pt x="0" y="-46" on="1"/>
+ <pt x="117" y="-46" on="1"/>
+ <pt x="119" y="-70" on="1"/>
+ <pt x="127" y="-160" on="0"/>
+ <pt x="147" y="-185" on="1"/>
+ <pt x="171" y="-215" on="0"/>
+ <pt x="234" y="-215" on="1"/>
+ <pt x="333" y="-215" on="0"/>
+ <pt x="353" y="-124" on="1"/>
+ <pt x="371" y="-45" on="0"/>
+ <pt x="371" y="148" on="1"/>
+ <pt x="371" y="1221" on="1"/>
+ <pt x="372" y="1340" on="0"/>
+ <pt x="354" y="1377" on="1"/>
+ <pt x="339" y="1409" on="0"/>
+ <pt x="273" y="1413" on="1"/>
+ <pt x="205" y="1417" on="1"/>
+ <pt x="186" y="1419" on="1"/>
+ <pt x="186" y="1480" on="1"/>
+ <pt x="766" y="1480" on="1"/>
+ <pt x="766" y="1419" on="1"/>
+ <pt x="747" y="1417" on="1"/>
+ <pt x="680" y="1413" on="1"/>
+ <pt x="612" y="1408" on="0"/>
+ <pt x="601" y="1386" on="1"/>
+ <pt x="590" y="1366" on="0"/>
+ <pt x="587" y="1320" on="1"/>
+ <pt x="581" y="1221" on="1"/>
+ <pt x="581" y="270" on="1"/>
+ <pt x="581" y="-35" on="0"/>
+ <pt x="482" y="-156" on="1"/>
+ <pt x="366" y="-297" on="0"/>
+ <pt x="159" y="-297" on="1"/>
+ <pt x="97" y="-297" on="0"/>
+ </contour>
+ <contour>
+ <pt x="124" y="1604" on="1"/>
+ <pt x="365" y="1925" on="1"/>
+ <pt x="587" y="1925" on="1"/>
+ <pt x="827" y="1604" on="1"/>
+ <pt x="741" y="1604" on="1"/>
+ <pt x="476" y="1826" on="1"/>
+ <pt x="210" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 7 7 33 48 84 12 19 41 40 39 38 35 5 36 19 3 1 29 28 21 11 4 19
+ 2 3 0 1 2 1 0 3 13 33 2 0 37 36 1 0 20 19 0 14 19 12 40 28 11
+ 2 41 36 35 2 4 11 0 3 39 38 37 21 20 5 13 28 0 0 29 28 32 1 11 1
+ 4 48 196 12 11 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="K" xMin="56" yMin="0" xMax="1463" yMax="1480">
+ <contour>
+ <pt x="451" y="754" on="1"/>
+ <pt x="899" y="1221" on="1"/>
+ <pt x="950" y="1275" on="0"/>
+ <pt x="983" y="1322" on="1"/>
+ <pt x="1018" y="1371" on="0"/>
+ <pt x="1036" y="1387" on="1"/>
+ <pt x="1046" y="1397" on="0"/>
+ <pt x="1046" y="1402" on="1"/>
+ <pt x="1046" y="1416" on="0"/>
+ <pt x="990" y="1417" on="1"/>
+ <pt x="901" y="1419" on="1"/>
+ <pt x="883" y="1419" on="1"/>
+ <pt x="883" y="1480" on="1"/>
+ <pt x="1339" y="1480" on="1"/>
+ <pt x="1339" y="1419" on="1"/>
+ <pt x="1322" y="1417" on="1"/>
+ <pt x="1261" y="1416" on="1"/>
+ <pt x="1207" y="1416" on="0"/>
+ <pt x="1160" y="1377" on="1"/>
+ <pt x="1115" y="1341" on="0"/>
+ <pt x="996" y="1220" on="1"/>
+ <pt x="618" y="835" on="1"/>
+ <pt x="1136" y="258" on="1"/>
+ <pt x="1240" y="150" on="1"/>
+ <pt x="1303" y="84" on="0"/>
+ <pt x="1334" y="76" on="1"/>
+ <pt x="1365" y="67" on="0"/>
+ <pt x="1442" y="63" on="1"/>
+ <pt x="1463" y="62" on="1"/>
+ <pt x="1463" y="0" on="1"/>
+ <pt x="858" y="0" on="1"/>
+ <pt x="858" y="62" on="1"/>
+ <pt x="876" y="62" on="1"/>
+ <pt x="1000" y="62" on="0"/>
+ <pt x="1000" y="86" on="1"/>
+ <pt x="1000" y="120" on="0"/>
+ <pt x="876" y="262" on="1"/>
+ <pt x="451" y="748" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="456" y="160" on="1"/>
+ <pt x="458" y="90" on="0"/>
+ <pt x="484" y="79" on="1"/>
+ <pt x="510" y="69" on="0"/>
+ <pt x="593" y="63" on="1"/>
+ <pt x="611" y="62" on="1"/>
+ <pt x="611" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 71 64 54 63 53 46 44 38 37 32 31 28 22 21 14 11 10 0 12 12 29 3 46 45 30
+ 29 3 0 64 63 13 12 0 3 14 64 71 63 54 46 53 45 44 32 31 30 29 28 22 21
+ 14 13 12 11 10 14 13 34 7 0 0 0 71 38 37 0 32 3 53 1 4 48 196 54 53
+ 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Kcommaaccent" xMin="56" yMin="-432" xMax="1463" yMax="1480">
+ <contour>
+ <pt x="451" y="754" on="1"/>
+ <pt x="899" y="1221" on="1"/>
+ <pt x="950" y="1274" on="0"/>
+ <pt x="983" y="1322" on="1"/>
+ <pt x="1018" y="1371" on="0"/>
+ <pt x="1036" y="1387" on="1"/>
+ <pt x="1046" y="1397" on="0"/>
+ <pt x="1046" y="1402" on="1"/>
+ <pt x="1046" y="1416" on="0"/>
+ <pt x="990" y="1417" on="1"/>
+ <pt x="901" y="1419" on="1"/>
+ <pt x="883" y="1419" on="1"/>
+ <pt x="883" y="1480" on="1"/>
+ <pt x="1339" y="1480" on="1"/>
+ <pt x="1339" y="1419" on="1"/>
+ <pt x="1322" y="1417" on="1"/>
+ <pt x="1261" y="1416" on="1"/>
+ <pt x="1207" y="1416" on="0"/>
+ <pt x="1160" y="1377" on="1"/>
+ <pt x="1115" y="1341" on="0"/>
+ <pt x="996" y="1220" on="1"/>
+ <pt x="618" y="835" on="1"/>
+ <pt x="1136" y="258" on="1"/>
+ <pt x="1240" y="150" on="1"/>
+ <pt x="1303" y="84" on="0"/>
+ <pt x="1334" y="76" on="1"/>
+ <pt x="1365" y="67" on="0"/>
+ <pt x="1442" y="63" on="1"/>
+ <pt x="1463" y="62" on="1"/>
+ <pt x="1463" y="0" on="1"/>
+ <pt x="858" y="0" on="1"/>
+ <pt x="858" y="62" on="1"/>
+ <pt x="876" y="62" on="1"/>
+ <pt x="1000" y="62" on="0"/>
+ <pt x="1000" y="86" on="1"/>
+ <pt x="1000" y="120" on="0"/>
+ <pt x="876" y="262" on="1"/>
+ <pt x="451" y="748" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="456" y="160" on="1"/>
+ <pt x="458" y="90" on="0"/>
+ <pt x="484" y="79" on="1"/>
+ <pt x="510" y="69" on="0"/>
+ <pt x="593" y="63" on="1"/>
+ <pt x="611" y="62" on="1"/>
+ <pt x="611" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ </contour>
+ <contour>
+ <pt x="562" y="-421" on="1"/>
+ <pt x="562" y="-349" on="1"/>
+ <pt x="611" y="-359" on="0"/>
+ <pt x="666" y="-359" on="1"/>
+ <pt x="769" y="-359" on="0"/>
+ <pt x="769" y="-279" on="1"/>
+ <pt x="769" y="-190" on="0"/>
+ <pt x="611" y="-175" on="1"/>
+ <pt x="611" y="-111" on="1"/>
+ <pt x="745" y="-114" on="0"/>
+ <pt x="811" y="-143" on="1"/>
+ <pt x="904" y="-185" on="0"/>
+ <pt x="904" y="-280" on="1"/>
+ <pt x="904" y="-432" on="0"/>
+ <pt x="687" y="-432" on="1"/>
+ <pt x="628" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 106 values pushed */
+ 0 0 75 17 86 48 84 71 64 54 63 53 46 44 38 37 32 31 28 22 21 14 11 10 0
+ 12 12 29 3 80 79 73 72 4 13 86 29 46 45 30 29 3 0 64 63 13 12 0 3 14
+ 0 0 77 48 84 48 196 64 71 63 54 46 53 80 79 73 72 45 44 32 31 30 29 28 22
+ 21 14 13 12 11 10 18 13 84 34 7 3 12 0 0 0 71 38 37 0 32 3 53 1 4
+ 48 196 54 53 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="L" xMin="56" yMin="0" xMax="1203" yMax="1480">
+ <contour>
+ <pt x="1096" y="276" on="1"/>
+ <pt x="1098" y="296" on="1"/>
+ <pt x="1203" y="296" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="451" y="108" on="0"/>
+ <pt x="478" y="101" on="1"/>
+ <pt x="509" y="86" on="0"/>
+ <pt x="623" y="86" on="1"/>
+ <pt x="859" y="86" on="1"/>
+ <pt x="1001" y="86" on="0"/>
+ <pt x="1046" y="103" on="1"/>
+ <pt x="1092" y="121" on="0"/>
+ <pt x="1094" y="175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 29 22 12 21 11 4 32 30 2 1 4 21 34 3 0 0 35 34 7 1 3 1 4 48 84
+ 4 3 1 0 22 21 0 14 22 29 21 12 4 11 35 34 32 1 4 2 29 3 0 0 30
+ 29 32 1 11 1 4 48 196 3 2 1 12 11 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lacute" xMin="56" yMin="0" xMax="1203" yMax="1925">
+ <contour>
+ <pt x="1096" y="276" on="1"/>
+ <pt x="1098" y="296" on="1"/>
+ <pt x="1203" y="296" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="451" y="108" on="0"/>
+ <pt x="478" y="101" on="1"/>
+ <pt x="509" y="86" on="0"/>
+ <pt x="623" y="86" on="1"/>
+ <pt x="859" y="86" on="1"/>
+ <pt x="1001" y="86" on="0"/>
+ <pt x="1046" y="103" on="1"/>
+ <pt x="1092" y="121" on="0"/>
+ <pt x="1094" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="309" y="1604" on="1"/>
+ <pt x="550" y="1925" on="1"/>
+ <pt x="809" y="1925" on="1"/>
+ <pt x="402" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 29 22 12 21 11 4 43 40 2 41 21 3 32 30 2 1 4 21 34 3 0 0 35 34 7
+ 1 3 1 4 48 84 42 41 1 4 3 1 2 0 22 21 0 14 22 29 21 12 4 11 42
+ 41 35 34 32 1 6 2 29 3 43 40 2 29 11 3 0 0 30 29 32 1 11 1 4 48
+ 196 3 2 1 12 11 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lcaron" xMin="56" yMin="0" xMax="1203" yMax="1480">
+ <contour>
+ <pt x="1096" y="276" on="1"/>
+ <pt x="1098" y="296" on="1"/>
+ <pt x="1203" y="296" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="451" y="108" on="0"/>
+ <pt x="478" y="101" on="1"/>
+ <pt x="509" y="86" on="0"/>
+ <pt x="623" y="86" on="1"/>
+ <pt x="859" y="86" on="1"/>
+ <pt x="1001" y="86" on="0"/>
+ <pt x="1046" y="103" on="1"/>
+ <pt x="1092" y="121" on="0"/>
+ <pt x="1094" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="888" y="1283" on="1"/>
+ <pt x="809" y="1283" on="1"/>
+ <pt x="809" y="1480" on="1"/>
+ <pt x="1006" y="1480" on="1"/>
+ <pt x="1006" y="1309" on="1"/>
+ <pt x="1006" y="1146" on="0"/>
+ <pt x="944" y="1081" on="1"/>
+ <pt x="897" y="1032" on="0"/>
+ <pt x="809" y="1026" on="1"/>
+ <pt x="809" y="1076" on="1"/>
+ <pt x="888" y="1082" on="0"/>
+ <pt x="888" y="1231" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 94 values pushed */
+ 29 22 12 21 11 4 51 49 48 44 41 40 32 30 2 1 10 21 34 3 0 0 35 34 7
+ 1 3 1 4 48 84 4 3 1 0 43 42 22 21 0 3 14 22 29 21 12 4 11 1 2
+ 43 2 51 40 35 3 43 41 3 34 32 2 41 29 3 0 0 49 48 42 41 4 3 43 30
+ 29 32 1 11 2 4 48 196 44 43 1 3 2 1 12 11 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lcommaaccent" xMin="56" yMin="-432" xMax="1203" yMax="1480">
+ <contour>
+ <pt x="1096" y="276" on="1"/>
+ <pt x="1098" y="296" on="1"/>
+ <pt x="1203" y="296" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="451" y="108" on="0"/>
+ <pt x="478" y="101" on="1"/>
+ <pt x="509" y="86" on="0"/>
+ <pt x="623" y="86" on="1"/>
+ <pt x="859" y="86" on="1"/>
+ <pt x="1001" y="86" on="0"/>
+ <pt x="1046" y="103" on="1"/>
+ <pt x="1092" y="121" on="0"/>
+ <pt x="1094" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="451" y="-421" on="1"/>
+ <pt x="451" y="-349" on="1"/>
+ <pt x="500" y="-359" on="0"/>
+ <pt x="555" y="-359" on="1"/>
+ <pt x="658" y="-359" on="0"/>
+ <pt x="658" y="-279" on="1"/>
+ <pt x="658" y="-190" on="0"/>
+ <pt x="500" y="-175" on="1"/>
+ <pt x="500" y="-111" on="1"/>
+ <pt x="634" y="-114" on="0"/>
+ <pt x="700" y="-143" on="1"/>
+ <pt x="793" y="-185" on="0"/>
+ <pt x="793" y="-280" on="1"/>
+ <pt x="793" y="-432" on="0"/>
+ <pt x="576" y="-432" on="1"/>
+ <pt x="517" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 94 values pushed */
+ 0 0 43 17 54 48 84 29 22 12 21 11 4 32 30 2 1 4 21 34 3 48 47 41 40
+ 4 13 54 3 0 0 35 34 7 1 3 1 4 48 84 4 3 1 0 22 21 0 14 0 0
+ 45 48 52 48 196 22 29 21 12 4 11 52 52 48 47 35 34 32 1 7 2 29 3 0 0
+ 41 40 30 29 32 3 11 1 4 48 196 3 2 1 12 11 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ldot" xMin="56" yMin="0" xMax="1203" yMax="1480">
+ <contour>
+ <pt x="1096" y="276" on="1"/>
+ <pt x="1098" y="296" on="1"/>
+ <pt x="1203" y="296" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="451" y="108" on="0"/>
+ <pt x="478" y="101" on="1"/>
+ <pt x="509" y="86" on="0"/>
+ <pt x="623" y="86" on="1"/>
+ <pt x="859" y="86" on="1"/>
+ <pt x="1001" y="86" on="0"/>
+ <pt x="1046" y="103" on="1"/>
+ <pt x="1092" y="121" on="0"/>
+ <pt x="1094" y="175" on="1"/>
+ </contour>
+ <contour>
+ <pt x="870" y="642" on="1"/>
+ <pt x="870" y="839" on="1"/>
+ <pt x="1067" y="839" on="1"/>
+ <pt x="1067" y="642" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 29 22 12 21 11 4 32 30 2 1 4 40 34 3 0 0 43 40 5 1 41 35 34 7 1
+ 3 2 4 48 84 42 41 1 4 3 1 2 0 22 21 0 14 22 29 21 12 4 11 1 2
+ 42 2 35 34 32 3 40 29 3 0 0 41 40 4 1 42 30 29 32 1 11 2 4 48 196
+ 43 42 1 3 2 1 12 11 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lslash" xMin="56" yMin="0" xMax="1203" yMax="1480">
+ <contour>
+ <pt x="241" y="748" on="1"/>
+ <pt x="56" y="641" on="1"/>
+ <pt x="56" y="726" on="1"/>
+ <pt x="241" y="833" on="1"/>
+ <pt x="241" y="1221" on="1"/>
+ <pt x="241" y="1280" on="0"/>
+ <pt x="234" y="1333" on="1"/>
+ <pt x="228" y="1372" on="0"/>
+ <pt x="220" y="1384" on="1"/>
+ <pt x="202" y="1410" on="0"/>
+ <pt x="142" y="1413" on="1"/>
+ <pt x="75" y="1417" on="1"/>
+ <pt x="56" y="1419" on="1"/>
+ <pt x="56" y="1480" on="1"/>
+ <pt x="636" y="1480" on="1"/>
+ <pt x="636" y="1419" on="1"/>
+ <pt x="617" y="1417" on="1"/>
+ <pt x="549" y="1413" on="1"/>
+ <pt x="474" y="1408" on="0"/>
+ <pt x="464" y="1366" on="1"/>
+ <pt x="451" y="1302" on="0"/>
+ <pt x="451" y="1221" on="1"/>
+ <pt x="451" y="954" on="1"/>
+ <pt x="722" y="1110" on="1"/>
+ <pt x="722" y="1025" on="1"/>
+ <pt x="451" y="869" on="1"/>
+ <pt x="451" y="259" on="1"/>
+ <pt x="451" y="108" on="0"/>
+ <pt x="478" y="101" on="1"/>
+ <pt x="509" y="86" on="0"/>
+ <pt x="623" y="86" on="1"/>
+ <pt x="859" y="86" on="1"/>
+ <pt x="1001" y="86" on="0"/>
+ <pt x="1046" y="103" on="1"/>
+ <pt x="1092" y="121" on="0"/>
+ <pt x="1094" y="175" on="1"/>
+ <pt x="1096" y="276" on="1"/>
+ <pt x="1098" y="296" on="1"/>
+ <pt x="1203" y="296" on="1"/>
+ <pt x="1203" y="0" on="1"/>
+ <pt x="56" y="0" on="1"/>
+ <pt x="56" y="62" on="1"/>
+ <pt x="75" y="63" on="1"/>
+ <pt x="142" y="68" on="1"/>
+ <pt x="218" y="74" on="0"/>
+ <pt x="228" y="115" on="1"/>
+ <pt x="241" y="177" on="0"/>
+ <pt x="241" y="259" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 47 40 21 14 4 13 38 37 28 26 25 24 23 22 3 2 1 0 12 13 30 3 0 0 31
+ 30 7 1 39 1 4 48 84 40 39 1 0 14 13 0 14 40 47 14 21 13 4 37 31 30
+ 28 24 23 6 38 21 3 2 1 0 0 0 26 25 22 21 32 3 0 1 4 48 196 39 38
+ 1 47 4 3 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="M" xMin="48" yMin="0" xMax="1773" yMax="1480">
+ <contour>
+ <pt x="461" y="1480" on="1"/>
+ <pt x="934" y="389" on="1"/>
+ <pt x="1400" y="1480" on="1"/>
+ <pt x="1773" y="1480" on="1"/>
+ <pt x="1773" y="1419" on="1"/>
+ <pt x="1754" y="1417" on="1"/>
+ <pt x="1686" y="1413" on="1"/>
+ <pt x="1618" y="1408" on="0"/>
+ <pt x="1607" y="1386" on="1"/>
+ <pt x="1597" y="1366" on="0"/>
+ <pt x="1594" y="1320" on="1"/>
+ <pt x="1588" y="1221" on="1"/>
+ <pt x="1588" y="259" on="1"/>
+ <pt x="1594" y="160" on="1"/>
+ <pt x="1598" y="93" on="0"/>
+ <pt x="1620" y="82" on="1"/>
+ <pt x="1639" y="71" on="0"/>
+ <pt x="1686" y="68" on="1"/>
+ <pt x="1754" y="63" on="1"/>
+ <pt x="1773" y="62" on="1"/>
+ <pt x="1773" y="0" on="1"/>
+ <pt x="1209" y="0" on="1"/>
+ <pt x="1209" y="62" on="1"/>
+ <pt x="1227" y="63" on="1"/>
+ <pt x="1294" y="68" on="1"/>
+ <pt x="1361" y="73" on="0"/>
+ <pt x="1372" y="95" on="1"/>
+ <pt x="1383" y="114" on="0"/>
+ <pt x="1386" y="160" on="1"/>
+ <pt x="1392" y="259" on="1"/>
+ <pt x="1392" y="1276" on="1"/>
+ <pt x="901" y="118" on="1"/>
+ <pt x="828" y="118" on="1"/>
+ <pt x="343" y="1231" on="1"/>
+ <pt x="343" y="259" on="1"/>
+ <pt x="343" y="203" on="0"/>
+ <pt x="351" y="147" on="1"/>
+ <pt x="358" y="96" on="0"/>
+ <pt x="383" y="82" on="1"/>
+ <pt x="404" y="71" on="0"/>
+ <pt x="442" y="68" on="1"/>
+ <pt x="510" y="63" on="1"/>
+ <pt x="528" y="62" on="1"/>
+ <pt x="528" y="0" on="1"/>
+ <pt x="48" y="0" on="1"/>
+ <pt x="48" y="62" on="1"/>
+ <pt x="67" y="63" on="1"/>
+ <pt x="135" y="68" on="1"/>
+ <pt x="199" y="73" on="0"/>
+ <pt x="233" y="139" on="0"/>
+ <pt x="233" y="259" on="1"/>
+ <pt x="234" y="1221" on="1"/>
+ <pt x="235" y="1335" on="0"/>
+ <pt x="216" y="1377" on="1"/>
+ <pt x="201" y="1409" on="0"/>
+ <pt x="135" y="1413" on="1"/>
+ <pt x="67" y="1417" on="1"/>
+ <pt x="48" y="1419" on="1"/>
+ <pt x="48" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 51 58 50 44 34 43 33 32 31 30 29 22 19 12 11 4 1 11 0 20 3 44 43 21 20
+ 3 0 58 3 2 0 0 3 14 58 51 44 50 43 34 2 11 29 2 32 31 22 21 1 0
+ 6 29 33 3 20 19 4 3 4 13 11 51 50 33 0 0 30 29 4 1 11 1 4 48 196
+ 12 11 1 34 33 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="N" xMin="43" yMin="-20" xMax="1435" yMax="1480">
+ <contour>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="1159" y="331" on="1"/>
+ <pt x="1159" y="1221" on="1"/>
+ <pt x="1153" y="1320" on="1"/>
+ <pt x="1149" y="1387" on="0"/>
+ <pt x="1127" y="1399" on="1"/>
+ <pt x="1107" y="1410" on="0"/>
+ <pt x="1061" y="1413" on="1"/>
+ <pt x="993" y="1417" on="1"/>
+ <pt x="974" y="1419" on="1"/>
+ <pt x="974" y="1480" on="1"/>
+ <pt x="1435" y="1480" on="1"/>
+ <pt x="1435" y="1419" on="1"/>
+ <pt x="1417" y="1417" on="1"/>
+ <pt x="1349" y="1413" on="1"/>
+ <pt x="1281" y="1409" on="0"/>
+ <pt x="1270" y="1386" on="1"/>
+ <pt x="1259" y="1366" on="0"/>
+ <pt x="1256" y="1320" on="1"/>
+ <pt x="1250" y="1221" on="1"/>
+ <pt x="1250" y="-20" on="1"/>
+ <pt x="1180" y="-20" on="1"/>
+ <pt x="322" y="1220" on="1"/>
+ <pt x="322" y="259" on="1"/>
+ <pt x="321" y="144" on="0"/>
+ <pt x="340" y="104" on="1"/>
+ <pt x="355" y="72" on="0"/>
+ <pt x="421" y="68" on="1"/>
+ <pt x="489" y="63" on="1"/>
+ <pt x="508" y="62" on="1"/>
+ <pt x="508" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="130" y="68" on="1"/>
+ <pt x="194" y="73" on="0"/>
+ <pt x="229" y="140" on="0"/>
+ <pt x="229" y="259" on="1"/>
+ <pt x="229" y="1221" on="1"/>
+ <pt x="230" y="1336" on="0"/>
+ <pt x="211" y="1377" on="1"/>
+ <pt x="196" y="1409" on="0"/>
+ <pt x="130" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 38 45 37 31 23 30 22 19 12 9 2 1 6 0 30 3 21 20 30 31 30 1 0 45 11
+ 10 0 0 3 14 45 38 31 37 30 23 21 19 1 2 10 9 0 3 1 22 3 12 11 2
+ 13 19 0 0 2 1 35 1 19 23 22 35 1 37 2 4 48 196 20 19 1 38 37 1 2
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Nacute" xMin="43" yMin="-20" xMax="1435" yMax="1925">
+ <contour>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="1159" y="331" on="1"/>
+ <pt x="1159" y="1221" on="1"/>
+ <pt x="1153" y="1320" on="1"/>
+ <pt x="1149" y="1387" on="0"/>
+ <pt x="1127" y="1399" on="1"/>
+ <pt x="1107" y="1410" on="0"/>
+ <pt x="1061" y="1413" on="1"/>
+ <pt x="993" y="1417" on="1"/>
+ <pt x="974" y="1419" on="1"/>
+ <pt x="974" y="1480" on="1"/>
+ <pt x="1435" y="1480" on="1"/>
+ <pt x="1435" y="1419" on="1"/>
+ <pt x="1417" y="1417" on="1"/>
+ <pt x="1349" y="1413" on="1"/>
+ <pt x="1281" y="1409" on="0"/>
+ <pt x="1270" y="1386" on="1"/>
+ <pt x="1259" y="1366" on="0"/>
+ <pt x="1256" y="1320" on="1"/>
+ <pt x="1250" y="1221" on="1"/>
+ <pt x="1250" y="-20" on="1"/>
+ <pt x="1180" y="-20" on="1"/>
+ <pt x="322" y="1220" on="1"/>
+ <pt x="322" y="259" on="1"/>
+ <pt x="321" y="144" on="0"/>
+ <pt x="340" y="104" on="1"/>
+ <pt x="355" y="72" on="0"/>
+ <pt x="421" y="68" on="1"/>
+ <pt x="489" y="63" on="1"/>
+ <pt x="508" y="62" on="1"/>
+ <pt x="508" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="130" y="68" on="1"/>
+ <pt x="194" y="73" on="0"/>
+ <pt x="229" y="140" on="0"/>
+ <pt x="229" y="259" on="1"/>
+ <pt x="229" y="1221" on="1"/>
+ <pt x="230" y="1336" on="0"/>
+ <pt x="211" y="1377" on="1"/>
+ <pt x="196" y="1409" on="0"/>
+ <pt x="130" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="646" y="1604" on="1"/>
+ <pt x="887" y="1925" on="1"/>
+ <pt x="1146" y="1925" on="1"/>
+ <pt x="739" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 38 45 37 31 23 30 49 46 2 47 0 3 22 19 12 9 2 1 6 0 30 3 21 20 30
+ 48 47 1 31 30 1 2 0 45 11 10 0 0 3 14 45 38 31 37 30 23 21 19 1 2
+ 49 48 47 46 10 9 0 7 1 22 3 12 11 2 13 19 0 0 2 1 35 1 19 23 22
+ 35 1 37 2 4 48 196 20 19 1 38 37 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ncaron" xMin="43" yMin="-20" xMax="1435" yMax="1925">
+ <contour>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="1159" y="331" on="1"/>
+ <pt x="1159" y="1221" on="1"/>
+ <pt x="1153" y="1320" on="1"/>
+ <pt x="1149" y="1387" on="0"/>
+ <pt x="1127" y="1399" on="1"/>
+ <pt x="1107" y="1410" on="0"/>
+ <pt x="1061" y="1413" on="1"/>
+ <pt x="993" y="1417" on="1"/>
+ <pt x="974" y="1419" on="1"/>
+ <pt x="974" y="1480" on="1"/>
+ <pt x="1435" y="1480" on="1"/>
+ <pt x="1435" y="1419" on="1"/>
+ <pt x="1417" y="1417" on="1"/>
+ <pt x="1349" y="1413" on="1"/>
+ <pt x="1281" y="1409" on="0"/>
+ <pt x="1270" y="1386" on="1"/>
+ <pt x="1259" y="1366" on="0"/>
+ <pt x="1256" y="1320" on="1"/>
+ <pt x="1250" y="1221" on="1"/>
+ <pt x="1250" y="-20" on="1"/>
+ <pt x="1180" y="-20" on="1"/>
+ <pt x="322" y="1220" on="1"/>
+ <pt x="322" y="259" on="1"/>
+ <pt x="321" y="144" on="0"/>
+ <pt x="340" y="104" on="1"/>
+ <pt x="355" y="72" on="0"/>
+ <pt x="421" y="68" on="1"/>
+ <pt x="489" y="63" on="1"/>
+ <pt x="508" y="62" on="1"/>
+ <pt x="508" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="130" y="68" on="1"/>
+ <pt x="194" y="73" on="0"/>
+ <pt x="229" y="140" on="0"/>
+ <pt x="229" y="259" on="1"/>
+ <pt x="229" y="1221" on="1"/>
+ <pt x="230" y="1336" on="0"/>
+ <pt x="211" y="1377" on="1"/>
+ <pt x="196" y="1409" on="0"/>
+ <pt x="130" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1073" y="1925" on="1"/>
+ <pt x="833" y="1604" on="1"/>
+ <pt x="611" y="1604" on="1"/>
+ <pt x="370" y="1925" on="1"/>
+ <pt x="456" y="1925" on="1"/>
+ <pt x="722" y="1703" on="1"/>
+ <pt x="987" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 95 values pushed */
+ 38 45 37 31 23 30 22 19 12 9 2 1 6 0 30 3 52 51 50 49 46 5 13 47 21
+ 20 30 48 47 1 31 30 1 2 0 45 11 10 0 0 3 14 45 38 31 37 30 23 21 19
+ 1 2 52 51 50 49 48 47 46 10 9 0 10 1 22 3 12 11 2 13 19 0 0 2 1
+ 35 1 19 23 22 35 1 37 2 4 48 196 20 19 1 38 37 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ncommaaccent" xMin="43" yMin="-432" xMax="1435" yMax="1480">
+ <contour>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="1159" y="331" on="1"/>
+ <pt x="1159" y="1221" on="1"/>
+ <pt x="1153" y="1320" on="1"/>
+ <pt x="1150" y="1384" on="0"/>
+ <pt x="1130" y="1397" on="1"/>
+ <pt x="1112" y="1410" on="0"/>
+ <pt x="1061" y="1413" on="1"/>
+ <pt x="993" y="1417" on="1"/>
+ <pt x="974" y="1419" on="1"/>
+ <pt x="974" y="1480" on="1"/>
+ <pt x="1435" y="1480" on="1"/>
+ <pt x="1435" y="1419" on="1"/>
+ <pt x="1417" y="1417" on="1"/>
+ <pt x="1349" y="1413" on="1"/>
+ <pt x="1281" y="1408" on="0"/>
+ <pt x="1270" y="1386" on="1"/>
+ <pt x="1259" y="1367" on="0"/>
+ <pt x="1256" y="1320" on="1"/>
+ <pt x="1250" y="1221" on="1"/>
+ <pt x="1250" y="-20" on="1"/>
+ <pt x="1180" y="-20" on="1"/>
+ <pt x="322" y="1220" on="1"/>
+ <pt x="322" y="259" on="1"/>
+ <pt x="321" y="144" on="0"/>
+ <pt x="340" y="104" on="1"/>
+ <pt x="355" y="72" on="0"/>
+ <pt x="421" y="68" on="1"/>
+ <pt x="489" y="63" on="1"/>
+ <pt x="508" y="62" on="1"/>
+ <pt x="508" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="130" y="68" on="1"/>
+ <pt x="194" y="73" on="0"/>
+ <pt x="229" y="140" on="0"/>
+ <pt x="229" y="259" on="1"/>
+ <pt x="229" y="1221" on="1"/>
+ <pt x="230" y="1335" on="0"/>
+ <pt x="211" y="1377" on="1"/>
+ <pt x="196" y="1409" on="0"/>
+ <pt x="130" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="582" y="-421" on="1"/>
+ <pt x="582" y="-349" on="1"/>
+ <pt x="631" y="-359" on="0"/>
+ <pt x="686" y="-359" on="1"/>
+ <pt x="789" y="-359" on="0"/>
+ <pt x="789" y="-279" on="1"/>
+ <pt x="789" y="-190" on="0"/>
+ <pt x="631" y="-175" on="1"/>
+ <pt x="631" y="-111" on="1"/>
+ <pt x="765" y="-114" on="0"/>
+ <pt x="831" y="-143" on="1"/>
+ <pt x="924" y="-185" on="0"/>
+ <pt x="924" y="-280" on="1"/>
+ <pt x="924" y="-432" on="0"/>
+ <pt x="707" y="-432" on="1"/>
+ <pt x="647" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 49 17 60 48 84 38 45 37 31 23 30 22 19 12 9 2 1 6 0 30 3 54 53
+ 47 46 21 20 6 13 60 30 31 30 1 0 45 11 10 0 0 3 14 0 0 51 48 58 48
+ 196 45 38 31 37 30 23 21 19 1 2 58 58 54 53 47 46 10 9 0 8 1 22 3 12
+ 11 2 13 19 0 0 2 1 35 1 19 23 22 35 1 37 2 4 48 196 20 19 1 38 37
+ 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ntilde" xMin="43" yMin="-20" xMax="1435" yMax="1839">
+ <contour>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="1159" y="331" on="1"/>
+ <pt x="1159" y="1221" on="1"/>
+ <pt x="1153" y="1320" on="1"/>
+ <pt x="1149" y="1387" on="0"/>
+ <pt x="1127" y="1399" on="1"/>
+ <pt x="1107" y="1410" on="0"/>
+ <pt x="1061" y="1413" on="1"/>
+ <pt x="993" y="1417" on="1"/>
+ <pt x="974" y="1419" on="1"/>
+ <pt x="974" y="1480" on="1"/>
+ <pt x="1435" y="1480" on="1"/>
+ <pt x="1435" y="1419" on="1"/>
+ <pt x="1417" y="1417" on="1"/>
+ <pt x="1349" y="1413" on="1"/>
+ <pt x="1281" y="1409" on="0"/>
+ <pt x="1270" y="1386" on="1"/>
+ <pt x="1259" y="1366" on="0"/>
+ <pt x="1256" y="1320" on="1"/>
+ <pt x="1250" y="1221" on="1"/>
+ <pt x="1250" y="-20" on="1"/>
+ <pt x="1180" y="-20" on="1"/>
+ <pt x="322" y="1220" on="1"/>
+ <pt x="322" y="259" on="1"/>
+ <pt x="321" y="144" on="0"/>
+ <pt x="340" y="104" on="1"/>
+ <pt x="355" y="72" on="0"/>
+ <pt x="421" y="68" on="1"/>
+ <pt x="489" y="63" on="1"/>
+ <pt x="508" y="62" on="1"/>
+ <pt x="508" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="130" y="68" on="1"/>
+ <pt x="194" y="73" on="0"/>
+ <pt x="229" y="140" on="0"/>
+ <pt x="229" y="259" on="1"/>
+ <pt x="229" y="1221" on="1"/>
+ <pt x="230" y="1336" on="0"/>
+ <pt x="211" y="1377" on="1"/>
+ <pt x="196" y="1409" on="0"/>
+ <pt x="130" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="425" y="1604" on="1"/>
+ <pt x="452" y="1744" on="0"/>
+ <pt x="521" y="1797" on="1"/>
+ <pt x="574" y="1839" on="0"/>
+ <pt x="652" y="1839" on="1"/>
+ <pt x="717" y="1839" on="0"/>
+ <pt x="770" y="1801" on="1"/>
+ <pt x="805" y="1776" on="1"/>
+ <pt x="857" y="1739" on="0"/>
+ <pt x="911" y="1739" on="1"/>
+ <pt x="1007" y="1739" on="0"/>
+ <pt x="1029" y="1838" on="1"/>
+ <pt x="1091" y="1838" on="1"/>
+ <pt x="1063" y="1699" on="0"/>
+ <pt x="995" y="1646" on="1"/>
+ <pt x="941" y="1604" on="0"/>
+ <pt x="864" y="1604" on="1"/>
+ <pt x="801" y="1604" on="0"/>
+ <pt x="746" y="1642" on="1"/>
+ <pt x="711" y="1666" on="1"/>
+ <pt x="656" y="1704" on="0"/>
+ <pt x="604" y="1704" on="1"/>
+ <pt x="516" y="1704" on="0"/>
+ <pt x="487" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 99 values pushed */
+ 0 0 67 20 50 55 20 62 48 84 38 45 37 31 23 30 22 19 12 9 2 1 6 0 30
+ 3 69 58 57 46 4 13 62 50 0 21 20 30 31 30 1 0 45 11 10 0 0 3 14 45
+ 38 31 37 30 23 21 19 1 2 69 58 57 46 10 9 0 7 1 22 3 12 11 2 13 19
+ 0 0 2 1 35 1 19 23 22 35 1 37 2 4 48 196 20 19 1 38 37 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="O" xMin="80" yMin="-37" xMax="1398" yMax="1517">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 2 0 0 14 0 0 28 34 4 20 34 12 48 196
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="OE" xMin="80" yMin="-37" xMax="1771" yMax="1517">
+ <contour>
+ <pt x="973" y="1408" on="1"/>
+ <pt x="973" y="1480" on="1"/>
+ <pt x="1715" y="1480" on="1"/>
+ <pt x="1715" y="1221" on="1"/>
+ <pt x="1604" y="1221" on="1"/>
+ <pt x="1603" y="1240" on="1"/>
+ <pt x="1601" y="1274" on="1"/>
+ <pt x="1598" y="1311" on="0"/>
+ <pt x="1598" y="1321" on="1"/>
+ <pt x="1598" y="1324" on="1"/>
+ <pt x="1598" y="1378" on="0"/>
+ <pt x="1581" y="1389" on="1"/>
+ <pt x="1566" y="1399" on="0"/>
+ <pt x="1525" y="1399" on="1"/>
+ <pt x="1422" y="1400" on="1"/>
+ <pt x="1198" y="1400" on="1"/>
+ <pt x="1198" y="808" on="1"/>
+ <pt x="1382" y="809" on="1"/>
+ <pt x="1445" y="811" on="1"/>
+ <pt x="1495" y="812" on="0"/>
+ <pt x="1504" y="825" on="1"/>
+ <pt x="1512" y="836" on="0"/>
+ <pt x="1514" y="867" on="1"/>
+ <pt x="1514" y="869" on="1"/>
+ <pt x="1514" y="871" on="1"/>
+ <pt x="1515" y="881" on="1"/>
+ <pt x="1515" y="885" on="0"/>
+ <pt x="1516" y="895" on="1"/>
+ <pt x="1517" y="911" on="0"/>
+ <pt x="1517" y="913" on="1"/>
+ <pt x="1518" y="931" on="1"/>
+ <pt x="1610" y="931" on="1"/>
+ <pt x="1610" y="605" on="1"/>
+ <pt x="1518" y="605" on="1"/>
+ <pt x="1517" y="623" on="1"/>
+ <pt x="1511" y="711" on="0"/>
+ <pt x="1486" y="717" on="1"/>
+ <pt x="1461" y="728" on="0"/>
+ <pt x="1382" y="728" on="1"/>
+ <pt x="1198" y="728" on="1"/>
+ <pt x="1198" y="259" on="1"/>
+ <pt x="1198" y="122" on="0"/>
+ <pt x="1238" y="105" on="1"/>
+ <pt x="1274" y="86" on="0"/>
+ <pt x="1369" y="86" on="1"/>
+ <pt x="1466" y="86" on="1"/>
+ <pt x="1567" y="92" on="1"/>
+ <pt x="1650" y="97" on="0"/>
+ <pt x="1655" y="162" on="1"/>
+ <pt x="1658" y="234" on="1"/>
+ <pt x="1660" y="253" on="1"/>
+ <pt x="1771" y="253" on="1"/>
+ <pt x="1771" y="0" on="1"/>
+ <pt x="973" y="0" on="1"/>
+ <pt x="973" y="73" on="1"/>
+ <pt x="904" y="15" on="0"/>
+ <pt x="856" y="-6" on="1"/>
+ <pt x="828" y="-19" on="0"/>
+ <pt x="786" y="-26" on="1"/>
+ <pt x="721" y="-37" on="0"/>
+ <pt x="681" y="-37" on="1"/>
+ <pt x="629" y="-37" on="0"/>
+ <pt x="524" y="-12" on="1"/>
+ <pt x="379" y="23" on="0"/>
+ <pt x="281" y="134" on="1"/>
+ <pt x="80" y="363" on="0"/>
+ <pt x="80" y="741" on="1"/>
+ <pt x="80" y="1091" on="0"/>
+ <pt x="246" y="1304" on="1"/>
+ <pt x="411" y="1517" on="0"/>
+ <pt x="678" y="1517" on="1"/>
+ <pt x="842" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="973" y="610" on="1"/>
+ <pt x="973" y="870" on="1"/>
+ <pt x="973" y="1190" on="0"/>
+ <pt x="910" y="1320" on="1"/>
+ <pt x="848" y="1450" on="0"/>
+ <pt x="694" y="1450" on="1"/>
+ <pt x="516" y="1450" on="0"/>
+ <pt x="410" y="1255" on="1"/>
+ <pt x="303" y="1060" on="0"/>
+ <pt x="303" y="740" on="1"/>
+ <pt x="303" y="420" on="0"/>
+ <pt x="410" y="226" on="1"/>
+ <pt x="516" y="31" on="0"/>
+ <pt x="694" y="31" on="1"/>
+ <pt x="864" y="31" on="0"/>
+ <pt x="924" y="194" on="1"/>
+ <pt x="973" y="327" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 133 values pushed */
+ 0 0 85 17 60 77 17 70 48 84 70 0 60 2 0 1 14 2 73 31 30 24 23 22 16
+ 9 8 4 3 11 14 38 3 72 54 51 50 45 44 42 40 36 33 32 11 38 52 3 0 0
+ 15 14 21 1 1 1 4 48 84 39 38 1 53 52 1 2 0 2 1 0 14 0 0 81 33
+ 66 48 196 50 2 31 2 45 44 42 38 36 33 30 24 23 22 14 9 8 4 14 31 15 3
+ 66 0 0 0 73 72 54 53 1 0 36 5 15 1 4 48 196 52 51 1 3 2 1 32 31
+ 1 40 39 16 15 3 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Oacute" xMin="80" yMin="-37" xMax="1398" yMax="1925">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="585" y="1604" on="1"/>
+ <pt x="826" y="1925" on="1"/>
+ <pt x="1085" y="1925" on="1"/>
+ <pt x="678" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 2 0 0 1 35 32 2 33 0 3 0 34 33 1
+ 0 14 0 0 28 34 4 20 34 12 48 196 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Obreve" xMin="80" yMin="-37" xMax="1398" yMax="1925">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="406" y="1925" on="1"/>
+ <pt x="471" y="1925" on="1"/>
+ <pt x="498" y="1835" on="0"/>
+ <pt x="558" y="1793" on="1"/>
+ <pt x="626" y="1746" on="0"/>
+ <pt x="739" y="1746" on="1"/>
+ <pt x="865" y="1746" on="0"/>
+ <pt x="935" y="1805" on="1"/>
+ <pt x="984" y="1845" on="0"/>
+ <pt x="1008" y="1925" on="1"/>
+ <pt x="1072" y="1925" on="1"/>
+ <pt x="1053" y="1790" on="0"/>
+ <pt x="981" y="1709" on="1"/>
+ <pt x="887" y="1604" on="0"/>
+ <pt x="739" y="1604" on="1"/>
+ <pt x="585" y="1604" on="0"/>
+ <pt x="490" y="1719" on="1"/>
+ <pt x="425" y="1796" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 37 20 46 24 38 8 16 38 0 48 84 8 2 0 0 1 42 41 33 32 4 13 46
+ 0 0 14 0 0 28 34 4 20 34 12 48 196 42 41 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ocircumflex" xMin="80" yMin="-37" xMax="1398" yMax="1925">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="388" y="1604" on="1"/>
+ <pt x="629" y="1925" on="1"/>
+ <pt x="851" y="1925" on="1"/>
+ <pt x="1091" y="1604" on="1"/>
+ <pt x="1005" y="1604" on="1"/>
+ <pt x="740" y="1826" on="1"/>
+ <pt x="474" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 49 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 2 0 0 1 38 37 36 35 32 5 33 0 3 0
+ 34 33 1 0 14 0 0 28 34 4 20 34 12 48 196 38 37 36 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Odieresis" xMin="80" yMin="-37" xMax="1398" yMax="1777">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="455" y="1604" on="1"/>
+ <pt x="455" y="1777" on="1"/>
+ <pt x="628" y="1777" on="1"/>
+ <pt x="628" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="850" y="1604" on="1"/>
+ <pt x="850" y="1777" on="1"/>
+ <pt x="1023" y="1777" on="1"/>
+ <pt x="1023" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 2 0 0 0 0 39 36 35 32 13 3 33 1 4
+ 48 84 38 37 34 33 3 0 14 0 0 28 34 4 20 34 12 48 196 4 38 12 32 0 0
+ 37 36 13 1 38 35 34 13 1 32 2 4 48 196 39 38 1 33 32 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ograve" xMin="80" yMin="-37" xMax="1398" yMax="1925">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="893" y="1604" on="1"/>
+ <pt x="800" y="1604" on="1"/>
+ <pt x="393" y="1925" on="1"/>
+ <pt x="652" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 2 0 0 1 33 32 2 34 0 3 0 35 34 1
+ 0 14 0 0 28 34 4 20 34 12 48 196 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ohungarumlaut" xMin="80" yMin="-37" xMax="1398" yMax="1925">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="492" y="1604" on="1"/>
+ <pt x="706" y="1925" on="1"/>
+ <pt x="875" y="1925" on="1"/>
+ <pt x="554" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="801" y="1604" on="1"/>
+ <pt x="1014" y="1925" on="1"/>
+ <pt x="1183" y="1925" on="1"/>
+ <pt x="862" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 51 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 2 0 0 1 39 36 35 32 4 33 0 3 0 38
+ 37 34 33 3 0 14 0 0 28 34 4 20 34 12 48 196 39 38 37 36 35 34 33 32 12
+ 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Omacron" xMin="80" yMin="-37" xMax="1398" yMax="1727">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="418" y="1604" on="1"/>
+ <pt x="418" y="1727" on="1"/>
+ <pt x="1060" y="1727" on="1"/>
+ <pt x="1060" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 2 0 0 0 0 35 32 12 1 33 1 4 48 84
+ 34 33 1 0 14 0 0 28 34 4 20 34 12 48 196 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Oslash" xMin="80" yMin="-37" xMax="1398" yMax="1517">
+ <contour>
+ <pt x="80" y="-37" on="1"/>
+ <pt x="253" y="181" on="1"/>
+ <pt x="176" y="282" on="0"/>
+ <pt x="137" y="387" on="1"/>
+ <pt x="80" y="542" on="0"/>
+ <pt x="80" y="741" on="1"/>
+ <pt x="80" y="1101" on="0"/>
+ <pt x="257" y="1309" on="1"/>
+ <pt x="434" y="1517" on="0"/>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="994" y="1517" on="0"/>
+ <pt x="1178" y="1352" on="1"/>
+ <pt x="1309" y="1517" on="1"/>
+ <pt x="1398" y="1517" on="1"/>
+ <pt x="1226" y="1298" on="1"/>
+ <pt x="1303" y="1198" on="0"/>
+ <pt x="1341" y="1094" on="1"/>
+ <pt x="1398" y="938" on="0"/>
+ <pt x="1398" y="739" on="1"/>
+ <pt x="1398" y="380" on="0"/>
+ <pt x="1221" y="172" on="1"/>
+ <pt x="1044" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="485" y="-37" on="0"/>
+ <pt x="305" y="124" on="1"/>
+ <pt x="179" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="407" y="254" on="1"/>
+ <pt x="463" y="154" on="0"/>
+ <pt x="526" y="104" on="1"/>
+ <pt x="617" y="31" on="0"/>
+ <pt x="739" y="31" on="1"/>
+ <pt x="940" y="31" on="0"/>
+ <pt x="1055" y="220" on="1"/>
+ <pt x="1170" y="409" on="0"/>
+ <pt x="1170" y="738" on="1"/>
+ <pt x="1170" y="973" on="0"/>
+ <pt x="1107" y="1147" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1074" y="1220" on="1"/>
+ <pt x="1017" y="1323" on="0"/>
+ <pt x="954" y="1374" on="1"/>
+ <pt x="862" y="1450" on="0"/>
+ <pt x="738" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="744" on="1"/>
+ <pt x="308" y="505" on="0"/>
+ <pt x="371" y="332" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 41 17 9 30 17 22 48 84 22 2 9 0 1 1 47 37 36 26 24 14 11 1 8
+ 0 2 3 0 0 1 13 12 2 13 0 0 1 25 0 2 0 14 0 0 45 34 5 34 34
+ 18 48 196 47 37 36 26 25 24 18 14 13 12 11 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Otilde" xMin="80" yMin="-37" xMax="1398" yMax="1839">
+ <contour>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1044" y="1517" on="0"/>
+ <pt x="1221" y="1309" on="1"/>
+ <pt x="1398" y="1101" on="0"/>
+ <pt x="1398" y="742" on="1"/>
+ <pt x="1398" y="377" on="0"/>
+ <pt x="1220" y="170" on="1"/>
+ <pt x="1043" y="-37" on="0"/>
+ <pt x="729" y="-37" on="1"/>
+ <pt x="461" y="-37" on="0"/>
+ <pt x="292" y="133" on="1"/>
+ <pt x="80" y="347" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1100" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="435" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="739" y="1450" on="1"/>
+ <pt x="538" y="1450" on="0"/>
+ <pt x="423" y="1261" on="1"/>
+ <pt x="308" y="1072" on="0"/>
+ <pt x="308" y="741" on="1"/>
+ <pt x="308" y="413" on="0"/>
+ <pt x="422" y="222" on="1"/>
+ <pt x="536" y="31" on="0"/>
+ <pt x="734" y="31" on="1"/>
+ <pt x="918" y="31" on="0"/>
+ <pt x="1030" y="182" on="1"/>
+ <pt x="1170" y="371" on="0"/>
+ <pt x="1170" y="743" on="1"/>
+ <pt x="1170" y="1074" on="0"/>
+ <pt x="1055" y="1261" on="1"/>
+ <pt x="939" y="1450" on="0"/>
+ </contour>
+ <contour>
+ <pt x="406" y="1604" on="1"/>
+ <pt x="433" y="1743" on="0"/>
+ <pt x="502" y="1797" on="1"/>
+ <pt x="555" y="1839" on="0"/>
+ <pt x="633" y="1839" on="1"/>
+ <pt x="698" y="1839" on="0"/>
+ <pt x="751" y="1801" on="1"/>
+ <pt x="786" y="1776" on="1"/>
+ <pt x="838" y="1739" on="0"/>
+ <pt x="892" y="1739" on="1"/>
+ <pt x="988" y="1739" on="0"/>
+ <pt x="1010" y="1838" on="1"/>
+ <pt x="1072" y="1838" on="1"/>
+ <pt x="1044" y="1699" on="0"/>
+ <pt x="976" y="1646" on="1"/>
+ <pt x="922" y="1604" on="0"/>
+ <pt x="845" y="1604" on="1"/>
+ <pt x="782" y="1604" on="0"/>
+ <pt x="727" y="1642" on="1"/>
+ <pt x="692" y="1666" on="1"/>
+ <pt x="637" y="1704" on="0"/>
+ <pt x="585" y="1704" on="1"/>
+ <pt x="497" y="1704" on="0"/>
+ <pt x="468" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 0 0 53 20 36 41 20 48 24 17 8 16 17 0 48 84 8 2 0 0 1 55 44 43 32
+ 4 13 48 36 0 0 14 0 0 28 34 4 20 34 12 48 196 55 44 43 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="P" xMin="31" yMin="0" xMax="1108" yMax="1492">
+ <contour>
+ <pt x="462" y="1480" on="1"/>
+ <pt x="608" y="1485" on="1"/>
+ <pt x="676" y="1487" on="1"/>
+ <pt x="836" y="1492" on="0"/>
+ <pt x="947" y="1427" on="1"/>
+ <pt x="1108" y="1333" on="0"/>
+ <pt x="1108" y="1095" on="1"/>
+ <pt x="1108" y="617" on="0"/>
+ <pt x="478" y="617" on="1"/>
+ <pt x="424" y="617" on="1"/>
+ <pt x="424" y="259" on="1"/>
+ <pt x="423" y="144" on="0"/>
+ <pt x="442" y="104" on="1"/>
+ <pt x="457" y="72" on="0"/>
+ <pt x="523" y="68" on="1"/>
+ <pt x="591" y="63" on="1"/>
+ <pt x="634" y="62" on="1"/>
+ <pt x="634" y="0" on="1"/>
+ <pt x="31" y="0" on="1"/>
+ <pt x="31" y="62" on="1"/>
+ <pt x="50" y="63" on="1"/>
+ <pt x="117" y="68" on="1"/>
+ <pt x="193" y="74" on="0"/>
+ <pt x="203" y="115" on="1"/>
+ <pt x="216" y="177" on="0"/>
+ <pt x="216" y="259" on="1"/>
+ <pt x="216" y="1221" on="1"/>
+ <pt x="216" y="1280" on="0"/>
+ <pt x="209" y="1333" on="1"/>
+ <pt x="203" y="1372" on="0"/>
+ <pt x="195" y="1384" on="1"/>
+ <pt x="177" y="1410" on="0"/>
+ <pt x="117" y="1413" on="1"/>
+ <pt x="50" y="1417" on="1"/>
+ <pt x="31" y="1419" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="424" y="685" on="1"/>
+ <pt x="490" y="685" on="1"/>
+ <pt x="886" y="685" on="0"/>
+ <pt x="886" y="1091" on="1"/>
+ <pt x="886" y="1265" on="0"/>
+ <pt x="810" y="1339" on="1"/>
+ <pt x="735" y="1413" on="0"/>
+ <pt x="559" y="1413" on="1"/>
+ <pt x="424" y="1413" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 26 35 25 18 10 17 44 43 37 36 9 8 6 0 17 3 18 17 1 0 35 0 0 14 0
+ 0 39 33 6 48 196 35 26 18 25 17 10 43 37 8 0 4 13 6 9 0 0 44 36 10
+ 9 32 3 25 1 4 48 196 26 25 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Q" xMin="80" yMin="-298" xMax="1711" yMax="1517">
+ <contour>
+ <pt x="1711" y="-174" on="1"/>
+ <pt x="1463" y="-298" on="1"/>
+ <pt x="1211" y="-224" on="0"/>
+ <pt x="926" y="-49" on="1"/>
+ <pt x="885" y="-24" on="1"/>
+ <pt x="809" y="-37" on="0"/>
+ <pt x="739" y="-37" on="1"/>
+ <pt x="434" y="-37" on="0"/>
+ <pt x="257" y="171" on="1"/>
+ <pt x="80" y="380" on="0"/>
+ <pt x="80" y="740" on="1"/>
+ <pt x="80" y="1099" on="0"/>
+ <pt x="257" y="1308" on="1"/>
+ <pt x="434" y="1517" on="0"/>
+ <pt x="739" y="1517" on="1"/>
+ <pt x="1045" y="1517" on="0"/>
+ <pt x="1222" y="1308" on="1"/>
+ <pt x="1398" y="1100" on="0"/>
+ <pt x="1398" y="740" on="1"/>
+ <pt x="1398" y="413" on="0"/>
+ <pt x="1247" y="204" on="1"/>
+ <pt x="1145" y="62" on="0"/>
+ <pt x="974" y="1" on="1"/>
+ <pt x="1211" y="-136" on="0"/>
+ </contour>
+ <contour>
+ <pt x="740" y="1450" on="1"/>
+ <pt x="540" y="1450" on="0"/>
+ <pt x="424" y="1262" on="1"/>
+ <pt x="308" y="1074" on="0"/>
+ <pt x="308" y="748" on="1"/>
+ <pt x="308" y="442" on="0"/>
+ <pt x="403" y="256" on="1"/>
+ <pt x="518" y="31" on="0"/>
+ <pt x="740" y="31" on="1"/>
+ <pt x="941" y="31" on="0"/>
+ <pt x="1056" y="220" on="1"/>
+ <pt x="1170" y="409" on="0"/>
+ <pt x="1170" y="740" on="1"/>
+ <pt x="1170" y="1073" on="0"/>
+ <pt x="1056" y="1261" on="1"/>
+ <pt x="940" y="1450" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 32 17 6 24 17 14 48 84 14 0 6 2 1 1 22 0 2 2 0 0 1 4 1
+ 0 3 13 2 0 14 0 0 36 34 18 28 34 10 48 196 22 18 10 4 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="R" xMin="31" yMin="0" xMax="1354" yMax="1492">
+ <contour>
+ <pt x="387" y="1480" on="1"/>
+ <pt x="485" y="1482" on="1"/>
+ <pt x="567" y="1485" on="1"/>
+ <pt x="647" y="1487" on="1"/>
+ <pt x="827" y="1492" on="0"/>
+ <pt x="948" y="1423" on="1"/>
+ <pt x="1106" y="1332" on="0"/>
+ <pt x="1106" y="1112" on="1"/>
+ <pt x="1106" y="924" on="0"/>
+ <pt x="993" y="811" on="1"/>
+ <pt x="926" y="745" on="0"/>
+ <pt x="800" y="697" on="1"/>
+ <pt x="1090" y="261" on="1"/>
+ <pt x="1183" y="132" on="1"/>
+ <pt x="1226" y="71" on="0"/>
+ <pt x="1291" y="66" on="1"/>
+ <pt x="1333" y="63" on="1"/>
+ <pt x="1354" y="62" on="1"/>
+ <pt x="1354" y="0" on="1"/>
+ <pt x="1001" y="0" on="1"/>
+ <pt x="597" y="651" on="1"/>
+ <pt x="426" y="651" on="1"/>
+ <pt x="426" y="259" on="1"/>
+ <pt x="431" y="160" on="1"/>
+ <pt x="433" y="90" on="0"/>
+ <pt x="459" y="79" on="1"/>
+ <pt x="485" y="69" on="0"/>
+ <pt x="568" y="63" on="1"/>
+ <pt x="586" y="62" on="1"/>
+ <pt x="586" y="0" on="1"/>
+ <pt x="31" y="0" on="1"/>
+ <pt x="31" y="62" on="1"/>
+ <pt x="50" y="63" on="1"/>
+ <pt x="117" y="68" on="1"/>
+ <pt x="193" y="74" on="0"/>
+ <pt x="203" y="115" on="1"/>
+ <pt x="216" y="177" on="0"/>
+ <pt x="216" y="259" on="1"/>
+ <pt x="216" y="1221" on="1"/>
+ <pt x="216" y="1280" on="0"/>
+ <pt x="209" y="1333" on="1"/>
+ <pt x="203" y="1372" on="0"/>
+ <pt x="195" y="1384" on="1"/>
+ <pt x="177" y="1410" on="0"/>
+ <pt x="117" y="1413" on="1"/>
+ <pt x="50" y="1417" on="1"/>
+ <pt x="31" y="1419" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="426" y="719" on="1"/>
+ <pt x="500" y="719" on="1"/>
+ <pt x="890" y="719" on="0"/>
+ <pt x="890" y="1094" on="1"/>
+ <pt x="890" y="1266" on="0"/>
+ <pt x="817" y="1340" on="1"/>
+ <pt x="744" y="1413" on="0"/>
+ <pt x="568" y="1413" on="1"/>
+ <pt x="426" y="1413" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 38 47 37 30 49 48 11 3 55 20 3 28 22 17 12 4 20 18 3 56 55 1 21 20 1
+ 30 29 19 18 3 3 0 47 0 0 14 0 0 51 10 7 48 196 47 38 30 37 0 21 37
+ 2 55 49 29 28 20 19 18 17 12 11 10 13 7 21 0 0 56 48 22 21 32 3 37 1
+ 4 48 196 38 37 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Racute" xMin="31" yMin="0" xMax="1354" yMax="1925">
+ <contour>
+ <pt x="387" y="1480" on="1"/>
+ <pt x="485" y="1482" on="1"/>
+ <pt x="567" y="1485" on="1"/>
+ <pt x="647" y="1487" on="1"/>
+ <pt x="827" y="1492" on="0"/>
+ <pt x="948" y="1423" on="1"/>
+ <pt x="1106" y="1332" on="0"/>
+ <pt x="1106" y="1112" on="1"/>
+ <pt x="1106" y="924" on="0"/>
+ <pt x="993" y="811" on="1"/>
+ <pt x="926" y="745" on="0"/>
+ <pt x="800" y="697" on="1"/>
+ <pt x="1090" y="261" on="1"/>
+ <pt x="1183" y="132" on="1"/>
+ <pt x="1226" y="71" on="0"/>
+ <pt x="1291" y="66" on="1"/>
+ <pt x="1333" y="63" on="1"/>
+ <pt x="1354" y="62" on="1"/>
+ <pt x="1354" y="0" on="1"/>
+ <pt x="1001" y="0" on="1"/>
+ <pt x="597" y="651" on="1"/>
+ <pt x="426" y="651" on="1"/>
+ <pt x="426" y="259" on="1"/>
+ <pt x="431" y="160" on="1"/>
+ <pt x="433" y="90" on="0"/>
+ <pt x="459" y="79" on="1"/>
+ <pt x="485" y="69" on="0"/>
+ <pt x="568" y="63" on="1"/>
+ <pt x="586" y="62" on="1"/>
+ <pt x="586" y="0" on="1"/>
+ <pt x="31" y="0" on="1"/>
+ <pt x="31" y="62" on="1"/>
+ <pt x="50" y="63" on="1"/>
+ <pt x="117" y="68" on="1"/>
+ <pt x="193" y="74" on="0"/>
+ <pt x="203" y="115" on="1"/>
+ <pt x="216" y="177" on="0"/>
+ <pt x="216" y="259" on="1"/>
+ <pt x="216" y="1221" on="1"/>
+ <pt x="216" y="1280" on="0"/>
+ <pt x="209" y="1333" on="1"/>
+ <pt x="203" y="1372" on="0"/>
+ <pt x="195" y="1384" on="1"/>
+ <pt x="177" y="1410" on="0"/>
+ <pt x="117" y="1413" on="1"/>
+ <pt x="50" y="1417" on="1"/>
+ <pt x="31" y="1419" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="426" y="719" on="1"/>
+ <pt x="500" y="719" on="1"/>
+ <pt x="890" y="719" on="0"/>
+ <pt x="890" y="1094" on="1"/>
+ <pt x="890" y="1266" on="0"/>
+ <pt x="817" y="1340" on="1"/>
+ <pt x="744" y="1413" on="0"/>
+ <pt x="568" y="1413" on="1"/>
+ <pt x="426" y="1413" on="1"/>
+ </contour>
+ <contour>
+ <pt x="463" y="1604" on="1"/>
+ <pt x="704" y="1925" on="1"/>
+ <pt x="963" y="1925" on="1"/>
+ <pt x="556" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 95 values pushed */
+ 38 47 37 30 60 57 2 58 0 3 49 48 11 3 55 20 3 28 22 17 12 4 20 18 3
+ 59 58 1 56 55 1 21 20 1 30 29 19 18 3 4 0 47 0 0 14 0 0 51 10 7
+ 48 196 47 38 30 37 0 21 37 2 60 59 58 57 55 49 29 28 20 19 18 17 12 11 14
+ 13 7 21 0 0 56 48 22 21 32 3 37 1 4 48 196 38 37 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Rcaron" xMin="31" yMin="0" xMax="1354" yMax="1925">
+ <contour>
+ <pt x="387" y="1480" on="1"/>
+ <pt x="485" y="1482" on="1"/>
+ <pt x="567" y="1485" on="1"/>
+ <pt x="647" y="1487" on="1"/>
+ <pt x="827" y="1492" on="0"/>
+ <pt x="948" y="1423" on="1"/>
+ <pt x="1106" y="1332" on="0"/>
+ <pt x="1106" y="1112" on="1"/>
+ <pt x="1106" y="924" on="0"/>
+ <pt x="993" y="811" on="1"/>
+ <pt x="926" y="745" on="0"/>
+ <pt x="800" y="697" on="1"/>
+ <pt x="1090" y="261" on="1"/>
+ <pt x="1183" y="132" on="1"/>
+ <pt x="1226" y="71" on="0"/>
+ <pt x="1291" y="66" on="1"/>
+ <pt x="1333" y="63" on="1"/>
+ <pt x="1354" y="62" on="1"/>
+ <pt x="1354" y="0" on="1"/>
+ <pt x="1001" y="0" on="1"/>
+ <pt x="597" y="651" on="1"/>
+ <pt x="426" y="651" on="1"/>
+ <pt x="426" y="259" on="1"/>
+ <pt x="431" y="160" on="1"/>
+ <pt x="433" y="90" on="0"/>
+ <pt x="459" y="79" on="1"/>
+ <pt x="485" y="69" on="0"/>
+ <pt x="568" y="63" on="1"/>
+ <pt x="586" y="62" on="1"/>
+ <pt x="586" y="0" on="1"/>
+ <pt x="31" y="0" on="1"/>
+ <pt x="31" y="62" on="1"/>
+ <pt x="50" y="63" on="1"/>
+ <pt x="117" y="68" on="1"/>
+ <pt x="193" y="74" on="0"/>
+ <pt x="203" y="115" on="1"/>
+ <pt x="216" y="177" on="0"/>
+ <pt x="216" y="259" on="1"/>
+ <pt x="216" y="1221" on="1"/>
+ <pt x="216" y="1280" on="0"/>
+ <pt x="209" y="1333" on="1"/>
+ <pt x="203" y="1372" on="0"/>
+ <pt x="195" y="1384" on="1"/>
+ <pt x="177" y="1410" on="0"/>
+ <pt x="117" y="1413" on="1"/>
+ <pt x="50" y="1417" on="1"/>
+ <pt x="31" y="1419" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="426" y="719" on="1"/>
+ <pt x="500" y="719" on="1"/>
+ <pt x="890" y="719" on="0"/>
+ <pt x="890" y="1094" on="1"/>
+ <pt x="890" y="1266" on="0"/>
+ <pt x="817" y="1340" on="1"/>
+ <pt x="744" y="1413" on="0"/>
+ <pt x="568" y="1413" on="1"/>
+ <pt x="426" y="1413" on="1"/>
+ </contour>
+ <contour>
+ <pt x="938" y="1925" on="1"/>
+ <pt x="698" y="1604" on="1"/>
+ <pt x="476" y="1604" on="1"/>
+ <pt x="235" y="1925" on="1"/>
+ <pt x="321" y="1925" on="1"/>
+ <pt x="587" y="1703" on="1"/>
+ <pt x="852" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 101 values pushed */
+ 38 47 37 30 49 48 11 3 55 20 3 28 22 17 12 4 20 18 3 63 62 61 60 57 5
+ 13 58 59 58 1 56 55 1 21 20 1 30 29 19 18 3 4 0 47 0 0 14 0 0 51
+ 10 7 48 196 47 38 30 37 61 60 0 3 21 37 3 63 62 59 58 57 55 49 29 28 20
+ 19 18 17 12 11 15 13 7 21 0 0 56 48 22 21 32 3 37 1 4 48 196 38 37 1
+ 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Rcommaaccent" xMin="31" yMin="-432" xMax="1354" yMax="1491">
+ <contour>
+ <pt x="387" y="1480" on="1"/>
+ <pt x="485" y="1482" on="1"/>
+ <pt x="567" y="1485" on="1"/>
+ <pt x="647" y="1487" on="1"/>
+ <pt x="828" y="1491" on="0"/>
+ <pt x="948" y="1423" on="1"/>
+ <pt x="1106" y="1332" on="0"/>
+ <pt x="1106" y="1112" on="1"/>
+ <pt x="1106" y="924" on="0"/>
+ <pt x="993" y="811" on="1"/>
+ <pt x="926" y="745" on="0"/>
+ <pt x="800" y="697" on="1"/>
+ <pt x="1090" y="261" on="1"/>
+ <pt x="1183" y="132" on="1"/>
+ <pt x="1226" y="71" on="0"/>
+ <pt x="1291" y="66" on="1"/>
+ <pt x="1333" y="63" on="1"/>
+ <pt x="1354" y="62" on="1"/>
+ <pt x="1354" y="0" on="1"/>
+ <pt x="1001" y="0" on="1"/>
+ <pt x="597" y="651" on="1"/>
+ <pt x="426" y="651" on="1"/>
+ <pt x="426" y="259" on="1"/>
+ <pt x="431" y="160" on="1"/>
+ <pt x="433" y="90" on="0"/>
+ <pt x="459" y="79" on="1"/>
+ <pt x="485" y="69" on="0"/>
+ <pt x="568" y="63" on="1"/>
+ <pt x="586" y="62" on="1"/>
+ <pt x="586" y="0" on="1"/>
+ <pt x="31" y="0" on="1"/>
+ <pt x="31" y="62" on="1"/>
+ <pt x="50" y="63" on="1"/>
+ <pt x="117" y="68" on="1"/>
+ <pt x="193" y="74" on="0"/>
+ <pt x="203" y="115" on="1"/>
+ <pt x="216" y="177" on="0"/>
+ <pt x="216" y="259" on="1"/>
+ <pt x="216" y="1221" on="1"/>
+ <pt x="216" y="1280" on="0"/>
+ <pt x="209" y="1333" on="1"/>
+ <pt x="203" y="1372" on="0"/>
+ <pt x="195" y="1384" on="1"/>
+ <pt x="177" y="1410" on="0"/>
+ <pt x="117" y="1413" on="1"/>
+ <pt x="50" y="1417" on="1"/>
+ <pt x="31" y="1419" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="426" y="719" on="1"/>
+ <pt x="500" y="719" on="1"/>
+ <pt x="890" y="719" on="0"/>
+ <pt x="890" y="1094" on="1"/>
+ <pt x="890" y="1266" on="0"/>
+ <pt x="817" y="1340" on="1"/>
+ <pt x="744" y="1413" on="0"/>
+ <pt x="568" y="1413" on="1"/>
+ <pt x="426" y="1413" on="1"/>
+ </contour>
+ <contour>
+ <pt x="574" y="-421" on="1"/>
+ <pt x="574" y="-349" on="1"/>
+ <pt x="623" y="-359" on="0"/>
+ <pt x="678" y="-359" on="1"/>
+ <pt x="781" y="-359" on="0"/>
+ <pt x="781" y="-279" on="1"/>
+ <pt x="781" y="-190" on="0"/>
+ <pt x="623" y="-175" on="1"/>
+ <pt x="623" y="-111" on="1"/>
+ <pt x="757" y="-114" on="0"/>
+ <pt x="823" y="-143" on="1"/>
+ <pt x="916" y="-185" on="0"/>
+ <pt x="916" y="-280" on="1"/>
+ <pt x="916" y="-432" on="0"/>
+ <pt x="699" y="-432" on="1"/>
+ <pt x="640" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 105 values pushed */
+ 0 0 60 17 71 48 84 38 47 37 30 49 48 11 3 55 20 3 28 22 17 12 4 20 18
+ 3 65 64 58 57 4 13 71 18 56 55 1 21 20 1 30 29 19 18 3 3 0 47 0 0
+ 14 0 0 62 48 69 51 10 7 48 196 47 38 30 37 0 21 37 2 65 64 58 57 55 49
+ 29 28 20 19 18 17 12 11 14 13 69 7 21 0 0 56 48 22 21 32 3 37 1 4 48
+ 196 38 37 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="S" xMin="119" yMin="-37" xMax="1045" yMax="1517">
+ <contour>
+ <pt x="119" y="30" on="1"/>
+ <pt x="119" y="315" on="1"/>
+ <pt x="224" y="315" on="1"/>
+ <pt x="225" y="297" on="1"/>
+ <pt x="227" y="257" on="0"/>
+ <pt x="228" y="228" on="1"/>
+ <pt x="228" y="222" on="1"/>
+ <pt x="228" y="147" on="0"/>
+ <pt x="297" y="99" on="1"/>
+ <pt x="386" y="37" on="0"/>
+ <pt x="542" y="37" on="1"/>
+ <pt x="835" y="37" on="0"/>
+ <pt x="835" y="319" on="1"/>
+ <pt x="835" y="437" on="0"/>
+ <pt x="790" y="498" on="1"/>
+ <pt x="746" y="558" on="0"/>
+ <pt x="602" y="636" on="1"/>
+ <pt x="470" y="707" on="1"/>
+ <pt x="130" y="890" on="0"/>
+ <pt x="130" y="1129" on="1"/>
+ <pt x="130" y="1298" on="0"/>
+ <pt x="255" y="1408" on="1"/>
+ <pt x="379" y="1517" on="0"/>
+ <pt x="581" y="1517" on="1"/>
+ <pt x="741" y="1517" on="0"/>
+ <pt x="962" y="1454" on="1"/>
+ <pt x="962" y="1191" on="1"/>
+ <pt x="851" y="1191" on="1"/>
+ <pt x="850" y="1208" on="1"/>
+ <pt x="847" y="1248" on="0"/>
+ <pt x="846" y="1281" on="1"/>
+ <pt x="846" y="1287" on="1"/>
+ <pt x="846" y="1364" on="0"/>
+ <pt x="797" y="1403" on="1"/>
+ <pt x="739" y="1450" on="0"/>
+ <pt x="596" y="1450" on="1"/>
+ <pt x="332" y="1450" on="0"/>
+ <pt x="332" y="1196" on="1"/>
+ <pt x="332" y="1093" on="0"/>
+ <pt x="376" y="1033" on="1"/>
+ <pt x="419" y="973" on="0"/>
+ <pt x="544" y="906" on="1"/>
+ <pt x="676" y="835" on="1"/>
+ <pt x="891" y="719" on="0"/>
+ <pt x="968" y="626" on="1"/>
+ <pt x="1045" y="534" on="0"/>
+ <pt x="1045" y="392" on="1"/>
+ <pt x="1045" y="206" on="0"/>
+ <pt x="906" y="84" on="1"/>
+ <pt x="768" y="-37" on="0"/>
+ <pt x="536" y="-37" on="1"/>
+ <pt x="304" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 35 17 23 10 21 50 48 84 50 2 23 0 1 1 31 30 27 26 25 6 5 2 1
+ 0 10 0 2 3 0 0 14 0 0 37 5 19 12 10 46 48 196 19 31 30 27 19 6 5
+ 2 7 25 0 3 46 25 26 25 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Sacute" xMin="119" yMin="-37" xMax="1045" yMax="1925">
+ <contour>
+ <pt x="119" y="30" on="1"/>
+ <pt x="119" y="315" on="1"/>
+ <pt x="224" y="315" on="1"/>
+ <pt x="225" y="297" on="1"/>
+ <pt x="227" y="257" on="0"/>
+ <pt x="228" y="228" on="1"/>
+ <pt x="228" y="222" on="1"/>
+ <pt x="228" y="147" on="0"/>
+ <pt x="297" y="99" on="1"/>
+ <pt x="386" y="37" on="0"/>
+ <pt x="542" y="37" on="1"/>
+ <pt x="835" y="37" on="0"/>
+ <pt x="835" y="319" on="1"/>
+ <pt x="835" y="437" on="0"/>
+ <pt x="790" y="498" on="1"/>
+ <pt x="746" y="558" on="0"/>
+ <pt x="602" y="636" on="1"/>
+ <pt x="470" y="707" on="1"/>
+ <pt x="130" y="890" on="0"/>
+ <pt x="130" y="1129" on="1"/>
+ <pt x="130" y="1298" on="0"/>
+ <pt x="255" y="1408" on="1"/>
+ <pt x="379" y="1517" on="0"/>
+ <pt x="581" y="1517" on="1"/>
+ <pt x="741" y="1517" on="0"/>
+ <pt x="962" y="1454" on="1"/>
+ <pt x="962" y="1191" on="1"/>
+ <pt x="851" y="1191" on="1"/>
+ <pt x="850" y="1208" on="1"/>
+ <pt x="847" y="1248" on="0"/>
+ <pt x="846" y="1281" on="1"/>
+ <pt x="846" y="1287" on="1"/>
+ <pt x="846" y="1364" on="0"/>
+ <pt x="797" y="1403" on="1"/>
+ <pt x="739" y="1450" on="0"/>
+ <pt x="596" y="1450" on="1"/>
+ <pt x="332" y="1450" on="0"/>
+ <pt x="332" y="1196" on="1"/>
+ <pt x="332" y="1093" on="0"/>
+ <pt x="376" y="1033" on="1"/>
+ <pt x="419" y="973" on="0"/>
+ <pt x="544" y="906" on="1"/>
+ <pt x="676" y="835" on="1"/>
+ <pt x="891" y="719" on="0"/>
+ <pt x="968" y="626" on="1"/>
+ <pt x="1045" y="534" on="0"/>
+ <pt x="1045" y="392" on="1"/>
+ <pt x="1045" y="206" on="0"/>
+ <pt x="906" y="84" on="1"/>
+ <pt x="768" y="-37" on="0"/>
+ <pt x="536" y="-37" on="1"/>
+ <pt x="304" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="482" y="1604" on="1"/>
+ <pt x="723" y="1925" on="1"/>
+ <pt x="982" y="1925" on="1"/>
+ <pt x="575" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 35 17 23 10 21 50 48 84 50 2 23 0 1 55 52 2 53 0 3 0 1 1 31
+ 30 27 26 25 6 5 2 1 0 10 0 2 3 0 0 54 53 1 0 14 0 0 37 5 19
+ 12 10 46 48 196 19 55 53 52 31 30 27 19 6 5 2 10 25 0 3 54 46 25 26 25
+ 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scaron" xMin="119" yMin="-37" xMax="1045" yMax="1925">
+ <contour>
+ <pt x="119" y="30" on="1"/>
+ <pt x="119" y="315" on="1"/>
+ <pt x="224" y="315" on="1"/>
+ <pt x="225" y="297" on="1"/>
+ <pt x="227" y="257" on="0"/>
+ <pt x="228" y="228" on="1"/>
+ <pt x="228" y="222" on="1"/>
+ <pt x="228" y="147" on="0"/>
+ <pt x="297" y="99" on="1"/>
+ <pt x="386" y="37" on="0"/>
+ <pt x="542" y="37" on="1"/>
+ <pt x="835" y="37" on="0"/>
+ <pt x="835" y="319" on="1"/>
+ <pt x="835" y="437" on="0"/>
+ <pt x="790" y="498" on="1"/>
+ <pt x="746" y="558" on="0"/>
+ <pt x="602" y="636" on="1"/>
+ <pt x="470" y="707" on="1"/>
+ <pt x="130" y="890" on="0"/>
+ <pt x="130" y="1129" on="1"/>
+ <pt x="130" y="1298" on="0"/>
+ <pt x="255" y="1408" on="1"/>
+ <pt x="379" y="1517" on="0"/>
+ <pt x="581" y="1517" on="1"/>
+ <pt x="741" y="1517" on="0"/>
+ <pt x="962" y="1454" on="1"/>
+ <pt x="962" y="1191" on="1"/>
+ <pt x="851" y="1191" on="1"/>
+ <pt x="850" y="1208" on="1"/>
+ <pt x="847" y="1248" on="0"/>
+ <pt x="846" y="1281" on="1"/>
+ <pt x="846" y="1287" on="1"/>
+ <pt x="846" y="1364" on="0"/>
+ <pt x="797" y="1403" on="1"/>
+ <pt x="739" y="1450" on="0"/>
+ <pt x="596" y="1450" on="1"/>
+ <pt x="332" y="1450" on="0"/>
+ <pt x="332" y="1196" on="1"/>
+ <pt x="332" y="1093" on="0"/>
+ <pt x="376" y="1033" on="1"/>
+ <pt x="419" y="973" on="0"/>
+ <pt x="544" y="906" on="1"/>
+ <pt x="676" y="835" on="1"/>
+ <pt x="891" y="719" on="0"/>
+ <pt x="968" y="626" on="1"/>
+ <pt x="1045" y="534" on="0"/>
+ <pt x="1045" y="392" on="1"/>
+ <pt x="1045" y="206" on="0"/>
+ <pt x="906" y="84" on="1"/>
+ <pt x="768" y="-37" on="0"/>
+ <pt x="536" y="-37" on="1"/>
+ <pt x="304" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="926" y="1925" on="1"/>
+ <pt x="686" y="1604" on="1"/>
+ <pt x="464" y="1604" on="1"/>
+ <pt x="223" y="1925" on="1"/>
+ <pt x="309" y="1925" on="1"/>
+ <pt x="575" y="1703" on="1"/>
+ <pt x="840" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 0 0 35 17 23 10 21 50 48 84 50 2 23 0 1 1 31 30 27 26 25 6 5 2 1
+ 0 10 0 2 3 0 0 58 57 56 55 52 5 13 53 54 53 1 0 14 0 0 37 5 19
+ 12 10 46 48 196 19 58 57 56 55 54 53 52 31 30 27 19 6 5 2 14 25 0 3 46
+ 25 26 25 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scedilla" xMin="119" yMin="-432" xMax="1045" yMax="1517">
+ <contour>
+ <pt x="119" y="30" on="1"/>
+ <pt x="119" y="315" on="1"/>
+ <pt x="224" y="315" on="1"/>
+ <pt x="225" y="297" on="1"/>
+ <pt x="227" y="257" on="0"/>
+ <pt x="228" y="228" on="1"/>
+ <pt x="228" y="222" on="1"/>
+ <pt x="228" y="147" on="0"/>
+ <pt x="297" y="99" on="1"/>
+ <pt x="386" y="37" on="0"/>
+ <pt x="542" y="37" on="1"/>
+ <pt x="835" y="37" on="0"/>
+ <pt x="835" y="319" on="1"/>
+ <pt x="835" y="437" on="0"/>
+ <pt x="790" y="498" on="1"/>
+ <pt x="746" y="558" on="0"/>
+ <pt x="602" y="636" on="1"/>
+ <pt x="470" y="707" on="1"/>
+ <pt x="130" y="890" on="0"/>
+ <pt x="130" y="1129" on="1"/>
+ <pt x="130" y="1299" on="0"/>
+ <pt x="255" y="1408" on="1"/>
+ <pt x="379" y="1517" on="0"/>
+ <pt x="581" y="1517" on="1"/>
+ <pt x="741" y="1517" on="0"/>
+ <pt x="962" y="1454" on="1"/>
+ <pt x="962" y="1191" on="1"/>
+ <pt x="851" y="1191" on="1"/>
+ <pt x="850" y="1208" on="1"/>
+ <pt x="847" y="1248" on="0"/>
+ <pt x="846" y="1281" on="1"/>
+ <pt x="846" y="1287" on="1"/>
+ <pt x="846" y="1364" on="0"/>
+ <pt x="797" y="1403" on="1"/>
+ <pt x="739" y="1450" on="0"/>
+ <pt x="596" y="1450" on="1"/>
+ <pt x="332" y="1450" on="0"/>
+ <pt x="332" y="1196" on="1"/>
+ <pt x="332" y="1093" on="0"/>
+ <pt x="376" y="1033" on="1"/>
+ <pt x="419" y="973" on="0"/>
+ <pt x="544" y="906" on="1"/>
+ <pt x="676" y="835" on="1"/>
+ <pt x="891" y="719" on="0"/>
+ <pt x="968" y="626" on="1"/>
+ <pt x="1045" y="534" on="0"/>
+ <pt x="1045" y="392" on="1"/>
+ <pt x="1045" y="206" on="0"/>
+ <pt x="906" y="84" on="1"/>
+ <pt x="768" y="-37" on="0"/>
+ <pt x="536" y="-37" on="1"/>
+ <pt x="304" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="402" y="-411" on="1"/>
+ <pt x="402" y="-343" on="1"/>
+ <pt x="464" y="-359" on="0"/>
+ <pt x="503" y="-359" on="1"/>
+ <pt x="610" y="-359" on="0"/>
+ <pt x="610" y="-277" on="1"/>
+ <pt x="610" y="-179" on="0"/>
+ <pt x="423" y="-175" on="1"/>
+ <pt x="518" y="0" on="1"/>
+ <pt x="597" y="0" on="1"/>
+ <pt x="531" y="-119" on="1"/>
+ <pt x="748" y="-138" on="0"/>
+ <pt x="748" y="-266" on="1"/>
+ <pt x="748" y="-336" on="0"/>
+ <pt x="690" y="-384" on="1"/>
+ <pt x="633" y="-432" on="0"/>
+ <pt x="546" y="-432" on="1"/>
+ <pt x="478" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 0 0 55 17 68 35 17 23 10 21 50 48 84 50 2 23 0 1 1 31 30 27 26 25 6
+ 5 2 1 0 10 0 2 3 0 0 1 62 61 60 59 53 52 6 13 68 2 0 14 0 0
+ 57 48 64 37 5 19 12 10 46 48 196 64 19 64 62 61 60 59 53 52 31 30 27 19 6
+ 5 2 14 25 0 3 46 25 26 25 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scircumflex" xMin="119" yMin="-37" xMax="1045" yMax="1925">
+ <contour>
+ <pt x="119" y="30" on="1"/>
+ <pt x="119" y="315" on="1"/>
+ <pt x="224" y="315" on="1"/>
+ <pt x="225" y="297" on="1"/>
+ <pt x="227" y="257" on="0"/>
+ <pt x="228" y="228" on="1"/>
+ <pt x="228" y="222" on="1"/>
+ <pt x="228" y="147" on="0"/>
+ <pt x="297" y="99" on="1"/>
+ <pt x="386" y="37" on="0"/>
+ <pt x="542" y="37" on="1"/>
+ <pt x="835" y="37" on="0"/>
+ <pt x="835" y="319" on="1"/>
+ <pt x="835" y="437" on="0"/>
+ <pt x="790" y="498" on="1"/>
+ <pt x="746" y="558" on="0"/>
+ <pt x="602" y="636" on="1"/>
+ <pt x="470" y="707" on="1"/>
+ <pt x="130" y="890" on="0"/>
+ <pt x="130" y="1129" on="1"/>
+ <pt x="130" y="1298" on="0"/>
+ <pt x="255" y="1408" on="1"/>
+ <pt x="379" y="1517" on="0"/>
+ <pt x="581" y="1517" on="1"/>
+ <pt x="741" y="1517" on="0"/>
+ <pt x="962" y="1454" on="1"/>
+ <pt x="962" y="1191" on="1"/>
+ <pt x="851" y="1191" on="1"/>
+ <pt x="850" y="1208" on="1"/>
+ <pt x="847" y="1248" on="0"/>
+ <pt x="846" y="1281" on="1"/>
+ <pt x="846" y="1287" on="1"/>
+ <pt x="846" y="1364" on="0"/>
+ <pt x="797" y="1403" on="1"/>
+ <pt x="739" y="1450" on="0"/>
+ <pt x="596" y="1450" on="1"/>
+ <pt x="332" y="1450" on="0"/>
+ <pt x="332" y="1196" on="1"/>
+ <pt x="332" y="1093" on="0"/>
+ <pt x="376" y="1033" on="1"/>
+ <pt x="419" y="973" on="0"/>
+ <pt x="544" y="906" on="1"/>
+ <pt x="676" y="835" on="1"/>
+ <pt x="891" y="719" on="0"/>
+ <pt x="968" y="626" on="1"/>
+ <pt x="1045" y="534" on="0"/>
+ <pt x="1045" y="392" on="1"/>
+ <pt x="1045" y="206" on="0"/>
+ <pt x="906" y="84" on="1"/>
+ <pt x="768" y="-37" on="0"/>
+ <pt x="536" y="-37" on="1"/>
+ <pt x="304" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="223" y="1604" on="1"/>
+ <pt x="464" y="1925" on="1"/>
+ <pt x="686" y="1925" on="1"/>
+ <pt x="926" y="1604" on="1"/>
+ <pt x="840" y="1604" on="1"/>
+ <pt x="575" y="1826" on="1"/>
+ <pt x="309" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 35 17 23 10 21 50 48 84 50 2 23 0 1 58 57 56 55 52 5 53 0 3 0
+ 1 1 31 30 27 26 25 6 5 2 1 0 10 0 2 3 0 0 54 53 1 0 14 0 0
+ 37 5 19 12 10 46 48 196 19 58 57 56 55 54 53 52 31 30 27 19 6 5 2 14 25
+ 0 3 46 25 26 25 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scommaaccent" xMin="119" yMin="-432" xMax="1045" yMax="1517">
+ <contour>
+ <pt x="119" y="30" on="1"/>
+ <pt x="119" y="315" on="1"/>
+ <pt x="224" y="315" on="1"/>
+ <pt x="225" y="297" on="1"/>
+ <pt x="227" y="257" on="0"/>
+ <pt x="228" y="228" on="1"/>
+ <pt x="228" y="222" on="1"/>
+ <pt x="228" y="147" on="0"/>
+ <pt x="297" y="99" on="1"/>
+ <pt x="386" y="37" on="0"/>
+ <pt x="542" y="37" on="1"/>
+ <pt x="835" y="37" on="0"/>
+ <pt x="835" y="319" on="1"/>
+ <pt x="835" y="437" on="0"/>
+ <pt x="790" y="498" on="1"/>
+ <pt x="746" y="558" on="0"/>
+ <pt x="602" y="636" on="1"/>
+ <pt x="470" y="707" on="1"/>
+ <pt x="130" y="890" on="0"/>
+ <pt x="130" y="1129" on="1"/>
+ <pt x="130" y="1299" on="0"/>
+ <pt x="255" y="1408" on="1"/>
+ <pt x="379" y="1517" on="0"/>
+ <pt x="581" y="1517" on="1"/>
+ <pt x="741" y="1517" on="0"/>
+ <pt x="962" y="1454" on="1"/>
+ <pt x="962" y="1191" on="1"/>
+ <pt x="851" y="1191" on="1"/>
+ <pt x="850" y="1208" on="1"/>
+ <pt x="847" y="1248" on="0"/>
+ <pt x="846" y="1281" on="1"/>
+ <pt x="846" y="1287" on="1"/>
+ <pt x="846" y="1364" on="0"/>
+ <pt x="797" y="1403" on="1"/>
+ <pt x="739" y="1450" on="0"/>
+ <pt x="596" y="1450" on="1"/>
+ <pt x="332" y="1450" on="0"/>
+ <pt x="332" y="1196" on="1"/>
+ <pt x="332" y="1093" on="0"/>
+ <pt x="376" y="1033" on="1"/>
+ <pt x="419" y="973" on="0"/>
+ <pt x="544" y="906" on="1"/>
+ <pt x="676" y="835" on="1"/>
+ <pt x="891" y="719" on="0"/>
+ <pt x="968" y="626" on="1"/>
+ <pt x="1045" y="534" on="0"/>
+ <pt x="1045" y="392" on="1"/>
+ <pt x="1045" y="206" on="0"/>
+ <pt x="906" y="84" on="1"/>
+ <pt x="768" y="-37" on="0"/>
+ <pt x="536" y="-37" on="1"/>
+ <pt x="304" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="442" y="-421" on="1"/>
+ <pt x="442" y="-349" on="1"/>
+ <pt x="491" y="-359" on="0"/>
+ <pt x="546" y="-359" on="1"/>
+ <pt x="649" y="-359" on="0"/>
+ <pt x="649" y="-279" on="1"/>
+ <pt x="649" y="-190" on="0"/>
+ <pt x="491" y="-175" on="1"/>
+ <pt x="491" y="-111" on="1"/>
+ <pt x="625" y="-114" on="0"/>
+ <pt x="691" y="-143" on="1"/>
+ <pt x="784" y="-185" on="0"/>
+ <pt x="784" y="-280" on="1"/>
+ <pt x="784" y="-432" on="0"/>
+ <pt x="567" y="-432" on="1"/>
+ <pt x="507" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 55 17 66 35 17 23 10 21 50 48 84 50 2 23 0 1 1 31 30 27 26 25 6
+ 5 2 1 0 10 0 2 3 0 0 1 60 59 53 52 4 13 66 2 0 14 0 0 57 48
+ 64 37 5 19 12 10 46 48 196 64 19 64 60 59 53 52 31 30 27 19 6 5 2 12 25
+ 0 3 46 25 26 25 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="T" xMin="31" yMin="0" xMax="1221" yMax="1480">
+ <contour>
+ <pt x="521" y="1400" on="1"/>
+ <pt x="325" y="1400" on="1"/>
+ <pt x="222" y="1395" on="1"/>
+ <pt x="158" y="1394" on="0"/>
+ <pt x="148" y="1371" on="1"/>
+ <pt x="140" y="1352" on="0"/>
+ <pt x="140" y="1301" on="1"/>
+ <pt x="140" y="1287" on="1"/>
+ <pt x="139" y="1270" on="1"/>
+ <pt x="139" y="1236" on="0"/>
+ <pt x="138" y="1230" on="1"/>
+ <pt x="136" y="1209" on="1"/>
+ <pt x="31" y="1209" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ <pt x="1221" y="1480" on="1"/>
+ <pt x="1221" y="1209" on="1"/>
+ <pt x="1116" y="1209" on="1"/>
+ <pt x="1115" y="1230" on="1"/>
+ <pt x="1114" y="1253" on="0"/>
+ <pt x="1113" y="1287" on="1"/>
+ <pt x="1113" y="1303" on="1"/>
+ <pt x="1114" y="1366" on="0"/>
+ <pt x="1098" y="1381" on="1"/>
+ <pt x="1083" y="1395" on="0"/>
+ <pt x="1031" y="1395" on="1"/>
+ <pt x="928" y="1400" on="1"/>
+ <pt x="731" y="1400" on="1"/>
+ <pt x="731" y="259" on="1"/>
+ <pt x="731" y="203" on="0"/>
+ <pt x="739" y="147" on="1"/>
+ <pt x="746" y="96" on="0"/>
+ <pt x="771" y="82" on="1"/>
+ <pt x="792" y="71" on="0"/>
+ <pt x="830" y="68" on="1"/>
+ <pt x="898" y="63" on="1"/>
+ <pt x="941" y="62" on="1"/>
+ <pt x="941" y="0" on="1"/>
+ <pt x="312" y="0" on="1"/>
+ <pt x="312" y="62" on="1"/>
+ <pt x="355" y="63" on="1"/>
+ <pt x="423" y="68" on="1"/>
+ <pt x="498" y="74" on="0"/>
+ <pt x="508" y="115" on="1"/>
+ <pt x="521" y="177" on="0"/>
+ <pt x="521" y="259" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 44 37 27 36 24 20 19 16 15 12 11 7 6 9 0 36 3 0 0 26 25 1 0 21 3
+ 13 1 4 48 84 37 36 1 0 14 13 0 14 37 44 36 27 25 24 20 19 16 5 14 26
+ 3 11 7 6 1 4 0 12 3 0 0 27 26 32 1 0 1 4 48 196 15 14 1 44 0
+ 1 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tbar" xMin="31" yMin="0" xMax="1221" yMax="1480">
+ <contour>
+ <pt x="521" y="715" on="1"/>
+ <pt x="218" y="715" on="1"/>
+ <pt x="218" y="789" on="1"/>
+ <pt x="521" y="789" on="1"/>
+ <pt x="521" y="1400" on="1"/>
+ <pt x="325" y="1400" on="1"/>
+ <pt x="222" y="1395" on="1"/>
+ <pt x="158" y="1394" on="0"/>
+ <pt x="148" y="1371" on="1"/>
+ <pt x="140" y="1352" on="0"/>
+ <pt x="140" y="1301" on="1"/>
+ <pt x="140" y="1287" on="1"/>
+ <pt x="139" y="1270" on="1"/>
+ <pt x="139" y="1236" on="0"/>
+ <pt x="138" y="1230" on="1"/>
+ <pt x="136" y="1209" on="1"/>
+ <pt x="31" y="1209" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ <pt x="1221" y="1480" on="1"/>
+ <pt x="1221" y="1209" on="1"/>
+ <pt x="1116" y="1209" on="1"/>
+ <pt x="1115" y="1230" on="1"/>
+ <pt x="1114" y="1253" on="0"/>
+ <pt x="1113" y="1287" on="1"/>
+ <pt x="1113" y="1303" on="1"/>
+ <pt x="1114" y="1366" on="0"/>
+ <pt x="1098" y="1381" on="1"/>
+ <pt x="1083" y="1395" on="0"/>
+ <pt x="1031" y="1395" on="1"/>
+ <pt x="928" y="1400" on="1"/>
+ <pt x="731" y="1400" on="1"/>
+ <pt x="731" y="789" on="1"/>
+ <pt x="1034" y="789" on="1"/>
+ <pt x="1034" y="715" on="1"/>
+ <pt x="731" y="715" on="1"/>
+ <pt x="731" y="259" on="1"/>
+ <pt x="731" y="203" on="0"/>
+ <pt x="739" y="147" on="1"/>
+ <pt x="746" y="96" on="0"/>
+ <pt x="771" y="82" on="1"/>
+ <pt x="792" y="71" on="0"/>
+ <pt x="830" y="68" on="1"/>
+ <pt x="898" y="63" on="1"/>
+ <pt x="941" y="62" on="1"/>
+ <pt x="941" y="0" on="1"/>
+ <pt x="312" y="0" on="1"/>
+ <pt x="312" y="62" on="1"/>
+ <pt x="355" y="63" on="1"/>
+ <pt x="423" y="68" on="1"/>
+ <pt x="498" y="74" on="0"/>
+ <pt x="508" y="115" on="1"/>
+ <pt x="521" y="177" on="0"/>
+ <pt x="521" y="259" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 102 values pushed */
+ 52 45 35 44 28 24 23 20 19 16 15 11 10 9 4 2 3 0 0 30 29 5 4 21 3
+ 17 34 33 1 0 21 3 2 2 4 48 84 32 31 3 2 3 45 44 1 2 0 18 17 0
+ 14 45 52 44 35 33 32 29 28 24 23 20 7 18 30 3 15 11 10 5 2 1 6 0 16
+ 3 0 0 35 34 31 30 32 3 0 1 4 48 196 19 18 1 52 4 3 0 3 17 16 1
+ 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcaron" xMin="31" yMin="0" xMax="1221" yMax="1925">
+ <contour>
+ <pt x="521" y="1400" on="1"/>
+ <pt x="325" y="1400" on="1"/>
+ <pt x="222" y="1395" on="1"/>
+ <pt x="158" y="1394" on="0"/>
+ <pt x="148" y="1371" on="1"/>
+ <pt x="140" y="1352" on="0"/>
+ <pt x="140" y="1301" on="1"/>
+ <pt x="140" y="1287" on="1"/>
+ <pt x="139" y="1270" on="1"/>
+ <pt x="139" y="1236" on="0"/>
+ <pt x="138" y="1230" on="1"/>
+ <pt x="136" y="1209" on="1"/>
+ <pt x="31" y="1209" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ <pt x="1221" y="1480" on="1"/>
+ <pt x="1221" y="1209" on="1"/>
+ <pt x="1116" y="1209" on="1"/>
+ <pt x="1115" y="1230" on="1"/>
+ <pt x="1114" y="1253" on="0"/>
+ <pt x="1113" y="1287" on="1"/>
+ <pt x="1113" y="1303" on="1"/>
+ <pt x="1114" y="1366" on="0"/>
+ <pt x="1098" y="1381" on="1"/>
+ <pt x="1083" y="1395" on="0"/>
+ <pt x="1031" y="1395" on="1"/>
+ <pt x="928" y="1400" on="1"/>
+ <pt x="731" y="1400" on="1"/>
+ <pt x="731" y="259" on="1"/>
+ <pt x="731" y="203" on="0"/>
+ <pt x="739" y="147" on="1"/>
+ <pt x="746" y="96" on="0"/>
+ <pt x="771" y="82" on="1"/>
+ <pt x="792" y="71" on="0"/>
+ <pt x="830" y="68" on="1"/>
+ <pt x="898" y="63" on="1"/>
+ <pt x="941" y="62" on="1"/>
+ <pt x="941" y="0" on="1"/>
+ <pt x="312" y="0" on="1"/>
+ <pt x="312" y="62" on="1"/>
+ <pt x="355" y="63" on="1"/>
+ <pt x="423" y="68" on="1"/>
+ <pt x="498" y="74" on="0"/>
+ <pt x="508" y="115" on="1"/>
+ <pt x="521" y="177" on="0"/>
+ <pt x="521" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="978" y="1925" on="1"/>
+ <pt x="738" y="1604" on="1"/>
+ <pt x="516" y="1604" on="1"/>
+ <pt x="275" y="1925" on="1"/>
+ <pt x="361" y="1925" on="1"/>
+ <pt x="627" y="1703" on="1"/>
+ <pt x="892" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 44 37 27 36 24 20 19 16 15 12 11 7 6 9 0 36 3 51 50 49 48 45 5 13 46
+ 0 0 26 25 1 0 21 3 13 1 4 48 84 47 46 1 37 36 1 2 0 14 13 0 14
+ 37 44 36 27 51 46 45 25 24 20 19 16 8 14 26 3 50 26 0 2 49 48 47 11 7
+ 6 1 7 0 12 3 0 0 27 26 32 1 0 1 4 48 196 15 14 1 44 0 1 13 12
+ 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcommaaccent" xMin="31" yMin="-432" xMax="1221" yMax="1480">
+ <contour>
+ <pt x="521" y="1400" on="1"/>
+ <pt x="325" y="1400" on="1"/>
+ <pt x="222" y="1395" on="1"/>
+ <pt x="158" y="1394" on="0"/>
+ <pt x="148" y="1371" on="1"/>
+ <pt x="140" y="1352" on="0"/>
+ <pt x="140" y="1301" on="1"/>
+ <pt x="140" y="1287" on="1"/>
+ <pt x="139" y="1270" on="1"/>
+ <pt x="139" y="1236" on="0"/>
+ <pt x="138" y="1230" on="1"/>
+ <pt x="136" y="1209" on="1"/>
+ <pt x="31" y="1209" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ <pt x="1221" y="1480" on="1"/>
+ <pt x="1221" y="1209" on="1"/>
+ <pt x="1116" y="1209" on="1"/>
+ <pt x="1115" y="1230" on="1"/>
+ <pt x="1114" y="1253" on="0"/>
+ <pt x="1113" y="1287" on="1"/>
+ <pt x="1113" y="1303" on="1"/>
+ <pt x="1114" y="1366" on="0"/>
+ <pt x="1098" y="1381" on="1"/>
+ <pt x="1083" y="1395" on="0"/>
+ <pt x="1031" y="1395" on="1"/>
+ <pt x="928" y="1400" on="1"/>
+ <pt x="731" y="1400" on="1"/>
+ <pt x="731" y="259" on="1"/>
+ <pt x="731" y="203" on="0"/>
+ <pt x="739" y="147" on="1"/>
+ <pt x="744" y="109" on="0"/>
+ <pt x="753" y="97" on="1"/>
+ <pt x="772" y="72" on="0"/>
+ <pt x="830" y="68" on="1"/>
+ <pt x="898" y="63" on="1"/>
+ <pt x="941" y="62" on="1"/>
+ <pt x="941" y="0" on="1"/>
+ <pt x="312" y="0" on="1"/>
+ <pt x="312" y="62" on="1"/>
+ <pt x="355" y="63" on="1"/>
+ <pt x="423" y="68" on="1"/>
+ <pt x="498" y="74" on="0"/>
+ <pt x="508" y="115" on="1"/>
+ <pt x="521" y="177" on="0"/>
+ <pt x="521" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="484" y="-411" on="1"/>
+ <pt x="484" y="-343" on="1"/>
+ <pt x="546" y="-359" on="0"/>
+ <pt x="585" y="-359" on="1"/>
+ <pt x="692" y="-359" on="0"/>
+ <pt x="692" y="-277" on="1"/>
+ <pt x="692" y="-179" on="0"/>
+ <pt x="505" y="-175" on="1"/>
+ <pt x="600" y="0" on="1"/>
+ <pt x="679" y="0" on="1"/>
+ <pt x="613" y="-119" on="1"/>
+ <pt x="830" y="-138" on="0"/>
+ <pt x="830" y="-266" on="1"/>
+ <pt x="830" y="-336" on="0"/>
+ <pt x="772" y="-384" on="1"/>
+ <pt x="715" y="-432" on="0"/>
+ <pt x="628" y="-432" on="1"/>
+ <pt x="560" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 117 values pushed */
+ 0 0 48 17 61 48 84 44 37 27 36 24 20 19 16 15 12 11 7 6 9 0 36 3 55
+ 52 46 45 4 13 61 36 0 0 26 25 1 0 21 3 13 1 4 48 84 54 53 37 36 3
+ 0 14 13 0 14 0 0 50 48 57 48 196 37 44 36 27 57 57 25 24 20 19 16 6 14
+ 26 3 55 54 53 3 26 0 3 52 46 45 11 7 6 1 7 0 12 3 0 0 27 26 32
+ 1 0 1 4 48 196 15 14 1 44 0 1 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcommabelow" xMin="31" yMin="-432" xMax="1221" yMax="1480">
+ <contour>
+ <pt x="521" y="1400" on="1"/>
+ <pt x="325" y="1400" on="1"/>
+ <pt x="222" y="1395" on="1"/>
+ <pt x="158" y="1394" on="0"/>
+ <pt x="148" y="1371" on="1"/>
+ <pt x="140" y="1352" on="0"/>
+ <pt x="140" y="1301" on="1"/>
+ <pt x="140" y="1287" on="1"/>
+ <pt x="139" y="1270" on="1"/>
+ <pt x="139" y="1236" on="0"/>
+ <pt x="138" y="1230" on="1"/>
+ <pt x="136" y="1209" on="1"/>
+ <pt x="31" y="1209" on="1"/>
+ <pt x="31" y="1480" on="1"/>
+ <pt x="1221" y="1480" on="1"/>
+ <pt x="1221" y="1209" on="1"/>
+ <pt x="1116" y="1209" on="1"/>
+ <pt x="1115" y="1230" on="1"/>
+ <pt x="1114" y="1253" on="0"/>
+ <pt x="1113" y="1287" on="1"/>
+ <pt x="1113" y="1303" on="1"/>
+ <pt x="1114" y="1366" on="0"/>
+ <pt x="1098" y="1381" on="1"/>
+ <pt x="1083" y="1395" on="0"/>
+ <pt x="1031" y="1395" on="1"/>
+ <pt x="928" y="1400" on="1"/>
+ <pt x="731" y="1400" on="1"/>
+ <pt x="731" y="259" on="1"/>
+ <pt x="731" y="203" on="0"/>
+ <pt x="739" y="147" on="1"/>
+ <pt x="744" y="109" on="0"/>
+ <pt x="753" y="97" on="1"/>
+ <pt x="772" y="72" on="0"/>
+ <pt x="830" y="68" on="1"/>
+ <pt x="898" y="63" on="1"/>
+ <pt x="941" y="62" on="1"/>
+ <pt x="941" y="0" on="1"/>
+ <pt x="312" y="0" on="1"/>
+ <pt x="312" y="62" on="1"/>
+ <pt x="355" y="63" on="1"/>
+ <pt x="423" y="68" on="1"/>
+ <pt x="498" y="74" on="0"/>
+ <pt x="508" y="115" on="1"/>
+ <pt x="521" y="177" on="0"/>
+ <pt x="521" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="472" y="-421" on="1"/>
+ <pt x="472" y="-349" on="1"/>
+ <pt x="521" y="-359" on="0"/>
+ <pt x="576" y="-359" on="1"/>
+ <pt x="679" y="-359" on="0"/>
+ <pt x="679" y="-279" on="1"/>
+ <pt x="679" y="-190" on="0"/>
+ <pt x="521" y="-175" on="1"/>
+ <pt x="521" y="-111" on="1"/>
+ <pt x="655" y="-114" on="0"/>
+ <pt x="721" y="-143" on="1"/>
+ <pt x="814" y="-185" on="0"/>
+ <pt x="814" y="-280" on="1"/>
+ <pt x="814" y="-432" on="0"/>
+ <pt x="597" y="-432" on="1"/>
+ <pt x="538" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 48 38 59 48 84 44 37 27 36 24 20 19 16 15 12 11 7 6 9 0 36 3 53
+ 52 46 45 4 13 59 36 0 0 26 25 1 0 42 3 13 1 4 48 84 37 36 1 0 14
+ 13 0 14 0 0 50 23 57 48 196 37 44 36 27 57 57 25 24 20 19 16 6 14 26 3
+ 46 45 11 7 6 1 6 0 12 3 0 0 27 26 37 1 0 1 4 48 196 15 14 1 53
+ 52 44 0 3 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Thorn" xMin="43" yMin="0" xMax="1077" yMax="1480">
+ <contour>
+ <pt x="438" y="1178" on="1"/>
+ <pt x="543" y="1179" on="1"/>
+ <pt x="800" y="1181" on="0"/>
+ <pt x="930" y="1104" on="1"/>
+ <pt x="1077" y="1016" on="0"/>
+ <pt x="1077" y="791" on="1"/>
+ <pt x="1077" y="315" on="0"/>
+ <pt x="443" y="315" on="1"/>
+ <pt x="438" y="315" on="1"/>
+ <pt x="438" y="259" on="1"/>
+ <pt x="438" y="200" on="0"/>
+ <pt x="445" y="147" on="1"/>
+ <pt x="451" y="109" on="0"/>
+ <pt x="459" y="97" on="1"/>
+ <pt x="478" y="72" on="0"/>
+ <pt x="536" y="68" on="1"/>
+ <pt x="604" y="63" on="1"/>
+ <pt x="623" y="62" on="1"/>
+ <pt x="623" y="0" on="1"/>
+ <pt x="43" y="0" on="1"/>
+ <pt x="43" y="62" on="1"/>
+ <pt x="62" y="63" on="1"/>
+ <pt x="129" y="68" on="1"/>
+ <pt x="205" y="74" on="0"/>
+ <pt x="215" y="115" on="1"/>
+ <pt x="228" y="177" on="0"/>
+ <pt x="228" y="259" on="1"/>
+ <pt x="228" y="1221" on="1"/>
+ <pt x="228" y="1280" on="0"/>
+ <pt x="221" y="1333" on="1"/>
+ <pt x="215" y="1372" on="0"/>
+ <pt x="207" y="1384" on="1"/>
+ <pt x="189" y="1410" on="0"/>
+ <pt x="129" y="1413" on="1"/>
+ <pt x="62" y="1417" on="1"/>
+ <pt x="43" y="1419" on="1"/>
+ <pt x="43" y="1480" on="1"/>
+ <pt x="623" y="1480" on="1"/>
+ <pt x="623" y="1419" on="1"/>
+ <pt x="604" y="1417" on="1"/>
+ <pt x="536" y="1413" on="1"/>
+ <pt x="461" y="1408" on="0"/>
+ <pt x="451" y="1366" on="1"/>
+ <pt x="438" y="1302" on="0"/>
+ <pt x="438" y="1221" on="1"/>
+ </contour>
+ <contour>
+ <pt x="438" y="382" on="1"/>
+ <pt x="455" y="382" on="1"/>
+ <pt x="647" y="382" on="0"/>
+ <pt x="751" y="489" on="1"/>
+ <pt x="855" y="596" on="0"/>
+ <pt x="855" y="791" on="1"/>
+ <pt x="855" y="959" on="0"/>
+ <pt x="769" y="1035" on="1"/>
+ <pt x="683" y="1110" on="0"/>
+ <pt x="494" y="1110" on="1"/>
+ <pt x="438" y="1110" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 44 37 27 36 26 19 9 18 55 54 46 45 8 7 0 7 36 18 3 19 18 1 0 37 36
+ 0 14 0 0 50 33 5 48 196 37 44 36 27 19 26 18 9 54 46 7 3 13 5 0 0
+ 0 55 45 44 9 8 0 32 5 26 1 4 48 196 27 26 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="U" xMin="19" yMin="-37" xMax="1456" yMax="1480">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 15 17 44 48 84 44 2 47 56 37 30 22 29 1 46 38 21 9 8 1 6 0 2
+ 3 0 56 30 29 0 0 3 14 56 47 30 37 29 22 1 0 2 21 8 3 0 0 22 21
+ 9 1 37 9 8 32 1 46 2 4 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uacute" xMin="19" yMin="-37" xMax="1456" yMax="1925">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="650" y="1604" on="1"/>
+ <pt x="891" y="1925" on="1"/>
+ <pt x="1150" y="1925" on="1"/>
+ <pt x="743" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 0 0 15 17 44 48 84 44 2 47 56 37 30 22 29 60 57 2 58 0 3 1 46 38 21
+ 9 8 1 6 0 2 3 0 59 58 1 0 56 30 29 0 0 3 14 56 47 30 37 29 22
+ 60 59 58 57 1 0 6 21 8 3 0 0 22 21 9 1 37 9 8 32 1 46 2 4 48
+ 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ubreve" xMin="19" yMin="-37" xMax="1456" yMax="1925">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="442" y="1925" on="1"/>
+ <pt x="507" y="1925" on="1"/>
+ <pt x="534" y="1835" on="0"/>
+ <pt x="594" y="1793" on="1"/>
+ <pt x="662" y="1746" on="0"/>
+ <pt x="775" y="1746" on="1"/>
+ <pt x="901" y="1746" on="0"/>
+ <pt x="971" y="1805" on="1"/>
+ <pt x="1020" y="1845" on="0"/>
+ <pt x="1044" y="1925" on="1"/>
+ <pt x="1108" y="1925" on="1"/>
+ <pt x="1089" y="1790" on="0"/>
+ <pt x="1017" y="1709" on="1"/>
+ <pt x="923" y="1604" on="0"/>
+ <pt x="775" y="1604" on="1"/>
+ <pt x="621" y="1604" on="0"/>
+ <pt x="526" y="1719" on="1"/>
+ <pt x="461" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 62 20 71 15 38 44 48 84 44 2 47 56 37 30 22 29 1 46 38 21 9 8 1
+ 6 0 2 3 0 67 66 58 57 4 13 71 0 56 30 29 0 0 3 14 56 47 30 37 29
+ 22 67 66 58 57 1 0 6 21 8 3 0 0 22 21 41 1 37 9 8 37 1 46 2 4
+ 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ucircumflex" xMin="19" yMin="-37" xMax="1456" yMax="1925">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="440" y="1604" on="1"/>
+ <pt x="681" y="1925" on="1"/>
+ <pt x="903" y="1925" on="1"/>
+ <pt x="1143" y="1604" on="1"/>
+ <pt x="1057" y="1604" on="1"/>
+ <pt x="792" y="1826" on="1"/>
+ <pt x="526" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 0 0 15 17 44 48 84 44 2 47 56 37 30 22 29 63 62 61 60 57 5 58 0 3 1
+ 46 38 21 9 8 1 6 0 2 3 0 59 58 1 0 56 30 29 0 0 3 14 56 47 30
+ 37 29 22 63 62 61 60 59 58 57 1 0 9 21 8 3 0 0 22 21 9 1 37 9 8
+ 32 1 46 2 4 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Udieresis" xMin="19" yMin="-37" xMax="1456" yMax="1777">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="508" y="1604" on="1"/>
+ <pt x="508" y="1777" on="1"/>
+ <pt x="681" y="1777" on="1"/>
+ <pt x="681" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="903" y="1604" on="1"/>
+ <pt x="903" y="1777" on="1"/>
+ <pt x="1076" y="1777" on="1"/>
+ <pt x="1076" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 105 values pushed */
+ 0 0 15 17 44 48 84 44 2 47 56 37 30 22 29 1 46 38 21 9 8 1 6 0 2
+ 3 0 0 0 64 61 60 57 13 3 58 1 4 48 84 63 62 59 58 3 0 56 30 29 0
+ 0 3 14 56 47 30 37 29 22 1 0 2 59 57 3 0 0 62 61 13 1 63 60 59 13
+ 1 57 22 21 9 1 37 9 8 32 1 46 4 4 48 196 64 63 1 58 57 1 38 37 1
+ 47 46 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ugrave" xMin="19" yMin="-37" xMax="1456" yMax="1925">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="934" y="1604" on="1"/>
+ <pt x="841" y="1604" on="1"/>
+ <pt x="434" y="1925" on="1"/>
+ <pt x="693" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 84 values pushed */
+ 0 0 15 17 44 48 84 44 2 47 56 37 30 22 29 58 57 2 59 0 3 1 46 38 21
+ 9 8 1 6 0 2 3 0 60 59 1 0 56 30 29 0 0 3 14 56 47 30 37 29 22
+ 60 59 58 57 1 0 6 21 8 3 0 0 22 21 9 1 37 9 8 32 1 46 2 4 48
+ 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uhungarumlaut" xMin="19" yMin="-37" xMax="1456" yMax="1925">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="565" y="1604" on="1"/>
+ <pt x="779" y="1925" on="1"/>
+ <pt x="948" y="1925" on="1"/>
+ <pt x="627" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="874" y="1604" on="1"/>
+ <pt x="1087" y="1925" on="1"/>
+ <pt x="1256" y="1925" on="1"/>
+ <pt x="935" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 95 values pushed */
+ 0 0 15 17 44 48 84 44 2 47 56 37 30 22 29 64 61 60 57 4 58 0 3 1 46
+ 38 21 9 8 1 6 0 2 3 0 63 62 59 58 3 0 56 30 29 0 0 3 14 56 47
+ 30 37 29 22 63 37 21 2 64 62 61 60 59 58 57 1 0 9 21 8 3 0 0 22 21
+ 9 1 37 9 8 32 1 46 2 4 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Umacron" xMin="19" yMin="-37" xMax="1456" yMax="1727">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="470" y="1604" on="1"/>
+ <pt x="470" y="1727" on="1"/>
+ <pt x="1112" y="1727" on="1"/>
+ <pt x="1112" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 0 0 15 17 44 48 84 44 2 47 56 37 30 22 29 1 46 38 21 9 8 1 6 0 2
+ 3 0 0 0 60 57 12 1 58 1 4 48 84 59 58 1 0 56 30 29 0 0 3 14 56
+ 47 30 37 29 22 60 59 58 57 1 0 6 21 8 3 0 0 22 21 9 1 37 9 8 32
+ 1 46 2 4 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Unterkomma" xMin="170" yMin="-432" xMax="512" yMax="-111">
+ <contour>
+ <pt x="170" y="-421" on="1"/>
+ <pt x="170" y="-349" on="1"/>
+ <pt x="219" y="-359" on="0"/>
+ <pt x="274" y="-359" on="1"/>
+ <pt x="377" y="-359" on="0"/>
+ <pt x="377" y="-279" on="1"/>
+ <pt x="377" y="-190" on="0"/>
+ <pt x="219" y="-175" on="1"/>
+ <pt x="219" y="-111" on="1"/>
+ <pt x="353" y="-114" on="0"/>
+ <pt x="419" y="-143" on="1"/>
+ <pt x="512" y="-185" on="0"/>
+ <pt x="512" y="-280" on="1"/>
+ <pt x="512" y="-432" on="0"/>
+ <pt x="295" y="-432" on="1"/>
+ <pt x="236" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 3 17 14 48 84 14 8 7 1 0 14 0 0 5 48 12 48 196 12 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uogonek" xMin="19" yMin="-370" xMax="1456" yMax="1480">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1365" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="395" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1034" y="-273" on="1"/>
+ <pt x="1034" y="-341" on="1"/>
+ <pt x="963" y="-370" on="0"/>
+ <pt x="885" y="-370" on="1"/>
+ <pt x="665" y="-370" on="0"/>
+ <pt x="665" y="-211" on="1"/>
+ <pt x="665" y="-90" on="0"/>
+ <pt x="823" y="0" on="1"/>
+ <pt x="930" y="0" on="1"/>
+ <pt x="801" y="-80" on="0"/>
+ <pt x="801" y="-182" on="1"/>
+ <pt x="801" y="-289" on="0"/>
+ <pt x="934" y="-289" on="1"/>
+ <pt x="985" y="-289" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 96 values pushed */
+ 0 0 69 7 60 15 17 44 48 84 44 2 47 56 37 30 22 29 1 46 38 21 9 8 1
+ 6 0 2 3 0 1 65 64 58 57 4 13 60 2 0 56 30 29 0 0 3 14 0 0 67
+ 48 62 48 196 56 47 30 37 29 22 62 65 64 62 58 57 1 0 7 21 8 3 0 0 22
+ 21 9 1 37 9 8 32 1 46 2 4 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uring" xMin="19" yMin="-37" xMax="1456" yMax="2033">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="782" y="2033" on="1"/>
+ <pt x="876" y="2033" on="0"/>
+ <pt x="942" y="1967" on="1"/>
+ <pt x="1009" y="1901" on="0"/>
+ <pt x="1009" y="1807" on="1"/>
+ <pt x="1009" y="1711" on="0"/>
+ <pt x="942" y="1645" on="1"/>
+ <pt x="875" y="1579" on="0"/>
+ <pt x="780" y="1579" on="1"/>
+ <pt x="696" y="1579" on="0"/>
+ <pt x="635" y="1633" on="1"/>
+ <pt x="555" y="1702" on="0"/>
+ <pt x="555" y="1806" on="1"/>
+ <pt x="555" y="1901" on="0"/>
+ <pt x="621" y="1967" on="1"/>
+ <pt x="687" y="2033" on="0"/>
+ </contour>
+ <contour>
+ <pt x="782" y="1965" on="1"/>
+ <pt x="716" y="1965" on="0"/>
+ <pt x="670" y="1919" on="1"/>
+ <pt x="623" y="1872" on="0"/>
+ <pt x="623" y="1807" on="1"/>
+ <pt x="623" y="1741" on="0"/>
+ <pt x="669" y="1694" on="1"/>
+ <pt x="715" y="1647" on="0"/>
+ <pt x="780" y="1647" on="1"/>
+ <pt x="841" y="1647" on="0"/>
+ <pt x="885" y="1684" on="1"/>
+ <pt x="941" y="1733" on="0"/>
+ <pt x="941" y="1807" on="1"/>
+ <pt x="941" y="1873" on="0"/>
+ <pt x="894" y="1919" on="1"/>
+ <pt x="847" y="1965" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 93 values pushed */
+ 0 0 81 17 65 73 17 57 15 17 44 48 84 44 2 47 56 37 30 22 29 1 46 38 21
+ 9 8 1 6 0 2 3 0 65 57 0 56 30 29 0 0 3 14 0 0 85 17 61 77 17
+ 69 48 196 56 47 30 37 29 22 69 61 69 61 1 0 4 21 8 3 0 0 22 21 9 1
+ 37 9 8 32 1 46 2 4 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Utilde" xMin="19" yMin="-37" xMax="1456" yMax="1839">
+ <contour>
+ <pt x="602" y="1480" on="1"/>
+ <pt x="602" y="1419" on="1"/>
+ <pt x="584" y="1417" on="1"/>
+ <pt x="516" y="1413" on="1"/>
+ <pt x="448" y="1408" on="0"/>
+ <pt x="437" y="1386" on="1"/>
+ <pt x="426" y="1367" on="0"/>
+ <pt x="423" y="1320" on="1"/>
+ <pt x="417" y="1221" on="1"/>
+ <pt x="417" y="588" on="1"/>
+ <pt x="417" y="360" on="0"/>
+ <pt x="429" y="290" on="1"/>
+ <pt x="441" y="219" on="0"/>
+ <pt x="490" y="156" on="1"/>
+ <pt x="587" y="31" on="0"/>
+ <pt x="779" y="31" on="1"/>
+ <pt x="978" y="31" on="0"/>
+ <pt x="1087" y="160" on="1"/>
+ <pt x="1143" y="227" on="0"/>
+ <pt x="1156" y="319" on="1"/>
+ <pt x="1167" y="397" on="0"/>
+ <pt x="1167" y="544" on="1"/>
+ <pt x="1167" y="1221" on="1"/>
+ <pt x="1168" y="1335" on="0"/>
+ <pt x="1149" y="1377" on="1"/>
+ <pt x="1134" y="1409" on="0"/>
+ <pt x="1068" y="1413" on="1"/>
+ <pt x="1000" y="1417" on="1"/>
+ <pt x="982" y="1419" on="1"/>
+ <pt x="982" y="1480" on="1"/>
+ <pt x="1456" y="1480" on="1"/>
+ <pt x="1456" y="1419" on="1"/>
+ <pt x="1437" y="1417" on="1"/>
+ <pt x="1369" y="1413" on="1"/>
+ <pt x="1294" y="1408" on="0"/>
+ <pt x="1284" y="1366" on="1"/>
+ <pt x="1271" y="1302" on="0"/>
+ <pt x="1271" y="1221" on="1"/>
+ <pt x="1271" y="601" on="1"/>
+ <pt x="1271" y="394" on="0"/>
+ <pt x="1248" y="299" on="1"/>
+ <pt x="1224" y="201" on="0"/>
+ <pt x="1156" y="120" on="1"/>
+ <pt x="1023" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="204" y="-37" on="0"/>
+ <pt x="204" y="554" on="1"/>
+ <pt x="204" y="1221" on="1"/>
+ <pt x="204" y="1280" on="0"/>
+ <pt x="197" y="1333" on="1"/>
+ <pt x="191" y="1372" on="0"/>
+ <pt x="183" y="1384" on="1"/>
+ <pt x="165" y="1410" on="0"/>
+ <pt x="105" y="1413" on="1"/>
+ <pt x="38" y="1417" on="1"/>
+ <pt x="19" y="1419" on="1"/>
+ <pt x="19" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="442" y="1604" on="1"/>
+ <pt x="469" y="1744" on="0"/>
+ <pt x="538" y="1797" on="1"/>
+ <pt x="591" y="1839" on="0"/>
+ <pt x="669" y="1839" on="1"/>
+ <pt x="734" y="1839" on="0"/>
+ <pt x="787" y="1801" on="1"/>
+ <pt x="822" y="1776" on="1"/>
+ <pt x="874" y="1739" on="0"/>
+ <pt x="928" y="1739" on="1"/>
+ <pt x="1023" y="1739" on="0"/>
+ <pt x="1046" y="1838" on="1"/>
+ <pt x="1108" y="1838" on="1"/>
+ <pt x="1080" y="1699" on="0"/>
+ <pt x="1012" y="1646" on="1"/>
+ <pt x="958" y="1604" on="0"/>
+ <pt x="881" y="1604" on="1"/>
+ <pt x="818" y="1604" on="0"/>
+ <pt x="763" y="1642" on="1"/>
+ <pt x="728" y="1666" on="1"/>
+ <pt x="673" y="1704" on="0"/>
+ <pt x="622" y="1704" on="1"/>
+ <pt x="533" y="1704" on="0"/>
+ <pt x="504" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 0 0 78 20 61 66 20 73 15 38 44 48 84 44 2 47 56 37 30 22 29 1 46 38 21
+ 9 8 1 6 0 2 3 0 80 69 68 57 4 13 73 61 0 56 30 29 0 0 3 14 56
+ 47 30 37 29 22 80 69 68 57 1 0 6 21 8 3 0 0 22 21 41 1 37 9 8 37
+ 1 46 2 4 48 196 38 37 1 47 46 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="V" xMin="0" yMin="-19" xMax="1479" yMax="1480">
+ <contour>
+ <pt x="724" y="-19" on="1"/>
+ <pt x="193" y="1216" on="1"/>
+ <pt x="137" y="1342" on="1"/>
+ <pt x="113" y="1398" on="0"/>
+ <pt x="91" y="1406" on="1"/>
+ <pt x="68" y="1414" on="0"/>
+ <pt x="21" y="1417" on="1"/>
+ <pt x="0" y="1419" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="543" y="1480" on="1"/>
+ <pt x="543" y="1419" on="1"/>
+ <pt x="522" y="1419" on="1"/>
+ <pt x="367" y="1419" on="0"/>
+ <pt x="367" y="1380" on="1"/>
+ <pt x="367" y="1366" on="0"/>
+ <pt x="401" y="1283" on="1"/>
+ <pt x="428" y="1216" on="1"/>
+ <pt x="828" y="284" on="1"/>
+ <pt x="1210" y="1217" on="1"/>
+ <pt x="1230" y="1268" on="1"/>
+ <pt x="1262" y="1349" on="0"/>
+ <pt x="1262" y="1376" on="1"/>
+ <pt x="1262" y="1415" on="0"/>
+ <pt x="1193" y="1417" on="1"/>
+ <pt x="1117" y="1419" on="1"/>
+ <pt x="1095" y="1419" on="1"/>
+ <pt x="1095" y="1480" on="1"/>
+ <pt x="1479" y="1480" on="1"/>
+ <pt x="1479" y="1419" on="1"/>
+ <pt x="1457" y="1417" on="1"/>
+ <pt x="1394" y="1413" on="0"/>
+ <pt x="1377" y="1396" on="1"/>
+ <pt x="1359" y="1380" on="0"/>
+ <pt x="1341" y="1335" on="1"/>
+ <pt x="1294" y="1217" on="1"/>
+ <pt x="792" y="-19" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 1 28 25 24 17 16 11 10 7 1 9 8 2 3 0 1 35 0 2 0 27 26 9 8 0
+ 3 14 35 28 27 26 25 24 21 17 16 13 11 10 9 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="W" xMin="0" yMin="-19" xMax="1933" yMax="1480">
+ <contour>
+ <pt x="524" y="-19" on="1"/>
+ <pt x="188" y="1215" on="1"/>
+ <pt x="155" y="1336" on="0"/>
+ <pt x="153" y="1347" on="1"/>
+ <pt x="138" y="1416" on="0"/>
+ <pt x="80" y="1416" on="1"/>
+ <pt x="22" y="1417" on="1"/>
+ <pt x="0" y="1419" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="536" y="1480" on="1"/>
+ <pt x="536" y="1419" on="1"/>
+ <pt x="516" y="1419" on="1"/>
+ <pt x="462" y="1417" on="1"/>
+ <pt x="368" y="1414" on="0"/>
+ <pt x="368" y="1363" on="1"/>
+ <pt x="368" y="1323" on="0"/>
+ <pt x="397" y="1215" on="1"/>
+ <pt x="630" y="354" on="1"/>
+ <pt x="990" y="1462" on="1"/>
+ <pt x="1060" y="1462" on="1"/>
+ <pt x="1382" y="323" on="1"/>
+ <pt x="1658" y="1214" on="1"/>
+ <pt x="1701" y="1352" on="0"/>
+ <pt x="1701" y="1383" on="1"/>
+ <pt x="1701" y="1415" on="0"/>
+ <pt x="1613" y="1417" on="1"/>
+ <pt x="1545" y="1419" on="1"/>
+ <pt x="1526" y="1419" on="1"/>
+ <pt x="1526" y="1480" on="1"/>
+ <pt x="1933" y="1480" on="1"/>
+ <pt x="1933" y="1419" on="1"/>
+ <pt x="1916" y="1417" on="1"/>
+ <pt x="1856" y="1415" on="1"/>
+ <pt x="1796" y="1413" on="0"/>
+ <pt x="1777" y="1352" on="1"/>
+ <pt x="1734" y="1215" on="1"/>
+ <pt x="1352" y="-19" on="1"/>
+ <pt x="1285" y="-19" on="1"/>
+ <pt x="963" y="1120" on="1"/>
+ <pt x="593" y="-19" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 1 38 30 27 26 19 18 11 10 7 9 8 1 3 0 1 1 20 17 2 1 2 3 0 0
+ 1 39 37 36 0 4 13 2 0 29 28 9 8 0 3 14 39 38 37 36 30 29 28 27 26
+ 23 20 19 18 17 14 11 10 9 8 7 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Wcircumflex" xMin="0" yMin="-19" xMax="1933" yMax="1925">
+ <contour>
+ <pt x="524" y="-19" on="1"/>
+ <pt x="188" y="1215" on="1"/>
+ <pt x="155" y="1336" on="0"/>
+ <pt x="153" y="1347" on="1"/>
+ <pt x="138" y="1416" on="0"/>
+ <pt x="80" y="1416" on="1"/>
+ <pt x="22" y="1417" on="1"/>
+ <pt x="0" y="1419" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="536" y="1480" on="1"/>
+ <pt x="536" y="1419" on="1"/>
+ <pt x="516" y="1419" on="1"/>
+ <pt x="462" y="1417" on="1"/>
+ <pt x="368" y="1414" on="0"/>
+ <pt x="368" y="1363" on="1"/>
+ <pt x="368" y="1323" on="0"/>
+ <pt x="397" y="1215" on="1"/>
+ <pt x="630" y="354" on="1"/>
+ <pt x="990" y="1462" on="1"/>
+ <pt x="1060" y="1462" on="1"/>
+ <pt x="1382" y="323" on="1"/>
+ <pt x="1658" y="1214" on="1"/>
+ <pt x="1701" y="1352" on="0"/>
+ <pt x="1701" y="1383" on="1"/>
+ <pt x="1701" y="1415" on="0"/>
+ <pt x="1613" y="1417" on="1"/>
+ <pt x="1545" y="1419" on="1"/>
+ <pt x="1526" y="1419" on="1"/>
+ <pt x="1526" y="1480" on="1"/>
+ <pt x="1933" y="1480" on="1"/>
+ <pt x="1933" y="1419" on="1"/>
+ <pt x="1916" y="1417" on="1"/>
+ <pt x="1856" y="1415" on="1"/>
+ <pt x="1796" y="1413" on="0"/>
+ <pt x="1777" y="1352" on="1"/>
+ <pt x="1734" y="1215" on="1"/>
+ <pt x="1352" y="-19" on="1"/>
+ <pt x="1285" y="-19" on="1"/>
+ <pt x="963" y="1120" on="1"/>
+ <pt x="593" y="-19" on="1"/>
+ </contour>
+ <contour>
+ <pt x="679" y="1604" on="1"/>
+ <pt x="920" y="1925" on="1"/>
+ <pt x="1142" y="1925" on="1"/>
+ <pt x="1382" y="1604" on="1"/>
+ <pt x="1296" y="1604" on="1"/>
+ <pt x="1031" y="1826" on="1"/>
+ <pt x="765" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 46 45 44 43 40 5 41 8 3 1 38 30 27 26 19 18 11 10 7 9 8 1 3 0 1
+ 1 20 17 2 1 2 3 0 0 1 39 37 36 0 4 13 2 0 42 41 1 0 29 28 9
+ 8 0 3 14 46 45 44 43 42 41 40 39 38 37 36 30 29 28 27 26 23 20 19 18 17
+ 14 11 10 9 8 7 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="X" xMin="12" yMin="0" xMax="1466" yMax="1480">
+ <contour>
+ <pt x="12" y="0" on="1"/>
+ <pt x="12" y="62" on="1"/>
+ <pt x="26" y="63" on="1"/>
+ <pt x="69" y="66" on="1"/>
+ <pt x="132" y="72" on="0"/>
+ <pt x="187" y="144" on="1"/>
+ <pt x="278" y="261" on="1"/>
+ <pt x="633" y="729" on="1"/>
+ <pt x="302" y="1222" on="1"/>
+ <pt x="222" y="1333" on="1"/>
+ <pt x="167" y="1411" on="0"/>
+ <pt x="107" y="1415" on="1"/>
+ <pt x="57" y="1417" on="1"/>
+ <pt x="36" y="1419" on="1"/>
+ <pt x="36" y="1480" on="1"/>
+ <pt x="619" y="1480" on="1"/>
+ <pt x="619" y="1419" on="1"/>
+ <pt x="601" y="1419" on="1"/>
+ <pt x="531" y="1418" on="1"/>
+ <pt x="456" y="1417" on="0"/>
+ <pt x="456" y="1386" on="1"/>
+ <pt x="456" y="1370" on="0"/>
+ <pt x="501" y="1310" on="1"/>
+ <pt x="509" y="1300" on="0"/>
+ <pt x="536" y="1258" on="1"/>
+ <pt x="560" y="1223" on="1"/>
+ <pt x="801" y="859" on="1"/>
+ <pt x="1091" y="1223" on="1"/>
+ <pt x="1200" y="1360" on="0"/>
+ <pt x="1200" y="1391" on="1"/>
+ <pt x="1200" y="1414" on="0"/>
+ <pt x="1138" y="1417" on="1"/>
+ <pt x="1089" y="1419" on="1"/>
+ <pt x="1070" y="1419" on="1"/>
+ <pt x="1070" y="1480" on="1"/>
+ <pt x="1441" y="1480" on="1"/>
+ <pt x="1441" y="1419" on="1"/>
+ <pt x="1417" y="1417" on="1"/>
+ <pt x="1325" y="1411" on="0"/>
+ <pt x="1264" y="1326" on="1"/>
+ <pt x="1229" y="1279" on="0"/>
+ <pt x="1184" y="1223" on="1"/>
+ <pt x="855" y="814" on="1"/>
+ <pt x="1220" y="261" on="1"/>
+ <pt x="1307" y="137" on="1"/>
+ <pt x="1351" y="71" on="0"/>
+ <pt x="1394" y="66" on="1"/>
+ <pt x="1447" y="63" on="1"/>
+ <pt x="1466" y="62" on="1"/>
+ <pt x="1466" y="0" on="1"/>
+ <pt x="899" y="0" on="1"/>
+ <pt x="899" y="62" on="1"/>
+ <pt x="916" y="62" on="1"/>
+ <pt x="977" y="63" on="1"/>
+ <pt x="1064" y="64" on="0"/>
+ <pt x="1064" y="99" on="1"/>
+ <pt x="1064" y="122" on="0"/>
+ <pt x="1023" y="181" on="1"/>
+ <pt x="968" y="260" on="1"/>
+ <pt x="691" y="676" on="1"/>
+ <pt x="376" y="261" on="1"/>
+ <pt x="358" y="237" on="1"/>
+ <pt x="342" y="216" on="1"/>
+ <pt x="331" y="202" on="1"/>
+ <pt x="321" y="189" on="1"/>
+ <pt x="265" y="115" on="0"/>
+ <pt x="265" y="95" on="1"/>
+ <pt x="265" y="64" on="0"/>
+ <pt x="345" y="63" on="1"/>
+ <pt x="405" y="62" on="1"/>
+ <pt x="426" y="62" on="1"/>
+ <pt x="426" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 70 69 59 58 52 51 48 43 42 36 33 32 26 17 16 13 8 7 1 19 14 0 3 71 50
+ 49 0 3 0 35 34 15 14 0 3 14 71 70 69 66 59 58 55 52 51 50 49 48 43 42
+ 36 35 34 33 32 29 26 20 17 16 15 14 13 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Y" xMin="0" yMin="0" xMax="1478" yMax="1480">
+ <contour>
+ <pt x="627" y="656" on="1"/>
+ <pt x="252" y="1215" on="1"/>
+ <pt x="193" y="1303" on="1"/>
+ <pt x="124" y="1408" on="0"/>
+ <pt x="77" y="1415" on="1"/>
+ <pt x="19" y="1417" on="1"/>
+ <pt x="0" y="1419" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="573" y="1480" on="1"/>
+ <pt x="573" y="1419" on="1"/>
+ <pt x="554" y="1419" on="1"/>
+ <pt x="483" y="1417" on="1"/>
+ <pt x="409" y="1415" on="0"/>
+ <pt x="409" y="1380" on="1"/>
+ <pt x="409" y="1351" on="0"/>
+ <pt x="457" y="1281" on="1"/>
+ <pt x="502" y="1215" on="1"/>
+ <pt x="816" y="748" on="1"/>
+ <pt x="1131" y="1214" on="1"/>
+ <pt x="1226" y="1354" on="0"/>
+ <pt x="1226" y="1389" on="1"/>
+ <pt x="1226" y="1414" on="0"/>
+ <pt x="1143" y="1417" on="1"/>
+ <pt x="1087" y="1419" on="1"/>
+ <pt x="1069" y="1419" on="1"/>
+ <pt x="1069" y="1480" on="1"/>
+ <pt x="1478" y="1480" on="1"/>
+ <pt x="1478" y="1419" on="1"/>
+ <pt x="1459" y="1417" on="1"/>
+ <pt x="1458" y="1417" on="0"/>
+ <pt x="1453" y="1418" on="1"/>
+ <pt x="1450" y="1415" on="0"/>
+ <pt x="1447" y="1415" on="1"/>
+ <pt x="1426" y="1416" on="1"/>
+ <pt x="1353" y="1419" on="0"/>
+ <pt x="1297" y="1333" on="1"/>
+ <pt x="1295" y="1329" on="0"/>
+ <pt x="1288" y="1319" on="1"/>
+ <pt x="1282" y="1310" on="0"/>
+ <pt x="1275" y="1301" on="1"/>
+ <pt x="1246" y="1258" on="0"/>
+ <pt x="1217" y="1215" on="1"/>
+ <pt x="837" y="656" on="1"/>
+ <pt x="837" y="259" on="1"/>
+ <pt x="836" y="140" on="0"/>
+ <pt x="854" y="104" on="1"/>
+ <pt x="869" y="72" on="0"/>
+ <pt x="935" y="68" on="1"/>
+ <pt x="1003" y="63" on="1"/>
+ <pt x="1022" y="62" on="1"/>
+ <pt x="1022" y="0" on="1"/>
+ <pt x="442" y="0" on="1"/>
+ <pt x="442" y="62" on="1"/>
+ <pt x="460" y="63" on="1"/>
+ <pt x="528" y="68" on="1"/>
+ <pt x="603" y="74" on="0"/>
+ <pt x="613" y="115" on="1"/>
+ <pt x="627" y="175" on="0"/>
+ <pt x="627" y="259" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 58 51 43 50 33 32 30 42 33 32 30 27 24 23 17 10 9 6 4 0 13 7 50 3 51
+ 50 1 0 26 25 8 7 0 3 14 51 58 50 43 17 42 0 2 27 26 25 24 23 5 13
+ 20 42 10 9 8 7 6 4 6 13 13 0 0 0 43 42 32 1 0 1 4 48 196 58 0
+ 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Yacute" xMin="0" yMin="0" xMax="1478" yMax="1925">
+ <contour>
+ <pt x="627" y="656" on="1"/>
+ <pt x="252" y="1215" on="1"/>
+ <pt x="193" y="1303" on="1"/>
+ <pt x="124" y="1408" on="0"/>
+ <pt x="77" y="1415" on="1"/>
+ <pt x="19" y="1417" on="1"/>
+ <pt x="0" y="1419" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="573" y="1480" on="1"/>
+ <pt x="573" y="1419" on="1"/>
+ <pt x="554" y="1419" on="1"/>
+ <pt x="483" y="1417" on="1"/>
+ <pt x="409" y="1415" on="0"/>
+ <pt x="409" y="1380" on="1"/>
+ <pt x="409" y="1351" on="0"/>
+ <pt x="457" y="1281" on="1"/>
+ <pt x="502" y="1215" on="1"/>
+ <pt x="816" y="748" on="1"/>
+ <pt x="1131" y="1214" on="1"/>
+ <pt x="1226" y="1354" on="0"/>
+ <pt x="1226" y="1389" on="1"/>
+ <pt x="1226" y="1414" on="0"/>
+ <pt x="1143" y="1417" on="1"/>
+ <pt x="1087" y="1419" on="1"/>
+ <pt x="1069" y="1419" on="1"/>
+ <pt x="1069" y="1480" on="1"/>
+ <pt x="1478" y="1480" on="1"/>
+ <pt x="1478" y="1419" on="1"/>
+ <pt x="1459" y="1417" on="1"/>
+ <pt x="1458" y="1417" on="0"/>
+ <pt x="1453" y="1418" on="1"/>
+ <pt x="1450" y="1415" on="0"/>
+ <pt x="1447" y="1415" on="1"/>
+ <pt x="1426" y="1416" on="1"/>
+ <pt x="1353" y="1419" on="0"/>
+ <pt x="1297" y="1333" on="1"/>
+ <pt x="1295" y="1329" on="0"/>
+ <pt x="1288" y="1319" on="1"/>
+ <pt x="1282" y="1310" on="0"/>
+ <pt x="1275" y="1301" on="1"/>
+ <pt x="1246" y="1258" on="0"/>
+ <pt x="1217" y="1215" on="1"/>
+ <pt x="837" y="656" on="1"/>
+ <pt x="837" y="259" on="1"/>
+ <pt x="836" y="140" on="0"/>
+ <pt x="854" y="104" on="1"/>
+ <pt x="869" y="72" on="0"/>
+ <pt x="935" y="68" on="1"/>
+ <pt x="1003" y="63" on="1"/>
+ <pt x="1022" y="62" on="1"/>
+ <pt x="1022" y="0" on="1"/>
+ <pt x="442" y="0" on="1"/>
+ <pt x="442" y="62" on="1"/>
+ <pt x="460" y="63" on="1"/>
+ <pt x="528" y="68" on="1"/>
+ <pt x="603" y="74" on="0"/>
+ <pt x="613" y="115" on="1"/>
+ <pt x="627" y="175" on="0"/>
+ <pt x="627" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="649" y="1604" on="1"/>
+ <pt x="890" y="1925" on="1"/>
+ <pt x="1149" y="1925" on="1"/>
+ <pt x="742" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 58 51 43 50 62 59 2 60 7 3 33 32 30 42 33 32 30 27 24 23 17 10 9 6 4
+ 0 13 7 50 3 61 60 1 51 50 1 2 0 26 25 8 7 0 3 14 51 58 50 43 62
+ 59 17 3 42 0 3 61 60 27 26 25 24 23 7 13 20 42 10 9 8 7 6 4 6 13
+ 13 0 0 0 43 42 32 1 0 1 4 48 196 58 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ycircumflex" xMin="0" yMin="0" xMax="1478" yMax="1925">
+ <contour>
+ <pt x="627" y="656" on="1"/>
+ <pt x="252" y="1215" on="1"/>
+ <pt x="193" y="1303" on="1"/>
+ <pt x="124" y="1408" on="0"/>
+ <pt x="77" y="1415" on="1"/>
+ <pt x="19" y="1417" on="1"/>
+ <pt x="0" y="1419" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="573" y="1480" on="1"/>
+ <pt x="573" y="1419" on="1"/>
+ <pt x="554" y="1419" on="1"/>
+ <pt x="483" y="1417" on="1"/>
+ <pt x="409" y="1415" on="0"/>
+ <pt x="409" y="1380" on="1"/>
+ <pt x="409" y="1351" on="0"/>
+ <pt x="457" y="1281" on="1"/>
+ <pt x="502" y="1215" on="1"/>
+ <pt x="816" y="748" on="1"/>
+ <pt x="1131" y="1214" on="1"/>
+ <pt x="1226" y="1354" on="0"/>
+ <pt x="1226" y="1389" on="1"/>
+ <pt x="1226" y="1414" on="0"/>
+ <pt x="1143" y="1417" on="1"/>
+ <pt x="1087" y="1419" on="1"/>
+ <pt x="1069" y="1419" on="1"/>
+ <pt x="1069" y="1480" on="1"/>
+ <pt x="1478" y="1480" on="1"/>
+ <pt x="1478" y="1419" on="1"/>
+ <pt x="1459" y="1417" on="1"/>
+ <pt x="1458" y="1417" on="0"/>
+ <pt x="1453" y="1418" on="1"/>
+ <pt x="1450" y="1415" on="0"/>
+ <pt x="1447" y="1415" on="1"/>
+ <pt x="1426" y="1416" on="1"/>
+ <pt x="1353" y="1419" on="0"/>
+ <pt x="1297" y="1333" on="1"/>
+ <pt x="1295" y="1329" on="0"/>
+ <pt x="1288" y="1319" on="1"/>
+ <pt x="1282" y="1310" on="0"/>
+ <pt x="1275" y="1301" on="1"/>
+ <pt x="1246" y="1258" on="0"/>
+ <pt x="1217" y="1215" on="1"/>
+ <pt x="837" y="656" on="1"/>
+ <pt x="837" y="259" on="1"/>
+ <pt x="836" y="140" on="0"/>
+ <pt x="854" y="104" on="1"/>
+ <pt x="869" y="72" on="0"/>
+ <pt x="935" y="68" on="1"/>
+ <pt x="1003" y="63" on="1"/>
+ <pt x="1022" y="62" on="1"/>
+ <pt x="1022" y="0" on="1"/>
+ <pt x="442" y="0" on="1"/>
+ <pt x="442" y="62" on="1"/>
+ <pt x="460" y="63" on="1"/>
+ <pt x="528" y="68" on="1"/>
+ <pt x="603" y="74" on="0"/>
+ <pt x="613" y="115" on="1"/>
+ <pt x="627" y="175" on="0"/>
+ <pt x="627" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="469" y="1604" on="1"/>
+ <pt x="710" y="1925" on="1"/>
+ <pt x="932" y="1925" on="1"/>
+ <pt x="1172" y="1604" on="1"/>
+ <pt x="1086" y="1604" on="1"/>
+ <pt x="821" y="1826" on="1"/>
+ <pt x="555" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 98 values pushed */
+ 58 51 43 50 65 64 63 62 59 5 60 7 3 33 32 30 42 33 32 30 27 24 23 17 10
+ 9 6 4 0 13 7 50 3 61 60 1 51 50 1 2 0 26 25 8 7 0 3 14 51 58
+ 50 43 64 60 17 3 42 0 3 63 62 61 27 26 25 24 23 8 13 20 42 65 59 10 9
+ 8 7 6 4 8 13 13 0 0 0 43 42 32 1 0 1 4 48 196 58 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ydieresis" xMin="0" yMin="0" xMax="1478" yMax="1777">
+ <contour>
+ <pt x="627" y="656" on="1"/>
+ <pt x="252" y="1215" on="1"/>
+ <pt x="193" y="1303" on="1"/>
+ <pt x="124" y="1408" on="0"/>
+ <pt x="77" y="1415" on="1"/>
+ <pt x="19" y="1417" on="1"/>
+ <pt x="0" y="1419" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="573" y="1480" on="1"/>
+ <pt x="573" y="1419" on="1"/>
+ <pt x="554" y="1419" on="1"/>
+ <pt x="483" y="1417" on="1"/>
+ <pt x="409" y="1415" on="0"/>
+ <pt x="409" y="1380" on="1"/>
+ <pt x="409" y="1351" on="0"/>
+ <pt x="457" y="1281" on="1"/>
+ <pt x="502" y="1215" on="1"/>
+ <pt x="816" y="748" on="1"/>
+ <pt x="1131" y="1214" on="1"/>
+ <pt x="1226" y="1354" on="0"/>
+ <pt x="1226" y="1389" on="1"/>
+ <pt x="1226" y="1414" on="0"/>
+ <pt x="1143" y="1417" on="1"/>
+ <pt x="1087" y="1419" on="1"/>
+ <pt x="1069" y="1419" on="1"/>
+ <pt x="1069" y="1480" on="1"/>
+ <pt x="1478" y="1480" on="1"/>
+ <pt x="1478" y="1419" on="1"/>
+ <pt x="1459" y="1417" on="1"/>
+ <pt x="1458" y="1417" on="0"/>
+ <pt x="1453" y="1418" on="1"/>
+ <pt x="1450" y="1415" on="0"/>
+ <pt x="1447" y="1415" on="1"/>
+ <pt x="1426" y="1416" on="1"/>
+ <pt x="1353" y="1419" on="0"/>
+ <pt x="1297" y="1333" on="1"/>
+ <pt x="1295" y="1329" on="0"/>
+ <pt x="1288" y="1319" on="1"/>
+ <pt x="1282" y="1310" on="0"/>
+ <pt x="1275" y="1301" on="1"/>
+ <pt x="1246" y="1258" on="0"/>
+ <pt x="1217" y="1215" on="1"/>
+ <pt x="837" y="656" on="1"/>
+ <pt x="837" y="259" on="1"/>
+ <pt x="836" y="140" on="0"/>
+ <pt x="854" y="104" on="1"/>
+ <pt x="869" y="72" on="0"/>
+ <pt x="935" y="68" on="1"/>
+ <pt x="1003" y="63" on="1"/>
+ <pt x="1022" y="62" on="1"/>
+ <pt x="1022" y="0" on="1"/>
+ <pt x="442" y="0" on="1"/>
+ <pt x="442" y="62" on="1"/>
+ <pt x="460" y="63" on="1"/>
+ <pt x="528" y="68" on="1"/>
+ <pt x="603" y="74" on="0"/>
+ <pt x="613" y="115" on="1"/>
+ <pt x="627" y="175" on="0"/>
+ <pt x="627" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="537" y="1604" on="1"/>
+ <pt x="537" y="1777" on="1"/>
+ <pt x="710" y="1777" on="1"/>
+ <pt x="710" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="932" y="1604" on="1"/>
+ <pt x="932" y="1777" on="1"/>
+ <pt x="1105" y="1777" on="1"/>
+ <pt x="1105" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 121 values pushed */
+ 58 51 43 50 33 32 30 42 33 32 30 27 24 23 17 10 9 6 4 0 13 7 50 3 0
+ 0 66 63 62 59 13 3 60 1 4 48 84 65 64 61 60 3 51 50 1 2 0 26 25 8
+ 7 0 3 14 51 58 50 43 25 24 23 3 65 63 3 17 42 61 2 10 9 8 3 0 59
+ 3 27 26 2 13 20 65 7 6 4 3 13 13 59 0 0 64 63 13 1 65 62 61 13 1
+ 59 43 42 32 1 0 3 4 48 196 66 65 1 60 59 1 58 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Z" xMin="92" yMin="0" xMax="1129" yMax="1480">
+ <contour>
+ <pt x="92" y="0" on="1"/>
+ <pt x="92" y="80" on="1"/>
+ <pt x="887" y="1400" on="1"/>
+ <pt x="436" y="1400" on="1"/>
+ <pt x="327" y="1396" on="1"/>
+ <pt x="263" y="1395" on="0"/>
+ <pt x="252" y="1377" on="1"/>
+ <pt x="242" y="1360" on="0"/>
+ <pt x="242" y="1322" on="1"/>
+ <pt x="239" y="1209" on="1"/>
+ <pt x="237" y="1184" on="1"/>
+ <pt x="126" y="1184" on="1"/>
+ <pt x="126" y="1480" on="1"/>
+ <pt x="1122" y="1480" on="1"/>
+ <pt x="1122" y="1413" on="1"/>
+ <pt x="331" y="93" on="1"/>
+ <pt x="779" y="93" on="1"/>
+ <pt x="945" y="99" on="1"/>
+ <pt x="1008" y="100" on="0"/>
+ <pt x="1012" y="165" on="1"/>
+ <pt x="1016" y="265" on="1"/>
+ <pt x="1017" y="284" on="1"/>
+ <pt x="1129" y="284" on="1"/>
+ <pt x="1129" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 14 12 2 2 22 21 11 10 4 2 15 3 1 15 0 2 0 0 3 2 21 1 12 16 15
+ 35 1 0 2 4 48 84 23 0 1 0 13 12 0 14 21 16 15 14 13 10 3 2 8 22
+ 11 3 1 0 11 23 22 1 12 11 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zacute" xMin="92" yMin="0" xMax="1129" yMax="1925">
+ <contour>
+ <pt x="92" y="0" on="1"/>
+ <pt x="92" y="80" on="1"/>
+ <pt x="887" y="1400" on="1"/>
+ <pt x="436" y="1400" on="1"/>
+ <pt x="327" y="1396" on="1"/>
+ <pt x="263" y="1395" on="0"/>
+ <pt x="252" y="1377" on="1"/>
+ <pt x="242" y="1360" on="0"/>
+ <pt x="242" y="1322" on="1"/>
+ <pt x="239" y="1209" on="1"/>
+ <pt x="237" y="1184" on="1"/>
+ <pt x="126" y="1184" on="1"/>
+ <pt x="126" y="1480" on="1"/>
+ <pt x="1122" y="1480" on="1"/>
+ <pt x="1122" y="1413" on="1"/>
+ <pt x="331" y="93" on="1"/>
+ <pt x="779" y="93" on="1"/>
+ <pt x="945" y="99" on="1"/>
+ <pt x="1008" y="100" on="0"/>
+ <pt x="1012" y="165" on="1"/>
+ <pt x="1016" y="265" on="1"/>
+ <pt x="1017" y="284" on="1"/>
+ <pt x="1129" y="284" on="1"/>
+ <pt x="1129" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="510" y="1604" on="1"/>
+ <pt x="751" y="1925" on="1"/>
+ <pt x="1010" y="1925" on="1"/>
+ <pt x="603" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 27 24 2 25 12 3 14 12 2 2 22 21 11 10 4 2 15 3 1 15 0 2 0 0 3
+ 2 21 1 12 16 15 35 1 0 2 4 48 84 26 25 1 23 0 1 2 0 13 12 0 14
+ 27 26 25 24 21 16 15 14 13 10 3 2 12 22 11 3 1 0 11 23 22 1 12 11 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zcaron" xMin="92" yMin="0" xMax="1129" yMax="1925">
+ <contour>
+ <pt x="92" y="0" on="1"/>
+ <pt x="92" y="80" on="1"/>
+ <pt x="887" y="1400" on="1"/>
+ <pt x="436" y="1400" on="1"/>
+ <pt x="327" y="1396" on="1"/>
+ <pt x="263" y="1395" on="0"/>
+ <pt x="252" y="1377" on="1"/>
+ <pt x="242" y="1360" on="0"/>
+ <pt x="242" y="1322" on="1"/>
+ <pt x="239" y="1209" on="1"/>
+ <pt x="237" y="1184" on="1"/>
+ <pt x="126" y="1184" on="1"/>
+ <pt x="126" y="1480" on="1"/>
+ <pt x="1122" y="1480" on="1"/>
+ <pt x="1122" y="1413" on="1"/>
+ <pt x="331" y="93" on="1"/>
+ <pt x="779" y="93" on="1"/>
+ <pt x="945" y="99" on="1"/>
+ <pt x="1008" y="100" on="0"/>
+ <pt x="1012" y="165" on="1"/>
+ <pt x="1016" y="265" on="1"/>
+ <pt x="1017" y="284" on="1"/>
+ <pt x="1129" y="284" on="1"/>
+ <pt x="1129" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="979" y="1925" on="1"/>
+ <pt x="739" y="1604" on="1"/>
+ <pt x="517" y="1604" on="1"/>
+ <pt x="276" y="1925" on="1"/>
+ <pt x="362" y="1925" on="1"/>
+ <pt x="628" y="1703" on="1"/>
+ <pt x="893" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 14 12 2 2 22 21 11 10 4 2 15 3 1 15 0 2 30 29 28 27 24 5 13 25 0
+ 0 3 2 21 1 12 16 15 35 1 0 2 4 48 84 26 25 1 23 0 1 2 0 13 12
+ 0 14 30 29 28 27 26 25 24 21 16 15 14 13 10 3 2 15 22 11 3 1 0 11 23
+ 22 1 12 11 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zdotaccent" xMin="92" yMin="0" xMax="1129" yMax="1801">
+ <contour>
+ <pt x="92" y="0" on="1"/>
+ <pt x="92" y="80" on="1"/>
+ <pt x="887" y="1400" on="1"/>
+ <pt x="436" y="1400" on="1"/>
+ <pt x="327" y="1396" on="1"/>
+ <pt x="263" y="1395" on="0"/>
+ <pt x="252" y="1377" on="1"/>
+ <pt x="242" y="1360" on="0"/>
+ <pt x="242" y="1322" on="1"/>
+ <pt x="239" y="1209" on="1"/>
+ <pt x="237" y="1184" on="1"/>
+ <pt x="126" y="1184" on="1"/>
+ <pt x="126" y="1480" on="1"/>
+ <pt x="1122" y="1480" on="1"/>
+ <pt x="1122" y="1413" on="1"/>
+ <pt x="331" y="93" on="1"/>
+ <pt x="779" y="93" on="1"/>
+ <pt x="945" y="99" on="1"/>
+ <pt x="1008" y="100" on="0"/>
+ <pt x="1012" y="165" on="1"/>
+ <pt x="1016" y="265" on="1"/>
+ <pt x="1017" y="284" on="1"/>
+ <pt x="1129" y="284" on="1"/>
+ <pt x="1129" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="512" y="1604" on="1"/>
+ <pt x="512" y="1801" on="1"/>
+ <pt x="709" y="1801" on="1"/>
+ <pt x="709" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 14 12 2 2 22 21 11 10 4 2 15 3 1 15 0 2 0 0 27 24 5 1 25 3 2
+ 21 1 12 16 15 35 1 0 3 4 48 84 26 25 1 23 0 1 2 0 13 12 0 14 21
+ 16 14 13 2 5 22 26 3 15 10 3 3 24 11 3 1 0 11 0 0 27 26 4 1 24
+ 1 4 48 196 25 24 1 23 22 1 12 11 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="a" xMin="75" yMin="-25" xMax="904" yMax="1110">
+ <contour>
+ <pt x="629" y="149" on="1"/>
+ <pt x="513" y="-25" on="0"/>
+ <pt x="344" y="-25" on="1"/>
+ <pt x="221" y="-25" on="0"/>
+ <pt x="148" y="55" on="1"/>
+ <pt x="75" y="136" on="0"/>
+ <pt x="75" y="273" on="1"/>
+ <pt x="75" y="642" on="0"/>
+ <pt x="543" y="642" on="1"/>
+ <pt x="584" y="642" on="1"/>
+ <pt x="584" y="777" on="1"/>
+ <pt x="584" y="940" on="0"/>
+ <pt x="558" y="986" on="1"/>
+ <pt x="532" y="1034" on="0"/>
+ <pt x="445" y="1034" on="1"/>
+ <pt x="361" y="1034" on="0"/>
+ <pt x="327" y="996" on="1"/>
+ <pt x="293" y="958" on="0"/>
+ <pt x="293" y="863" on="1"/>
+ <pt x="293" y="845" on="1"/>
+ <pt x="157" y="845" on="1"/>
+ <pt x="157" y="1019" on="1"/>
+ <pt x="305" y="1110" on="0"/>
+ <pt x="473" y="1110" on="1"/>
+ <pt x="639" y="1110" on="0"/>
+ <pt x="710" y="1036" on="1"/>
+ <pt x="781" y="962" on="0"/>
+ <pt x="781" y="785" on="1"/>
+ <pt x="781" y="301" on="1"/>
+ <pt x="781" y="156" on="0"/>
+ <pt x="794" y="110" on="1"/>
+ <pt x="807" y="65" on="0"/>
+ <pt x="847" y="65" on="1"/>
+ <pt x="863" y="65" on="0"/>
+ <pt x="898" y="74" on="1"/>
+ <pt x="904" y="0" on="1"/>
+ <pt x="828" y="-25" on="0"/>
+ <pt x="792" y="-25" on="1"/>
+ <pt x="668" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="584" y="171" on="1"/>
+ <pt x="584" y="580" on="1"/>
+ <pt x="538" y="580" on="1"/>
+ <pt x="288" y="580" on="0"/>
+ <pt x="288" y="312" on="1"/>
+ <pt x="288" y="93" on="0"/>
+ <pt x="431" y="93" on="1"/>
+ <pt x="503" y="93" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 45 22 2 14 21 23 48 84 37 2 23 1 2 2 28 35 1 1 41 40 39 27 21
+ 20 19 18 10 9 8 0 12 1 2 3 0 0 1 35 2 0 14 0 0 43 10 6 48 196
+ 35 28 0 27 9 2 41 19 18 8 4 9 20 3 6 20 0 0 40 39 10 9 4 3 27
+ 1 4 48 196 28 27 1 21 20 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="aacute" xMin="75" yMin="-25" xMax="904" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="192" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="abreve" xMin="75" yMin="-25" xMax="904" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="breve" x="133" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="acircumflex" xMin="75" yMin="-25" xMax="904" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="133" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="acute" xMin="91" yMin="1283" xMax="591" yMax="1604">
+ <contour>
+ <pt x="91" y="1283" on="1"/>
+ <pt x="332" y="1604" on="1"/>
+ <pt x="591" y="1604" on="1"/>
+ <pt x="184" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 12 values pushed */
+ 3 0 1 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="adieresis" xMin="75" yMin="-25" xMax="904" yMax="1456">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="134" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ae" xMin="75" yMin="-25" xMax="1304" yMax="1111">
+ <contour>
+ <pt x="649" y="181" on="1"/>
+ <pt x="582" y="71" on="0"/>
+ <pt x="525" y="27" on="1"/>
+ <pt x="457" y="-25" on="0"/>
+ <pt x="347" y="-25" on="1"/>
+ <pt x="221" y="-25" on="0"/>
+ <pt x="148" y="55" on="1"/>
+ <pt x="75" y="136" on="0"/>
+ <pt x="75" y="273" on="1"/>
+ <pt x="75" y="642" on="0"/>
+ <pt x="542" y="642" on="1"/>
+ <pt x="583" y="642" on="1"/>
+ <pt x="583" y="777" on="1"/>
+ <pt x="583" y="939" on="0"/>
+ <pt x="558" y="986" on="1"/>
+ <pt x="533" y="1034" on="0"/>
+ <pt x="445" y="1034" on="1"/>
+ <pt x="361" y="1034" on="0"/>
+ <pt x="326" y="996" on="1"/>
+ <pt x="292" y="958" on="0"/>
+ <pt x="292" y="863" on="1"/>
+ <pt x="292" y="845" on="1"/>
+ <pt x="156" y="845" on="1"/>
+ <pt x="156" y="1019" on="1"/>
+ <pt x="304" y="1110" on="0"/>
+ <pt x="469" y="1110" on="1"/>
+ <pt x="643" y="1110" on="0"/>
+ <pt x="732" y="1009" on="1"/>
+ <pt x="848" y="1111" on="0"/>
+ <pt x="975" y="1111" on="1"/>
+ <pt x="1304" y="1111" on="0"/>
+ <pt x="1304" y="605" on="1"/>
+ <pt x="1304" y="586" on="1"/>
+ <pt x="781" y="586" on="1"/>
+ <pt x="785" y="348" on="0"/>
+ <pt x="838" y="233" on="1"/>
+ <pt x="910" y="75" on="0"/>
+ <pt x="1067" y="75" on="1"/>
+ <pt x="1159" y="75" on="0"/>
+ <pt x="1304" y="150" on="1"/>
+ <pt x="1304" y="49" on="1"/>
+ <pt x="1158" y="-25" on="0"/>
+ <pt x="1029" y="-25" on="1"/>
+ <pt x="890" y="-25" on="0"/>
+ <pt x="780" y="51" on="1"/>
+ <pt x="715" y="96" on="0"/>
+ </contour>
+ <contour>
+ <pt x="583" y="171" on="1"/>
+ <pt x="583" y="580" on="1"/>
+ <pt x="538" y="580" on="1"/>
+ <pt x="288" y="580" on="0"/>
+ <pt x="288" y="312" on="1"/>
+ <pt x="288" y="93" on="0"/>
+ <pt x="431" y="93" on="1"/>
+ <pt x="502" y="93" on="0"/>
+ </contour>
+ <contour>
+ <pt x="781" y="648" on="1"/>
+ <pt x="1095" y="648" on="1"/>
+ <pt x="1095" y="692" on="1"/>
+ <pt x="1095" y="890" on="0"/>
+ <pt x="1067" y="966" on="1"/>
+ <pt x="1038" y="1043" on="0"/>
+ <pt x="963" y="1043" on="1"/>
+ <pt x="864" y="1043" on="0"/>
+ <pt x="818" y="925" on="1"/>
+ <pt x="784" y="837" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 112 values pushed */
+ 0 0 60 17 29 52 22 4 37 9 42 16 21 25 48 84 42 2 29 1 25 1 4 2 1
+ 56 27 23 22 21 20 12 7 1 54 3 0 31 11 10 3 54 32 3 1 48 47 46 40 39
+ 0 6 32 2 3 0 0 0 33 32 14 1 54 1 4 48 84 55 54 1 0 14 0 0 50
+ 10 8 48 196 48 21 20 10 4 11 22 3 56 55 54 40 39 33 32 31 27 0 10 13 11
+ 8 22 47 46 12 11 3 23 22 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="afii00208" xMin="99" yMin="543" xMax="1950" yMax="642">
+ <contour>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="642" on="1"/>
+ <pt x="1950" y="642" on="1"/>
+ <pt x="1950" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 9 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="agrave" xMin="75" yMin="-25" xMax="904" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="75" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="amacron" xMin="75" yMin="-25" xMax="904" yMax="1406">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="120" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ampersand" xMin="99" yMin="-37" xMax="1541" yMax="1518">
+ <contour>
+ <pt x="1152" y="0" on="1"/>
+ <pt x="1058" y="103" on="1"/>
+ <pt x="833" y="-37" on="0"/>
+ <pt x="618" y="-37" on="1"/>
+ <pt x="394" y="-37" on="0"/>
+ <pt x="246" y="97" on="1"/>
+ <pt x="99" y="231" on="0"/>
+ <pt x="99" y="437" on="1"/>
+ <pt x="99" y="632" on="0"/>
+ <pt x="238" y="756" on="1"/>
+ <pt x="322" y="830" on="0"/>
+ <pt x="482" y="888" on="1"/>
+ <pt x="358" y="1058" on="0"/>
+ <pt x="358" y="1193" on="1"/>
+ <pt x="358" y="1339" on="0"/>
+ <pt x="460" y="1428" on="1"/>
+ <pt x="562" y="1518" on="0"/>
+ <pt x="736" y="1518" on="1"/>
+ <pt x="908" y="1518" on="0"/>
+ <pt x="1006" y="1439" on="1"/>
+ <pt x="1105" y="1361" on="0"/>
+ <pt x="1105" y="1224" on="1"/>
+ <pt x="1105" y="1066" on="0"/>
+ <pt x="971" y="963" on="1"/>
+ <pt x="890" y="901" on="0"/>
+ <pt x="736" y="851" on="1"/>
+ <pt x="791" y="777" on="1"/>
+ <pt x="932" y="584" on="1"/>
+ <pt x="1077" y="389" on="1"/>
+ <pt x="1152" y="286" on="1"/>
+ <pt x="1242" y="417" on="0"/>
+ <pt x="1242" y="603" on="1"/>
+ <pt x="1240" y="660" on="1"/>
+ <pt x="1239" y="719" on="0"/>
+ <pt x="1175" y="719" on="1"/>
+ <pt x="1163" y="719" on="0"/>
+ <pt x="1125" y="722" on="1"/>
+ <pt x="1091" y="724" on="1"/>
+ <pt x="1072" y="725" on="1"/>
+ <pt x="1072" y="786" on="1"/>
+ <pt x="1541" y="786" on="1"/>
+ <pt x="1541" y="725" on="1"/>
+ <pt x="1520" y="724" on="1"/>
+ <pt x="1440" y="720" on="1"/>
+ <pt x="1398" y="718" on="0"/>
+ <pt x="1391" y="698" on="1"/>
+ <pt x="1384" y="680" on="0"/>
+ <pt x="1384" y="641" on="1"/>
+ <pt x="1384" y="472" on="0"/>
+ <pt x="1198" y="236" on="1"/>
+ <pt x="1203" y="231" on="1"/>
+ <pt x="1209" y="224" on="1"/>
+ <pt x="1219" y="214" on="0"/>
+ <pt x="1225" y="207" on="1"/>
+ <pt x="1228" y="204" on="1"/>
+ <pt x="1240" y="192" on="1"/>
+ <pt x="1252" y="178" on="0"/>
+ <pt x="1269" y="161" on="1"/>
+ <pt x="1301" y="127" on="0"/>
+ <pt x="1321" y="110" on="1"/>
+ <pt x="1368" y="72" on="0"/>
+ <pt x="1424" y="69" on="1"/>
+ <pt x="1515" y="63" on="1"/>
+ <pt x="1528" y="62" on="1"/>
+ <pt x="1528" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1013" y="155" on="1"/>
+ <pt x="775" y="432" on="0"/>
+ <pt x="513" y="835" on="1"/>
+ <pt x="417" y="787" on="0"/>
+ <pt x="368" y="724" on="1"/>
+ <pt x="297" y="633" on="0"/>
+ <pt x="297" y="494" on="1"/>
+ <pt x="297" y="306" on="0"/>
+ <pt x="414" y="191" on="1"/>
+ <pt x="531" y="75" on="0"/>
+ <pt x="723" y="75" on="1"/>
+ <pt x="879" y="75" on="0"/>
+ </contour>
+ <contour>
+ <pt x="702" y="896" on="1"/>
+ <pt x="800" y="961" on="0"/>
+ <pt x="848" y="1028" on="1"/>
+ <pt x="920" y="1125" on="0"/>
+ <pt x="920" y="1250" on="1"/>
+ <pt x="920" y="1450" on="0"/>
+ <pt x="742" y="1450" on="1"/>
+ <pt x="656" y="1450" on="0"/>
+ <pt x="606" y="1396" on="1"/>
+ <pt x="555" y="1343" on="0"/>
+ <pt x="555" y="1254" on="1"/>
+ <pt x="555" y="1116" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 83 17 17 75 15 3 48 84 17 0 3 2 1 77 67 25 11 4 0 39 3 0 65
+ 63 49 41 38 31 29 1 8 39 0 3 40 39 1 64 0 1 2 0 14 0 0 87 5 13
+ 81 16 21 71 5 7 48 196 77 67 65 64 63 49 41 40 39 38 31 29 25 21 13 11 7
+ 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="anoteleia" xMin="133" yMin="491" xMax="380" yMax="738">
+ <contour>
+ <pt x="133" y="491" on="1"/>
+ <pt x="133" y="738" on="1"/>
+ <pt x="380" y="738" on="1"/>
+ <pt x="380" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 84 2 1 1 0 14 0 0 3 2 6 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="aogonek" xMin="75" yMin="-370" xMax="917" yMax="1110">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="392" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="aring" xMin="75" yMin="-25" xMax="904" yMax="1737">
+ <contour>
+ <pt x="629" y="149" on="1"/>
+ <pt x="513" y="-25" on="0"/>
+ <pt x="344" y="-25" on="1"/>
+ <pt x="221" y="-25" on="0"/>
+ <pt x="148" y="55" on="1"/>
+ <pt x="75" y="136" on="0"/>
+ <pt x="75" y="273" on="1"/>
+ <pt x="75" y="642" on="0"/>
+ <pt x="543" y="642" on="1"/>
+ <pt x="584" y="642" on="1"/>
+ <pt x="584" y="777" on="1"/>
+ <pt x="584" y="940" on="0"/>
+ <pt x="558" y="986" on="1"/>
+ <pt x="532" y="1034" on="0"/>
+ <pt x="445" y="1034" on="1"/>
+ <pt x="361" y="1034" on="0"/>
+ <pt x="327" y="996" on="1"/>
+ <pt x="293" y="958" on="0"/>
+ <pt x="293" y="863" on="1"/>
+ <pt x="293" y="845" on="1"/>
+ <pt x="157" y="845" on="1"/>
+ <pt x="157" y="1019" on="1"/>
+ <pt x="305" y="1110" on="0"/>
+ <pt x="473" y="1110" on="1"/>
+ <pt x="639" y="1110" on="0"/>
+ <pt x="710" y="1036" on="1"/>
+ <pt x="781" y="962" on="0"/>
+ <pt x="781" y="785" on="1"/>
+ <pt x="781" y="301" on="1"/>
+ <pt x="781" y="156" on="0"/>
+ <pt x="794" y="110" on="1"/>
+ <pt x="807" y="65" on="0"/>
+ <pt x="847" y="65" on="1"/>
+ <pt x="863" y="65" on="0"/>
+ <pt x="898" y="74" on="1"/>
+ <pt x="904" y="0" on="1"/>
+ <pt x="828" y="-25" on="0"/>
+ <pt x="792" y="-25" on="1"/>
+ <pt x="668" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="584" y="171" on="1"/>
+ <pt x="584" y="580" on="1"/>
+ <pt x="538" y="580" on="1"/>
+ <pt x="288" y="580" on="0"/>
+ <pt x="288" y="312" on="1"/>
+ <pt x="288" y="93" on="0"/>
+ <pt x="431" y="93" on="1"/>
+ <pt x="503" y="93" on="0"/>
+ </contour>
+ <contour>
+ <pt x="475" y="1737" on="1"/>
+ <pt x="569" y="1737" on="0"/>
+ <pt x="635" y="1671" on="1"/>
+ <pt x="702" y="1605" on="0"/>
+ <pt x="702" y="1511" on="1"/>
+ <pt x="702" y="1415" on="0"/>
+ <pt x="635" y="1349" on="1"/>
+ <pt x="569" y="1283" on="0"/>
+ <pt x="473" y="1283" on="1"/>
+ <pt x="390" y="1283" on="0"/>
+ <pt x="328" y="1337" on="1"/>
+ <pt x="248" y="1406" on="0"/>
+ <pt x="248" y="1510" on="1"/>
+ <pt x="248" y="1605" on="0"/>
+ <pt x="314" y="1671" on="1"/>
+ <pt x="381" y="1737" on="0"/>
+ </contour>
+ <contour>
+ <pt x="475" y="1669" on="1"/>
+ <pt x="409" y="1669" on="0"/>
+ <pt x="363" y="1623" on="1"/>
+ <pt x="316" y="1576" on="0"/>
+ <pt x="316" y="1511" on="1"/>
+ <pt x="316" y="1445" on="0"/>
+ <pt x="362" y="1398" on="1"/>
+ <pt x="409" y="1351" on="0"/>
+ <pt x="473" y="1351" on="1"/>
+ <pt x="534" y="1351" on="0"/>
+ <pt x="578" y="1388" on="1"/>
+ <pt x="634" y="1436" on="0"/>
+ <pt x="634" y="1511" on="1"/>
+ <pt x="634" y="1577" on="0"/>
+ <pt x="588" y="1623" on="1"/>
+ <pt x="541" y="1669" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 71 17 55 63 17 47 45 22 2 14 21 23 48 84 37 2 23 1 2 2 28 35 1
+ 1 41 40 39 27 21 20 19 18 10 9 8 0 12 1 2 3 0 0 1 55 47 1 0 1
+ 35 2 0 14 0 0 75 17 51 67 17 59 43 10 6 48 196 35 28 51 51 0 2 27 9
+ 3 59 59 41 19 18 8 5 9 20 3 6 20 0 0 40 39 10 9 4 3 27 1 4 48
+ 196 28 27 1 21 20 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="asciicircum" xMin="36" yMin="592" xMax="924" yMax="1480">
+ <contour>
+ <pt x="36" y="592" on="1"/>
+ <pt x="480" y="1480" on="1"/>
+ <pt x="924" y="592" on="1"/>
+ <pt x="797" y="592" on="1"/>
+ <pt x="480" y="1224" on="1"/>
+ <pt x="162" y="592" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 5 4 3 2 1 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="asciitilde" xMin="60" yMin="421" xMax="1047" yMax="763">
+ <contour>
+ <pt x="122" y="444" on="1"/>
+ <pt x="60" y="444" on="1"/>
+ <pt x="70" y="583" on="0"/>
+ <pt x="115" y="656" on="1"/>
+ <pt x="181" y="763" on="0"/>
+ <pt x="324" y="763" on="1"/>
+ <pt x="447" y="763" on="0"/>
+ <pt x="582" y="648" on="1"/>
+ <pt x="622" y="614" on="1"/>
+ <pt x="728" y="524" on="0"/>
+ <pt x="813" y="524" on="1"/>
+ <pt x="899" y="524" on="0"/>
+ <pt x="950" y="605" on="1"/>
+ <pt x="984" y="659" on="0"/>
+ <pt x="985" y="740" on="1"/>
+ <pt x="1047" y="740" on="1"/>
+ <pt x="1037" y="600" on="0"/>
+ <pt x="992" y="528" on="1"/>
+ <pt x="926" y="421" on="0"/>
+ <pt x="783" y="421" on="1"/>
+ <pt x="660" y="421" on="0"/>
+ <pt x="525" y="536" on="1"/>
+ <pt x="485" y="570" on="1"/>
+ <pt x="378" y="661" on="0"/>
+ <pt x="294" y="661" on="1"/>
+ <pt x="208" y="661" on="0"/>
+ <pt x="157" y="580" on="1"/>
+ <pt x="123" y="526" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 21 values pushed */
+ 0 0 24 41 5 10 41 19 48 84 19 15 14 5 1 0 14 15 14 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="asterisk" xMin="120" yMin="734" xMax="905" yMax="1480">
+ <contour>
+ <pt x="577" y="1152" on="1"/>
+ <pt x="859" y="1282" on="1"/>
+ <pt x="905" y="1142" on="1"/>
+ <pt x="600" y="1081" on="1"/>
+ <pt x="601" y="1085" on="0"/>
+ <pt x="601" y="1090" on="1"/>
+ <pt x="601" y="1094" on="1"/>
+ <pt x="601" y="1097" on="1"/>
+ <pt x="601" y="1126" on="0"/>
+ </contour>
+ <contour>
+ <pt x="589" y="1049" on="1"/>
+ <pt x="801" y="821" on="1"/>
+ <pt x="681" y="734" on="1"/>
+ <pt x="530" y="1005" on="1"/>
+ <pt x="570" y="1015" on="0"/>
+ </contour>
+ <contour>
+ <pt x="495" y="1005" on="1"/>
+ <pt x="344" y="734" on="1"/>
+ <pt x="224" y="821" on="1"/>
+ <pt x="435" y="1049" on="1"/>
+ <pt x="457" y="1013" on="0"/>
+ </contour>
+ <contour>
+ <pt x="425" y="1081" on="1"/>
+ <pt x="120" y="1142" on="1"/>
+ <pt x="166" y="1282" on="1"/>
+ <pt x="448" y="1152" on="1"/>
+ <pt x="424" y="1125" on="0"/>
+ <pt x="424" y="1097" on="1"/>
+ <pt x="424" y="1094" on="1"/>
+ <pt x="424" y="1090" on="1"/>
+ <pt x="425" y="1085" on="0"/>
+ </contour>
+ <contour>
+ <pt x="476" y="1172" on="1"/>
+ <pt x="438" y="1480" on="1"/>
+ <pt x="586" y="1480" on="1"/>
+ <pt x="549" y="1172" on="1"/>
+ <pt x="526" y="1181" on="0"/>
+ <pt x="512" y="1181" on="1"/>
+ <pt x="498" y="1181" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 33 1 33 31 28 26 25 24 22 21 20 7 6 5 2 1 0 15 29 1 3 0 1 1 19
+ 17 16 15 14 12 11 10 9 3 10 1 2 3 0 0 30 29 0 14 31 30 29 28 26 25
+ 24 22 21 20 19 17 16 15 14 12 11 10 9 7 6 5 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="at" xMin="140" yMin="-37" xMax="1747" yMax="1517">
+ <contour>
+ <pt x="1151" y="44" on="1"/>
+ <pt x="969" y="-37" on="0"/>
+ <pt x="802" y="-37" on="1"/>
+ <pt x="517" y="-37" on="0"/>
+ <pt x="329" y="137" on="1"/>
+ <pt x="140" y="310" on="0"/>
+ <pt x="140" y="580" on="1"/>
+ <pt x="140" y="913" on="0"/>
+ <pt x="386" y="1195" on="1"/>
+ <pt x="668" y="1517" on="0"/>
+ <pt x="1080" y="1517" on="1"/>
+ <pt x="1367" y="1517" on="0"/>
+ <pt x="1557" y="1337" on="1"/>
+ <pt x="1747" y="1158" on="0"/>
+ <pt x="1747" y="889" on="1"/>
+ <pt x="1747" y="651" on="0"/>
+ <pt x="1597" y="473" on="1"/>
+ <pt x="1448" y="295" on="0"/>
+ <pt x="1247" y="295" on="1"/>
+ <pt x="1073" y="295" on="0"/>
+ <pt x="1073" y="435" on="1"/>
+ <pt x="1073" y="475" on="0"/>
+ <pt x="1082" y="507" on="1"/>
+ <pt x="1106" y="593" on="1"/>
+ <pt x="1115" y="635" on="1"/>
+ <pt x="1094" y="635" on="1"/>
+ <pt x="1000" y="480" on="0"/>
+ <pt x="922" y="404" on="1"/>
+ <pt x="812" y="296" on="0"/>
+ <pt x="703" y="296" on="1"/>
+ <pt x="524" y="296" on="0"/>
+ <pt x="524" y="529" on="1"/>
+ <pt x="524" y="766" on="0"/>
+ <pt x="690" y="970" on="1"/>
+ <pt x="856" y="1173" on="0"/>
+ <pt x="1051" y="1173" on="1"/>
+ <pt x="1093" y="1173" on="0"/>
+ <pt x="1133" y="1162" on="1"/>
+ <pt x="1214" y="1140" on="1"/>
+ <pt x="1216" y="1139" on="0"/>
+ <pt x="1220" y="1138" on="1"/>
+ <pt x="1224" y="1137" on="1"/>
+ <pt x="1229" y="1136" on="1"/>
+ <pt x="1237" y="1134" on="0"/>
+ <pt x="1241" y="1133" on="1"/>
+ <pt x="1336" y="1133" on="1"/>
+ <pt x="1220" y="560" on="1"/>
+ <pt x="1209" y="506" on="0"/>
+ <pt x="1209" y="463" on="1"/>
+ <pt x="1209" y="370" on="0"/>
+ <pt x="1311" y="370" on="1"/>
+ <pt x="1450" y="370" on="0"/>
+ <pt x="1567" y="537" on="1"/>
+ <pt x="1685" y="705" on="0"/>
+ <pt x="1685" y="901" on="1"/>
+ <pt x="1685" y="1136" on="0"/>
+ <pt x="1509" y="1296" on="1"/>
+ <pt x="1332" y="1456" on="0"/>
+ <pt x="1075" y="1456" on="1"/>
+ <pt x="740" y="1456" on="0"/>
+ <pt x="471" y="1189" on="1"/>
+ <pt x="202" y="922" on="0"/>
+ <pt x="202" y="592" on="1"/>
+ <pt x="202" y="343" on="0"/>
+ <pt x="372" y="184" on="1"/>
+ <pt x="542" y="25" on="0"/>
+ <pt x="801" y="25" on="1"/>
+ <pt x="956" y="25" on="0"/>
+ <pt x="1129" y="100" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1124" y="819" on="1"/>
+ <pt x="1166" y="1030" on="1"/>
+ <pt x="1081" y="1073" on="0"/>
+ <pt x="989" y="1073" on="1"/>
+ <pt x="850" y="1073" on="0"/>
+ <pt x="760" y="931" on="1"/>
+ <pt x="669" y="789" on="0"/>
+ <pt x="669" y="581" on="1"/>
+ <pt x="669" y="419" on="0"/>
+ <pt x="760" y="419" on="1"/>
+ <pt x="836" y="419" on="0"/>
+ <pt x="926" y="519" on="1"/>
+ <pt x="1011" y="615" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 0 0 78 22 29 72 9 35 66 11 2 58 11 10 50 21 18 48 84 10 0 2 2 35 29
+ 18 1 1 70 69 68 45 44 35 29 25 24 23 18 0 12 0 2 3 0 0 14 0 0 76
+ 47 31 62 11 6 54 11 14 48 48 20 48 196 70 69 68 45 44 31 25 24 23 20 14 6
+ 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="atilde" xMin="75" yMin="-25" xMax="904" yMax="1518">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="119" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="b" xMin="0" yMin="-25" xMax="956" yMax="1579">
+ <contour>
+ <pt x="121" y="-12" on="1"/>
+ <pt x="121" y="1320" on="1"/>
+ <pt x="119" y="1419" on="1"/>
+ <pt x="119" y="1487" on="0"/>
+ <pt x="94" y="1501" on="1"/>
+ <pt x="72" y="1513" on="0"/>
+ <pt x="19" y="1516" on="1"/>
+ <pt x="0" y="1517" on="1"/>
+ <pt x="0" y="1579" on="1"/>
+ <pt x="318" y="1579" on="1"/>
+ <pt x="318" y="907" on="1"/>
+ <pt x="377" y="999" on="0"/>
+ <pt x="432" y="1044" on="1"/>
+ <pt x="512" y="1110" on="0"/>
+ <pt x="610" y="1110" on="1"/>
+ <pt x="770" y="1110" on="0"/>
+ <pt x="863" y="968" on="1"/>
+ <pt x="956" y="826" on="0"/>
+ <pt x="956" y="575" on="1"/>
+ <pt x="956" y="293" on="0"/>
+ <pt x="835" y="134" on="1"/>
+ <pt x="714" y="-25" on="0"/>
+ <pt x="503" y="-25" on="1"/>
+ <pt x="429" y="-25" on="0"/>
+ <pt x="318" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="318" y="77" on="1"/>
+ <pt x="399" y="54" on="0"/>
+ <pt x="449" y="54" on="1"/>
+ <pt x="585" y="54" on="0"/>
+ <pt x="664" y="181" on="1"/>
+ <pt x="743" y="308" on="0"/>
+ <pt x="743" y="536" on="1"/>
+ <pt x="743" y="983" on="0"/>
+ <pt x="542" y="983" on="1"/>
+ <pt x="449" y="983" on="0"/>
+ <pt x="318" y="837" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 0 0 33 29 14 27 21 22 48 84 22 2 14 1 1 7 1 2 8 1 3 0 1 1 35
+ 25 10 3 1 2 3 0 0 1 24 0 2 0 9 8 1 0 14 0 0 31 10 18 48 196
+ 18 9 8 7 0 0 0 35 25 24 10 9 4 4 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="backslash" xMin="-30" yMin="-296" xMax="600" yMax="1481">
+ <contour>
+ <pt x="600" y="-296" on="1"/>
+ <pt x="496" y="-296" on="1"/>
+ <pt x="-30" y="1481" on="1"/>
+ <pt x="74" y="1481" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 9 values pushed */
+ 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bar" xMin="156" yMin="-296" xMax="255" yMax="1579">
+ <contour>
+ <pt x="156" y="-296" on="1"/>
+ <pt x="156" y="1579" on="1"/>
+ <pt x="255" y="1579" on="1"/>
+ <pt x="255" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 3 2 1 0 14 0 0 3 2 9 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="braceleft" xMin="148" yMin="-296" xMax="761" yMax="1579">
+ <contour>
+ <pt x="148" y="611" on="1"/>
+ <pt x="148" y="672" on="1"/>
+ <pt x="226" y="672" on="1"/>
+ <pt x="407" y="672" on="0"/>
+ <pt x="407" y="840" on="1"/>
+ <pt x="407" y="882" on="0"/>
+ <pt x="393" y="953" on="1"/>
+ <pt x="383" y="1003" on="1"/>
+ <pt x="365" y="1100" on="1"/>
+ <pt x="346" y="1202" on="0"/>
+ <pt x="346" y="1268" on="1"/>
+ <pt x="346" y="1403" on="0"/>
+ <pt x="446" y="1491" on="1"/>
+ <pt x="546" y="1579" on="0"/>
+ <pt x="701" y="1579" on="1"/>
+ <pt x="761" y="1579" on="1"/>
+ <pt x="761" y="1517" on="1"/>
+ <pt x="701" y="1517" on="1"/>
+ <pt x="506" y="1517" on="0"/>
+ <pt x="506" y="1349" on="1"/>
+ <pt x="506" y="1313" on="0"/>
+ <pt x="513" y="1286" on="1"/>
+ <pt x="525" y="1239" on="1"/>
+ <pt x="539" y="1169" on="1"/>
+ <pt x="557" y="1079" on="0"/>
+ <pt x="557" y="990" on="1"/>
+ <pt x="557" y="835" on="0"/>
+ <pt x="476" y="740" on="1"/>
+ <pt x="428" y="685" on="0"/>
+ <pt x="337" y="642" on="1"/>
+ <pt x="435" y="595" on="0"/>
+ <pt x="485" y="532" on="1"/>
+ <pt x="557" y="439" on="0"/>
+ <pt x="557" y="291" on="1"/>
+ <pt x="557" y="202" on="0"/>
+ <pt x="539" y="114" on="1"/>
+ <pt x="525" y="45" on="1"/>
+ <pt x="513" y="-2" on="1"/>
+ <pt x="506" y="-29" on="0"/>
+ <pt x="506" y="-69" on="1"/>
+ <pt x="506" y="-234" on="0"/>
+ <pt x="701" y="-234" on="1"/>
+ <pt x="761" y="-234" on="1"/>
+ <pt x="761" y="-296" on="1"/>
+ <pt x="701" y="-296" on="1"/>
+ <pt x="546" y="-296" on="0"/>
+ <pt x="446" y="-208" on="1"/>
+ <pt x="346" y="-120" on="0"/>
+ <pt x="346" y="17" on="1"/>
+ <pt x="346" y="81" on="0"/>
+ <pt x="365" y="183" on="1"/>
+ <pt x="383" y="280" on="1"/>
+ <pt x="393" y="330" on="1"/>
+ <pt x="407" y="401" on="0"/>
+ <pt x="407" y="443" on="1"/>
+ <pt x="407" y="611" on="0"/>
+ <pt x="226" y="611" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 45 values pushed */
+ 56 44 43 42 41 29 22 17 16 15 14 2 1 0 14 0 0 39 24 48 19 24 10 48 196
+ 56 54 48 44 43 42 41 33 29 25 22 17 16 15 14 10 4 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="braceright" xMin="222" yMin="-296" xMax="835" yMax="1579">
+ <contour>
+ <pt x="835" y="672" on="1"/>
+ <pt x="835" y="611" on="1"/>
+ <pt x="758" y="611" on="1"/>
+ <pt x="576" y="611" on="0"/>
+ <pt x="576" y="444" on="1"/>
+ <pt x="576" y="399" on="0"/>
+ <pt x="590" y="330" on="1"/>
+ <pt x="600" y="280" on="1"/>
+ <pt x="618" y="183" on="1"/>
+ <pt x="638" y="74" on="0"/>
+ <pt x="638" y="16" on="1"/>
+ <pt x="638" y="-120" on="0"/>
+ <pt x="538" y="-208" on="1"/>
+ <pt x="438" y="-296" on="0"/>
+ <pt x="283" y="-296" on="1"/>
+ <pt x="222" y="-296" on="1"/>
+ <pt x="222" y="-234" on="1"/>
+ <pt x="282" y="-234" on="1"/>
+ <pt x="478" y="-234" on="0"/>
+ <pt x="478" y="-68" on="1"/>
+ <pt x="478" y="-34" on="0"/>
+ <pt x="470" y="-2" on="1"/>
+ <pt x="458" y="45" on="1"/>
+ <pt x="445" y="114" on="1"/>
+ <pt x="427" y="209" on="0"/>
+ <pt x="427" y="293" on="1"/>
+ <pt x="427" y="448" on="0"/>
+ <pt x="508" y="543" on="1"/>
+ <pt x="556" y="598" on="0"/>
+ <pt x="647" y="642" on="1"/>
+ <pt x="549" y="688" on="0"/>
+ <pt x="499" y="752" on="1"/>
+ <pt x="427" y="844" on="0"/>
+ <pt x="427" y="992" on="1"/>
+ <pt x="427" y="1073" on="0"/>
+ <pt x="445" y="1169" on="1"/>
+ <pt x="458" y="1239" on="1"/>
+ <pt x="470" y="1286" on="1"/>
+ <pt x="478" y="1318" on="0"/>
+ <pt x="478" y="1352" on="1"/>
+ <pt x="478" y="1517" on="0"/>
+ <pt x="282" y="1517" on="1"/>
+ <pt x="222" y="1517" on="1"/>
+ <pt x="222" y="1579" on="1"/>
+ <pt x="283" y="1579" on="1"/>
+ <pt x="438" y="1579" on="0"/>
+ <pt x="538" y="1491" on="1"/>
+ <pt x="638" y="1403" on="0"/>
+ <pt x="638" y="1266" on="1"/>
+ <pt x="638" y="1209" on="0"/>
+ <pt x="618" y="1100" on="1"/>
+ <pt x="600" y="1003" on="1"/>
+ <pt x="590" y="953" on="1"/>
+ <pt x="576" y="884" on="0"/>
+ <pt x="576" y="840" on="1"/>
+ <pt x="576" y="672" on="0"/>
+ <pt x="758" y="672" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 56 44 43 42 41 36 29 22 17 16 15 14 2 1 0 14 0 0 39 24 48 19 24 10 48
+ 196 56 54 48 44 43 42 41 36 33 29 25 22 17 16 15 14 10 4 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bracketleft" xMin="185" yMin="-296" xMax="589" yMax="1579">
+ <contour>
+ <pt x="185" y="-296" on="1"/>
+ <pt x="185" y="1579" on="1"/>
+ <pt x="589" y="1579" on="1"/>
+ <pt x="589" y="1517" on="1"/>
+ <pt x="358" y="1517" on="1"/>
+ <pt x="358" y="-234" on="1"/>
+ <pt x="589" y="-234" on="1"/>
+ <pt x="589" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 4 3 14 1 1 6 5 14 1 0 2 4 48 84 2 1 1 7 0 1 2 0 14
+ 7 6 3 2 4 13 4 0 0 5 4 13 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bracketright" xMin="93" yMin="-296" xMax="497" yMax="1579">
+ <contour>
+ <pt x="93" y="-296" on="1"/>
+ <pt x="93" y="-234" on="1"/>
+ <pt x="325" y="-234" on="1"/>
+ <pt x="325" y="1517" on="1"/>
+ <pt x="93" y="1517" on="1"/>
+ <pt x="93" y="1579" on="1"/>
+ <pt x="497" y="1579" on="1"/>
+ <pt x="497" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 4 3 14 1 5 2 1 14 1 0 2 4 48 84 6 5 1 7 0 1 2 0 14
+ 5 4 1 0 4 13 2 0 0 3 2 13 1 6 1 4 48 196 7 6 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="breve" xMin="8" yMin="1283" xMax="674" yMax="1604">
+ <contour>
+ <pt x="8" y="1604" on="1"/>
+ <pt x="73" y="1604" on="1"/>
+ <pt x="100" y="1514" on="0"/>
+ <pt x="160" y="1472" on="1"/>
+ <pt x="228" y="1425" on="0"/>
+ <pt x="341" y="1425" on="1"/>
+ <pt x="467" y="1425" on="0"/>
+ <pt x="537" y="1484" on="1"/>
+ <pt x="586" y="1524" on="0"/>
+ <pt x="610" y="1604" on="1"/>
+ <pt x="674" y="1604" on="1"/>
+ <pt x="655" y="1469" on="0"/>
+ <pt x="583" y="1388" on="1"/>
+ <pt x="489" y="1283" on="0"/>
+ <pt x="341" y="1283" on="1"/>
+ <pt x="187" y="1283" on="0"/>
+ <pt x="92" y="1398" on="1"/>
+ <pt x="27" y="1476" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 0 0 5 20 14 48 84 14 10 9 1 0 14 10 9 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="brokenbar" xMin="156" yMin="-296" xMax="255" yMax="1579">
+ <contour>
+ <pt x="156" y="-296" on="1"/>
+ <pt x="156" y="444" on="1"/>
+ <pt x="255" y="444" on="1"/>
+ <pt x="255" y="-296" on="1"/>
+ </contour>
+ <contour>
+ <pt x="156" y="839" on="1"/>
+ <pt x="156" y="1579" on="1"/>
+ <pt x="255" y="1579" on="1"/>
+ <pt x="255" y="839" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 28 values pushed */
+ 7 6 5 4 3 2 1 0 14 0 0 7 6 3 2 9 3 0 1 4 48 196 5 4 1
+ 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bullet" xMin="81" yMin="555" xMax="636" yMax="1110">
+ <contour>
+ <pt x="359" y="1110" on="1"/>
+ <pt x="474" y="1110" on="0"/>
+ <pt x="555" y="1028" on="1"/>
+ <pt x="636" y="946" on="0"/>
+ <pt x="636" y="831" on="1"/>
+ <pt x="636" y="717" on="0"/>
+ <pt x="554" y="636" on="1"/>
+ <pt x="472" y="555" on="0"/>
+ <pt x="354" y="555" on="1"/>
+ <pt x="255" y="555" on="0"/>
+ <pt x="179" y="621" on="1"/>
+ <pt x="81" y="707" on="0"/>
+ <pt x="81" y="833" on="1"/>
+ <pt x="81" y="948" on="0"/>
+ <pt x="163" y="1029" on="1"/>
+ <pt x="244" y="1110" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 0 0 0 8 48 84 8 14 0 0 4 12 48 196 12
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="c" xMin="68" yMin="-25" xMax="848" yMax="1110">
+ <contour>
+ <pt x="848" y="37" on="1"/>
+ <pt x="696" y="-25" on="0"/>
+ <pt x="568" y="-25" on="1"/>
+ <pt x="350" y="-25" on="0"/>
+ <pt x="209" y="137" on="1"/>
+ <pt x="68" y="298" on="0"/>
+ <pt x="68" y="550" on="1"/>
+ <pt x="68" y="800" on="0"/>
+ <pt x="202" y="955" on="1"/>
+ <pt x="336" y="1110" on="0"/>
+ <pt x="557" y="1110" on="1"/>
+ <pt x="689" y="1110" on="0"/>
+ <pt x="848" y="1061" on="1"/>
+ <pt x="848" y="802" on="1"/>
+ <pt x="724" y="802" on="1"/>
+ <pt x="724" y="820" on="1"/>
+ <pt x="724" y="1043" on="0"/>
+ <pt x="557" y="1043" on="1"/>
+ <pt x="434" y="1043" on="0"/>
+ <pt x="359" y="914" on="1"/>
+ <pt x="284" y="786" on="0"/>
+ <pt x="284" y="577" on="1"/>
+ <pt x="284" y="339" on="0"/>
+ <pt x="377" y="206" on="1"/>
+ <pt x="470" y="73" on="0"/>
+ <pt x="632" y="73" on="1"/>
+ <pt x="710" y="73" on="0"/>
+ <pt x="848" y="123" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 25 9 2 17 17 10 48 84 10 1 2 2 1 1 27 15 14 13 12 0 6 1 2
+ 3 0 0 14 0 0 21 10 6 48 196 15 14 6 0 27 13 12 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cacute" xMin="68" yMin="-25" xMax="907" yMax="1604">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="316" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="caron" xMin="-10" yMin="1283" xMax="693" yMax="1604">
+ <contour>
+ <pt x="693" y="1604" on="1"/>
+ <pt x="453" y="1283" on="1"/>
+ <pt x="231" y="1283" on="1"/>
+ <pt x="-10" y="1604" on="1"/>
+ <pt x="76" y="1604" on="1"/>
+ <pt x="342" y="1382" on="1"/>
+ <pt x="607" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 6 5 4 3 0 5 13 1 2 1 1 0 14 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ccaron" xMin="68" yMin="-25" xMax="909" yMax="1604">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="216" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ccedilla" xMin="68" yMin="-432" xMax="848" yMax="1110">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="cedilla" x="198" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ccircumflex" xMin="68" yMin="-25" xMax="909" yMax="1604">
+ <contour>
+ <pt x="848" y="37" on="1"/>
+ <pt x="696" y="-25" on="0"/>
+ <pt x="568" y="-25" on="1"/>
+ <pt x="350" y="-25" on="0"/>
+ <pt x="209" y="137" on="1"/>
+ <pt x="68" y="298" on="0"/>
+ <pt x="68" y="550" on="1"/>
+ <pt x="68" y="800" on="0"/>
+ <pt x="202" y="955" on="1"/>
+ <pt x="336" y="1110" on="0"/>
+ <pt x="557" y="1110" on="1"/>
+ <pt x="689" y="1110" on="0"/>
+ <pt x="848" y="1061" on="1"/>
+ <pt x="848" y="802" on="1"/>
+ <pt x="724" y="802" on="1"/>
+ <pt x="724" y="820" on="1"/>
+ <pt x="724" y="1043" on="0"/>
+ <pt x="557" y="1043" on="1"/>
+ <pt x="434" y="1043" on="0"/>
+ <pt x="359" y="914" on="1"/>
+ <pt x="284" y="786" on="0"/>
+ <pt x="284" y="577" on="1"/>
+ <pt x="284" y="339" on="0"/>
+ <pt x="377" y="206" on="1"/>
+ <pt x="470" y="73" on="0"/>
+ <pt x="632" y="73" on="1"/>
+ <pt x="710" y="73" on="0"/>
+ <pt x="848" y="123" on="1"/>
+ </contour>
+ <contour>
+ <pt x="206" y="1283" on="1"/>
+ <pt x="447" y="1604" on="1"/>
+ <pt x="669" y="1604" on="1"/>
+ <pt x="909" y="1283" on="1"/>
+ <pt x="823" y="1283" on="1"/>
+ <pt x="558" y="1505" on="1"/>
+ <pt x="292" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 78 values pushed */
+ 0 0 25 9 2 17 17 10 48 84 10 1 2 2 1 33 29 0 2 0 1 1 34 32 31
+ 28 4 0 1 3 0 0 1 1 27 15 14 13 12 0 6 1 2 3 0 0 30 29 1 0
+ 14 0 0 21 10 6 48 196 31 0 34 33 32 30 29 28 15 14 8 13 6 0 27 13 12
+ 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cdotaccent" xMin="68" yMin="-25" xMax="848" yMax="1480">
+ <contour>
+ <pt x="848" y="37" on="1"/>
+ <pt x="696" y="-25" on="0"/>
+ <pt x="568" y="-25" on="1"/>
+ <pt x="350" y="-25" on="0"/>
+ <pt x="209" y="137" on="1"/>
+ <pt x="68" y="298" on="0"/>
+ <pt x="68" y="550" on="1"/>
+ <pt x="68" y="800" on="0"/>
+ <pt x="202" y="955" on="1"/>
+ <pt x="336" y="1110" on="0"/>
+ <pt x="557" y="1110" on="1"/>
+ <pt x="689" y="1110" on="0"/>
+ <pt x="848" y="1061" on="1"/>
+ <pt x="848" y="802" on="1"/>
+ <pt x="724" y="802" on="1"/>
+ <pt x="724" y="820" on="1"/>
+ <pt x="724" y="1043" on="0"/>
+ <pt x="557" y="1043" on="1"/>
+ <pt x="434" y="1043" on="0"/>
+ <pt x="359" y="914" on="1"/>
+ <pt x="284" y="786" on="0"/>
+ <pt x="284" y="577" on="1"/>
+ <pt x="284" y="339" on="0"/>
+ <pt x="377" y="206" on="1"/>
+ <pt x="470" y="73" on="0"/>
+ <pt x="632" y="73" on="1"/>
+ <pt x="710" y="73" on="0"/>
+ <pt x="848" y="123" on="1"/>
+ </contour>
+ <contour>
+ <pt x="463" y="1283" on="1"/>
+ <pt x="463" y="1480" on="1"/>
+ <pt x="660" y="1480" on="1"/>
+ <pt x="660" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 0 0 25 9 2 17 17 10 48 84 10 1 2 2 1 1 27 15 14 13 12 0 6 1 2
+ 3 0 0 0 0 31 28 5 1 29 1 4 48 84 30 29 0 14 0 0 21 10 6 48 196
+ 15 14 2 0 30 3 6 28 0 0 29 28 4 1 30 1 4 48 196 31 30 1 27 13 12
+ 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cedilla" xMin="168" yMin="-432" xMax="514" yMax="0">
+ <contour>
+ <pt x="168" y="-411" on="1"/>
+ <pt x="168" y="-343" on="1"/>
+ <pt x="230" y="-359" on="0"/>
+ <pt x="269" y="-359" on="1"/>
+ <pt x="376" y="-359" on="0"/>
+ <pt x="376" y="-277" on="1"/>
+ <pt x="376" y="-179" on="0"/>
+ <pt x="189" y="-175" on="1"/>
+ <pt x="284" y="0" on="1"/>
+ <pt x="363" y="0" on="1"/>
+ <pt x="297" y="-119" on="1"/>
+ <pt x="394" y="-127" on="0"/>
+ <pt x="441" y="-152" on="1"/>
+ <pt x="514" y="-189" on="0"/>
+ <pt x="514" y="-266" on="1"/>
+ <pt x="514" y="-336" on="0"/>
+ <pt x="456" y="-384" on="1"/>
+ <pt x="399" y="-432" on="0"/>
+ <pt x="312" y="-432" on="1"/>
+ <pt x="244" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 3 17 18 48 84 18 10 9 8 7 1 0 14 0 0 5 48 14 48 196 14 10 9
+ 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cent" xMin="123" yMin="0" xMax="962" yMax="1480">
+ <contour>
+ <pt x="598" y="0" on="1"/>
+ <pt x="598" y="176" on="1"/>
+ <pt x="402" y="198" on="0"/>
+ <pt x="282" y="322" on="1"/>
+ <pt x="123" y="484" on="0"/>
+ <pt x="123" y="751" on="1"/>
+ <pt x="123" y="1011" on="0"/>
+ <pt x="260" y="1154" on="1"/>
+ <pt x="340" y="1238" on="0"/>
+ <pt x="455" y="1276" on="1"/>
+ <pt x="503" y="1292" on="0"/>
+ <pt x="598" y="1308" on="1"/>
+ <pt x="598" y="1480" on="1"/>
+ <pt x="660" y="1480" on="1"/>
+ <pt x="660" y="1313" on="1"/>
+ <pt x="820" y="1299" on="0"/>
+ <pt x="962" y="1252" on="1"/>
+ <pt x="962" y="999" on="1"/>
+ <pt x="851" y="999" on="1"/>
+ <pt x="850" y="1018" on="1"/>
+ <pt x="848" y="1043" on="1"/>
+ <pt x="848" y="1053" on="0"/>
+ <pt x="847" y="1063" on="1"/>
+ <pt x="846" y="1074" on="1"/>
+ <pt x="846" y="1083" on="0"/>
+ <pt x="846" y="1091" on="1"/>
+ <pt x="844" y="1169" on="0"/>
+ <pt x="806" y="1201" on="1"/>
+ <pt x="766" y="1234" on="0"/>
+ <pt x="660" y="1242" on="1"/>
+ <pt x="660" y="273" on="1"/>
+ <pt x="692" y="270" on="0"/>
+ <pt x="709" y="270" on="1"/>
+ <pt x="800" y="270" on="0"/>
+ <pt x="962" y="331" on="1"/>
+ <pt x="962" y="234" on="1"/>
+ <pt x="825" y="181" on="0"/>
+ <pt x="660" y="171" on="1"/>
+ <pt x="660" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="598" y="280" on="1"/>
+ <pt x="598" y="1243" on="1"/>
+ <pt x="535" y="1225" on="0"/>
+ <pt x="504" y="1205" on="1"/>
+ <pt x="333" y="1093" on="0"/>
+ <pt x="333" y="733" on="1"/>
+ <pt x="333" y="497" on="0"/>
+ <pt x="429" y="382" on="1"/>
+ <pt x="471" y="332" on="0"/>
+ <pt x="523" y="307" on="1"/>
+ <pt x="548" y="295" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 61 values pushed */
+ 40 39 38 37 35 34 32 30 29 18 17 16 14 13 12 11 1 0 14 0 0 44 10 5 48
+ 196 18 16 13 2 5 0 0 0 40 39 12 11 1 0 11 5 13 1 4 48 196 35 34 17
+ 16 3 38 37 30 29 14 13 5 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="circumflex" xMin="-10" yMin="1283" xMax="693" yMax="1604">
+ <contour>
+ <pt x="-10" y="1283" on="1"/>
+ <pt x="231" y="1604" on="1"/>
+ <pt x="453" y="1604" on="1"/>
+ <pt x="693" y="1283" on="1"/>
+ <pt x="607" y="1283" on="1"/>
+ <pt x="342" y="1505" on="1"/>
+ <pt x="76" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 1 5 1 0 2 0 1 6 4 3 0 4 13 0 0 2 1 1 0 14 6 5 4 3 2
+ 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="colon" xMin="161" yMin="0" xMax="408" yMax="1086">
+ <contour>
+ <pt x="161" y="0" on="1"/>
+ <pt x="161" y="247" on="1"/>
+ <pt x="408" y="247" on="1"/>
+ <pt x="408" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="161" y="839" on="1"/>
+ <pt x="161" y="1086" on="1"/>
+ <pt x="408" y="1086" on="1"/>
+ <pt x="408" y="839" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 7 4 6 1 5 2 1 6 1 0 2 4 48 84 3 0 1 0 6 5 1 14 0
+ 0 7 6 3 2 6 3 0 1 4 48 196 5 4 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="comma" xMin="133" yMin="-321" xMax="380" yMax="247">
+ <contour>
+ <pt x="232" y="0" on="1"/>
+ <pt x="133" y="0" on="1"/>
+ <pt x="133" y="247" on="1"/>
+ <pt x="380" y="247" on="1"/>
+ <pt x="380" y="32" on="1"/>
+ <pt x="380" y="-107" on="0"/>
+ <pt x="363" y="-151" on="1"/>
+ <pt x="341" y="-216" on="0"/>
+ <pt x="270" y="-270" on="1"/>
+ <pt x="210" y="-317" on="0"/>
+ <pt x="133" y="-321" on="1"/>
+ <pt x="133" y="-259" on="1"/>
+ <pt x="232" y="-251" on="0"/>
+ <pt x="232" y="-65" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 13 11 10 4 1 0 6 13 2 3 2 1 0 14 13 0 2 3 1 3 0 0 4 3 6
+ 1 1 1 4 48 196 11 10 2 1 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="copyright" xMin="87" yMin="49" xMax="1469" yMax="1431">
+ <contour>
+ <pt x="779" y="1431" on="1"/>
+ <pt x="1063" y="1431" on="0"/>
+ <pt x="1266" y="1229" on="1"/>
+ <pt x="1469" y="1027" on="0"/>
+ <pt x="1469" y="741" on="1"/>
+ <pt x="1469" y="452" on="0"/>
+ <pt x="1265" y="251" on="1"/>
+ <pt x="1062" y="49" on="0"/>
+ <pt x="770" y="49" on="1"/>
+ <pt x="519" y="49" on="0"/>
+ <pt x="331" y="213" on="1"/>
+ <pt x="87" y="426" on="0"/>
+ <pt x="87" y="740" on="1"/>
+ <pt x="87" y="1027" on="0"/>
+ <pt x="290" y="1229" on="1"/>
+ <pt x="493" y="1431" on="0"/>
+ </contour>
+ <contour>
+ <pt x="778" y="1369" on="1"/>
+ <pt x="518" y="1369" on="0"/>
+ <pt x="334" y="1185" on="1"/>
+ <pt x="149" y="1001" on="0"/>
+ <pt x="149" y="740" on="1"/>
+ <pt x="149" y="483" on="0"/>
+ <pt x="333" y="297" on="1"/>
+ <pt x="516" y="111" on="0"/>
+ <pt x="773" y="111" on="1"/>
+ <pt x="1010" y="111" on="0"/>
+ <pt x="1184" y="259" on="1"/>
+ <pt x="1407" y="450" on="0"/>
+ <pt x="1407" y="742" on="1"/>
+ <pt x="1407" y="1002" on="0"/>
+ <pt x="1222" y="1185" on="1"/>
+ <pt x="1037" y="1369" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1071" y="364" on="1"/>
+ <pt x="939" y="313" on="0"/>
+ <pt x="800" y="313" on="1"/>
+ <pt x="594" y="313" on="0"/>
+ <pt x="480" y="426" on="1"/>
+ <pt x="365" y="539" on="0"/>
+ <pt x="365" y="741" on="1"/>
+ <pt x="365" y="944" on="0"/>
+ <pt x="477" y="1056" on="1"/>
+ <pt x="589" y="1168" on="0"/>
+ <pt x="796" y="1168" on="1"/>
+ <pt x="916" y="1168" on="0"/>
+ <pt x="1057" y="1132" on="1"/>
+ <pt x="1057" y="964" on="1"/>
+ <pt x="975" y="964" on="1"/>
+ <pt x="975" y="974" on="1"/>
+ <pt x="975" y="1049" on="0"/>
+ <pt x="934" y="1081" on="1"/>
+ <pt x="893" y="1113" on="0"/>
+ <pt x="799" y="1113" on="1"/>
+ <pt x="545" y="1113" on="0"/>
+ <pt x="545" y="745" on="1"/>
+ <pt x="545" y="381" on="0"/>
+ <pt x="834" y="381" on="1"/>
+ <pt x="936" y="381" on="0"/>
+ <pt x="1071" y="442" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 55 17 34 51 25 42 24 11 8 16 11 0 48 84 8 2 0 0 42 34 1 1 57
+ 47 46 45 44 42 34 32 8 0 2 3 0 0 14 0 0 53 16 38 28 11 4 20 11 12
+ 48 196 57 32 2 13 4 44 47 46 38 12 44 45 44 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="currency" xMin="130" yMin="414" xMax="893" yMax="1178">
+ <contour>
+ <pt x="322" y="545" on="1"/>
+ <pt x="192" y="414" on="1"/>
+ <pt x="130" y="476" on="1"/>
+ <pt x="261" y="607" on="1"/>
+ <pt x="197" y="695" on="0"/>
+ <pt x="197" y="796" on="1"/>
+ <pt x="197" y="898" on="0"/>
+ <pt x="261" y="985" on="1"/>
+ <pt x="130" y="1116" on="1"/>
+ <pt x="192" y="1178" on="1"/>
+ <pt x="322" y="1047" on="1"/>
+ <pt x="415" y="1110" on="0"/>
+ <pt x="512" y="1110" on="1"/>
+ <pt x="609" y="1110" on="0"/>
+ <pt x="701" y="1047" on="1"/>
+ <pt x="832" y="1178" on="1"/>
+ <pt x="893" y="1116" on="1"/>
+ <pt x="762" y="985" on="1"/>
+ <pt x="826" y="897" on="0"/>
+ <pt x="826" y="796" on="1"/>
+ <pt x="826" y="695" on="0"/>
+ <pt x="762" y="607" on="1"/>
+ <pt x="893" y="476" on="1"/>
+ <pt x="832" y="414" on="1"/>
+ <pt x="701" y="545" on="1"/>
+ <pt x="610" y="482" on="0"/>
+ <pt x="512" y="482" on="1"/>
+ <pt x="415" y="482" on="0"/>
+ </contour>
+ <contour>
+ <pt x="512" y="1012" on="1"/>
+ <pt x="422" y="1012" on="0"/>
+ <pt x="359" y="950" on="1"/>
+ <pt x="296" y="887" on="0"/>
+ <pt x="296" y="799" on="1"/>
+ <pt x="296" y="716" on="0"/>
+ <pt x="346" y="656" on="1"/>
+ <pt x="410" y="580" on="0"/>
+ <pt x="512" y="580" on="1"/>
+ <pt x="603" y="580" on="0"/>
+ <pt x="665" y="643" on="1"/>
+ <pt x="727" y="705" on="0"/>
+ <pt x="727" y="796" on="1"/>
+ <pt x="727" y="887" on="0"/>
+ <pt x="664" y="949" on="1"/>
+ <pt x="601" y="1012" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 0 36 9 26 28 9 12 48 84 12 1 1 16 15 9 8 4 13 1 0 1 24 23 22
+ 21 17 14 10 7 3 2 1 0 12 13 26 1 0 14 0 0 40 9 19 32 9 5 48 196
+ 24 23 22 21 19 17 16 15 14 10 9 8 7 5 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="d" xMin="68" yMin="-25" xMax="1024" yMax="1579">
+ <contour>
+ <pt x="706" y="0" on="1"/>
+ <pt x="706" y="179" on="1"/>
+ <pt x="648" y="87" on="0"/>
+ <pt x="592" y="41" on="1"/>
+ <pt x="512" y="-25" on="0"/>
+ <pt x="414" y="-25" on="1"/>
+ <pt x="254" y="-25" on="0"/>
+ <pt x="161" y="118" on="1"/>
+ <pt x="68" y="260" on="0"/>
+ <pt x="68" y="510" on="1"/>
+ <pt x="68" y="793" on="0"/>
+ <pt x="189" y="951" on="1"/>
+ <pt x="310" y="1110" on="0"/>
+ <pt x="523" y="1110" on="1"/>
+ <pt x="597" y="1110" on="0"/>
+ <pt x="706" y="1086" on="1"/>
+ <pt x="706" y="1320" on="1"/>
+ <pt x="704" y="1419" on="1"/>
+ <pt x="703" y="1488" on="0"/>
+ <pt x="679" y="1501" on="1"/>
+ <pt x="657" y="1513" on="0"/>
+ <pt x="604" y="1516" on="1"/>
+ <pt x="585" y="1517" on="1"/>
+ <pt x="585" y="1579" on="1"/>
+ <pt x="903" y="1579" on="1"/>
+ <pt x="903" y="259" on="1"/>
+ <pt x="905" y="160" on="1"/>
+ <pt x="905" y="92" on="0"/>
+ <pt x="930" y="78" on="1"/>
+ <pt x="953" y="66" on="0"/>
+ <pt x="1006" y="63" on="1"/>
+ <pt x="1024" y="62" on="1"/>
+ <pt x="1024" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="706" y="1008" on="1"/>
+ <pt x="626" y="1032" on="0"/>
+ <pt x="576" y="1032" on="1"/>
+ <pt x="439" y="1032" on="0"/>
+ <pt x="360" y="905" on="1"/>
+ <pt x="281" y="778" on="0"/>
+ <pt x="281" y="550" on="1"/>
+ <pt x="281" y="103" on="0"/>
+ <pt x="482" y="103" on="1"/>
+ <pt x="576" y="103" on="0"/>
+ <pt x="706" y="248" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 78 values pushed */
+ 0 0 41 29 5 35 21 13 48 84 13 1 5 2 1 22 16 2 23 1 3 0 1 43 33
+ 31 25 15 1 6 1 0 3 0 24 23 1 32 0 1 2 0 14 0 0 39 10 9 48 196
+ 32 31 2 13 24 23 22 9 0 0 0 43 33 16 15 1 0 4 5 24 1 4 48 196 25
+ 24 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dagger" xMin="80" yMin="-296" xMax="944" yMax="1480">
+ <contour>
+ <pt x="413" y="-296" on="1"/>
+ <pt x="462" y="857" on="1"/>
+ <pt x="80" y="814" on="1"/>
+ <pt x="80" y="962" on="1"/>
+ <pt x="462" y="919" on="1"/>
+ <pt x="413" y="1480" on="1"/>
+ <pt x="610" y="1480" on="1"/>
+ <pt x="561" y="919" on="1"/>
+ <pt x="944" y="962" on="1"/>
+ <pt x="944" y="814" on="1"/>
+ <pt x="561" y="857" on="1"/>
+ <pt x="610" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 42 values pushed */
+ 1 10 9 8 7 4 3 2 1 8 5 2 3 0 11 0 1 0 6 5 0 14 11 10 7
+ 6 5 4 1 0 8 8 2 3 9 8 1 3 2 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="daggerdbl" xMin="80" yMin="-296" xMax="944" yMax="1480">
+ <contour>
+ <pt x="413" y="-296" on="1"/>
+ <pt x="462" y="265" on="1"/>
+ <pt x="80" y="222" on="1"/>
+ <pt x="80" y="370" on="1"/>
+ <pt x="462" y="327" on="1"/>
+ <pt x="462" y="857" on="1"/>
+ <pt x="80" y="814" on="1"/>
+ <pt x="80" y="962" on="1"/>
+ <pt x="462" y="919" on="1"/>
+ <pt x="413" y="1480" on="1"/>
+ <pt x="610" y="1480" on="1"/>
+ <pt x="561" y="919" on="1"/>
+ <pt x="944" y="962" on="1"/>
+ <pt x="944" y="814" on="1"/>
+ <pt x="561" y="857" on="1"/>
+ <pt x="561" y="327" on="1"/>
+ <pt x="944" y="370" on="1"/>
+ <pt x="944" y="222" on="1"/>
+ <pt x="561" y="265" on="1"/>
+ <pt x="610" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 1 18 17 16 15 14 13 12 11 8 7 6 5 4 3 2 1 16 9 2 3 0 19 0 1
+ 0 10 9 0 14 19 10 2 12 11 3 9 0 2 1 2 3 0 0 18 15 14 11 9 3
+ 1 1 4 48 196 17 16 13 12 3 8 5 4 1 3 7 6 3 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dcaron" xMin="68" yMin="-25" xMax="1298" yMax="1579">
+ <contour>
+ <pt x="706" y="179" on="1"/>
+ <pt x="648" y="87" on="0"/>
+ <pt x="592" y="41" on="1"/>
+ <pt x="512" y="-25" on="0"/>
+ <pt x="414" y="-25" on="1"/>
+ <pt x="254" y="-25" on="0"/>
+ <pt x="161" y="118" on="1"/>
+ <pt x="68" y="260" on="0"/>
+ <pt x="68" y="510" on="1"/>
+ <pt x="68" y="793" on="0"/>
+ <pt x="189" y="951" on="1"/>
+ <pt x="310" y="1110" on="0"/>
+ <pt x="523" y="1110" on="1"/>
+ <pt x="597" y="1110" on="0"/>
+ <pt x="706" y="1086" on="1"/>
+ <pt x="706" y="1320" on="1"/>
+ <pt x="704" y="1419" on="1"/>
+ <pt x="703" y="1488" on="0"/>
+ <pt x="679" y="1501" on="1"/>
+ <pt x="657" y="1513" on="0"/>
+ <pt x="604" y="1516" on="1"/>
+ <pt x="585" y="1517" on="1"/>
+ <pt x="585" y="1579" on="1"/>
+ <pt x="903" y="1579" on="1"/>
+ <pt x="903" y="259" on="1"/>
+ <pt x="905" y="160" on="1"/>
+ <pt x="905" y="92" on="0"/>
+ <pt x="930" y="78" on="1"/>
+ <pt x="953" y="66" on="0"/>
+ <pt x="1006" y="63" on="1"/>
+ <pt x="1024" y="62" on="1"/>
+ <pt x="1024" y="0" on="1"/>
+ <pt x="706" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="706" y="1008" on="1"/>
+ <pt x="626" y="1032" on="0"/>
+ <pt x="576" y="1032" on="1"/>
+ <pt x="439" y="1032" on="0"/>
+ <pt x="360" y="905" on="1"/>
+ <pt x="281" y="778" on="0"/>
+ <pt x="281" y="550" on="1"/>
+ <pt x="281" y="103" on="0"/>
+ <pt x="482" y="103" on="1"/>
+ <pt x="576" y="103" on="0"/>
+ <pt x="706" y="248" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1180" y="1382" on="1"/>
+ <pt x="1101" y="1382" on="1"/>
+ <pt x="1101" y="1579" on="1"/>
+ <pt x="1298" y="1579" on="1"/>
+ <pt x="1298" y="1408" on="1"/>
+ <pt x="1298" y="1245" on="0"/>
+ <pt x="1236" y="1180" on="1"/>
+ <pt x="1188" y="1131" on="0"/>
+ <pt x="1101" y="1125" on="1"/>
+ <pt x="1101" y="1175" on="1"/>
+ <pt x="1180" y="1181" on="0"/>
+ <pt x="1180" y="1330" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 104 values pushed */
+ 0 0 41 29 4 35 21 12 48 84 12 1 4 2 1 55 53 52 48 45 44 21 15 8 22
+ 1 3 0 1 43 33 30 24 14 0 6 1 31 3 0 47 46 23 22 3 32 31 1 2 0
+ 14 0 0 39 10 8 48 196 55 44 2 47 45 3 31 30 2 45 23 3 22 21 8 0 0
+ 0 53 52 46 45 4 3 47 43 33 32 15 14 0 4 5 23 2 4 48 196 48 47 1 24
+ 23 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dcroat" xMin="68" yMin="-25" xMax="1024" yMax="1579">
+ <contour>
+ <pt x="706" y="0" on="1"/>
+ <pt x="706" y="179" on="1"/>
+ <pt x="648" y="87" on="0"/>
+ <pt x="592" y="41" on="1"/>
+ <pt x="512" y="-25" on="0"/>
+ <pt x="414" y="-25" on="1"/>
+ <pt x="254" y="-25" on="0"/>
+ <pt x="161" y="118" on="1"/>
+ <pt x="68" y="260" on="0"/>
+ <pt x="68" y="510" on="1"/>
+ <pt x="68" y="793" on="0"/>
+ <pt x="189" y="951" on="1"/>
+ <pt x="310" y="1110" on="0"/>
+ <pt x="523" y="1110" on="1"/>
+ <pt x="597" y="1110" on="0"/>
+ <pt x="706" y="1086" on="1"/>
+ <pt x="706" y="1246" on="1"/>
+ <pt x="410" y="1246" on="1"/>
+ <pt x="410" y="1308" on="1"/>
+ <pt x="706" y="1308" on="1"/>
+ <pt x="706" y="1320" on="1"/>
+ <pt x="704" y="1419" on="1"/>
+ <pt x="703" y="1488" on="0"/>
+ <pt x="679" y="1501" on="1"/>
+ <pt x="657" y="1513" on="0"/>
+ <pt x="604" y="1516" on="1"/>
+ <pt x="585" y="1517" on="1"/>
+ <pt x="585" y="1579" on="1"/>
+ <pt x="903" y="1579" on="1"/>
+ <pt x="903" y="1308" on="1"/>
+ <pt x="1024" y="1308" on="1"/>
+ <pt x="1024" y="1246" on="1"/>
+ <pt x="903" y="1246" on="1"/>
+ <pt x="903" y="259" on="1"/>
+ <pt x="905" y="160" on="1"/>
+ <pt x="905" y="92" on="0"/>
+ <pt x="930" y="78" on="1"/>
+ <pt x="953" y="66" on="0"/>
+ <pt x="1006" y="63" on="1"/>
+ <pt x="1024" y="62" on="1"/>
+ <pt x="1024" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="706" y="1008" on="1"/>
+ <pt x="626" y="1032" on="0"/>
+ <pt x="576" y="1032" on="1"/>
+ <pt x="439" y="1032" on="0"/>
+ <pt x="360" y="905" on="1"/>
+ <pt x="281" y="778" on="0"/>
+ <pt x="281" y="550" on="1"/>
+ <pt x="281" y="103" on="0"/>
+ <pt x="482" y="103" on="1"/>
+ <pt x="576" y="103" on="0"/>
+ <pt x="706" y="248" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 104 values pushed */
+ 0 0 49 29 5 43 21 13 48 84 13 1 5 2 26 20 2 27 18 3 1 51 41 39 33
+ 15 1 6 1 0 3 0 0 0 32 31 17 16 14 3 18 1 4 48 84 28 27 1 30 29
+ 19 18 3 40 0 1 3 0 14 0 0 47 10 9 48 196 40 39 31 30 4 13 28 27 26
+ 18 17 4 13 9 0 0 0 51 41 20 19 16 15 1 0 4 7 28 1 4 48 196 33 32
+ 29 28 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="degree" xMin="114" yMin="925" xMax="706" yMax="1517">
+ <contour>
+ <pt x="410" y="1517" on="1"/>
+ <pt x="531" y="1517" on="0"/>
+ <pt x="619" y="1430" on="1"/>
+ <pt x="706" y="1344" on="0"/>
+ <pt x="706" y="1222" on="1"/>
+ <pt x="706" y="1098" on="0"/>
+ <pt x="619" y="1012" on="1"/>
+ <pt x="531" y="925" on="0"/>
+ <pt x="406" y="925" on="1"/>
+ <pt x="300" y="925" on="0"/>
+ <pt x="219" y="995" on="1"/>
+ <pt x="114" y="1087" on="0"/>
+ <pt x="114" y="1221" on="1"/>
+ <pt x="114" y="1344" on="0"/>
+ <pt x="201" y="1430" on="1"/>
+ <pt x="289" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="410" y="1431" on="1"/>
+ <pt x="323" y="1431" on="0"/>
+ <pt x="262" y="1370" on="1"/>
+ <pt x="200" y="1308" on="0"/>
+ <pt x="200" y="1221" on="1"/>
+ <pt x="200" y="1136" on="0"/>
+ <pt x="262" y="1074" on="1"/>
+ <pt x="323" y="1012" on="0"/>
+ <pt x="409" y="1012" on="1"/>
+ <pt x="488" y="1012" on="0"/>
+ <pt x="546" y="1062" on="1"/>
+ <pt x="620" y="1125" on="0"/>
+ <pt x="620" y="1222" on="1"/>
+ <pt x="620" y="1309" on="0"/>
+ <pt x="558" y="1370" on="1"/>
+ <pt x="496" y="1431" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 28 values pushed */
+ 0 0 24 8 16 7 0 48 84 0 0 1 8 0 0 14 0 0 28 8 4 20 8 12 48
+ 196 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dieresis" xMin="57" yMin="1283" xMax="625" yMax="1456">
+ <contour>
+ <pt x="57" y="1283" on="1"/>
+ <pt x="57" y="1456" on="1"/>
+ <pt x="230" y="1456" on="1"/>
+ <pt x="230" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="452" y="1283" on="1"/>
+ <pt x="452" y="1456" on="1"/>
+ <pt x="625" y="1456" on="1"/>
+ <pt x="625" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 7 4 3 0 13 3 1 1 4 48 84 6 5 2 1 3 0 14 0 0 5 4 13
+ 1 6 3 2 13 1 0 2 4 48 196 7 6 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="divide" xMin="84" yMin="99" xMax="1071" yMax="1086">
+ <contour>
+ <pt x="479" y="99" on="1"/>
+ <pt x="479" y="296" on="1"/>
+ <pt x="676" y="296" on="1"/>
+ <pt x="676" y="99" on="1"/>
+ </contour>
+ <contour>
+ <pt x="84" y="543" on="1"/>
+ <pt x="84" y="642" on="1"/>
+ <pt x="1071" y="642" on="1"/>
+ <pt x="1071" y="543" on="1"/>
+ </contour>
+ <contour>
+ <pt x="479" y="888" on="1"/>
+ <pt x="479" y="1086" on="1"/>
+ <pt x="676" y="1086" on="1"/>
+ <pt x="676" y="888" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 0 0 11 8 5 1 9 7 4 9 1 5 2 1 5 1 0 3 4 48 84 6 5 1 3
+ 0 1 2 0 10 9 1 14 7 6 2 13 2 5 4 0 0 0 11 10 3 2 4 3 0
+ 1 4 48 196 9 8 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dollar" xMin="80" yMin="-123" xMax="931" yMax="1604">
+ <contour>
+ <pt x="495" y="-123" on="1"/>
+ <pt x="495" y="0" on="1"/>
+ <pt x="283" y="0" on="0"/>
+ <pt x="80" y="86" on="1"/>
+ <pt x="80" y="333" on="1"/>
+ <pt x="191" y="333" on="1"/>
+ <pt x="192" y="315" on="1"/>
+ <pt x="194" y="279" on="0"/>
+ <pt x="195" y="253" on="1"/>
+ <pt x="195" y="247" on="1"/>
+ <pt x="195" y="166" on="0"/>
+ <pt x="267" y="116" on="1"/>
+ <pt x="340" y="65" on="0"/>
+ <pt x="456" y="65" on="1"/>
+ <pt x="495" y="66" on="1"/>
+ <pt x="495" y="673" on="1"/>
+ <pt x="303" y="785" on="0"/>
+ <pt x="224" y="875" on="1"/>
+ <pt x="129" y="981" on="0"/>
+ <pt x="129" y="1130" on="1"/>
+ <pt x="129" y="1271" on="0"/>
+ <pt x="213" y="1360" on="1"/>
+ <pt x="275" y="1425" on="0"/>
+ <pt x="379" y="1460" on="1"/>
+ <pt x="417" y="1472" on="0"/>
+ <pt x="495" y="1487" on="1"/>
+ <pt x="495" y="1604" on="1"/>
+ <pt x="556" y="1604" on="1"/>
+ <pt x="557" y="1485" on="1"/>
+ <pt x="728" y="1477" on="0"/>
+ <pt x="913" y="1408" on="1"/>
+ <pt x="913" y="1178" on="1"/>
+ <pt x="802" y="1178" on="1"/>
+ <pt x="801" y="1197" on="1"/>
+ <pt x="799" y="1220" on="1"/>
+ <pt x="799" y="1225" on="0"/>
+ <pt x="798" y="1238" on="1"/>
+ <pt x="797" y="1253" on="0"/>
+ <pt x="797" y="1258" on="1"/>
+ <pt x="797" y="1262" on="1"/>
+ <pt x="797" y="1326" on="0"/>
+ <pt x="748" y="1366" on="1"/>
+ <pt x="687" y="1417" on="0"/>
+ <pt x="576" y="1417" on="1"/>
+ <pt x="557" y="1417" on="1"/>
+ <pt x="557" y="837" on="1"/>
+ <pt x="581" y="822" on="1"/>
+ <pt x="610" y="803" on="1"/>
+ <pt x="632" y="789" on="1"/>
+ <pt x="662" y="770" on="1"/>
+ <pt x="826" y="665" on="0"/>
+ <pt x="874" y="603" on="1"/>
+ <pt x="931" y="530" on="0"/>
+ <pt x="931" y="412" on="1"/>
+ <pt x="931" y="228" on="0"/>
+ <pt x="799" y="110" on="1"/>
+ <pt x="709" y="29" on="0"/>
+ <pt x="557" y="-3" on="1"/>
+ <pt x="557" y="-123" on="1"/>
+ </contour>
+ <contour>
+ <pt x="557" y="78" on="1"/>
+ <pt x="648" y="110" on="0"/>
+ <pt x="693" y="162" on="1"/>
+ <pt x="759" y="237" on="0"/>
+ <pt x="759" y="357" on="1"/>
+ <pt x="759" y="506" on="0"/>
+ <pt x="603" y="607" on="1"/>
+ <pt x="557" y="637" on="1"/>
+ </contour>
+ <contour>
+ <pt x="495" y="879" on="1"/>
+ <pt x="495" y="1410" on="1"/>
+ <pt x="414" y="1397" on="0"/>
+ <pt x="365" y="1343" on="1"/>
+ <pt x="301" y="1273" on="0"/>
+ <pt x="301" y="1167" on="1"/>
+ <pt x="301" y="1012" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 94 values pushed */
+ 68 67 66 59 58 57 45 44 43 39 38 32 31 30 28 27 26 25 15 14 9 8 5 4 3
+ 1 0 14 0 0 72 18 19 63 18 53 48 196 43 39 38 32 4 30 28 3 27 28 0 2
+ 19 19 9 8 5 4 0 3 3 53 30 0 0 66 59 58 57 45 44 28 11 6 0 1 4
+ 48 196 31 30 1 68 67 26 25 15 14 1 0 7 4 3 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotaccent" xMin="242" yMin="1283" xMax="439" yMax="1480">
+ <contour>
+ <pt x="242" y="1283" on="1"/>
+ <pt x="242" y="1480" on="1"/>
+ <pt x="439" y="1480" on="1"/>
+ <pt x="439" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 0 0 3 0 5 1 1 1 4 48 84 2 1 0 14 0 0 3 2 4 1 0 1 4 48
+ 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotlessi" xMin="47" yMin="0" xMax="536" yMax="1086">
+ <contour>
+ <pt x="536" y="62" on="1"/>
+ <pt x="536" y="0" on="1"/>
+ <pt x="47" y="0" on="1"/>
+ <pt x="47" y="62" on="1"/>
+ <pt x="66" y="63" on="1"/>
+ <pt x="174" y="70" on="0"/>
+ <pt x="180" y="87" on="1"/>
+ <pt x="191" y="106" on="0"/>
+ <pt x="191" y="160" on="1"/>
+ <pt x="193" y="259" on="1"/>
+ <pt x="193" y="827" on="1"/>
+ <pt x="191" y="925" on="1"/>
+ <pt x="190" y="999" on="0"/>
+ <pt x="169" y="1007" on="1"/>
+ <pt x="149" y="1018" on="0"/>
+ <pt x="66" y="1023" on="1"/>
+ <pt x="47" y="1024" on="1"/>
+ <pt x="47" y="1086" on="1"/>
+ <pt x="390" y="1086" on="1"/>
+ <pt x="390" y="259" on="1"/>
+ <pt x="392" y="160" on="1"/>
+ <pt x="393" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="435" y="68" on="0"/>
+ <pt x="517" y="63" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 49 values pushed */
+ 19 16 13 10 9 6 3 0 8 17 1 3 2 1 1 0 18 17 1 14 1 0 2 13 18
+ 17 16 13 6 3 2 6 13 9 0 0 19 18 4 1 9 1 4 48 196 10 9 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotlessj" xMin="-78" yMin="-419" xMax="459" yMax="1086">
+ <contour>
+ <pt x="-78" y="-380" on="1"/>
+ <pt x="-78" y="-136" on="1"/>
+ <pt x="21" y="-136" on="1"/>
+ <pt x="22" y="-154" on="1"/>
+ <pt x="26" y="-272" on="0"/>
+ <pt x="47" y="-311" on="1"/>
+ <pt x="72" y="-358" on="0"/>
+ <pt x="133" y="-358" on="1"/>
+ <pt x="262" y="-358" on="0"/>
+ <pt x="262" y="-185" on="1"/>
+ <pt x="262" y="-82" on="1"/>
+ <pt x="262" y="827" on="1"/>
+ <pt x="260" y="925" on="1"/>
+ <pt x="260" y="993" on="0"/>
+ <pt x="235" y="1007" on="1"/>
+ <pt x="214" y="1019" on="0"/>
+ <pt x="159" y="1023" on="1"/>
+ <pt x="141" y="1024" on="1"/>
+ <pt x="141" y="1086" on="1"/>
+ <pt x="459" y="1086" on="1"/>
+ <pt x="459" y="12" on="1"/>
+ <pt x="459" y="-419" on="0"/>
+ <pt x="127" y="-419" on="1"/>
+ <pt x="51" y="-419" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 0 7 11 22 48 84 1 20 17 11 3 18 2 3 0 1 10 9 2 1 0 5 13 22
+ 2 0 19 18 1 14 18 17 2 3 9 0 3 0 0 11 10 9 4 2 19 1 4 48 196
+ 20 19 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotmath" xMin="133" yMin="491" xMax="380" yMax="738">
+ <contour>
+ <pt x="133" y="491" on="1"/>
+ <pt x="133" y="738" on="1"/>
+ <pt x="380" y="738" on="1"/>
+ <pt x="380" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 84 2 1 1 0 14 0 0 3 2 6 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="e" xMin="68" yMin="-25" xMax="848" yMax="1110">
+ <contour>
+ <pt x="848" y="49" on="1"/>
+ <pt x="682" y="-25" on="0"/>
+ <pt x="542" y="-25" on="1"/>
+ <pt x="322" y="-25" on="0"/>
+ <pt x="195" y="124" on="1"/>
+ <pt x="68" y="273" on="0"/>
+ <pt x="68" y="536" on="1"/>
+ <pt x="68" y="796" on="0"/>
+ <pt x="185" y="953" on="1"/>
+ <pt x="301" y="1110" on="0"/>
+ <pt x="496" y="1110" on="1"/>
+ <pt x="677" y="1110" on="0"/>
+ <pt x="763" y="988" on="1"/>
+ <pt x="848" y="866" on="0"/>
+ <pt x="848" y="605" on="1"/>
+ <pt x="848" y="586" on="1"/>
+ <pt x="284" y="586" on="1"/>
+ <pt x="287" y="442" on="0"/>
+ <pt x="302" y="368" on="1"/>
+ <pt x="362" y="75" on="0"/>
+ <pt x="600" y="75" on="1"/>
+ <pt x="722" y="75" on="0"/>
+ <pt x="848" y="150" on="1"/>
+ </contour>
+ <contour>
+ <pt x="284" y="648" on="1"/>
+ <pt x="638" y="648" on="1"/>
+ <pt x="639" y="692" on="1"/>
+ <pt x="643" y="869" on="0"/>
+ <pt x="611" y="957" on="1"/>
+ <pt x="580" y="1043" on="0"/>
+ <pt x="486" y="1043" on="1"/>
+ <pt x="382" y="1043" on="0"/>
+ <pt x="325" y="901" on="1"/>
+ <pt x="286" y="803" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 0 0 29 17 10 20 9 2 48 84 10 1 2 2 14 23 15 2 1 22 0 2 15 2 3
+ 0 0 0 16 15 14 1 23 1 4 48 84 24 23 1 0 14 24 23 22 16 15 14 6 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eacute" xMin="68" yMin="-25" xMax="848" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="211" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ebreve" xMin="68" yMin="-25" xMax="848" yMax="1604">
+ <contour>
+ <pt x="848" y="49" on="1"/>
+ <pt x="682" y="-25" on="0"/>
+ <pt x="542" y="-25" on="1"/>
+ <pt x="322" y="-25" on="0"/>
+ <pt x="195" y="124" on="1"/>
+ <pt x="68" y="273" on="0"/>
+ <pt x="68" y="536" on="1"/>
+ <pt x="68" y="796" on="0"/>
+ <pt x="185" y="953" on="1"/>
+ <pt x="301" y="1110" on="0"/>
+ <pt x="496" y="1110" on="1"/>
+ <pt x="677" y="1110" on="0"/>
+ <pt x="763" y="988" on="1"/>
+ <pt x="848" y="866" on="0"/>
+ <pt x="848" y="605" on="1"/>
+ <pt x="848" y="586" on="1"/>
+ <pt x="284" y="586" on="1"/>
+ <pt x="287" y="442" on="0"/>
+ <pt x="302" y="368" on="1"/>
+ <pt x="362" y="75" on="0"/>
+ <pt x="600" y="75" on="1"/>
+ <pt x="722" y="75" on="0"/>
+ <pt x="848" y="150" on="1"/>
+ </contour>
+ <contour>
+ <pt x="284" y="648" on="1"/>
+ <pt x="638" y="648" on="1"/>
+ <pt x="639" y="692" on="1"/>
+ <pt x="643" y="869" on="0"/>
+ <pt x="611" y="957" on="1"/>
+ <pt x="580" y="1043" on="0"/>
+ <pt x="486" y="1043" on="1"/>
+ <pt x="382" y="1043" on="0"/>
+ <pt x="325" y="901" on="1"/>
+ <pt x="286" y="803" on="0"/>
+ </contour>
+ <contour>
+ <pt x="160" y="1604" on="1"/>
+ <pt x="225" y="1604" on="1"/>
+ <pt x="252" y="1514" on="0"/>
+ <pt x="312" y="1472" on="1"/>
+ <pt x="380" y="1425" on="0"/>
+ <pt x="493" y="1425" on="1"/>
+ <pt x="619" y="1425" on="0"/>
+ <pt x="689" y="1484" on="1"/>
+ <pt x="737" y="1523" on="0"/>
+ <pt x="762" y="1604" on="1"/>
+ <pt x="826" y="1604" on="1"/>
+ <pt x="807" y="1469" on="0"/>
+ <pt x="735" y="1388" on="1"/>
+ <pt x="640" y="1283" on="0"/>
+ <pt x="493" y="1283" on="1"/>
+ <pt x="340" y="1283" on="0"/>
+ <pt x="244" y="1398" on="1"/>
+ <pt x="179" y="1475" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 38 20 47 29 17 10 20 9 2 48 84 10 1 2 2 14 23 15 2 1 22 0 2
+ 15 2 3 0 1 43 42 34 33 4 13 47 1 0 0 0 16 15 14 1 23 1 4 48 84
+ 24 23 1 0 14 43 42 34 33 24 23 22 16 15 14 6 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ecaron" xMin="68" yMin="-25" xMax="848" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="152" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ecircumflex" xMin="68" yMin="-25" xMax="848" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="152" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="edieresis" xMin="68" yMin="-25" xMax="848" yMax="1456">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="153" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="edotaccent" xMin="68" yMin="-25" xMax="848" yMax="1480">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="dotaccent" x="153" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="egrave" xMin="68" yMin="-25" xMax="848" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="94" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="eight" xMin="40" yMin="-37" xMax="977" yMax="1518">
+ <contour>
+ <pt x="342" y="797" on="1"/>
+ <pt x="222" y="881" on="0"/>
+ <pt x="173" y="949" on="1"/>
+ <pt x="114" y="1029" on="0"/>
+ <pt x="114" y="1148" on="1"/>
+ <pt x="114" y="1317" on="0"/>
+ <pt x="223" y="1417" on="1"/>
+ <pt x="331" y="1518" on="0"/>
+ <pt x="517" y="1518" on="1"/>
+ <pt x="698" y="1518" on="0"/>
+ <pt x="807" y="1430" on="1"/>
+ <pt x="916" y="1342" on="0"/>
+ <pt x="916" y="1196" on="1"/>
+ <pt x="916" y="1062" on="0"/>
+ <pt x="811" y="952" on="1"/>
+ <pt x="747" y="886" on="0"/>
+ <pt x="627" y="816" on="1"/>
+ <pt x="677" y="787" on="1"/>
+ <pt x="843" y="691" on="0"/>
+ <pt x="911" y="599" on="1"/>
+ <pt x="977" y="510" on="0"/>
+ <pt x="977" y="383" on="1"/>
+ <pt x="977" y="204" on="0"/>
+ <pt x="840" y="84" on="1"/>
+ <pt x="703" y="-37" on="0"/>
+ <pt x="500" y="-37" on="1"/>
+ <pt x="301" y="-37" on="0"/>
+ <pt x="171" y="76" on="1"/>
+ <pt x="40" y="188" on="0"/>
+ <pt x="40" y="364" on="1"/>
+ <pt x="40" y="541" on="0"/>
+ <pt x="152" y="664" on="1"/>
+ <pt x="218" y="735" on="0"/>
+ </contour>
+ <contour>
+ <pt x="569" y="850" on="1"/>
+ <pt x="743" y="986" on="0"/>
+ <pt x="743" y="1187" on="1"/>
+ <pt x="743" y="1304" on="0"/>
+ <pt x="675" y="1377" on="1"/>
+ <pt x="608" y="1450" on="0"/>
+ <pt x="505" y="1450" on="1"/>
+ <pt x="407" y="1450" on="0"/>
+ <pt x="347" y="1386" on="1"/>
+ <pt x="286" y="1323" on="0"/>
+ <pt x="286" y="1219" on="1"/>
+ <pt x="286" y="1107" on="0"/>
+ <pt x="344" y="1042" on="1"/>
+ <pt x="392" y="988" on="0"/>
+ <pt x="510" y="896" on="1"/>
+ </contour>
+ <contour>
+ <pt x="386" y="754" on="1"/>
+ <pt x="237" y="607" on="0"/>
+ <pt x="237" y="388" on="1"/>
+ <pt x="237" y="225" on="0"/>
+ <pt x="315" y="128" on="1"/>
+ <pt x="392" y="31" on="0"/>
+ <pt x="520" y="31" on="1"/>
+ <pt x="630" y="31" on="0"/>
+ <pt x="705" y="116" on="1"/>
+ <pt x="780" y="200" on="0"/>
+ <pt x="780" y="321" on="1"/>
+ <pt x="780" y="442" on="0"/>
+ <pt x="700" y="523" on="1"/>
+ <pt x="637" y="588" on="0"/>
+ <pt x="501" y="678" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 51 values pushed */
+ 0 0 54 17 25 39 17 8 48 84 25 2 8 0 1 1 48 33 16 0 4 0 2 3 0
+ 0 14 0 0 58 5 21 50 5 29 43 18 4 35 18 12 48 196 48 33 29 21 16 12 4
+ 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ellipsis" xMin="243" yMin="0" xMax="1806" yMax="197">
+ <contour>
+ <pt x="243" y="0" on="1"/>
+ <pt x="243" y="197" on="1"/>
+ <pt x="440" y="197" on="1"/>
+ <pt x="440" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="926" y="0" on="1"/>
+ <pt x="926" y="197" on="1"/>
+ <pt x="1123" y="197" on="1"/>
+ <pt x="1123" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1608" y="0" on="1"/>
+ <pt x="1608" y="197" on="1"/>
+ <pt x="1806" y="197" on="1"/>
+ <pt x="1806" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 10 9 6 5 2 1 5 5 0 1 4 48 84 11 8 7 4 3 0 5 0 14 0
+ 0 9 8 4 1 10 7 6 4 1 4 3 2 4 1 0 3 4 48 196 11 10 1 5 4
+ 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="emacron" xMin="68" yMin="-25" xMax="848" yMax="1406">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="153" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="emdash" xMin="99" yMin="543" xMax="1950" yMax="642">
+ <contour>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="642" on="1"/>
+ <pt x="1950" y="642" on="1"/>
+ <pt x="1950" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 9 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="endash" xMin="86" yMin="543" xMax="937" yMax="666">
+ <contour>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="666" on="1"/>
+ <pt x="937" y="666" on="1"/>
+ <pt x="937" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eng" xMin="37" yMin="-419" xMax="897" yMax="1110">
+ <contour>
+ <pt x="37" y="0" on="1"/>
+ <pt x="37" y="62" on="1"/>
+ <pt x="56" y="63" on="1"/>
+ <pt x="129" y="67" on="0"/>
+ <pt x="142" y="89" on="1"/>
+ <pt x="155" y="108" on="0"/>
+ <pt x="156" y="160" on="1"/>
+ <pt x="158" y="259" on="1"/>
+ <pt x="158" y="827" on="1"/>
+ <pt x="156" y="925" on="1"/>
+ <pt x="156" y="993" on="0"/>
+ <pt x="131" y="1007" on="1"/>
+ <pt x="110" y="1019" on="0"/>
+ <pt x="56" y="1023" on="1"/>
+ <pt x="37" y="1024" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="356" y="1086" on="1"/>
+ <pt x="356" y="907" on="1"/>
+ <pt x="420" y="999" on="0"/>
+ <pt x="480" y="1044" on="1"/>
+ <pt x="566" y="1110" on="0"/>
+ <pt x="667" y="1110" on="1"/>
+ <pt x="791" y="1110" on="0"/>
+ <pt x="844" y="1032" on="1"/>
+ <pt x="897" y="954" on="0"/>
+ <pt x="897" y="765" on="1"/>
+ <pt x="897" y="12" on="1"/>
+ <pt x="897" y="-419" on="0"/>
+ <pt x="536" y="-419" on="1"/>
+ <pt x="438" y="-419" on="0"/>
+ <pt x="311" y="-380" on="1"/>
+ <pt x="311" y="-136" on="1"/>
+ <pt x="422" y="-136" on="1"/>
+ <pt x="423" y="-154" on="1"/>
+ <pt x="428" y="-277" on="0"/>
+ <pt x="451" y="-314" on="1"/>
+ <pt x="478" y="-358" on="0"/>
+ <pt x="550" y="-358" on="1"/>
+ <pt x="700" y="-358" on="0"/>
+ <pt x="700" y="-185" on="1"/>
+ <pt x="700" y="-82" on="1"/>
+ <pt x="700" y="734" on="1"/>
+ <pt x="697" y="811" on="1"/>
+ <pt x="694" y="900" on="0"/>
+ <pt x="672" y="937" on="1"/>
+ <pt x="647" y="981" on="0"/>
+ <pt x="592" y="981" on="1"/>
+ <pt x="476" y="981" on="0"/>
+ <pt x="356" y="840" on="1"/>
+ <pt x="356" y="259" on="1"/>
+ <pt x="357" y="160" on="1"/>
+ <pt x="358" y="91" on="0"/>
+ <pt x="383" y="78" on="1"/>
+ <pt x="405" y="66" on="0"/>
+ <pt x="458" y="63" on="1"/>
+ <pt x="477" y="62" on="1"/>
+ <pt x="477" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 88 values pushed */
+ 0 0 46 29 21 37 11 28 48 84 21 1 55 49 48 41 26 25 17 14 8 7 1 11 15
+ 0 3 40 39 32 31 30 5 13 28 0 56 0 1 0 16 15 1 14 56 55 32 3 39 16
+ 3 15 14 1 0 4 13 7 0 0 41 40 39 4 2 25 49 48 17 16 4 3 7 2 4
+ 48 196 26 25 1 31 30 1 8 7 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eogonek" xMin="68" yMin="-370" xMax="848" yMax="1110">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="281" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="equal" xMin="84" yMin="358" xMax="1071" yMax="827">
+ <contour>
+ <pt x="84" y="358" on="1"/>
+ <pt x="84" y="456" on="1"/>
+ <pt x="1071" y="456" on="1"/>
+ <pt x="1071" y="358" on="1"/>
+ </contour>
+ <contour>
+ <pt x="84" y="728" on="1"/>
+ <pt x="84" y="827" on="1"/>
+ <pt x="1071" y="827" on="1"/>
+ <pt x="1071" y="728" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 33 values pushed */
+ 0 0 7 4 9 1 5 2 1 9 1 0 2 4 48 84 6 5 1 3 0 1 2 0 14
+ 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="estimated" xMin="68" yMin="-25" xMax="848" yMax="1110">
+ <contour>
+ <pt x="848" y="49" on="1"/>
+ <pt x="682" y="-25" on="0"/>
+ <pt x="542" y="-25" on="1"/>
+ <pt x="322" y="-25" on="0"/>
+ <pt x="195" y="124" on="1"/>
+ <pt x="68" y="273" on="0"/>
+ <pt x="68" y="536" on="1"/>
+ <pt x="68" y="796" on="0"/>
+ <pt x="185" y="953" on="1"/>
+ <pt x="301" y="1110" on="0"/>
+ <pt x="496" y="1110" on="1"/>
+ <pt x="677" y="1110" on="0"/>
+ <pt x="763" y="988" on="1"/>
+ <pt x="848" y="866" on="0"/>
+ <pt x="848" y="605" on="1"/>
+ <pt x="848" y="586" on="1"/>
+ <pt x="284" y="586" on="1"/>
+ <pt x="287" y="442" on="0"/>
+ <pt x="302" y="368" on="1"/>
+ <pt x="362" y="75" on="0"/>
+ <pt x="600" y="75" on="1"/>
+ <pt x="722" y="75" on="0"/>
+ <pt x="848" y="150" on="1"/>
+ </contour>
+ <contour>
+ <pt x="284" y="648" on="1"/>
+ <pt x="638" y="648" on="1"/>
+ <pt x="639" y="692" on="1"/>
+ <pt x="643" y="869" on="0"/>
+ <pt x="611" y="957" on="1"/>
+ <pt x="580" y="1043" on="0"/>
+ <pt x="486" y="1043" on="1"/>
+ <pt x="382" y="1043" on="0"/>
+ <pt x="325" y="901" on="1"/>
+ <pt x="286" y="803" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 0 0 29 17 10 20 9 2 48 84 10 1 2 2 14 23 15 2 1 22 0 2 15 2 3
+ 0 0 0 16 15 14 1 23 1 4 48 84 24 23 1 0 14 24 23 22 16 15 14 6 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eth" xMin="17" yMin="-25" xMax="962" yMax="1585">
+ <contour>
+ <pt x="597" y="1078" on="1"/>
+ <pt x="530" y="1184" on="0"/>
+ <pt x="399" y="1317" on="1"/>
+ <pt x="107" y="1119" on="1"/>
+ <pt x="71" y="1172" on="1"/>
+ <pt x="350" y="1357" on="1"/>
+ <pt x="193" y="1492" on="0"/>
+ <pt x="17" y="1507" on="1"/>
+ <pt x="17" y="1579" on="1"/>
+ <pt x="265" y="1579" on="0"/>
+ <pt x="479" y="1444" on="1"/>
+ <pt x="689" y="1585" on="1"/>
+ <pt x="724" y="1535" on="1"/>
+ <pt x="527" y="1404" on="1"/>
+ <pt x="646" y="1317" on="0"/>
+ <pt x="711" y="1248" on="1"/>
+ <pt x="962" y="979" on="0"/>
+ <pt x="962" y="586" on="1"/>
+ <pt x="962" y="298" on="0"/>
+ <pt x="843" y="137" on="1"/>
+ <pt x="725" y="-25" on="0"/>
+ <pt x="511" y="-25" on="1"/>
+ <pt x="307" y="-25" on="0"/>
+ <pt x="184" y="127" on="1"/>
+ <pt x="62" y="279" on="0"/>
+ <pt x="62" y="531" on="1"/>
+ <pt x="62" y="781" on="0"/>
+ <pt x="184" y="933" on="1"/>
+ <pt x="307" y="1086" on="0"/>
+ <pt x="503" y="1086" on="1"/>
+ <pt x="542" y="1086" on="0"/>
+ </contour>
+ <contour>
+ <pt x="511" y="1018" on="1"/>
+ <pt x="406" y="1018" on="0"/>
+ <pt x="342" y="884" on="1"/>
+ <pt x="277" y="750" on="0"/>
+ <pt x="277" y="531" on="1"/>
+ <pt x="277" y="311" on="0"/>
+ <pt x="342" y="177" on="1"/>
+ <pt x="406" y="43" on="0"/>
+ <pt x="512" y="43" on="1"/>
+ <pt x="617" y="43" on="0"/>
+ <pt x="681" y="176" on="1"/>
+ <pt x="746" y="310" on="0"/>
+ <pt x="746" y="525" on="1"/>
+ <pt x="746" y="729" on="0"/>
+ <pt x="693" y="859" on="1"/>
+ <pt x="628" y="1018" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 69 values pushed */
+ 0 0 39 17 21 31 17 29 48 84 29 1 21 2 1 1 13 10 5 4 3 2 6 0 1
+ 3 0 0 1 1 0 1 2 2 0 0 1 12 11 8 7 4 13 0 0 14 0 0 43 10
+ 17 35 10 25 48 196 25 17 13 12 11 10 8 7 5 4 3 2 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="exclam" xMin="242" yMin="0" xMax="439" yMax="1480">
+ <contour>
+ <pt x="242" y="0" on="1"/>
+ <pt x="242" y="197" on="1"/>
+ <pt x="439" y="197" on="1"/>
+ <pt x="439" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="310" y="395" on="1"/>
+ <pt x="242" y="1184" on="1"/>
+ <pt x="242" y="1480" on="1"/>
+ <pt x="439" y="1480" on="1"/>
+ <pt x="439" y="1184" on="1"/>
+ <pt x="372" y="395" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 9 8 5 4 4 6 1 3 0 0 2 1 5 1 0 1 4 48 84 3 0 1 0 7 6
+ 0 14 9 4 2 2 0 3 0 0 8 7 3 2 4 3 0 1 4 48 196 6 5 1 0
+ 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="exclamdown" xMin="242" yMin="-395" xMax="439" yMax="1086">
+ <contour>
+ <pt x="439" y="1086" on="1"/>
+ <pt x="439" y="888" on="1"/>
+ <pt x="242" y="888" on="1"/>
+ <pt x="242" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="372" y="691" on="1"/>
+ <pt x="439" y="-99" on="1"/>
+ <pt x="439" y="-395" on="1"/>
+ <pt x="242" y="-395" on="1"/>
+ <pt x="242" y="-99" on="1"/>
+ <pt x="310" y="691" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 1 9 4 2 1 2 3 0 1 8 5 2 2 6 3 0 0 0 2 1 5 1 0 1 4
+ 48 84 7 6 1 0 3 0 1 14 9 4 2 0 2 3 0 0 6 5 1 0 4 3 2
+ 1 4 48 196 8 7 3 2 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="f" xMin="37" yMin="0" xMax="719" yMax="1604">
+ <contour>
+ <pt x="55" y="0" on="1"/>
+ <pt x="55" y="62" on="1"/>
+ <pt x="74" y="63" on="1"/>
+ <pt x="151" y="68" on="0"/>
+ <pt x="163" y="92" on="1"/>
+ <pt x="174" y="112" on="0"/>
+ <pt x="174" y="160" on="1"/>
+ <pt x="176" y="259" on="1"/>
+ <pt x="176" y="999" on="1"/>
+ <pt x="37" y="999" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="176" y="1086" on="1"/>
+ <pt x="176" y="1138" on="1"/>
+ <pt x="176" y="1401" on="0"/>
+ <pt x="245" y="1502" on="1"/>
+ <pt x="314" y="1604" on="0"/>
+ <pt x="489" y="1604" on="1"/>
+ <pt x="617" y="1604" on="0"/>
+ <pt x="719" y="1530" on="1"/>
+ <pt x="719" y="1295" on="1"/>
+ <pt x="608" y="1295" on="1"/>
+ <pt x="607" y="1314" on="1"/>
+ <pt x="605" y="1353" on="0"/>
+ <pt x="604" y="1380" on="1"/>
+ <pt x="604" y="1385" on="1"/>
+ <pt x="604" y="1540" on="0"/>
+ <pt x="496" y="1540" on="1"/>
+ <pt x="376" y="1540" on="0"/>
+ <pt x="374" y="1357" on="1"/>
+ <pt x="373" y="1257" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="596" y="1086" on="1"/>
+ <pt x="596" y="1005" on="1"/>
+ <pt x="373" y="1005" on="1"/>
+ <pt x="373" y="259" on="1"/>
+ <pt x="375" y="160" on="1"/>
+ <pt x="376" y="88" on="0"/>
+ <pt x="408" y="75" on="1"/>
+ <pt x="434" y="63" on="0"/>
+ <pt x="500" y="63" on="1"/>
+ <pt x="544" y="62" on="1"/>
+ <pt x="544" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 95 values pushed */
+ 0 0 26 11 16 48 84 40 34 7 1 4 8 0 3 29 24 23 20 19 18 12 7 13 16
+ 10 0 0 33 32 7 1 10 1 4 9 8 1 10 1 6 48 84 41 0 1 0 31 30 11
+ 10 1 3 14 41 40 32 31 24 23 20 7 18 29 3 10 9 1 0 4 13 7 0 0 34
+ 33 30 29 4 3 7 1 4 48 196 19 18 1 12 11 8 7 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fi" xMin="37" yMin="0" xMax="1104" yMax="1604">
+ <contour>
+ <pt x="786" y="1283" on="1"/>
+ <pt x="786" y="1480" on="1"/>
+ <pt x="959" y="1480" on="1"/>
+ <pt x="959" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="55" y="0" on="1"/>
+ <pt x="55" y="62" on="1"/>
+ <pt x="74" y="63" on="1"/>
+ <pt x="151" y="68" on="0"/>
+ <pt x="163" y="92" on="1"/>
+ <pt x="174" y="112" on="0"/>
+ <pt x="174" y="160" on="1"/>
+ <pt x="176" y="259" on="1"/>
+ <pt x="176" y="999" on="1"/>
+ <pt x="37" y="999" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="176" y="1086" on="1"/>
+ <pt x="176" y="1138" on="1"/>
+ <pt x="176" y="1394" on="0"/>
+ <pt x="243" y="1499" on="1"/>
+ <pt x="311" y="1604" on="0"/>
+ <pt x="471" y="1604" on="1"/>
+ <pt x="585" y="1604" on="0"/>
+ <pt x="687" y="1530" on="1"/>
+ <pt x="687" y="1308" on="1"/>
+ <pt x="576" y="1308" on="1"/>
+ <pt x="575" y="1324" on="1"/>
+ <pt x="574" y="1357" on="0"/>
+ <pt x="573" y="1375" on="1"/>
+ <pt x="573" y="1383" on="0"/>
+ <pt x="573" y="1386" on="1"/>
+ <pt x="573" y="1540" on="0"/>
+ <pt x="480" y="1540" on="1"/>
+ <pt x="376" y="1540" on="0"/>
+ <pt x="374" y="1357" on="1"/>
+ <pt x="373" y="1257" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="959" y="1086" on="1"/>
+ <pt x="959" y="259" on="1"/>
+ <pt x="961" y="160" on="1"/>
+ <pt x="962" y="86" on="0"/>
+ <pt x="983" y="78" on="1"/>
+ <pt x="1003" y="68" on="0"/>
+ <pt x="1086" y="63" on="1"/>
+ <pt x="1104" y="62" on="1"/>
+ <pt x="1104" y="0" on="1"/>
+ <pt x="616" y="0" on="1"/>
+ <pt x="616" y="62" on="1"/>
+ <pt x="678" y="63" on="1"/>
+ <pt x="759" y="63" on="0"/>
+ <pt x="760" y="160" on="1"/>
+ <pt x="761" y="259" on="1"/>
+ <pt x="761" y="1005" on="1"/>
+ <pt x="373" y="1005" on="1"/>
+ <pt x="373" y="259" on="1"/>
+ <pt x="375" y="160" on="1"/>
+ <pt x="376" y="88" on="0"/>
+ <pt x="408" y="75" on="1"/>
+ <pt x="434" y="63" on="0"/>
+ <pt x="500" y="63" on="1"/>
+ <pt x="544" y="62" on="1"/>
+ <pt x="544" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 138 values pushed */
+ 0 0 31 11 20 48 84 49 45 24 23 2 1 0 3 34 16 2 0 14 3 59 53 50 43
+ 37 11 5 7 12 4 3 22 20 1 0 0 52 51 7 1 14 1 4 13 12 1 14 1 6
+ 3 0 5 1 1 1 4 48 84 60 45 44 4 3 0 36 35 15 14 1 3 2 1 0 14
+ 45 49 49 50 22 2 60 59 24 3 22 34 3 44 43 2 13 2 14 13 5 4 4 13 11
+ 0 0 51 50 4 1 2 53 52 35 34 4 3 11 1 0 13 1 2 3 4 48 196 23 22
+ 1 16 15 12 11 3 37 36 3 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fi#1" xMin="37" yMin="0" xMax="1104" yMax="1604">
+ <contour>
+ <pt x="786" y="1283" on="1"/>
+ <pt x="786" y="1480" on="1"/>
+ <pt x="959" y="1480" on="1"/>
+ <pt x="959" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="55" y="0" on="1"/>
+ <pt x="55" y="62" on="1"/>
+ <pt x="74" y="63" on="1"/>
+ <pt x="151" y="68" on="0"/>
+ <pt x="163" y="92" on="1"/>
+ <pt x="174" y="112" on="0"/>
+ <pt x="174" y="160" on="1"/>
+ <pt x="176" y="259" on="1"/>
+ <pt x="176" y="999" on="1"/>
+ <pt x="37" y="999" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="176" y="1086" on="1"/>
+ <pt x="176" y="1138" on="1"/>
+ <pt x="176" y="1394" on="0"/>
+ <pt x="243" y="1499" on="1"/>
+ <pt x="311" y="1604" on="0"/>
+ <pt x="471" y="1604" on="1"/>
+ <pt x="585" y="1604" on="0"/>
+ <pt x="687" y="1530" on="1"/>
+ <pt x="687" y="1308" on="1"/>
+ <pt x="576" y="1308" on="1"/>
+ <pt x="575" y="1324" on="1"/>
+ <pt x="574" y="1357" on="0"/>
+ <pt x="573" y="1375" on="1"/>
+ <pt x="573" y="1383" on="0"/>
+ <pt x="573" y="1386" on="1"/>
+ <pt x="573" y="1540" on="0"/>
+ <pt x="480" y="1540" on="1"/>
+ <pt x="376" y="1540" on="0"/>
+ <pt x="374" y="1357" on="1"/>
+ <pt x="373" y="1257" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="959" y="1086" on="1"/>
+ <pt x="959" y="259" on="1"/>
+ <pt x="961" y="160" on="1"/>
+ <pt x="962" y="86" on="0"/>
+ <pt x="983" y="78" on="1"/>
+ <pt x="1003" y="68" on="0"/>
+ <pt x="1086" y="63" on="1"/>
+ <pt x="1104" y="62" on="1"/>
+ <pt x="1104" y="0" on="1"/>
+ <pt x="616" y="0" on="1"/>
+ <pt x="616" y="62" on="1"/>
+ <pt x="678" y="63" on="1"/>
+ <pt x="759" y="63" on="0"/>
+ <pt x="760" y="160" on="1"/>
+ <pt x="761" y="259" on="1"/>
+ <pt x="761" y="1005" on="1"/>
+ <pt x="373" y="1005" on="1"/>
+ <pt x="373" y="259" on="1"/>
+ <pt x="375" y="160" on="1"/>
+ <pt x="376" y="88" on="0"/>
+ <pt x="408" y="75" on="1"/>
+ <pt x="434" y="63" on="0"/>
+ <pt x="500" y="63" on="1"/>
+ <pt x="544" y="62" on="1"/>
+ <pt x="544" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 138 values pushed */
+ 0 0 31 11 20 48 84 49 45 24 23 2 1 0 3 34 16 2 0 14 3 59 53 50 43
+ 37 11 5 7 12 4 3 22 20 1 0 0 52 51 7 1 14 1 4 13 12 1 14 1 6
+ 3 0 5 1 1 1 4 48 84 60 45 44 4 3 0 36 35 15 14 1 3 2 1 0 14
+ 45 49 49 50 22 2 60 59 24 3 22 34 3 44 43 2 13 2 14 13 5 4 4 13 11
+ 0 0 51 50 4 1 2 53 52 35 34 4 3 11 1 0 13 1 2 3 4 48 196 23 22
+ 1 16 15 12 11 3 37 36 3 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="figuredash" xMin="86" yMin="543" xMax="937" yMax="666">
+ <contour>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="666" on="1"/>
+ <pt x="937" y="666" on="1"/>
+ <pt x="937" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="five" xMin="130" yMin="-37" xMax="907" yMax="1480">
+ <contour>
+ <pt x="130" y="-3" on="1"/>
+ <pt x="130" y="247" on="1"/>
+ <pt x="229" y="247" on="1"/>
+ <pt x="230" y="223" on="1"/>
+ <pt x="232" y="147" on="1"/>
+ <pt x="235" y="25" on="0"/>
+ <pt x="406" y="25" on="1"/>
+ <pt x="541" y="25" on="0"/>
+ <pt x="619" y="134" on="1"/>
+ <pt x="697" y="244" on="0"/>
+ <pt x="697" y="421" on="1"/>
+ <pt x="697" y="820" on="0"/>
+ <pt x="192" y="820" on="1"/>
+ <pt x="155" y="820" on="1"/>
+ <pt x="155" y="1480" on="1"/>
+ <pt x="876" y="1480" on="1"/>
+ <pt x="876" y="1308" on="1"/>
+ <pt x="216" y="1308" on="1"/>
+ <pt x="216" y="894" on="1"/>
+ <pt x="308" y="894" on="1"/>
+ <pt x="592" y="894" on="0"/>
+ <pt x="749" y="769" on="1"/>
+ <pt x="907" y="644" on="0"/>
+ <pt x="907" y="420" on="1"/>
+ <pt x="907" y="210" on="0"/>
+ <pt x="764" y="87" on="1"/>
+ <pt x="621" y="-37" on="0"/>
+ <pt x="384" y="-37" on="1"/>
+ <pt x="270" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 6 11 27 48 84 27 2 1 19 18 13 12 2 1 6 16 2 3 0 1 0 2 0
+ 0 0 17 16 13 1 14 1 4 48 84 15 14 0 14 0 0 10 10 23 48 196 19 2 2
+ 15 17 3 12 17 13 2 23 15 0 0 18 17 11 1 13 1 4 48 196 16 15 1 14 13
+ 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fl" xMin="37" yMin="0" xMax="1104" yMax="1604">
+ <contour>
+ <pt x="55" y="0" on="1"/>
+ <pt x="55" y="62" on="1"/>
+ <pt x="74" y="63" on="1"/>
+ <pt x="151" y="68" on="0"/>
+ <pt x="163" y="92" on="1"/>
+ <pt x="174" y="112" on="0"/>
+ <pt x="174" y="160" on="1"/>
+ <pt x="176" y="259" on="1"/>
+ <pt x="176" y="999" on="1"/>
+ <pt x="37" y="999" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="176" y="1086" on="1"/>
+ <pt x="176" y="1138" on="1"/>
+ <pt x="176" y="1313" on="0"/>
+ <pt x="192" y="1384" on="1"/>
+ <pt x="208" y="1457" on="0"/>
+ <pt x="260" y="1514" on="1"/>
+ <pt x="342" y="1604" on="0"/>
+ <pt x="468" y="1604" on="1"/>
+ <pt x="518" y="1604" on="0"/>
+ <pt x="632" y="1579" on="1"/>
+ <pt x="959" y="1579" on="1"/>
+ <pt x="959" y="259" on="1"/>
+ <pt x="961" y="160" on="1"/>
+ <pt x="962" y="86" on="0"/>
+ <pt x="983" y="78" on="1"/>
+ <pt x="1003" y="68" on="0"/>
+ <pt x="1086" y="63" on="1"/>
+ <pt x="1104" y="62" on="1"/>
+ <pt x="1104" y="0" on="1"/>
+ <pt x="616" y="0" on="1"/>
+ <pt x="616" y="62" on="1"/>
+ <pt x="678" y="63" on="1"/>
+ <pt x="759" y="63" on="0"/>
+ <pt x="760" y="160" on="1"/>
+ <pt x="761" y="259" on="1"/>
+ <pt x="761" y="1437" on="1"/>
+ <pt x="604" y="1540" on="0"/>
+ <pt x="486" y="1540" on="1"/>
+ <pt x="376" y="1540" on="0"/>
+ <pt x="374" y="1357" on="1"/>
+ <pt x="373" y="1257" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="546" y="1086" on="1"/>
+ <pt x="546" y="1005" on="1"/>
+ <pt x="373" y="1005" on="1"/>
+ <pt x="373" y="259" on="1"/>
+ <pt x="375" y="160" on="1"/>
+ <pt x="376" y="88" on="0"/>
+ <pt x="408" y="75" on="1"/>
+ <pt x="434" y="63" on="0"/>
+ <pt x="500" y="63" on="1"/>
+ <pt x="544" y="62" on="1"/>
+ <pt x="544" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 115 values pushed */
+ 0 0 38 11 18 48 84 34 30 41 36 12 3 20 10 3 52 46 35 28 22 7 1 7 8
+ 0 3 18 20 0 0 45 44 7 1 10 1 4 9 8 1 10 1 6 48 84 21 20 1 53
+ 30 29 0 3 2 0 43 42 11 10 1 3 14 30 34 53 52 44 43 34 20 6 35 41 3
+ 29 28 2 13 21 10 9 1 0 4 13 7 0 0 36 35 4 1 21 46 45 42 41 4 3
+ 7 2 4 48 196 22 21 1 12 11 8 7 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fl#1" xMin="37" yMin="0" xMax="1104" yMax="1604">
+ <contour>
+ <pt x="55" y="0" on="1"/>
+ <pt x="55" y="62" on="1"/>
+ <pt x="74" y="63" on="1"/>
+ <pt x="151" y="68" on="0"/>
+ <pt x="163" y="92" on="1"/>
+ <pt x="174" y="112" on="0"/>
+ <pt x="174" y="160" on="1"/>
+ <pt x="176" y="259" on="1"/>
+ <pt x="176" y="999" on="1"/>
+ <pt x="37" y="999" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="176" y="1086" on="1"/>
+ <pt x="176" y="1138" on="1"/>
+ <pt x="176" y="1313" on="0"/>
+ <pt x="192" y="1384" on="1"/>
+ <pt x="208" y="1457" on="0"/>
+ <pt x="260" y="1514" on="1"/>
+ <pt x="342" y="1604" on="0"/>
+ <pt x="468" y="1604" on="1"/>
+ <pt x="518" y="1604" on="0"/>
+ <pt x="632" y="1579" on="1"/>
+ <pt x="959" y="1579" on="1"/>
+ <pt x="959" y="259" on="1"/>
+ <pt x="961" y="160" on="1"/>
+ <pt x="962" y="86" on="0"/>
+ <pt x="983" y="78" on="1"/>
+ <pt x="1003" y="68" on="0"/>
+ <pt x="1086" y="63" on="1"/>
+ <pt x="1104" y="62" on="1"/>
+ <pt x="1104" y="0" on="1"/>
+ <pt x="616" y="0" on="1"/>
+ <pt x="616" y="62" on="1"/>
+ <pt x="678" y="63" on="1"/>
+ <pt x="759" y="63" on="0"/>
+ <pt x="760" y="160" on="1"/>
+ <pt x="761" y="259" on="1"/>
+ <pt x="761" y="1437" on="1"/>
+ <pt x="604" y="1540" on="0"/>
+ <pt x="486" y="1540" on="1"/>
+ <pt x="376" y="1540" on="0"/>
+ <pt x="374" y="1357" on="1"/>
+ <pt x="373" y="1257" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="546" y="1086" on="1"/>
+ <pt x="546" y="1005" on="1"/>
+ <pt x="373" y="1005" on="1"/>
+ <pt x="373" y="259" on="1"/>
+ <pt x="375" y="160" on="1"/>
+ <pt x="376" y="88" on="0"/>
+ <pt x="408" y="75" on="1"/>
+ <pt x="434" y="63" on="0"/>
+ <pt x="500" y="63" on="1"/>
+ <pt x="544" y="62" on="1"/>
+ <pt x="544" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 115 values pushed */
+ 0 0 38 11 18 48 84 34 30 41 36 12 3 20 10 3 52 46 35 28 22 7 1 7 8
+ 0 3 18 20 0 0 45 44 7 1 10 1 4 9 8 1 10 1 6 48 84 21 20 1 53
+ 30 29 0 3 2 0 43 42 11 10 1 3 14 30 34 53 52 44 43 34 20 6 35 41 3
+ 29 28 2 13 21 10 9 1 0 4 13 7 0 0 36 35 4 1 21 46 45 42 41 4 3
+ 7 2 4 48 196 22 21 1 12 11 8 7 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="florin" xMin="12" yMin="-296" xMax="949" yMax="1505">
+ <contour>
+ <pt x="12" y="-296" on="1"/>
+ <pt x="218" y="740" on="1"/>
+ <pt x="16" y="740" on="1"/>
+ <pt x="16" y="802" on="1"/>
+ <pt x="230" y="802" on="1"/>
+ <pt x="254" y="922" on="1"/>
+ <pt x="308" y="1196" on="0"/>
+ <pt x="446" y="1351" on="1"/>
+ <pt x="583" y="1505" on="0"/>
+ <pt x="772" y="1505" on="1"/>
+ <pt x="852" y="1505" on="0"/>
+ <pt x="949" y="1475" on="1"/>
+ <pt x="949" y="1246" on="1"/>
+ <pt x="851" y="1246" on="1"/>
+ <pt x="848" y="1293" on="0"/>
+ <pt x="847" y="1320" on="1"/>
+ <pt x="842" y="1444" on="0"/>
+ <pt x="723" y="1444" on="1"/>
+ <pt x="605" y="1444" on="0"/>
+ <pt x="552" y="1316" on="1"/>
+ <pt x="509" y="1212" on="0"/>
+ <pt x="463" y="979" on="1"/>
+ <pt x="428" y="802" on="1"/>
+ <pt x="678" y="802" on="1"/>
+ <pt x="678" y="740" on="1"/>
+ <pt x="415" y="740" on="1"/>
+ <pt x="209" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 0 0 17 11 9 48 84 9 0 1 13 12 11 3 0 3 3 0 0 0 25 24 2 1 14
+ 3 3 1 4 48 84 23 22 4 3 3 26 0 1 2 0 14 26 25 24 23 22 13 4 3
+ 2 1 0 11 13 11 12 11 1 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="25" yMin="0" xMax="975" yMax="1505">
+ <contour>
+ <pt x="630" y="419" on="1"/>
+ <pt x="25" y="419" on="1"/>
+ <pt x="25" y="518" on="1"/>
+ <pt x="692" y="1505" on="1"/>
+ <pt x="803" y="1505" on="1"/>
+ <pt x="803" y="568" on="1"/>
+ <pt x="975" y="568" on="1"/>
+ <pt x="975" y="419" on="1"/>
+ <pt x="803" y="419" on="1"/>
+ <pt x="803" y="259" on="1"/>
+ <pt x="809" y="160" on="1"/>
+ <pt x="813" y="94" on="0"/>
+ <pt x="834" y="84" on="1"/>
+ <pt x="852" y="73" on="0"/>
+ <pt x="901" y="68" on="1"/>
+ <pt x="944" y="63" on="1"/>
+ <pt x="963" y="62" on="1"/>
+ <pt x="963" y="0" on="1"/>
+ <pt x="445" y="0" on="1"/>
+ <pt x="445" y="62" on="1"/>
+ <pt x="463" y="63" on="1"/>
+ <pt x="542" y="68" on="1"/>
+ <pt x="605" y="73" on="0"/>
+ <pt x="618" y="124" on="1"/>
+ <pt x="630" y="166" on="0"/>
+ <pt x="630" y="259" on="1"/>
+ </contour>
+ <contour>
+ <pt x="136" y="568" on="1"/>
+ <pt x="630" y="568" on="1"/>
+ <pt x="630" y="1299" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 25 18 2 5 0 2 16 9 2 0 17 3 28 4 3 3 13 5 0 0 27 26 6 5 19
+ 3 0 1 4 48 84 8 7 1 0 3 18 17 1 2 0 14 18 25 17 16 2 6 4 3
+ 3 4 0 2 26 2 1 3 13 0 0 0 28 27 25 0 13 3 4 1 4 48 196 7 6
+ 1 9 8 5 4 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="foursuperiour" xMin="31" yMin="772" xMax="582" yMax="1522">
+ <contour>
+ <pt x="284" y="772" on="1"/>
+ <pt x="284" y="810" on="1"/>
+ <pt x="293" y="811" on="1"/>
+ <pt x="343" y="812" on="0"/>
+ <pt x="357" y="819" on="1"/>
+ <pt x="372" y="828" on="0"/>
+ <pt x="374" y="859" on="1"/>
+ <pt x="377" y="909" on="1"/>
+ <pt x="377" y="977" on="1"/>
+ <pt x="31" y="977" on="1"/>
+ <pt x="31" y="1043" on="1"/>
+ <pt x="399" y="1522" on="1"/>
+ <pt x="490" y="1522" on="1"/>
+ <pt x="490" y="1066" on="1"/>
+ <pt x="582" y="1066" on="1"/>
+ <pt x="582" y="977" on="1"/>
+ <pt x="490" y="977" on="1"/>
+ <pt x="490" y="909" on="1"/>
+ <pt x="493" y="859" on="1"/>
+ <pt x="495" y="824" on="0"/>
+ <pt x="515" y="817" on="1"/>
+ <pt x="531" y="812" on="0"/>
+ <pt x="567" y="811" on="1"/>
+ <pt x="576" y="810" on="1"/>
+ <pt x="576" y="772" on="1"/>
+ </contour>
+ <contour>
+ <pt x="97" y="1066" on="1"/>
+ <pt x="377" y="1066" on="1"/>
+ <pt x="377" y="1429" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 10 13 8 2 23 17 7 1 4 8 0 3 27 12 11 3 13 13 0 0 16 15 9 8 46
+ 3 13 1 4 48 84 26 25 14 13 3 24 0 1 2 0 14 11 12 7 2 24 23 15 14
+ 4 13 12 25 10 9 1 0 5 13 7 0 0 27 26 8 7 15 3 12 1 4 48 196 17
+ 16 13 12 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fraction" xMin="-416" yMin="-37" xMax="759" yMax="1517">
+ <contour>
+ <pt x="-416" y="-37" on="1"/>
+ <pt x="672" y="1517" on="1"/>
+ <pt x="759" y="1517" on="1"/>
+ <pt x="-330" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 9 values pushed */
+ 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fraction#1" xMin="-416" yMin="-37" xMax="759" yMax="1517">
+ <contour>
+ <pt x="-416" y="-37" on="1"/>
+ <pt x="672" y="1517" on="1"/>
+ <pt x="759" y="1517" on="1"/>
+ <pt x="-330" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 9 values pushed */
+ 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="g" xMin="53" yMin="-419" xMax="991" yMax="1110">
+ <contour>
+ <pt x="258" y="42" on="1"/>
+ <pt x="145" y="96" on="0"/>
+ <pt x="145" y="182" on="1"/>
+ <pt x="145" y="266" on="0"/>
+ <pt x="300" y="367" on="1"/>
+ <pt x="326" y="384" on="1"/>
+ <pt x="231" y="432" on="0"/>
+ <pt x="183" y="497" on="1"/>
+ <pt x="114" y="589" on="0"/>
+ <pt x="114" y="732" on="1"/>
+ <pt x="114" y="908" on="0"/>
+ <pt x="209" y="1009" on="1"/>
+ <pt x="303" y="1110" on="0"/>
+ <pt x="462" y="1110" on="1"/>
+ <pt x="539" y="1110" on="0"/>
+ <pt x="640" y="1070" on="1"/>
+ <pt x="991" y="1098" on="1"/>
+ <pt x="940" y="978" on="1"/>
+ <pt x="702" y="1020" on="1"/>
+ <pt x="830" y="889" on="0"/>
+ <pt x="830" y="731" on="1"/>
+ <pt x="830" y="569" on="0"/>
+ <pt x="728" y="456" on="1"/>
+ <pt x="626" y="342" on="0"/>
+ <pt x="481" y="342" on="1"/>
+ <pt x="437" y="342" on="0"/>
+ <pt x="394" y="360" on="1"/>
+ <pt x="318" y="298" on="0"/>
+ <pt x="318" y="243" on="1"/>
+ <pt x="318" y="195" on="0"/>
+ <pt x="369" y="183" on="1"/>
+ <pt x="410" y="173" on="0"/>
+ <pt x="499" y="173" on="1"/>
+ <pt x="561" y="173" on="1"/>
+ <pt x="757" y="173" on="0"/>
+ <pt x="845" y="114" on="1"/>
+ <pt x="933" y="55" on="0"/>
+ <pt x="933" y="-73" on="1"/>
+ <pt x="933" y="-225" on="0"/>
+ <pt x="795" y="-322" on="1"/>
+ <pt x="658" y="-419" on="0"/>
+ <pt x="446" y="-419" on="1"/>
+ <pt x="269" y="-419" on="0"/>
+ <pt x="161" y="-354" on="1"/>
+ <pt x="53" y="-289" on="0"/>
+ <pt x="53" y="-183" on="1"/>
+ <pt x="53" y="-51" on="0"/>
+ </contour>
+ <contour>
+ <pt x="472" y="1043" on="1"/>
+ <pt x="312" y="1043" on="0"/>
+ <pt x="312" y="731" on="1"/>
+ <pt x="312" y="410" on="0"/>
+ <pt x="472" y="410" on="1"/>
+ <pt x="633" y="410" on="0"/>
+ <pt x="633" y="725" on="1"/>
+ <pt x="633" y="1043" on="0"/>
+ </contour>
+ <contour>
+ <pt x="310" y="25" on="1"/>
+ <pt x="248" y="-38" on="0"/>
+ <pt x="248" y="-144" on="1"/>
+ <pt x="248" y="-238" on="0"/>
+ <pt x="313" y="-295" on="1"/>
+ <pt x="379" y="-352" on="0"/>
+ <pt x="480" y="-352" on="1"/>
+ <pt x="589" y="-352" on="0"/>
+ <pt x="665" y="-284" on="1"/>
+ <pt x="741" y="-217" on="0"/>
+ <pt x="741" y="-123" on="1"/>
+ <pt x="741" y="25" on="0"/>
+ <pt x="541" y="25" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 61 17 41 51 17 24 47 17 13 48 84 13 1 24 1 33 32 26 24 18 17 15 5
+ 0 9 1 55 3 0 1 16 1 0 41 55 67 55 1 0 14 0 0 65 30 37 57 30 45
+ 53 5 20 49 5 9 48 196 67 55 45 37 33 32 28 26 20 18 17 16 15 9 5 2 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gbreve" xMin="53" yMin="-419" xMax="991" yMax="1604">
+ <component glyphName="g" x="0" y="0" flags="0x4"/>
+ <component glyphName="breve" x="127" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="gcircumflex" xMin="53" yMin="-419" xMax="991" yMax="1604">
+ <contour>
+ <pt x="258" y="42" on="1"/>
+ <pt x="145" y="96" on="0"/>
+ <pt x="145" y="182" on="1"/>
+ <pt x="145" y="266" on="0"/>
+ <pt x="300" y="367" on="1"/>
+ <pt x="326" y="384" on="1"/>
+ <pt x="231" y="432" on="0"/>
+ <pt x="183" y="497" on="1"/>
+ <pt x="114" y="589" on="0"/>
+ <pt x="114" y="732" on="1"/>
+ <pt x="114" y="908" on="0"/>
+ <pt x="209" y="1009" on="1"/>
+ <pt x="303" y="1110" on="0"/>
+ <pt x="462" y="1110" on="1"/>
+ <pt x="539" y="1110" on="0"/>
+ <pt x="640" y="1070" on="1"/>
+ <pt x="991" y="1098" on="1"/>
+ <pt x="940" y="978" on="1"/>
+ <pt x="702" y="1020" on="1"/>
+ <pt x="830" y="889" on="0"/>
+ <pt x="830" y="731" on="1"/>
+ <pt x="830" y="569" on="0"/>
+ <pt x="728" y="456" on="1"/>
+ <pt x="626" y="342" on="0"/>
+ <pt x="481" y="342" on="1"/>
+ <pt x="437" y="342" on="0"/>
+ <pt x="394" y="360" on="1"/>
+ <pt x="318" y="298" on="0"/>
+ <pt x="318" y="243" on="1"/>
+ <pt x="318" y="195" on="0"/>
+ <pt x="369" y="183" on="1"/>
+ <pt x="410" y="173" on="0"/>
+ <pt x="499" y="173" on="1"/>
+ <pt x="561" y="173" on="1"/>
+ <pt x="757" y="173" on="0"/>
+ <pt x="845" y="114" on="1"/>
+ <pt x="933" y="55" on="0"/>
+ <pt x="933" y="-73" on="1"/>
+ <pt x="933" y="-225" on="0"/>
+ <pt x="795" y="-322" on="1"/>
+ <pt x="658" y="-419" on="0"/>
+ <pt x="446" y="-419" on="1"/>
+ <pt x="269" y="-419" on="0"/>
+ <pt x="161" y="-354" on="1"/>
+ <pt x="53" y="-289" on="0"/>
+ <pt x="53" y="-183" on="1"/>
+ <pt x="53" y="-51" on="0"/>
+ </contour>
+ <contour>
+ <pt x="472" y="1043" on="1"/>
+ <pt x="312" y="1043" on="0"/>
+ <pt x="312" y="731" on="1"/>
+ <pt x="312" y="410" on="0"/>
+ <pt x="472" y="410" on="1"/>
+ <pt x="633" y="410" on="0"/>
+ <pt x="633" y="725" on="1"/>
+ <pt x="633" y="1043" on="0"/>
+ </contour>
+ <contour>
+ <pt x="310" y="25" on="1"/>
+ <pt x="248" y="-38" on="0"/>
+ <pt x="248" y="-144" on="1"/>
+ <pt x="248" y="-238" on="0"/>
+ <pt x="313" y="-295" on="1"/>
+ <pt x="379" y="-352" on="0"/>
+ <pt x="480" y="-352" on="1"/>
+ <pt x="589" y="-352" on="0"/>
+ <pt x="665" y="-284" on="1"/>
+ <pt x="741" y="-217" on="0"/>
+ <pt x="741" y="-123" on="1"/>
+ <pt x="741" y="25" on="0"/>
+ <pt x="541" y="25" on="1"/>
+ </contour>
+ <contour>
+ <pt x="141" y="1283" on="1"/>
+ <pt x="382" y="1604" on="1"/>
+ <pt x="604" y="1604" on="1"/>
+ <pt x="844" y="1283" on="1"/>
+ <pt x="758" y="1283" on="1"/>
+ <pt x="493" y="1505" on="1"/>
+ <pt x="227" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 101 values pushed */
+ 0 0 61 17 41 51 17 24 47 17 13 48 84 13 1 1 73 69 0 2 0 1 1 74 72
+ 71 68 16 5 0 1 3 0 0 24 1 33 32 26 24 18 17 15 5 0 9 1 55 3 0
+ 41 55 70 69 1 67 55 1 2 0 14 0 0 65 30 37 57 30 45 53 5 20 49 5 9
+ 48 196 74 73 72 71 70 69 68 67 55 45 37 33 32 28 26 20 18 17 16 15 9 5 2
+ 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gcommaaccent" xMin="53" yMin="-419" xMax="991" yMax="1737">
+ <contour>
+ <pt x="258" y="42" on="1"/>
+ <pt x="145" y="96" on="0"/>
+ <pt x="145" y="182" on="1"/>
+ <pt x="145" y="266" on="0"/>
+ <pt x="300" y="367" on="1"/>
+ <pt x="326" y="384" on="1"/>
+ <pt x="231" y="432" on="0"/>
+ <pt x="183" y="497" on="1"/>
+ <pt x="114" y="589" on="0"/>
+ <pt x="114" y="732" on="1"/>
+ <pt x="114" y="908" on="0"/>
+ <pt x="209" y="1009" on="1"/>
+ <pt x="303" y="1110" on="0"/>
+ <pt x="462" y="1110" on="1"/>
+ <pt x="539" y="1110" on="0"/>
+ <pt x="640" y="1070" on="1"/>
+ <pt x="991" y="1098" on="1"/>
+ <pt x="940" y="978" on="1"/>
+ <pt x="702" y="1020" on="1"/>
+ <pt x="830" y="889" on="0"/>
+ <pt x="830" y="731" on="1"/>
+ <pt x="830" y="569" on="0"/>
+ <pt x="728" y="456" on="1"/>
+ <pt x="626" y="342" on="0"/>
+ <pt x="481" y="342" on="1"/>
+ <pt x="437" y="342" on="0"/>
+ <pt x="394" y="360" on="1"/>
+ <pt x="318" y="298" on="0"/>
+ <pt x="318" y="243" on="1"/>
+ <pt x="318" y="195" on="0"/>
+ <pt x="369" y="183" on="1"/>
+ <pt x="410" y="173" on="0"/>
+ <pt x="499" y="173" on="1"/>
+ <pt x="561" y="173" on="1"/>
+ <pt x="757" y="173" on="0"/>
+ <pt x="845" y="114" on="1"/>
+ <pt x="933" y="55" on="0"/>
+ <pt x="933" y="-73" on="1"/>
+ <pt x="933" y="-225" on="0"/>
+ <pt x="795" y="-322" on="1"/>
+ <pt x="658" y="-419" on="0"/>
+ <pt x="446" y="-419" on="1"/>
+ <pt x="269" y="-419" on="0"/>
+ <pt x="161" y="-354" on="1"/>
+ <pt x="53" y="-289" on="0"/>
+ <pt x="53" y="-183" on="1"/>
+ <pt x="53" y="-51" on="0"/>
+ </contour>
+ <contour>
+ <pt x="472" y="1043" on="1"/>
+ <pt x="312" y="1043" on="0"/>
+ <pt x="312" y="731" on="1"/>
+ <pt x="312" y="410" on="0"/>
+ <pt x="472" y="410" on="1"/>
+ <pt x="633" y="410" on="0"/>
+ <pt x="633" y="725" on="1"/>
+ <pt x="633" y="1043" on="0"/>
+ </contour>
+ <contour>
+ <pt x="310" y="25" on="1"/>
+ <pt x="248" y="-38" on="0"/>
+ <pt x="248" y="-144" on="1"/>
+ <pt x="248" y="-238" on="0"/>
+ <pt x="313" y="-295" on="1"/>
+ <pt x="379" y="-352" on="0"/>
+ <pt x="480" y="-352" on="1"/>
+ <pt x="589" y="-352" on="0"/>
+ <pt x="665" y="-284" on="1"/>
+ <pt x="741" y="-217" on="0"/>
+ <pt x="741" y="-123" on="1"/>
+ <pt x="741" y="25" on="0"/>
+ <pt x="541" y="25" on="1"/>
+ </contour>
+ <contour>
+ <pt x="487" y="1480" on="1"/>
+ <pt x="566" y="1480" on="1"/>
+ <pt x="566" y="1283" on="1"/>
+ <pt x="369" y="1283" on="1"/>
+ <pt x="369" y="1455" on="1"/>
+ <pt x="369" y="1616" on="0"/>
+ <pt x="431" y="1682" on="1"/>
+ <pt x="478" y="1732" on="0"/>
+ <pt x="566" y="1737" on="1"/>
+ <pt x="566" y="1688" on="1"/>
+ <pt x="487" y="1681" on="0"/>
+ <pt x="487" y="1532" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 121 values pushed */
+ 0 0 61 17 41 51 17 24 47 17 13 48 84 13 1 1 16 70 1 2 0 24 1 33 32
+ 26 24 18 17 15 5 0 9 1 55 3 0 79 77 76 72 69 68 6 13 70 41 55 71 70
+ 1 67 55 1 2 0 14 0 0 65 30 37 57 30 45 53 5 20 49 5 9 48 196 79 68
+ 67 33 32 26 6 69 71 3 18 17 16 15 4 13 37 20 69 55 5 0 3 13 45 28 9
+ 2 4 12 71 0 0 77 76 70 69 4 3 71 1 4 48 196 72 71 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gdotaccent" xMin="53" yMin="-419" xMax="991" yMax="1480">
+ <contour>
+ <pt x="258" y="42" on="1"/>
+ <pt x="145" y="96" on="0"/>
+ <pt x="145" y="182" on="1"/>
+ <pt x="145" y="266" on="0"/>
+ <pt x="300" y="367" on="1"/>
+ <pt x="326" y="384" on="1"/>
+ <pt x="231" y="432" on="0"/>
+ <pt x="183" y="497" on="1"/>
+ <pt x="114" y="589" on="0"/>
+ <pt x="114" y="732" on="1"/>
+ <pt x="114" y="908" on="0"/>
+ <pt x="209" y="1009" on="1"/>
+ <pt x="303" y="1110" on="0"/>
+ <pt x="462" y="1110" on="1"/>
+ <pt x="539" y="1110" on="0"/>
+ <pt x="640" y="1070" on="1"/>
+ <pt x="991" y="1098" on="1"/>
+ <pt x="940" y="978" on="1"/>
+ <pt x="702" y="1020" on="1"/>
+ <pt x="830" y="889" on="0"/>
+ <pt x="830" y="731" on="1"/>
+ <pt x="830" y="569" on="0"/>
+ <pt x="728" y="456" on="1"/>
+ <pt x="626" y="342" on="0"/>
+ <pt x="481" y="342" on="1"/>
+ <pt x="437" y="342" on="0"/>
+ <pt x="394" y="360" on="1"/>
+ <pt x="318" y="298" on="0"/>
+ <pt x="318" y="243" on="1"/>
+ <pt x="318" y="195" on="0"/>
+ <pt x="369" y="183" on="1"/>
+ <pt x="410" y="173" on="0"/>
+ <pt x="499" y="173" on="1"/>
+ <pt x="561" y="173" on="1"/>
+ <pt x="757" y="173" on="0"/>
+ <pt x="845" y="114" on="1"/>
+ <pt x="933" y="55" on="0"/>
+ <pt x="933" y="-73" on="1"/>
+ <pt x="933" y="-225" on="0"/>
+ <pt x="795" y="-322" on="1"/>
+ <pt x="658" y="-419" on="0"/>
+ <pt x="446" y="-419" on="1"/>
+ <pt x="269" y="-419" on="0"/>
+ <pt x="161" y="-354" on="1"/>
+ <pt x="53" y="-289" on="0"/>
+ <pt x="53" y="-183" on="1"/>
+ <pt x="53" y="-51" on="0"/>
+ </contour>
+ <contour>
+ <pt x="472" y="1043" on="1"/>
+ <pt x="312" y="1043" on="0"/>
+ <pt x="312" y="731" on="1"/>
+ <pt x="312" y="410" on="0"/>
+ <pt x="472" y="410" on="1"/>
+ <pt x="633" y="410" on="0"/>
+ <pt x="633" y="725" on="1"/>
+ <pt x="633" y="1043" on="0"/>
+ </contour>
+ <contour>
+ <pt x="310" y="25" on="1"/>
+ <pt x="248" y="-38" on="0"/>
+ <pt x="248" y="-144" on="1"/>
+ <pt x="248" y="-238" on="0"/>
+ <pt x="313" y="-295" on="1"/>
+ <pt x="379" y="-352" on="0"/>
+ <pt x="480" y="-352" on="1"/>
+ <pt x="589" y="-352" on="0"/>
+ <pt x="665" y="-284" on="1"/>
+ <pt x="741" y="-217" on="0"/>
+ <pt x="741" y="-123" on="1"/>
+ <pt x="741" y="25" on="0"/>
+ <pt x="541" y="25" on="1"/>
+ </contour>
+ <contour>
+ <pt x="369" y="1283" on="1"/>
+ <pt x="369" y="1480" on="1"/>
+ <pt x="566" y="1480" on="1"/>
+ <pt x="566" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 120 values pushed */
+ 0 0 61 17 41 51 17 24 47 17 13 48 84 13 1 1 16 68 1 2 0 24 1 33 32
+ 26 24 18 17 15 5 0 9 1 55 3 0 1 41 2 0 0 0 71 68 5 1 69 1 4
+ 48 84 67 55 1 0 70 69 0 14 0 0 65 30 37 57 30 45 53 5 20 49 5 9 48
+ 196 67 33 32 26 4 70 68 3 18 17 16 15 4 13 37 20 70 55 5 0 3 13 45 28
+ 9 2 4 12 68 0 0 71 70 4 1 68 1 4 48 196 69 68 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="germandbls" xMin="27" yMin="-25" xMax="993" yMax="1604">
+ <contour>
+ <pt x="530" y="4" on="1"/>
+ <pt x="530" y="228" on="1"/>
+ <pt x="617" y="228" on="1"/>
+ <pt x="618" y="210" on="1"/>
+ <pt x="622" y="139" on="1"/>
+ <pt x="628" y="36" on="0"/>
+ <pt x="712" y="36" on="1"/>
+ <pt x="765" y="36" on="0"/>
+ <pt x="799" y="84" on="1"/>
+ <pt x="833" y="133" on="0"/>
+ <pt x="833" y="204" on="1"/>
+ <pt x="833" y="313" on="0"/>
+ <pt x="712" y="451" on="1"/>
+ <pt x="597" y="582" on="1"/>
+ <pt x="451" y="749" on="0"/>
+ <pt x="451" y="835" on="1"/>
+ <pt x="451" y="911" on="0"/>
+ <pt x="535" y="1017" on="1"/>
+ <pt x="562" y="1051" on="1"/>
+ <pt x="641" y="1151" on="0"/>
+ <pt x="641" y="1304" on="1"/>
+ <pt x="641" y="1542" on="0"/>
+ <pt x="490" y="1542" on="1"/>
+ <pt x="391" y="1542" on="0"/>
+ <pt x="365" y="1445" on="1"/>
+ <pt x="345" y="1371" on="0"/>
+ <pt x="345" y="1216" on="1"/>
+ <pt x="345" y="259" on="1"/>
+ <pt x="350" y="159" on="1"/>
+ <pt x="351" y="96" on="0"/>
+ <pt x="370" y="80" on="1"/>
+ <pt x="389" y="66" on="0"/>
+ <pt x="438" y="63" on="1"/>
+ <pt x="456" y="62" on="1"/>
+ <pt x="456" y="0" on="1"/>
+ <pt x="27" y="0" on="1"/>
+ <pt x="27" y="62" on="1"/>
+ <pt x="45" y="63" on="1"/>
+ <pt x="120" y="67" on="0"/>
+ <pt x="132" y="89" on="1"/>
+ <pt x="145" y="108" on="0"/>
+ <pt x="146" y="160" on="1"/>
+ <pt x="148" y="259" on="1"/>
+ <pt x="148" y="1112" on="1"/>
+ <pt x="148" y="1383" on="0"/>
+ <pt x="226" y="1493" on="1"/>
+ <pt x="305" y="1604" on="0"/>
+ <pt x="497" y="1604" on="1"/>
+ <pt x="649" y="1604" on="0"/>
+ <pt x="737" y="1536" on="1"/>
+ <pt x="826" y="1469" on="0"/>
+ <pt x="826" y="1358" on="1"/>
+ <pt x="826" y="1252" on="0"/>
+ <pt x="693" y="1108" on="1"/>
+ <pt x="656" y="1068" on="1"/>
+ <pt x="623" y="1034" on="1"/>
+ <pt x="579" y="989" on="0"/>
+ <pt x="579" y="939" on="1"/>
+ <pt x="579" y="882" on="0"/>
+ <pt x="642" y="812" on="1"/>
+ <pt x="701" y="746" on="1"/>
+ <pt x="803" y="630" on="1"/>
+ <pt x="926" y="490" on="0"/>
+ <pt x="959" y="430" on="1"/>
+ <pt x="993" y="367" on="0"/>
+ <pt x="993" y="282" on="1"/>
+ <pt x="993" y="154" on="0"/>
+ <pt x="908" y="64" on="1"/>
+ <pt x="823" y="-25" on="0"/>
+ <pt x="701" y="-25" on="1"/>
+ <pt x="645" y="-25" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 22 11 47 6 11 69 48 84 69 2 43 42 36 33 27 26 2 1 0 9 13 47 34
+ 35 34 1 0 14 0 0 20 16 51 10 24 65 48 196 15 34 33 15 3 0 26 3 2 65
+ 57 51 3 12 0 36 35 42 0 0 27 26 4 1 42 1 4 48 196 1 0 1 43 42 1
+ 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ MDRP[00000]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="grave" xMin="91" yMin="1283" xMax="591" yMax="1604">
+ <contour>
+ <pt x="591" y="1283" on="1"/>
+ <pt x="498" y="1283" on="1"/>
+ <pt x="91" y="1604" on="1"/>
+ <pt x="350" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 12 values pushed */
+ 1 0 2 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="greater" xMin="84" yMin="99" xMax="1071" yMax="1086">
+ <contour>
+ <pt x="84" y="1086" on="1"/>
+ <pt x="1071" y="592" on="1"/>
+ <pt x="84" y="99" on="1"/>
+ <pt x="84" y="209" on="1"/>
+ <pt x="848" y="591" on="1"/>
+ <pt x="848" y="593" on="1"/>
+ <pt x="84" y="976" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 6 5 4 3 2 1 0 14 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guillemotleft" xMin="74" yMin="111" xMax="938" yMax="975">
+ <contour>
+ <pt x="547" y="936" on="1"/>
+ <pt x="273" y="543" on="1"/>
+ <pt x="547" y="151" on="1"/>
+ <pt x="497" y="111" on="1"/>
+ <pt x="74" y="543" on="1"/>
+ <pt x="497" y="975" on="1"/>
+ </contour>
+ <contour>
+ <pt x="938" y="936" on="1"/>
+ <pt x="664" y="543" on="1"/>
+ <pt x="938" y="151" on="1"/>
+ <pt x="888" y="111" on="1"/>
+ <pt x="465" y="543" on="1"/>
+ <pt x="888" y="975" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 11 10 9 8 7 6 5 4 3 2 1 0 14 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guillemotright" xMin="86" yMin="111" xMax="950" yMax="975">
+ <contour>
+ <pt x="477" y="149" on="1"/>
+ <pt x="750" y="543" on="1"/>
+ <pt x="477" y="934" on="1"/>
+ <pt x="527" y="975" on="1"/>
+ <pt x="950" y="543" on="1"/>
+ <pt x="527" y="111" on="1"/>
+ </contour>
+ <contour>
+ <pt x="86" y="149" on="1"/>
+ <pt x="359" y="543" on="1"/>
+ <pt x="86" y="934" on="1"/>
+ <pt x="136" y="975" on="1"/>
+ <pt x="559" y="543" on="1"/>
+ <pt x="136" y="111" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 11 10 9 8 7 6 5 4 3 2 1 0 14 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guilsinglleft" xMin="86" yMin="111" xMax="559" yMax="975">
+ <contour>
+ <pt x="559" y="936" on="1"/>
+ <pt x="285" y="543" on="1"/>
+ <pt x="559" y="151" on="1"/>
+ <pt x="509" y="111" on="1"/>
+ <pt x="86" y="543" on="1"/>
+ <pt x="509" y="975" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 5 4 3 2 1 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guilsinglright" xMin="123" yMin="111" xMax="596" yMax="975">
+ <contour>
+ <pt x="123" y="149" on="1"/>
+ <pt x="396" y="543" on="1"/>
+ <pt x="123" y="934" on="1"/>
+ <pt x="173" y="975" on="1"/>
+ <pt x="596" y="543" on="1"/>
+ <pt x="173" y="111" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 5 4 3 2 1 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="h" xMin="37" yMin="0" xMax="1018" yMax="1579">
+ <contour>
+ <pt x="37" y="0" on="1"/>
+ <pt x="37" y="62" on="1"/>
+ <pt x="56" y="63" on="1"/>
+ <pt x="129" y="67" on="0"/>
+ <pt x="142" y="89" on="1"/>
+ <pt x="155" y="108" on="0"/>
+ <pt x="156" y="160" on="1"/>
+ <pt x="158" y="259" on="1"/>
+ <pt x="158" y="1320" on="1"/>
+ <pt x="156" y="1419" on="1"/>
+ <pt x="156" y="1487" on="0"/>
+ <pt x="131" y="1501" on="1"/>
+ <pt x="109" y="1513" on="0"/>
+ <pt x="56" y="1516" on="1"/>
+ <pt x="37" y="1517" on="1"/>
+ <pt x="37" y="1579" on="1"/>
+ <pt x="356" y="1579" on="1"/>
+ <pt x="356" y="907" on="1"/>
+ <pt x="420" y="999" on="0"/>
+ <pt x="480" y="1044" on="1"/>
+ <pt x="566" y="1110" on="0"/>
+ <pt x="667" y="1110" on="1"/>
+ <pt x="791" y="1110" on="0"/>
+ <pt x="844" y="1032" on="1"/>
+ <pt x="897" y="954" on="0"/>
+ <pt x="897" y="765" on="1"/>
+ <pt x="897" y="259" on="1"/>
+ <pt x="899" y="160" on="1"/>
+ <pt x="899" y="92" on="0"/>
+ <pt x="924" y="78" on="1"/>
+ <pt x="946" y="66" on="0"/>
+ <pt x="1000" y="63" on="1"/>
+ <pt x="1018" y="62" on="1"/>
+ <pt x="1018" y="0" on="1"/>
+ <pt x="579" y="0" on="1"/>
+ <pt x="579" y="62" on="1"/>
+ <pt x="598" y="63" on="1"/>
+ <pt x="675" y="68" on="0"/>
+ <pt x="687" y="92" on="1"/>
+ <pt x="698" y="112" on="0"/>
+ <pt x="698" y="160" on="1"/>
+ <pt x="700" y="259" on="1"/>
+ <pt x="700" y="734" on="1"/>
+ <pt x="697" y="811" on="1"/>
+ <pt x="694" y="900" on="0"/>
+ <pt x="672" y="937" on="1"/>
+ <pt x="647" y="981" on="0"/>
+ <pt x="592" y="981" on="1"/>
+ <pt x="477" y="981" on="0"/>
+ <pt x="356" y="840" on="1"/>
+ <pt x="356" y="259" on="1"/>
+ <pt x="357" y="160" on="1"/>
+ <pt x="358" y="91" on="0"/>
+ <pt x="383" y="78" on="1"/>
+ <pt x="405" y="66" on="0"/>
+ <pt x="458" y="63" on="1"/>
+ <pt x="477" y="62" on="1"/>
+ <pt x="477" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 94 values pushed */
+ 0 0 47 29 21 48 84 21 1 51 57 1 14 8 2 15 1 3 0 1 50 49 42 41 35
+ 32 26 25 17 7 1 11 1 0 3 0 16 15 1 57 34 33 0 3 2 0 14 57 51 51
+ 35 34 3 41 16 3 33 32 2 13 25 15 14 1 0 4 13 7 0 0 42 41 4 1 25
+ 50 49 17 16 4 3 7 2 4 48 196 26 25 1 8 7 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hbar" xMin="37" yMin="0" xMax="1018" yMax="1579">
+ <contour>
+ <pt x="37" y="0" on="1"/>
+ <pt x="37" y="62" on="1"/>
+ <pt x="56" y="63" on="1"/>
+ <pt x="129" y="67" on="0"/>
+ <pt x="142" y="89" on="1"/>
+ <pt x="155" y="108" on="0"/>
+ <pt x="156" y="160" on="1"/>
+ <pt x="158" y="259" on="1"/>
+ <pt x="158" y="1246" on="1"/>
+ <pt x="37" y="1246" on="1"/>
+ <pt x="37" y="1308" on="1"/>
+ <pt x="158" y="1308" on="1"/>
+ <pt x="158" y="1320" on="1"/>
+ <pt x="156" y="1419" on="1"/>
+ <pt x="156" y="1487" on="0"/>
+ <pt x="131" y="1501" on="1"/>
+ <pt x="109" y="1513" on="0"/>
+ <pt x="56" y="1516" on="1"/>
+ <pt x="37" y="1517" on="1"/>
+ <pt x="37" y="1579" on="1"/>
+ <pt x="356" y="1579" on="1"/>
+ <pt x="356" y="1308" on="1"/>
+ <pt x="666" y="1308" on="1"/>
+ <pt x="666" y="1246" on="1"/>
+ <pt x="356" y="1246" on="1"/>
+ <pt x="356" y="907" on="1"/>
+ <pt x="420" y="999" on="0"/>
+ <pt x="480" y="1044" on="1"/>
+ <pt x="566" y="1110" on="0"/>
+ <pt x="667" y="1110" on="1"/>
+ <pt x="791" y="1110" on="0"/>
+ <pt x="844" y="1032" on="1"/>
+ <pt x="897" y="954" on="0"/>
+ <pt x="897" y="765" on="1"/>
+ <pt x="897" y="259" on="1"/>
+ <pt x="899" y="160" on="1"/>
+ <pt x="899" y="92" on="0"/>
+ <pt x="924" y="78" on="1"/>
+ <pt x="946" y="66" on="0"/>
+ <pt x="1000" y="63" on="1"/>
+ <pt x="1018" y="62" on="1"/>
+ <pt x="1018" y="0" on="1"/>
+ <pt x="579" y="0" on="1"/>
+ <pt x="579" y="62" on="1"/>
+ <pt x="598" y="63" on="1"/>
+ <pt x="675" y="68" on="0"/>
+ <pt x="687" y="92" on="1"/>
+ <pt x="698" y="112" on="0"/>
+ <pt x="698" y="160" on="1"/>
+ <pt x="700" y="259" on="1"/>
+ <pt x="700" y="734" on="1"/>
+ <pt x="697" y="811" on="1"/>
+ <pt x="694" y="900" on="0"/>
+ <pt x="672" y="937" on="1"/>
+ <pt x="647" y="981" on="0"/>
+ <pt x="592" y="981" on="1"/>
+ <pt x="477" y="981" on="0"/>
+ <pt x="356" y="840" on="1"/>
+ <pt x="356" y="259" on="1"/>
+ <pt x="357" y="160" on="1"/>
+ <pt x="358" y="91" on="0"/>
+ <pt x="383" y="78" on="1"/>
+ <pt x="405" y="66" on="0"/>
+ <pt x="458" y="63" on="1"/>
+ <pt x="477" y="62" on="1"/>
+ <pt x="477" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 118 values pushed */
+ 0 0 55 29 29 48 84 29 1 59 65 18 12 2 19 10 3 1 58 57 50 49 43 40 34
+ 33 25 7 1 11 1 0 3 0 0 0 24 23 9 8 14 3 10 1 4 48 84 20 19 1
+ 22 21 11 10 3 65 42 41 0 3 3 0 14 65 59 59 43 42 23 22 5 49 20 3 41
+ 40 2 13 33 19 18 10 9 1 0 6 13 7 0 0 50 49 4 1 33 58 57 25 24 21
+ 20 4 5 7 2 4 48 196 34 33 1 12 11 8 7 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hcircumflex" xMin="37" yMin="0" xMax="1018" yMax="1999">
+ <contour>
+ <pt x="37" y="0" on="1"/>
+ <pt x="37" y="62" on="1"/>
+ <pt x="56" y="63" on="1"/>
+ <pt x="129" y="67" on="0"/>
+ <pt x="142" y="89" on="1"/>
+ <pt x="155" y="108" on="0"/>
+ <pt x="156" y="160" on="1"/>
+ <pt x="158" y="259" on="1"/>
+ <pt x="158" y="1320" on="1"/>
+ <pt x="156" y="1419" on="1"/>
+ <pt x="156" y="1487" on="0"/>
+ <pt x="131" y="1501" on="1"/>
+ <pt x="109" y="1513" on="0"/>
+ <pt x="56" y="1516" on="1"/>
+ <pt x="37" y="1517" on="1"/>
+ <pt x="37" y="1579" on="1"/>
+ <pt x="356" y="1579" on="1"/>
+ <pt x="356" y="907" on="1"/>
+ <pt x="420" y="999" on="0"/>
+ <pt x="480" y="1044" on="1"/>
+ <pt x="566" y="1110" on="0"/>
+ <pt x="667" y="1110" on="1"/>
+ <pt x="791" y="1110" on="0"/>
+ <pt x="844" y="1032" on="1"/>
+ <pt x="897" y="954" on="0"/>
+ <pt x="897" y="765" on="1"/>
+ <pt x="897" y="259" on="1"/>
+ <pt x="899" y="160" on="1"/>
+ <pt x="899" y="92" on="0"/>
+ <pt x="924" y="78" on="1"/>
+ <pt x="946" y="66" on="0"/>
+ <pt x="1000" y="63" on="1"/>
+ <pt x="1018" y="62" on="1"/>
+ <pt x="1018" y="0" on="1"/>
+ <pt x="579" y="0" on="1"/>
+ <pt x="579" y="62" on="1"/>
+ <pt x="598" y="63" on="1"/>
+ <pt x="675" y="68" on="0"/>
+ <pt x="687" y="92" on="1"/>
+ <pt x="698" y="112" on="0"/>
+ <pt x="698" y="160" on="1"/>
+ <pt x="700" y="259" on="1"/>
+ <pt x="700" y="734" on="1"/>
+ <pt x="697" y="811" on="1"/>
+ <pt x="694" y="900" on="0"/>
+ <pt x="672" y="937" on="1"/>
+ <pt x="647" y="981" on="0"/>
+ <pt x="592" y="981" on="1"/>
+ <pt x="477" y="981" on="0"/>
+ <pt x="356" y="840" on="1"/>
+ <pt x="356" y="259" on="1"/>
+ <pt x="357" y="160" on="1"/>
+ <pt x="358" y="91" on="0"/>
+ <pt x="383" y="78" on="1"/>
+ <pt x="405" y="66" on="0"/>
+ <pt x="458" y="63" on="1"/>
+ <pt x="477" y="62" on="1"/>
+ <pt x="477" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="171" y="1678" on="1"/>
+ <pt x="412" y="1999" on="1"/>
+ <pt x="634" y="1999" on="1"/>
+ <pt x="874" y="1678" on="1"/>
+ <pt x="788" y="1678" on="1"/>
+ <pt x="523" y="1900" on="1"/>
+ <pt x="257" y="1678" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 121 values pushed */
+ 0 0 47 39 21 48 84 21 1 51 57 64 63 62 61 58 5 59 15 3 1 14 8 2 15
+ 1 3 0 1 50 49 42 41 35 32 26 25 17 7 1 11 1 0 3 0 60 59 1 16 15
+ 1 57 34 33 0 3 3 0 14 57 51 62 61 2 25 41 3 63 60 59 51 35 34 6 41
+ 16 3 64 58 2 16 7 3 33 32 2 13 25 15 14 1 0 4 13 7 0 0 42 41 5
+ 1 25 50 49 17 16 5 3 7 2 4 48 196 26 25 1 8 7 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hungarumlaut" xMin="-5" yMin="1283" xMax="686" yMax="1604">
+ <contour>
+ <pt x="-5" y="1283" on="1"/>
+ <pt x="209" y="1604" on="1"/>
+ <pt x="378" y="1604" on="1"/>
+ <pt x="57" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="304" y="1283" on="1"/>
+ <pt x="517" y="1604" on="1"/>
+ <pt x="686" y="1604" on="1"/>
+ <pt x="365" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 7 4 3 0 4 13 1 6 5 2 1 3 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hyphen" xMin="82" yMin="543" xMax="600" yMax="666">
+ <contour>
+ <pt x="82" y="543" on="1"/>
+ <pt x="82" y="666" on="1"/>
+ <pt x="600" y="666" on="1"/>
+ <pt x="600" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hyphen#1" xMin="82" yMin="543" xMax="600" yMax="666">
+ <contour>
+ <pt x="82" y="543" on="1"/>
+ <pt x="82" y="666" on="1"/>
+ <pt x="600" y="666" on="1"/>
+ <pt x="600" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="i" xMin="47" yMin="0" xMax="536" yMax="1480">
+ <contour>
+ <pt x="193" y="1283" on="1"/>
+ <pt x="193" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="47" y="0" on="1"/>
+ <pt x="47" y="62" on="1"/>
+ <pt x="66" y="63" on="1"/>
+ <pt x="174" y="70" on="0"/>
+ <pt x="180" y="87" on="1"/>
+ <pt x="191" y="106" on="0"/>
+ <pt x="191" y="160" on="1"/>
+ <pt x="193" y="259" on="1"/>
+ <pt x="193" y="827" on="1"/>
+ <pt x="191" y="925" on="1"/>
+ <pt x="190" y="999" on="0"/>
+ <pt x="169" y="1007" on="1"/>
+ <pt x="149" y="1018" on="0"/>
+ <pt x="66" y="1023" on="1"/>
+ <pt x="47" y="1024" on="1"/>
+ <pt x="47" y="1086" on="1"/>
+ <pt x="390" y="1086" on="1"/>
+ <pt x="390" y="259" on="1"/>
+ <pt x="392" y="160" on="1"/>
+ <pt x="393" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="435" y="68" on="0"/>
+ <pt x="517" y="63" on="1"/>
+ <pt x="536" y="62" on="1"/>
+ <pt x="536" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 27 21 18 15 12 11 8 5 8 19 4 3 0 0 3 0 5 1 1 1 4 48 84 28 4
+ 1 0 20 19 1 2 1 0 14 28 27 2 13 2 19 18 15 8 5 4 6 13 0 0 0
+ 21 20 3 2 4 3 0 1 4 48 196 12 11 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="iacute" xMin="47" yMin="0" xMax="576" yMax="1604">
+ <component glyphName="dotlessi" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="-15" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ibreve" xMin="-42" yMin="0" xMax="624" yMax="1604">
+ <contour>
+ <pt x="535" y="62" on="1"/>
+ <pt x="535" y="0" on="1"/>
+ <pt x="46" y="0" on="1"/>
+ <pt x="46" y="62" on="1"/>
+ <pt x="65" y="63" on="1"/>
+ <pt x="173" y="70" on="0"/>
+ <pt x="179" y="87" on="1"/>
+ <pt x="189" y="106" on="0"/>
+ <pt x="190" y="160" on="1"/>
+ <pt x="192" y="259" on="1"/>
+ <pt x="192" y="827" on="1"/>
+ <pt x="190" y="925" on="1"/>
+ <pt x="189" y="999" on="0"/>
+ <pt x="168" y="1007" on="1"/>
+ <pt x="149" y="1018" on="0"/>
+ <pt x="65" y="1023" on="1"/>
+ <pt x="46" y="1024" on="1"/>
+ <pt x="46" y="1086" on="1"/>
+ <pt x="389" y="1086" on="1"/>
+ <pt x="389" y="259" on="1"/>
+ <pt x="391" y="160" on="1"/>
+ <pt x="392" y="85" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="437" y="68" on="0"/>
+ <pt x="516" y="63" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-42" y="1604" on="1"/>
+ <pt x="23" y="1604" on="1"/>
+ <pt x="50" y="1514" on="0"/>
+ <pt x="110" y="1472" on="1"/>
+ <pt x="178" y="1425" on="0"/>
+ <pt x="291" y="1425" on="1"/>
+ <pt x="417" y="1425" on="0"/>
+ <pt x="487" y="1484" on="1"/>
+ <pt x="536" y="1524" on="0"/>
+ <pt x="560" y="1604" on="1"/>
+ <pt x="624" y="1604" on="1"/>
+ <pt x="605" y="1469" on="0"/>
+ <pt x="533" y="1388" on="1"/>
+ <pt x="439" y="1283" on="0"/>
+ <pt x="291" y="1283" on="1"/>
+ <pt x="137" y="1283" on="0"/>
+ <pt x="42" y="1398" on="1"/>
+ <pt x="-23" y="1476" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 30 20 39 48 84 19 16 13 10 9 3 0 7 17 1 3 35 34 26 25 4 13 39
+ 17 2 1 1 0 18 17 1 14 35 34 1 0 4 13 18 26 25 17 16 13 3 2 7 13
+ 9 0 0 19 18 4 1 9 1 4 48 196 10 9 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="icircumflex" xMin="-61" yMin="0" xMax="642" yMax="1604">
+ <component glyphName="dotlessi" x="-1" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="-51" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="idieresis" xMin="7" yMin="0" xMax="575" yMax="1456">
+ <contour>
+ <pt x="535" y="62" on="1"/>
+ <pt x="535" y="0" on="1"/>
+ <pt x="46" y="0" on="1"/>
+ <pt x="46" y="62" on="1"/>
+ <pt x="65" y="63" on="1"/>
+ <pt x="173" y="70" on="0"/>
+ <pt x="179" y="87" on="1"/>
+ <pt x="189" y="106" on="0"/>
+ <pt x="190" y="160" on="1"/>
+ <pt x="192" y="259" on="1"/>
+ <pt x="192" y="827" on="1"/>
+ <pt x="190" y="925" on="1"/>
+ <pt x="189" y="999" on="0"/>
+ <pt x="168" y="1007" on="1"/>
+ <pt x="149" y="1018" on="0"/>
+ <pt x="65" y="1023" on="1"/>
+ <pt x="46" y="1024" on="1"/>
+ <pt x="46" y="1086" on="1"/>
+ <pt x="389" y="1086" on="1"/>
+ <pt x="389" y="259" on="1"/>
+ <pt x="391" y="160" on="1"/>
+ <pt x="392" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="437" y="68" on="0"/>
+ <pt x="516" y="63" on="1"/>
+ </contour>
+ <contour>
+ <pt x="7" y="1283" on="1"/>
+ <pt x="7" y="1456" on="1"/>
+ <pt x="180" y="1456" on="1"/>
+ <pt x="180" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="402" y="1283" on="1"/>
+ <pt x="402" y="1456" on="1"/>
+ <pt x="575" y="1456" on="1"/>
+ <pt x="575" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 19 16 13 10 9 3 0 7 17 1 3 0 0 32 29 28 25 13 3 26 1 4 48 84 31
+ 30 27 26 3 2 1 1 2 0 18 17 1 14 1 0 2 31 29 3 17 16 13 3 2 5
+ 27 25 3 0 0 30 29 13 1 31 28 27 13 1 25 19 18 4 1 9 3 4 48 196 32
+ 31 1 26 25 1 10 9 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="igrave" xMin="7" yMin="0" xMax="535" yMax="1604">
+ <component glyphName="dotlessi" x="-1" y="0" flags="0x4"/>
+ <component glyphName="grave" x="-84" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ij" xMin="47" yMin="-419" xMax="1021" yMax="1480">
+ <component glyphName="i" x="0" y="0" flags="0x4"/>
+ <component glyphName="j" x="562" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="imacron" xMin="-40" yMin="0" xMax="602" yMax="1406">
+ <component glyphName="dotlessi" x="-1" y="0" flags="0x4"/>
+ <component glyphName="macron" x="-60" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="iogonek" xMin="47" yMin="-370" xMax="536" yMax="1480">
+ <component glyphName="i" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="-39" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="itilde" xMin="-55" yMin="0" xMax="611" yMax="1518">
+ <contour>
+ <pt x="535" y="62" on="1"/>
+ <pt x="535" y="0" on="1"/>
+ <pt x="46" y="0" on="1"/>
+ <pt x="46" y="62" on="1"/>
+ <pt x="65" y="63" on="1"/>
+ <pt x="173" y="70" on="0"/>
+ <pt x="179" y="87" on="1"/>
+ <pt x="189" y="106" on="0"/>
+ <pt x="190" y="160" on="1"/>
+ <pt x="192" y="259" on="1"/>
+ <pt x="192" y="827" on="1"/>
+ <pt x="190" y="925" on="1"/>
+ <pt x="189" y="999" on="0"/>
+ <pt x="168" y="1007" on="1"/>
+ <pt x="149" y="1018" on="0"/>
+ <pt x="65" y="1023" on="1"/>
+ <pt x="46" y="1024" on="1"/>
+ <pt x="46" y="1086" on="1"/>
+ <pt x="389" y="1086" on="1"/>
+ <pt x="389" y="259" on="1"/>
+ <pt x="391" y="160" on="1"/>
+ <pt x="392" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="437" y="68" on="0"/>
+ <pt x="516" y="63" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-55" y="1283" on="1"/>
+ <pt x="-28" y="1423" on="0"/>
+ <pt x="41" y="1476" on="1"/>
+ <pt x="95" y="1518" on="0"/>
+ <pt x="172" y="1518" on="1"/>
+ <pt x="237" y="1518" on="0"/>
+ <pt x="290" y="1480" on="1"/>
+ <pt x="325" y="1455" on="1"/>
+ <pt x="377" y="1418" on="0"/>
+ <pt x="431" y="1418" on="1"/>
+ <pt x="527" y="1418" on="0"/>
+ <pt x="549" y="1517" on="1"/>
+ <pt x="611" y="1517" on="1"/>
+ <pt x="583" y="1378" on="0"/>
+ <pt x="515" y="1325" on="1"/>
+ <pt x="461" y="1283" on="0"/>
+ <pt x="384" y="1283" on="1"/>
+ <pt x="321" y="1283" on="0"/>
+ <pt x="266" y="1321" on="1"/>
+ <pt x="231" y="1345" on="1"/>
+ <pt x="176" y="1383" on="0"/>
+ <pt x="124" y="1383" on="1"/>
+ <pt x="36" y="1383" on="0"/>
+ <pt x="7" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 46 20 29 34 20 41 48 84 29 0 41 1 48 41 25 3 0 17 3 0 19 16 13
+ 10 9 3 0 7 17 1 3 1 37 36 2 13 0 0 2 1 1 0 18 17 1 14 37 36
+ 1 0 4 13 18 48 25 17 16 13 3 2 7 13 9 0 0 19 18 5 1 9 1 4 48
+ 196 10 9 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="j" xMin="-78" yMin="-419" xMax="459" yMax="1480">
+ <contour>
+ <pt x="-78" y="-380" on="1"/>
+ <pt x="-78" y="-136" on="1"/>
+ <pt x="21" y="-136" on="1"/>
+ <pt x="22" y="-154" on="1"/>
+ <pt x="26" y="-268" on="0"/>
+ <pt x="47" y="-306" on="1"/>
+ <pt x="72" y="-352" on="0"/>
+ <pt x="133" y="-352" on="1"/>
+ <pt x="262" y="-352" on="0"/>
+ <pt x="262" y="-185" on="1"/>
+ <pt x="262" y="-82" on="1"/>
+ <pt x="262" y="827" on="1"/>
+ <pt x="260" y="925" on="1"/>
+ <pt x="260" y="993" on="0"/>
+ <pt x="235" y="1007" on="1"/>
+ <pt x="214" y="1019" on="0"/>
+ <pt x="159" y="1023" on="1"/>
+ <pt x="141" y="1024" on="1"/>
+ <pt x="141" y="1086" on="1"/>
+ <pt x="459" y="1086" on="1"/>
+ <pt x="459" y="12" on="1"/>
+ <pt x="459" y="-419" on="0"/>
+ <pt x="127" y="-419" on="1"/>
+ <pt x="51" y="-419" on="0"/>
+ </contour>
+ <contour>
+ <pt x="262" y="1283" on="1"/>
+ <pt x="262" y="1480" on="1"/>
+ <pt x="459" y="1480" on="1"/>
+ <pt x="459" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 0 0 7 17 22 48 84 1 20 17 11 3 18 2 3 0 1 10 9 2 1 0 5 13 22
+ 2 0 0 0 27 24 5 1 25 1 4 48 84 26 25 0 19 18 1 14 18 17 2 3 9
+ 0 3 0 0 25 24 11 10 9 4 4 19 1 4 48 196 27 26 20 19 3 1 0 1 2
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="jcircumflex" xMin="-78" yMin="-419" xMax="656" yMax="1604">
+ <contour>
+ <pt x="-78" y="-380" on="1"/>
+ <pt x="-78" y="-136" on="1"/>
+ <pt x="21" y="-136" on="1"/>
+ <pt x="22" y="-154" on="1"/>
+ <pt x="26" y="-268" on="0"/>
+ <pt x="47" y="-306" on="1"/>
+ <pt x="72" y="-352" on="0"/>
+ <pt x="133" y="-352" on="1"/>
+ <pt x="262" y="-352" on="0"/>
+ <pt x="262" y="-185" on="1"/>
+ <pt x="262" y="-82" on="1"/>
+ <pt x="262" y="827" on="1"/>
+ <pt x="260" y="925" on="1"/>
+ <pt x="260" y="993" on="0"/>
+ <pt x="235" y="1007" on="1"/>
+ <pt x="214" y="1019" on="0"/>
+ <pt x="159" y="1023" on="1"/>
+ <pt x="141" y="1024" on="1"/>
+ <pt x="141" y="1086" on="1"/>
+ <pt x="459" y="1086" on="1"/>
+ <pt x="459" y="12" on="1"/>
+ <pt x="459" y="-419" on="0"/>
+ <pt x="127" y="-419" on="1"/>
+ <pt x="51" y="-419" on="0"/>
+ </contour>
+ <contour>
+ <pt x="-47" y="1283" on="1"/>
+ <pt x="194" y="1604" on="1"/>
+ <pt x="416" y="1604" on="1"/>
+ <pt x="656" y="1283" on="1"/>
+ <pt x="570" y="1283" on="1"/>
+ <pt x="305" y="1505" on="1"/>
+ <pt x="40" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 0 0 7 17 22 48 84 1 29 25 0 2 0 1 30 28 27 24 4 0 18 3 0 1 20
+ 17 11 3 18 2 3 0 1 10 9 2 1 0 5 13 22 2 0 26 25 1 0 19 18 1
+ 14 29 26 2 19 9 3 30 25 24 18 17 2 6 9 0 3 28 27 2 13 19 0 0 20
+ 19 4 1 9 1 4 48 196 11 10 9 2 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="k" xMin="31" yMin="0" xMax="1024" yMax="1579">
+ <contour>
+ <pt x="31" y="0" on="1"/>
+ <pt x="31" y="62" on="1"/>
+ <pt x="50" y="63" on="1"/>
+ <pt x="123" y="67" on="0"/>
+ <pt x="136" y="89" on="1"/>
+ <pt x="149" y="108" on="0"/>
+ <pt x="150" y="160" on="1"/>
+ <pt x="152" y="259" on="1"/>
+ <pt x="152" y="1320" on="1"/>
+ <pt x="150" y="1419" on="1"/>
+ <pt x="150" y="1487" on="0"/>
+ <pt x="125" y="1501" on="1"/>
+ <pt x="103" y="1513" on="0"/>
+ <pt x="50" y="1516" on="1"/>
+ <pt x="31" y="1517" on="1"/>
+ <pt x="31" y="1579" on="1"/>
+ <pt x="349" y="1579" on="1"/>
+ <pt x="349" y="583" on="1"/>
+ <pt x="396" y="583" on="1"/>
+ <pt x="586" y="825" on="1"/>
+ <pt x="664" y="925" on="1"/>
+ <pt x="704" y="979" on="1"/>
+ <pt x="717" y="996" on="0"/>
+ <pt x="717" y="1005" on="1"/>
+ <pt x="717" y="1022" on="0"/>
+ <pt x="683" y="1022" on="1"/>
+ <pt x="678" y="1022" on="1"/>
+ <pt x="673" y="1022" on="1"/>
+ <pt x="667" y="1022" on="1"/>
+ <pt x="661" y="1023" on="1"/>
+ <pt x="651" y="1023" on="0"/>
+ <pt x="640" y="1024" on="1"/>
+ <pt x="632" y="1024" on="1"/>
+ <pt x="631" y="1024" on="1"/>
+ <pt x="609" y="1024" on="1"/>
+ <pt x="609" y="1086" on="1"/>
+ <pt x="946" y="1086" on="1"/>
+ <pt x="946" y="1024" on="1"/>
+ <pt x="928" y="1023" on="1"/>
+ <pt x="840" y="1018" on="0"/>
+ <pt x="819" y="998" on="1"/>
+ <pt x="796" y="980" on="0"/>
+ <pt x="757" y="928" on="1"/>
+ <pt x="686" y="835" on="1"/>
+ <pt x="539" y="640" on="1"/>
+ <pt x="811" y="253" on="1"/>
+ <pt x="896" y="132" on="0"/>
+ <pt x="930" y="98" on="1"/>
+ <pt x="964" y="66" on="0"/>
+ <pt x="1005" y="63" on="1"/>
+ <pt x="1024" y="62" on="1"/>
+ <pt x="1024" y="0" on="1"/>
+ <pt x="769" y="0" on="1"/>
+ <pt x="396" y="534" on="1"/>
+ <pt x="349" y="534" on="1"/>
+ <pt x="349" y="259" on="1"/>
+ <pt x="351" y="160" on="1"/>
+ <pt x="352" y="91" on="0"/>
+ <pt x="376" y="78" on="1"/>
+ <pt x="398" y="66" on="0"/>
+ <pt x="452" y="63" on="1"/>
+ <pt x="470" y="62" on="1"/>
+ <pt x="470" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 14 8 2 15 35 3 61 55 54 53 50 44 37 34 33 32 31 28 27 26 25 18 17 7 1
+ 19 35 0 3 16 15 1 62 52 51 0 3 2 0 36 35 1 14 62 61 53 52 51 50 44
+ 37 36 35 34 33 32 31 28 27 26 25 18 19 13 23 16 15 14 1 0 4 13 7 0 0
+ 55 54 17 16 4 3 7 1 4 48 196 8 7 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="kcommaaccent" xMin="31" yMin="-432" xMax="1024" yMax="1579">
+ <component glyphName="k" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="276" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="kgreenlandic" xMin="37" yMin="0" xMax="1024" yMax="1086">
+ <contour>
+ <pt x="476" y="62" on="1"/>
+ <pt x="476" y="0" on="1"/>
+ <pt x="37" y="0" on="1"/>
+ <pt x="37" y="62" on="1"/>
+ <pt x="56" y="63" on="1"/>
+ <pt x="129" y="67" on="0"/>
+ <pt x="142" y="89" on="1"/>
+ <pt x="155" y="108" on="0"/>
+ <pt x="156" y="160" on="1"/>
+ <pt x="158" y="259" on="1"/>
+ <pt x="158" y="827" on="1"/>
+ <pt x="156" y="925" on="1"/>
+ <pt x="156" y="993" on="0"/>
+ <pt x="131" y="1007" on="1"/>
+ <pt x="111" y="1019" on="0"/>
+ <pt x="56" y="1023" on="1"/>
+ <pt x="37" y="1024" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="355" y="1086" on="1"/>
+ <pt x="355" y="583" on="1"/>
+ <pt x="402" y="583" on="1"/>
+ <pt x="592" y="825" on="1"/>
+ <pt x="670" y="925" on="1"/>
+ <pt x="710" y="979" on="1"/>
+ <pt x="723" y="996" on="0"/>
+ <pt x="723" y="1005" on="1"/>
+ <pt x="723" y="1022" on="0"/>
+ <pt x="689" y="1022" on="1"/>
+ <pt x="684" y="1022" on="1"/>
+ <pt x="679" y="1022" on="1"/>
+ <pt x="673" y="1022" on="1"/>
+ <pt x="667" y="1023" on="1"/>
+ <pt x="657" y="1023" on="0"/>
+ <pt x="646" y="1024" on="1"/>
+ <pt x="638" y="1024" on="1"/>
+ <pt x="637" y="1024" on="1"/>
+ <pt x="615" y="1024" on="1"/>
+ <pt x="615" y="1086" on="1"/>
+ <pt x="952" y="1086" on="1"/>
+ <pt x="952" y="1024" on="1"/>
+ <pt x="934" y="1023" on="1"/>
+ <pt x="846" y="1018" on="0"/>
+ <pt x="825" y="998" on="1"/>
+ <pt x="802" y="980" on="0"/>
+ <pt x="763" y="928" on="1"/>
+ <pt x="692" y="835" on="1"/>
+ <pt x="545" y="640" on="1"/>
+ <pt x="817" y="253" on="1"/>
+ <pt x="949" y="64" on="0"/>
+ <pt x="1011" y="62" on="1"/>
+ <pt x="1024" y="62" on="1"/>
+ <pt x="1024" y="0" on="1"/>
+ <pt x="775" y="0" on="1"/>
+ <pt x="402" y="534" on="1"/>
+ <pt x="355" y="534" on="1"/>
+ <pt x="355" y="259" on="1"/>
+ <pt x="357" y="160" on="1"/>
+ <pt x="358" y="91" on="0"/>
+ <pt x="382" y="78" on="1"/>
+ <pt x="404" y="66" on="0"/>
+ <pt x="458" y="63" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 55 54 53 50 49 46 39 36 35 34 33 30 29 28 27 20 19 16 10 9 3 0 22 17 1
+ 3 52 51 2 1 3 0 38 37 18 17 1 3 14 53 52 51 50 49 46 39 38 37 36 35
+ 34 33 30 29 28 27 20 1 0 20 13 25 18 17 16 3 2 4 13 9 0 0 55 54 19
+ 18 4 3 9 1 4 48 196 10 9 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="l" xMin="47" yMin="0" xMax="536" yMax="1579">
+ <contour>
+ <pt x="47" y="0" on="1"/>
+ <pt x="47" y="62" on="1"/>
+ <pt x="66" y="63" on="1"/>
+ <pt x="174" y="70" on="0"/>
+ <pt x="180" y="87" on="1"/>
+ <pt x="191" y="106" on="0"/>
+ <pt x="191" y="160" on="1"/>
+ <pt x="193" y="259" on="1"/>
+ <pt x="193" y="1320" on="1"/>
+ <pt x="191" y="1419" on="1"/>
+ <pt x="190" y="1493" on="0"/>
+ <pt x="169" y="1501" on="1"/>
+ <pt x="148" y="1511" on="0"/>
+ <pt x="66" y="1516" on="1"/>
+ <pt x="47" y="1517" on="1"/>
+ <pt x="47" y="1579" on="1"/>
+ <pt x="390" y="1579" on="1"/>
+ <pt x="390" y="259" on="1"/>
+ <pt x="392" y="160" on="1"/>
+ <pt x="393" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="435" y="68" on="0"/>
+ <pt x="517" y="63" on="1"/>
+ <pt x="536" y="62" on="1"/>
+ <pt x="536" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 23 17 14 8 7 4 1 7 15 0 3 16 15 1 24 0 1 2 0 14 24 23 2 13 16
+ 15 14 4 1 0 5 13 7 0 0 17 16 4 1 7 1 4 48 196 8 7 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lacute" xMin="47" yMin="0" xMax="576" yMax="1999">
+ <component glyphName="l" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="-15" y="395" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="lcaron" xMin="47" yMin="0" xMax="785" yMax="1579">
+ <contour>
+ <pt x="536" y="62" on="1"/>
+ <pt x="536" y="0" on="1"/>
+ <pt x="47" y="0" on="1"/>
+ <pt x="47" y="62" on="1"/>
+ <pt x="66" y="63" on="1"/>
+ <pt x="174" y="70" on="0"/>
+ <pt x="180" y="87" on="1"/>
+ <pt x="191" y="106" on="0"/>
+ <pt x="191" y="160" on="1"/>
+ <pt x="193" y="259" on="1"/>
+ <pt x="193" y="1320" on="1"/>
+ <pt x="191" y="1419" on="1"/>
+ <pt x="190" y="1493" on="0"/>
+ <pt x="169" y="1501" on="1"/>
+ <pt x="148" y="1511" on="0"/>
+ <pt x="66" y="1516" on="1"/>
+ <pt x="47" y="1517" on="1"/>
+ <pt x="47" y="1579" on="1"/>
+ <pt x="390" y="1579" on="1"/>
+ <pt x="390" y="259" on="1"/>
+ <pt x="392" y="160" on="1"/>
+ <pt x="393" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="435" y="68" on="0"/>
+ <pt x="517" y="63" on="1"/>
+ </contour>
+ <contour>
+ <pt x="667" y="1382" on="1"/>
+ <pt x="588" y="1382" on="1"/>
+ <pt x="588" y="1579" on="1"/>
+ <pt x="785" y="1579" on="1"/>
+ <pt x="785" y="1408" on="1"/>
+ <pt x="785" y="1245" on="0"/>
+ <pt x="723" y="1180" on="1"/>
+ <pt x="675" y="1131" on="0"/>
+ <pt x="588" y="1125" on="1"/>
+ <pt x="588" y="1175" on="1"/>
+ <pt x="667" y="1181" on="0"/>
+ <pt x="667" y="1330" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 36 34 33 29 26 25 19 16 10 9 6 3 0 13 17 1 3 28 27 18 17 3 2 1 1
+ 2 0 14 36 25 2 28 26 3 1 0 2 26 18 3 17 16 6 3 2 5 13 9 0 0
+ 34 33 27 26 4 3 28 19 18 4 1 9 2 4 48 196 29 28 1 10 9 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lcommaaccent" xMin="47" yMin="-432" xMax="536" yMax="1579">
+ <component glyphName="l" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="-26" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ldot" xMin="47" yMin="0" xMax="742" yMax="1579">
+ <contour>
+ <pt x="536" y="62" on="1"/>
+ <pt x="536" y="0" on="1"/>
+ <pt x="47" y="0" on="1"/>
+ <pt x="47" y="62" on="1"/>
+ <pt x="66" y="63" on="1"/>
+ <pt x="174" y="70" on="0"/>
+ <pt x="180" y="87" on="1"/>
+ <pt x="191" y="106" on="0"/>
+ <pt x="191" y="160" on="1"/>
+ <pt x="193" y="259" on="1"/>
+ <pt x="193" y="1320" on="1"/>
+ <pt x="191" y="1419" on="1"/>
+ <pt x="190" y="1493" on="0"/>
+ <pt x="169" y="1501" on="1"/>
+ <pt x="148" y="1511" on="0"/>
+ <pt x="66" y="1516" on="1"/>
+ <pt x="47" y="1517" on="1"/>
+ <pt x="47" y="1579" on="1"/>
+ <pt x="390" y="1579" on="1"/>
+ <pt x="390" y="259" on="1"/>
+ <pt x="392" y="160" on="1"/>
+ <pt x="393" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="435" y="68" on="0"/>
+ <pt x="517" y="63" on="1"/>
+ </contour>
+ <contour>
+ <pt x="545" y="691" on="1"/>
+ <pt x="545" y="888" on="1"/>
+ <pt x="742" y="888" on="1"/>
+ <pt x="742" y="691" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 16 10 2 17 26 3 19 9 6 3 0 5 25 1 3 0 0 28 25 5 1 26 1 4 48
+ 84 27 26 1 18 17 1 2 1 1 3 0 14 1 0 2 25 18 3 17 16 6 3 2 5
+ 13 9 0 0 26 25 4 1 27 19 18 4 1 9 2 4 48 196 28 27 1 10 9 1 2
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="less" xMin="84" yMin="99" xMax="1071" yMax="1086">
+ <contour>
+ <pt x="1071" y="99" on="1"/>
+ <pt x="84" y="592" on="1"/>
+ <pt x="1071" y="1086" on="1"/>
+ <pt x="1071" y="975" on="1"/>
+ <pt x="307" y="593" on="1"/>
+ <pt x="307" y="591" on="1"/>
+ <pt x="1071" y="209" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 6 5 4 3 2 1 0 14 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="logicalnot" xMin="84" yMin="296" xMax="1022" yMax="790">
+ <contour>
+ <pt x="923" y="296" on="1"/>
+ <pt x="923" y="691" on="1"/>
+ <pt x="84" y="691" on="1"/>
+ <pt x="84" y="790" on="1"/>
+ <pt x="1022" y="790" on="1"/>
+ <pt x="1022" y="691" on="1"/>
+ <pt x="1022" y="691" on="1"/>
+ <pt x="1022" y="296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 41 values pushed */
+ 7 0 1 0 0 6 5 2 1 9 3 3 1 4 48 84 4 3 1 0 14 3 2 0 0
+ 0 1 0 9 1 4 1 4 48 196 7 6 5 4 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="longs" xMin="37" yMin="0" xMax="719" yMax="1604">
+ <contour>
+ <pt x="176" y="999" on="1"/>
+ <pt x="37" y="999" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="176" y="1086" on="1"/>
+ <pt x="176" y="1138" on="1"/>
+ <pt x="176" y="1401" on="0"/>
+ <pt x="245" y="1502" on="1"/>
+ <pt x="314" y="1604" on="0"/>
+ <pt x="489" y="1604" on="1"/>
+ <pt x="617" y="1604" on="0"/>
+ <pt x="719" y="1530" on="1"/>
+ <pt x="719" y="1295" on="1"/>
+ <pt x="608" y="1295" on="1"/>
+ <pt x="607" y="1314" on="1"/>
+ <pt x="605" y="1353" on="0"/>
+ <pt x="604" y="1380" on="1"/>
+ <pt x="604" y="1385" on="1"/>
+ <pt x="604" y="1540" on="0"/>
+ <pt x="496" y="1540" on="1"/>
+ <pt x="376" y="1540" on="0"/>
+ <pt x="374" y="1357" on="1"/>
+ <pt x="373" y="1257" on="1"/>
+ <pt x="373" y="259" on="1"/>
+ <pt x="375" y="160" on="1"/>
+ <pt x="376" y="88" on="0"/>
+ <pt x="408" y="75" on="1"/>
+ <pt x="434" y="63" on="0"/>
+ <pt x="500" y="63" on="1"/>
+ <pt x="544" y="62" on="1"/>
+ <pt x="544" y="0" on="1"/>
+ <pt x="55" y="0" on="1"/>
+ <pt x="55" y="62" on="1"/>
+ <pt x="74" y="63" on="1"/>
+ <pt x="151" y="68" on="0"/>
+ <pt x="163" y="92" on="1"/>
+ <pt x="174" y="112" on="0"/>
+ <pt x="174" y="160" on="1"/>
+ <pt x="176" y="259" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 18 38 8 48 84 37 31 28 22 4 0 29 3 21 16 15 12 11 10 4 7 13 8
+ 2 0 0 1 0 8 1 2 1 4 48 84 30 29 1 0 3 2 1 14 29 28 16 15 12
+ 5 10 21 3 31 30 2 1 4 13 0 0 0 22 21 5 1 0 1 4 48 196 11 10 1
+ 37 4 3 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lslash" xMin="47" yMin="0" xMax="536" yMax="1579">
+ <contour>
+ <pt x="47" y="0" on="1"/>
+ <pt x="47" y="62" on="1"/>
+ <pt x="66" y="63" on="1"/>
+ <pt x="174" y="70" on="0"/>
+ <pt x="180" y="87" on="1"/>
+ <pt x="191" y="106" on="0"/>
+ <pt x="191" y="160" on="1"/>
+ <pt x="193" y="259" on="1"/>
+ <pt x="193" y="783" on="1"/>
+ <pt x="47" y="699" on="1"/>
+ <pt x="47" y="784" on="1"/>
+ <pt x="193" y="868" on="1"/>
+ <pt x="193" y="1320" on="1"/>
+ <pt x="191" y="1419" on="1"/>
+ <pt x="190" y="1493" on="0"/>
+ <pt x="169" y="1501" on="1"/>
+ <pt x="148" y="1511" on="0"/>
+ <pt x="66" y="1516" on="1"/>
+ <pt x="47" y="1517" on="1"/>
+ <pt x="47" y="1579" on="1"/>
+ <pt x="390" y="1579" on="1"/>
+ <pt x="390" y="982" on="1"/>
+ <pt x="536" y="1066" on="1"/>
+ <pt x="536" y="981" on="1"/>
+ <pt x="390" y="897" on="1"/>
+ <pt x="390" y="259" on="1"/>
+ <pt x="392" y="160" on="1"/>
+ <pt x="393" y="86" on="0"/>
+ <pt x="414" y="78" on="1"/>
+ <pt x="435" y="68" on="0"/>
+ <pt x="517" y="63" on="1"/>
+ <pt x="536" y="62" on="1"/>
+ <pt x="536" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 64 values pushed */
+ 31 25 24 23 22 21 18 12 11 10 9 8 7 4 1 15 19 0 3 20 19 1 32 0 1
+ 2 0 14 32 31 23 22 4 13 20 19 18 10 9 4 1 0 7 13 7 0 0 25 24 21
+ 20 4 3 7 1 4 48 196 12 11 8 7 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="m" xMin="37" yMin="0" xMax="1584" yMax="1110">
+ <contour>
+ <pt x="37" y="0" on="1"/>
+ <pt x="37" y="62" on="1"/>
+ <pt x="56" y="63" on="1"/>
+ <pt x="129" y="67" on="0"/>
+ <pt x="142" y="89" on="1"/>
+ <pt x="155" y="108" on="0"/>
+ <pt x="156" y="160" on="1"/>
+ <pt x="158" y="259" on="1"/>
+ <pt x="158" y="827" on="1"/>
+ <pt x="156" y="925" on="1"/>
+ <pt x="156" y="993" on="0"/>
+ <pt x="131" y="1007" on="1"/>
+ <pt x="111" y="1019" on="0"/>
+ <pt x="56" y="1023" on="1"/>
+ <pt x="37" y="1024" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="355" y="1086" on="1"/>
+ <pt x="355" y="907" on="1"/>
+ <pt x="420" y="999" on="0"/>
+ <pt x="480" y="1044" on="1"/>
+ <pt x="566" y="1110" on="0"/>
+ <pt x="667" y="1110" on="1"/>
+ <pt x="764" y="1110" on="0"/>
+ <pt x="826" y="1056" on="1"/>
+ <pt x="880" y="1009" on="0"/>
+ <pt x="909" y="904" on="1"/>
+ <pt x="972" y="997" on="0"/>
+ <pt x="1033" y="1043" on="1"/>
+ <pt x="1120" y="1110" on="0"/>
+ <pt x="1226" y="1110" on="1"/>
+ <pt x="1356" y="1110" on="0"/>
+ <pt x="1409" y="1033" on="1"/>
+ <pt x="1463" y="956" on="0"/>
+ <pt x="1463" y="765" on="1"/>
+ <pt x="1463" y="259" on="1"/>
+ <pt x="1465" y="160" on="1"/>
+ <pt x="1466" y="91" on="0"/>
+ <pt x="1490" y="78" on="1"/>
+ <pt x="1512" y="66" on="0"/>
+ <pt x="1566" y="63" on="1"/>
+ <pt x="1584" y="62" on="1"/>
+ <pt x="1584" y="0" on="1"/>
+ <pt x="1145" y="0" on="1"/>
+ <pt x="1145" y="62" on="1"/>
+ <pt x="1164" y="63" on="1"/>
+ <pt x="1237" y="67" on="0"/>
+ <pt x="1251" y="89" on="1"/>
+ <pt x="1263" y="109" on="0"/>
+ <pt x="1264" y="160" on="1"/>
+ <pt x="1266" y="259" on="1"/>
+ <pt x="1266" y="734" on="1"/>
+ <pt x="1264" y="811" on="1"/>
+ <pt x="1262" y="894" on="0"/>
+ <pt x="1240" y="933" on="1"/>
+ <pt x="1212" y="981" on="0"/>
+ <pt x="1151" y="981" on="1"/>
+ <pt x="1031" y="981" on="0"/>
+ <pt x="909" y="840" on="1"/>
+ <pt x="909" y="259" on="1"/>
+ <pt x="911" y="160" on="1"/>
+ <pt x="911" y="91" on="0"/>
+ <pt x="936" y="78" on="1"/>
+ <pt x="958" y="66" on="0"/>
+ <pt x="1012" y="63" on="1"/>
+ <pt x="1030" y="62" on="1"/>
+ <pt x="1030" y="0" on="1"/>
+ <pt x="591" y="0" on="1"/>
+ <pt x="591" y="62" on="1"/>
+ <pt x="610" y="63" on="1"/>
+ <pt x="683" y="68" on="0"/>
+ <pt x="696" y="89" on="1"/>
+ <pt x="709" y="109" on="0"/>
+ <pt x="710" y="160" on="1"/>
+ <pt x="712" y="259" on="1"/>
+ <pt x="712" y="734" on="1"/>
+ <pt x="710" y="811" on="1"/>
+ <pt x="708" y="895" on="0"/>
+ <pt x="685" y="934" on="1"/>
+ <pt x="658" y="981" on="0"/>
+ <pt x="598" y="981" on="1"/>
+ <pt x="477" y="981" on="0"/>
+ <pt x="355" y="840" on="1"/>
+ <pt x="355" y="259" on="1"/>
+ <pt x="357" y="160" on="1"/>
+ <pt x="358" y="91" on="0"/>
+ <pt x="382" y="78" on="1"/>
+ <pt x="404" y="66" on="0"/>
+ <pt x="458" y="63" on="1"/>
+ <pt x="476" y="62" on="1"/>
+ <pt x="476" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 114 values pushed */
+ 0 0 79 29 21 55 29 29 48 84 29 1 21 1 88 82 81 74 73 67 64 58 57 50 49
+ 43 40 34 33 25 17 14 8 7 1 21 15 0 3 89 66 65 42 41 0 5 0 16 15 1
+ 14 65 64 43 42 4 49 25 3 89 88 67 66 4 73 16 3 41 40 2 13 33 15 14 1
+ 0 4 13 7 0 0 50 49 4 1 33 58 57 25 4 2 73 82 81 17 16 4 3 7 3
+ 4 48 196 34 33 1 74 73 1 8 7 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="macron" xMin="20" yMin="1283" xMax="662" yMax="1406">
+ <contour>
+ <pt x="20" y="1283" on="1"/>
+ <pt x="20" y="1406" on="1"/>
+ <pt x="662" y="1406" on="1"/>
+ <pt x="662" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="macron#1" xMin="99" yMin="1480" xMax="926" yMax="1604">
+ <contour>
+ <pt x="99" y="1480" on="1"/>
+ <pt x="99" y="1604" on="1"/>
+ <pt x="926" y="1604" on="1"/>
+ <pt x="926" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="minus" xMin="222" yMin="543" xMax="1406" yMax="642">
+ <contour>
+ <pt x="222" y="543" on="1"/>
+ <pt x="222" y="642" on="1"/>
+ <pt x="1406" y="642" on="1"/>
+ <pt x="1406" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 9 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="mu" xMin="12" yMin="-296" xMax="993" yMax="1086">
+ <contour>
+ <pt x="331" y="-22" on="1"/>
+ <pt x="331" y="-296" on="1"/>
+ <pt x="133" y="-296" on="1"/>
+ <pt x="133" y="321" on="1"/>
+ <pt x="133" y="827" on="1"/>
+ <pt x="131" y="925" on="1"/>
+ <pt x="131" y="993" on="0"/>
+ <pt x="106" y="1007" on="1"/>
+ <pt x="86" y="1019" on="0"/>
+ <pt x="31" y="1023" on="1"/>
+ <pt x="12" y="1024" on="1"/>
+ <pt x="12" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="352" on="1"/>
+ <pt x="333" y="274" on="1"/>
+ <pt x="335" y="188" on="0"/>
+ <pt x="357" y="150" on="1"/>
+ <pt x="383" y="105" on="0"/>
+ <pt x="439" y="105" on="1"/>
+ <pt x="554" y="105" on="0"/>
+ <pt x="675" y="245" on="1"/>
+ <pt x="675" y="827" on="1"/>
+ <pt x="673" y="925" on="1"/>
+ <pt x="672" y="994" on="0"/>
+ <pt x="648" y="1007" on="1"/>
+ <pt x="627" y="1019" on="0"/>
+ <pt x="573" y="1023" on="1"/>
+ <pt x="554" y="1024" on="1"/>
+ <pt x="554" y="1086" on="1"/>
+ <pt x="872" y="1086" on="1"/>
+ <pt x="872" y="259" on="1"/>
+ <pt x="874" y="160" on="1"/>
+ <pt x="874" y="92" on="0"/>
+ <pt x="899" y="78" on="1"/>
+ <pt x="921" y="66" on="0"/>
+ <pt x="974" y="63" on="1"/>
+ <pt x="993" y="62" on="1"/>
+ <pt x="993" y="0" on="1"/>
+ <pt x="675" y="0" on="1"/>
+ <pt x="675" y="179" on="1"/>
+ <pt x="533" y="-25" on="0"/>
+ <pt x="368" y="-25" on="1"/>
+ <pt x="352" y="-25" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 18 29 41 48 84 41 2 39 36 30 27 21 20 13 10 4 3 10 11 37 3 0 37
+ 1 2 38 37 1 2 1 1 2 0 29 28 12 11 1 3 14 28 27 2 20 0 3 37 36
+ 2 13 29 11 10 2 0 0 39 38 21 20 4 3 29 13 12 1 0 4 3 2 2 4 48
+ 196 30 29 1 4 3 2 2 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="multiply" xMin="84" yMin="99" xMax="1071" yMax="1086">
+ <contour>
+ <pt x="84" y="169" on="1"/>
+ <pt x="507" y="592" on="1"/>
+ <pt x="84" y="1016" on="1"/>
+ <pt x="153" y="1086" on="1"/>
+ <pt x="577" y="662" on="1"/>
+ <pt x="1001" y="1086" on="1"/>
+ <pt x="1071" y="1016" on="1"/>
+ <pt x="647" y="592" on="1"/>
+ <pt x="1071" y="169" on="1"/>
+ <pt x="1001" y="99" on="1"/>
+ <pt x="577" y="523" on="1"/>
+ <pt x="154" y="99" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 1 11 10 9 8 7 6 5 4 3 2 1 0 12 13 1 0 14 11 10 9 8 7 6 5
+ 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="n" xMin="37" yMin="0" xMax="1018" yMax="1110">
+ <contour>
+ <pt x="37" y="0" on="1"/>
+ <pt x="37" y="62" on="1"/>
+ <pt x="56" y="63" on="1"/>
+ <pt x="129" y="67" on="0"/>
+ <pt x="142" y="89" on="1"/>
+ <pt x="155" y="108" on="0"/>
+ <pt x="156" y="160" on="1"/>
+ <pt x="158" y="259" on="1"/>
+ <pt x="158" y="827" on="1"/>
+ <pt x="156" y="925" on="1"/>
+ <pt x="156" y="993" on="0"/>
+ <pt x="131" y="1007" on="1"/>
+ <pt x="111" y="1019" on="0"/>
+ <pt x="56" y="1023" on="1"/>
+ <pt x="37" y="1024" on="1"/>
+ <pt x="37" y="1086" on="1"/>
+ <pt x="356" y="1086" on="1"/>
+ <pt x="356" y="907" on="1"/>
+ <pt x="420" y="999" on="0"/>
+ <pt x="480" y="1044" on="1"/>
+ <pt x="566" y="1110" on="0"/>
+ <pt x="667" y="1110" on="1"/>
+ <pt x="791" y="1110" on="0"/>
+ <pt x="844" y="1032" on="1"/>
+ <pt x="897" y="954" on="0"/>
+ <pt x="897" y="765" on="1"/>
+ <pt x="897" y="259" on="1"/>
+ <pt x="899" y="160" on="1"/>
+ <pt x="899" y="92" on="0"/>
+ <pt x="924" y="78" on="1"/>
+ <pt x="946" y="66" on="0"/>
+ <pt x="1000" y="63" on="1"/>
+ <pt x="1018" y="62" on="1"/>
+ <pt x="1018" y="0" on="1"/>
+ <pt x="579" y="0" on="1"/>
+ <pt x="579" y="62" on="1"/>
+ <pt x="598" y="63" on="1"/>
+ <pt x="675" y="68" on="0"/>
+ <pt x="687" y="92" on="1"/>
+ <pt x="698" y="112" on="0"/>
+ <pt x="698" y="160" on="1"/>
+ <pt x="700" y="259" on="1"/>
+ <pt x="700" y="734" on="1"/>
+ <pt x="697" y="811" on="1"/>
+ <pt x="694" y="900" on="0"/>
+ <pt x="672" y="937" on="1"/>
+ <pt x="647" y="981" on="0"/>
+ <pt x="592" y="981" on="1"/>
+ <pt x="477" y="981" on="0"/>
+ <pt x="356" y="840" on="1"/>
+ <pt x="356" y="259" on="1"/>
+ <pt x="357" y="160" on="1"/>
+ <pt x="358" y="91" on="0"/>
+ <pt x="383" y="78" on="1"/>
+ <pt x="405" y="66" on="0"/>
+ <pt x="458" y="63" on="1"/>
+ <pt x="477" y="62" on="1"/>
+ <pt x="477" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 47 29 21 48 84 21 1 51 57 50 49 42 41 35 32 26 25 17 14 8 7 1 13
+ 15 0 3 57 34 33 0 3 0 16 15 1 14 57 51 51 35 34 3 41 16 3 33 32 2
+ 13 25 15 14 1 0 4 13 7 0 0 42 41 4 1 25 50 49 17 16 4 3 7 2 4
+ 48 196 26 25 1 8 7 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nacute" xMin="37" yMin="0" xMax="1018" yMax="1604">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="271" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="napostrophe" xMin="25" yMin="0" xMax="1230" yMax="1579">
+ <contour>
+ <pt x="249" y="0" on="1"/>
+ <pt x="249" y="62" on="1"/>
+ <pt x="268" y="63" on="1"/>
+ <pt x="341" y="68" on="0"/>
+ <pt x="354" y="89" on="1"/>
+ <pt x="367" y="109" on="0"/>
+ <pt x="368" y="160" on="1"/>
+ <pt x="370" y="259" on="1"/>
+ <pt x="370" y="827" on="1"/>
+ <pt x="368" y="925" on="1"/>
+ <pt x="367" y="994" on="0"/>
+ <pt x="343" y="1007" on="1"/>
+ <pt x="322" y="1019" on="0"/>
+ <pt x="268" y="1023" on="1"/>
+ <pt x="249" y="1024" on="1"/>
+ <pt x="249" y="1086" on="1"/>
+ <pt x="568" y="1086" on="1"/>
+ <pt x="568" y="907" on="1"/>
+ <pt x="632" y="998" on="0"/>
+ <pt x="692" y="1044" on="1"/>
+ <pt x="777" y="1110" on="0"/>
+ <pt x="879" y="1110" on="1"/>
+ <pt x="1003" y="1110" on="0"/>
+ <pt x="1056" y="1032" on="1"/>
+ <pt x="1109" y="954" on="0"/>
+ <pt x="1109" y="765" on="1"/>
+ <pt x="1109" y="259" on="1"/>
+ <pt x="1111" y="160" on="1"/>
+ <pt x="1112" y="91" on="0"/>
+ <pt x="1136" y="78" on="1"/>
+ <pt x="1158" y="66" on="0"/>
+ <pt x="1212" y="63" on="1"/>
+ <pt x="1230" y="62" on="1"/>
+ <pt x="1230" y="0" on="1"/>
+ <pt x="791" y="0" on="1"/>
+ <pt x="791" y="62" on="1"/>
+ <pt x="810" y="63" on="1"/>
+ <pt x="883" y="68" on="0"/>
+ <pt x="897" y="89" on="1"/>
+ <pt x="909" y="109" on="0"/>
+ <pt x="910" y="160" on="1"/>
+ <pt x="912" y="259" on="1"/>
+ <pt x="912" y="734" on="1"/>
+ <pt x="909" y="811" on="1"/>
+ <pt x="906" y="900" on="0"/>
+ <pt x="884" y="937" on="1"/>
+ <pt x="859" y="981" on="0"/>
+ <pt x="804" y="981" on="1"/>
+ <pt x="689" y="981" on="0"/>
+ <pt x="568" y="840" on="1"/>
+ <pt x="568" y="259" on="1"/>
+ <pt x="569" y="160" on="1"/>
+ <pt x="570" y="91" on="0"/>
+ <pt x="595" y="78" on="1"/>
+ <pt x="617" y="66" on="0"/>
+ <pt x="670" y="63" on="1"/>
+ <pt x="689" y="62" on="1"/>
+ <pt x="689" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="104" y="1382" on="1"/>
+ <pt x="25" y="1382" on="1"/>
+ <pt x="25" y="1579" on="1"/>
+ <pt x="222" y="1579" on="1"/>
+ <pt x="222" y="1408" on="1"/>
+ <pt x="222" y="1245" on="0"/>
+ <pt x="160" y="1180" on="1"/>
+ <pt x="113" y="1131" on="0"/>
+ <pt x="25" y="1125" on="1"/>
+ <pt x="25" y="1175" on="1"/>
+ <pt x="104" y="1181" on="0"/>
+ <pt x="104" y="1330" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 116 values pushed */
+ 0 0 47 29 21 48 84 21 1 51 57 69 67 66 62 59 58 6 60 15 3 50 49 42 41
+ 35 32 26 25 17 14 8 7 1 13 15 0 3 61 60 1 57 34 33 0 3 2 0 16 15
+ 1 14 57 51 51 35 34 3 41 16 3 15 14 1 0 4 7 61 3 69 58 2 61 59 3
+ 33 32 2 13 25 0 0 62 61 4 1 59 42 41 4 1 25 50 49 17 16 4 3 7 3
+ 4 48 196 67 66 60 59 3 26 25 1 8 7 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nbhyphen" xMin="82" yMin="543" xMax="600" yMax="666">
+ <contour>
+ <pt x="82" y="543" on="1"/>
+ <pt x="82" y="666" on="1"/>
+ <pt x="600" y="666" on="1"/>
+ <pt x="600" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ncaron" xMin="37" yMin="0" xMax="1018" yMax="1604">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="162" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ncommaaccent" xMin="37" yMin="-432" xMax="1018" yMax="1110">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="233" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="nine" xMin="37" yMin="-37" xMax="975" yMax="1518">
+ <contour>
+ <pt x="764" y="723" on="1"/>
+ <pt x="713" y="637" on="0"/>
+ <pt x="654" y="593" on="1"/>
+ <pt x="568" y="530" on="0"/>
+ <pt x="449" y="530" on="1"/>
+ <pt x="269" y="530" on="0"/>
+ <pt x="153" y="659" on="1"/>
+ <pt x="37" y="789" on="0"/>
+ <pt x="37" y="993" on="1"/>
+ <pt x="37" y="1216" on="0"/>
+ <pt x="171" y="1367" on="1"/>
+ <pt x="305" y="1518" on="0"/>
+ <pt x="502" y="1518" on="1"/>
+ <pt x="721" y="1518" on="0"/>
+ <pt x="848" y="1320" on="1"/>
+ <pt x="975" y="1121" on="0"/>
+ <pt x="975" y="779" on="1"/>
+ <pt x="975" y="402" on="0"/>
+ <pt x="827" y="183" on="1"/>
+ <pt x="679" y="-37" on="0"/>
+ <pt x="416" y="-37" on="1"/>
+ <pt x="251" y="-37" on="0"/>
+ <pt x="120" y="29" on="1"/>
+ <pt x="120" y="253" on="1"/>
+ <pt x="219" y="253" on="1"/>
+ <pt x="220" y="232" on="1"/>
+ <pt x="225" y="120" on="0"/>
+ <pt x="270" y="75" on="1"/>
+ <pt x="313" y="31" on="0"/>
+ <pt x="412" y="31" on="1"/>
+ <pt x="600" y="31" on="0"/>
+ <pt x="694" y="269" on="1"/>
+ <pt x="761" y="439" on="0"/>
+ </contour>
+ <contour>
+ <pt x="472" y="1450" on="1"/>
+ <pt x="364" y="1450" on="0"/>
+ <pt x="301" y="1333" on="1"/>
+ <pt x="237" y="1215" on="0"/>
+ <pt x="237" y="1018" on="1"/>
+ <pt x="237" y="600" on="0"/>
+ <pt x="499" y="600" on="1"/>
+ <pt x="610" y="600" on="0"/>
+ <pt x="684" y="695" on="1"/>
+ <pt x="759" y="791" on="0"/>
+ <pt x="759" y="940" on="1"/>
+ <pt x="759" y="1128" on="0"/>
+ <pt x="691" y="1271" on="1"/>
+ <pt x="606" y="1450" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 0 0 39 17 4 33 17 12 29 17 20 48 84 20 2 12 0 4 1 1 24 23 22 4 0
+ 5 0 2 3 0 0 14 0 0 43 10 16 37 5 8 48 196 24 0 2 13 16 22 8 22
+ 23 22 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nonbreakingspace"/><!-- contains no outline data -->
+
+ <TTGlyph name="ntilde" xMin="37" yMin="0" xMax="1018" yMax="1518">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="175" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="numbersign" xMin="0" yMin="0" xMax="1024" yMax="1480">
+ <contour>
+ <pt x="93" y="0" on="1"/>
+ <pt x="207" y="456" on="1"/>
+ <pt x="0" y="456" on="1"/>
+ <pt x="19" y="555" on="1"/>
+ <pt x="232" y="555" on="1"/>
+ <pt x="324" y="925" on="1"/>
+ <pt x="93" y="925" on="1"/>
+ <pt x="112" y="1024" on="1"/>
+ <pt x="349" y="1024" on="1"/>
+ <pt x="463" y="1480" on="1"/>
+ <pt x="566" y="1480" on="1"/>
+ <pt x="451" y="1024" on="1"/>
+ <pt x="715" y="1024" on="1"/>
+ <pt x="829" y="1480" on="1"/>
+ <pt x="932" y="1480" on="1"/>
+ <pt x="818" y="1024" on="1"/>
+ <pt x="1024" y="1024" on="1"/>
+ <pt x="1006" y="925" on="1"/>
+ <pt x="793" y="925" on="1"/>
+ <pt x="701" y="555" on="1"/>
+ <pt x="931" y="555" on="1"/>
+ <pt x="913" y="456" on="1"/>
+ <pt x="676" y="456" on="1"/>
+ <pt x="562" y="0" on="1"/>
+ <pt x="459" y="0" on="1"/>
+ <pt x="573" y="456" on="1"/>
+ <pt x="310" y="456" on="1"/>
+ <pt x="195" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="334" y="555" on="1"/>
+ <pt x="598" y="555" on="1"/>
+ <pt x="690" y="925" on="1"/>
+ <pt x="427" y="925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 14 13 10 9 4 13 7 27 24 23 0 4 13 1 0 0 31 30 18 17 6 5 9 5 7
+ 26 25 22 21 2 1 9 5 3 2 4 48 84 16 15 12 11 8 7 5 29 28 20 19 4
+ 3 5 2 0 14 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
+ 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="o" xMin="62" yMin="-25" xMax="962" yMax="1110">
+ <contour>
+ <pt x="512" y="1110" on="1"/>
+ <pt x="719" y="1110" on="0"/>
+ <pt x="840" y="957" on="1"/>
+ <pt x="962" y="805" on="0"/>
+ <pt x="962" y="544" on="1"/>
+ <pt x="962" y="279" on="0"/>
+ <pt x="840" y="127" on="1"/>
+ <pt x="719" y="-25" on="0"/>
+ <pt x="506" y="-25" on="1"/>
+ <pt x="324" y="-25" on="0"/>
+ <pt x="209" y="99" on="1"/>
+ <pt x="62" y="257" on="0"/>
+ <pt x="62" y="543" on="1"/>
+ <pt x="62" y="805" on="0"/>
+ <pt x="183" y="957" on="1"/>
+ <pt x="305" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="512" y="1043" on="1"/>
+ <pt x="404" y="1043" on="0"/>
+ <pt x="341" y="908" on="1"/>
+ <pt x="278" y="772" on="0"/>
+ <pt x="278" y="538" on="1"/>
+ <pt x="278" y="43" on="0"/>
+ <pt x="517" y="43" on="1"/>
+ <pt x="607" y="43" on="0"/>
+ <pt x="667" y="147" on="1"/>
+ <pt x="747" y="286" on="0"/>
+ <pt x="747" y="545" on="1"/>
+ <pt x="747" y="772" on="0"/>
+ <pt x="683" y="908" on="1"/>
+ <pt x="620" y="1043" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 22 17 8 16 17 0 48 84 8 2 0 1 14 0 0 26 10 4 20 10 12 48 196
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="oacute" xMin="62" yMin="-25" xMax="962" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="255" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="obreve" xMin="62" yMin="-25" xMax="962" yMax="1604">
+ <contour>
+ <pt x="512" y="1110" on="1"/>
+ <pt x="719" y="1110" on="0"/>
+ <pt x="840" y="957" on="1"/>
+ <pt x="962" y="805" on="0"/>
+ <pt x="962" y="544" on="1"/>
+ <pt x="962" y="279" on="0"/>
+ <pt x="840" y="127" on="1"/>
+ <pt x="719" y="-25" on="0"/>
+ <pt x="506" y="-25" on="1"/>
+ <pt x="324" y="-25" on="0"/>
+ <pt x="209" y="99" on="1"/>
+ <pt x="62" y="257" on="0"/>
+ <pt x="62" y="543" on="1"/>
+ <pt x="62" y="805" on="0"/>
+ <pt x="183" y="957" on="1"/>
+ <pt x="305" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="512" y="1043" on="1"/>
+ <pt x="404" y="1043" on="0"/>
+ <pt x="341" y="908" on="1"/>
+ <pt x="278" y="772" on="0"/>
+ <pt x="278" y="538" on="1"/>
+ <pt x="278" y="43" on="0"/>
+ <pt x="517" y="43" on="1"/>
+ <pt x="607" y="43" on="0"/>
+ <pt x="667" y="147" on="1"/>
+ <pt x="747" y="286" on="0"/>
+ <pt x="747" y="545" on="1"/>
+ <pt x="747" y="772" on="0"/>
+ <pt x="683" y="908" on="1"/>
+ <pt x="620" y="1043" on="0"/>
+ </contour>
+ <contour>
+ <pt x="179" y="1604" on="1"/>
+ <pt x="244" y="1604" on="1"/>
+ <pt x="271" y="1514" on="0"/>
+ <pt x="331" y="1472" on="1"/>
+ <pt x="399" y="1425" on="0"/>
+ <pt x="512" y="1425" on="1"/>
+ <pt x="638" y="1425" on="0"/>
+ <pt x="708" y="1484" on="1"/>
+ <pt x="756" y="1523" on="0"/>
+ <pt x="781" y="1604" on="1"/>
+ <pt x="845" y="1604" on="1"/>
+ <pt x="826" y="1469" on="0"/>
+ <pt x="754" y="1388" on="1"/>
+ <pt x="659" y="1283" on="0"/>
+ <pt x="512" y="1283" on="1"/>
+ <pt x="359" y="1283" on="0"/>
+ <pt x="263" y="1398" on="1"/>
+ <pt x="198" y="1475" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 35 20 44 22 38 8 16 38 0 48 84 8 2 0 1 1 40 39 31 30 4 13 44
+ 1 0 14 0 0 26 40 4 20 40 12 48 196 40 39 31 30 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ocircumflex" xMin="62" yMin="-25" xMax="962" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="171" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="odieresis" xMin="62" yMin="-25" xMax="962" yMax="1456">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="172" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="oe" xMin="62" yMin="-25" xMax="1417" yMax="1110">
+ <contour>
+ <pt x="790" y="927" on="1"/>
+ <pt x="906" y="1109" on="0"/>
+ <pt x="1071" y="1109" on="1"/>
+ <pt x="1234" y="1109" on="0"/>
+ <pt x="1325" y="977" on="1"/>
+ <pt x="1417" y="845" on="0"/>
+ <pt x="1417" y="603" on="1"/>
+ <pt x="1417" y="585" on="1"/>
+ <pt x="904" y="585" on="1"/>
+ <pt x="909" y="345" on="0"/>
+ <pt x="960" y="230" on="1"/>
+ <pt x="1031" y="74" on="0"/>
+ <pt x="1184" y="74" on="1"/>
+ <pt x="1284" y="74" on="0"/>
+ <pt x="1417" y="146" on="1"/>
+ <pt x="1417" y="46" on="1"/>
+ <pt x="1268" y="-25" on="0"/>
+ <pt x="1144" y="-25" on="1"/>
+ <pt x="1008" y="-25" on="0"/>
+ <pt x="907" y="54" on="1"/>
+ <pt x="847" y="100" on="0"/>
+ <pt x="790" y="188" on="1"/>
+ <pt x="718" y="71" on="0"/>
+ <pt x="664" y="27" on="1"/>
+ <pt x="600" y="-25" on="0"/>
+ <pt x="495" y="-25" on="1"/>
+ <pt x="304" y="-25" on="0"/>
+ <pt x="183" y="134" on="1"/>
+ <pt x="62" y="292" on="0"/>
+ <pt x="62" y="543" on="1"/>
+ <pt x="62" y="791" on="0"/>
+ <pt x="183" y="951" on="1"/>
+ <pt x="303" y="1110" on="0"/>
+ <pt x="491" y="1110" on="1"/>
+ <pt x="614" y="1110" on="0"/>
+ <pt x="698" y="1042" on="1"/>
+ <pt x="747" y="1003" on="0"/>
+ </contour>
+ <contour>
+ <pt x="500" y="1047" on="1"/>
+ <pt x="273" y="1047" on="0"/>
+ <pt x="273" y="532" on="1"/>
+ <pt x="273" y="38" on="0"/>
+ <pt x="503" y="38" on="1"/>
+ <pt x="629" y="38" on="0"/>
+ <pt x="665" y="197" on="1"/>
+ <pt x="692" y="317" on="0"/>
+ <pt x="692" y="550" on="1"/>
+ <pt x="692" y="823" on="0"/>
+ <pt x="649" y="934" on="1"/>
+ <pt x="606" y="1047" on="0"/>
+ </contour>
+ <contour>
+ <pt x="905" y="648" on="1"/>
+ <pt x="1207" y="648" on="1"/>
+ <pt x="1207" y="692" on="1"/>
+ <pt x="1207" y="1049" on="0"/>
+ <pt x="1064" y="1049" on="1"/>
+ <pt x="973" y="1049" on="0"/>
+ <pt x="935" y="919" on="1"/>
+ <pt x="907" y="827" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 53 11 2 41 11 25 37 11 33 12 9 17 48 84 33 1 25 2 17 2 2 1 1
+ 51 0 2 1 49 3 0 6 49 7 2 1 21 15 14 3 7 2 3 0 0 0 8 7 14
+ 1 49 1 4 48 84 50 49 1 0 14 0 0 39 10 29 48 196 51 50 49 45 29 21 15
+ 14 8 7 6 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ogonek" xMin="156" yMin="-370" xMax="525" yMax="0">
+ <contour>
+ <pt x="525" y="-273" on="1"/>
+ <pt x="525" y="-341" on="1"/>
+ <pt x="454" y="-370" on="0"/>
+ <pt x="376" y="-370" on="1"/>
+ <pt x="156" y="-370" on="0"/>
+ <pt x="156" y="-211" on="1"/>
+ <pt x="156" y="-89" on="0"/>
+ <pt x="314" y="0" on="1"/>
+ <pt x="421" y="0" on="1"/>
+ <pt x="292" y="-80" on="0"/>
+ <pt x="292" y="-182" on="1"/>
+ <pt x="292" y="-289" on="0"/>
+ <pt x="425" y="-289" on="1"/>
+ <pt x="476" y="-289" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 12 7 3 48 84 8 7 3 1 0 14 0 0 10 48 5 48 196 8 7 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ograve" xMin="62" yMin="-25" xMax="962" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="88" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ohungarumlaut" xMin="62" yMin="-25" xMax="962" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="hungarumlaut" x="258" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="omacron" xMin="62" yMin="-25" xMax="962" yMax="1406">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="171" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="130" yMin="0" xMax="895" yMax="1493">
+ <contour>
+ <pt x="611" y="1493" on="1"/>
+ <pt x="611" y="259" on="1"/>
+ <pt x="617" y="160" on="1"/>
+ <pt x="622" y="89" on="0"/>
+ <pt x="666" y="75" on="1"/>
+ <pt x="701" y="63" on="0"/>
+ <pt x="778" y="63" on="1"/>
+ <pt x="895" y="62" on="1"/>
+ <pt x="895" y="0" on="1"/>
+ <pt x="130" y="0" on="1"/>
+ <pt x="130" y="62" on="1"/>
+ <pt x="247" y="63" on="1"/>
+ <pt x="296" y="64" on="0"/>
+ <pt x="357" y="74" on="1"/>
+ <pt x="384" y="80" on="0"/>
+ <pt x="392" y="92" on="1"/>
+ <pt x="414" y="129" on="0"/>
+ <pt x="414" y="259" on="1"/>
+ <pt x="414" y="1177" on="1"/>
+ <pt x="408" y="1278" on="1"/>
+ <pt x="404" y="1349" on="0"/>
+ <pt x="367" y="1349" on="1"/>
+ <pt x="338" y="1349" on="0"/>
+ <pt x="229" y="1329" on="1"/>
+ <pt x="130" y="1311" on="1"/>
+ <pt x="130" y="1373" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 42 values pushed */
+ 17 9 25 24 18 7 1 0 6 13 21 8 9 8 1 0 14 9 17 8 7 2 13 0 25
+ 24 17 0 0 1 0 4 1 17 1 4 48 196 18 17 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onehalf" xMin="173" yMin="-37" xMax="1388" yMax="1517">
+ <contour>
+ <pt x="173" y="-37" on="1"/>
+ <pt x="1261" y="1517" on="1"/>
+ <pt x="1347" y="1517" on="1"/>
+ <pt x="259" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="173" y="772" on="1"/>
+ <pt x="173" y="810" on="1"/>
+ <pt x="207" y="811" on="1"/>
+ <pt x="252" y="815" on="1"/>
+ <pt x="295" y="818" on="0"/>
+ <pt x="302" y="840" on="1"/>
+ <pt x="309" y="859" on="0"/>
+ <pt x="309" y="909" on="1"/>
+ <pt x="309" y="1344" on="1"/>
+ <pt x="306" y="1395" on="1"/>
+ <pt x="304" y="1431" on="0"/>
+ <pt x="285" y="1431" on="1"/>
+ <pt x="269" y="1431" on="0"/>
+ <pt x="216" y="1421" on="1"/>
+ <pt x="173" y="1413" on="1"/>
+ <pt x="173" y="1453" on="1"/>
+ <pt x="432" y="1517" on="1"/>
+ <pt x="432" y="909" on="1"/>
+ <pt x="432" y="848" on="0"/>
+ <pt x="442" y="831" on="1"/>
+ <pt x="451" y="816" on="0"/>
+ <pt x="490" y="814" on="1"/>
+ <pt x="534" y="811" on="1"/>
+ <pt x="568" y="810" on="1"/>
+ <pt x="568" y="772" on="1"/>
+ </contour>
+ <contour>
+ <pt x="918" y="0" on="1"/>
+ <pt x="918" y="49" on="1"/>
+ <pt x="959" y="165" on="0"/>
+ <pt x="1070" y="267" on="1"/>
+ <pt x="1111" y="305" on="1"/>
+ <pt x="1258" y="441" on="0"/>
+ <pt x="1258" y="562" on="1"/>
+ <pt x="1258" y="718" on="0"/>
+ <pt x="1121" y="718" on="1"/>
+ <pt x="1061" y="718" on="0"/>
+ <pt x="995" y="669" on="1"/>
+ <pt x="995" y="579" on="1"/>
+ <pt x="936" y="579" on="1"/>
+ <pt x="936" y="715" on="1"/>
+ <pt x="1045" y="758" on="0"/>
+ <pt x="1145" y="758" on="1"/>
+ <pt x="1253" y="758" on="0"/>
+ <pt x="1321" y="702" on="1"/>
+ <pt x="1388" y="646" on="0"/>
+ <pt x="1388" y="560" on="1"/>
+ <pt x="1388" y="452" on="0"/>
+ <pt x="1257" y="356" on="1"/>
+ <pt x="1226" y="334" on="0"/>
+ <pt x="1202" y="318" on="1"/>
+ <pt x="1152" y="281" on="1"/>
+ <pt x="1040" y="199" on="0"/>
+ <pt x="1030" y="105" on="1"/>
+ <pt x="1386" y="105" on="1"/>
+ <pt x="1386" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 106 values pushed */
+ 0 0 37 45 44 48 84 44 44 42 41 40 39 5 4 55 3 30 55 29 2 27 21 20 19
+ 18 12 11 5 2 1 10 13 15 4 3 0 29 0 0 56 55 43 1 29 1 4 48 84 57
+ 29 1 28 4 1 2 0 14 0 0 35 44 48 48 196 57 56 55 42 41 40 39 30 29 28
+ 27 2 1 13 13 48 20 19 18 5 4 3 0 6 13 11 0 0 21 20 12 1 11 1 4
+ 48 196 12 11 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onequarter" xMin="173" yMin="-37" xMax="1364" yMax="1517">
+ <contour>
+ <pt x="173" y="-37" on="1"/>
+ <pt x="1261" y="1517" on="1"/>
+ <pt x="1347" y="1517" on="1"/>
+ <pt x="259" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1065" y="0" on="1"/>
+ <pt x="1065" y="39" on="1"/>
+ <pt x="1075" y="39" on="1"/>
+ <pt x="1125" y="39" on="0"/>
+ <pt x="1139" y="48" on="1"/>
+ <pt x="1153" y="57" on="0"/>
+ <pt x="1155" y="88" on="1"/>
+ <pt x="1158" y="137" on="1"/>
+ <pt x="1158" y="205" on="1"/>
+ <pt x="813" y="205" on="1"/>
+ <pt x="813" y="271" on="1"/>
+ <pt x="1181" y="751" on="1"/>
+ <pt x="1271" y="751" on="1"/>
+ <pt x="1271" y="294" on="1"/>
+ <pt x="1364" y="294" on="1"/>
+ <pt x="1364" y="205" on="1"/>
+ <pt x="1271" y="205" on="1"/>
+ <pt x="1271" y="137" on="1"/>
+ <pt x="1274" y="88" on="1"/>
+ <pt x="1276" y="52" on="0"/>
+ <pt x="1297" y="45" on="1"/>
+ <pt x="1313" y="39" on="0"/>
+ <pt x="1348" y="39" on="1"/>
+ <pt x="1358" y="39" on="1"/>
+ <pt x="1358" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="878" y="294" on="1"/>
+ <pt x="1158" y="294" on="1"/>
+ <pt x="1158" y="658" on="1"/>
+ </contour>
+ <contour>
+ <pt x="173" y="772" on="1"/>
+ <pt x="173" y="810" on="1"/>
+ <pt x="207" y="811" on="1"/>
+ <pt x="252" y="815" on="1"/>
+ <pt x="295" y="818" on="0"/>
+ <pt x="302" y="840" on="1"/>
+ <pt x="309" y="859" on="0"/>
+ <pt x="309" y="909" on="1"/>
+ <pt x="309" y="1344" on="1"/>
+ <pt x="306" y="1395" on="1"/>
+ <pt x="304" y="1431" on="0"/>
+ <pt x="285" y="1431" on="1"/>
+ <pt x="269" y="1431" on="0"/>
+ <pt x="216" y="1421" on="1"/>
+ <pt x="173" y="1413" on="1"/>
+ <pt x="173" y="1453" on="1"/>
+ <pt x="432" y="1517" on="1"/>
+ <pt x="432" y="909" on="1"/>
+ <pt x="432" y="848" on="0"/>
+ <pt x="442" y="831" on="1"/>
+ <pt x="451" y="816" on="0"/>
+ <pt x="490" y="814" on="1"/>
+ <pt x="534" y="811" on="1"/>
+ <pt x="568" y="810" on="1"/>
+ <pt x="568" y="772" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 129 values pushed */
+ 31 16 15 3 32 17 3 14 17 12 2 27 26 21 11 6 5 6 12 4 3 55 49 48 47
+ 46 40 39 33 2 1 10 13 43 32 3 0 4 0 0 30 29 18 17 46 3 12 1 4 48
+ 84 56 32 1 20 19 13 12 3 28 4 1 3 0 14 15 1 2 16 11 3 56 55 29 14
+ 13 6 5 4 8 11 48 3 28 27 26 19 18 2 6 13 16 47 46 33 32 3 0 6 13
+ 39 0 0 49 48 12 1 39 31 30 12 11 15 3 16 2 4 48 196 40 39 1 21 20 17
+ 16 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onesuperior" xMin="136" yMin="772" xMax="531" yMax="1517">
+ <contour>
+ <pt x="136" y="772" on="1"/>
+ <pt x="136" y="810" on="1"/>
+ <pt x="170" y="811" on="1"/>
+ <pt x="215" y="815" on="1"/>
+ <pt x="258" y="818" on="0"/>
+ <pt x="265" y="840" on="1"/>
+ <pt x="272" y="860" on="0"/>
+ <pt x="272" y="909" on="1"/>
+ <pt x="272" y="1344" on="1"/>
+ <pt x="269" y="1395" on="1"/>
+ <pt x="267" y="1431" on="0"/>
+ <pt x="248" y="1431" on="1"/>
+ <pt x="234" y="1431" on="0"/>
+ <pt x="179" y="1421" on="1"/>
+ <pt x="136" y="1413" on="1"/>
+ <pt x="136" y="1453" on="1"/>
+ <pt x="395" y="1517" on="1"/>
+ <pt x="395" y="909" on="1"/>
+ <pt x="395" y="848" on="0"/>
+ <pt x="405" y="831" on="1"/>
+ <pt x="414" y="816" on="0"/>
+ <pt x="453" y="814" on="1"/>
+ <pt x="497" y="811" on="1"/>
+ <pt x="531" y="810" on="1"/>
+ <pt x="531" y="772" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 23 17 16 15 14 8 7 1 8 13 11 0 24 0 1 0 14 24 23 2 13 16 15 14 1
+ 0 4 13 7 0 0 17 16 12 1 7 1 4 48 196 8 7 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ordfeminine" xMin="25" yMin="830" xMax="561" yMax="1517">
+ <contour>
+ <pt x="363" y="925" on="1"/>
+ <pt x="282" y="830" on="0"/>
+ <pt x="193" y="830" on="1"/>
+ <pt x="25" y="830" on="0"/>
+ <pt x="25" y="1007" on="1"/>
+ <pt x="25" y="1222" on="0"/>
+ <pt x="317" y="1222" on="1"/>
+ <pt x="363" y="1222" on="1"/>
+ <pt x="363" y="1283" on="1"/>
+ <pt x="363" y="1388" on="0"/>
+ <pt x="341" y="1426" on="1"/>
+ <pt x="318" y="1465" on="0"/>
+ <pt x="257" y="1465" on="1"/>
+ <pt x="161" y="1465" on="0"/>
+ <pt x="161" y="1356" on="1"/>
+ <pt x="161" y="1338" on="1"/>
+ <pt x="59" y="1338" on="1"/>
+ <pt x="59" y="1462" on="1"/>
+ <pt x="157" y="1517" on="0"/>
+ <pt x="276" y="1517" on="1"/>
+ <pt x="401" y="1517" on="0"/>
+ <pt x="450" y="1466" on="1"/>
+ <pt x="499" y="1416" on="0"/>
+ <pt x="499" y="1283" on="1"/>
+ <pt x="499" y="1024" on="1"/>
+ <pt x="499" y="919" on="0"/>
+ <pt x="539" y="919" on="1"/>
+ <pt x="547" y="919" on="0"/>
+ <pt x="561" y="922" on="1"/>
+ <pt x="561" y="866" on="1"/>
+ <pt x="512" y="830" on="0"/>
+ <pt x="466" y="830" on="1"/>
+ <pt x="392" y="830" on="0"/>
+ </contour>
+ <contour>
+ <pt x="363" y="989" on="1"/>
+ <pt x="363" y="1171" on="1"/>
+ <pt x="326" y="1171" on="1"/>
+ <pt x="173" y="1171" on="0"/>
+ <pt x="173" y="1018" on="1"/>
+ <pt x="173" y="915" on="0"/>
+ <pt x="249" y="915" on="1"/>
+ <pt x="300" y="915" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 78 values pushed */
+ 0 0 39 7 2 12 25 19 48 84 19 0 1 35 34 33 29 28 24 23 17 16 15 14 8
+ 7 6 0 15 13 31 26 2 3 12 0 0 14 0 0 37 47 4 48 196 29 28 2 13 23
+ 35 17 16 15 14 6 6 13 4 0 0 0 34 33 8 7 0 23 4 23 1 4 48 196 24
+ 23 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ordmasculine" xMin="25" yMin="830" xMax="611" yMax="1517">
+ <contour>
+ <pt x="318" y="1517" on="1"/>
+ <pt x="451" y="1517" on="0"/>
+ <pt x="531" y="1424" on="1"/>
+ <pt x="611" y="1331" on="0"/>
+ <pt x="611" y="1174" on="1"/>
+ <pt x="611" y="1015" on="0"/>
+ <pt x="531" y="923" on="1"/>
+ <pt x="450" y="830" on="0"/>
+ <pt x="314" y="830" on="1"/>
+ <pt x="197" y="830" on="0"/>
+ <pt x="121" y="906" on="1"/>
+ <pt x="25" y="1002" on="0"/>
+ <pt x="25" y="1174" on="1"/>
+ <pt x="25" y="1331" on="0"/>
+ <pt x="105" y="1424" on="1"/>
+ <pt x="184" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="318" y="1465" on="1"/>
+ <pt x="182" y="1465" on="0"/>
+ <pt x="182" y="1174" on="1"/>
+ <pt x="182" y="883" on="0"/>
+ <pt x="322" y="883" on="1"/>
+ <pt x="453" y="883" on="0"/>
+ <pt x="453" y="1168" on="1"/>
+ <pt x="453" y="1465" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 20 25 8 16 25 0 48 84 0 0 1 8 0 0 14 0 0 22 24 4 18 24 12
+ 48 196 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="oslash" xMin="62" yMin="-25" xMax="963" yMax="1110">
+ <contour>
+ <pt x="62" y="-25" on="1"/>
+ <pt x="177" y="138" on="1"/>
+ <pt x="62" y="310" on="0"/>
+ <pt x="62" y="544" on="1"/>
+ <pt x="62" y="804" on="0"/>
+ <pt x="183" y="957" on="1"/>
+ <pt x="304" y="1110" on="0"/>
+ <pt x="511" y="1110" on="1"/>
+ <pt x="677" y="1110" on="0"/>
+ <pt x="795" y="1008" on="1"/>
+ <pt x="867" y="1110" on="1"/>
+ <pt x="963" y="1110" on="1"/>
+ <pt x="847" y="948" on="1"/>
+ <pt x="963" y="776" on="0"/>
+ <pt x="963" y="540" on="1"/>
+ <pt x="963" y="281" on="0"/>
+ <pt x="841" y="128" on="1"/>
+ <pt x="720" y="-25" on="0"/>
+ <pt x="513" y="-25" on="1"/>
+ <pt x="347" y="-25" on="0"/>
+ <pt x="230" y="77" on="1"/>
+ <pt x="158" y="-25" on="1"/>
+ </contour>
+ <contour>
+ <pt x="698" y="873" on="1"/>
+ <pt x="638" y="1043" on="0"/>
+ <pt x="513" y="1043" on="1"/>
+ <pt x="404" y="1043" on="0"/>
+ <pt x="341" y="907" on="1"/>
+ <pt x="278" y="772" on="0"/>
+ <pt x="278" y="547" on="1"/>
+ <pt x="278" y="439" on="0"/>
+ <pt x="301" y="312" on="1"/>
+ </contour>
+ <contour>
+ <pt x="326" y="213" on="1"/>
+ <pt x="386" y="43" on="0"/>
+ <pt x="512" y="43" on="1"/>
+ <pt x="621" y="43" on="0"/>
+ <pt x="684" y="179" on="1"/>
+ <pt x="747" y="315" on="0"/>
+ <pt x="747" y="541" on="1"/>
+ <pt x="747" y="644" on="0"/>
+ <pt x="724" y="773" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 33 17 18 24 17 7 48 84 18 2 7 1 1 1 39 31 30 22 20 12 9 1 8
+ 1 2 3 0 0 1 11 10 2 13 1 0 1 21 0 2 0 14 0 0 37 10 14 28 10
+ 3 48 196 39 31 30 22 21 20 14 12 11 10 9 3 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="otilde" xMin="62" yMin="-25" xMax="962" yMax="1518">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="171" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="p" xMin="0" yMin="-395" xMax="956" yMax="1110">
+ <contour>
+ <pt x="0" y="-395" on="1"/>
+ <pt x="0" y="-333" on="1"/>
+ <pt x="19" y="-332" on="1"/>
+ <pt x="92" y="-328" on="0"/>
+ <pt x="105" y="-306" on="1"/>
+ <pt x="118" y="-287" on="0"/>
+ <pt x="119" y="-235" on="1"/>
+ <pt x="121" y="-136" on="1"/>
+ <pt x="121" y="827" on="1"/>
+ <pt x="119" y="925" on="1"/>
+ <pt x="119" y="993" on="0"/>
+ <pt x="94" y="1007" on="1"/>
+ <pt x="74" y="1019" on="0"/>
+ <pt x="19" y="1023" on="1"/>
+ <pt x="0" y="1024" on="1"/>
+ <pt x="0" y="1086" on="1"/>
+ <pt x="318" y="1086" on="1"/>
+ <pt x="318" y="907" on="1"/>
+ <pt x="376" y="998" on="0"/>
+ <pt x="432" y="1044" on="1"/>
+ <pt x="512" y="1110" on="0"/>
+ <pt x="610" y="1110" on="1"/>
+ <pt x="770" y="1110" on="0"/>
+ <pt x="863" y="968" on="1"/>
+ <pt x="956" y="826" on="0"/>
+ <pt x="956" y="575" on="1"/>
+ <pt x="956" y="293" on="0"/>
+ <pt x="835" y="134" on="1"/>
+ <pt x="714" y="-25" on="0"/>
+ <pt x="503" y="-25" on="1"/>
+ <pt x="429" y="-25" on="0"/>
+ <pt x="318" y="0" on="1"/>
+ <pt x="318" y="-136" on="1"/>
+ <pt x="320" y="-235" on="1"/>
+ <pt x="321" y="-304" on="0"/>
+ <pt x="345" y="-317" on="1"/>
+ <pt x="367" y="-329" on="0"/>
+ <pt x="421" y="-332" on="1"/>
+ <pt x="439" y="-333" on="1"/>
+ <pt x="439" y="-395" on="1"/>
+ </contour>
+ <contour>
+ <pt x="318" y="77" on="1"/>
+ <pt x="399" y="54" on="0"/>
+ <pt x="449" y="54" on="1"/>
+ <pt x="585" y="54" on="0"/>
+ <pt x="664" y="181" on="1"/>
+ <pt x="743" y="308" on="0"/>
+ <pt x="743" y="536" on="1"/>
+ <pt x="743" y="983" on="0"/>
+ <pt x="542" y="983" on="1"/>
+ <pt x="449" y="983" on="0"/>
+ <pt x="318" y="837" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 48 29 21 42 21 29 48 84 29 2 21 1 1 50 40 17 14 8 5 15 2 3 0
+ 1 38 32 31 7 1 5 2 0 3 0 39 0 1 0 16 15 1 14 0 0 46 10 25 48
+ 196 39 38 2 13 25 16 15 14 1 0 4 13 7 0 0 50 40 32 31 17 16 4 5 7
+ 1 4 48 196 8 7 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="paragraph" xMin="15" yMin="-296" xMax="805" yMax="1489">
+ <contour>
+ <pt x="484" y="-296" on="1"/>
+ <pt x="484" y="740" on="1"/>
+ <pt x="291" y="744" on="0"/>
+ <pt x="171" y="834" on="1"/>
+ <pt x="15" y="951" on="0"/>
+ <pt x="15" y="1159" on="1"/>
+ <pt x="15" y="1362" on="0"/>
+ <pt x="150" y="1440" on="1"/>
+ <pt x="233" y="1489" on="0"/>
+ <pt x="360" y="1487" on="1"/>
+ <pt x="431" y="1486" on="1"/>
+ <pt x="536" y="1482" on="1"/>
+ <pt x="653" y="1480" on="1"/>
+ <pt x="805" y="1480" on="1"/>
+ <pt x="805" y="-296" on="1"/>
+ <pt x="731" y="-296" on="1"/>
+ <pt x="731" y="1382" on="1"/>
+ <pt x="558" y="1382" on="1"/>
+ <pt x="558" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 1 1 16 2 2 0 1 18 15 14 0 4 13 2 0 0 0 17 16 9 1 12 1 4 48
+ 84 13 12 0 14 12 15 17 2 5 0 0 0 16 15 21 1 13 1 0 21 1 17 2 4
+ 48 196 14 13 1 18 17 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="parenleft" xMin="116" yMin="-296" xMax="579" yMax="1579">
+ <contour>
+ <pt x="579" y="-234" on="1"/>
+ <pt x="579" y="-296" on="1"/>
+ <pt x="384" y="-169" on="0"/>
+ <pt x="268" y="38" on="1"/>
+ <pt x="116" y="312" on="0"/>
+ <pt x="116" y="643" on="1"/>
+ <pt x="116" y="983" on="0"/>
+ <pt x="286" y="1271" on="1"/>
+ <pt x="398" y="1462" on="0"/>
+ <pt x="579" y="1579" on="1"/>
+ <pt x="579" y="1517" on="1"/>
+ <pt x="440" y="1355" on="0"/>
+ <pt x="382" y="1195" on="1"/>
+ <pt x="313" y="1003" on="0"/>
+ <pt x="313" y="642" on="1"/>
+ <pt x="313" y="266" on="0"/>
+ <pt x="389" y="70" on="1"/>
+ <pt x="447" y="-81" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 10 9 1 0 14 0 0 14 5 5 48 196 10 9 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="parenright" xMin="104" yMin="-296" xMax="567" yMax="1579">
+ <contour>
+ <pt x="104" y="1517" on="1"/>
+ <pt x="104" y="1579" on="1"/>
+ <pt x="299" y="1452" on="0"/>
+ <pt x="415" y="1245" on="1"/>
+ <pt x="567" y="971" on="0"/>
+ <pt x="567" y="640" on="1"/>
+ <pt x="567" y="299" on="0"/>
+ <pt x="397" y="12" on="1"/>
+ <pt x="285" y="-178" on="0"/>
+ <pt x="104" y="-296" on="1"/>
+ <pt x="104" y="-234" on="1"/>
+ <pt x="244" y="-72" on="0"/>
+ <pt x="300" y="88" on="1"/>
+ <pt x="369" y="280" on="0"/>
+ <pt x="369" y="639" on="1"/>
+ <pt x="369" y="1016" on="0"/>
+ <pt x="293" y="1214" on="1"/>
+ <pt x="236" y="1363" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 10 9 1 0 14 0 0 14 5 5 48 196 10 9 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="percent" xMin="120" yMin="-37" xMax="1585" yMax="1517">
+ <contour>
+ <pt x="195" y="-37" on="1"/>
+ <pt x="1385" y="1517" on="1"/>
+ <pt x="1509" y="1517" on="1"/>
+ <pt x="320" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="435" y="1480" on="1"/>
+ <pt x="573" y="1480" on="0"/>
+ <pt x="661" y="1377" on="1"/>
+ <pt x="749" y="1274" on="0"/>
+ <pt x="749" y="1110" on="1"/>
+ <pt x="749" y="945" on="0"/>
+ <pt x="660" y="843" on="1"/>
+ <pt x="571" y="740" on="0"/>
+ <pt x="430" y="740" on="1"/>
+ <pt x="309" y="740" on="0"/>
+ <pt x="226" y="824" on="1"/>
+ <pt x="120" y="931" on="0"/>
+ <pt x="120" y="1110" on="1"/>
+ <pt x="120" y="1273" on="0"/>
+ <pt x="208" y="1376" on="1"/>
+ <pt x="296" y="1480" on="0"/>
+ </contour>
+ <contour>
+ <pt x="434" y="1419" on="1"/>
+ <pt x="268" y="1419" on="0"/>
+ <pt x="268" y="1111" on="1"/>
+ <pt x="268" y="802" on="0"/>
+ <pt x="433" y="802" on="1"/>
+ <pt x="601" y="802" on="0"/>
+ <pt x="601" y="1116" on="1"/>
+ <pt x="601" y="1419" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1270" y="740" on="1"/>
+ <pt x="1409" y="740" on="0"/>
+ <pt x="1497" y="636" on="1"/>
+ <pt x="1585" y="533" on="0"/>
+ <pt x="1585" y="370" on="1"/>
+ <pt x="1585" y="205" on="0"/>
+ <pt x="1496" y="103" on="1"/>
+ <pt x="1407" y="0" on="0"/>
+ <pt x="1266" y="0" on="1"/>
+ <pt x="1144" y="0" on="0"/>
+ <pt x="1062" y="84" on="1"/>
+ <pt x="956" y="192" on="0"/>
+ <pt x="956" y="370" on="1"/>
+ <pt x="956" y="533" on="0"/>
+ <pt x="1044" y="636" on="1"/>
+ <pt x="1132" y="740" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1270" y="679" on="1"/>
+ <pt x="1104" y="679" on="0"/>
+ <pt x="1104" y="370" on="1"/>
+ <pt x="1104" y="61" on="0"/>
+ <pt x="1269" y="61" on="1"/>
+ <pt x="1437" y="61" on="0"/>
+ <pt x="1437" y="374" on="1"/>
+ <pt x="1437" y="679" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 69 values pushed */
+ 0 0 48 11 36 44 11 28 24 11 12 20 11 4 48 84 36 2 4 0 28 12 1 1 28
+ 12 2 0 2 3 0 0 1 2 1 2 13 0 0 1 3 0 2 0 14 0 0 50 47 32
+ 46 47 40 26 47 8 22 47 16 48 196 40 32 16 8 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="period" xMin="133" yMin="0" xMax="380" yMax="247">
+ <contour>
+ <pt x="133" y="0" on="1"/>
+ <pt x="133" y="247" on="1"/>
+ <pt x="380" y="247" on="1"/>
+ <pt x="380" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 2 1 6 1 0 1 4 48 84 3 0 1 0 14 0 0 3 2 6 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="periodcentered" xMin="133" yMin="491" xMax="380" yMax="738">
+ <contour>
+ <pt x="133" y="491" on="1"/>
+ <pt x="133" y="738" on="1"/>
+ <pt x="380" y="738" on="1"/>
+ <pt x="380" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 84 2 1 1 0 14 0 0 3 2 6 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="periodcentered#1" xMin="133" yMin="491" xMax="380" yMax="738">
+ <contour>
+ <pt x="133" y="491" on="1"/>
+ <pt x="133" y="738" on="1"/>
+ <pt x="380" y="738" on="1"/>
+ <pt x="380" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 84 2 1 1 0 14 0 0 3 2 6 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="perthousand" xMin="34" yMin="-37" xMax="2014" yMax="1517">
+ <contour>
+ <pt x="349" y="1480" on="1"/>
+ <pt x="487" y="1480" on="0"/>
+ <pt x="575" y="1377" on="1"/>
+ <pt x="663" y="1273" on="0"/>
+ <pt x="663" y="1111" on="1"/>
+ <pt x="663" y="945" on="0"/>
+ <pt x="575" y="843" on="1"/>
+ <pt x="487" y="740" on="0"/>
+ <pt x="345" y="740" on="1"/>
+ <pt x="224" y="740" on="0"/>
+ <pt x="140" y="824" on="1"/>
+ <pt x="34" y="932" on="0"/>
+ <pt x="34" y="1110" on="1"/>
+ <pt x="34" y="1273" on="0"/>
+ <pt x="122" y="1376" on="1"/>
+ <pt x="210" y="1480" on="0"/>
+ </contour>
+ <contour>
+ <pt x="349" y="1419" on="1"/>
+ <pt x="182" y="1419" on="0"/>
+ <pt x="182" y="1111" on="1"/>
+ <pt x="182" y="802" on="0"/>
+ <pt x="347" y="802" on="1"/>
+ <pt x="515" y="802" on="0"/>
+ <pt x="515" y="1112" on="1"/>
+ <pt x="515" y="1419" on="0"/>
+ </contour>
+ <contour>
+ <pt x="972" y="740" on="1"/>
+ <pt x="1110" y="740" on="0"/>
+ <pt x="1198" y="636" on="1"/>
+ <pt x="1286" y="532" on="0"/>
+ <pt x="1286" y="370" on="1"/>
+ <pt x="1286" y="205" on="0"/>
+ <pt x="1198" y="103" on="1"/>
+ <pt x="1110" y="0" on="0"/>
+ <pt x="968" y="0" on="1"/>
+ <pt x="847" y="0" on="0"/>
+ <pt x="763" y="84" on="1"/>
+ <pt x="657" y="192" on="0"/>
+ <pt x="657" y="370" on="1"/>
+ <pt x="657" y="532" on="0"/>
+ <pt x="745" y="636" on="1"/>
+ <pt x="834" y="740" on="0"/>
+ </contour>
+ <contour>
+ <pt x="972" y="679" on="1"/>
+ <pt x="805" y="679" on="0"/>
+ <pt x="805" y="371" on="1"/>
+ <pt x="805" y="61" on="0"/>
+ <pt x="971" y="61" on="1"/>
+ <pt x="1138" y="61" on="0"/>
+ <pt x="1138" y="371" on="1"/>
+ <pt x="1138" y="679" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1700" y="740" on="1"/>
+ <pt x="1838" y="740" on="0"/>
+ <pt x="1926" y="636" on="1"/>
+ <pt x="2014" y="532" on="0"/>
+ <pt x="2014" y="370" on="1"/>
+ <pt x="2014" y="205" on="0"/>
+ <pt x="1926" y="103" on="1"/>
+ <pt x="1838" y="0" on="0"/>
+ <pt x="1696" y="0" on="1"/>
+ <pt x="1575" y="0" on="0"/>
+ <pt x="1491" y="84" on="1"/>
+ <pt x="1385" y="192" on="0"/>
+ <pt x="1385" y="370" on="1"/>
+ <pt x="1385" y="532" on="0"/>
+ <pt x="1473" y="636" on="1"/>
+ <pt x="1562" y="740" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1700" y="679" on="1"/>
+ <pt x="1533" y="679" on="0"/>
+ <pt x="1533" y="371" on="1"/>
+ <pt x="1533" y="61" on="0"/>
+ <pt x="1698" y="61" on="1"/>
+ <pt x="1866" y="61" on="0"/>
+ <pt x="1866" y="375" on="1"/>
+ <pt x="1866" y="679" on="0"/>
+ </contour>
+ <contour>
+ <pt x="73" y="-37" on="1"/>
+ <pt x="1162" y="1517" on="1"/>
+ <pt x="1248" y="1517" on="1"/>
+ <pt x="160" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 68 11 56 64 11 48 44 11 32 40 11 24 20 11 8 16 11 0 48 84 56 2 32
+ 2 0 0 48 24 8 1 1 48 24 8 3 0 2 3 0 0 1 74 73 2 13 0 0 1
+ 75 72 2 0 14 0 0 70 47 52 66 47 60 46 47 28 42 47 36 22 47 4 18 47 12
+ 48 196 75 74 73 72 60 52 36 28 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="plus" xMin="84" yMin="99" xMax="1071" yMax="1086">
+ <contour>
+ <pt x="528" y="99" on="1"/>
+ <pt x="528" y="543" on="1"/>
+ <pt x="84" y="543" on="1"/>
+ <pt x="84" y="642" on="1"/>
+ <pt x="528" y="642" on="1"/>
+ <pt x="528" y="1086" on="1"/>
+ <pt x="627" y="1086" on="1"/>
+ <pt x="627" y="642" on="1"/>
+ <pt x="1071" y="642" on="1"/>
+ <pt x="1071" y="543" on="1"/>
+ <pt x="627" y="543" on="1"/>
+ <pt x="627" y="99" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 55 values pushed */
+ 6 5 2 13 3 11 0 1 0 0 10 9 2 1 9 3 3 1 4 48 84 8 7 4 3
+ 3 0 14 9 8 2 13 6 3 2 0 0 0 11 10 7 6 9 3 0 1 4 48 196 5
+ 4 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="plusminus" xMin="84" yMin="0" xMax="1071" yMax="1184">
+ <contour>
+ <pt x="84" y="0" on="1"/>
+ <pt x="84" y="99" on="1"/>
+ <pt x="1071" y="99" on="1"/>
+ <pt x="1071" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="528" y="296" on="1"/>
+ <pt x="528" y="691" on="1"/>
+ <pt x="84" y="691" on="1"/>
+ <pt x="84" y="790" on="1"/>
+ <pt x="528" y="790" on="1"/>
+ <pt x="528" y="1184" on="1"/>
+ <pt x="627" y="1184" on="1"/>
+ <pt x="627" y="790" on="1"/>
+ <pt x="1071" y="790" on="1"/>
+ <pt x="1071" y="691" on="1"/>
+ <pt x="627" y="691" on="1"/>
+ <pt x="627" y="296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 15 4 2 5 1 3 10 9 2 13 7 0 0 14 13 6 5 9 3 7 2 1 9 1 0
+ 2 4 48 84 12 11 8 7 3 3 0 1 2 0 14 13 12 3 2 4 13 10 7 6 1
+ 0 4 13 4 0 0 15 14 11 10 9 3 4 1 4 48 196 9 8 5 4 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="q" xMin="68" yMin="-395" xMax="1024" yMax="1110">
+ <contour>
+ <pt x="585" y="-395" on="1"/>
+ <pt x="585" y="-333" on="1"/>
+ <pt x="604" y="-332" on="1"/>
+ <pt x="677" y="-327" on="0"/>
+ <pt x="690" y="-306" on="1"/>
+ <pt x="703" y="-286" on="0"/>
+ <pt x="704" y="-235" on="1"/>
+ <pt x="706" y="-136" on="1"/>
+ <pt x="706" y="179" on="1"/>
+ <pt x="648" y="87" on="0"/>
+ <pt x="592" y="41" on="1"/>
+ <pt x="512" y="-25" on="0"/>
+ <pt x="414" y="-25" on="1"/>
+ <pt x="254" y="-25" on="0"/>
+ <pt x="161" y="118" on="1"/>
+ <pt x="68" y="260" on="0"/>
+ <pt x="68" y="510" on="1"/>
+ <pt x="68" y="793" on="0"/>
+ <pt x="189" y="951" on="1"/>
+ <pt x="310" y="1110" on="0"/>
+ <pt x="523" y="1110" on="1"/>
+ <pt x="597" y="1110" on="0"/>
+ <pt x="706" y="1086" on="1"/>
+ <pt x="903" y="1086" on="1"/>
+ <pt x="903" y="-136" on="1"/>
+ <pt x="905" y="-235" on="1"/>
+ <pt x="905" y="-303" on="0"/>
+ <pt x="930" y="-317" on="1"/>
+ <pt x="952" y="-329" on="0"/>
+ <pt x="1006" y="-332" on="1"/>
+ <pt x="1024" y="-333" on="1"/>
+ <pt x="1024" y="-395" on="1"/>
+ </contour>
+ <contour>
+ <pt x="706" y="1008" on="1"/>
+ <pt x="626" y="1032" on="0"/>
+ <pt x="576" y="1032" on="1"/>
+ <pt x="439" y="1032" on="0"/>
+ <pt x="360" y="905" on="1"/>
+ <pt x="281" y="777" on="0"/>
+ <pt x="281" y="551" on="1"/>
+ <pt x="281" y="103" on="0"/>
+ <pt x="482" y="103" on="1"/>
+ <pt x="576" y="103" on="0"/>
+ <pt x="706" y="248" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 40 29 12 34 21 20 48 84 20 1 12 2 1 42 32 8 3 22 2 3 0 1 30
+ 24 7 1 4 2 0 3 0 31 0 1 0 23 22 1 14 0 0 38 10 16 48 196 31 30
+ 2 13 23 1 0 16 7 0 0 42 32 22 8 7 4 4 23 1 4 48 196 24 23 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="question" xMin="51" yMin="0" xMax="851" yMax="1517">
+ <contour>
+ <pt x="271" y="0" on="1"/>
+ <pt x="271" y="197" on="1"/>
+ <pt x="468" y="197" on="1"/>
+ <pt x="468" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="271" y="395" on="1"/>
+ <pt x="271" y="413" on="1"/>
+ <pt x="271" y="617" on="0"/>
+ <pt x="413" y="758" on="1"/>
+ <pt x="453" y="798" on="1"/>
+ <pt x="641" y="986" on="0"/>
+ <pt x="641" y="1184" on="1"/>
+ <pt x="641" y="1309" on="0"/>
+ <pt x="569" y="1382" on="1"/>
+ <pt x="498" y="1456" on="0"/>
+ <pt x="371" y="1456" on="1"/>
+ <pt x="161" y="1456" on="0"/>
+ <pt x="155" y="1305" on="1"/>
+ <pt x="151" y="1198" on="1"/>
+ <pt x="150" y="1177" on="1"/>
+ <pt x="51" y="1177" on="1"/>
+ <pt x="51" y="1451" on="1"/>
+ <pt x="248" y="1517" on="0"/>
+ <pt x="413" y="1517" on="1"/>
+ <pt x="610" y="1517" on="0"/>
+ <pt x="731" y="1427" on="1"/>
+ <pt x="851" y="1338" on="0"/>
+ <pt x="851" y="1194" on="1"/>
+ <pt x="851" y="1029" on="0"/>
+ <pt x="641" y="868" on="1"/>
+ <pt x="595" y="832" on="0"/>
+ <pt x="577" y="815" on="1"/>
+ <pt x="540" y="781" on="1"/>
+ <pt x="468" y="715" on="0"/>
+ <pt x="468" y="532" on="1"/>
+ <pt x="468" y="395" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 14 11 22 48 84 22 0 1 33 20 19 18 5 5 0 4 3 0 0 0 2 1 5
+ 1 0 1 4 48 84 34 4 1 3 0 1 2 0 14 0 0 10 10 26 48 196 18 0 19
+ 2 26 2 0 0 34 33 3 2 4 3 0 1 4 48 196 34 33 3 2 3 20 19 1 5
+ 4 1 0 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="questiondown" xMin="51" yMin="-37" xMax="851" yMax="1480">
+ <contour>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="631" y="1283" on="1"/>
+ <pt x="433" y="1283" on="1"/>
+ <pt x="433" y="1480" on="1"/>
+ </contour>
+ <contour>
+ <pt x="631" y="1086" on="1"/>
+ <pt x="631" y="1067" on="1"/>
+ <pt x="631" y="864" on="0"/>
+ <pt x="488" y="722" on="1"/>
+ <pt x="448" y="683" on="1"/>
+ <pt x="261" y="500" on="0"/>
+ <pt x="261" y="297" on="1"/>
+ <pt x="261" y="172" on="0"/>
+ <pt x="333" y="99" on="1"/>
+ <pt x="404" y="25" on="0"/>
+ <pt x="531" y="25" on="1"/>
+ <pt x="739" y="25" on="0"/>
+ <pt x="746" y="176" on="1"/>
+ <pt x="751" y="282" on="1"/>
+ <pt x="752" y="303" on="1"/>
+ <pt x="851" y="303" on="1"/>
+ <pt x="851" y="30" on="1"/>
+ <pt x="658" y="-37" on="0"/>
+ <pt x="488" y="-37" on="1"/>
+ <pt x="291" y="-37" on="0"/>
+ <pt x="171" y="53" on="1"/>
+ <pt x="51" y="142" on="0"/>
+ <pt x="51" y="286" on="1"/>
+ <pt x="51" y="396" on="0"/>
+ <pt x="139" y="500" on="1"/>
+ <pt x="181" y="550" on="0"/>
+ <pt x="261" y="613" on="1"/>
+ <pt x="305" y="647" on="0"/>
+ <pt x="325" y="666" on="1"/>
+ <pt x="361" y="700" on="1"/>
+ <pt x="433" y="767" on="0"/>
+ <pt x="433" y="948" on="1"/>
+ <pt x="433" y="1086" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 0 0 14 11 22 48 84 22 2 1 35 20 19 18 5 5 4 2 3 0 0 0 2 1 5
+ 1 0 1 4 48 84 36 4 1 3 0 0 14 0 0 10 10 26 48 196 18 19 0 2 26
+ 2 0 0 5 4 1 0 4 3 2 1 4 48 196 20 19 1 36 35 3 2 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedbl" xMin="146" yMin="1086" xMax="689" yMax="1579">
+ <contour>
+ <pt x="214" y="1086" on="1"/>
+ <pt x="146" y="1579" on="1"/>
+ <pt x="343" y="1579" on="1"/>
+ <pt x="276" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="559" y="1086" on="1"/>
+ <pt x="491" y="1579" on="1"/>
+ <pt x="689" y="1579" on="1"/>
+ <pt x="621" y="1086" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 7 4 3 0 4 13 1 6 5 2 1 3 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblbase" xMin="146" yMin="-321" xMax="788" yMax="247">
+ <contour>
+ <pt x="639" y="0" on="1"/>
+ <pt x="541" y="0" on="1"/>
+ <pt x="541" y="247" on="1"/>
+ <pt x="788" y="247" on="1"/>
+ <pt x="788" y="32" on="1"/>
+ <pt x="788" y="-107" on="0"/>
+ <pt x="771" y="-151" on="1"/>
+ <pt x="750" y="-213" on="0"/>
+ <pt x="678" y="-270" on="1"/>
+ <pt x="618" y="-317" on="0"/>
+ <pt x="541" y="-321" on="1"/>
+ <pt x="541" y="-259" on="1"/>
+ <pt x="639" y="-251" on="0"/>
+ <pt x="639" y="-65" on="1"/>
+ </contour>
+ <contour>
+ <pt x="245" y="0" on="1"/>
+ <pt x="146" y="0" on="1"/>
+ <pt x="146" y="247" on="1"/>
+ <pt x="393" y="247" on="1"/>
+ <pt x="393" y="32" on="1"/>
+ <pt x="393" y="-107" on="0"/>
+ <pt x="376" y="-151" on="1"/>
+ <pt x="354" y="-216" on="0"/>
+ <pt x="283" y="-270" on="1"/>
+ <pt x="223" y="-317" on="0"/>
+ <pt x="146" y="-321" on="1"/>
+ <pt x="146" y="-259" on="1"/>
+ <pt x="245" y="-251" on="0"/>
+ <pt x="245" y="-65" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 27 25 24 18 15 14 13 11 10 4 1 0 12 13 2 17 16 3 2 3 0 14 13 0 2
+ 3 1 3 27 14 2 17 15 3 0 0 18 17 6 1 15 11 10 2 1 6 3 3 2 4
+ 48 196 25 24 16 15 3 4 3 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblleft" xMin="122" yMin="1012" xMax="764" yMax="1579">
+ <contour>
+ <pt x="270" y="1258" on="1"/>
+ <pt x="369" y="1258" on="1"/>
+ <pt x="369" y="1012" on="1"/>
+ <pt x="122" y="1012" on="1"/>
+ <pt x="122" y="1226" on="1"/>
+ <pt x="122" y="1367" on="0"/>
+ <pt x="138" y="1410" on="1"/>
+ <pt x="160" y="1474" on="0"/>
+ <pt x="232" y="1529" on="1"/>
+ <pt x="292" y="1575" on="0"/>
+ <pt x="369" y="1579" on="1"/>
+ <pt x="369" y="1517" on="1"/>
+ <pt x="270" y="1509" on="0"/>
+ <pt x="270" y="1323" on="1"/>
+ </contour>
+ <contour>
+ <pt x="665" y="1258" on="1"/>
+ <pt x="764" y="1258" on="1"/>
+ <pt x="764" y="1012" on="1"/>
+ <pt x="517" y="1012" on="1"/>
+ <pt x="517" y="1226" on="1"/>
+ <pt x="517" y="1368" on="0"/>
+ <pt x="533" y="1409" on="1"/>
+ <pt x="556" y="1476" on="0"/>
+ <pt x="627" y="1529" on="1"/>
+ <pt x="687" y="1574" on="0"/>
+ <pt x="764" y="1579" on="1"/>
+ <pt x="764" y="1517" on="1"/>
+ <pt x="665" y="1509" on="0"/>
+ <pt x="665" y="1323" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 27 25 24 18 15 14 13 11 10 4 1 0 12 13 2 17 16 3 2 3 0 14 27 14 2
+ 15 17 3 13 0 2 1 3 3 0 0 18 17 6 1 15 11 10 2 1 6 3 3 2 4
+ 48 196 25 24 16 15 3 4 3 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblright" xMin="146" yMin="1012" xMax="788" yMax="1579">
+ <contour>
+ <pt x="639" y="1332" on="1"/>
+ <pt x="541" y="1332" on="1"/>
+ <pt x="541" y="1579" on="1"/>
+ <pt x="788" y="1579" on="1"/>
+ <pt x="788" y="1365" on="1"/>
+ <pt x="788" y="1226" on="0"/>
+ <pt x="771" y="1181" on="1"/>
+ <pt x="750" y="1118" on="0"/>
+ <pt x="678" y="1062" on="1"/>
+ <pt x="618" y="1017" on="0"/>
+ <pt x="541" y="1012" on="1"/>
+ <pt x="541" y="1073" on="1"/>
+ <pt x="639" y="1082" on="0"/>
+ <pt x="639" y="1268" on="1"/>
+ </contour>
+ <contour>
+ <pt x="245" y="1332" on="1"/>
+ <pt x="146" y="1332" on="1"/>
+ <pt x="146" y="1579" on="1"/>
+ <pt x="393" y="1579" on="1"/>
+ <pt x="393" y="1365" on="1"/>
+ <pt x="393" y="1226" on="0"/>
+ <pt x="376" y="1181" on="1"/>
+ <pt x="353" y="1115" on="0"/>
+ <pt x="283" y="1062" on="1"/>
+ <pt x="223" y="1017" on="0"/>
+ <pt x="146" y="1012" on="1"/>
+ <pt x="146" y="1073" on="1"/>
+ <pt x="245" y="1082" on="0"/>
+ <pt x="245" y="1268" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 27 25 24 18 15 14 13 11 10 4 1 0 12 13 2 17 16 3 2 3 0 14 13 0 2
+ 3 1 3 27 14 2 17 15 3 0 0 18 17 6 1 15 11 10 2 1 6 3 3 2 4
+ 48 196 25 24 16 15 3 4 3 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quoteleft" xMin="205" yMin="1012" xMax="452" yMax="1579">
+ <contour>
+ <pt x="353" y="1258" on="1"/>
+ <pt x="452" y="1258" on="1"/>
+ <pt x="452" y="1012" on="1"/>
+ <pt x="205" y="1012" on="1"/>
+ <pt x="205" y="1226" on="1"/>
+ <pt x="205" y="1367" on="0"/>
+ <pt x="221" y="1410" on="1"/>
+ <pt x="243" y="1474" on="0"/>
+ <pt x="315" y="1529" on="1"/>
+ <pt x="375" y="1575" on="0"/>
+ <pt x="452" y="1579" on="1"/>
+ <pt x="452" y="1517" on="1"/>
+ <pt x="353" y="1509" on="0"/>
+ <pt x="353" y="1323" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 13 11 10 4 1 0 6 13 2 3 2 1 0 14 13 0 2 1 3 3 0 0 11 10 2
+ 1 6 3 3 1 4 48 196 4 3 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotereversed"/><!-- contains no outline data -->
+
+ <TTGlyph name="quoteright" xMin="230" yMin="1012" xMax="477" yMax="1579">
+ <contour>
+ <pt x="329" y="1332" on="1"/>
+ <pt x="230" y="1332" on="1"/>
+ <pt x="230" y="1579" on="1"/>
+ <pt x="477" y="1579" on="1"/>
+ <pt x="477" y="1365" on="1"/>
+ <pt x="477" y="1226" on="0"/>
+ <pt x="460" y="1181" on="1"/>
+ <pt x="437" y="1115" on="0"/>
+ <pt x="367" y="1062" on="1"/>
+ <pt x="307" y="1017" on="0"/>
+ <pt x="230" y="1012" on="1"/>
+ <pt x="230" y="1073" on="1"/>
+ <pt x="329" y="1082" on="0"/>
+ <pt x="329" y="1268" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 13 11 10 4 1 0 6 13 2 3 2 1 0 14 13 0 2 3 1 3 0 0 4 3 6
+ 1 1 1 4 48 196 11 10 2 1 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotesinglbase" xMin="230" yMin="-321" xMax="477" yMax="247">
+ <contour>
+ <pt x="329" y="0" on="1"/>
+ <pt x="230" y="0" on="1"/>
+ <pt x="230" y="247" on="1"/>
+ <pt x="477" y="247" on="1"/>
+ <pt x="477" y="32" on="1"/>
+ <pt x="477" y="-107" on="0"/>
+ <pt x="460" y="-151" on="1"/>
+ <pt x="438" y="-216" on="0"/>
+ <pt x="367" y="-270" on="1"/>
+ <pt x="307" y="-317" on="0"/>
+ <pt x="230" y="-321" on="1"/>
+ <pt x="230" y="-259" on="1"/>
+ <pt x="329" y="-251" on="0"/>
+ <pt x="329" y="-65" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 13 11 10 4 1 0 6 13 2 3 2 1 0 14 13 0 2 3 1 3 0 0 4 3 6
+ 1 1 1 4 48 196 11 10 2 1 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotesingle" xMin="61" yMin="1036" xMax="308" yMax="1579">
+ <contour>
+ <pt x="154" y="1036" on="1"/>
+ <pt x="61" y="1579" on="1"/>
+ <pt x="308" y="1579" on="1"/>
+ <pt x="215" y="1036" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 12 values pushed */
+ 3 0 1 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="r" xMin="31" yMin="0" xMax="670" yMax="1110">
+ <contour>
+ <pt x="31" y="0" on="1"/>
+ <pt x="31" y="62" on="1"/>
+ <pt x="50" y="63" on="1"/>
+ <pt x="123" y="67" on="0"/>
+ <pt x="136" y="89" on="1"/>
+ <pt x="149" y="108" on="0"/>
+ <pt x="150" y="160" on="1"/>
+ <pt x="152" y="259" on="1"/>
+ <pt x="152" y="827" on="1"/>
+ <pt x="150" y="925" on="1"/>
+ <pt x="150" y="993" on="0"/>
+ <pt x="125" y="1007" on="1"/>
+ <pt x="105" y="1019" on="0"/>
+ <pt x="50" y="1023" on="1"/>
+ <pt x="31" y="1024" on="1"/>
+ <pt x="31" y="1086" on="1"/>
+ <pt x="349" y="1086" on="1"/>
+ <pt x="349" y="907" on="1"/>
+ <pt x="458" y="1110" on="0"/>
+ <pt x="609" y="1110" on="1"/>
+ <pt x="640" y="1110" on="0"/>
+ <pt x="670" y="1099" on="1"/>
+ <pt x="670" y="802" on="1"/>
+ <pt x="578" y="802" on="1"/>
+ <pt x="576" y="820" on="1"/>
+ <pt x="575" y="827" on="1"/>
+ <pt x="575" y="833" on="0"/>
+ <pt x="574" y="845" on="1"/>
+ <pt x="574" y="852" on="0"/>
+ <pt x="573" y="862" on="1"/>
+ <pt x="569" y="939" on="0"/>
+ <pt x="517" y="939" on="1"/>
+ <pt x="435" y="939" on="0"/>
+ <pt x="349" y="814" on="1"/>
+ <pt x="349" y="259" on="1"/>
+ <pt x="351" y="160" on="1"/>
+ <pt x="352" y="91" on="0"/>
+ <pt x="376" y="78" on="1"/>
+ <pt x="398" y="66" on="0"/>
+ <pt x="452" y="63" on="1"/>
+ <pt x="470" y="62" on="1"/>
+ <pt x="470" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 0 31 13 19 48 84 19 1 40 34 33 23 22 17 14 8 7 1 10 15 0 3 21 15
+ 41 0 1 0 16 15 1 14 41 40 23 3 21 16 3 15 14 1 0 4 13 7 0 0 34
+ 33 17 16 4 3 7 1 4 48 196 22 21 1 8 7 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="racute" xMin="31" yMin="0" xMax="671" yMax="1604">
+ <component glyphName="r" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="80" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="radicalex" xMin="99" yMin="1480" xMax="926" yMax="1604">
+ <contour>
+ <pt x="99" y="1480" on="1"/>
+ <pt x="99" y="1604" on="1"/>
+ <pt x="926" y="1604" on="1"/>
+ <pt x="926" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="rcaron" xMin="-12" yMin="0" xMax="691" yMax="1604">
+ <component glyphName="r" x="-1" y="0" flags="0x4"/>
+ <component glyphName="caron" x="-2" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="rcommaaccent" xMin="31" yMin="-432" xMax="670" yMax="1110">
+ <component glyphName="r" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="-18" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="registered" xMin="87" yMin="49" xMax="1469" yMax="1431">
+ <contour>
+ <pt x="779" y="1431" on="1"/>
+ <pt x="1063" y="1431" on="0"/>
+ <pt x="1266" y="1229" on="1"/>
+ <pt x="1469" y="1027" on="0"/>
+ <pt x="1469" y="741" on="1"/>
+ <pt x="1469" y="452" on="0"/>
+ <pt x="1265" y="251" on="1"/>
+ <pt x="1062" y="49" on="0"/>
+ <pt x="770" y="49" on="1"/>
+ <pt x="519" y="49" on="0"/>
+ <pt x="331" y="213" on="1"/>
+ <pt x="87" y="426" on="0"/>
+ <pt x="87" y="740" on="1"/>
+ <pt x="87" y="1027" on="0"/>
+ <pt x="290" y="1229" on="1"/>
+ <pt x="493" y="1431" on="0"/>
+ </contour>
+ <contour>
+ <pt x="778" y="1369" on="1"/>
+ <pt x="518" y="1369" on="0"/>
+ <pt x="334" y="1185" on="1"/>
+ <pt x="149" y="1001" on="0"/>
+ <pt x="149" y="740" on="1"/>
+ <pt x="149" y="483" on="0"/>
+ <pt x="333" y="297" on="1"/>
+ <pt x="516" y="111" on="0"/>
+ <pt x="773" y="111" on="1"/>
+ <pt x="1010" y="111" on="0"/>
+ <pt x="1184" y="259" on="1"/>
+ <pt x="1407" y="450" on="0"/>
+ <pt x="1407" y="742" on="1"/>
+ <pt x="1407" y="1002" on="0"/>
+ <pt x="1222" y="1185" on="1"/>
+ <pt x="1037" y="1369" on="0"/>
+ </contour>
+ <contour>
+ <pt x="692" y="683" on="1"/>
+ <pt x="692" y="486" on="1"/>
+ <pt x="694" y="432" on="1"/>
+ <pt x="695" y="394" on="0"/>
+ <pt x="707" y="388" on="1"/>
+ <pt x="721" y="382" on="0"/>
+ <pt x="759" y="379" on="1"/>
+ <pt x="759" y="327" on="1"/>
+ <pt x="455" y="327" on="1"/>
+ <pt x="455" y="379" on="1"/>
+ <pt x="482" y="381" on="1"/>
+ <pt x="525" y="385" on="0"/>
+ <pt x="526" y="432" on="1"/>
+ <pt x="529" y="486" on="1"/>
+ <pt x="529" y="982" on="1"/>
+ <pt x="526" y="1036" on="1"/>
+ <pt x="525" y="1082" on="0"/>
+ <pt x="482" y="1087" on="1"/>
+ <pt x="455" y="1090" on="1"/>
+ <pt x="455" y="1141" on="1"/>
+ <pt x="678" y="1141" on="1"/>
+ <pt x="729" y="1142" on="1"/>
+ <pt x="778" y="1144" on="1"/>
+ <pt x="827" y="1145" on="1"/>
+ <pt x="927" y="1147" on="0"/>
+ <pt x="993" y="1109" on="1"/>
+ <pt x="1080" y="1059" on="0"/>
+ <pt x="1080" y="937" on="1"/>
+ <pt x="1080" y="775" on="0"/>
+ <pt x="923" y="706" on="1"/>
+ <pt x="1082" y="485" on="1"/>
+ <pt x="1126" y="429" on="1"/>
+ <pt x="1155" y="391" on="0"/>
+ <pt x="1179" y="384" on="1"/>
+ <pt x="1179" y="327" on="1"/>
+ <pt x="987" y="327" on="1"/>
+ <pt x="761" y="683" on="1"/>
+ </contour>
+ <contour>
+ <pt x="692" y="738" on="1"/>
+ <pt x="722" y="738" on="1"/>
+ <pt x="909" y="738" on="0"/>
+ <pt x="909" y="926" on="1"/>
+ <pt x="909" y="1087" on="0"/>
+ <pt x="753" y="1087" on="1"/>
+ <pt x="692" y="1087" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 101 values pushed */
+ 0 0 24 11 8 16 11 0 48 84 8 2 0 0 75 74 70 69 68 65 62 61 50 46 45
+ 41 38 33 32 15 51 39 3 52 51 1 67 66 40 39 3 2 0 14 0 0 72 18 59 28
+ 11 4 20 11 12 48 196 52 32 45 2 74 70 68 67 66 65 62 61 39 38 10 13 59 4
+ 32 51 50 41 40 4 13 12 45 0 0 75 69 33 32 26 3 45 1 4 48 196 46 45 1
+ 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ring" xMin="114" yMin="1283" xMax="568" yMax="1737">
+ <contour>
+ <pt x="341" y="1737" on="1"/>
+ <pt x="435" y="1737" on="0"/>
+ <pt x="501" y="1671" on="1"/>
+ <pt x="568" y="1605" on="0"/>
+ <pt x="568" y="1511" on="1"/>
+ <pt x="568" y="1415" on="0"/>
+ <pt x="501" y="1349" on="1"/>
+ <pt x="435" y="1283" on="0"/>
+ <pt x="339" y="1283" on="1"/>
+ <pt x="256" y="1283" on="0"/>
+ <pt x="194" y="1337" on="1"/>
+ <pt x="114" y="1406" on="0"/>
+ <pt x="114" y="1510" on="1"/>
+ <pt x="114" y="1605" on="0"/>
+ <pt x="180" y="1671" on="1"/>
+ <pt x="246" y="1737" on="0"/>
+ </contour>
+ <contour>
+ <pt x="341" y="1669" on="1"/>
+ <pt x="275" y="1669" on="0"/>
+ <pt x="229" y="1623" on="1"/>
+ <pt x="182" y="1576" on="0"/>
+ <pt x="182" y="1511" on="1"/>
+ <pt x="182" y="1445" on="0"/>
+ <pt x="228" y="1398" on="1"/>
+ <pt x="275" y="1351" on="0"/>
+ <pt x="339" y="1351" on="1"/>
+ <pt x="400" y="1351" on="0"/>
+ <pt x="444" y="1388" on="1"/>
+ <pt x="500" y="1437" on="0"/>
+ <pt x="500" y="1511" on="1"/>
+ <pt x="500" y="1577" on="0"/>
+ <pt x="453" y="1623" on="1"/>
+ <pt x="407" y="1669" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 24 17 8 16 17 0 48 84 8 0 14 0 0 28 17 4 20 17 12 48 196 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="s" xMin="95" yMin="-25" xMax="733" yMax="1110">
+ <contour>
+ <pt x="95" y="56" on="1"/>
+ <pt x="95" y="307" on="1"/>
+ <pt x="194" y="307" on="1"/>
+ <pt x="195" y="289" on="1"/>
+ <pt x="198" y="218" on="1"/>
+ <pt x="205" y="43" on="0"/>
+ <pt x="374" y="43" on="1"/>
+ <pt x="536" y="43" on="0"/>
+ <pt x="536" y="232" on="1"/>
+ <pt x="536" y="325" on="0"/>
+ <pt x="498" y="368" on="1"/>
+ <pt x="467" y="405" on="0"/>
+ <pt x="390" y="456" on="1"/>
+ <pt x="332" y="495" on="1"/>
+ <pt x="189" y="591" on="0"/>
+ <pt x="145" y="653" on="1"/>
+ <pt x="101" y="715" on="0"/>
+ <pt x="101" y="819" on="1"/>
+ <pt x="101" y="1110" on="0"/>
+ <pt x="411" y="1110" on="1"/>
+ <pt x="536" y="1110" on="0"/>
+ <pt x="656" y="1049" on="1"/>
+ <pt x="656" y="814" on="1"/>
+ <pt x="558" y="814" on="1"/>
+ <pt x="558" y="832" on="1"/>
+ <pt x="558" y="1043" on="0"/>
+ <pt x="426" y="1043" on="1"/>
+ <pt x="286" y="1043" on="0"/>
+ <pt x="286" y="881" on="1"/>
+ <pt x="286" y="761" on="0"/>
+ <pt x="378" y="701" on="1"/>
+ <pt x="464" y="645" on="1"/>
+ <pt x="520" y="607" on="1"/>
+ <pt x="652" y="518" on="0"/>
+ <pt x="692" y="458" on="1"/>
+ <pt x="733" y="398" on="0"/>
+ <pt x="733" y="294" on="1"/>
+ <pt x="733" y="141" on="0"/>
+ <pt x="644" y="58" on="1"/>
+ <pt x="554" y="-25" on="0"/>
+ <pt x="395" y="-25" on="1"/>
+ <pt x="256" y="-25" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 0 0 26 17 19 6 17 40 48 84 40 2 19 1 1 1 24 23 22 21 2 1 0 7 1
+ 2 3 0 0 14 0 0 28 16 17 8 5 36 48 196 17 24 23 17 2 4 21 0 3 36
+ 21 22 21 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="sacute" xMin="95" yMin="-25" xMax="776" yMax="1604">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="185" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scaron" xMin="66" yMin="-25" xMax="769" yMax="1604">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="76" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scedilla" xMin="95" yMin="-432" xMax="733" yMax="1110">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="cedilla" x="70" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scircumflex" xMin="62" yMin="-25" xMax="765" yMax="1604">
+ <contour>
+ <pt x="94" y="56" on="1"/>
+ <pt x="94" y="307" on="1"/>
+ <pt x="193" y="307" on="1"/>
+ <pt x="194" y="289" on="1"/>
+ <pt x="197" y="218" on="1"/>
+ <pt x="204" y="43" on="0"/>
+ <pt x="373" y="43" on="1"/>
+ <pt x="535" y="43" on="0"/>
+ <pt x="535" y="231" on="1"/>
+ <pt x="535" y="326" on="0"/>
+ <pt x="498" y="368" on="1"/>
+ <pt x="465" y="405" on="0"/>
+ <pt x="389" y="456" on="1"/>
+ <pt x="331" y="495" on="1"/>
+ <pt x="189" y="591" on="0"/>
+ <pt x="144" y="653" on="1"/>
+ <pt x="100" y="715" on="0"/>
+ <pt x="100" y="819" on="1"/>
+ <pt x="100" y="1110" on="0"/>
+ <pt x="410" y="1110" on="1"/>
+ <pt x="536" y="1110" on="0"/>
+ <pt x="655" y="1049" on="1"/>
+ <pt x="655" y="814" on="1"/>
+ <pt x="557" y="814" on="1"/>
+ <pt x="557" y="832" on="1"/>
+ <pt x="557" y="1043" on="0"/>
+ <pt x="425" y="1043" on="1"/>
+ <pt x="285" y="1043" on="0"/>
+ <pt x="285" y="881" on="1"/>
+ <pt x="285" y="761" on="0"/>
+ <pt x="377" y="701" on="1"/>
+ <pt x="463" y="645" on="1"/>
+ <pt x="519" y="607" on="1"/>
+ <pt x="652" y="517" on="0"/>
+ <pt x="691" y="458" on="1"/>
+ <pt x="732" y="398" on="0"/>
+ <pt x="732" y="294" on="1"/>
+ <pt x="732" y="141" on="0"/>
+ <pt x="643" y="58" on="1"/>
+ <pt x="554" y="-25" on="0"/>
+ <pt x="394" y="-25" on="1"/>
+ <pt x="255" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="62" y="1283" on="1"/>
+ <pt x="303" y="1604" on="1"/>
+ <pt x="525" y="1604" on="1"/>
+ <pt x="765" y="1283" on="1"/>
+ <pt x="679" y="1283" on="1"/>
+ <pt x="414" y="1505" on="1"/>
+ <pt x="148" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 91 values pushed */
+ 0 0 26 17 19 6 17 40 48 84 40 2 19 1 1 47 43 0 2 0 1 1 48 46 45
+ 42 4 0 1 3 0 0 1 1 24 23 22 21 2 1 0 7 1 2 3 0 0 44 43 1
+ 0 14 0 0 28 16 17 8 5 36 48 196 17 48 47 44 43 24 23 17 2 8 21 0 3
+ 46 45 2 13 36 21 42 0 22 21 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="scommaaccent" xMin="95" yMin="-432" xMax="733" yMax="1110">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="79" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="section" xMin="75" yMin="-321" xMax="962" yMax="1517">
+ <contour>
+ <pt x="75" y="-258" on="1"/>
+ <pt x="75" y="-37" on="1"/>
+ <pt x="174" y="-37" on="1"/>
+ <pt x="175" y="-56" on="1"/>
+ <pt x="178" y="-104" on="1"/>
+ <pt x="182" y="-170" on="0"/>
+ <pt x="276" y="-215" on="1"/>
+ <pt x="368" y="-260" on="0"/>
+ <pt x="498" y="-260" on="1"/>
+ <pt x="628" y="-260" on="0"/>
+ <pt x="708" y="-192" on="1"/>
+ <pt x="788" y="-125" on="0"/>
+ <pt x="788" y="-19" on="1"/>
+ <pt x="788" y="67" on="0"/>
+ <pt x="724" y="113" on="1"/>
+ <pt x="671" y="150" on="0"/>
+ <pt x="556" y="198" on="1"/>
+ <pt x="449" y="243" on="1"/>
+ <pt x="249" y="327" on="0"/>
+ <pt x="167" y="406" on="1"/>
+ <pt x="86" y="485" on="0"/>
+ <pt x="86" y="595" on="1"/>
+ <pt x="86" y="746" on="0"/>
+ <pt x="257" y="889" on="1"/>
+ <pt x="182" y="931" on="0"/>
+ <pt x="144" y="979" on="1"/>
+ <pt x="89" y="1050" on="0"/>
+ <pt x="89" y="1150" on="1"/>
+ <pt x="89" y="1318" on="0"/>
+ <pt x="218" y="1417" on="1"/>
+ <pt x="348" y="1517" on="0"/>
+ <pt x="570" y="1517" on="1"/>
+ <pt x="735" y="1517" on="0"/>
+ <pt x="914" y="1461" on="1"/>
+ <pt x="914" y="1234" on="1"/>
+ <pt x="816" y="1234" on="1"/>
+ <pt x="814" y="1252" on="1"/>
+ <pt x="812" y="1313" on="1"/>
+ <pt x="810" y="1376" on="0"/>
+ <pt x="735" y="1416" on="1"/>
+ <pt x="661" y="1456" on="0"/>
+ <pt x="551" y="1456" on="1"/>
+ <pt x="422" y="1456" on="0"/>
+ <pt x="342" y="1386" on="1"/>
+ <pt x="263" y="1317" on="0"/>
+ <pt x="263" y="1206" on="1"/>
+ <pt x="263" y="1128" on="0"/>
+ <pt x="308" y="1081" on="1"/>
+ <pt x="354" y="1031" on="0"/>
+ <pt x="468" y="984" on="1"/>
+ <pt x="575" y="940" on="1"/>
+ <pt x="801" y="847" on="0"/>
+ <pt x="873" y="778" on="1"/>
+ <pt x="943" y="710" on="0"/>
+ <pt x="943" y="589" on="1"/>
+ <pt x="943" y="437" on="0"/>
+ <pt x="782" y="291" on="1"/>
+ <pt x="863" y="244" on="0"/>
+ <pt x="903" y="194" on="1"/>
+ <pt x="962" y="121" on="0"/>
+ <pt x="962" y="23" on="1"/>
+ <pt x="962" y="-137" on="0"/>
+ <pt x="838" y="-229" on="1"/>
+ <pt x="714" y="-321" on="0"/>
+ <pt x="490" y="-321" on="1"/>
+ <pt x="303" y="-321" on="0"/>
+ </contour>
+ <contour>
+ <pt x="728" y="329" on="1"/>
+ <pt x="793" y="422" on="0"/>
+ <pt x="793" y="510" on="1"/>
+ <pt x="793" y="634" on="0"/>
+ <pt x="652" y="697" on="1"/>
+ <pt x="443" y="791" on="1"/>
+ <pt x="304" y="852" on="1"/>
+ <pt x="253" y="759" on="0"/>
+ <pt x="253" y="685" on="1"/>
+ <pt x="253" y="572" on="0"/>
+ <pt x="337" y="514" on="1"/>
+ <pt x="410" y="464" on="0"/>
+ <pt x="589" y="388" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 41 11 31 8 11 64 48 84 31 0 1 72 66 56 35 34 33 23 2 1 0 10 13
+ 64 0 0 14 0 0 74 18 21 68 47 54 45 18 27 12 18 60 48 196 27 21 72 66 56
+ 35 27 23 21 2 8 33 0 3 60 54 33 34 33 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="semicolon" xMin="161" yMin="-321" xMax="408" yMax="1086">
+ <contour>
+ <pt x="260" y="0" on="1"/>
+ <pt x="161" y="0" on="1"/>
+ <pt x="161" y="247" on="1"/>
+ <pt x="408" y="247" on="1"/>
+ <pt x="408" y="32" on="1"/>
+ <pt x="408" y="-107" on="0"/>
+ <pt x="391" y="-151" on="1"/>
+ <pt x="369" y="-216" on="0"/>
+ <pt x="298" y="-270" on="1"/>
+ <pt x="238" y="-317" on="0"/>
+ <pt x="161" y="-321" on="1"/>
+ <pt x="161" y="-259" on="1"/>
+ <pt x="260" y="-251" on="0"/>
+ <pt x="260" y="-65" on="1"/>
+ </contour>
+ <contour>
+ <pt x="161" y="839" on="1"/>
+ <pt x="161" y="1086" on="1"/>
+ <pt x="408" y="1086" on="1"/>
+ <pt x="408" y="839" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 1 4 2 2 2 0 1 13 11 10 1 0 5 13 2 0 0 0 17 14 6 1 15 1 4
+ 48 84 3 2 1 0 16 15 1 14 13 0 2 3 1 3 0 0 17 16 4 3 6 3 1
+ 1 4 48 196 15 14 11 10 2 1 5 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="semicolon#1" xMin="161" yMin="-321" xMax="408" yMax="1086">
+ <contour>
+ <pt x="260" y="0" on="1"/>
+ <pt x="161" y="0" on="1"/>
+ <pt x="161" y="247" on="1"/>
+ <pt x="408" y="247" on="1"/>
+ <pt x="408" y="32" on="1"/>
+ <pt x="408" y="-107" on="0"/>
+ <pt x="391" y="-151" on="1"/>
+ <pt x="369" y="-216" on="0"/>
+ <pt x="298" y="-270" on="1"/>
+ <pt x="238" y="-317" on="0"/>
+ <pt x="161" y="-321" on="1"/>
+ <pt x="161" y="-259" on="1"/>
+ <pt x="260" y="-251" on="0"/>
+ <pt x="260" y="-65" on="1"/>
+ </contour>
+ <contour>
+ <pt x="161" y="839" on="1"/>
+ <pt x="161" y="1086" on="1"/>
+ <pt x="408" y="1086" on="1"/>
+ <pt x="408" y="839" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 1 4 2 2 2 0 1 13 11 10 1 0 5 13 2 0 0 0 17 14 6 1 15 1 4
+ 48 84 3 2 1 0 16 15 1 14 13 0 2 3 1 3 0 0 17 16 4 3 6 3 1
+ 1 4 48 196 15 14 11 10 2 1 5 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="108" yMin="0" xMax="996" yMax="1480">
+ <contour>
+ <pt x="182" y="0" on="1"/>
+ <pt x="268" y="469" on="0"/>
+ <pt x="731" y="1095" on="1"/>
+ <pt x="879" y="1295" on="1"/>
+ <pt x="108" y="1295" on="1"/>
+ <pt x="108" y="1480" on="1"/>
+ <pt x="996" y="1480" on="1"/>
+ <pt x="996" y="1351" on="1"/>
+ <pt x="746" y="1010" on="0"/>
+ <pt x="590" y="648" on="1"/>
+ <pt x="434" y="285" on="0"/>
+ <pt x="416" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 35 values pushed */
+ 7 5 3 2 0 0 4 3 28 1 5 1 4 48 84 11 0 1 0 6 5 0 14 11 7
+ 6 3 0 5 13 4 5 4 1 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="sfthyphen" xMin="82" yMin="543" xMax="600" yMax="666">
+ <contour>
+ <pt x="82" y="543" on="1"/>
+ <pt x="82" y="666" on="1"/>
+ <pt x="600" y="666" on="1"/>
+ <pt x="600" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="49" yMin="-37" xMax="987" yMax="1518">
+ <contour>
+ <pt x="259" y="757" on="1"/>
+ <pt x="311" y="843" on="0"/>
+ <pt x="370" y="887" on="1"/>
+ <pt x="455" y="950" on="0"/>
+ <pt x="575" y="950" on="1"/>
+ <pt x="755" y="950" on="0"/>
+ <pt x="871" y="821" on="1"/>
+ <pt x="987" y="692" on="0"/>
+ <pt x="987" y="488" on="1"/>
+ <pt x="987" y="264" on="0"/>
+ <pt x="853" y="114" on="1"/>
+ <pt x="720" y="-37" on="0"/>
+ <pt x="522" y="-37" on="1"/>
+ <pt x="303" y="-37" on="0"/>
+ <pt x="176" y="161" on="1"/>
+ <pt x="49" y="358" on="0"/>
+ <pt x="49" y="700" on="1"/>
+ <pt x="49" y="1078" on="0"/>
+ <pt x="197" y="1298" on="1"/>
+ <pt x="345" y="1518" on="0"/>
+ <pt x="608" y="1518" on="1"/>
+ <pt x="772" y="1518" on="0"/>
+ <pt x="904" y="1452" on="1"/>
+ <pt x="904" y="1227" on="1"/>
+ <pt x="805" y="1227" on="1"/>
+ <pt x="804" y="1248" on="1"/>
+ <pt x="799" y="1359" on="0"/>
+ <pt x="754" y="1405" on="1"/>
+ <pt x="710" y="1450" on="0"/>
+ <pt x="611" y="1450" on="1"/>
+ <pt x="424" y="1450" on="0"/>
+ <pt x="329" y="1212" on="1"/>
+ <pt x="262" y="1043" on="0"/>
+ </contour>
+ <contour>
+ <pt x="525" y="880" on="1"/>
+ <pt x="413" y="880" on="0"/>
+ <pt x="339" y="785" on="1"/>
+ <pt x="265" y="691" on="0"/>
+ <pt x="265" y="542" on="1"/>
+ <pt x="265" y="352" on="0"/>
+ <pt x="333" y="210" on="1"/>
+ <pt x="419" y="31" on="0"/>
+ <pt x="551" y="31" on="1"/>
+ <pt x="659" y="31" on="0"/>
+ <pt x="722" y="148" on="1"/>
+ <pt x="786" y="265" on="0"/>
+ <pt x="786" y="463" on="1"/>
+ <pt x="786" y="880" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 0 0 41 17 12 33 17 4 29 17 20 48 84 20 0 12 2 4 1 1 24 23 22 4 0
+ 5 0 2 3 0 0 14 0 0 45 5 8 37 10 16 48 196 8 22 24 0 16 22 23 22
+ 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="slash" xMin="-30" yMin="-296" xMax="600" yMax="1481">
+ <contour>
+ <pt x="-30" y="-296" on="1"/>
+ <pt x="496" y="1481" on="1"/>
+ <pt x="600" y="1481" on="1"/>
+ <pt x="74" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 9 values pushed */
+ 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="space"/><!-- contains no outline data -->
+
+ <TTGlyph name="sterling" xMin="74" yMin="0" xMax="925" yMax="1505">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="148" on="1"/>
+ <pt x="198" y="181" on="0"/>
+ <pt x="241" y="263" on="1"/>
+ <pt x="284" y="344" on="0"/>
+ <pt x="284" y="547" on="1"/>
+ <pt x="284" y="740" on="1"/>
+ <pt x="111" y="740" on="1"/>
+ <pt x="111" y="802" on="1"/>
+ <pt x="284" y="802" on="1"/>
+ <pt x="284" y="1024" on="1"/>
+ <pt x="284" y="1505" on="0"/>
+ <pt x="653" y="1505" on="1"/>
+ <pt x="786" y="1505" on="0"/>
+ <pt x="925" y="1435" on="1"/>
+ <pt x="925" y="1221" on="1"/>
+ <pt x="827" y="1221" on="1"/>
+ <pt x="825" y="1240" on="1"/>
+ <pt x="822" y="1314" on="1"/>
+ <pt x="817" y="1444" on="0"/>
+ <pt x="663" y="1444" on="1"/>
+ <pt x="547" y="1444" on="0"/>
+ <pt x="511" y="1363" on="1"/>
+ <pt x="481" y="1294" on="0"/>
+ <pt x="481" y="1138" on="1"/>
+ <pt x="481" y="802" on="1"/>
+ <pt x="716" y="802" on="1"/>
+ <pt x="716" y="740" on="1"/>
+ <pt x="481" y="740" on="1"/>
+ <pt x="481" y="586" on="1"/>
+ <pt x="481" y="306" on="0"/>
+ <pt x="199" y="148" on="1"/>
+ <pt x="925" y="148" on="1"/>
+ <pt x="925" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 98 values pushed */
+ 0 0 20 11 12 48 84 12 0 1 24 16 15 14 10 5 0 8 3 0 29 5 2 6 1
+ 3 0 0 28 27 7 6 14 3 8 32 31 1 19 2 0 2 4 48 84 26 25 9 8 3
+ 33 0 1 2 0 14 27 26 16 3 14 24 3 31 8 7 3 5 0 3 0 0 29 28 25
+ 24 4 3 5 1 4 48 196 33 32 15 14 3 10 9 6 5 3 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="t" xMin="25" yMin="-25" xMax="558" yMax="1332">
+ <contour>
+ <pt x="136" y="999" on="1"/>
+ <pt x="25" y="999" on="1"/>
+ <pt x="25" y="1086" on="1"/>
+ <pt x="136" y="1086" on="1"/>
+ <pt x="136" y="1283" on="1"/>
+ <pt x="334" y="1332" on="1"/>
+ <pt x="334" y="1086" on="1"/>
+ <pt x="558" y="1086" on="1"/>
+ <pt x="558" y="999" on="1"/>
+ <pt x="334" y="999" on="1"/>
+ <pt x="334" y="313" on="1"/>
+ <pt x="334" y="226" on="1"/>
+ <pt x="334" y="55" on="0"/>
+ <pt x="438" y="55" on="1"/>
+ <pt x="477" y="55" on="0"/>
+ <pt x="533" y="86" on="1"/>
+ <pt x="533" y="6" on="1"/>
+ <pt x="455" y="-25" on="0"/>
+ <pt x="389" y="-25" on="1"/>
+ <pt x="251" y="-25" on="0"/>
+ <pt x="193" y="56" on="1"/>
+ <pt x="136" y="137" on="0"/>
+ <pt x="136" y="339" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 18 2 11 16 1 22 16 10 3 0 2 3 0 5 4 2 13 2 0 0 9 8 1 0 3
+ 2 1 6 48 84 7 6 3 2 1 3 14 16 11 8 7 2 13 5 2 1 0 0 0 11
+ 10 9 6 5 4 4 0 1 4 48 196 22 4 3 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tbar" xMin="25" yMin="-25" xMax="558" yMax="1332">
+ <contour>
+ <pt x="136" y="617" on="1"/>
+ <pt x="25" y="617" on="1"/>
+ <pt x="25" y="691" on="1"/>
+ <pt x="136" y="691" on="1"/>
+ <pt x="136" y="999" on="1"/>
+ <pt x="25" y="999" on="1"/>
+ <pt x="25" y="1086" on="1"/>
+ <pt x="136" y="1086" on="1"/>
+ <pt x="136" y="1283" on="1"/>
+ <pt x="334" y="1332" on="1"/>
+ <pt x="334" y="1086" on="1"/>
+ <pt x="558" y="1086" on="1"/>
+ <pt x="558" y="999" on="1"/>
+ <pt x="334" y="999" on="1"/>
+ <pt x="334" y="691" on="1"/>
+ <pt x="558" y="691" on="1"/>
+ <pt x="558" y="617" on="1"/>
+ <pt x="334" y="617" on="1"/>
+ <pt x="334" y="313" on="1"/>
+ <pt x="334" y="226" on="1"/>
+ <pt x="334" y="55" on="0"/>
+ <pt x="438" y="55" on="1"/>
+ <pt x="477" y="55" on="0"/>
+ <pt x="533" y="86" on="1"/>
+ <pt x="533" y="6" on="1"/>
+ <pt x="455" y="-25" on="0"/>
+ <pt x="389" y="-25" on="1"/>
+ <pt x="251" y="-25" on="0"/>
+ <pt x="193" y="56" on="1"/>
+ <pt x="136" y="137" on="0"/>
+ <pt x="136" y="339" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 26 2 19 24 1 30 24 18 3 0 2 3 0 9 8 2 13 6 0 0 13 12 5 4 3
+ 6 1 6 17 16 1 0 21 3 2 1 4 48 84 15 14 3 2 3 0 11 10 7 6 1
+ 3 14 24 19 16 15 12 11 4 13 9 6 5 2 1 4 13 0 0 0 19 18 17 14 13
+ 10 9 4 6 0 1 4 48 196 30 8 7 4 3 0 5 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcaron" xMin="25" yMin="-25" xMax="679" yMax="1688">
+ <contour>
+ <pt x="136" y="999" on="1"/>
+ <pt x="25" y="999" on="1"/>
+ <pt x="25" y="1086" on="1"/>
+ <pt x="136" y="1086" on="1"/>
+ <pt x="136" y="1283" on="1"/>
+ <pt x="334" y="1332" on="1"/>
+ <pt x="334" y="1086" on="1"/>
+ <pt x="558" y="1086" on="1"/>
+ <pt x="558" y="999" on="1"/>
+ <pt x="334" y="999" on="1"/>
+ <pt x="334" y="313" on="1"/>
+ <pt x="334" y="226" on="1"/>
+ <pt x="334" y="55" on="0"/>
+ <pt x="438" y="55" on="1"/>
+ <pt x="477" y="55" on="0"/>
+ <pt x="533" y="86" on="1"/>
+ <pt x="533" y="6" on="1"/>
+ <pt x="455" y="-25" on="0"/>
+ <pt x="389" y="-25" on="1"/>
+ <pt x="251" y="-25" on="0"/>
+ <pt x="193" y="56" on="1"/>
+ <pt x="136" y="137" on="0"/>
+ <pt x="136" y="339" on="1"/>
+ </contour>
+ <contour>
+ <pt x="561" y="1491" on="1"/>
+ <pt x="482" y="1491" on="1"/>
+ <pt x="482" y="1688" on="1"/>
+ <pt x="679" y="1688" on="1"/>
+ <pt x="679" y="1517" on="1"/>
+ <pt x="679" y="1354" on="0"/>
+ <pt x="617" y="1289" on="1"/>
+ <pt x="570" y="1240" on="0"/>
+ <pt x="482" y="1234" on="1"/>
+ <pt x="482" y="1284" on="1"/>
+ <pt x="561" y="1290" on="0"/>
+ <pt x="561" y="1439" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 18 2 11 16 34 32 31 27 24 23 5 4 8 25 2 3 1 22 16 10 3 0 2 3 0
+ 0 0 9 8 1 0 3 2 1 6 48 84 26 25 1 0 7 6 3 2 1 3 14 16 11
+ 34 23 8 7 4 26 24 3 2 1 0 0 0 32 31 25 24 4 3 26 11 10 9 6 5
+ 4 4 0 2 4 48 196 27 26 1 22 4 3 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcommaaccent" xMin="25" yMin="-432" xMax="558" yMax="1332">
+ <contour>
+ <pt x="136" y="999" on="1"/>
+ <pt x="25" y="999" on="1"/>
+ <pt x="25" y="1086" on="1"/>
+ <pt x="136" y="1086" on="1"/>
+ <pt x="136" y="1283" on="1"/>
+ <pt x="334" y="1332" on="1"/>
+ <pt x="334" y="1086" on="1"/>
+ <pt x="558" y="1086" on="1"/>
+ <pt x="558" y="999" on="1"/>
+ <pt x="334" y="999" on="1"/>
+ <pt x="334" y="313" on="1"/>
+ <pt x="334" y="226" on="1"/>
+ <pt x="334" y="55" on="0"/>
+ <pt x="438" y="55" on="1"/>
+ <pt x="477" y="55" on="0"/>
+ <pt x="533" y="86" on="1"/>
+ <pt x="533" y="6" on="1"/>
+ <pt x="455" y="-25" on="0"/>
+ <pt x="389" y="-25" on="1"/>
+ <pt x="251" y="-25" on="0"/>
+ <pt x="193" y="56" on="1"/>
+ <pt x="136" y="137" on="0"/>
+ <pt x="136" y="339" on="1"/>
+ </contour>
+ <contour>
+ <pt x="186" y="-411" on="1"/>
+ <pt x="186" y="-343" on="1"/>
+ <pt x="248" y="-359" on="0"/>
+ <pt x="287" y="-359" on="1"/>
+ <pt x="394" y="-359" on="0"/>
+ <pt x="394" y="-277" on="1"/>
+ <pt x="394" y="-179" on="0"/>
+ <pt x="207" y="-175" on="1"/>
+ <pt x="302" y="0" on="1"/>
+ <pt x="381" y="0" on="1"/>
+ <pt x="315" y="-119" on="1"/>
+ <pt x="411" y="-127" on="0"/>
+ <pt x="460" y="-152" on="1"/>
+ <pt x="532" y="-189" on="0"/>
+ <pt x="532" y="-266" on="1"/>
+ <pt x="532" y="-336" on="0"/>
+ <pt x="474" y="-384" on="1"/>
+ <pt x="417" y="-432" on="0"/>
+ <pt x="330" y="-432" on="1"/>
+ <pt x="262" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 104 values pushed */
+ 0 0 26 17 41 48 84 18 2 11 16 1 22 16 10 3 0 2 3 0 5 4 2 13 2
+ 1 33 32 31 30 24 23 6 13 41 2 0 0 0 9 8 1 0 3 2 1 6 48 84 7
+ 6 3 2 1 3 14 0 0 28 48 37 48 196 16 11 33 31 30 24 23 5 5 0 3 32
+ 8 7 3 13 37 5 2 1 0 0 0 11 10 9 6 5 4 4 0 1 4 48 196 22 4
+ 3 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcommabelow" xMin="25" yMin="-432" xMax="558" yMax="1332">
+ <component glyphName="t" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="-9" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="thorn" xMin="0" yMin="-395" xMax="956" yMax="1579">
+ <contour>
+ <pt x="0" y="-395" on="1"/>
+ <pt x="0" y="-333" on="1"/>
+ <pt x="19" y="-332" on="1"/>
+ <pt x="92" y="-328" on="0"/>
+ <pt x="105" y="-306" on="1"/>
+ <pt x="118" y="-286" on="0"/>
+ <pt x="119" y="-234" on="1"/>
+ <pt x="121" y="-136" on="1"/>
+ <pt x="119" y="1426" on="1"/>
+ <pt x="119" y="1489" on="0"/>
+ <pt x="93" y="1501" on="1"/>
+ <pt x="71" y="1513" on="0"/>
+ <pt x="19" y="1516" on="1"/>
+ <pt x="0" y="1517" on="1"/>
+ <pt x="0" y="1579" on="1"/>
+ <pt x="318" y="1579" on="1"/>
+ <pt x="318" y="907" on="1"/>
+ <pt x="376" y="999" on="0"/>
+ <pt x="432" y="1044" on="1"/>
+ <pt x="512" y="1110" on="0"/>
+ <pt x="610" y="1110" on="1"/>
+ <pt x="769" y="1110" on="0"/>
+ <pt x="863" y="968" on="1"/>
+ <pt x="956" y="826" on="0"/>
+ <pt x="956" y="575" on="1"/>
+ <pt x="956" y="293" on="0"/>
+ <pt x="835" y="134" on="1"/>
+ <pt x="714" y="-25" on="0"/>
+ <pt x="503" y="-25" on="1"/>
+ <pt x="429" y="-25" on="0"/>
+ <pt x="318" y="0" on="1"/>
+ <pt x="318" y="-136" on="1"/>
+ <pt x="320" y="-235" on="1"/>
+ <pt x="321" y="-304" on="0"/>
+ <pt x="345" y="-317" on="1"/>
+ <pt x="367" y="-329" on="0"/>
+ <pt x="421" y="-332" on="1"/>
+ <pt x="439" y="-333" on="1"/>
+ <pt x="439" y="-395" on="1"/>
+ </contour>
+ <contour>
+ <pt x="318" y="77" on="1"/>
+ <pt x="399" y="54" on="0"/>
+ <pt x="449" y="54" on="1"/>
+ <pt x="585" y="54" on="0"/>
+ <pt x="664" y="181" on="1"/>
+ <pt x="743" y="308" on="0"/>
+ <pt x="743" y="536" on="1"/>
+ <pt x="743" y="983" on="0"/>
+ <pt x="542" y="983" on="1"/>
+ <pt x="449" y="983" on="0"/>
+ <pt x="318" y="837" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 47 29 20 41 21 28 48 84 28 2 20 1 1 13 14 1 2 0 1 1 49 39 16
+ 3 1 2 3 0 0 1 37 31 30 7 1 5 2 0 3 0 15 14 1 38 0 1 2 0
+ 14 0 0 45 10 24 48 196 38 37 2 13 24 15 14 13 7 1 0 5 13 15 49 39 31
+ 30 16 15 5 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="93" yMin="-37" xMax="910" yMax="1517">
+ <contour>
+ <pt x="93" y="10" on="1"/>
+ <pt x="93" y="271" on="1"/>
+ <pt x="191" y="271" on="1"/>
+ <pt x="192" y="249" on="1"/>
+ <pt x="195" y="182" on="1"/>
+ <pt x="198" y="113" on="0"/>
+ <pt x="261" y="72" on="1"/>
+ <pt x="324" y="31" on="0"/>
+ <pt x="422" y="31" on="1"/>
+ <pt x="550" y="31" on="0"/>
+ <pt x="625" y="128" on="1"/>
+ <pt x="700" y="226" on="0"/>
+ <pt x="700" y="388" on="1"/>
+ <pt x="700" y="565" on="0"/>
+ <pt x="606" y="662" on="1"/>
+ <pt x="512" y="759" on="0"/>
+ <pt x="338" y="759" on="1"/>
+ <pt x="228" y="759" on="1"/>
+ <pt x="228" y="820" on="1"/>
+ <pt x="294" y="820" on="1"/>
+ <pt x="669" y="820" on="0"/>
+ <pt x="669" y="1155" on="1"/>
+ <pt x="669" y="1450" on="0"/>
+ <pt x="418" y="1450" on="1"/>
+ <pt x="334" y="1450" on="0"/>
+ <pt x="270" y="1419" on="1"/>
+ <pt x="235" y="1402" on="0"/>
+ <pt x="222" y="1363" on="1"/>
+ <pt x="212" y="1331" on="0"/>
+ <pt x="204" y="1249" on="1"/>
+ <pt x="202" y="1234" on="1"/>
+ <pt x="104" y="1234" on="1"/>
+ <pt x="104" y="1460" on="1"/>
+ <pt x="271" y="1517" on="0"/>
+ <pt x="428" y="1517" on="1"/>
+ <pt x="634" y="1517" on="0"/>
+ <pt x="750" y="1427" on="1"/>
+ <pt x="866" y="1336" on="0"/>
+ <pt x="866" y="1176" on="1"/>
+ <pt x="866" y="1018" on="0"/>
+ <pt x="753" y="914" on="1"/>
+ <pt x="686" y="852" on="0"/>
+ <pt x="555" y="800" on="1"/>
+ <pt x="668" y="769" on="0"/>
+ <pt x="726" y="734" on="1"/>
+ <pt x="910" y="624" on="0"/>
+ <pt x="910" y="404" on="1"/>
+ <pt x="910" y="203" on="0"/>
+ <pt x="778" y="83" on="1"/>
+ <pt x="646" y="-37" on="0"/>
+ <pt x="417" y="-37" on="1"/>
+ <pt x="254" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 64 values pushed */
+ 0 0 23 17 34 8 17 50 48 84 50 2 34 0 1 1 42 32 31 30 19 18 17 16 2
+ 1 0 11 0 2 3 0 0 14 0 0 21 5 38 12 10 46 48 196 42 30 19 18 17 16
+ 2 7 13 46 38 31 32 31 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="threequarters" xMin="173" yMin="-37" xMax="1364" yMax="1517">
+ <contour>
+ <pt x="173" y="-37" on="1"/>
+ <pt x="1261" y="1517" on="1"/>
+ <pt x="1347" y="1517" on="1"/>
+ <pt x="259" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1065" y="0" on="1"/>
+ <pt x="1065" y="39" on="1"/>
+ <pt x="1075" y="39" on="1"/>
+ <pt x="1126" y="39" on="0"/>
+ <pt x="1139" y="48" on="1"/>
+ <pt x="1153" y="56" on="0"/>
+ <pt x="1155" y="88" on="1"/>
+ <pt x="1158" y="137" on="1"/>
+ <pt x="1158" y="205" on="1"/>
+ <pt x="813" y="205" on="1"/>
+ <pt x="813" y="271" on="1"/>
+ <pt x="1181" y="751" on="1"/>
+ <pt x="1271" y="751" on="1"/>
+ <pt x="1271" y="294" on="1"/>
+ <pt x="1364" y="294" on="1"/>
+ <pt x="1364" y="205" on="1"/>
+ <pt x="1271" y="205" on="1"/>
+ <pt x="1271" y="137" on="1"/>
+ <pt x="1274" y="88" on="1"/>
+ <pt x="1276" y="52" on="0"/>
+ <pt x="1297" y="45" on="1"/>
+ <pt x="1313" y="39" on="0"/>
+ <pt x="1348" y="39" on="1"/>
+ <pt x="1358" y="39" on="1"/>
+ <pt x="1358" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="878" y="294" on="1"/>
+ <pt x="1158" y="294" on="1"/>
+ <pt x="1158" y="658" on="1"/>
+ </contour>
+ <contour>
+ <pt x="173" y="766" on="1"/>
+ <pt x="173" y="901" on="1"/>
+ <pt x="232" y="901" on="1"/>
+ <pt x="232" y="891" on="1"/>
+ <pt x="233" y="881" on="1"/>
+ <pt x="233" y="872" on="1"/>
+ <pt x="234" y="865" on="0"/>
+ <pt x="234" y="861" on="1"/>
+ <pt x="234" y="858" on="1"/>
+ <pt x="234" y="779" on="0"/>
+ <pt x="353" y="779" on="1"/>
+ <pt x="502" y="779" on="0"/>
+ <pt x="502" y="951" on="1"/>
+ <pt x="502" y="1133" on="0"/>
+ <pt x="297" y="1133" on="1"/>
+ <pt x="241" y="1133" on="1"/>
+ <pt x="241" y="1172" on="1"/>
+ <pt x="279" y="1172" on="1"/>
+ <pt x="483" y="1172" on="0"/>
+ <pt x="483" y="1334" on="1"/>
+ <pt x="483" y="1479" on="0"/>
+ <pt x="352" y="1479" on="1"/>
+ <pt x="246" y="1479" on="0"/>
+ <pt x="242" y="1415" on="1"/>
+ <pt x="239" y="1370" on="1"/>
+ <pt x="238" y="1362" on="1"/>
+ <pt x="178" y="1362" on="1"/>
+ <pt x="178" y="1487" on="1"/>
+ <pt x="273" y="1517" on="0"/>
+ <pt x="371" y="1517" on="1"/>
+ <pt x="606" y="1517" on="0"/>
+ <pt x="606" y="1344" on="1"/>
+ <pt x="606" y="1214" on="0"/>
+ <pt x="446" y="1158" on="1"/>
+ <pt x="630" y="1110" on="0"/>
+ <pt x="630" y="959" on="1"/>
+ <pt x="630" y="858" on="0"/>
+ <pt x="558" y="800" on="1"/>
+ <pt x="486" y="741" on="0"/>
+ <pt x="358" y="741" on="1"/>
+ <pt x="260" y="741" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 150 values pushed */
+ 0 0 53 45 61 42 45 71 48 84 14 17 12 2 27 26 21 11 6 5 6 12 4 3 65
+ 59 58 57 49 48 47 46 40 39 37 36 35 34 33 32 31 16 15 2 1 21 13 71 61 17
+ 3 0 4 0 0 30 29 18 17 46 3 12 1 4 48 84 20 19 13 12 3 28 4 1 2
+ 0 14 0 0 51 44 63 44 44 67 48 196 15 1 2 16 11 3 28 27 26 19 18 2 6
+ 13 16 65 59 58 57 49 48 47 46 40 39 37 36 35 34 33 32 29 14 13 6 5 4 3
+ 0 24 13 67 63 11 0 0 31 30 12 11 15 3 16 1 4 48 196 21 20 17 16 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="threesuperior" xMin="86" yMin="741" xMax="543" yMax="1517">
+ <contour>
+ <pt x="86" y="766" on="1"/>
+ <pt x="86" y="901" on="1"/>
+ <pt x="145" y="901" on="1"/>
+ <pt x="145" y="891" on="1"/>
+ <pt x="146" y="881" on="1"/>
+ <pt x="146" y="872" on="1"/>
+ <pt x="147" y="865" on="0"/>
+ <pt x="147" y="861" on="1"/>
+ <pt x="147" y="858" on="1"/>
+ <pt x="147" y="779" on="0"/>
+ <pt x="267" y="779" on="1"/>
+ <pt x="415" y="779" on="0"/>
+ <pt x="415" y="951" on="1"/>
+ <pt x="415" y="1133" on="0"/>
+ <pt x="210" y="1133" on="1"/>
+ <pt x="154" y="1133" on="1"/>
+ <pt x="154" y="1172" on="1"/>
+ <pt x="192" y="1172" on="1"/>
+ <pt x="396" y="1172" on="0"/>
+ <pt x="396" y="1334" on="1"/>
+ <pt x="396" y="1479" on="0"/>
+ <pt x="265" y="1479" on="1"/>
+ <pt x="159" y="1479" on="0"/>
+ <pt x="155" y="1415" on="1"/>
+ <pt x="152" y="1370" on="1"/>
+ <pt x="151" y="1362" on="1"/>
+ <pt x="91" y="1362" on="1"/>
+ <pt x="91" y="1487" on="1"/>
+ <pt x="192" y="1517" on="0"/>
+ <pt x="284" y="1517" on="1"/>
+ <pt x="519" y="1517" on="0"/>
+ <pt x="519" y="1344" on="1"/>
+ <pt x="519" y="1215" on="0"/>
+ <pt x="359" y="1158" on="1"/>
+ <pt x="466" y="1130" on="0"/>
+ <pt x="508" y="1073" on="1"/>
+ <pt x="543" y="1026" on="0"/>
+ <pt x="543" y="959" on="1"/>
+ <pt x="543" y="858" on="0"/>
+ <pt x="471" y="800" on="1"/>
+ <pt x="400" y="741" on="0"/>
+ <pt x="271" y="741" on="1"/>
+ <pt x="173" y="741" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 0 0 21 45 29 10 45 41 48 84 41 33 29 27 26 25 17 16 15 14 8 7 5 4 3
+ 2 1 0 14 0 0 19 44 31 12 44 37 48 196 37 33 31 27 26 25 17 16 15 14 8
+ 7 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tilde" xMin="8" yMin="1283" xMax="674" yMax="1518">
+ <contour>
+ <pt x="8" y="1283" on="1"/>
+ <pt x="35" y="1423" on="0"/>
+ <pt x="104" y="1476" on="1"/>
+ <pt x="158" y="1518" on="0"/>
+ <pt x="235" y="1518" on="1"/>
+ <pt x="300" y="1518" on="0"/>
+ <pt x="353" y="1480" on="1"/>
+ <pt x="388" y="1455" on="1"/>
+ <pt x="440" y="1418" on="0"/>
+ <pt x="494" y="1418" on="1"/>
+ <pt x="590" y="1418" on="0"/>
+ <pt x="612" y="1517" on="1"/>
+ <pt x="674" y="1517" on="1"/>
+ <pt x="646" y="1378" on="0"/>
+ <pt x="578" y="1325" on="1"/>
+ <pt x="524" y="1283" on="0"/>
+ <pt x="447" y="1283" on="1"/>
+ <pt x="384" y="1283" on="0"/>
+ <pt x="329" y="1321" on="1"/>
+ <pt x="294" y="1345" on="1"/>
+ <pt x="239" y="1383" on="0"/>
+ <pt x="187" y="1383" on="1"/>
+ <pt x="100" y="1383" on="0"/>
+ <pt x="70" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 0 0 21 20 4 9 20 16 48 84 4 0 1 12 11 2 13 0 0 1 23 0 16 0 0
+ 14 23 12 11 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="trademark" xMin="140" yMin="728" xMax="1867" yMax="1480">
+ <contour>
+ <pt x="411" y="1419" on="1"/>
+ <pt x="226" y="1419" on="1"/>
+ <pt x="226" y="1283" on="1"/>
+ <pt x="140" y="1283" on="1"/>
+ <pt x="140" y="1480" on="1"/>
+ <pt x="819" y="1480" on="1"/>
+ <pt x="819" y="1283" on="1"/>
+ <pt x="732" y="1283" on="1"/>
+ <pt x="732" y="1419" on="1"/>
+ <pt x="547" y="1419" on="1"/>
+ <pt x="547" y="790" on="1"/>
+ <pt x="671" y="790" on="1"/>
+ <pt x="671" y="728" on="1"/>
+ <pt x="288" y="728" on="1"/>
+ <pt x="288" y="790" on="1"/>
+ <pt x="411" y="790" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1358" y="795" on="1"/>
+ <pt x="1127" y="1413" on="1"/>
+ <pt x="1127" y="728" on="1"/>
+ <pt x="905" y="728" on="1"/>
+ <pt x="905" y="790" on="1"/>
+ <pt x="1028" y="790" on="1"/>
+ <pt x="1028" y="1419" on="1"/>
+ <pt x="893" y="1419" on="1"/>
+ <pt x="893" y="1480" on="1"/>
+ <pt x="1249" y="1480" on="1"/>
+ <pt x="1414" y="1038" on="1"/>
+ <pt x="1567" y="1480" on="1"/>
+ <pt x="1867" y="1480" on="1"/>
+ <pt x="1867" y="1419" on="1"/>
+ <pt x="1744" y="1419" on="1"/>
+ <pt x="1744" y="790" on="1"/>
+ <pt x="1867" y="790" on="1"/>
+ <pt x="1867" y="728" on="1"/>
+ <pt x="1608" y="728" on="1"/>
+ <pt x="1608" y="1413" on="1"/>
+ <pt x="1395" y="795" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 133 values pushed */
+ 36 35 32 31 26 21 20 17 16 15 14 11 10 7 6 3 2 17 0 12 3 0 0 30 29
+ 23 22 9 8 1 0 14 7 4 1 4 48 84 34 33 19 18 13 12 5 0 28 27 25 24
+ 5 4 0 5 14 36 27 26 25 16 5 34 17 3 24 23 20 19 4 21 5 3 12 11 8
+ 7 4 5 9 3 14 13 2 1 4 0 3 3 33 32 29 28 4 13 30 0 0 35 34 23
+ 1 30 22 21 9 1 17 10 9 23 1 0 3 4 48 196 31 30 1 18 17 1 6 5 1
+ 15 0 1 4 3 1 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="68" yMin="0" xMax="906" yMax="1518">
+ <contour>
+ <pt x="68" y="0" on="1"/>
+ <pt x="68" y="99" on="1"/>
+ <pt x="103" y="253" on="0"/>
+ <pt x="178" y="354" on="1"/>
+ <pt x="246" y="447" on="0"/>
+ <pt x="400" y="599" on="1"/>
+ <pt x="463" y="662" on="1"/>
+ <pt x="605" y="805" on="0"/>
+ <pt x="649" y="893" on="1"/>
+ <pt x="697" y="989" on="0"/>
+ <pt x="697" y="1129" on="1"/>
+ <pt x="697" y="1450" on="0"/>
+ <pt x="444" y="1450" on="1"/>
+ <pt x="346" y="1450" on="0"/>
+ <pt x="272" y="1400" on="1"/>
+ <pt x="240" y="1379" on="0"/>
+ <pt x="230" y="1358" on="1"/>
+ <pt x="206" y="1306" on="0"/>
+ <pt x="201" y="1182" on="1"/>
+ <pt x="200" y="1157" on="1"/>
+ <pt x="101" y="1157" on="1"/>
+ <pt x="101" y="1427" on="1"/>
+ <pt x="290" y="1518" on="0"/>
+ <pt x="480" y="1518" on="1"/>
+ <pt x="906" y="1518" on="0"/>
+ <pt x="906" y="1137" on="1"/>
+ <pt x="906" y="999" on="0"/>
+ <pt x="841" y="913" on="1"/>
+ <pt x="791" y="847" on="0"/>
+ <pt x="661" y="729" on="1"/>
+ <pt x="561" y="638" on="1"/>
+ <pt x="497" y="580" on="1"/>
+ <pt x="338" y="437" on="0"/>
+ <pt x="286" y="343" on="1"/>
+ <pt x="244" y="268" on="0"/>
+ <pt x="229" y="173" on="1"/>
+ <pt x="900" y="173" on="1"/>
+ <pt x="900" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 64 values pushed */
+ 0 0 12 17 23 48 84 23 0 1 21 20 19 3 0 35 3 0 1 35 0 2 0 0 36
+ 35 13 1 0 1 4 48 84 37 0 1 0 14 0 0 10 10 25 48 196 35 19 2 36 20
+ 3 25 36 1 0 20 37 36 1 21 20 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="twosuperior" xMin="86" yMin="759" xMax="556" yMax="1518">
+ <contour>
+ <pt x="86" y="759" on="1"/>
+ <pt x="86" y="809" on="1"/>
+ <pt x="127" y="925" on="0"/>
+ <pt x="238" y="1026" on="1"/>
+ <pt x="279" y="1064" on="1"/>
+ <pt x="426" y="1200" on="0"/>
+ <pt x="426" y="1322" on="1"/>
+ <pt x="426" y="1477" on="0"/>
+ <pt x="289" y="1477" on="1"/>
+ <pt x="228" y="1477" on="0"/>
+ <pt x="163" y="1428" on="1"/>
+ <pt x="163" y="1338" on="1"/>
+ <pt x="104" y="1338" on="1"/>
+ <pt x="104" y="1474" on="1"/>
+ <pt x="214" y="1518" on="0"/>
+ <pt x="313" y="1518" on="1"/>
+ <pt x="422" y="1518" on="0"/>
+ <pt x="489" y="1462" on="1"/>
+ <pt x="556" y="1406" on="0"/>
+ <pt x="556" y="1319" on="1"/>
+ <pt x="556" y="1247" on="0"/>
+ <pt x="503" y="1185" on="1"/>
+ <pt x="473" y="1148" on="0"/>
+ <pt x="404" y="1100" on="1"/>
+ <pt x="383" y="1086" on="0"/>
+ <pt x="370" y="1077" on="1"/>
+ <pt x="320" y="1040" on="1"/>
+ <pt x="208" y="957" on="0"/>
+ <pt x="198" y="864" on="1"/>
+ <pt x="554" y="864" on="1"/>
+ <pt x="554" y="759" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 0 0 8 45 15 48 84 1 28 0 2 13 12 11 10 4 13 15 28 0 0 30 0 43 1
+ 28 1 4 48 84 29 28 1 0 14 0 0 6 44 19 48 196 30 29 28 19 13 12 11 10
+ 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="u" xMin="12" yMin="-25" xMax="993" yMax="1086">
+ <contour>
+ <pt x="675" y="0" on="1"/>
+ <pt x="675" y="179" on="1"/>
+ <pt x="611" y="87" on="0"/>
+ <pt x="551" y="41" on="1"/>
+ <pt x="466" y="-25" on="0"/>
+ <pt x="364" y="-25" on="1"/>
+ <pt x="240" y="-25" on="0"/>
+ <pt x="186" y="53" on="1"/>
+ <pt x="133" y="131" on="0"/>
+ <pt x="133" y="321" on="1"/>
+ <pt x="133" y="827" on="1"/>
+ <pt x="131" y="925" on="1"/>
+ <pt x="131" y="993" on="0"/>
+ <pt x="106" y="1007" on="1"/>
+ <pt x="86" y="1019" on="0"/>
+ <pt x="31" y="1023" on="1"/>
+ <pt x="12" y="1024" on="1"/>
+ <pt x="12" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="352" on="1"/>
+ <pt x="333" y="274" on="1"/>
+ <pt x="335" y="188" on="0"/>
+ <pt x="357" y="150" on="1"/>
+ <pt x="383" y="105" on="0"/>
+ <pt x="439" y="105" on="1"/>
+ <pt x="554" y="105" on="0"/>
+ <pt x="675" y="245" on="1"/>
+ <pt x="675" y="827" on="1"/>
+ <pt x="673" y="925" on="1"/>
+ <pt x="672" y="994" on="0"/>
+ <pt x="648" y="1007" on="1"/>
+ <pt x="627" y="1019" on="0"/>
+ <pt x="573" y="1023" on="1"/>
+ <pt x="554" y="1024" on="1"/>
+ <pt x="554" y="1086" on="1"/>
+ <pt x="872" y="1086" on="1"/>
+ <pt x="872" y="259" on="1"/>
+ <pt x="874" y="160" on="1"/>
+ <pt x="874" y="92" on="0"/>
+ <pt x="899" y="78" on="1"/>
+ <pt x="922" y="66" on="0"/>
+ <pt x="974" y="63" on="1"/>
+ <pt x="993" y="62" on="1"/>
+ <pt x="993" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 0 0 24 29 5 48 84 5 2 42 36 33 27 26 19 16 10 9 1 10 17 0 3 43 0
+ 1 0 35 34 18 17 1 3 14 34 33 2 0 18 3 43 42 2 13 35 17 16 9 0 0
+ 27 26 1 0 4 3 35 19 18 4 1 9 2 4 48 196 36 35 1 10 9 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="uacute" xMin="12" yMin="-25" xMax="993" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="196" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ubreve" xMin="12" yMin="-25" xMax="993" yMax="1604">
+ <contour>
+ <pt x="675" y="0" on="1"/>
+ <pt x="675" y="179" on="1"/>
+ <pt x="611" y="87" on="0"/>
+ <pt x="551" y="41" on="1"/>
+ <pt x="466" y="-25" on="0"/>
+ <pt x="364" y="-25" on="1"/>
+ <pt x="240" y="-25" on="0"/>
+ <pt x="186" y="53" on="1"/>
+ <pt x="133" y="131" on="0"/>
+ <pt x="133" y="321" on="1"/>
+ <pt x="133" y="827" on="1"/>
+ <pt x="131" y="925" on="1"/>
+ <pt x="131" y="993" on="0"/>
+ <pt x="106" y="1007" on="1"/>
+ <pt x="86" y="1019" on="0"/>
+ <pt x="31" y="1023" on="1"/>
+ <pt x="12" y="1024" on="1"/>
+ <pt x="12" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="352" on="1"/>
+ <pt x="333" y="274" on="1"/>
+ <pt x="335" y="188" on="0"/>
+ <pt x="357" y="150" on="1"/>
+ <pt x="383" y="105" on="0"/>
+ <pt x="439" y="105" on="1"/>
+ <pt x="554" y="105" on="0"/>
+ <pt x="675" y="245" on="1"/>
+ <pt x="675" y="827" on="1"/>
+ <pt x="673" y="925" on="1"/>
+ <pt x="672" y="994" on="0"/>
+ <pt x="648" y="1007" on="1"/>
+ <pt x="627" y="1019" on="0"/>
+ <pt x="573" y="1023" on="1"/>
+ <pt x="554" y="1024" on="1"/>
+ <pt x="554" y="1086" on="1"/>
+ <pt x="872" y="1086" on="1"/>
+ <pt x="872" y="259" on="1"/>
+ <pt x="874" y="160" on="1"/>
+ <pt x="874" y="92" on="0"/>
+ <pt x="899" y="78" on="1"/>
+ <pt x="922" y="66" on="0"/>
+ <pt x="974" y="63" on="1"/>
+ <pt x="993" y="62" on="1"/>
+ <pt x="993" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="146" y="1604" on="1"/>
+ <pt x="211" y="1604" on="1"/>
+ <pt x="238" y="1514" on="0"/>
+ <pt x="298" y="1472" on="1"/>
+ <pt x="366" y="1425" on="0"/>
+ <pt x="479" y="1425" on="1"/>
+ <pt x="605" y="1425" on="0"/>
+ <pt x="675" y="1484" on="1"/>
+ <pt x="724" y="1524" on="0"/>
+ <pt x="748" y="1604" on="1"/>
+ <pt x="812" y="1604" on="1"/>
+ <pt x="793" y="1469" on="0"/>
+ <pt x="721" y="1388" on="1"/>
+ <pt x="626" y="1283" on="0"/>
+ <pt x="479" y="1283" on="1"/>
+ <pt x="325" y="1283" on="0"/>
+ <pt x="230" y="1398" on="1"/>
+ <pt x="165" y="1476" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 0 0 49 20 58 24 29 5 48 84 5 2 42 36 33 27 26 19 16 10 9 1 10 17 0
+ 3 54 53 45 44 4 13 58 17 43 0 1 0 35 34 18 17 1 3 14 54 53 2 35 0
+ 3 34 33 2 0 18 3 45 44 2 18 9 3 43 42 2 13 35 17 16 9 0 0 27 26
+ 1 0 4 3 35 19 18 4 1 9 2 4 48 196 36 35 1 10 9 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ucircumflex" xMin="12" yMin="-25" xMax="993" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="143" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="udieresis" xMin="12" yMin="-25" xMax="993" yMax="1456">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="162" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ugrave" xMin="12" yMin="-25" xMax="993" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="78" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="uhungarumlaut" xMin="12" yMin="-25" xMax="993" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="hungarumlaut" x="249" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="umacron" xMin="12" yMin="-25" xMax="993" yMax="1406">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="161" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="underscore" xMin="0" yMin="-123" xMax="1024" yMax="0">
+ <contour>
+ <pt x="0" y="-123" on="1"/>
+ <pt x="0" y="0" on="1"/>
+ <pt x="1024" y="0" on="1"/>
+ <pt x="1024" y="-123" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 12 1 1 1 4 48 84 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="uogonek" xMin="12" yMin="-370" xMax="993" yMax="1086">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="419" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="uring" xMin="12" yMin="-25" xMax="993" yMax="1737">
+ <contour>
+ <pt x="675" y="0" on="1"/>
+ <pt x="675" y="179" on="1"/>
+ <pt x="611" y="87" on="0"/>
+ <pt x="551" y="41" on="1"/>
+ <pt x="466" y="-25" on="0"/>
+ <pt x="364" y="-25" on="1"/>
+ <pt x="240" y="-25" on="0"/>
+ <pt x="186" y="53" on="1"/>
+ <pt x="133" y="131" on="0"/>
+ <pt x="133" y="321" on="1"/>
+ <pt x="133" y="827" on="1"/>
+ <pt x="131" y="925" on="1"/>
+ <pt x="131" y="993" on="0"/>
+ <pt x="106" y="1007" on="1"/>
+ <pt x="86" y="1019" on="0"/>
+ <pt x="31" y="1023" on="1"/>
+ <pt x="12" y="1024" on="1"/>
+ <pt x="12" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="352" on="1"/>
+ <pt x="333" y="274" on="1"/>
+ <pt x="335" y="188" on="0"/>
+ <pt x="357" y="150" on="1"/>
+ <pt x="383" y="105" on="0"/>
+ <pt x="439" y="105" on="1"/>
+ <pt x="554" y="105" on="0"/>
+ <pt x="675" y="245" on="1"/>
+ <pt x="675" y="827" on="1"/>
+ <pt x="673" y="925" on="1"/>
+ <pt x="672" y="994" on="0"/>
+ <pt x="648" y="1007" on="1"/>
+ <pt x="627" y="1019" on="0"/>
+ <pt x="573" y="1023" on="1"/>
+ <pt x="554" y="1024" on="1"/>
+ <pt x="554" y="1086" on="1"/>
+ <pt x="872" y="1086" on="1"/>
+ <pt x="872" y="259" on="1"/>
+ <pt x="874" y="160" on="1"/>
+ <pt x="874" y="92" on="0"/>
+ <pt x="899" y="78" on="1"/>
+ <pt x="922" y="66" on="0"/>
+ <pt x="974" y="63" on="1"/>
+ <pt x="993" y="62" on="1"/>
+ <pt x="993" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="491" y="1737" on="1"/>
+ <pt x="585" y="1737" on="0"/>
+ <pt x="651" y="1671" on="1"/>
+ <pt x="718" y="1605" on="0"/>
+ <pt x="718" y="1511" on="1"/>
+ <pt x="718" y="1415" on="0"/>
+ <pt x="651" y="1349" on="1"/>
+ <pt x="584" y="1283" on="0"/>
+ <pt x="489" y="1283" on="1"/>
+ <pt x="405" y="1283" on="0"/>
+ <pt x="344" y="1337" on="1"/>
+ <pt x="264" y="1407" on="0"/>
+ <pt x="264" y="1510" on="1"/>
+ <pt x="264" y="1605" on="0"/>
+ <pt x="330" y="1671" on="1"/>
+ <pt x="396" y="1737" on="0"/>
+ </contour>
+ <contour>
+ <pt x="491" y="1669" on="1"/>
+ <pt x="425" y="1669" on="0"/>
+ <pt x="378" y="1623" on="1"/>
+ <pt x="332" y="1576" on="0"/>
+ <pt x="332" y="1511" on="1"/>
+ <pt x="332" y="1445" on="0"/>
+ <pt x="378" y="1398" on="1"/>
+ <pt x="424" y="1351" on="0"/>
+ <pt x="489" y="1351" on="1"/>
+ <pt x="550" y="1351" on="0"/>
+ <pt x="594" y="1388" on="1"/>
+ <pt x="650" y="1437" on="0"/>
+ <pt x="650" y="1511" on="1"/>
+ <pt x="650" y="1577" on="0"/>
+ <pt x="603" y="1623" on="1"/>
+ <pt x="556" y="1669" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 68 17 52 60 17 44 24 29 5 48 84 5 2 42 36 33 27 26 19 16 10 9 1
+ 10 17 0 3 52 44 17 43 0 1 0 35 34 18 17 1 3 14 0 0 72 17 48 64 17
+ 56 48 196 48 48 35 0 2 34 33 2 0 18 3 56 56 18 9 2 43 42 2 13 35 17
+ 16 9 0 0 27 26 1 0 4 3 35 19 18 4 1 9 2 4 48 196 36 35 1 10 9
+ 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="utilde" xMin="12" yMin="-25" xMax="993" yMax="1518">
+ <contour>
+ <pt x="675" y="0" on="1"/>
+ <pt x="675" y="179" on="1"/>
+ <pt x="611" y="87" on="0"/>
+ <pt x="551" y="41" on="1"/>
+ <pt x="466" y="-25" on="0"/>
+ <pt x="364" y="-25" on="1"/>
+ <pt x="240" y="-25" on="0"/>
+ <pt x="186" y="53" on="1"/>
+ <pt x="133" y="131" on="0"/>
+ <pt x="133" y="321" on="1"/>
+ <pt x="133" y="827" on="1"/>
+ <pt x="131" y="925" on="1"/>
+ <pt x="131" y="993" on="0"/>
+ <pt x="106" y="1007" on="1"/>
+ <pt x="86" y="1019" on="0"/>
+ <pt x="31" y="1023" on="1"/>
+ <pt x="12" y="1024" on="1"/>
+ <pt x="12" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="352" on="1"/>
+ <pt x="333" y="274" on="1"/>
+ <pt x="335" y="188" on="0"/>
+ <pt x="357" y="150" on="1"/>
+ <pt x="383" y="105" on="0"/>
+ <pt x="439" y="105" on="1"/>
+ <pt x="554" y="105" on="0"/>
+ <pt x="675" y="245" on="1"/>
+ <pt x="675" y="827" on="1"/>
+ <pt x="673" y="925" on="1"/>
+ <pt x="672" y="994" on="0"/>
+ <pt x="648" y="1007" on="1"/>
+ <pt x="627" y="1019" on="0"/>
+ <pt x="573" y="1023" on="1"/>
+ <pt x="554" y="1024" on="1"/>
+ <pt x="554" y="1086" on="1"/>
+ <pt x="872" y="1086" on="1"/>
+ <pt x="872" y="259" on="1"/>
+ <pt x="874" y="160" on="1"/>
+ <pt x="874" y="92" on="0"/>
+ <pt x="899" y="78" on="1"/>
+ <pt x="922" y="66" on="0"/>
+ <pt x="974" y="63" on="1"/>
+ <pt x="993" y="62" on="1"/>
+ <pt x="993" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="158" y="1283" on="1"/>
+ <pt x="185" y="1423" on="0"/>
+ <pt x="254" y="1476" on="1"/>
+ <pt x="308" y="1518" on="0"/>
+ <pt x="385" y="1518" on="1"/>
+ <pt x="450" y="1518" on="0"/>
+ <pt x="503" y="1480" on="1"/>
+ <pt x="538" y="1455" on="1"/>
+ <pt x="590" y="1418" on="0"/>
+ <pt x="644" y="1418" on="1"/>
+ <pt x="739" y="1418" on="0"/>
+ <pt x="762" y="1517" on="1"/>
+ <pt x="824" y="1517" on="1"/>
+ <pt x="796" y="1378" on="0"/>
+ <pt x="728" y="1325" on="1"/>
+ <pt x="674" y="1283" on="0"/>
+ <pt x="597" y="1283" on="1"/>
+ <pt x="534" y="1283" on="0"/>
+ <pt x="479" y="1321" on="1"/>
+ <pt x="444" y="1345" on="1"/>
+ <pt x="389" y="1383" on="0"/>
+ <pt x="337" y="1383" on="1"/>
+ <pt x="249" y="1383" on="0"/>
+ <pt x="220" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 111 values pushed */
+ 0 0 65 20 48 53 20 60 24 29 5 48 84 48 0 5 2 60 1 67 60 44 3 0 17
+ 3 0 42 36 33 27 26 19 16 10 9 1 10 17 0 3 1 56 55 2 13 0 0 43 0
+ 1 0 35 34 18 17 1 3 14 56 55 2 35 0 3 34 33 2 0 18 3 67 44 2 18
+ 9 3 43 42 2 13 35 17 16 9 0 0 27 26 1 0 4 3 35 19 18 4 1 9 2
+ 4 48 196 36 35 1 10 9 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="v" xMin="0" yMin="-12" xMax="1024" yMax="1086">
+ <contour>
+ <pt x="493" y="-12" on="1"/>
+ <pt x="156" y="820" on="1"/>
+ <pt x="76" y="1019" on="0"/>
+ <pt x="18" y="1023" on="1"/>
+ <pt x="0" y="1024" on="1"/>
+ <pt x="0" y="1086" on="1"/>
+ <pt x="438" y="1086" on="1"/>
+ <pt x="438" y="1024" on="1"/>
+ <pt x="418" y="1024" on="1"/>
+ <pt x="389" y="1023" on="1"/>
+ <pt x="311" y="1020" on="0"/>
+ <pt x="311" y="982" on="1"/>
+ <pt x="311" y="964" on="0"/>
+ <pt x="341" y="891" on="1"/>
+ <pt x="371" y="818" on="1"/>
+ <pt x="591" y="272" on="1"/>
+ <pt x="795" y="817" on="1"/>
+ <pt x="821" y="884" on="1"/>
+ <pt x="852" y="964" on="0"/>
+ <pt x="852" y="982" on="1"/>
+ <pt x="852" y="1024" on="0"/>
+ <pt x="758" y="1024" on="1"/>
+ <pt x="736" y="1024" on="1"/>
+ <pt x="736" y="1086" on="1"/>
+ <pt x="1024" y="1086" on="1"/>
+ <pt x="1024" y="1024" on="1"/>
+ <pt x="1007" y="1023" on="1"/>
+ <pt x="946" y="1018" on="0"/>
+ <pt x="912" y="931" on="1"/>
+ <pt x="867" y="817" on="1"/>
+ <pt x="553" y="-12" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 40 values pushed */
+ 1 25 22 21 15 8 7 4 7 5 2 3 0 1 30 0 2 0 24 23 6 5 1 3 14
+ 30 25 24 23 22 21 19 15 11 8 7 6 5 4 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="w" xMin="0" yMin="-12" xMax="1479" yMax="1086">
+ <contour>
+ <pt x="382" y="-12" on="1"/>
+ <pt x="152" y="827" on="1"/>
+ <pt x="118" y="950" on="0"/>
+ <pt x="95" y="985" on="1"/>
+ <pt x="72" y="1020" on="0"/>
+ <pt x="19" y="1023" on="1"/>
+ <pt x="0" y="1024" on="1"/>
+ <pt x="0" y="1086" on="1"/>
+ <pt x="445" y="1086" on="1"/>
+ <pt x="445" y="1024" on="1"/>
+ <pt x="424" y="1024" on="1"/>
+ <pt x="322" y="1024" on="0"/>
+ <pt x="322" y="977" on="1"/>
+ <pt x="322" y="943" on="0"/>
+ <pt x="354" y="827" on="1"/>
+ <pt x="493" y="323" on="1"/>
+ <pt x="757" y="1080" on="1"/>
+ <pt x="823" y="1080" on="1"/>
+ <pt x="1098" y="284" on="1"/>
+ <pt x="1259" y="827" on="1"/>
+ <pt x="1276" y="885" on="1"/>
+ <pt x="1295" y="954" on="1"/>
+ <pt x="1300" y="971" on="0"/>
+ <pt x="1300" y="979" on="1"/>
+ <pt x="1300" y="1021" on="0"/>
+ <pt x="1224" y="1023" on="1"/>
+ <pt x="1195" y="1024" on="1"/>
+ <pt x="1173" y="1024" on="1"/>
+ <pt x="1173" y="1086" on="1"/>
+ <pt x="1479" y="1086" on="1"/>
+ <pt x="1478" y="1024" on="1"/>
+ <pt x="1456" y="1023" on="1"/>
+ <pt x="1386" y="1019" on="0"/>
+ <pt x="1352" y="908" on="1"/>
+ <pt x="1327" y="827" on="1"/>
+ <pt x="1069" y="-12" on="1"/>
+ <pt x="1014" y="-12" on="1"/>
+ <pt x="727" y="801" on="1"/>
+ <pt x="443" y="-12" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 1 37 30 27 26 18 17 16 15 10 9 6 11 7 2 3 0 1 38 36 35 0 4 13 2
+ 0 29 28 8 7 1 3 14 38 37 36 35 30 29 28 27 26 23 18 17 16 15 12 10 9
+ 8 7 6 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="wcircumflex" xMin="0" yMin="-12" xMax="1479" yMax="1604">
+ <contour>
+ <pt x="382" y="-12" on="1"/>
+ <pt x="152" y="827" on="1"/>
+ <pt x="118" y="950" on="0"/>
+ <pt x="95" y="985" on="1"/>
+ <pt x="72" y="1020" on="0"/>
+ <pt x="19" y="1023" on="1"/>
+ <pt x="0" y="1024" on="1"/>
+ <pt x="0" y="1086" on="1"/>
+ <pt x="445" y="1086" on="1"/>
+ <pt x="445" y="1024" on="1"/>
+ <pt x="424" y="1024" on="1"/>
+ <pt x="322" y="1024" on="0"/>
+ <pt x="322" y="977" on="1"/>
+ <pt x="322" y="943" on="0"/>
+ <pt x="354" y="827" on="1"/>
+ <pt x="493" y="323" on="1"/>
+ <pt x="757" y="1080" on="1"/>
+ <pt x="823" y="1080" on="1"/>
+ <pt x="1098" y="284" on="1"/>
+ <pt x="1259" y="827" on="1"/>
+ <pt x="1276" y="885" on="1"/>
+ <pt x="1295" y="954" on="1"/>
+ <pt x="1300" y="971" on="0"/>
+ <pt x="1300" y="979" on="1"/>
+ <pt x="1300" y="1021" on="0"/>
+ <pt x="1224" y="1023" on="1"/>
+ <pt x="1195" y="1024" on="1"/>
+ <pt x="1173" y="1024" on="1"/>
+ <pt x="1173" y="1086" on="1"/>
+ <pt x="1479" y="1086" on="1"/>
+ <pt x="1478" y="1024" on="1"/>
+ <pt x="1456" y="1023" on="1"/>
+ <pt x="1386" y="1019" on="0"/>
+ <pt x="1352" y="908" on="1"/>
+ <pt x="1327" y="827" on="1"/>
+ <pt x="1069" y="-12" on="1"/>
+ <pt x="1014" y="-12" on="1"/>
+ <pt x="727" y="801" on="1"/>
+ <pt x="443" y="-12" on="1"/>
+ </contour>
+ <contour>
+ <pt x="458" y="1283" on="1"/>
+ <pt x="699" y="1604" on="1"/>
+ <pt x="921" y="1604" on="1"/>
+ <pt x="1161" y="1283" on="1"/>
+ <pt x="1075" y="1283" on="1"/>
+ <pt x="810" y="1505" on="1"/>
+ <pt x="544" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 1 44 40 0 2 0 1 45 43 42 39 4 0 7 3 0 1 37 30 27 26 18 17 16 15
+ 10 9 6 11 7 2 3 0 1 38 36 35 0 4 13 2 0 41 40 1 0 29 28 8 7
+ 1 3 14 45 44 43 42 41 40 39 38 37 36 35 30 29 28 27 26 23 18 17 16 15 12
+ 10 9 8 7 6 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="x" xMin="0" yMin="0" xMax="1024" yMax="1086">
+ <contour>
+ <pt x="6" y="0" on="1"/>
+ <pt x="6" y="62" on="1"/>
+ <pt x="22" y="63" on="1"/>
+ <pt x="86" y="68" on="0"/>
+ <pt x="135" y="138" on="1"/>
+ <pt x="218" y="256" on="1"/>
+ <pt x="406" y="523" on="1"/>
+ <pt x="219" y="824" on="1"/>
+ <pt x="127" y="971" on="0"/>
+ <pt x="103" y="995" on="1"/>
+ <pt x="79" y="1019" on="0"/>
+ <pt x="18" y="1023" on="1"/>
+ <pt x="0" y="1024" on="1"/>
+ <pt x="0" y="1086" on="1"/>
+ <pt x="492" y="1086" on="1"/>
+ <pt x="492" y="1024" on="1"/>
+ <pt x="472" y="1024" on="1"/>
+ <pt x="431" y="1022" on="1"/>
+ <pt x="363" y="1019" on="0"/>
+ <pt x="363" y="989" on="1"/>
+ <pt x="363" y="978" on="0"/>
+ <pt x="377" y="955" on="1"/>
+ <pt x="379" y="951" on="1"/>
+ <pt x="386" y="941" on="0"/>
+ <pt x="396" y="922" on="1"/>
+ <pt x="404" y="909" on="1"/>
+ <pt x="420" y="878" on="0"/>
+ <pt x="454" y="824" on="1"/>
+ <pt x="576" y="627" on="1"/>
+ <pt x="693" y="819" on="1"/>
+ <pt x="744" y="909" on="1"/>
+ <pt x="783" y="978" on="0"/>
+ <pt x="783" y="993" on="1"/>
+ <pt x="783" y="1022" on="0"/>
+ <pt x="729" y="1023" on="1"/>
+ <pt x="692" y="1024" on="1"/>
+ <pt x="669" y="1024" on="1"/>
+ <pt x="669" y="1086" on="1"/>
+ <pt x="987" y="1086" on="1"/>
+ <pt x="987" y="1024" on="1"/>
+ <pt x="967" y="1023" on="1"/>
+ <pt x="901" y="1018" on="0"/>
+ <pt x="871" y="978" on="1"/>
+ <pt x="842" y="943" on="0"/>
+ <pt x="768" y="824" on="1"/>
+ <pt x="613" y="570" on="1"/>
+ <pt x="805" y="258" on="1"/>
+ <pt x="879" y="137" on="0"/>
+ <pt x="916" y="101" on="1"/>
+ <pt x="952" y="67" on="0"/>
+ <pt x="1008" y="63" on="1"/>
+ <pt x="1024" y="62" on="1"/>
+ <pt x="1024" y="0" on="1"/>
+ <pt x="530" y="0" on="1"/>
+ <pt x="530" y="62" on="1"/>
+ <pt x="548" y="62" on="1"/>
+ <pt x="594" y="63" on="1"/>
+ <pt x="668" y="64" on="0"/>
+ <pt x="668" y="91" on="1"/>
+ <pt x="668" y="101" on="0"/>
+ <pt x="650" y="126" on="1"/>
+ <pt x="639" y="142" on="0"/>
+ <pt x="620" y="179" on="1"/>
+ <pt x="602" y="213" on="0"/>
+ <pt x="575" y="257" on="1"/>
+ <pt x="441" y="469" on="1"/>
+ <pt x="292" y="257" on="1"/>
+ <pt x="260" y="212" on="0"/>
+ <pt x="247" y="186" on="1"/>
+ <pt x="217" y="130" on="1"/>
+ <pt x="203" y="104" on="0"/>
+ <pt x="203" y="94" on="1"/>
+ <pt x="203" y="65" on="0"/>
+ <pt x="278" y="63" on="1"/>
+ <pt x="316" y="62" on="1"/>
+ <pt x="339" y="62" on="1"/>
+ <pt x="339" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 75 74 65 55 54 51 45 39 36 35 29 28 16 15 12 6 1 17 13 0 3 76 53 52 0
+ 3 0 38 37 14 13 1 3 14 76 75 74 71 65 58 55 54 53 52 51 45 39 38 37 36
+ 35 32 29 28 19 16 15 14 13 12 6 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="y" xMin="0" yMin="-395" xMax="1024" yMax="1086">
+ <contour>
+ <pt x="487" y="0" on="1"/>
+ <pt x="156" y="820" on="1"/>
+ <pt x="76" y="1020" on="0"/>
+ <pt x="17" y="1023" on="1"/>
+ <pt x="0" y="1024" on="1"/>
+ <pt x="0" y="1086" on="1"/>
+ <pt x="437" y="1086" on="1"/>
+ <pt x="437" y="1024" on="1"/>
+ <pt x="418" y="1024" on="1"/>
+ <pt x="389" y="1023" on="1"/>
+ <pt x="310" y="1020" on="0"/>
+ <pt x="310" y="982" on="1"/>
+ <pt x="310" y="961" on="0"/>
+ <pt x="340" y="891" on="1"/>
+ <pt x="371" y="818" on="1"/>
+ <pt x="591" y="272" on="1"/>
+ <pt x="794" y="817" on="1"/>
+ <pt x="820" y="884" on="1"/>
+ <pt x="851" y="964" on="0"/>
+ <pt x="851" y="982" on="1"/>
+ <pt x="851" y="1024" on="0"/>
+ <pt x="758" y="1024" on="1"/>
+ <pt x="736" y="1024" on="1"/>
+ <pt x="736" y="1086" on="1"/>
+ <pt x="1024" y="1086" on="1"/>
+ <pt x="1024" y="1024" on="1"/>
+ <pt x="1007" y="1023" on="1"/>
+ <pt x="945" y="1019" on="0"/>
+ <pt x="911" y="931" on="1"/>
+ <pt x="867" y="817" on="1"/>
+ <pt x="411" y="-395" on="1"/>
+ <pt x="162" y="-395" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 1 25 22 21 15 8 7 4 7 5 2 3 0 1 0 2 30 2 0 31 30 1 0 24 23
+ 6 5 1 3 14 31 30 25 24 23 22 21 19 15 11 8 7 6 5 4 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="yacute" xMin="0" yMin="-395" xMax="1024" yMax="1604">
+ <component glyphName="y" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="309" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ycircumflex" xMin="0" yMin="-395" xMax="1024" yMax="1604">
+ <contour>
+ <pt x="487" y="0" on="1"/>
+ <pt x="156" y="820" on="1"/>
+ <pt x="76" y="1020" on="0"/>
+ <pt x="17" y="1023" on="1"/>
+ <pt x="0" y="1024" on="1"/>
+ <pt x="0" y="1086" on="1"/>
+ <pt x="437" y="1086" on="1"/>
+ <pt x="437" y="1024" on="1"/>
+ <pt x="418" y="1024" on="1"/>
+ <pt x="389" y="1023" on="1"/>
+ <pt x="310" y="1020" on="0"/>
+ <pt x="310" y="982" on="1"/>
+ <pt x="310" y="961" on="0"/>
+ <pt x="340" y="891" on="1"/>
+ <pt x="371" y="818" on="1"/>
+ <pt x="591" y="272" on="1"/>
+ <pt x="794" y="817" on="1"/>
+ <pt x="820" y="884" on="1"/>
+ <pt x="851" y="964" on="0"/>
+ <pt x="851" y="982" on="1"/>
+ <pt x="851" y="1024" on="0"/>
+ <pt x="758" y="1024" on="1"/>
+ <pt x="736" y="1024" on="1"/>
+ <pt x="736" y="1086" on="1"/>
+ <pt x="1024" y="1086" on="1"/>
+ <pt x="1024" y="1024" on="1"/>
+ <pt x="1007" y="1023" on="1"/>
+ <pt x="945" y="1019" on="0"/>
+ <pt x="911" y="931" on="1"/>
+ <pt x="867" y="817" on="1"/>
+ <pt x="411" y="-395" on="1"/>
+ <pt x="162" y="-395" on="1"/>
+ </contour>
+ <contour>
+ <pt x="235" y="1283" on="1"/>
+ <pt x="476" y="1604" on="1"/>
+ <pt x="698" y="1604" on="1"/>
+ <pt x="938" y="1283" on="1"/>
+ <pt x="852" y="1283" on="1"/>
+ <pt x="587" y="1505" on="1"/>
+ <pt x="321" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 1 37 33 0 2 0 1 38 36 35 32 4 0 5 3 0 1 25 22 21 15 8 7 4 7
+ 5 2 3 0 1 0 2 30 2 0 34 33 1 31 30 1 2 0 24 23 6 5 1 3 14
+ 38 37 36 35 34 33 32 31 30 25 24 23 22 21 19 15 11 8 7 6 5 4 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ydieresis" xMin="0" yMin="-395" xMax="1024" yMax="1456">
+ <component glyphName="y" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="250" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="yen" xMin="0" yMin="0" xMax="1024" yMax="1480">
+ <contour>
+ <pt x="414" y="395" on="1"/>
+ <pt x="105" y="395" on="1"/>
+ <pt x="105" y="456" on="1"/>
+ <pt x="414" y="456" on="1"/>
+ <pt x="414" y="666" on="1"/>
+ <pt x="105" y="666" on="1"/>
+ <pt x="105" y="728" on="1"/>
+ <pt x="414" y="728" on="1"/>
+ <pt x="219" y="1182" on="1"/>
+ <pt x="152" y="1338" on="0"/>
+ <pt x="103" y="1378" on="1"/>
+ <pt x="62" y="1413" on="0"/>
+ <pt x="0" y="1417" on="1"/>
+ <pt x="0" y="1480" on="1"/>
+ <pt x="502" y="1480" on="1"/>
+ <pt x="502" y="1419" on="1"/>
+ <pt x="493" y="1419" on="0"/>
+ <pt x="478" y="1418" on="1"/>
+ <pt x="467" y="1418" on="1"/>
+ <pt x="455" y="1418" on="1"/>
+ <pt x="376" y="1418" on="0"/>
+ <pt x="376" y="1376" on="1"/>
+ <pt x="376" y="1349" on="0"/>
+ <pt x="399" y="1291" on="1"/>
+ <pt x="573" y="854" on="1"/>
+ <pt x="768" y="1312" on="1"/>
+ <pt x="787" y="1357" on="0"/>
+ <pt x="787" y="1385" on="1"/>
+ <pt x="787" y="1421" on="0"/>
+ <pt x="734" y="1418" on="1"/>
+ <pt x="726" y="1418" on="1"/>
+ <pt x="720" y="1417" on="1"/>
+ <pt x="709" y="1417" on="1"/>
+ <pt x="700" y="1417" on="1"/>
+ <pt x="683" y="1418" on="0"/>
+ <pt x="665" y="1419" on="1"/>
+ <pt x="665" y="1480" on="1"/>
+ <pt x="1024" y="1480" on="1"/>
+ <pt x="1024" y="1417" on="1"/>
+ <pt x="933" y="1409" on="0"/>
+ <pt x="897" y="1360" on="1"/>
+ <pt x="861" y="1314" on="0"/>
+ <pt x="804" y="1179" on="1"/>
+ <pt x="611" y="728" on="1"/>
+ <pt x="920" y="728" on="1"/>
+ <pt x="920" y="666" on="1"/>
+ <pt x="611" y="666" on="1"/>
+ <pt x="611" y="456" on="1"/>
+ <pt x="920" y="456" on="1"/>
+ <pt x="920" y="395" on="1"/>
+ <pt x="611" y="395" on="1"/>
+ <pt x="611" y="259" on="1"/>
+ <pt x="611" y="202" on="0"/>
+ <pt x="619" y="147" on="1"/>
+ <pt x="626" y="96" on="0"/>
+ <pt x="651" y="82" on="1"/>
+ <pt x="673" y="71" on="0"/>
+ <pt x="710" y="68" on="1"/>
+ <pt x="778" y="63" on="1"/>
+ <pt x="796" y="62" on="1"/>
+ <pt x="796" y="0" on="1"/>
+ <pt x="229" y="0" on="1"/>
+ <pt x="229" y="62" on="1"/>
+ <pt x="247" y="63" on="1"/>
+ <pt x="315" y="68" on="1"/>
+ <pt x="390" y="74" on="0"/>
+ <pt x="400" y="115" on="1"/>
+ <pt x="414" y="175" on="0"/>
+ <pt x="414" y="259" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 119 values pushed */
+ 68 61 51 60 32 29 38 35 32 29 24 19 18 17 15 12 10 13 6 3 0 0 46 45 5
+ 4 14 3 6 48 47 3 2 14 3 0 2 4 48 84 44 43 7 6 3 50 49 1 0 3
+ 61 60 1 3 0 37 36 14 13 0 3 14 61 68 60 51 24 19 18 17 15 14 6 43 0
+ 3 49 48 45 44 38 37 36 35 8 13 27 43 13 12 6 5 2 1 6 13 21 0 0 0
+ 51 50 47 46 43 4 4 0 1 4 48 196 68 7 4 3 0 4 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="z" xMin="62" yMin="0" xMax="846" yMax="1086">
+ <contour>
+ <pt x="62" y="0" on="1"/>
+ <pt x="62" y="62" on="1"/>
+ <pt x="590" y="1018" on="1"/>
+ <pt x="396" y="1018" on="1"/>
+ <pt x="300" y="1017" on="1"/>
+ <pt x="218" y="1017" on="0"/>
+ <pt x="207" y="991" on="1"/>
+ <pt x="197" y="972" on="0"/>
+ <pt x="198" y="926" on="1"/>
+ <pt x="198" y="913" on="1"/>
+ <pt x="198" y="900" on="1"/>
+ <pt x="197" y="875" on="0"/>
+ <pt x="197" y="869" on="1"/>
+ <pt x="195" y="848" on="1"/>
+ <pt x="90" y="848" on="1"/>
+ <pt x="90" y="1086" on="1"/>
+ <pt x="819" y="1086" on="1"/>
+ <pt x="819" y="1024" on="1"/>
+ <pt x="294" y="74" on="1"/>
+ <pt x="536" y="74" on="1"/>
+ <pt x="657" y="79" on="1"/>
+ <pt x="739" y="80" on="0"/>
+ <pt x="740" y="151" on="1"/>
+ <pt x="740" y="226" on="1"/>
+ <pt x="741" y="250" on="1"/>
+ <pt x="846" y="250" on="1"/>
+ <pt x="846" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 17 15 2 2 25 24 23 22 14 13 10 9 8 9 2 18 3 1 18 0 2 0 0 3 2
+ 14 1 15 19 18 21 1 0 2 4 48 84 26 0 1 0 16 15 1 14 24 23 22 19 18
+ 17 16 13 10 9 8 3 2 13 25 14 3 1 0 14 26 25 1 15 14 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="zacute" xMin="62" yMin="0" xMax="846" yMax="1604">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="234" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zcaron" xMin="62" yMin="0" xMax="846" yMax="1604">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="115" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zdotaccent" xMin="62" yMin="0" xMax="846" yMax="1480">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="dotaccent" x="113" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="56" yMin="-37" xMax="969" yMax="1517">
+ <contour>
+ <pt x="512" y="1517" on="1"/>
+ <pt x="712" y="1517" on="0"/>
+ <pt x="840" y="1300" on="1"/>
+ <pt x="969" y="1082" on="0"/>
+ <pt x="969" y="743" on="1"/>
+ <pt x="969" y="397" on="0"/>
+ <pt x="841" y="180" on="1"/>
+ <pt x="713" y="-37" on="0"/>
+ <pt x="506" y="-37" on="1"/>
+ <pt x="332" y="-37" on="0"/>
+ <pt x="211" y="138" on="1"/>
+ <pt x="56" y="363" on="0"/>
+ <pt x="56" y="741" on="1"/>
+ <pt x="56" y="1083" on="0"/>
+ <pt x="184" y="1299" on="1"/>
+ <pt x="312" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="512" y="1456" on="1"/>
+ <pt x="265" y="1456" on="0"/>
+ <pt x="265" y="743" on="1"/>
+ <pt x="265" y="25" on="0"/>
+ <pt x="519" y="25" on="1"/>
+ <pt x="759" y="25" on="0"/>
+ <pt x="759" y="755" on="1"/>
+ <pt x="759" y="1016" on="0"/>
+ <pt x="712" y="1233" on="1"/>
+ <pt x="688" y="1343" on="0"/>
+ <pt x="623" y="1408" on="1"/>
+ <pt x="576" y="1456" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 20 11 8 16 11 0 48 84 8 2 0 0 14 0 0 22 10 4 18 10 12 48 196
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ </glyf>
+
+ <kern>
+ <version value="0"/>
+ <kernsubtable coverage="1" format="0">
+ <pair l="A" r="C" v="-106"/>
+ <pair l="A" r="Ccedilla" v="-115"/>
+ <pair l="A" r="G" v="-107"/>
+ <pair l="A" r="O" v="-96"/>
+ <pair l="A" r="Odieresis" v="-96"/>
+ <pair l="A" r="Q" v="-95"/>
+ <pair l="A" r="T" v="-78"/>
+ <pair l="A" r="U" v="-111"/>
+ <pair l="A" r="Uacute" v="-111"/>
+ <pair l="A" r="Ucircumflex" v="-111"/>
+ <pair l="A" r="Udieresis" v="-111"/>
+ <pair l="A" r="Ugrave" v="-111"/>
+ <pair l="A" r="V" v="-239"/>
+ <pair l="A" r="W" v="-172"/>
+ <pair l="A" r="Y" v="-143"/>
+ <pair l="A" r="a" v="-1"/>
+ <pair l="A" r="b" v="7"/>
+ <pair l="A" r="c" v="-71"/>
+ <pair l="A" r="ccedilla" v="-87"/>
+ <pair l="A" r="comma" v="10"/>
+ <pair l="A" r="d" v="-32"/>
+ <pair l="A" r="e" v="-61"/>
+ <pair l="A" r="g" v="-11"/>
+ <pair l="A" r="guillemotleft" v="-108"/>
+ <pair l="A" r="guilsinglleft" v="-114"/>
+ <pair l="A" r="hyphen" v="-61"/>
+ <pair l="A" r="o" v="-50"/>
+ <pair l="A" r="period" v="10"/>
+ <pair l="A" r="q" v="-32"/>
+ <pair l="A" r="quotedblright" v="-216"/>
+ <pair l="A" r="quoteright" v="-258"/>
+ <pair l="A" r="t" v="-24"/>
+ <pair l="A" r="u" v="-19"/>
+ <pair l="A" r="v" v="-149"/>
+ <pair l="A" r="w" v="-112"/>
+ <pair l="A" r="y" v="-150"/>
+ <pair l="Aacute" r="C" v="-106"/>
+ <pair l="Aacute" r="G" v="-107"/>
+ <pair l="Aacute" r="O" v="-96"/>
+ <pair l="Aacute" r="Q" v="-95"/>
+ <pair l="Aacute" r="T" v="-78"/>
+ <pair l="Aacute" r="U" v="-111"/>
+ <pair l="Aacute" r="V" v="-239"/>
+ <pair l="Aacute" r="W" v="-172"/>
+ <pair l="Aacute" r="Y" v="-143"/>
+ <pair l="Aacute" r="a" v="-1"/>
+ <pair l="Aacute" r="b" v="7"/>
+ <pair l="Aacute" r="c" v="-71"/>
+ <pair l="Aacute" r="comma" v="10"/>
+ <pair l="Aacute" r="d" v="-32"/>
+ <pair l="Aacute" r="e" v="-61"/>
+ <pair l="Aacute" r="g" v="-11"/>
+ <pair l="Aacute" r="guillemotleft" v="-108"/>
+ <pair l="Aacute" r="guilsinglleft" v="-114"/>
+ <pair l="Aacute" r="hyphen" v="-61"/>
+ <pair l="Aacute" r="o" v="-50"/>
+ <pair l="Aacute" r="period" v="10"/>
+ <pair l="Aacute" r="q" v="-32"/>
+ <pair l="Aacute" r="quoteright" v="-258"/>
+ <pair l="Aacute" r="t" v="-24"/>
+ <pair l="Aacute" r="u" v="-19"/>
+ <pair l="Aacute" r="v" v="-149"/>
+ <pair l="Aacute" r="w" v="-112"/>
+ <pair l="Aacute" r="y" v="-150"/>
+ <pair l="Acircumflex" r="C" v="-106"/>
+ <pair l="Acircumflex" r="G" v="-107"/>
+ <pair l="Acircumflex" r="O" v="-96"/>
+ <pair l="Acircumflex" r="Q" v="-95"/>
+ <pair l="Acircumflex" r="T" v="-78"/>
+ <pair l="Acircumflex" r="U" v="-111"/>
+ <pair l="Acircumflex" r="V" v="-239"/>
+ <pair l="Acircumflex" r="W" v="-172"/>
+ <pair l="Acircumflex" r="Y" v="-143"/>
+ <pair l="Acircumflex" r="comma" v="10"/>
+ <pair l="Acircumflex" r="period" v="10"/>
+ <pair l="Adieresis" r="C" v="-106"/>
+ <pair l="Adieresis" r="G" v="-107"/>
+ <pair l="Adieresis" r="O" v="-96"/>
+ <pair l="Adieresis" r="Q" v="-95"/>
+ <pair l="Adieresis" r="T" v="-78"/>
+ <pair l="Adieresis" r="U" v="-111"/>
+ <pair l="Adieresis" r="V" v="-239"/>
+ <pair l="Adieresis" r="W" v="-172"/>
+ <pair l="Adieresis" r="Y" v="-143"/>
+ <pair l="Adieresis" r="a" v="-1"/>
+ <pair l="Adieresis" r="b" v="7"/>
+ <pair l="Adieresis" r="c" v="-71"/>
+ <pair l="Adieresis" r="comma" v="10"/>
+ <pair l="Adieresis" r="d" v="-32"/>
+ <pair l="Adieresis" r="g" v="-11"/>
+ <pair l="Adieresis" r="guillemotleft" v="-108"/>
+ <pair l="Adieresis" r="guilsinglleft" v="-114"/>
+ <pair l="Adieresis" r="hyphen" v="-61"/>
+ <pair l="Adieresis" r="o" v="-50"/>
+ <pair l="Adieresis" r="period" v="10"/>
+ <pair l="Adieresis" r="q" v="-32"/>
+ <pair l="Adieresis" r="quotedblright" v="-216"/>
+ <pair l="Adieresis" r="quoteright" v="-258"/>
+ <pair l="Adieresis" r="t" v="-24"/>
+ <pair l="Adieresis" r="u" v="-19"/>
+ <pair l="Adieresis" r="v" v="-149"/>
+ <pair l="Adieresis" r="w" v="-112"/>
+ <pair l="Adieresis" r="y" v="-150"/>
+ <pair l="Agrave" r="C" v="-106"/>
+ <pair l="Agrave" r="G" v="-107"/>
+ <pair l="Agrave" r="O" v="-96"/>
+ <pair l="Agrave" r="Q" v="-95"/>
+ <pair l="Agrave" r="T" v="-78"/>
+ <pair l="Agrave" r="U" v="-111"/>
+ <pair l="Agrave" r="V" v="-239"/>
+ <pair l="Agrave" r="W" v="-172"/>
+ <pair l="Agrave" r="Y" v="-143"/>
+ <pair l="Agrave" r="comma" v="10"/>
+ <pair l="Agrave" r="period" v="10"/>
+ <pair l="Aring" r="C" v="-106"/>
+ <pair l="Aring" r="G" v="-107"/>
+ <pair l="Aring" r="O" v="-96"/>
+ <pair l="Aring" r="Q" v="-95"/>
+ <pair l="Aring" r="T" v="-78"/>
+ <pair l="Aring" r="U" v="-111"/>
+ <pair l="Aring" r="V" v="-239"/>
+ <pair l="Aring" r="W" v="-172"/>
+ <pair l="Aring" r="Y" v="-143"/>
+ <pair l="Aring" r="a" v="-1"/>
+ <pair l="Aring" r="b" v="7"/>
+ <pair l="Aring" r="c" v="-71"/>
+ <pair l="Aring" r="comma" v="10"/>
+ <pair l="Aring" r="d" v="-32"/>
+ <pair l="Aring" r="e" v="-61"/>
+ <pair l="Aring" r="g" v="-11"/>
+ <pair l="Aring" r="guillemotleft" v="-108"/>
+ <pair l="Aring" r="guilsinglleft" v="-114"/>
+ <pair l="Aring" r="hyphen" v="-61"/>
+ <pair l="Aring" r="o" v="-50"/>
+ <pair l="Aring" r="period" v="10"/>
+ <pair l="Aring" r="q" v="-32"/>
+ <pair l="Aring" r="quotedblright" v="-216"/>
+ <pair l="Aring" r="quoteright" v="-258"/>
+ <pair l="Aring" r="t" v="-24"/>
+ <pair l="Aring" r="u" v="-19"/>
+ <pair l="Aring" r="v" v="-149"/>
+ <pair l="Aring" r="w" v="-112"/>
+ <pair l="Aring" r="y" v="-150"/>
+ <pair l="Atilde" r="C" v="-106"/>
+ <pair l="Atilde" r="G" v="-107"/>
+ <pair l="Atilde" r="O" v="-96"/>
+ <pair l="Atilde" r="Q" v="-95"/>
+ <pair l="Atilde" r="T" v="-78"/>
+ <pair l="Atilde" r="U" v="-111"/>
+ <pair l="Atilde" r="V" v="-239"/>
+ <pair l="Atilde" r="W" v="-172"/>
+ <pair l="Atilde" r="Y" v="-143"/>
+ <pair l="Atilde" r="comma" v="10"/>
+ <pair l="Atilde" r="period" v="10"/>
+ <pair l="B" r="A" v="-53"/>
+ <pair l="B" r="AE" v="-53"/>
+ <pair l="B" r="Aacute" v="-53"/>
+ <pair l="B" r="Acircumflex" v="-53"/>
+ <pair l="B" r="Adieresis" v="-53"/>
+ <pair l="B" r="Aring" v="-53"/>
+ <pair l="B" r="Atilde" v="-53"/>
+ <pair l="B" r="O" v="-38"/>
+ <pair l="B" r="OE" v="-37"/>
+ <pair l="B" r="Oacute" v="-38"/>
+ <pair l="B" r="Ocircumflex" v="-38"/>
+ <pair l="B" r="Odieresis" v="-38"/>
+ <pair l="B" r="Ograve" v="-38"/>
+ <pair l="B" r="Oslash" v="-32"/>
+ <pair l="B" r="V" v="-62"/>
+ <pair l="B" r="W" v="-62"/>
+ <pair l="B" r="Y" v="-62"/>
+ <pair l="C" r="A" v="22"/>
+ <pair l="C" r="AE" v="22"/>
+ <pair l="C" r="Aacute" v="22"/>
+ <pair l="C" r="Adieresis" v="22"/>
+ <pair l="C" r="Aring" v="22"/>
+ <pair l="C" r="H" v="2"/>
+ <pair l="C" r="K" v="-5"/>
+ <pair l="C" r="O" v="-62"/>
+ <pair l="C" r="Oacute" v="-62"/>
+ <pair l="C" r="Odieresis" v="-62"/>
+ <pair l="Ccedilla" r="A" v="13"/>
+ <pair l="D" r="A" v="-114"/>
+ <pair l="D" r="Aacute" v="-114"/>
+ <pair l="D" r="Acircumflex" v="-114"/>
+ <pair l="D" r="Adieresis" v="-114"/>
+ <pair l="D" r="Agrave" v="-114"/>
+ <pair l="D" r="Aring" v="-114"/>
+ <pair l="D" r="Atilde" v="-114"/>
+ <pair l="D" r="J" v="-124"/>
+ <pair l="D" r="T" v="-27"/>
+ <pair l="D" r="V" v="-97"/>
+ <pair l="D" r="W" v="-93"/>
+ <pair l="D" r="X" v="-115"/>
+ <pair l="D" r="Y" v="-97"/>
+ <pair l="F" r="A" v="-167"/>
+ <pair l="F" r="Aacute" v="-167"/>
+ <pair l="F" r="Acircumflex" v="-167"/>
+ <pair l="F" r="Adieresis" v="-167"/>
+ <pair l="F" r="Agrave" v="-167"/>
+ <pair l="F" r="Aring" v="-167"/>
+ <pair l="F" r="Atilde" v="-167"/>
+ <pair l="F" r="J" v="-55"/>
+ <pair l="F" r="O" v="-57"/>
+ <pair l="F" r="Odieresis" v="-57"/>
+ <pair l="F" r="a" v="-108"/>
+ <pair l="F" r="aacute" v="-108"/>
+ <pair l="F" r="adieresis" v="-67"/>
+ <pair l="F" r="ae" v="-108"/>
+ <pair l="F" r="aring" v="-98"/>
+ <pair l="F" r="comma" v="-164"/>
+ <pair l="F" r="e" v="-64"/>
+ <pair l="F" r="eacute" v="-64"/>
+ <pair l="F" r="hyphen" v="-10"/>
+ <pair l="F" r="i" v="-68"/>
+ <pair l="F" r="j" v="-102"/>
+ <pair l="F" r="o" v="-61"/>
+ <pair l="F" r="oacute" v="-61"/>
+ <pair l="F" r="odieresis" v="-61"/>
+ <pair l="F" r="oe" v="-61"/>
+ <pair l="F" r="oslash" v="-61"/>
+ <pair l="F" r="period" v="-165"/>
+ <pair l="F" r="r" v="-91"/>
+ <pair l="F" r="u" v="-81"/>
+ <pair l="G" r="A" v="-19"/>
+ <pair l="G" r="AE" v="-19"/>
+ <pair l="G" r="Aacute" v="-19"/>
+ <pair l="G" r="Acircumflex" v="-19"/>
+ <pair l="G" r="Adieresis" v="-19"/>
+ <pair l="G" r="Agrave" v="-19"/>
+ <pair l="G" r="Aring" v="-19"/>
+ <pair l="G" r="Atilde" v="-19"/>
+ <pair l="G" r="T" v="-36"/>
+ <pair l="G" r="V" v="-21"/>
+ <pair l="G" r="W" v="-21"/>
+ <pair l="G" r="Y" v="-21"/>
+ <pair l="J" r="A" v="-35"/>
+ <pair l="J" r="AE" v="-35"/>
+ <pair l="J" r="Adieresis" v="-35"/>
+ <pair l="J" r="Aring" v="-35"/>
+ <pair l="K" r="C" v="-114"/>
+ <pair l="K" r="G" v="-115"/>
+ <pair l="K" r="O" v="-104"/>
+ <pair l="K" r="OE" v="-97"/>
+ <pair l="K" r="Oacute" v="-104"/>
+ <pair l="K" r="Odieresis" v="-104"/>
+ <pair l="K" r="S" v="10"/>
+ <pair l="K" r="T" v="-8"/>
+ <pair l="K" r="a" v="-9"/>
+ <pair l="K" r="adieresis" v="-9"/>
+ <pair l="K" r="ae" v="-9"/>
+ <pair l="K" r="aring" v="-9"/>
+ <pair l="K" r="e" v="-69"/>
+ <pair l="K" r="hyphen" v="-221"/>
+ <pair l="K" r="o" v="-58"/>
+ <pair l="K" r="oacute" v="-58"/>
+ <pair l="K" r="odieresis" v="-58"/>
+ <pair l="K" r="u" v="-27"/>
+ <pair l="K" r="udieresis" v="-27"/>
+ <pair l="K" r="y" v="-168"/>
+ <pair l="L" r="A" v="54"/>
+ <pair l="L" r="AE" v="54"/>
+ <pair l="L" r="Aacute" v="54"/>
+ <pair l="L" r="Adieresis" v="54"/>
+ <pair l="L" r="Aring" v="54"/>
+ <pair l="L" r="C" v="-40"/>
+ <pair l="L" r="Ccedilla" v="-46"/>
+ <pair l="L" r="G" v="-41"/>
+ <pair l="L" r="O" v="-33"/>
+ <pair l="L" r="Oacute" v="-33"/>
+ <pair l="L" r="Ocircumflex" v="-33"/>
+ <pair l="L" r="Odieresis" v="-33"/>
+ <pair l="L" r="Ograve" v="-33"/>
+ <pair l="L" r="Otilde" v="-33"/>
+ <pair l="L" r="S" v="-5"/>
+ <pair l="L" r="T" v="-101"/>
+ <pair l="L" r="U" v="-65"/>
+ <pair l="L" r="Udieresis" v="-65"/>
+ <pair l="L" r="V" v="-229"/>
+ <pair l="L" r="W" v="-164"/>
+ <pair l="L" r="Y" v="-166"/>
+ <pair l="L" r="hyphen" v="-63"/>
+ <pair l="L" r="quotedblright" v="-298"/>
+ <pair l="L" r="quoteright" v="-340"/>
+ <pair l="L" r="u" v="-21"/>
+ <pair l="L" r="udieresis" v="-21"/>
+ <pair l="L" r="y" v="-139"/>
+ <pair l="N" r="A" v="-37"/>
+ <pair l="N" r="AE" v="-37"/>
+ <pair l="N" r="Aacute" v="-37"/>
+ <pair l="N" r="Adieresis" v="-37"/>
+ <pair l="N" r="Aring" v="-37"/>
+ <pair l="N" r="C" v="-50"/>
+ <pair l="N" r="Ccedilla" v="-50"/>
+ <pair l="N" r="G" v="-53"/>
+ <pair l="N" r="O" v="-48"/>
+ <pair l="N" r="Oacute" v="-48"/>
+ <pair l="N" r="Odieresis" v="-48"/>
+ <pair l="N" r="a" v="-69"/>
+ <pair l="N" r="aacute" v="-69"/>
+ <pair l="N" r="adieresis" v="-49"/>
+ <pair l="N" r="ae" v="-69"/>
+ <pair l="N" r="aring" v="-69"/>
+ <pair l="N" r="comma" v="-37"/>
+ <pair l="N" r="e" v="-53"/>
+ <pair l="N" r="eacute" v="-53"/>
+ <pair l="N" r="o" v="-50"/>
+ <pair l="N" r="oacute" v="-50"/>
+ <pair l="N" r="odieresis" v="-50"/>
+ <pair l="N" r="oslash" v="-43"/>
+ <pair l="N" r="period" v="-38"/>
+ <pair l="N" r="u" v="-49"/>
+ <pair l="N" r="udieresis" v="-49"/>
+ <pair l="O" r="A" v="-95"/>
+ <pair l="O" r="AE" v="-95"/>
+ <pair l="O" r="Aacute" v="-95"/>
+ <pair l="O" r="Adieresis" v="-95"/>
+ <pair l="O" r="Aring" v="-95"/>
+ <pair l="O" r="T" v="-27"/>
+ <pair l="O" r="V" v="-89"/>
+ <pair l="O" r="W" v="-89"/>
+ <pair l="O" r="X" v="-101"/>
+ <pair l="O" r="Y" v="-89"/>
+ <pair l="Oacute" r="A" v="-95"/>
+ <pair l="Oacute" r="T" v="-27"/>
+ <pair l="Oacute" r="V" v="-89"/>
+ <pair l="Oacute" r="W" v="-89"/>
+ <pair l="Oacute" r="Y" v="-89"/>
+ <pair l="Ocircumflex" r="T" v="-27"/>
+ <pair l="Ocircumflex" r="V" v="-89"/>
+ <pair l="Ocircumflex" r="Y" v="-89"/>
+ <pair l="Odieresis" r="A" v="-95"/>
+ <pair l="Odieresis" r="T" v="-27"/>
+ <pair l="Odieresis" r="V" v="-89"/>
+ <pair l="Odieresis" r="W" v="-89"/>
+ <pair l="Odieresis" r="X" v="-101"/>
+ <pair l="Odieresis" r="Y" v="-89"/>
+ <pair l="Ograve" r="T" v="-27"/>
+ <pair l="Ograve" r="V" v="-89"/>
+ <pair l="Ograve" r="Y" v="-89"/>
+ <pair l="Oslash" r="A" v="-96"/>
+ <pair l="Otilde" r="T" v="-27"/>
+ <pair l="Otilde" r="V" v="-89"/>
+ <pair l="Otilde" r="Y" v="-89"/>
+ <pair l="P" r="A" v="-174"/>
+ <pair l="P" r="AE" v="-174"/>
+ <pair l="P" r="Aacute" v="-174"/>
+ <pair l="P" r="Adieresis" v="-174"/>
+ <pair l="P" r="Aring" v="-174"/>
+ <pair l="P" r="J" v="-86"/>
+ <pair l="P" r="a" v="-26"/>
+ <pair l="P" r="aacute" v="-26"/>
+ <pair l="P" r="adieresis" v="-26"/>
+ <pair l="P" r="ae" v="-26"/>
+ <pair l="P" r="aring" v="-26"/>
+ <pair l="P" r="comma" v="-208"/>
+ <pair l="P" r="e" v="-33"/>
+ <pair l="P" r="eacute" v="-33"/>
+ <pair l="P" r="hyphen" v="-46"/>
+ <pair l="P" r="o" v="-30"/>
+ <pair l="P" r="oacute" v="-30"/>
+ <pair l="P" r="odieresis" v="-30"/>
+ <pair l="P" r="oe" v="-32"/>
+ <pair l="P" r="oslash" v="-30"/>
+ <pair l="P" r="period" v="-209"/>
+ <pair l="R" r="C" v="-99"/>
+ <pair l="R" r="Ccedilla" v="-99"/>
+ <pair l="R" r="G" v="-102"/>
+ <pair l="R" r="O" v="-96"/>
+ <pair l="R" r="OE" v="-94"/>
+ <pair l="R" r="Oacute" v="-96"/>
+ <pair l="R" r="Odieresis" v="-96"/>
+ <pair l="R" r="T" v="-70"/>
+ <pair l="R" r="U" v="-116"/>
+ <pair l="R" r="Udieresis" v="-116"/>
+ <pair l="R" r="V" v="-108"/>
+ <pair l="R" r="W" v="-108"/>
+ <pair l="R" r="Y" v="-108"/>
+ <pair l="R" r="a" v="-6"/>
+ <pair l="R" r="aacute" v="-6"/>
+ <pair l="R" r="adieresis" v="-6"/>
+ <pair l="R" r="ae" v="-6"/>
+ <pair l="R" r="aring" v="-6"/>
+ <pair l="R" r="e" v="-66"/>
+ <pair l="R" r="eacute" v="-66"/>
+ <pair l="R" r="hyphen" v="-128"/>
+ <pair l="R" r="o" v="-56"/>
+ <pair l="R" r="oacute" v="-56"/>
+ <pair l="R" r="odieresis" v="-56"/>
+ <pair l="R" r="oe" v="-58"/>
+ <pair l="R" r="u" v="-25"/>
+ <pair l="R" r="uacute" v="-25"/>
+ <pair l="R" r="udieresis" v="-25"/>
+ <pair l="R" r="y" v="-62"/>
+ <pair l="S" r="A" v="-43"/>
+ <pair l="S" r="AE" v="-43"/>
+ <pair l="S" r="Aacute" v="-43"/>
+ <pair l="S" r="Adieresis" v="-43"/>
+ <pair l="S" r="Aring" v="-43"/>
+ <pair l="S" r="T" v="-26"/>
+ <pair l="S" r="V" v="-10"/>
+ <pair l="S" r="W" v="-10"/>
+ <pair l="S" r="Y" v="-10"/>
+ <pair l="S" r="t" v="-40"/>
+ <pair l="T" r="A" v="-77"/>
+ <pair l="T" r="AE" v="-77"/>
+ <pair l="T" r="Aacute" v="-77"/>
+ <pair l="T" r="Acircumflex" v="-77"/>
+ <pair l="T" r="Adieresis" v="-77"/>
+ <pair l="T" r="Agrave" v="-77"/>
+ <pair l="T" r="Aring" v="-77"/>
+ <pair l="T" r="Atilde" v="-77"/>
+ <pair l="T" r="C" v="-28"/>
+ <pair l="T" r="G" v="-31"/>
+ <pair l="T" r="J" v="-30"/>
+ <pair l="T" r="O" v="-27"/>
+ <pair l="T" r="OE" v="-24"/>
+ <pair l="T" r="Oacute" v="-27"/>
+ <pair l="T" r="Ocircumflex" v="-27"/>
+ <pair l="T" r="Odieresis" v="-27"/>
+ <pair l="T" r="Ograve" v="-27"/>
+ <pair l="T" r="Oslash" v="-27"/>
+ <pair l="T" r="Otilde" v="-27"/>
+ <pair l="T" r="S" v="-4"/>
+ <pair l="T" r="V" v="63"/>
+ <pair l="T" r="W" v="63"/>
+ <pair l="T" r="Y" v="63"/>
+ <pair l="T" r="a" v="-155"/>
+ <pair l="T" r="ae" v="-155"/>
+ <pair l="T" r="c" v="-198"/>
+ <pair l="T" r="colon" v="-157"/>
+ <pair l="T" r="comma" v="-143"/>
+ <pair l="T" r="e" v="-192"/>
+ <pair l="T" r="g" v="-166"/>
+ <pair l="T" r="guillemotleft" v="-218"/>
+ <pair l="T" r="guilsinglleft" v="-224"/>
+ <pair l="T" r="hyphen" v="-155"/>
+ <pair l="T" r="i" v="-42"/>
+ <pair l="T" r="j" v="-77"/>
+ <pair l="T" r="o" v="-189"/>
+ <pair l="T" r="oslash" v="-129"/>
+ <pair l="T" r="period" v="-143"/>
+ <pair l="T" r="r" v="-101"/>
+ <pair l="T" r="s" v="-133"/>
+ <pair l="T" r="semicolon" v="-157"/>
+ <pair l="T" r="u" v="-174"/>
+ <pair l="T" r="v" v="-190"/>
+ <pair l="T" r="w" v="-190"/>
+ <pair l="T" r="y" v="-190"/>
+ <pair l="U" r="A" v="-106"/>
+ <pair l="U" r="AE" v="-106"/>
+ <pair l="U" r="Aacute" v="-106"/>
+ <pair l="U" r="Acircumflex" v="-106"/>
+ <pair l="U" r="Adieresis" v="-106"/>
+ <pair l="U" r="Aring" v="-106"/>
+ <pair l="U" r="Atilde" v="-106"/>
+ <pair l="U" r="comma" v="-66"/>
+ <pair l="U" r="m" v="-54"/>
+ <pair l="U" r="n" v="-54"/>
+ <pair l="U" r="p" v="-35"/>
+ <pair l="U" r="period" v="-61"/>
+ <pair l="U" r="r" v="-51"/>
+ <pair l="Uacute" r="A" v="-106"/>
+ <pair l="Uacute" r="comma" v="-66"/>
+ <pair l="Uacute" r="m" v="-54"/>
+ <pair l="Uacute" r="n" v="-54"/>
+ <pair l="Uacute" r="p" v="-35"/>
+ <pair l="Uacute" r="period" v="-61"/>
+ <pair l="Uacute" r="r" v="-51"/>
+ <pair l="Ucircumflex" r="A" v="-106"/>
+ <pair l="Udieresis" r="A" v="-106"/>
+ <pair l="Udieresis" r="b" v="38"/>
+ <pair l="Udieresis" r="comma" v="-66"/>
+ <pair l="Udieresis" r="m" v="-54"/>
+ <pair l="Udieresis" r="n" v="-54"/>
+ <pair l="Udieresis" r="p" v="-35"/>
+ <pair l="Udieresis" r="period" v="-61"/>
+ <pair l="Udieresis" r="r" v="-51"/>
+ <pair l="Ugrave" r="A" v="-106"/>
+ <pair l="V" r="A" v="-229"/>
+ <pair l="V" r="AE" v="-248"/>
+ <pair l="V" r="Aacute" v="-229"/>
+ <pair l="V" r="Acircumflex" v="-229"/>
+ <pair l="V" r="Adieresis" v="-229"/>
+ <pair l="V" r="Agrave" v="-229"/>
+ <pair l="V" r="Aring" v="-229"/>
+ <pair l="V" r="Atilde" v="-229"/>
+ <pair l="V" r="C" v="-93"/>
+ <pair l="V" r="G" v="-96"/>
+ <pair l="V" r="O" v="-92"/>
+ <pair l="V" r="Oacute" v="-92"/>
+ <pair l="V" r="Ocircumflex" v="-92"/>
+ <pair l="V" r="Odieresis" v="-92"/>
+ <pair l="V" r="Ograve" v="-92"/>
+ <pair l="V" r="Oslash" v="-89"/>
+ <pair l="V" r="Otilde" v="-92"/>
+ <pair l="V" r="S" v="-43"/>
+ <pair l="V" r="T" v="61"/>
+ <pair l="V" r="a" v="-140"/>
+ <pair l="V" r="ae" v="-140"/>
+ <pair l="V" r="colon" v="-125"/>
+ <pair l="V" r="comma" v="-215"/>
+ <pair l="V" r="e" v="-156"/>
+ <pair l="V" r="g" v="-149"/>
+ <pair l="V" r="guillemotleft" v="-184"/>
+ <pair l="V" r="guilsinglleft" v="-190"/>
+ <pair l="V" r="hyphen" v="-113"/>
+ <pair l="V" r="i" v="-28"/>
+ <pair l="V" r="o" v="-153"/>
+ <pair l="V" r="oslash" v="-153"/>
+ <pair l="V" r="period" v="-214"/>
+ <pair l="V" r="r" v="-65"/>
+ <pair l="V" r="semicolon" v="-121"/>
+ <pair l="V" r="u" v="-59"/>
+ <pair l="V" r="y" v="-53"/>
+ <pair l="W" r="A" v="-200"/>
+ <pair l="W" r="AE" v="-200"/>
+ <pair l="W" r="Aacute" v="-200"/>
+ <pair l="W" r="Acircumflex" v="-200"/>
+ <pair l="W" r="Adieresis" v="-200"/>
+ <pair l="W" r="Agrave" v="-200"/>
+ <pair l="W" r="Aring" v="-200"/>
+ <pair l="W" r="Atilde" v="-200"/>
+ <pair l="W" r="C" v="-93"/>
+ <pair l="W" r="G" v="-97"/>
+ <pair l="W" r="O" v="-92"/>
+ <pair l="W" r="Oacute" v="-92"/>
+ <pair l="W" r="Ocircumflex" v="-92"/>
+ <pair l="W" r="Odieresis" v="-92"/>
+ <pair l="W" r="Ograve" v="-92"/>
+ <pair l="W" r="Oslash" v="-89"/>
+ <pair l="W" r="Otilde" v="-92"/>
+ <pair l="W" r="S" v="-44"/>
+ <pair l="W" r="T" v="61"/>
+ <pair l="W" r="a" v="-137"/>
+ <pair l="W" r="ae" v="-137"/>
+ <pair l="W" r="colon" v="-124"/>
+ <pair l="W" r="comma" v="-175"/>
+ <pair l="W" r="e" v="-141"/>
+ <pair l="W" r="g" v="-143"/>
+ <pair l="W" r="guillemotleft" v="-160"/>
+ <pair l="W" r="guilsinglleft" v="-166"/>
+ <pair l="W" r="hyphen" v="-91"/>
+ <pair l="W" r="i" v="-28"/>
+ <pair l="W" r="o" v="-137"/>
+ <pair l="W" r="oslash" v="-131"/>
+ <pair l="W" r="period" v="-174"/>
+ <pair l="W" r="r" v="-65"/>
+ <pair l="W" r="semicolon" v="-121"/>
+ <pair l="W" r="u" v="-59"/>
+ <pair l="W" r="y" v="-53"/>
+ <pair l="X" r="C" v="-111"/>
+ <pair l="X" r="O" v="-102"/>
+ <pair l="X" r="Odieresis" v="-102"/>
+ <pair l="X" r="Q" v="-101"/>
+ <pair l="X" r="a" v="-7"/>
+ <pair l="X" r="e" v="-67"/>
+ <pair l="X" r="hyphen" v="-138"/>
+ <pair l="X" r="o" v="-57"/>
+ <pair l="X" r="u" v="-25"/>
+ <pair l="X" r="y" v="-138"/>
+ <pair l="Y" r="A" v="-150"/>
+ <pair l="Y" r="AE" v="-150"/>
+ <pair l="Y" r="Aacute" v="-150"/>
+ <pair l="Y" r="Acircumflex" v="-150"/>
+ <pair l="Y" r="Adieresis" v="-150"/>
+ <pair l="Y" r="Agrave" v="-150"/>
+ <pair l="Y" r="Aring" v="-150"/>
+ <pair l="Y" r="Atilde" v="-150"/>
+ <pair l="Y" r="C" v="-92"/>
+ <pair l="Y" r="G" v="-96"/>
+ <pair l="Y" r="O" v="-92"/>
+ <pair l="Y" r="Oacute" v="-92"/>
+ <pair l="Y" r="Ocircumflex" v="-92"/>
+ <pair l="Y" r="Odieresis" v="-92"/>
+ <pair l="Y" r="Ograve" v="-92"/>
+ <pair l="Y" r="Oslash" v="-89"/>
+ <pair l="Y" r="Otilde" v="-92"/>
+ <pair l="Y" r="S" v="-43"/>
+ <pair l="Y" r="T" v="61"/>
+ <pair l="Y" r="a" v="-202"/>
+ <pair l="Y" r="ae" v="-202"/>
+ <pair l="Y" r="colon" v="-181"/>
+ <pair l="Y" r="comma" v="-217"/>
+ <pair l="Y" r="e" v="-224"/>
+ <pair l="Y" r="g" v="-218"/>
+ <pair l="Y" r="guillemotleft" v="-279"/>
+ <pair l="Y" r="guilsinglleft" v="-285"/>
+ <pair l="Y" r="hyphen" v="-211"/>
+ <pair l="Y" r="i" v="-28"/>
+ <pair l="Y" r="o" v="-220"/>
+ <pair l="Y" r="oslash" v="-203"/>
+ <pair l="Y" r="p" v="-102"/>
+ <pair l="Y" r="period" v="-217"/>
+ <pair l="Y" r="semicolon" v="-174"/>
+ <pair l="Y" r="u" v="-115"/>
+ <pair l="Y" r="v" v="-109"/>
+ <pair l="Z" r="v" v="-96"/>
+ <pair l="Z" r="y" v="-96"/>
+ <pair l="a" r="j" v="-73"/>
+ <pair l="a" r="quoteright" v="-84"/>
+ <pair l="a" r="v" v="-28"/>
+ <pair l="a" r="w" v="-28"/>
+ <pair l="a" r="y" v="-28"/>
+ <pair l="aacute" r="v" v="-28"/>
+ <pair l="aacute" r="w" v="-28"/>
+ <pair l="aacute" r="y" v="-28"/>
+ <pair l="adieresis" r="v" v="-28"/>
+ <pair l="adieresis" r="w" v="-28"/>
+ <pair l="adieresis" r="y" v="-28"/>
+ <pair l="ae" r="v" v="-20"/>
+ <pair l="ae" r="w" v="-20"/>
+ <pair l="ae" r="y" v="-20"/>
+ <pair l="agrave" r="v" v="-28"/>
+ <pair l="agrave" r="w" v="-28"/>
+ <pair l="agrave" r="y" v="-28"/>
+ <pair l="aring" r="v" v="-28"/>
+ <pair l="aring" r="w" v="-28"/>
+ <pair l="aring" r="y" v="-28"/>
+ <pair l="b" r="v" v="-36"/>
+ <pair l="b" r="w" v="-36"/>
+ <pair l="b" r="y" v="-36"/>
+ <pair l="c" r="h" v="11"/>
+ <pair l="c" r="k" v="14"/>
+ <pair l="comma" r="one" v="-51"/>
+ <pair l="comma" r="quotedblright" v="-84"/>
+ <pair l="comma" r="quoteright" v="-126"/>
+ <pair l="e" r="quoteright" v="-65"/>
+ <pair l="e" r="t" v="-26"/>
+ <pair l="e" r="v" v="-21"/>
+ <pair l="e" r="w" v="-21"/>
+ <pair l="e" r="x" v="27"/>
+ <pair l="e" r="y" v="-21"/>
+ <pair l="eacute" r="v" v="-21"/>
+ <pair l="eacute" r="w" v="-21"/>
+ <pair l="eacute" r="y" v="-21"/>
+ <pair l="ecircumflex" r="v" v="-21"/>
+ <pair l="ecircumflex" r="w" v="-21"/>
+ <pair l="ecircumflex" r="y" v="-21"/>
+ <pair l="eight" r="four" v="41"/>
+ <pair l="eight" r="one" v="-48"/>
+ <pair l="eight" r="seven" v="-34"/>
+ <pair l="f" r="a" v="-60"/>
+ <pair l="f" r="aacute" v="-60"/>
+ <pair l="f" r="adieresis" v="-16"/>
+ <pair l="f" r="ae" v="-60"/>
+ <pair l="f" r="aring" v="-45"/>
+ <pair l="f" r="e" v="-90"/>
+ <pair l="f" r="eacute" v="-77"/>
+ <pair l="f" r="f" v="0"/>
+ <pair l="f" r="i" v="-5"/>
+ <pair l="f" r="j" v="-52"/>
+ <pair l="f" r="l" v="55"/>
+ <pair l="f" r="o" v="-87"/>
+ <pair l="f" r="oacute" v="-87"/>
+ <pair l="f" r="odieresis" v="-35"/>
+ <pair l="f" r="oe" v="-89"/>
+ <pair l="f" r="oslash" v="-52"/>
+ <pair l="f" r="quoteright" v="-26"/>
+ <pair l="f" r="s" v="-51"/>
+ <pair l="f" r="t" v="11"/>
+ <pair l="five" r="four" v="7"/>
+ <pair l="five" r="one" v="-60"/>
+ <pair l="five" r="seven" v="-49"/>
+ <pair l="four" r="four" v="41"/>
+ <pair l="four" r="one" v="-16"/>
+ <pair l="four" r="seven" v="-43"/>
+ <pair l="g" r="a" v="-53"/>
+ <pair l="g" r="adieresis" v="-53"/>
+ <pair l="g" r="ae" v="-53"/>
+ <pair l="g" r="aring" v="-53"/>
+ <pair l="g" r="e" v="-77"/>
+ <pair l="g" r="eacute" v="-77"/>
+ <pair l="g" r="l" v="-11"/>
+ <pair l="g" r="oacute" v="-73"/>
+ <pair l="g" r="odieresis" v="-73"/>
+ <pair l="g" r="r" v="22"/>
+ <pair l="guillemotright" r="A" v="-105"/>
+ <pair l="guillemotright" r="AE" v="-136"/>
+ <pair l="guillemotright" r="Aacute" v="-105"/>
+ <pair l="guillemotright" r="Adieresis" v="-105"/>
+ <pair l="guillemotright" r="Aring" v="-105"/>
+ <pair l="guillemotright" r="T" v="-218"/>
+ <pair l="guillemotright" r="V" v="-195"/>
+ <pair l="guillemotright" r="W" v="-141"/>
+ <pair l="guillemotright" r="Y" v="-271"/>
+ <pair l="guilsinglright" r="A" v="-110"/>
+ <pair l="guilsinglright" r="AE" v="-141"/>
+ <pair l="guilsinglright" r="Aacute" v="-110"/>
+ <pair l="guilsinglright" r="Adieresis" v="-110"/>
+ <pair l="guilsinglright" r="Aring" v="-110"/>
+ <pair l="guilsinglright" r="T" v="-223"/>
+ <pair l="guilsinglright" r="V" v="-200"/>
+ <pair l="guilsinglright" r="W" v="-146"/>
+ <pair l="guilsinglright" r="Y" v="-276"/>
+ <pair l="h" r="quoteright" v="-80"/>
+ <pair l="h" r="y" v="-23"/>
+ <pair l="hyphen" r="A" v="-58"/>
+ <pair l="hyphen" r="AE" v="-96"/>
+ <pair l="hyphen" r="Aacute" v="-58"/>
+ <pair l="hyphen" r="Adieresis" v="-58"/>
+ <pair l="hyphen" r="Aring" v="-58"/>
+ <pair l="hyphen" r="T" v="-154"/>
+ <pair l="hyphen" r="V" v="-122"/>
+ <pair l="hyphen" r="W" v="-71"/>
+ <pair l="hyphen" r="Y" v="-202"/>
+ <pair l="i" r="T" v="-35"/>
+ <pair l="i" r="j" v="-86"/>
+ <pair l="k" r="a" v="-9"/>
+ <pair l="k" r="aacute" v="-9"/>
+ <pair l="k" r="adieresis" v="-9"/>
+ <pair l="k" r="ae" v="-9"/>
+ <pair l="k" r="aring" v="-9"/>
+ <pair l="k" r="comma" v="2"/>
+ <pair l="k" r="e" v="-69"/>
+ <pair l="k" r="eacute" v="-69"/>
+ <pair l="k" r="g" v="-19"/>
+ <pair l="k" r="hyphen" v="-134"/>
+ <pair l="k" r="o" v="-58"/>
+ <pair l="k" r="oacute" v="-58"/>
+ <pair l="k" r="odieresis" v="-58"/>
+ <pair l="k" r="period" v="2"/>
+ <pair l="k" r="s" v="12"/>
+ <pair l="k" r="u" v="15"/>
+ <pair l="k" r="udieresis" v="15"/>
+ <pair l="l" r="v" v="-29"/>
+ <pair l="l" r="y" v="-29"/>
+ <pair l="m" r="p" v="-6"/>
+ <pair l="m" r="v" v="-25"/>
+ <pair l="m" r="w" v="-25"/>
+ <pair l="m" r="y" v="-25"/>
+ <pair l="n" r="T" v="-89"/>
+ <pair l="n" r="p" v="-3"/>
+ <pair l="n" r="quoteright" v="-80"/>
+ <pair l="n" r="v" v="-23"/>
+ <pair l="n" r="w" v="-23"/>
+ <pair l="n" r="y" v="-23"/>
+ <pair l="nine" r="four" v="30"/>
+ <pair l="nine" r="one" v="-67"/>
+ <pair l="nine" r="seven" v="-50"/>
+ <pair l="o" r="T" v="-190"/>
+ <pair l="o" r="quoteright" v="-88"/>
+ <pair l="o" r="t" v="-18"/>
+ <pair l="o" r="v" v="-54"/>
+ <pair l="o" r="w" v="-54"/>
+ <pair l="o" r="x" v="-54"/>
+ <pair l="o" r="y" v="-54"/>
+ <pair l="oacute" r="v" v="-54"/>
+ <pair l="oacute" r="w" v="-54"/>
+ <pair l="oacute" r="y" v="-54"/>
+ <pair l="ocircumflex" r="t" v="-18"/>
+ <pair l="odieresis" r="t" v="-18"/>
+ <pair l="odieresis" r="v" v="-54"/>
+ <pair l="odieresis" r="w" v="-54"/>
+ <pair l="odieresis" r="x" v="-54"/>
+ <pair l="odieresis" r="y" v="-54"/>
+ <pair l="ograve" r="v" v="-54"/>
+ <pair l="ograve" r="w" v="-54"/>
+ <pair l="ograve" r="y" v="-54"/>
+ <pair l="one" r="comma" v="-52"/>
+ <pair l="one" r="eight" v="-72"/>
+ <pair l="one" r="five" v="-50"/>
+ <pair l="one" r="four" v="-139"/>
+ <pair l="one" r="nine" v="-46"/>
+ <pair l="one" r="one" v="-50"/>
+ <pair l="one" r="period" v="-52"/>
+ <pair l="one" r="seven" v="-78"/>
+ <pair l="one" r="six" v="-109"/>
+ <pair l="one" r="three" v="-32"/>
+ <pair l="one" r="two" v="-20"/>
+ <pair l="one" r="zero" v="-112"/>
+ <pair l="p" r="t" v="-17"/>
+ <pair l="p" r="y" v="-36"/>
+ <pair l="period" r="one" v="-51"/>
+ <pair l="period" r="quotedblright" v="-86"/>
+ <pair l="period" r="quoteright" v="-128"/>
+ <pair l="q" r="c" v="-20"/>
+ <pair l="q" r="u" v="-6"/>
+ <pair l="quotedblbase" r="A" v="18"/>
+ <pair l="quotedblbase" r="AE" v="18"/>
+ <pair l="quotedblbase" r="T" v="-137"/>
+ <pair l="quotedblbase" r="V" v="-223"/>
+ <pair l="quotedblbase" r="W" v="-143"/>
+ <pair l="quotedblbase" r="Y" v="-202"/>
+ <pair l="quotedblleft" r="A" v="-217"/>
+ <pair l="quotedblleft" r="AE" v="-306"/>
+ <pair l="quotedblleft" r="Aacute" v="-217"/>
+ <pair l="quotedblleft" r="Adieresis" v="-217"/>
+ <pair l="quotedblleft" r="Aring" v="-217"/>
+ <pair l="quotedblleft" r="T" v="-9"/>
+ <pair l="quotedblleft" r="V" v="-10"/>
+ <pair l="quotedblleft" r="W" v="-10"/>
+ <pair l="quotedblleft" r="Y" v="-10"/>
+ <pair l="quotedblright" r="A" v="-210"/>
+ <pair l="quotedblright" r="AE" v="-303"/>
+ <pair l="quotedblright" r="Aacute" v="-210"/>
+ <pair l="quotedblright" r="Adieresis" v="-210"/>
+ <pair l="quotedblright" r="Aring" v="-210"/>
+ <pair l="quotedblright" r="T" v="2"/>
+ <pair l="quotedblright" r="V" v="18"/>
+ <pair l="quotedblright" r="W" v="18"/>
+ <pair l="quotedblright" r="Y" v="18"/>
+ <pair l="quoteleft" r="A" v="-258"/>
+ <pair l="quoteleft" r="AE" v="-347"/>
+ <pair l="quoteleft" r="Aacute" v="-258"/>
+ <pair l="quoteleft" r="Adieresis" v="-258"/>
+ <pair l="quoteleft" r="Aring" v="-258"/>
+ <pair l="quoteleft" r="T" v="-51"/>
+ <pair l="quoteleft" r="V" v="-52"/>
+ <pair l="quoteleft" r="W" v="-52"/>
+ <pair l="quoteleft" r="Y" v="-52"/>
+ <pair l="quoteright" r="A" v="-251"/>
+ <pair l="quoteright" r="AE" v="-344"/>
+ <pair l="quoteright" r="Aacute" v="-251"/>
+ <pair l="quoteright" r="Adieresis" v="-251"/>
+ <pair l="quoteright" r="Aring" v="-251"/>
+ <pair l="quoteright" r="comma" v="-136"/>
+ <pair l="quoteright" r="d" v="-101"/>
+ <pair l="quoteright" r="o" v="-96"/>
+ <pair l="quoteright" r="period" v="-138"/>
+ <pair l="quoteright" r="r" v="-64"/>
+ <pair l="quoteright" r="s" v="-79"/>
+ <pair l="quoteright" r="t" v="-61"/>
+ <pair l="quoteright" r="v" v="-50"/>
+ <pair l="quoteright" r="w" v="-50"/>
+ <pair l="quoteright" r="y" v="-50"/>
+ <pair l="r" r="a" v="-23"/>
+ <pair l="r" r="aacute" v="-23"/>
+ <pair l="r" r="acircumflex" v="-23"/>
+ <pair l="r" r="adieresis" v="-23"/>
+ <pair l="r" r="ae" v="-23"/>
+ <pair l="r" r="agrave" v="-23"/>
+ <pair l="r" r="aring" v="-23"/>
+ <pair l="r" r="c" v="2"/>
+ <pair l="r" r="ccedilla" v="6"/>
+ <pair l="r" r="colon" v="-16"/>
+ <pair l="r" r="comma" v="-97"/>
+ <pair l="r" r="d" v="3"/>
+ <pair l="r" r="e" v="4"/>
+ <pair l="r" r="eacute" v="4"/>
+ <pair l="r" r="ecircumflex" v="4"/>
+ <pair l="r" r="egrave" v="4"/>
+ <pair l="r" r="f" v="36"/>
+ <pair l="r" r="g" v="-2"/>
+ <pair l="r" r="h" v="-24"/>
+ <pair l="r" r="hyphen" v="-87"/>
+ <pair l="r" r="i" v="31"/>
+ <pair l="r" r="j" v="-15"/>
+ <pair l="r" r="k" v="-21"/>
+ <pair l="r" r="l" v="-41"/>
+ <pair l="r" r="m" v="36"/>
+ <pair l="r" r="n" v="36"/>
+ <pair l="r" r="o" v="7"/>
+ <pair l="r" r="oacute" v="7"/>
+ <pair l="r" r="ocircumflex" v="7"/>
+ <pair l="r" r="odieresis" v="7"/>
+ <pair l="r" r="oe" v="6"/>
+ <pair l="r" r="ograve" v="7"/>
+ <pair l="r" r="oslash" v="7"/>
+ <pair l="r" r="p" v="54"/>
+ <pair l="r" r="period" v="-97"/>
+ <pair l="r" r="q" v="3"/>
+ <pair l="r" r="quoteright" v="-18"/>
+ <pair l="r" r="r" v="39"/>
+ <pair l="r" r="s" v="4"/>
+ <pair l="r" r="semicolon" v="-16"/>
+ <pair l="r" r="t" v="42"/>
+ <pair l="r" r="u" v="48"/>
+ <pair l="r" r="v" v="54"/>
+ <pair l="r" r="w" v="54"/>
+ <pair l="r" r="x" v="54"/>
+ <pair l="r" r="y" v="54"/>
+ <pair l="r" r="z" v="9"/>
+ <pair l="s" r="quoteright" v="-97"/>
+ <pair l="s" r="t" v="-22"/>
+ <pair l="seven" r="colon" v="-111"/>
+ <pair l="seven" r="comma" v="-205"/>
+ <pair l="seven" r="eight" v="-13"/>
+ <pair l="seven" r="five" v="-13"/>
+ <pair l="seven" r="four" v="-174"/>
+ <pair l="seven" r="one" v="0"/>
+ <pair l="seven" r="period" v="-206"/>
+ <pair l="seven" r="seven" v="10"/>
+ <pair l="seven" r="six" v="-45"/>
+ <pair l="seven" r="three" v="12"/>
+ <pair l="seven" r="two" v="13"/>
+ <pair l="six" r="four" v="47"/>
+ <pair l="six" r="one" v="-46"/>
+ <pair l="six" r="seven" v="-35"/>
+ <pair l="t" r="S" v="-2"/>
+ <pair l="t" r="a" v="-18"/>
+ <pair l="t" r="aacute" v="-18"/>
+ <pair l="t" r="adieresis" v="-18"/>
+ <pair l="t" r="ae" v="-18"/>
+ <pair l="t" r="aring" v="-18"/>
+ <pair l="t" r="colon" v="-16"/>
+ <pair l="t" r="e" v="-52"/>
+ <pair l="t" r="eacute" v="-52"/>
+ <pair l="t" r="h" v="24"/>
+ <pair l="t" r="o" v="-49"/>
+ <pair l="t" r="oacute" v="-49"/>
+ <pair l="t" r="odieresis" v="-49"/>
+ <pair l="t" r="quoteright" v="-50"/>
+ <pair l="t" r="semicolon" v="-16"/>
+ <pair l="three" r="four" v="9"/>
+ <pair l="three" r="one" v="-74"/>
+ <pair l="three" r="seven" v="-60"/>
+ <pair l="two" r="four" v="-114"/>
+ <pair l="two" r="one" v="-48"/>
+ <pair l="two" r="seven" v="-42"/>
+ <pair l="u" r="quoteright" v="-80"/>
+ <pair l="v" r="a" v="-18"/>
+ <pair l="v" r="aacute" v="-18"/>
+ <pair l="v" r="acircumflex" v="-18"/>
+ <pair l="v" r="adieresis" v="-18"/>
+ <pair l="v" r="ae" v="-18"/>
+ <pair l="v" r="agrave" v="-18"/>
+ <pair l="v" r="aring" v="-18"/>
+ <pair l="v" r="atilde" v="-18"/>
+ <pair l="v" r="c" v="-67"/>
+ <pair l="v" r="colon" v="-11"/>
+ <pair l="v" r="comma" v="-142"/>
+ <pair l="v" r="e" v="-55"/>
+ <pair l="v" r="eacute" v="-55"/>
+ <pair l="v" r="ecircumflex" v="-55"/>
+ <pair l="v" r="egrave" v="-55"/>
+ <pair l="v" r="g" v="-36"/>
+ <pair l="v" r="hyphen" v="-40"/>
+ <pair l="v" r="l" v="-36"/>
+ <pair l="v" r="o" v="-53"/>
+ <pair l="v" r="oacute" v="-53"/>
+ <pair l="v" r="odieresis" v="-53"/>
+ <pair l="v" r="ograve" v="-53"/>
+ <pair l="v" r="oslash" v="-53"/>
+ <pair l="v" r="period" v="-143"/>
+ <pair l="v" r="s" v="-16"/>
+ <pair l="v" r="semicolon" v="-11"/>
+ <pair l="w" r="a" v="-19"/>
+ <pair l="w" r="aacute" v="-19"/>
+ <pair l="w" r="acircumflex" v="-19"/>
+ <pair l="w" r="adieresis" v="-19"/>
+ <pair l="w" r="ae" v="-19"/>
+ <pair l="w" r="agrave" v="-19"/>
+ <pair l="w" r="aring" v="-19"/>
+ <pair l="w" r="atilde" v="-19"/>
+ <pair l="w" r="c" v="-68"/>
+ <pair l="w" r="colon" v="-12"/>
+ <pair l="w" r="comma" v="-120"/>
+ <pair l="w" r="e" v="-56"/>
+ <pair l="w" r="eacute" v="-56"/>
+ <pair l="w" r="ecircumflex" v="-56"/>
+ <pair l="w" r="egrave" v="-56"/>
+ <pair l="w" r="g" v="-37"/>
+ <pair l="w" r="hyphen" v="-32"/>
+ <pair l="w" r="l" v="-37"/>
+ <pair l="w" r="o" v="-54"/>
+ <pair l="w" r="oacute" v="-54"/>
+ <pair l="w" r="odieresis" v="-54"/>
+ <pair l="w" r="ograve" v="-54"/>
+ <pair l="w" r="oslash" v="-54"/>
+ <pair l="w" r="period" v="-121"/>
+ <pair l="w" r="s" v="-17"/>
+ <pair l="w" r="semicolon" v="-12"/>
+ <pair l="x" r="a" v="-9"/>
+ <pair l="x" r="c" v="-77"/>
+ <pair l="x" r="e" v="-69"/>
+ <pair l="x" r="eacute" v="-69"/>
+ <pair l="x" r="o" v="-59"/>
+ <pair l="x" r="q" v="-40"/>
+ <pair l="y" r="a" v="-18"/>
+ <pair l="y" r="aacute" v="-18"/>
+ <pair l="y" r="acircumflex" v="-18"/>
+ <pair l="y" r="adieresis" v="-18"/>
+ <pair l="y" r="ae" v="-18"/>
+ <pair l="y" r="agrave" v="-18"/>
+ <pair l="y" r="aring" v="-18"/>
+ <pair l="y" r="atilde" v="-18"/>
+ <pair l="y" r="c" v="-67"/>
+ <pair l="y" r="colon" v="-11"/>
+ <pair l="y" r="comma" v="-142"/>
+ <pair l="y" r="e" v="-55"/>
+ <pair l="y" r="eacute" v="-55"/>
+ <pair l="y" r="ecircumflex" v="-55"/>
+ <pair l="y" r="egrave" v="-55"/>
+ <pair l="y" r="g" v="-36"/>
+ <pair l="y" r="hyphen" v="-39"/>
+ <pair l="y" r="l" v="-36"/>
+ <pair l="y" r="o" v="-53"/>
+ <pair l="y" r="oacute" v="-53"/>
+ <pair l="y" r="odieresis" v="-53"/>
+ <pair l="y" r="ograve" v="-53"/>
+ <pair l="y" r="oslash" v="-53"/>
+ <pair l="y" r="period" v="-142"/>
+ <pair l="y" r="s" v="-16"/>
+ <pair l="y" r="semicolon" v="-11"/>
+ <pair l="zero" r="four" v="30"/>
+ <pair l="zero" r="one" v="-78"/>
+ <pair l="zero" r="seven" v="-60"/>
+ </kernsubtable>
+ </kern>
+
+ <name>
+ <namerecord nameID="0" platformID="1" platEncID="0" langID="0x0">
+ Copyright (c) 2001 by Bigelow &amp; Holmes Inc. Instructions copyright (c) 2001 by URW++.
+ </namerecord>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0">
+ Luxi Serif
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0">
+ Regular
+ </namerecord>
+ <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0">
+ Luxi Serif Regular: B&amp;H
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0">
+ Luxi Serif Regular
+ </namerecord>
+ <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0">
+ 1.2 : October 12, 2001
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0">
+ LuxiSerif
+ </namerecord>
+ <namerecord nameID="7" platformID="1" platEncID="0" langID="0x0">
+ Luxi is a registered trademark of Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="8" platformID="1" platEncID="0" langID="0x0">
+ Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="9" platformID="1" platEncID="0" langID="0x0">
+ Kris Holmes and Charles Bigelow
+ </namerecord>
+ <namerecord nameID="11" platformID="1" platEncID="0" langID="0x0">
+ http://www.urwpp.de
+ </namerecord>
+ <namerecord nameID="12" platformID="1" platEncID="0" langID="0x0">
+ design@bigelowandholmes.com
+ </namerecord>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (c) 2001 by Bigelow &amp; Holmes Inc. Instructions copyright (c) 2001 by URW++.
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Luxi Serif
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
+ Luxi Serif Regular: B&amp;H
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Luxi Serif Regular
+ </namerecord>
+ <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
+ 1.2 : October 12, 2001
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ LuxiSerif
+ </namerecord>
+ <namerecord nameID="7" platformID="3" platEncID="1" langID="0x409">
+ Luxi is a registered trademark of Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="8" platformID="3" platEncID="1" langID="0x409">
+ Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="9" platformID="3" platEncID="1" langID="0x409">
+ Kris Holmes and Charles Bigelow
+ </namerecord>
+ <namerecord nameID="11" platformID="3" platEncID="1" langID="0x409">
+ http://www.urwpp.de
+ </namerecord>
+ <namerecord nameID="12" platformID="3" platEncID="1" langID="0x409">
+ design@bigelowandholmes.com
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="2.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ <psNames>
+ <!-- This file uses unique glyph names based on the information
+ found in the 'post' table. Since these names might not be unique,
+ we have to invent artificial names in case of clashes. In order to
+ be able to retain the original information, we need a name to
+ ps name mapping for those cases where they differ. That's what
+ you see below.
+ -->
+ <psName name=".notdef#1" psName=".notdef"/>
+ <psName name=".notdef#10" psName=".notdef"/>
+ <psName name=".notdef#11" psName=".notdef"/>
+ <psName name=".notdef#12" psName=".notdef"/>
+ <psName name=".notdef#13" psName=".notdef"/>
+ <psName name=".notdef#14" psName=".notdef"/>
+ <psName name=".notdef#15" psName=".notdef"/>
+ <psName name=".notdef#16" psName=".notdef"/>
+ <psName name=".notdef#17" psName=".notdef"/>
+ <psName name=".notdef#18" psName=".notdef"/>
+ <psName name=".notdef#2" psName=".notdef"/>
+ <psName name=".notdef#3" psName=".notdef"/>
+ <psName name=".notdef#4" psName=".notdef"/>
+ <psName name=".notdef#5" psName=".notdef"/>
+ <psName name=".notdef#6" psName=".notdef"/>
+ <psName name=".notdef#7" psName=".notdef"/>
+ <psName name=".notdef#8" psName=".notdef"/>
+ <psName name=".notdef#9" psName=".notdef"/>
+ <psName name="Euro#1" psName="Euro"/>
+ <psName name="fi#1" psName="fi"/>
+ <psName name="fl#1" psName="fl"/>
+ <psName name="fraction#1" psName="fraction"/>
+ <psName name="hyphen#1" psName="hyphen"/>
+ <psName name="macron#1" psName="macron"/>
+ <psName name="periodcentered#1" psName="periodcentered"/>
+ <psName name="semicolon#1" psName="semicolon"/>
+ </psNames>
+ <extraNames>
+ <!-- following are the name that are not taken from the standard Mac glyph order -->
+ <psName name="fraction"/>
+ <psName name="fi"/>
+ <psName name="Euro"/>
+ <psName name="tilde"/>
+ <psName name="macron"/>
+ <psName name="Euro"/>
+ <psName name="sfthyphen"/>
+ <psName name="periodcentered"/>
+ <psName name="Amacron"/>
+ <psName name="amacron"/>
+ <psName name="Abreve"/>
+ <psName name="abreve"/>
+ <psName name="Aogonek"/>
+ <psName name="aogonek"/>
+ <psName name="Ccircumflex"/>
+ <psName name="ccircumflex"/>
+ <psName name="Cdotaccent"/>
+ <psName name="cdotaccent"/>
+ <psName name="Dcaron"/>
+ <psName name="dcaron"/>
+ <psName name="Dcroat"/>
+ <psName name="dcroat"/>
+ <psName name="Emacron"/>
+ <psName name="emacron"/>
+ <psName name="Ebreve"/>
+ <psName name="ebreve"/>
+ <psName name="Edotaccent"/>
+ <psName name="edotaccent"/>
+ <psName name="Eogonek"/>
+ <psName name="eogonek"/>
+ <psName name="Ecaron"/>
+ <psName name="ecaron"/>
+ <psName name="Gcircumflex"/>
+ <psName name="gcircumflex"/>
+ <psName name="Gdotaccent"/>
+ <psName name="gdotaccent"/>
+ <psName name="Gcommaaccent"/>
+ <psName name="gcommaaccent"/>
+ <psName name="Hcircumflex"/>
+ <psName name="hcircumflex"/>
+ <psName name="Hbar"/>
+ <psName name="hbar"/>
+ <psName name="Itilde"/>
+ <psName name="itilde"/>
+ <psName name="Imacron"/>
+ <psName name="imacron"/>
+ <psName name="Ibreve"/>
+ <psName name="ibreve"/>
+ <psName name="Iogonek"/>
+ <psName name="iogonek"/>
+ <psName name="IJ"/>
+ <psName name="ij"/>
+ <psName name="Jcircumflex"/>
+ <psName name="jcircumflex"/>
+ <psName name="Kcommaaccent"/>
+ <psName name="kcommaaccent"/>
+ <psName name="kgreenlandic"/>
+ <psName name="Lacute"/>
+ <psName name="lacute"/>
+ <psName name="Lcommaaccent"/>
+ <psName name="lcommaaccent"/>
+ <psName name="Lcaron"/>
+ <psName name="lcaron"/>
+ <psName name="Ldot"/>
+ <psName name="ldot"/>
+ <psName name="Nacute"/>
+ <psName name="nacute"/>
+ <psName name="Ncommaaccent"/>
+ <psName name="ncommaaccent"/>
+ <psName name="Ncaron"/>
+ <psName name="ncaron"/>
+ <psName name="napostrophe"/>
+ <psName name="Eng"/>
+ <psName name="eng"/>
+ <psName name="Omacron"/>
+ <psName name="omacron"/>
+ <psName name="Obreve"/>
+ <psName name="obreve"/>
+ <psName name="Ohungarumlaut"/>
+ <psName name="ohungarumlaut"/>
+ <psName name="Racute"/>
+ <psName name="racute"/>
+ <psName name="Rcommaaccent"/>
+ <psName name="rcommaaccent"/>
+ <psName name="Rcaron"/>
+ <psName name="rcaron"/>
+ <psName name="Sacute"/>
+ <psName name="sacute"/>
+ <psName name="Scircumflex"/>
+ <psName name="scircumflex"/>
+ <psName name="Tcommaaccent"/>
+ <psName name="tcommaaccent"/>
+ <psName name="Tcaron"/>
+ <psName name="tcaron"/>
+ <psName name="Tbar"/>
+ <psName name="tbar"/>
+ <psName name="Utilde"/>
+ <psName name="utilde"/>
+ <psName name="Umacron"/>
+ <psName name="umacron"/>
+ <psName name="Ubreve"/>
+ <psName name="ubreve"/>
+ <psName name="Uring"/>
+ <psName name="uring"/>
+ <psName name="Uhungarumlaut"/>
+ <psName name="uhungarumlaut"/>
+ <psName name="Uogonek"/>
+ <psName name="uogonek"/>
+ <psName name="Wcircumflex"/>
+ <psName name="wcircumflex"/>
+ <psName name="Ycircumflex"/>
+ <psName name="ycircumflex"/>
+ <psName name="Zacute"/>
+ <psName name="zacute"/>
+ <psName name="Zdotaccent"/>
+ <psName name="zdotaccent"/>
+ <psName name="longs"/>
+ <psName name="Scommaaccent"/>
+ <psName name="scommaaccent"/>
+ <psName name="Tcommabelow"/>
+ <psName name="tcommabelow"/>
+ <psName name="Unterkomma"/>
+ <psName name="semicolon"/>
+ <psName name="anoteleia"/>
+ <psName name="hyphen"/>
+ <psName name="nbhyphen"/>
+ <psName name="figuredash"/>
+ <psName name="afii00208"/>
+ <psName name="quotereversed"/>
+ <psName name="radicalex"/>
+ <psName name="estimated"/>
+ <psName name="dotmath"/>
+ <psName name="fi"/>
+ <psName name="fl"/>
+ <psName name="foursuperiour"/>
+ <psName name="dotlessj"/>
+ </extraNames>
+ </post>
+
+ <gasp>
+ <gaspRange rangeMaxPPEM="8" rangeGaspBehavior="2"/>
+ <gaspRange rangeMaxPPEM="16" rangeGaspBehavior="1"/>
+ <gaspRange rangeMaxPPEM="65535" rangeGaspBehavior="3"/>
+ </gasp>
+
+ <vhea>
+ <tableVersion value="1.0"/>
+ <ascent value="2033"/>
+ <descent value="432"/>
+ <lineGap value="0"/>
+ <advanceHeightMax value="2465"/>
+ <minTopSideBearing value="0"/>
+ <minBottomSideBearing value="0"/>
+ <yMaxExtent value="2465"/>
+ <caretSlopeRise value="0"/>
+ <caretSlopeRun value="1"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <reserved4 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfVMetrics value="391"/>
+ </vhea>
+
+ <vmtx>
+ <mtx name=".notdef" height="2465" tsb="553"/>
+ <mtx name=".notdef#1" height="0" tsb="0"/>
+ <mtx name=".notdef#10" height="2465" tsb="0"/>
+ <mtx name=".notdef#11" height="2465" tsb="0"/>
+ <mtx name=".notdef#12" height="2465" tsb="0"/>
+ <mtx name=".notdef#13" height="2465" tsb="0"/>
+ <mtx name=".notdef#14" height="2465" tsb="0"/>
+ <mtx name=".notdef#15" height="2465" tsb="0"/>
+ <mtx name=".notdef#16" height="1024" tsb="0"/>
+ <mtx name=".notdef#17" height="2465" tsb="0"/>
+ <mtx name=".notdef#18" height="2465" tsb="0"/>
+ <mtx name=".notdef#2" height="2465" tsb="0"/>
+ <mtx name=".notdef#3" height="2465" tsb="0"/>
+ <mtx name=".notdef#4" height="2465" tsb="0"/>
+ <mtx name=".notdef#5" height="2465" tsb="0"/>
+ <mtx name=".notdef#6" height="2465" tsb="0"/>
+ <mtx name=".notdef#7" height="2465" tsb="0"/>
+ <mtx name=".notdef#8" height="2465" tsb="0"/>
+ <mtx name=".notdef#9" height="2465" tsb="0"/>
+ <mtx name="A" height="2465" tsb="534"/>
+ <mtx name="AE" height="2465" tsb="553"/>
+ <mtx name="Aacute" height="2465" tsb="108"/>
+ <mtx name="Abreve" height="2465" tsb="108"/>
+ <mtx name="Acircumflex" height="2465" tsb="108"/>
+ <mtx name="Adieresis" height="2465" tsb="256"/>
+ <mtx name="Agrave" height="2465" tsb="108"/>
+ <mtx name="Amacron" height="2465" tsb="306"/>
+ <mtx name="Aogonek" height="2465" tsb="534"/>
+ <mtx name="Aring" height="2465" tsb="99"/>
+ <mtx name="Atilde" height="2465" tsb="194"/>
+ <mtx name="B" height="2465" tsb="553"/>
+ <mtx name="C" height="2465" tsb="516"/>
+ <mtx name="Cacute" height="2465" tsb="108"/>
+ <mtx name="Ccaron" height="2465" tsb="108"/>
+ <mtx name="Ccedilla" height="2465" tsb="516"/>
+ <mtx name="Ccircumflex" height="2465" tsb="108"/>
+ <mtx name="Cdotaccent" height="2465" tsb="232"/>
+ <mtx name="D" height="2465" tsb="544"/>
+ <mtx name="Dcaron" height="2465" tsb="108"/>
+ <mtx name="Dcroat" height="2465" tsb="544"/>
+ <mtx name="E" height="2465" tsb="553"/>
+ <mtx name="Eacute" height="2465" tsb="108"/>
+ <mtx name="Ebreve" height="2465" tsb="108"/>
+ <mtx name="Ecaron" height="2465" tsb="108"/>
+ <mtx name="Ecircumflex" height="2465" tsb="108"/>
+ <mtx name="Edieresis" height="2465" tsb="256"/>
+ <mtx name="Edotaccent" height="2465" tsb="232"/>
+ <mtx name="Egrave" height="2465" tsb="108"/>
+ <mtx name="Emacron" height="2465" tsb="306"/>
+ <mtx name="Eng" height="2465" tsb="553"/>
+ <mtx name="Eogonek" height="2465" tsb="553"/>
+ <mtx name="Eth" height="2465" tsb="544"/>
+ <mtx name="Euro" height="2465" tsb="516"/>
+ <mtx name="Euro#1" height="2465" tsb="516"/>
+ <mtx name="F" height="2465" tsb="553"/>
+ <mtx name="G" height="2465" tsb="515"/>
+ <mtx name="Gbreve" height="2465" tsb="108"/>
+ <mtx name="Gcircumflex" height="2465" tsb="108"/>
+ <mtx name="Gcommaaccent" height="2465" tsb="515"/>
+ <mtx name="Gdotaccent" height="2465" tsb="232"/>
+ <mtx name="H" height="2465" tsb="553"/>
+ <mtx name="Hbar" height="2465" tsb="553"/>
+ <mtx name="Hcircumflex" height="2465" tsb="108"/>
+ <mtx name="I" height="2465" tsb="553"/>
+ <mtx name="IJ" height="2465" tsb="553"/>
+ <mtx name="Iacute" height="2465" tsb="108"/>
+ <mtx name="Ibreve" height="2465" tsb="108"/>
+ <mtx name="Icircumflex" height="2465" tsb="108"/>
+ <mtx name="Idieresis" height="2465" tsb="256"/>
+ <mtx name="Idotaccent" height="2465" tsb="232"/>
+ <mtx name="Igrave" height="2465" tsb="108"/>
+ <mtx name="Imacron" height="2465" tsb="306"/>
+ <mtx name="Iogonek" height="2465" tsb="553"/>
+ <mtx name="Itilde" height="2465" tsb="194"/>
+ <mtx name="J" height="2465" tsb="553"/>
+ <mtx name="Jcircumflex" height="2465" tsb="108"/>
+ <mtx name="K" height="2465" tsb="553"/>
+ <mtx name="Kcommaaccent" height="2465" tsb="553"/>
+ <mtx name="L" height="2465" tsb="553"/>
+ <mtx name="Lacute" height="2465" tsb="108"/>
+ <mtx name="Lcaron" height="2465" tsb="553"/>
+ <mtx name="Lcommaaccent" height="2465" tsb="553"/>
+ <mtx name="Ldot" height="2465" tsb="553"/>
+ <mtx name="Lslash" height="2465" tsb="553"/>
+ <mtx name="M" height="2465" tsb="553"/>
+ <mtx name="N" height="2465" tsb="553"/>
+ <mtx name="Nacute" height="2465" tsb="108"/>
+ <mtx name="Ncaron" height="2465" tsb="108"/>
+ <mtx name="Ncommaaccent" height="2465" tsb="553"/>
+ <mtx name="Ntilde" height="2465" tsb="194"/>
+ <mtx name="O" height="2465" tsb="516"/>
+ <mtx name="OE" height="2465" tsb="516"/>
+ <mtx name="Oacute" height="2465" tsb="108"/>
+ <mtx name="Obreve" height="2465" tsb="108"/>
+ <mtx name="Ocircumflex" height="2465" tsb="108"/>
+ <mtx name="Odieresis" height="2465" tsb="256"/>
+ <mtx name="Ograve" height="2465" tsb="108"/>
+ <mtx name="Ohungarumlaut" height="2465" tsb="108"/>
+ <mtx name="Omacron" height="2465" tsb="306"/>
+ <mtx name="Oslash" height="2465" tsb="516"/>
+ <mtx name="Otilde" height="2465" tsb="194"/>
+ <mtx name="P" height="2465" tsb="541"/>
+ <mtx name="Q" height="2465" tsb="516"/>
+ <mtx name="R" height="2465" tsb="541"/>
+ <mtx name="Racute" height="2465" tsb="108"/>
+ <mtx name="Rcaron" height="2465" tsb="108"/>
+ <mtx name="Rcommaaccent" height="2465" tsb="542"/>
+ <mtx name="S" height="2465" tsb="516"/>
+ <mtx name="Sacute" height="2465" tsb="108"/>
+ <mtx name="Scaron" height="2465" tsb="108"/>
+ <mtx name="Scedilla" height="2465" tsb="516"/>
+ <mtx name="Scircumflex" height="2465" tsb="108"/>
+ <mtx name="Scommaaccent" height="2465" tsb="516"/>
+ <mtx name="T" height="2465" tsb="553"/>
+ <mtx name="Tbar" height="2465" tsb="553"/>
+ <mtx name="Tcaron" height="2465" tsb="108"/>
+ <mtx name="Tcommaaccent" height="2465" tsb="553"/>
+ <mtx name="Tcommabelow" height="2465" tsb="553"/>
+ <mtx name="Thorn" height="2465" tsb="553"/>
+ <mtx name="U" height="2465" tsb="553"/>
+ <mtx name="Uacute" height="2465" tsb="108"/>
+ <mtx name="Ubreve" height="2465" tsb="108"/>
+ <mtx name="Ucircumflex" height="2465" tsb="108"/>
+ <mtx name="Udieresis" height="2465" tsb="256"/>
+ <mtx name="Ugrave" height="2465" tsb="108"/>
+ <mtx name="Uhungarumlaut" height="2465" tsb="108"/>
+ <mtx name="Umacron" height="2465" tsb="306"/>
+ <mtx name="Unterkomma" height="2465" tsb="2144"/>
+ <mtx name="Uogonek" height="2465" tsb="553"/>
+ <mtx name="Uring" height="2465" tsb="0"/>
+ <mtx name="Utilde" height="2465" tsb="194"/>
+ <mtx name="V" height="2465" tsb="553"/>
+ <mtx name="W" height="2465" tsb="553"/>
+ <mtx name="Wcircumflex" height="2465" tsb="108"/>
+ <mtx name="X" height="2465" tsb="553"/>
+ <mtx name="Y" height="2465" tsb="553"/>
+ <mtx name="Yacute" height="2465" tsb="108"/>
+ <mtx name="Ycircumflex" height="2465" tsb="108"/>
+ <mtx name="Ydieresis" height="2465" tsb="256"/>
+ <mtx name="Z" height="2465" tsb="553"/>
+ <mtx name="Zacute" height="2465" tsb="108"/>
+ <mtx name="Zcaron" height="2465" tsb="108"/>
+ <mtx name="Zdotaccent" height="2465" tsb="232"/>
+ <mtx name="a" height="2465" tsb="923"/>
+ <mtx name="aacute" height="2465" tsb="429"/>
+ <mtx name="abreve" height="2465" tsb="429"/>
+ <mtx name="acircumflex" height="2465" tsb="429"/>
+ <mtx name="acute" height="2465" tsb="429"/>
+ <mtx name="adieresis" height="2465" tsb="577"/>
+ <mtx name="ae" height="2465" tsb="922"/>
+ <mtx name="afii00208" height="2465" tsb="1391"/>
+ <mtx name="agrave" height="2465" tsb="429"/>
+ <mtx name="amacron" height="2465" tsb="627"/>
+ <mtx name="ampersand" height="2465" tsb="515"/>
+ <mtx name="anoteleia" height="2465" tsb="1295"/>
+ <mtx name="aogonek" height="2465" tsb="923"/>
+ <mtx name="aring" height="2465" tsb="296"/>
+ <mtx name="asciicircum" height="2465" tsb="553"/>
+ <mtx name="asciitilde" height="2465" tsb="1270"/>
+ <mtx name="asterisk" height="2465" tsb="553"/>
+ <mtx name="at" height="2465" tsb="516"/>
+ <mtx name="atilde" height="2465" tsb="515"/>
+ <mtx name="b" height="2465" tsb="454"/>
+ <mtx name="backslash" height="2465" tsb="552"/>
+ <mtx name="bar" height="2465" tsb="454"/>
+ <mtx name="braceleft" height="2465" tsb="454"/>
+ <mtx name="braceright" height="2465" tsb="454"/>
+ <mtx name="bracketleft" height="2465" tsb="454"/>
+ <mtx name="bracketright" height="2465" tsb="454"/>
+ <mtx name="breve" height="2465" tsb="429"/>
+ <mtx name="brokenbar" height="2465" tsb="454"/>
+ <mtx name="bullet" height="2465" tsb="923"/>
+ <mtx name="c" height="2465" tsb="923"/>
+ <mtx name="cacute" height="2465" tsb="429"/>
+ <mtx name="caron" height="2465" tsb="429"/>
+ <mtx name="ccaron" height="2465" tsb="429"/>
+ <mtx name="ccedilla" height="2465" tsb="923"/>
+ <mtx name="ccircumflex" height="2465" tsb="429"/>
+ <mtx name="cdotaccent" height="2465" tsb="553"/>
+ <mtx name="cedilla" height="2465" tsb="2033"/>
+ <mtx name="cent" height="2465" tsb="553"/>
+ <mtx name="circumflex" height="2465" tsb="429"/>
+ <mtx name="colon" height="2465" tsb="947"/>
+ <mtx name="comma" height="2465" tsb="1786"/>
+ <mtx name="copyright" height="2465" tsb="602"/>
+ <mtx name="currency" height="2465" tsb="855"/>
+ <mtx name="d" height="2465" tsb="454"/>
+ <mtx name="dagger" height="2465" tsb="553"/>
+ <mtx name="daggerdbl" height="2465" tsb="553"/>
+ <mtx name="dcaron" height="2465" tsb="454"/>
+ <mtx name="dcroat" height="2465" tsb="454"/>
+ <mtx name="degree" height="2465" tsb="516"/>
+ <mtx name="dieresis" height="2465" tsb="577"/>
+ <mtx name="divide" height="2465" tsb="947"/>
+ <mtx name="dollar" height="2465" tsb="429"/>
+ <mtx name="dotaccent" height="2465" tsb="553"/>
+ <mtx name="dotlessi" height="2465" tsb="947"/>
+ <mtx name="dotlessj" height="2465" tsb="947"/>
+ <mtx name="dotmath" height="2465" tsb="1295"/>
+ <mtx name="e" height="2465" tsb="923"/>
+ <mtx name="eacute" height="2465" tsb="429"/>
+ <mtx name="ebreve" height="2465" tsb="429"/>
+ <mtx name="ecaron" height="2465" tsb="429"/>
+ <mtx name="ecircumflex" height="2465" tsb="429"/>
+ <mtx name="edieresis" height="2465" tsb="577"/>
+ <mtx name="edotaccent" height="2465" tsb="553"/>
+ <mtx name="egrave" height="2465" tsb="429"/>
+ <mtx name="eight" height="2465" tsb="515"/>
+ <mtx name="ellipsis" height="2465" tsb="1836"/>
+ <mtx name="emacron" height="2465" tsb="627"/>
+ <mtx name="emdash" height="2465" tsb="1391"/>
+ <mtx name="endash" height="2465" tsb="1367"/>
+ <mtx name="eng" height="2465" tsb="923"/>
+ <mtx name="eogonek" height="2465" tsb="923"/>
+ <mtx name="equal" height="2465" tsb="1206"/>
+ <mtx name="estimated" height="2465" tsb="923"/>
+ <mtx name="eth" height="2465" tsb="448"/>
+ <mtx name="exclam" height="2465" tsb="553"/>
+ <mtx name="exclamdown" height="2465" tsb="947"/>
+ <mtx name="f" height="2465" tsb="429"/>
+ <mtx name="fi" height="2465" tsb="429"/>
+ <mtx name="fi#1" height="2465" tsb="429"/>
+ <mtx name="figuredash" height="2465" tsb="1367"/>
+ <mtx name="five" height="2465" tsb="553"/>
+ <mtx name="fl" height="2465" tsb="429"/>
+ <mtx name="fl#1" height="2465" tsb="429"/>
+ <mtx name="florin" height="2465" tsb="528"/>
+ <mtx name="four" height="2465" tsb="528"/>
+ <mtx name="foursuperiour" height="2465" tsb="511"/>
+ <mtx name="fraction" height="2465" tsb="516"/>
+ <mtx name="fraction#1" height="2465" tsb="516"/>
+ <mtx name="g" height="2465" tsb="923"/>
+ <mtx name="gbreve" height="2465" tsb="429"/>
+ <mtx name="gcircumflex" height="2465" tsb="429"/>
+ <mtx name="gcommaaccent" height="2465" tsb="296"/>
+ <mtx name="gdotaccent" height="2465" tsb="553"/>
+ <mtx name="germandbls" height="2465" tsb="429"/>
+ <mtx name="grave" height="2465" tsb="429"/>
+ <mtx name="greater" height="2465" tsb="947"/>
+ <mtx name="guillemotleft" height="2465" tsb="1058"/>
+ <mtx name="guillemotright" height="2465" tsb="1058"/>
+ <mtx name="guilsinglleft" height="2465" tsb="1058"/>
+ <mtx name="guilsinglright" height="2465" tsb="1058"/>
+ <mtx name="h" height="2465" tsb="454"/>
+ <mtx name="hbar" height="2465" tsb="454"/>
+ <mtx name="hcircumflex" height="2465" tsb="34"/>
+ <mtx name="hungarumlaut" height="2465" tsb="429"/>
+ <mtx name="hyphen" height="2465" tsb="1367"/>
+ <mtx name="hyphen#1" height="2465" tsb="1367"/>
+ <mtx name="i" height="2465" tsb="553"/>
+ <mtx name="iacute" height="2465" tsb="429"/>
+ <mtx name="ibreve" height="2465" tsb="429"/>
+ <mtx name="icircumflex" height="2465" tsb="429"/>
+ <mtx name="idieresis" height="2465" tsb="577"/>
+ <mtx name="igrave" height="2465" tsb="429"/>
+ <mtx name="ij" height="2465" tsb="553"/>
+ <mtx name="imacron" height="2465" tsb="627"/>
+ <mtx name="iogonek" height="2465" tsb="553"/>
+ <mtx name="itilde" height="2465" tsb="515"/>
+ <mtx name="j" height="2465" tsb="553"/>
+ <mtx name="jcircumflex" height="2465" tsb="429"/>
+ <mtx name="k" height="2465" tsb="454"/>
+ <mtx name="kcommaaccent" height="2465" tsb="454"/>
+ <mtx name="kgreenlandic" height="2465" tsb="947"/>
+ <mtx name="l" height="2465" tsb="454"/>
+ <mtx name="lacute" height="2465" tsb="34"/>
+ <mtx name="lcaron" height="2465" tsb="454"/>
+ <mtx name="lcommaaccent" height="2465" tsb="454"/>
+ <mtx name="ldot" height="2465" tsb="454"/>
+ <mtx name="less" height="2465" tsb="947"/>
+ <mtx name="logicalnot" height="2465" tsb="1243"/>
+ <mtx name="longs" height="2465" tsb="429"/>
+ <mtx name="lslash" height="2465" tsb="454"/>
+ <mtx name="m" height="2465" tsb="923"/>
+ <mtx name="macron" height="2465" tsb="627"/>
+ <mtx name="macron#1" height="2465" tsb="429"/>
+ <mtx name="minus" height="2465" tsb="1391"/>
+ <mtx name="mu" height="2465" tsb="947"/>
+ <mtx name="multiply" height="2465" tsb="947"/>
+ <mtx name="n" height="2465" tsb="923"/>
+ <mtx name="nacute" height="2465" tsb="429"/>
+ <mtx name="napostrophe" height="2465" tsb="454"/>
+ <mtx name="nbhyphen" height="2465" tsb="1367"/>
+ <mtx name="ncaron" height="2465" tsb="429"/>
+ <mtx name="ncommaaccent" height="2465" tsb="923"/>
+ <mtx name="nine" height="2465" tsb="515"/>
+ <mtx name="nonbreakingspace" height="2465" tsb="2033"/>
+ <mtx name="ntilde" height="2465" tsb="515"/>
+ <mtx name="numbersign" height="2465" tsb="553"/>
+ <mtx name="o" height="2465" tsb="923"/>
+ <mtx name="oacute" height="2465" tsb="429"/>
+ <mtx name="obreve" height="2465" tsb="429"/>
+ <mtx name="ocircumflex" height="2465" tsb="429"/>
+ <mtx name="odieresis" height="2465" tsb="577"/>
+ <mtx name="oe" height="2465" tsb="923"/>
+ <mtx name="ogonek" height="2465" tsb="2033"/>
+ <mtx name="ograve" height="2465" tsb="429"/>
+ <mtx name="ohungarumlaut" height="2465" tsb="429"/>
+ <mtx name="omacron" height="2465" tsb="627"/>
+ <mtx name="one" height="2465" tsb="540"/>
+ <mtx name="onehalf" height="2465" tsb="516"/>
+ <mtx name="onequarter" height="2465" tsb="516"/>
+ <mtx name="onesuperior" height="2465" tsb="516"/>
+ <mtx name="ordfeminine" height="2465" tsb="516"/>
+ <mtx name="ordmasculine" height="2465" tsb="516"/>
+ <mtx name="oslash" height="2465" tsb="923"/>
+ <mtx name="otilde" height="2465" tsb="515"/>
+ <mtx name="p" height="2465" tsb="923"/>
+ <mtx name="paragraph" height="2465" tsb="544"/>
+ <mtx name="parenleft" height="2465" tsb="454"/>
+ <mtx name="parenright" height="2465" tsb="454"/>
+ <mtx name="percent" height="2465" tsb="516"/>
+ <mtx name="period" height="2465" tsb="1786"/>
+ <mtx name="periodcentered" height="2465" tsb="1295"/>
+ <mtx name="periodcentered#1" height="2465" tsb="1295"/>
+ <mtx name="perthousand" height="2465" tsb="516"/>
+ <mtx name="plus" height="2465" tsb="947"/>
+ <mtx name="plusminus" height="2465" tsb="849"/>
+ <mtx name="q" height="2465" tsb="923"/>
+ <mtx name="question" height="2465" tsb="516"/>
+ <mtx name="questiondown" height="2465" tsb="553"/>
+ <mtx name="quotedbl" height="2465" tsb="454"/>
+ <mtx name="quotedblbase" height="2465" tsb="1786"/>
+ <mtx name="quotedblleft" height="2465" tsb="454"/>
+ <mtx name="quotedblright" height="2465" tsb="454"/>
+ <mtx name="quoteleft" height="2465" tsb="454"/>
+ <mtx name="quotereversed" height="2465" tsb="2033"/>
+ <mtx name="quoteright" height="2465" tsb="454"/>
+ <mtx name="quotesinglbase" height="2465" tsb="1786"/>
+ <mtx name="quotesingle" height="2465" tsb="454"/>
+ <mtx name="r" height="2465" tsb="923"/>
+ <mtx name="racute" height="2465" tsb="429"/>
+ <mtx name="radicalex" height="2465" tsb="429"/>
+ <mtx name="rcaron" height="2465" tsb="429"/>
+ <mtx name="rcommaaccent" height="2465" tsb="923"/>
+ <mtx name="registered" height="2465" tsb="602"/>
+ <mtx name="ring" height="2465" tsb="296"/>
+ <mtx name="s" height="2465" tsb="923"/>
+ <mtx name="sacute" height="2465" tsb="429"/>
+ <mtx name="scaron" height="2465" tsb="429"/>
+ <mtx name="scedilla" height="2465" tsb="923"/>
+ <mtx name="scircumflex" height="2465" tsb="429"/>
+ <mtx name="scommaaccent" height="2465" tsb="923"/>
+ <mtx name="section" height="2465" tsb="516"/>
+ <mtx name="semicolon" height="2465" tsb="947"/>
+ <mtx name="semicolon#1" height="2465" tsb="947"/>
+ <mtx name="seven" height="2465" tsb="553"/>
+ <mtx name="sfthyphen" height="2465" tsb="1367"/>
+ <mtx name="six" height="2465" tsb="515"/>
+ <mtx name="slash" height="2465" tsb="552"/>
+ <mtx name="space" height="2465" tsb="2033"/>
+ <mtx name="sterling" height="2465" tsb="528"/>
+ <mtx name="t" height="2465" tsb="701"/>
+ <mtx name="tbar" height="2465" tsb="701"/>
+ <mtx name="tcaron" height="2465" tsb="345"/>
+ <mtx name="tcommaaccent" height="2465" tsb="701"/>
+ <mtx name="tcommabelow" height="2465" tsb="701"/>
+ <mtx name="thorn" height="2465" tsb="454"/>
+ <mtx name="three" height="2465" tsb="516"/>
+ <mtx name="threequarters" height="2465" tsb="516"/>
+ <mtx name="threesuperior" height="2465" tsb="516"/>
+ <mtx name="tilde" height="2465" tsb="515"/>
+ <mtx name="trademark" height="2465" tsb="553"/>
+ <mtx name="two" height="2465" tsb="515"/>
+ <mtx name="twosuperior" height="2465" tsb="515"/>
+ <mtx name="u" height="2465" tsb="947"/>
+ <mtx name="uacute" height="2465" tsb="429"/>
+ <mtx name="ubreve" height="2465" tsb="429"/>
+ <mtx name="ucircumflex" height="2465" tsb="429"/>
+ <mtx name="udieresis" height="2465" tsb="577"/>
+ <mtx name="ugrave" height="2465" tsb="429"/>
+ <mtx name="uhungarumlaut" height="2465" tsb="429"/>
+ <mtx name="umacron" height="2465" tsb="627"/>
+ <mtx name="underscore" height="2465" tsb="2033"/>
+ <mtx name="uogonek" height="2465" tsb="947"/>
+ <mtx name="uring" height="2465" tsb="296"/>
+ <mtx name="utilde" height="2465" tsb="515"/>
+ <mtx name="v" height="2465" tsb="947"/>
+ <mtx name="w" height="2465" tsb="947"/>
+ <mtx name="wcircumflex" height="2465" tsb="429"/>
+ <mtx name="x" height="2465" tsb="947"/>
+ <mtx name="y" height="2465" tsb="947"/>
+ <mtx name="yacute" height="2465" tsb="429"/>
+ <mtx name="ycircumflex" height="2465" tsb="429"/>
+ <mtx name="ydieresis" height="2465" tsb="577"/>
+ <mtx name="yen" height="2465" tsb="553"/>
+ <mtx name="z" height="2465" tsb="947"/>
+ <mtx name="zacute" height="2465" tsb="429"/>
+ <mtx name="zcaron" height="2465" tsb="429"/>
+ <mtx name="zdotaccent" height="2465" tsb="553"/>
+ <mtx name="zero" height="2465" tsb="516"/>
+ </vmtx>
+
+</ttFont>
diff --git a/vendor/github.com/golang/freetype/testdata/luxisr-12pt-sans-hinting.txt b/vendor/github.com/golang/freetype/testdata/luxisr-12pt-sans-hinting.txt
new file mode 100644
index 000000000..e2761641d
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luxisr-12pt-sans-hinting.txt
@@ -0,0 +1,392 @@
+freetype version 2.5.1
+213 21 0 192 555;21 0 1, 21 555 1, 192 555 1, 192 0 1, 171 21 1, 171 534 1, 43 534 1, 43 21 1
+0 0 0 0 0;
+213 0 0 0 0;
+213 0 0 0 0;
+213 70 0 144 555;70 0 1, 70 74 1, 144 74 1, 144 0 1, 79 148 1, 70 444 1, 70 555 1, 144 555 1, 144 444 1, 135 148 1
+273 35 407 238 592;44 407 1, 35 592 1, 108 592 1, 99 407 1, 173 407 1, 164 592 1, 238 592 1, 229 407 1
+427 9 0 418 555;47 0 1, 89 167 1, 9 167 1, 18 213 1, 100 213 1, 133 342 1, 44 342 1, 54 389 1, 144 389 1, 186 555 1, 234 555 1, 192 389 1, 291 389 1, 332 555 1, 380 555 1, 339 389 1, 418 389 1, 409 342 1, 327 342 1, 294 213 1, 383 213 1, 374 167 1, 283 167 1, 242 0 1, 194 0 1, 235 167 1, 137 167 1, 95 0 1, 148 213 1, 247 213 1, 279 342 1, 180 342 1
+427 39 -46 353 602;187 -46 1, 187 0 1, 121 0 0, 39 31 1, 39 95 1, 123 56 0, 187 56 1, 187 255 1, 117 298 0, 88 330 1, 55 368 0, 55 422 1, 55 486 0, 103 524 1, 135 550 0, 187 555 1, 187 602 1, 224 602 1, 224 555 1, 278 555 0, 344 530 1, 344 470 1, 273 501 0, 224 504 1, 224 307 1, 228 304 1, 238 298 0, 247 293 1, 251 290 1, 299 262 0, 322 237 1, 353 205 0, 353 155 1, 353 87 0, 308 42 1, 276 12 0, 224 0 1, 224 -46 1, 224 60 1, 288 85 0, 288 144 1, 288 175 0, 270 195 1, 257 210 0, 224 233 1, 187 331 1, 187 502 1, 120 479 0, 120 425 1, 120 376 0
+683 42 -14 641 569;94 -14 1, 531 569 1, 589 569 1, 152 -14 1, 161 555 1, 216 555 0, 248 518 1, 280 480 0, 280 416 1, 280 352 0, 248 315 1, 216 278 0, 161 278 1, 106 278 0, 74 315 1, 42 353 0, 42 418 1, 42 475 0, 68 511 1, 101 555 0, 161 518 1, 134 518 0, 117 491 1, 100 462 0, 100 419 1, 100 375 0, 114 348 1, 131 315 0, 161 315 1, 189 315 0, 206 343 1, 222 371 0, 222 416 1, 222 462 0, 206 490 1, 188 518 0, 522 278 1, 577 278 0, 609 240 1, 641 203 0, 641 139 1, 641 75 0, 609 38 1, 577 0 0, 522 0 1, 467 0 0, 435 38 1, 403 75 0, 403 141 1, 403 198 0, 429 233 1, 462 278 0, 522 241 1, 494 241 0, 477 213 1, 461 185 0, 461 141 1, 461 98 0, 474 71 1, 491 37 0, 522 37 1, 549 37 0, 566 65 1, 583 93 0, 583 139 1, 583 185 0, 566 213 1, 549 241 0
+512 21 -14 485 569;384 0 1, 357 33 1, 282 -14 0, 214 -14 1, 132 -14 0, 77 37 1, 21 88 0, 21 166 1, 21 243 0, 69 290 1, 98 318 0, 152 339 1, 119 400 0, 119 445 1, 119 501 0, 153 535 1, 188 569 0, 247 569 1, 303 569 0, 336 539 1, 368 508 0, 368 457 1, 368 401 0, 325 360 1, 298 335 0, 248 312 1, 311 198 0, 373 123 1, 410 171 0, 410 265 1, 410 295 1, 483 295 1, 483 165 0, 408 83 1, 441 41 0, 485 0 1, 325 76 1, 251 160 0, 178 296 1, 141 279 0, 123 257 1, 95 225 0, 95 179 1, 95 122 0, 134 82 1, 172 42 0, 226 42 1, 268 42 0, 220 359 1, 256 374 0, 273 392 1, 299 419 0, 299 456 1, 299 513 0, 246 513 1, 191 513 0, 191 453 1, 191 416 0, 217 365 1
+147 27 389 120 592;45 389 1, 27 592 1, 120 592 1, 101 389 1
+256 49 -111 225 592;225 -60 1, 225 -111 1, 150 -58 0, 107 21 1, 49 123 0, 49 241 1, 49 364 0, 111 470 1, 154 542 0, 225 592 1, 225 541 1, 174 485 0, 152 426 1, 123 353 0, 123 241 1, 123 124 0, 154 48 1, 177 -7 0
+256 31 -111 207 592;31 541 1, 31 592 1, 106 539 0, 150 461 1, 207 359 0, 207 241 1, 207 117 0, 144 12 1, 102 -60 0, 31 -111 1, 31 -60 1, 81 -3 0, 104 56 1, 132 129 0, 132 241 1, 132 357 0, 101 433 1, 79 487 0
+299 15 282 284 555;267 483 1, 284 431 1, 180 406 1, 180 407 1, 180 411 0, 180 411 1, 180 411 1, 180 427 0, 170 437 1, 255 314 1, 210 282 1, 152 382 1, 170 384 0, 178 401 1, 88 282 1, 43 314 1, 120 401 1, 128 384 0, 147 382 1, 15 431 1, 32 483 1, 129 437 1, 118 427 0, 118 411 1, 118 411 1, 118 411 0, 118 409 1, 119 408 1, 119 407 0, 119 406 1, 122 555 1, 177 555 1, 165 440 1, 157 444 0, 149 444 1, 141 444 0, 133 440 1
+449 39 37 409 407;196 37 1, 196 194 1, 39 194 1, 39 250 1, 196 250 1, 196 407 1, 252 407 1, 252 250 1, 409 250 1, 409 194 1, 252 194 1, 252 37 1
+213 60 -120 153 93;60 -120 1, 60 -93 1, 96 -83 0, 96 -8 1, 96 0 1, 60 0 1, 60 93 1, 153 93 1, 153 12 1, 153 -110 0
+256 33 194 223 250;33 194 1, 33 250 1, 223 250 1, 223 194 1
+213 60 0 153 93;60 0 1, 60 93 1, 153 93 1, 153 0 1
+213 -22 -111 236 555;-22 -111 1, 178 555 1, 236 555 1, 36 -111 1
+427 30 -14 397 569;213 569 1, 298 569 0, 347 491 1, 397 413 0, 397 279 1, 397 142 0, 347 64 1, 298 -14 0, 211 -14 1, 137 -14 0, 90 50 1, 30 130 0, 30 278 1, 30 413 0, 80 491 1, 129 569 0, 213 513 1, 163 513 0, 136 452 1, 109 390 0, 109 278 1, 109 167 0, 136 104 1, 163 42 0, 214 42 1, 260 42 0, 285 87 1, 318 148 0, 318 279 1, 318 392 0, 291 452 1, 263 513 0
+427 86 0 383 569;86 0 1, 86 56 1, 197 56 1, 197 494 1, 86 466 1, 86 523 1, 272 569 1, 272 56 1, 383 56 1, 383 0 1
+427 38 0 353 569;38 0 1, 38 65 1, 64 125 0, 125 188 1, 165 230 1, 202 267 1, 274 341 0, 274 415 1, 274 468 0, 246 493 1, 224 514 0, 184 514 1, 132 514 0, 52 469 1, 52 534 1, 128 569 0, 194 569 1, 267 569 0, 310 527 1, 353 485 0, 353 413 1, 353 364 0, 331 326 1, 308 287 0, 247 233 1, 221 209 1, 143 139 0, 128 65 1, 350 65 1, 350 0 1
+427 57 -14 362 569;57 4 1, 57 73 1, 60 72 1, 70 68 0, 74 67 1, 115 52 0, 129 48 1, 154 42 0, 174 42 1, 230 42 0, 258 73 1, 283 100 0, 283 150 1, 283 208 0, 245 239 1, 208 270 0, 138 270 1, 109 270 1, 109 320 1, 134 320 1, 199 321 0, 234 350 1, 270 379 0, 270 430 1, 270 513 0, 180 513 1, 134 513 0, 65 482 1, 65 547 1, 133 569 0, 185 569 1, 275 569 0, 315 526 1, 344 494 0, 344 441 1, 344 381 0, 302 343 1, 277 320 0, 228 301 1, 271 290 0, 293 277 1, 362 237 0, 362 153 1, 362 77 0, 312 32 1, 263 -14 0, 181 -14 1, 137 -14 0
+427 12 0 402 555;258 0 1, 258 157 1, 12 157 1, 12 213 1, 258 555 1, 327 555 1, 327 218 1, 402 218 1, 402 157 1, 327 157 1, 327 0 1, 84 218 1, 263 218 1, 263 464 1
+427 61 -14 362 555;61 -2 1, 61 64 1, 118 42 0, 166 42 1, 221 42 0, 252 74 1, 284 107 0, 284 162 1, 284 288 0, 113 288 1, 92 288 0, 71 285 1, 71 555 1, 351 555 1, 351 491 1, 135 491 1, 135 344 1, 234 343 0, 291 304 1, 362 255 0, 362 159 1, 362 78 0, 308 32 1, 253 -14 0, 158 -14 1, 116 -14 0
+427 32 -14 385 569;112 292 1, 164 356 0, 238 356 1, 306 356 0, 346 310 1, 385 264 0, 385 182 1, 385 92 0, 339 39 1, 292 -14 0, 214 -14 1, 129 -14 0, 80 59 1, 32 132 0, 32 260 1, 32 405 0, 90 487 1, 148 569 0, 251 569 1, 298 569 0, 355 548 1, 355 484 1, 287 514 0, 249 514 1, 166 514 0, 133 431 1, 120 398 0, 115 357 1, 113 335 0, 218 303 1, 172 303 0, 143 271 1, 114 239 0, 114 183 1, 114 122 0, 144 82 1, 174 42 0, 221 42 1, 312 42 0, 312 167 1, 312 303 0
+427 51 0 407 555;83 0 1, 94 65 0, 114 112 1, 134 159 0, 185 242 1, 337 486 1, 51 486 1, 51 555 1, 407 555 1, 407 486 1, 194 171 0, 168 0 1
+427 37 -14 408 569;147 302 1, 111 329 0, 92 353 1, 66 389 0, 66 429 1, 66 491 0, 112 530 1, 158 569 0, 233 569 1, 302 569 0, 344 536 1, 386 503 0, 386 449 1, 386 400 0, 349 357 1, 326 331 0, 283 302 1, 339 273 0, 368 243 1, 408 199 0, 408 143 1, 408 74 0, 356 30 1, 303 -14 0, 219 -14 1, 137 -14 0, 87 28 1, 37 69 0, 37 138 1, 37 198 0, 78 245 1, 102 274 0, 242 326 1, 319 379 0, 319 437 1, 319 472 0, 294 492 1, 268 513 0, 225 513 1, 183 513 0, 158 494 1, 133 474 0, 133 441 1, 133 402 0, 176 368 1, 197 351 0, 188 272 1, 146 240 0, 130 216 1, 111 189 0, 111 149 1, 111 101 0, 142 71 1, 173 42 0, 223 42 1, 271 42 0, 302 67 1, 332 92 0, 332 132 1, 332 168 0, 309 192 1, 289 212 0, 240 241 1
+427 32 -14 385 569;305 263 1, 253 199 0, 179 199 1, 110 199 0, 71 245 1, 32 292 0, 32 373 1, 32 463 0, 78 516 1, 124 569 0, 202 569 1, 288 569 0, 336 496 1, 385 423 0, 385 296 1, 385 150 0, 327 68 1, 269 -14 0, 166 -14 1, 118 -14 0, 61 7 1, 61 71 1, 130 42 0, 168 42 1, 251 42 0, 284 125 1, 297 158 0, 302 198 1, 304 220 0, 196 513 1, 104 513 0, 104 389 1, 104 252 0, 198 252 1, 245 252 0, 273 284 1, 302 317 0, 302 372 1, 302 433 0, 273 473 1, 243 513 0
+213 70 0 144 407;70 0 1, 70 74 1, 144 74 1, 144 0 1, 70 333 1, 70 407 1, 144 407 1, 144 333 1
+213 70 -120 144 407;70 -120 1, 70 -93 1, 96 -79 0, 96 -9 1, 96 0 1, 70 0 1, 70 74 1, 144 74 1, 144 12 1, 143 -102 0, 70 333 1, 70 407 1, 144 407 1, 144 333 1
+449 39 37 409 407;409 37 1, 39 222 1, 409 407 1, 409 345 1, 164 222 1, 164 222 1, 409 99 1
+449 39 125 409 319;39 125 1, 39 180 1, 409 180 1, 409 125 1, 39 264 1, 39 319 1, 409 319 1, 409 264 1
+449 39 37 409 407;39 407 1, 409 222 1, 39 37 1, 39 99 1, 284 222 1, 284 222 1, 39 345 1
+427 52 0 380 569;141 0 1, 141 74 1, 215 74 1, 215 0 1, 141 148 1, 141 168 1, 141 260 0, 202 308 1, 236 334 1, 302 385 0, 302 440 1, 302 513 0, 199 513 1, 136 513 0, 52 486 1, 52 548 1, 135 569 0, 204 569 1, 281 569 0, 324 544 1, 380 512 0, 380 441 1, 380 371 0, 309 327 1, 278 308 1, 241 285 0, 228 260 1, 215 236 0, 215 189 1, 215 148 1
+780 95 -14 692 569;470 17 1, 400 -14 0, 336 -14 1, 232 -14 0, 164 51 1, 95 116 0, 95 218 1, 95 356 0, 201 462 1, 306 569 0, 445 569 1, 551 569 0, 621 501 1, 692 434 0, 692 333 1, 692 241 0, 635 176 1, 578 111 0, 498 111 1, 435 111 0, 435 154 1, 435 169 0, 443 194 1, 458 241 1, 453 241 1, 422 182 0, 393 153 1, 352 111 0, 307 111 1, 236 111 0, 236 196 1, 236 290 0, 297 366 1, 357 442 0, 434 442 1, 443 442 0, 458 441 1, 462 441 0, 467 440 1, 482 440 0, 492 440 1, 543 440 1, 496 201 1, 494 190 0, 494 178 1, 494 153 0, 522 153 1, 572 153 0, 611 206 1, 650 260 0, 650 328 1, 650 414 0, 590 471 1, 531 528 0, 440 528 1, 321 528 0, 229 434 1, 137 341 0, 137 222 1, 137 135 0, 195 82 1, 252 28 0, 342 28 1, 400 28 0, 456 55 1, 462 312 1, 477 386 1, 442 398 0, 417 398 1, 364 398 0, 329 344 1, 294 291 0, 294 213 1, 294 157 0, 324 157 1, 374 157 0
+512 7 0 503 555;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1
+512 62 0 462 555;62 0 1, 62 555 1, 240 555 1, 349 555 0, 394 527 1, 440 498 0, 440 431 1, 440 369 0, 395 330 1, 368 307 0, 317 289 1, 382 270 0, 415 242 1, 462 202 0, 462 138 1, 462 80 0, 423 41 1, 396 13 0, 353 6 1, 318 0 0, 259 0 1, 141 59 1, 199 59 1, 309 59 0, 344 75 1, 378 92 0, 378 144 1, 378 201 0, 334 231 1, 289 261 0, 205 261 1, 141 261 1, 141 311 1, 208 311 1, 359 311 0, 359 417 1, 359 471 0, 315 485 1, 282 496 0, 213 496 1, 141 496 1
+555 44 -14 507 569;507 29 1, 421 -14 0, 323 -14 1, 186 -14 0, 115 60 1, 44 135 0, 44 277 1, 44 419 0, 116 494 1, 189 569 0, 327 569 1, 404 569 0, 506 545 1, 506 471 1, 390 510 0, 323 510 1, 228 510 0, 178 450 1, 128 390 0, 128 278 1, 128 167 0, 182 108 1, 235 48 0, 332 48 1, 414 48 0, 507 96 1
+555 62 0 520 555;62 0 1, 62 555 1, 240 555 1, 520 555 0, 520 290 1, 520 152 0, 447 76 1, 374 0 0, 241 0 1, 141 59 1, 235 59 1, 435 59 0, 435 281 1, 435 412 0, 356 466 1, 333 482 0, 301 488 1, 263 496 0, 199 496 1, 141 496 1
+512 72 0 491 555;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1
+469 72 0 449 555;72 0 1, 72 555 1, 449 555 1, 449 496 1, 150 496 1, 150 310 1, 411 310 1, 411 252 1, 150 252 1, 150 0 1
+597 35 -14 527 569;527 258 1, 527 15 1, 424 -14 0, 327 -14 1, 35 -14 0, 35 276 1, 35 417 0, 110 493 1, 186 569 0, 329 569 1, 421 569 0, 526 544 1, 526 471 1, 406 510 0, 326 510 1, 119 510 0, 119 279 1, 119 165 0, 176 105 1, 233 45 0, 338 45 1, 381 45 0, 449 59 1, 449 200 1, 356 200 1, 356 258 1
+555 62 0 492 555;62 0 1, 62 555 1, 141 555 1, 141 321 1, 414 321 1, 414 555 1, 492 555 1, 492 0 1, 414 0 1, 414 262 1, 141 262 1, 141 0 1
+213 68 0 146 555;68 0 1, 68 555 1, 146 555 1, 146 0 1
+384 18 -111 315 555;18 -87 1, 18 -19 1, 83 -48 0, 138 -48 1, 203 -48 0, 221 -18 1, 236 7 0, 236 68 1, 236 555 1, 315 555 1, 315 70 1, 315 -111 0, 135 -111 1, 74 -111 0
+512 72 0 494 555;72 0 1, 72 555 1, 146 555 1, 146 282 1, 376 555 1, 455 555 1, 232 290 1, 494 0 1, 394 0 1, 146 281 1, 146 0 1
+427 62 0 413 555;62 0 1, 62 555 1, 141 555 1, 141 59 1, 413 59 1, 413 0 1
+640 62 0 578 555;62 0 1, 62 555 1, 171 555 1, 324 126 1, 480 555 1, 578 555 1, 578 0 1, 504 0 1, 504 451 1, 353 37 1, 277 37 1, 130 453 1, 130 0 1
+555 62 0 492 555;62 0 1, 62 555 1, 139 555 1, 425 126 1, 425 555 1, 492 555 1, 492 0 1, 415 0 1, 129 429 1, 129 0 1
+597 35 -14 563 569;299 569 1, 419 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 419 -14 0, 295 -14 1, 189 -14 0, 121 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 214 510 0, 167 449 1, 119 388 0, 119 278 1, 119 169 0, 167 107 1, 213 45 0, 297 45 1, 375 45 0, 421 95 1, 479 156 0, 479 278 1, 479 388 0, 431 449 1, 383 510 0
+512 63 0 494 555;63 0 1, 63 555 1, 280 555 1, 366 555 0, 403 545 1, 441 535 0, 465 507 1, 494 471 0, 494 408 1, 494 221 0, 257 221 1, 141 221 1, 141 0 1, 141 280 1, 254 280 1, 411 280 0, 411 404 1, 411 464 0, 370 481 1, 335 496 0, 255 496 1, 141 496 1
+597 35 -111 615 569;615 -48 1, 565 -111 1, 434 -68 0, 346 -10 1, 307 -14 0, 287 -14 1, 177 -14 0, 106 68 1, 35 149 0, 35 278 1, 35 410 0, 107 489 1, 178 569 0, 298 569 1, 419 569 0, 491 489 1, 563 410 0, 563 277 1, 563 160 0, 509 87 1, 488 58 0, 460 38 1, 446 27 0, 418 11 1, 510 -30 0, 297 510 1, 214 510 0, 167 448 1, 119 387 0, 119 278 1, 119 169 0, 167 107 1, 214 45 0, 297 45 1, 382 45 0, 430 106 1, 479 167 0, 479 275 1, 479 376 0, 440 436 1, 392 510 0
+555 62 0 538 555;62 0 1, 62 555 1, 294 555 1, 465 555 0, 465 417 1, 465 350 0, 423 306 1, 399 281 0, 353 260 1, 538 0 1, 441 0 1, 283 235 1, 141 235 1, 141 0 1, 141 294 1, 229 294 1, 309 294 0, 346 321 1, 384 350 0, 384 408 1, 384 456 0, 353 476 1, 323 496 0, 253 496 1, 141 496 1
+512 45 -14 466 569;45 20 1, 45 98 1, 156 45 0, 264 45 1, 385 45 0, 385 135 1, 385 181 0, 352 203 1, 326 220 0, 269 239 1, 193 264 1, 48 311 0, 48 421 1, 48 569 0, 251 569 1, 338 569 0, 432 545 1, 432 473 1, 334 510 0, 246 510 1, 124 510 0, 124 427 1, 124 394 0, 147 374 1, 171 354 0, 230 334 1, 308 309 1, 395 281 0, 431 244 1, 466 207 0, 466 146 1, 466 72 0, 411 29 1, 357 -14 0, 261 -14 1, 167 -14 0
+469 8 0 461 555;195 0 1, 195 496 1, 8 496 1, 8 555 1, 461 555 1, 461 496 1, 274 496 1, 274 0 1
+555 62 -14 492 555;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1
+512 14 0 508 555;228 0 1, 14 555 1, 95 555 1, 272 99 1, 441 555 1, 508 555 1, 302 0 1
+725 9 0 716 555;152 0 1, 9 555 1, 85 555 1, 199 117 1, 329 555 1, 405 555 1, 530 121 1, 651 555 1, 716 555 1, 560 0 1, 482 0 1, 358 428 1, 230 0 1
+512 11 0 502 555;11 0 1, 215 276 1, 20 555 1, 113 555 1, 263 339 1, 423 555 1, 498 555 1, 299 289 1, 502 0 1, 409 0 1, 251 224 1, 85 0 1
+512 11 0 501 555;210 0 1, 210 231 1, 11 555 1, 101 555 1, 259 298 1, 428 555 1, 501 555 1, 289 233 1, 289 0 1
+469 38 0 431 555;38 0 1, 38 63 1, 336 496 1, 56 496 1, 56 555 1, 431 555 1, 431 496 1, 132 63 1, 431 63 1, 431 0 1
+213 56 -111 204 592;56 -111 1, 56 592 1, 204 592 1, 204 537 1, 121 537 1, 121 -56 1, 204 -56 1, 204 -111 1
+213 -22 -111 236 555;236 -111 1, 178 -111 1, -22 555 1, 36 555 1
+213 10 -111 158 592;158 592 1, 158 -111 1, 10 -111 1, 10 -56 1, 93 -56 1, 93 537 1, 10 537 1, 10 592 1
+360 14 222 347 555;180 431 1, 75 222 1, 14 222 1, 180 555 1, 347 222 1, 284 222 1
+427 0 -56 427 0;0 -56 1, 0 0 1, 427 0 1, 427 -56 1
+256 40 481 216 602;216 481 1, 160 481 1, 40 602 1, 125 602 1
+427 36 -9 412 416;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0
+427 58 -9 395 592;132 264 1, 132 56 1, 183 46 0, 209 46 1, 315 46 0, 315 207 1, 315 275 0, 294 313 1, 273 352 0, 238 352 1, 191 352 0, 132 331 1, 153 369 0, 176 389 1, 209 416 0, 254 416 1, 317 416 0, 356 361 1, 395 306 0, 395 215 1, 395 108 0, 344 49 1, 294 -9 0, 203 -9 1, 168 -9 0, 132 0 1, 58 -5 1, 58 592 1, 132 592 1
+384 32 -9 347 416;347 12 1, 279 -9 0, 219 -9 1, 135 -9 0, 84 50 1, 32 109 0, 32 204 1, 32 303 0, 85 360 1, 137 416 0, 231 416 1, 278 416 0, 343 403 1, 343 341 1, 281 360 0, 245 360 1, 116 360 0, 116 204 1, 116 130 0, 149 90 1, 182 50 0, 242 50 1, 287 50 0, 347 76 1
+427 32 -9 369 592;295 143 1, 295 351 1, 243 361 0, 218 361 1, 112 361 0, 112 200 1, 112 133 0, 133 94 1, 154 56 0, 189 56 1, 236 56 0, 295 76 1, 274 38 0, 251 18 1, 218 -9 0, 173 -9 1, 110 -9 0, 71 46 1, 32 101 0, 32 193 1, 32 299 0, 83 358 1, 133 416 0, 224 416 1, 259 416 0, 295 407 1, 295 592 1, 369 592 1, 369 0 1, 295 0 1
+427 32 -9 383 416;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0
+213 12 0 236 602;66 0 1, 66 352 1, 12 352 1, 12 407 1, 66 407 1, 66 456 1, 66 602 0, 181 602 1, 206 602 0, 236 592 1, 236 533 1, 209 546 0, 189 546 1, 162 546 0, 151 528 1, 140 510 0, 140 464 1, 140 407 1, 213 407 1, 213 352 1, 140 352 1, 140 0 1
+427 35 -158 372 416;298 162 1, 298 351 1, 245 361 0, 222 361 1, 115 361 0, 115 215 1, 115 150 0, 136 112 1, 157 74 0, 192 74 1, 239 74 0, 298 95 1, 277 57 0, 254 37 1, 221 9 0, 176 9 1, 113 9 0, 74 64 1, 35 119 0, 35 207 1, 35 306 0, 85 361 1, 135 416 0, 226 416 1, 261 416 0, 298 407 1, 372 407 1, 372 111 1, 372 15 0, 362 -31 1, 334 -158 0, 174 -158 1, 106 -158 0, 38 -135 1, 38 -71 1, 118 -102 0, 173 -102 1, 298 -102 0, 298 31 1
+427 58 0 374 592;58 0 1, 58 592 1, 132 592 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1
+171 48 0 122 555;48 0 1, 48 407 1, 122 407 1, 122 0 1, 48 481 1, 48 555 1, 122 555 1, 122 481 1
+171 -58 -157 124 555;-58 -145 1, -58 -87 1, -28 -102 0, -2 -102 1, 35 -102 0, 43 -74 1, 50 -51 0, 50 0 1, 50 407 1, 124 407 1, 124 0 1, 124 -157 0, 4 -157 1, -29 -157 0, 50 481 1, 50 555 1, 124 555 1, 124 481 1
+384 58 0 377 592;58 0 1, 58 592 1, 132 592 1, 132 210 1, 268 407 1, 339 407 1, 209 215 1, 377 0 1, 287 0 1, 132 209 1, 132 0 1
+171 48 0 122 592;48 0 1, 48 592 1, 122 592 1, 122 0 1
+640 58 0 587 416;58 0 1, 58 407 1, 132 407 1, 132 331 1, 164 380 0, 185 397 1, 210 416 0, 249 416 1, 298 416 0, 329 385 1, 346 366 0, 359 331 1, 392 380 0, 413 397 1, 437 416 0, 477 416 1, 587 416 0, 587 296 1, 587 0 1, 513 0 1, 512 285 1, 512 355 0, 458 355 1, 410 355 0, 359 273 1, 359 0 1, 285 0 1, 285 285 1, 285 355 0, 231 355 1, 183 355 0, 132 273 1, 132 0 1
+427 58 0 374 416;58 0 1, 58 407 1, 132 407 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1
+427 32 -9 395 416;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0
+427 58 -148 395 416;132 -148 1, 58 -148 1, 58 407 1, 132 407 1, 132 331 1, 153 369 0, 176 389 1, 209 416 0, 254 416 1, 317 416 0, 356 361 1, 395 306 0, 395 215 1, 395 108 0, 344 49 1, 294 -9 0, 203 -9 1, 168 -9 0, 132 0 1, 132 264 1, 132 56 1, 183 46 0, 209 46 1, 315 46 0, 315 207 1, 315 275 0, 294 313 1, 273 352 0, 238 352 1, 191 352 0
+427 32 -148 369 416;295 407 1, 369 407 1, 369 -148 1, 295 -148 1, 295 76 1, 274 38 0, 251 18 1, 218 -9 0, 173 -9 1, 110 -9 0, 71 46 1, 32 101 0, 32 193 1, 32 299 0, 83 358 1, 133 416 0, 224 416 1, 259 416 0, 295 143 1, 295 351 1, 243 361 0, 218 361 1, 112 361 0, 112 200 1, 112 133 0, 133 94 1, 154 56 0, 189 56 1, 236 56 0
+256 58 0 251 416;58 0 1, 58 407 1, 132 407 1, 132 331 1, 148 369 0, 166 389 1, 193 416 0, 230 416 1, 237 416 0, 251 414 1, 251 345 1, 231 352 0, 219 352 1, 178 352 0, 132 269 1, 132 0 1
+384 44 -9 341 416;44 14 1, 44 82 1, 118 46 0, 181 46 1, 266 46 0, 266 106 1, 266 147 0, 207 167 1, 141 189 1, 46 220 0, 46 303 1, 46 416 0, 201 416 1, 246 416 0, 309 404 1, 309 342 1, 253 361 0, 196 361 1, 119 361 0, 119 310 1, 119 273 0, 172 256 1, 231 237 1, 341 201 0, 341 113 1, 341 57 0, 297 24 1, 254 -9 0, 178 -9 1, 119 -9 0
+213 11 -9 210 488;199 -2 1, 176 -9 0, 156 -9 1, 57 -9 0, 57 113 1, 57 352 1, 11 352 1, 11 407 1, 57 407 1, 57 481 1, 131 488 1, 131 407 1, 210 407 1, 210 352 1, 131 352 1, 131 126 1, 131 78 0, 139 62 1, 147 46 0, 174 46 1, 188 46 0, 199 50 1
+427 53 -9 369 407;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1
+384 7 0 380 407;152 0 1, 7 407 1, 82 407 1, 195 90 1, 314 407 1, 380 407 1, 225 0 1
+555 4 0 549 407;102 0 1, 4 407 1, 77 407 1, 150 101 1, 244 407 1, 318 407 1, 400 99 1, 486 407 1, 549 407 1, 435 0 1, 361 0 1, 275 315 1, 177 0 1
+384 11 0 372 407;11 0 1, 143 215 1, 15 407 1, 101 407 1, 203 255 1, 294 407 1, 362 407 1, 238 202 1, 372 0 1, 287 0 1, 177 164 1, 79 0 1
+384 7 -148 380 407;152 0 1, 7 407 1, 82 407 1, 193 95 1, 314 407 1, 380 407 1, 164 -148 1, 87 -148 1
+384 28 0 356 407;28 0 1, 28 56 1, 261 352 1, 39 352 1, 39 407 1, 352 407 1, 352 352 1, 119 56 1, 356 56 1, 356 0 1
+257 9 -111 213 592;9 269 1, 32 269 1, 90 269 0, 90 330 1, 90 354 0, 84 381 1, 77 414 1, 69 447 0, 69 476 1, 69 537 0, 120 569 1, 156 591 0, 213 592 1, 213 537 1, 193 537 1, 167 537 0, 151 524 1, 134 510 0, 134 490 1, 134 482 0, 139 455 1, 145 416 1, 149 391 0, 149 361 1, 149 290 0, 94 241 1, 149 192 0, 149 120 1, 149 90 0, 145 65 1, 139 27 1, 134 -1 0, 134 -9 1, 134 -29 0, 151 -42 1, 168 -56 0, 193 -56 1, 213 -56 1, 213 -111 1, 153 -110 0, 117 -85 1, 69 -53 0, 69 6 1, 69 35 0, 77 67 1, 84 100 1, 90 127 0, 90 152 1, 90 213 0, 32 213 1, 9 213 1
+200 72 -111 128 592;72 -111 1, 72 592 1, 128 592 1, 128 -111 1
+257 44 -111 247 592;247 213 1, 224 213 1, 167 213 0, 167 152 1, 167 124 0, 173 100 1, 180 67 1, 187 36 0, 187 6 1, 187 -56 0, 135 -88 1, 100 -110 0, 44 -111 1, 44 -56 1, 63 -56 1, 89 -56 0, 105 -42 1, 122 -29 0, 122 -9 1, 122 1 0, 118 27 1, 111 65 1, 107 88 0, 107 120 1, 107 192 0, 162 241 1, 137 263 0, 125 285 1, 107 318 0, 107 361 1, 107 393 0, 111 416 1, 118 455 1, 122 480 0, 122 491 1, 122 510 0, 105 524 1, 88 537 0, 63 537 1, 44 537 1, 44 592 1, 104 591 0, 140 566 1, 187 534 0, 187 475 1, 187 445 0, 180 414 1, 173 381 1, 167 357 0, 167 329 1, 167 269 0, 224 269 1, 247 269 1
+449 39 155 409 290;95 167 1, 39 167 1, 40 206 0, 47 227 1, 69 290 0, 139 290 1, 176 290 0, 213 264 1, 255 235 1, 280 218 1, 291 210 0, 309 210 1, 352 210 0, 354 278 1, 409 278 1, 408 238 0, 401 217 1, 379 155 0, 310 155 1, 273 155 0, 235 180 1, 193 209 1, 168 227 1, 157 234 0, 140 234 1, 96 234 0
+512 7 0 503 666;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1, 150 602 1, 150 666 1, 215 666 1, 215 602 1, 299 602 1, 299 666 1, 363 666 1, 363 602 1
+512 7 0 503 726;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1, 257 726 1, 292 726 0, 317 701 1, 342 676 0, 342 641 1, 342 605 0, 317 580 1, 292 555 0, 256 555 1, 225 555 0, 202 576 1, 172 602 0, 172 641 1, 172 676 0, 197 701 1, 222 726 0, 257 693 1, 235 693 0, 219 678 1, 204 663 0, 204 641 1, 204 619 0, 219 603 1, 235 588 0, 256 588 1, 276 588 0, 291 600 1, 310 616 0, 310 641 1, 310 663 0, 294 678 1, 279 693 0
+555 44 -162 507 569;507 29 1, 421 -14 0, 323 -14 1, 186 -14 0, 115 60 1, 44 135 0, 44 277 1, 44 419 0, 116 494 1, 189 569 0, 327 569 1, 404 569 0, 506 545 1, 506 471 1, 390 510 0, 323 510 1, 228 510 0, 178 450 1, 128 390 0, 128 278 1, 128 167 0, 182 108 1, 235 48 0, 332 48 1, 414 48 0, 507 96 1, 288 0 1, 324 0 1, 302 -41 1, 329 -42 0, 348 -56 1, 374 -74 0, 374 -101 1, 374 -126 0, 352 -144 1, 330 -162 0, 298 -162 1, 273 -162 0, 244 -154 1, 244 -124 1, 263 -129 0, 283 -129 1, 322 -129 0, 322 -102 1, 322 -67 0, 252 -66 1
+512 72 0 491 722;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 224 602 1, 315 722 1, 400 722 1, 280 602 1
+555 62 0 492 689;62 0 1, 62 555 1, 139 555 1, 425 126 1, 425 555 1, 492 555 1, 492 0 1, 415 0 1, 129 429 1, 129 0 1, 162 602 1, 165 637 0, 174 656 1, 191 689 0, 232 689 1, 259 689 0, 282 675 1, 305 661 1, 326 648 0, 337 648 1, 362 648 0, 366 689 1, 412 689 1, 409 654 0, 400 635 1, 383 602 0, 342 602 1, 315 602 0, 292 616 1, 269 630 1, 249 643 0, 237 643 1, 212 643 0, 208 602 1
+597 35 -14 563 666;299 569 1, 418 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 418 -14 0, 295 -14 1, 189 -14 0, 120 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 213 510 0, 166 449 1, 119 388 0, 119 278 1, 119 169 0, 166 107 1, 213 45 0, 297 45 1, 374 45 0, 420 95 1, 478 156 0, 478 278 1, 478 388 0, 431 449 1, 383 510 0, 192 602 1, 192 666 1, 257 666 1, 257 602 1, 340 602 1, 340 666 1, 405 666 1, 405 602 1
+555 62 -14 492 666;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 176 602 1, 176 666 1, 240 666 1, 240 602 1, 324 602 1, 324 666 1, 389 666 1, 389 602 1
+427 36 -9 412 602;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+427 36 -9 412 602;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 280 481 1, 224 481 1, 104 602 1, 189 602 1
+427 36 -9 412 602;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 61 481 1, 151 602 1, 233 602 1, 323 481 1, 268 481 1, 192 557 1, 192 557 1, 116 481 1
+427 36 -9 412 546;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 85 481 1, 85 546 1, 150 546 1, 150 481 1, 234 481 1, 234 546 1, 298 546 1, 298 481 1
+427 36 -9 412 569;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 67 481 1, 70 516 0, 79 535 1, 96 569 0, 137 569 1, 164 569 0, 187 555 1, 210 541 1, 231 528 0, 242 528 1, 267 528 0, 271 569 1, 317 569 1, 314 534 0, 305 515 1, 288 481 0, 247 481 1, 220 481 0, 197 496 1, 174 510 1, 154 522 0, 142 522 1, 117 522 0, 113 481 1
+427 36 -9 412 651;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 192 651 1, 227 651 0, 252 627 1, 277 602 0, 277 567 1, 277 531 0, 252 506 1, 227 481 0, 191 481 1, 160 481 0, 137 501 1, 107 527 0, 107 566 1, 107 602 0, 132 626 1, 156 651 0, 192 619 1, 170 619 0, 154 603 1, 139 588 0, 139 566 1, 139 545 0, 154 529 1, 170 513 0, 191 513 1, 211 513 0, 226 526 1, 245 542 0, 245 567 1, 245 588 0, 229 603 1, 214 619 0
+384 32 -162 347 416;347 12 1, 279 -9 0, 219 -9 1, 135 -9 0, 84 50 1, 32 109 0, 32 204 1, 32 303 0, 85 360 1, 137 416 0, 231 416 1, 278 416 0, 343 403 1, 343 341 1, 281 360 0, 245 360 1, 116 360 0, 116 204 1, 116 130 0, 149 90 1, 182 50 0, 242 50 1, 287 50 0, 347 76 1, 235 0 1, 271 0 1, 248 -41 1, 275 -42 0, 295 -56 1, 321 -74 0, 321 -101 1, 321 -126 0, 299 -144 1, 277 -162 0, 245 -162 1, 220 -162 0, 191 -154 1, 191 -124 1, 210 -129 0, 230 -129 1, 269 -129 0, 269 -102 1, 269 -67 0, 199 -66 1
+427 32 -9 383 602;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+427 32 -9 383 602;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 280 481 1, 224 481 1, 104 602 1, 189 602 1
+427 32 -9 383 602;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 61 481 1, 151 602 1, 233 602 1, 323 481 1, 268 481 1, 192 557 1, 192 557 1, 116 481 1
+427 32 -9 383 546;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 85 481 1, 85 546 1, 150 546 1, 150 481 1, 234 481 1, 234 546 1, 298 546 1, 298 481 1
+171 40 0 216 602;48 0 1, 48 407 1, 122 407 1, 122 0 1, 40 481 1, 131 602 1, 216 602 1, 96 481 1
+171 -24 0 152 602;48 0 1, 48 407 1, 122 407 1, 122 0 1, 152 481 1, 96 481 1, -24 602 1, 61 602 1
+171 -67 0 195 602;48 0 1, 48 407 1, 122 407 1, 122 0 1, -67 481 1, 23 602 1, 105 602 1, 195 481 1, 140 481 1, 64 557 1, 64 557 1, -12 481 1
+171 -21 0 192 546;48 0 1, 48 407 1, 122 407 1, 122 0 1, -21 481 1, -21 546 1, 44 546 1, 44 481 1, 127 481 1, 127 546 1, 192 546 1, 192 481 1
+427 58 0 374 569;58 0 1, 58 407 1, 132 407 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1, 67 481 1, 70 516 0, 79 535 1, 96 569 0, 137 569 1, 164 569 0, 187 555 1, 210 541 1, 231 528 0, 242 528 1, 267 528 0, 271 569 1, 317 569 1, 314 534 0, 305 515 1, 288 481 0, 247 481 1, 220 481 0, 197 496 1, 174 510 1, 154 522 0, 142 522 1, 117 522 0, 113 481 1
+427 32 -9 395 602;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+427 32 -9 395 602;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 280 481 1, 224 481 1, 104 602 1, 189 602 1
+427 32 -9 395 602;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 61 481 1, 151 602 1, 233 602 1, 323 481 1, 268 481 1, 192 557 1, 192 557 1, 116 481 1
+427 32 -9 395 546;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 85 481 1, 85 546 1, 150 546 1, 150 481 1, 234 481 1, 234 546 1, 298 546 1, 298 481 1
+427 32 -9 395 569;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 67 481 1, 70 516 0, 79 535 1, 96 569 0, 137 569 1, 164 569 0, 187 555 1, 210 541 1, 231 528 0, 242 528 1, 267 528 0, 271 569 1, 317 569 1, 314 534 0, 305 515 1, 288 481 0, 247 481 1, 220 481 0, 197 496 1, 174 510 1, 154 522 0, 142 522 1, 117 522 0, 113 481 1
+427 53 -9 369 602;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+427 53 -9 369 602;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 280 481 1, 224 481 1, 104 602 1, 189 602 1
+427 53 -9 369 602;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 61 481 1, 151 602 1, 233 602 1, 323 481 1, 268 481 1, 192 557 1, 192 557 1, 116 481 1
+427 53 -9 369 546;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 85 481 1, 85 546 1, 150 546 1, 150 481 1, 234 481 1, 234 546 1, 298 546 1, 298 481 1
+427 56 -111 371 555;177 -111 1, 186 315 1, 56 305 1, 56 361 1, 186 352 1, 177 555 1, 251 555 1, 241 352 1, 371 361 1, 371 305 1, 241 315 1, 251 -111 1
+307 43 347 265 569;154 569 1, 199 569 0, 232 536 1, 265 504 0, 265 458 1, 265 412 0, 232 380 1, 199 347 0, 152 347 1, 113 347 0, 82 373 1, 43 408 0, 43 458 1, 43 504 0, 75 536 1, 108 569 0, 154 523 1, 127 523 0, 108 504 1, 89 485 0, 89 458 1, 89 432 0, 108 413 1, 127 393 0, 153 393 1, 177 393 0, 195 409 1, 219 428 0, 219 458 1, 219 485 0, 200 504 1, 180 523 0
+427 65 0 380 555;237 0 1, 237 65 1, 166 74 0, 123 120 1, 65 181 0, 65 278 1, 65 379 0, 124 435 1, 165 475 0, 237 486 1, 237 555 1, 274 555 1, 274 486 1, 324 483 0, 380 468 1, 380 406 1, 314 429 0, 274 432 1, 274 117 1, 325 117 0, 380 143 1, 380 87 1, 324 65 0, 274 65 1, 274 0 1, 237 429 1, 215 426 0, 203 420 1, 146 390 0, 146 277 1, 146 199 0, 180 158 1, 200 135 0, 237 122 1
+427 45 0 362 569;45 0 1, 45 65 1, 124 90 0, 124 183 1, 124 269 1, 57 269 1, 57 324 1, 124 324 1, 124 405 1, 124 485 0, 162 527 1, 200 569 0, 272 569 1, 310 569 0, 357 558 1, 357 495 1, 308 513 0, 269 513 1, 198 513 0, 198 427 1, 198 324 1, 279 324 1, 279 269 1, 198 269 1, 198 221 1, 198 153 0, 180 120 1, 166 92 0, 133 65 1, 362 65 1, 362 0 1
+427 48 -125 379 569;48 -98 1, 48 -30 1, 142 -69 0, 203 -69 1, 250 -69 0, 281 -51 1, 311 -32 0, 311 -1 1, 311 27 0, 288 43 1, 270 56 0, 225 75 1, 159 104 1, 50 150 0, 50 230 1, 50 284 0, 105 342 1, 52 379 0, 52 434 1, 52 494 0, 101 531 1, 149 569 0, 229 569 1, 284 569 0, 358 551 1, 358 491 1, 280 513 0, 228 513 1, 179 513 0, 149 494 1, 119 475 0, 119 445 1, 119 404 0, 185 377 1, 236 357 1, 314 325 0, 343 296 1, 373 266 0, 373 221 1, 373 168 0, 317 104 1, 379 66 0, 379 3 1, 379 -56 0, 329 -90 1, 279 -125 0, 196 -125 1, 138 -125 0, 281 128 1, 308 166 0, 308 200 1, 308 228 0, 290 245 1, 272 263 0, 226 282 1, 143 317 1, 115 282 0, 115 249 1, 115 198 0, 201 162 1
+269 30 208 239 416;135 416 1, 178 416 0, 208 386 1, 239 355 0, 239 312 1, 239 269 0, 208 239 1, 177 208 0, 133 208 1, 96 208 0, 67 233 1, 30 265 0, 30 312 1, 30 356 0, 61 386 1, 92 416 0
+413 33 -111 338 555;190 -111 1, 190 278 1, 122 284 0, 83 316 1, 33 358 0, 33 433 1, 33 499 0, 69 527 1, 105 555 0, 190 555 1, 338 555 1, 338 -111 1, 292 -111 1, 292 509 1, 237 509 1, 237 -111 1
+469 48 -9 437 602;48 0 1, 48 432 1, 48 527 0, 83 564 1, 117 602 0, 206 602 1, 349 602 0, 349 500 1, 349 451 0, 300 399 1, 261 357 0, 261 337 1, 261 312 0, 303 281 1, 372 230 1, 437 182 0, 437 111 1, 437 -9 0, 296 -9 1, 234 -9 0, 183 11 1, 183 76 1, 253 46 0, 296 46 1, 368 46 0, 368 104 1, 368 141 0, 324 174 1, 244 236 1, 195 273 0, 195 315 1, 195 351 0, 238 407 1, 275 455 0, 275 487 1, 275 546 0, 201 546 1, 157 546 0, 140 528 1, 122 509 0, 122 463 1, 122 0 1
+566 6 0 561 555;283 555 1, 398 555 0, 479 474 1, 561 393 0, 561 278 1, 561 162 0, 479 81 1, 398 0 0, 280 0 1, 179 0 0, 104 66 1, 6 152 0, 6 278 1, 6 393 0, 87 474 1, 169 555 0, 283 516 1, 185 516 0, 115 446 1, 45 376 0, 45 278 1, 45 181 0, 115 110 1, 184 40 0, 281 40 1, 370 40 0, 437 96 1, 521 168 0, 521 278 1, 521 376 0, 451 446 1, 381 516 0, 192 126 1, 192 426 1, 286 426 1, 377 426 0, 377 353 1, 377 301 0, 324 266 1, 415 126 1, 359 126 1, 278 252 1, 240 252 1, 240 126 1, 237 289 1, 251 289 1, 330 289 0, 330 347 1, 330 396 0, 264 396 1, 237 396 1
+566 6 0 561 555;283 555 1, 398 555 0, 479 474 1, 561 393 0, 561 278 1, 561 162 0, 479 81 1, 398 0 0, 280 0 1, 179 0 0, 104 66 1, 6 152 0, 6 278 1, 6 393 0, 87 474 1, 169 555 0, 283 516 1, 185 516 0, 115 446 1, 45 376 0, 45 278 1, 45 181 0, 115 110 1, 184 40 0, 281 40 1, 370 40 0, 437 96 1, 521 168 0, 521 278 1, 521 376 0, 451 446 1, 381 516 0, 384 137 1, 333 119 0, 293 119 1, 226 119 0, 183 163 1, 140 207 0, 140 276 1, 140 348 0, 182 391 1, 224 434 0, 295 434 1, 332 434 0, 375 425 1, 384 423 1, 384 379 1, 336 399 0, 298 399 1, 251 399 0, 222 365 1, 193 332 0, 193 277 1, 193 222 0, 223 191 1, 253 159 0, 303 159 1, 343 159 0, 384 181 1
+768 83 278 662 555;176 278 1, 176 509 1, 83 509 1, 83 555 1, 333 555 1, 333 509 1, 240 509 1, 240 278 1, 380 278 1, 380 555 1, 467 555 1, 525 395 1, 582 555 1, 662 555 1, 662 278 1, 597 278 1, 597 479 1, 536 301 1, 491 301 1, 430 463 1, 430 278 1
+256 40 481 216 602;40 481 1, 131 602 1, 216 602 1, 96 481 1
+256 21 481 234 546;21 481 1, 21 546 1, 86 546 1, 86 481 1, 170 481 1, 170 546 1, 234 546 1, 234 481 1
+213 0 0 0 0;
+768 7 0 746 555;224 213 1, 381 213 1, 381 460 1, 7 0 1, 360 555 1, 730 555 1, 730 496 1, 459 496 1, 459 318 1, 693 318 1, 693 260 1, 459 260 1, 459 59 1, 746 59 1, 746 0 1, 381 0 1, 381 155 1, 187 155 1, 89 0 1
+597 35 -14 563 569;39 -14 1, 104 69 1, 74 107 0, 58 146 1, 35 204 0, 35 278 1, 35 410 0, 107 490 1, 179 569 0, 298 569 1, 389 569 0, 459 519 1, 498 569 1, 563 569 1, 496 484 1, 525 446 0, 541 407 1, 563 350 0, 563 277 1, 563 144 0, 491 65 1, 419 -14 0, 299 -14 1, 211 -14 0, 142 34 1, 104 -14 1, 184 88 1, 233 45 0, 299 45 1, 384 45 0, 431 106 1, 479 167 0, 479 276 1, 479 363 0, 448 423 1, 416 465 1, 366 510 0, 299 510 1, 214 510 0, 167 449 1, 119 388 0, 119 279 1, 119 190 0, 152 129 1
+213 0 0 0 0;
+449 39 0 409 444;196 111 1, 196 250 1, 39 250 1, 39 305 1, 196 305 1, 196 444 1, 252 444 1, 252 305 1, 409 305 1, 409 250 1, 252 250 1, 252 111 1, 39 0 1, 39 56 1, 409 56 1, 409 0 1
+213 0 0 0 0;
+213 0 0 0 0;
+427 9 0 404 555;170 0 1, 170 129 1, 59 129 1, 59 176 1, 170 176 1, 170 231 1, 59 231 1, 59 278 1, 170 278 1, 9 555 1, 95 555 1, 216 346 1, 216 346 1, 338 555 1, 404 555 1, 244 278 1, 355 278 1, 355 231 1, 244 231 1, 244 176 1, 355 176 1, 355 129 1, 244 129 1, 244 0 1
+427 53 -148 369 407;53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 295 0 1, 295 76 1, 236 -7 0, 176 -7 1, 152 -7 0, 127 9 1, 127 -148 1, 53 -148 1
+213 0 0 0 0;
+213 0 0 0 0;
+213 0 0 0 0;
+213 0 0 0 0;
+213 0 0 0 0;
+284 32 308 267 569;182 343 1, 144 308 0, 105 308 1, 74 308 0, 53 328 1, 32 348 0, 32 378 1, 32 464 0, 161 464 1, 179 464 1, 179 490 1, 179 531 0, 133 531 1, 97 531 0, 54 509 1, 54 551 1, 102 569 0, 144 569 1, 234 569 0, 234 492 1, 234 380 1, 234 345 0, 255 346 1, 257 346 1, 258 346 0, 261 346 1, 263 346 0, 265 347 1, 267 315 1, 248 308 0, 231 308 1, 194 308 0, 184 343 1, 179 374 1, 179 431 1, 164 431 1, 88 431 0, 88 385 1, 88 350 0, 124 350 1, 150 350 0
+281 28 308 252 569;140 569 1, 192 569 0, 222 534 1, 252 499 0, 252 439 1, 252 378 0, 222 343 1, 192 308 0, 139 308 1, 93 308 0, 64 337 1, 28 373 0, 28 439 1, 28 499 0, 58 534 1, 89 569 0, 140 531 1, 87 531 0, 87 439 1, 87 347 0, 140 347 1, 194 347 0, 194 440 1, 194 531 0
+213 0 0 0 0;
+683 36 -9 638 416;288 92 1, 288 197 1, 260 198 1, 235 199 0, 207 195 1, 110 181 0, 110 114 1, 110 51 0, 184 51 1, 236 51 0, 344 369 1, 400 416 0, 472 416 1, 638 416 0, 638 215 1, 638 192 1, 360 192 1, 365 148 0, 375 125 1, 408 47 0, 512 47 1, 568 47 0, 636 72 1, 636 13 1, 559 -9 0, 494 -9 1, 423 -9 0, 374 23 1, 347 41 0, 322 77 1, 279 31 0, 248 12 1, 211 -9 0, 160 -9 1, 104 -9 0, 70 21 1, 36 53 0, 36 102 1, 36 241 0, 270 241 1, 288 241 1, 288 290 1, 288 329 0, 269 345 1, 251 361 0, 205 361 1, 141 361 0, 71 325 1, 71 386 1, 148 416 0, 218 416 1, 303 416 0, 364 248 1, 564 248 1, 563 284 0, 556 302 1, 536 361 0, 469 361 1, 422 361 0, 396 333 1, 371 308 0
+469 54 -9 416 416;131 22 1, 108 -9 1, 54 -9 1, 99 53 1, 54 116 0, 54 204 1, 54 303 0, 102 360 1, 151 416 0, 236 416 1, 296 416 0, 339 385 1, 362 416 1, 416 416 1, 371 354 1, 416 291 0, 416 203 1, 416 105 0, 367 48 1, 319 -9 0, 234 -9 1, 174 -9 0, 169 75 1, 170 75 1, 185 59 0, 198 53 1, 215 46 0, 234 46 1, 336 46 0, 336 204 1, 336 251 0, 325 291 1, 301 332 1, 300 333 1, 272 361 0, 235 361 1, 134 361 0, 134 205 1, 134 152 0, 145 116 1
+469 69 -162 398 407;309 407 1, 309 333 1, 235 333 1, 235 407 1, 309 259 1, 309 239 1, 309 147 0, 248 99 1, 214 73 1, 148 22 0, 148 -33 1, 148 -107 0, 251 -107 1, 314 -107 0, 398 -78 1, 398 -141 1, 316 -162 0, 246 -162 1, 169 -162 0, 125 -137 1, 69 -105 0, 69 -34 1, 69 36 0, 141 81 1, 171 99 1, 209 122 0, 222 147 1, 235 171 0, 235 218 1, 235 259 1
+256 91 -148 165 407;165 407 1, 165 333 1, 91 333 1, 91 407 1, 156 259 1, 165 -37 1, 165 -148 1, 91 -148 1, 91 -37 1, 100 259 1
+449 32 111 402 333;32 278 1, 32 333 1, 402 333 1, 402 111 1, 347 111 1, 347 278 1
+213 0 0 0 0;
+427 18 -111 384 569;18 -111 1, 94 269 1, 32 269 1, 32 324 1, 105 324 1, 113 363 1, 154 569 0, 300 569 1, 339 569 0, 384 558 1, 373 500 1, 332 514 0, 299 514 1, 218 514 0, 195 398 1, 180 324 1, 251 324 1, 251 269 1, 169 269 1, 94 -111 1
+213 0 0 0 0;
+213 0 0 0 0;
+427 43 37 376 370;376 342 1, 265 204 1, 376 65 1, 339 37 1, 191 204 1, 339 370 1, 228 342 1, 117 204 1, 228 65 1, 191 37 1, 43 204 1, 191 370 1
+427 51 37 384 370;51 65 1, 162 204 1, 51 342 1, 88 370 1, 236 204 1, 88 37 1, 199 65 1, 310 204 1, 199 342 1, 236 370 1, 384 204 1, 236 37 1
+768 93 0 676 74;93 0 1, 93 74 1, 167 74 1, 167 0 1, 347 0 1, 347 74 1, 421 74 1, 421 0 1, 602 0 1, 602 74 1, 676 74 1, 676 0 1
+427 0 0 0 0;
+512 7 0 503 722;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1, 312 602 1, 257 602 1, 137 722 1, 222 722 1
+512 7 0 503 689;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1, 132 602 1, 135 636 0, 144 656 1, 161 689 0, 202 689 1, 229 689 0, 252 675 1, 275 661 1, 296 648 0, 307 648 1, 332 648 0, 336 689 1, 382 689 1, 379 654 0, 370 635 1, 353 602 0, 312 602 1, 285 602 0, 262 616 1, 239 630 1, 219 643 0, 207 643 1, 182 643 0, 178 602 1
+597 35 -14 563 689;299 569 1, 418 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 418 -14 0, 295 -14 1, 189 -14 0, 120 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 213 510 0, 166 449 1, 119 388 0, 119 278 1, 119 169 0, 166 107 1, 213 45 0, 297 45 1, 374 45 0, 420 95 1, 478 156 0, 478 278 1, 478 388 0, 431 449 1, 383 510 0, 174 602 1, 176 636 0, 186 656 1, 203 689 0, 244 689 1, 271 689 0, 294 675 1, 316 661 1, 338 648 0, 349 648 1, 373 648 0, 377 689 1, 423 689 1, 421 654 0, 411 635 1, 395 602 0, 354 602 1, 327 602 0, 303 616 1, 281 630 1, 260 643 0, 248 643 1, 224 643 0, 220 602 1
+768 35 -14 747 569;423 0 1, 423 22 1, 362 -14 0, 291 -14 1, 176 -14 0, 105 66 1, 35 147 0, 35 278 1, 35 411 0, 106 490 1, 177 569 0, 294 569 1, 363 569 0, 423 534 1, 423 555 1, 730 555 1, 730 496 1, 502 496 1, 502 318 1, 693 318 1, 693 260 1, 502 260 1, 502 59 1, 747 59 1, 747 0 1, 423 213 1, 423 342 1, 423 430 0, 393 470 1, 363 510 0, 296 510 1, 212 510 0, 165 449 1, 119 388 0, 119 278 1, 119 167 0, 165 106 1, 213 45 0, 296 45 1, 423 45 0
+725 32 -9 680 416;371 341 1, 395 375 0, 422 392 1, 461 416 0, 516 416 1, 612 416 0, 650 348 1, 678 297 0, 680 192 1, 412 192 1, 419 120 0, 447 87 1, 481 46 0, 560 46 1, 618 46 0, 680 73 1, 680 14 1, 608 -9 0, 542 -9 1, 474 -9 0, 434 12 1, 404 29 0, 373 65 1, 350 32 0, 323 15 1, 283 -9 0, 227 -9 1, 138 -9 0, 85 48 1, 32 106 0, 32 204 1, 32 302 0, 86 359 1, 138 416 0, 228 416 1, 287 416 0, 327 388 1, 350 372 0, 228 361 1, 111 361 0, 111 205 1, 111 137 0, 134 98 1, 163 46 0, 229 46 1, 337 46 0, 337 204 1, 337 276 0, 314 315 1, 288 361 0, 414 243 1, 601 243 1, 600 291 0, 588 317 1, 567 361 0, 514 361 1, 462 361 0, 437 321 1, 420 295 0
+427 38 204 390 250;38 204 1, 38 250 1, 390 250 1, 390 204 1
+768 37 204 731 241;37 204 1, 37 241 1, 731 241 1, 731 204 1
+256 21 398 225 592;225 592 1, 225 564 1, 198 551 0, 198 480 1, 198 472 1, 225 472 1, 225 398 1, 151 398 1, 151 460 1, 151 573 0, 95 592 1, 95 564 1, 69 551 0, 69 480 1, 69 472 1, 95 472 1, 95 398 1, 21 398 1, 21 460 1, 22 573 0
+256 31 398 234 592;31 398 1, 31 426 1, 57 440 0, 57 510 1, 57 518 1, 31 518 1, 31 592 1, 105 592 1, 105 530 1, 104 417 0, 160 398 1, 160 426 1, 187 440 0, 187 510 1, 187 518 1, 160 518 1, 160 592 1, 234 592 1, 234 530 1, 234 417 0
+171 35 380 127 592;127 592 1, 127 564 1, 91 554 0, 91 480 1, 91 472 1, 127 472 1, 127 380 1, 35 380 1, 35 460 1, 35 582 0
+171 44 380 136 592;44 380 1, 44 407 1, 80 417 0, 80 492 1, 80 500 1, 44 500 1, 44 592 1, 136 592 1, 136 512 1, 136 389 0
+449 39 0 409 444;39 194 1, 39 250 1, 409 250 1, 409 194 1, 178 352 1, 178 444 1, 270 444 1, 270 352 1, 178 0 1, 178 93 1, 270 93 1, 270 0 1
+213 0 0 0 0;
+384 7 -148 380 546;152 0 1, 7 407 1, 82 407 1, 193 95 1, 314 407 1, 380 407 1, 164 -148 1, 87 -148 1, 85 481 1, 85 546 1, 150 546 1, 150 481 1, 234 481 1, 234 546 1, 298 546 1, 298 481 1
+512 11 0 501 666;210 0 1, 210 231 1, 11 555 1, 101 555 1, 259 298 1, 428 555 1, 501 555 1, 289 233 1, 289 0 1, 158 602 1, 158 666 1, 223 666 1, 223 602 1, 306 602 1, 306 666 1, 371 666 1, 371 602 1
+128 -165 -14 293 569;-165 -14 1, 243 569 1, 293 569 1, -114 -14 1
+427 46 110 381 446;137 168 1, 78 110 1, 46 143 1, 104 201 1, 80 240 0, 80 278 1, 80 315 0, 104 354 1, 46 413 1, 78 446 1, 137 387 1, 174 411 0, 213 411 1, 253 411 0, 290 387 1, 348 446 1, 381 413 1, 323 354 1, 347 315 0, 347 278 1, 347 240 0, 323 201 1, 381 143 1, 348 110 1, 290 168 1, 253 144 0, 213 144 1, 174 144 0, 213 365 1, 177 365 0, 152 339 1, 126 314 0, 126 277 1, 126 241 0, 152 216 1, 176 191 0, 212 191 1, 246 191 0, 270 211 1, 300 237 0, 300 278 1, 300 314 0, 275 339 1, 250 365 0
+256 28 37 213 370;213 342 1, 102 204 1, 213 65 1, 176 37 1, 28 204 1, 176 370 1
+256 43 37 228 370;43 65 1, 154 204 1, 43 342 1, 80 370 1, 228 204 1, 80 37 1
+384 12 0 336 602;66 0 1, 66 352 1, 12 352 1, 12 407 1, 66 407 1, 66 456 1, 66 602 0, 181 602 1, 206 602 0, 236 592 1, 236 533 1, 209 546 0, 189 546 1, 162 546 0, 151 528 1, 140 510 0, 140 464 1, 140 407 1, 336 407 1, 336 0 1, 262 0 1, 262 352 1, 140 352 1, 140 0 1, 262 481 1, 262 555 1, 336 555 1, 336 481 1
+384 12 0 336 602;66 0 1, 66 352 1, 12 352 1, 12 407 1, 66 407 1, 66 456 1, 66 602 0, 179 602 1, 262 592 1, 336 592 1, 336 0 1, 262 0 1, 262 537 1, 246 540 1, 214 546 0, 192 546 1, 159 546 0, 148 524 1, 140 505 0, 140 464 1, 140 407 1, 206 407 1, 206 352 1, 140 352 1, 140 0 1
+427 56 -111 371 555;177 -111 1, 186 93 1, 56 83 1, 56 139 1, 186 129 1, 186 315 1, 56 305 1, 56 361 1, 186 352 1, 177 555 1, 251 555 1, 241 352 1, 371 361 1, 371 305 1, 241 315 1, 241 129 1, 371 139 1, 371 83 1, 241 93 1, 251 -111 1
+213 60 184 153 277;60 184 1, 60 277 1, 153 277 1, 153 184 1
+171 39 -111 132 93;39 -111 1, 39 -83 1, 75 -73 0, 75 -8 1, 75 0 1, 39 0 1, 39 93 1, 132 93 1, 132 12 1, 131 -101 0
+256 26 -120 230 74;26 -120 1, 26 -93 1, 53 -79 0, 53 -9 1, 53 0 1, 26 0 1, 26 74 1, 100 74 1, 100 12 1, 100 -102 0, 156 -120 1, 156 -93 1, 182 -78 0, 182 -9 1, 182 0 1, 156 0 1, 156 74 1, 230 74 1, 230 12 1, 230 -102 0
+768 9 -14 759 569;128 555 1, 181 555 0, 213 518 1, 245 480 0, 245 417 1, 245 352 0, 213 315 1, 182 278 0, 126 278 1, 78 278 0, 48 308 1, 9 347 0, 9 416 1, 9 480 0, 41 518 1, 74 555 0, 127 518 1, 65 518 0, 65 417 1, 65 315 0, 128 315 1, 190 315 0, 190 416 1, 190 463 0, 173 491 1, 156 518 0, 377 278 1, 431 278 0, 463 240 1, 495 203 0, 495 139 1, 495 74 0, 463 37 1, 431 0 0, 376 0 1, 328 0 0, 297 30 1, 259 69 0, 259 139 1, 259 203 0, 291 240 1, 323 278 0, 377 241 1, 315 241 0, 315 139 1, 315 37 0, 377 37 1, 440 37 0, 440 138 1, 440 186 0, 423 213 1, 405 241 0, 641 278 1, 695 278 0, 727 240 1, 759 203 0, 759 140 1, 759 74 0, 727 37 1, 695 0 0, 640 0 1, 592 0 0, 561 31 1, 523 69 0, 523 139 1, 523 203 0, 555 240 1, 587 278 0, 640 241 1, 578 241 0, 578 139 1, 578 37 0, 641 37 1, 704 37 0, 704 139 1, 704 186 0, 686 213 1, 669 241 0, 23 -14 1, 431 569 1, 482 569 1, 74 -14 1
+512 7 0 503 722;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1, 126 602 1, 216 722 1, 298 722 1, 388 602 1, 333 602 1, 257 677 1, 257 677 1, 181 602 1
+512 72 0 491 722;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 150 602 1, 240 722 1, 322 722 1, 412 602 1, 357 602 1, 281 677 1, 281 677 1, 205 602 1
+512 7 0 503 722;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1, 201 602 1, 292 722 1, 377 722 1, 257 602 1
+512 72 0 491 666;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 169 602 1, 169 666 1, 234 666 1, 234 602 1, 317 602 1, 317 666 1, 382 666 1, 382 602 1
+512 72 0 491 722;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 335 602 1, 280 602 1, 159 722 1, 245 722 1
+213 51 0 227 722;68 0 1, 68 555 1, 146 555 1, 146 0 1, 51 602 1, 142 722 1, 227 722 1, 107 602 1
+213 -24 0 238 722;68 0 1, 68 555 1, 146 555 1, 146 0 1, -24 602 1, 66 722 1, 148 722 1, 238 602 1, 183 602 1, 107 677 1, 107 677 1, 31 602 1
+213 0 0 213 666;68 0 1, 68 555 1, 146 555 1, 146 0 1, 0 602 1, 0 666 1, 65 666 1, 65 602 1, 149 602 1, 149 666 1, 213 666 1, 213 602 1
+213 -14 0 162 722;68 0 1, 68 555 1, 146 555 1, 146 0 1, 162 602 1, 107 602 1, -14 722 1, 72 722 1
+597 35 -14 563 722;299 569 1, 418 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 418 -14 0, 295 -14 1, 189 -14 0, 120 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 213 510 0, 166 449 1, 119 388 0, 119 278 1, 119 169 0, 166 107 1, 213 45 0, 297 45 1, 374 45 0, 420 95 1, 478 156 0, 478 278 1, 478 388 0, 431 449 1, 383 510 0, 243 602 1, 333 722 1, 419 722 1, 299 602 1
+597 35 -14 563 722;299 569 1, 418 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 418 -14 0, 295 -14 1, 189 -14 0, 120 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 213 510 0, 166 449 1, 119 388 0, 119 278 1, 119 169 0, 166 107 1, 213 45 0, 297 45 1, 374 45 0, 420 95 1, 478 156 0, 478 278 1, 478 388 0, 431 449 1, 383 510 0, 167 602 1, 258 722 1, 339 722 1, 430 602 1, 374 602 1, 299 677 1, 298 677 1, 223 602 1
+427 0 -14 405 568;141 201 1, 156 141 0, 178 108 1, 218 48 0, 290 48 1, 337 48 0, 405 75 1, 405 10 1, 332 -14 0, 281 -14 1, 194 -14 0, 140 38 1, 101 74 0, 82 134 1, 75 156 0, 66 201 1, 0 201 1, 19 248 1, 61 248 1, 60 276 1, 60 277 0, 60 284 1, 61 300 0, 62 321 1, 0 321 1, 19 368 1, 69 368 1, 84 430 0, 102 462 1, 161 568 0, 293 568 1, 341 568 0, 405 552 1, 405 483 1, 342 510 0, 294 510 1, 228 510 0, 188 462 1, 166 434 0, 154 400 1, 149 386 0, 144 368 1, 356 368 1, 337 321 1, 136 321 1, 134 294 0, 134 276 1, 135 248 1, 307 248 1, 288 201 1
+597 35 -14 563 722;299 569 1, 418 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 418 -14 0, 295 -14 1, 189 -14 0, 120 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 213 510 0, 166 449 1, 119 388 0, 119 278 1, 119 169 0, 166 107 1, 213 45 0, 297 45 1, 374 45 0, 420 95 1, 478 156 0, 478 278 1, 478 388 0, 431 449 1, 383 510 0, 354 602 1, 299 602 1, 178 722 1, 264 722 1
+555 62 -14 492 722;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 227 602 1, 317 722 1, 402 722 1, 282 602 1
+555 62 -14 492 722;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 151 602 1, 241 722 1, 323 722 1, 413 602 1, 358 602 1, 282 677 1, 282 677 1, 206 602 1
+555 62 -14 492 722;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 338 602 1, 282 602 1, 162 722 1, 247 722 1
+171 48 0 122 407;48 0 1, 48 407 1, 122 407 1, 122 0 1
+256 -3 481 259 602;-3 481 1, 87 602 1, 169 602 1, 259 481 1, 204 481 1, 128 557 1, 128 557 1, 52 481 1
+256 3 481 253 569;3 481 1, 6 516 0, 15 535 1, 32 569 0, 73 569 1, 100 569 0, 123 555 1, 146 541 1, 167 528 0, 178 528 1, 203 528 0, 207 569 1, 253 569 1, 250 534 0, 241 515 1, 224 481 0, 183 481 1, 156 481 0, 133 496 1, 110 510 1, 90 522 0, 78 522 1, 53 522 0, 49 481 1
+256 8 481 248 537;8 481 1, 8 537 1, 248 537 1, 248 481 1
+256 3 481 253 602;3 602 1, 49 602 1, 57 566 0, 77 551 1, 97 537 0, 128 537 1, 163 537 0, 183 555 1, 200 570 0, 207 602 1, 253 602 1, 247 551 0, 219 521 1, 184 481 0, 128 481 1, 69 481 0, 33 524 1, 9 554 0
+256 91 481 165 555;91 481 1, 91 555 1, 165 555 1, 165 481 1
+256 43 481 213 651;128 651 1, 163 651 0, 188 627 1, 213 602 0, 213 567 1, 213 531 0, 188 506 1, 163 481 0, 127 481 1, 96 481 0, 73 501 1, 43 527 0, 43 566 1, 43 602 0, 68 626 1, 92 651 0, 128 619 1, 106 619 0, 90 603 1, 75 588 0, 75 566 1, 75 545 0, 90 529 1, 106 513 0, 127 513 1, 147 513 0, 162 526 1, 181 542 0, 181 567 1, 181 588 0, 165 603 1, 150 619 0
+256 63 -162 193 0;107 0 1, 143 0 1, 120 -41 1, 147 -42 0, 167 -56 1, 193 -74 0, 193 -101 1, 193 -126 0, 171 -144 1, 149 -162 0, 117 -162 1, 92 -162 0, 63 -154 1, 63 -124 1, 82 -129 0, 102 -129 1, 141 -129 0, 141 -102 1, 141 -67 0, 71 -66 1
+256 -19 481 275 602;-19 481 1, 71 602 1, 143 602 1, 23 481 1, 113 481 1, 203 602 1, 275 602 1, 155 481 1
+256 64 -139 192 0;123 0 1, 163 0 1, 115 -30 0, 115 -67 1, 115 -103 0, 158 -103 1, 178 -103 0, 192 -98 1, 192 -128 1, 169 -139 0, 140 -139 1, 64 -139 0, 64 -80 1, 64 -34 0
+256 -3 481 259 602;259 602 1, 169 481 1, 87 481 1, -3 602 1, 52 602 1, 128 526 1, 128 526 1, 204 602 1
+427 0 -14 405 568;141 201 1, 156 141 0, 178 108 1, 218 48 0, 290 48 1, 337 48 0, 405 75 1, 405 10 1, 332 -14 0, 281 -14 1, 194 -14 0, 140 38 1, 101 74 0, 82 134 1, 75 156 0, 66 201 1, 0 201 1, 19 248 1, 61 248 1, 60 276 1, 60 277 0, 60 284 1, 61 300 0, 62 321 1, 0 321 1, 19 368 1, 69 368 1, 84 430 0, 102 462 1, 161 568 0, 293 568 1, 341 568 0, 405 552 1, 405 483 1, 342 510 0, 294 510 1, 228 510 0, 188 462 1, 166 434 0, 154 400 1, 149 386 0, 144 368 1, 356 368 1, 337 321 1, 136 321 1, 134 294 0, 134 276 1, 135 248 1, 307 248 1, 288 201 1
+213 0 0 0 0;
+200 72 -111 128 592;72 -111 1, 72 167 1, 128 167 1, 128 -111 1, 72 315 1, 72 592 1, 128 592 1, 128 315 1
+256 33 194 223 250;33 194 1, 33 250 1, 223 250 1, 223 194 1
+427 37 546 390 602;37 546 1, 37 602 1, 390 602 1, 390 546 1
+256 28 222 240 564;28 222 1, 28 268 1, 53 312 0, 96 350 1, 122 373 1, 181 425 0, 181 471 1, 181 525 0, 120 525 1, 85 525 0, 36 500 1, 36 543 1, 85 564 0, 130 564 1, 179 564 0, 210 538 1, 240 513 0, 240 473 1, 240 420 0, 171 363 1, 151 346 1, 101 305 0, 92 268 1, 238 268 1, 238 222 1
+256 28 214 234 564;32 507 1, 32 549 1, 75 564 0, 117 564 1, 223 564 0, 223 486 1, 223 450 0, 197 426 1, 182 413 0, 151 402 1, 199 389 0, 218 364 1, 234 343 0, 234 312 1, 234 267 0, 201 240 1, 169 214 0, 112 214 1, 74 214 0, 28 225 1, 28 270 1, 78 251 0, 108 251 1, 175 251 0, 175 312 1, 175 381 0, 78 381 1, 59 381 1, 59 416 1, 75 416 1, 167 416 0, 167 478 1, 167 526 0, 108 526 1, 74 526 0
+213 60 184 153 277;60 184 1, 60 277 1, 153 277 1, 153 184 1
+256 46 222 176 564;120 222 1, 120 507 1, 46 488 1, 46 531 1, 176 564 1, 176 222 1
+641 44 -14 594 569;117 222 1, 117 507 1, 44 488 1, 44 531 1, 173 564 1, 173 222 1, 497 0 1, 497 91 1, 344 91 1, 344 133 1, 495 333 1, 548 333 1, 548 135 1, 594 135 1, 594 91 1, 548 91 1, 548 0 1, 393 135 1, 497 135 1, 497 271 1, 72 -14 1, 480 569 1, 530 569 1, 122 -14 1
+641 44 -14 594 569;382 0 1, 382 46 1, 406 88 0, 450 128 1, 477 151 1, 535 203 0, 535 249 1, 535 303 0, 475 303 1, 440 303 0, 390 278 1, 390 321 1, 440 341 0, 485 341 1, 534 341 0, 564 316 1, 594 291 0, 594 250 1, 594 196 0, 525 140 1, 505 124 1, 455 83 0, 447 46 1, 593 46 1, 593 0 1, 53 -14 1, 461 569 1, 512 569 1, 104 -14 1, 117 222 1, 117 507 1, 44 488 1, 44 531 1, 173 564 1, 173 222 1
+641 42 -14 599 569;46 507 1, 46 549 1, 89 564 0, 131 564 1, 237 564 0, 237 486 1, 237 450 0, 211 426 1, 195 413 0, 165 402 1, 213 389 0, 232 364 1, 248 343 0, 248 312 1, 248 267 0, 215 240 1, 183 214 0, 126 214 1, 87 214 0, 42 225 1, 42 270 1, 92 251 0, 122 251 1, 189 251 0, 189 312 1, 189 381 0, 92 381 1, 72 381 1, 72 416 1, 89 416 1, 180 416 0, 180 478 1, 180 526 0, 122 526 1, 88 526 0, 502 0 1, 502 91 1, 349 91 1, 349 133 1, 500 333 1, 552 333 1, 552 135 1, 599 135 1, 599 91 1, 552 91 1, 552 0 1, 398 135 1, 502 135 1, 502 271 1, 107 -14 1, 515 569 1, 565 569 1, 157 -14 1
+555 2 0 520 555;62 0 1, 62 255 1, 2 255 1, 2 314 1, 62 314 1, 62 555 1, 240 555 1, 520 555 0, 520 290 1, 520 152 0, 447 76 1, 374 0 0, 241 0 1, 141 59 1, 235 59 1, 435 59 0, 435 281 1, 435 412 0, 356 466 1, 333 482 0, 301 488 1, 263 496 0, 199 496 1, 141 496 1, 141 314 1, 266 314 1, 266 255 1, 141 255 1
+449 44 42 404 402;44 81 1, 185 222 1, 44 363 1, 84 402 1, 224 261 1, 365 402 1, 404 363 1, 264 222 1, 404 81 1, 365 42 1, 224 183 1, 84 42 1
+512 11 0 501 722;210 0 1, 210 231 1, 11 555 1, 101 555 1, 259 298 1, 428 555 1, 501 555 1, 289 233 1, 289 0 1, 204 602 1, 294 722 1, 380 722 1, 259 602 1
+512 63 0 494 555;63 0 1, 63 555 1, 141 555 1, 141 450 1, 280 450 1, 366 450 0, 403 440 1, 441 431 0, 465 402 1, 494 366 0, 494 304 1, 494 116 0, 257 116 1, 141 116 1, 141 0 1, 141 175 1, 254 175 1, 411 175 0, 411 299 1, 411 359 0, 370 376 1, 335 391 0, 255 391 1, 141 391 1
+427 32 -9 395 629;47 538 1, 47 594 1, 122 594 0, 183 565 1, 241 629 1, 270 596 1, 222 542 1, 269 506 0, 294 478 1, 395 366 0, 395 206 1, 395 105 0, 347 48 1, 299 -9 0, 216 -9 1, 132 -9 0, 82 48 1, 32 105 0, 32 201 1, 32 297 0, 81 352 1, 129 407 0, 214 407 1, 234 407 0, 259 402 1, 230 456 0, 177 494 1, 122 432 1, 92 465 1, 140 518 1, 102 538 0, 212 352 1, 165 352 0, 138 312 1, 111 272 0, 111 199 1, 111 46 0, 214 46 1, 316 46 0, 316 199 1, 316 352 0
+384 7 -148 380 602;152 0 1, 7 407 1, 82 407 1, 193 95 1, 314 407 1, 380 407 1, 164 -148 1, 87 -148 1, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+427 58 -148 395 592;132 -148 1, 58 -148 1, 58 592 1, 132 592 1, 132 331 1, 153 369 0, 176 389 1, 209 416 0, 254 416 1, 317 416 0, 356 361 1, 395 306 0, 395 215 1, 395 108 0, 344 49 1, 294 -9 0, 203 -9 1, 168 -9 0, 132 0 1, 132 264 1, 132 56 1, 183 46 0, 209 46 1, 315 46 0, 315 207 1, 315 275 0, 294 313 1, 273 352 0, 238 352 1, 191 352 0
+514 8 0 504 657;8 0 1, 219 555 1, 297 555 1, 504 0 1, 419 0 1, 362 154 1, 139 154 1, 81 0 1, 161 212 1, 340 212 1, 251 450 1, 137 602 1, 137 657 1, 378 657 1, 378 602 1
+432 36 -9 412 537;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 72 481 1, 72 537 1, 312 537 1, 312 481 1
+514 8 0 504 722;8 0 1, 219 555 1, 297 555 1, 504 0 1, 419 0 1, 362 154 1, 139 154 1, 81 0 1, 161 212 1, 340 212 1, 251 450 1, 133 722 1, 179 722 1, 187 687 0, 207 672 1, 227 657 0, 258 657 1, 293 657 0, 313 675 1, 329 690 0, 336 722 1, 383 722 1, 377 672 0, 349 641 1, 314 602 0, 258 602 1, 199 602 0, 163 645 1, 139 674 0
+432 36 -9 412 602;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 67 602 1, 113 602 1, 121 566 0, 141 551 1, 161 537 0, 192 537 1, 227 537 0, 247 555 1, 264 570 0, 271 602 1, 317 602 1, 311 551 0, 283 521 1, 248 481 0, 192 481 1, 133 481 0, 97 524 1, 73 554 0
+512 7 -139 503 555;7 0 1, 218 555 1, 296 555 1, 503 0 1, 419 0 1, 361 154 1, 138 154 1, 80 0 1, 161 212 1, 339 212 1, 250 450 1, 419 0 1, 459 0 1, 411 -30 0, 411 -67 1, 411 -103 0, 454 -103 1, 474 -103 0, 488 -98 1, 488 -128 1, 464 -139 0, 435 -139 1, 359 -139 0, 359 -80 1, 359 -34 0
+427 36 -139 412 416;290 52 1, 221 -9 0, 155 -9 1, 102 -9 0, 69 22 1, 36 53 0, 36 102 1, 36 241 0, 262 241 1, 279 241 1, 279 290 1, 279 361 0, 201 361 1, 140 361 0, 71 325 1, 71 386 1, 148 416 0, 215 416 1, 287 416 0, 320 386 1, 353 356 0, 353 290 1, 353 105 1, 353 42 0, 392 42 1, 398 42 0, 407 44 1, 412 3 1, 384 -9 0, 357 -9 1, 332 -9 0, 315 5 1, 299 19 0, 279 92 1, 279 197 1, 255 198 1, 233 199 0, 205 195 1, 112 182 0, 112 114 1, 112 51 0, 180 51 1, 227 51 0, 315 0 1, 355 0 1, 307 -30 0, 307 -67 1, 307 -103 0, 350 -103 1, 370 -103 0, 384 -98 1, 384 -128 1, 361 -139 0, 332 -139 1, 256 -139 0, 256 -80 1, 256 -34 0
+555 44 -14 507 722;507 29 1, 421 -14 0, 323 -14 1, 186 -14 0, 115 60 1, 44 135 0, 44 277 1, 44 419 0, 116 494 1, 189 569 0, 327 569 1, 404 569 0, 506 545 1, 506 471 1, 390 510 0, 323 510 1, 228 510 0, 178 450 1, 128 390 0, 128 278 1, 128 167 0, 182 108 1, 235 48 0, 332 48 1, 414 48 0, 507 96 1, 264 602 1, 355 722 1, 440 722 1, 320 602 1
+384 32 -9 347 602;347 12 1, 279 -9 0, 219 -9 1, 135 -9 0, 84 50 1, 32 109 0, 32 204 1, 32 303 0, 85 360 1, 137 416 0, 231 416 1, 278 416 0, 343 403 1, 343 341 1, 281 360 0, 245 360 1, 116 360 0, 116 204 1, 116 130 0, 149 90 1, 182 50 0, 242 50 1, 287 50 0, 347 76 1, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+555 44 -14 507 722;507 29 1, 421 -14 0, 323 -14 1, 186 -14 0, 115 60 1, 44 135 0, 44 277 1, 44 419 0, 116 494 1, 189 569 0, 327 569 1, 404 569 0, 506 545 1, 506 471 1, 390 510 0, 323 510 1, 228 510 0, 178 450 1, 128 390 0, 128 278 1, 128 167 0, 182 108 1, 235 48 0, 332 48 1, 414 48 0, 507 96 1, 189 602 1, 279 722 1, 361 722 1, 451 602 1, 396 602 1, 320 677 1, 320 677 1, 244 602 1
+384 32 -9 359 602;347 12 1, 279 -9 0, 219 -9 1, 135 -9 0, 84 50 1, 32 109 0, 32 204 1, 32 303 0, 85 360 1, 137 416 0, 231 416 1, 278 416 0, 343 403 1, 343 341 1, 281 360 0, 245 360 1, 116 360 0, 116 204 1, 116 130 0, 149 90 1, 182 50 0, 242 50 1, 287 50 0, 347 76 1, 96 481 1, 187 602 1, 269 602 1, 359 481 1, 303 481 1, 228 557 1, 227 557 1, 152 481 1
+555 44 -14 507 675;507 29 1, 421 -14 0, 323 -14 1, 186 -14 0, 115 60 1, 44 135 0, 44 277 1, 44 419 0, 116 494 1, 189 569 0, 327 569 1, 404 569 0, 506 545 1, 506 471 1, 390 510 0, 323 510 1, 228 510 0, 178 450 1, 128 390 0, 128 278 1, 128 167 0, 182 108 1, 235 48 0, 332 48 1, 414 48 0, 507 96 1, 283 602 1, 283 675 1, 357 675 1, 357 602 1
+384 32 -9 347 555;347 12 1, 279 -9 0, 219 -9 1, 135 -9 0, 84 50 1, 32 109 0, 32 204 1, 32 303 0, 85 360 1, 137 416 0, 231 416 1, 278 416 0, 343 403 1, 343 341 1, 281 360 0, 245 360 1, 116 360 0, 116 204 1, 116 130 0, 149 90 1, 182 50 0, 242 50 1, 287 50 0, 347 76 1, 191 481 1, 191 555 1, 264 555 1, 264 481 1
+555 44 -14 507 722;507 29 1, 421 -14 0, 323 -14 1, 186 -14 0, 115 60 1, 44 135 0, 44 277 1, 44 419 0, 116 494 1, 189 569 0, 327 569 1, 404 569 0, 506 545 1, 506 471 1, 390 510 0, 323 510 1, 228 510 0, 178 450 1, 128 390 0, 128 278 1, 128 167 0, 182 108 1, 235 48 0, 332 48 1, 414 48 0, 507 96 1, 451 722 1, 361 602 1, 279 602 1, 189 722 1, 244 722 1, 320 646 1, 320 646 1, 396 722 1
+384 32 -9 387 602;347 12 1, 279 -9 0, 219 -9 1, 135 -9 0, 84 50 1, 32 109 0, 32 204 1, 32 303 0, 85 360 1, 137 416 0, 231 416 1, 278 416 0, 343 403 1, 343 341 1, 281 360 0, 245 360 1, 116 360 0, 116 204 1, 116 130 0, 149 90 1, 182 50 0, 242 50 1, 287 50 0, 347 76 1, 387 602 1, 297 481 1, 215 481 1, 125 602 1, 180 602 1, 256 526 1, 256 526 1, 332 602 1
+555 62 0 520 722;62 0 1, 62 555 1, 240 555 1, 520 555 0, 520 290 1, 520 152 0, 447 76 1, 374 0 0, 241 0 1, 141 59 1, 235 59 1, 435 59 0, 435 281 1, 435 412 0, 356 466 1, 333 482 0, 301 488 1, 263 496 0, 199 496 1, 141 496 1, 387 722 1, 297 602 1, 215 602 1, 125 722 1, 180 722 1, 255 646 1, 256 646 1, 332 722 1
+472 32 -9 472 592;295 143 1, 295 351 1, 243 361 0, 218 361 1, 112 361 0, 112 200 1, 112 133 0, 133 94 1, 154 56 0, 189 56 1, 236 56 0, 295 76 1, 274 38 0, 251 18 1, 218 -9 0, 173 -9 1, 110 -9 0, 71 46 1, 32 101 0, 32 193 1, 32 299 0, 83 358 1, 133 416 0, 224 416 1, 259 416 0, 295 407 1, 295 592 1, 369 592 1, 369 0 1, 295 0 1, 398 422 1, 398 444 1, 427 452 0, 427 512 1, 427 518 1, 398 518 1, 398 592 1, 472 592 1, 472 528 1, 472 430 0
+555 2 0 520 555;62 0 1, 62 255 1, 2 255 1, 2 314 1, 62 314 1, 62 555 1, 240 555 1, 520 555 0, 520 290 1, 520 152 0, 447 76 1, 374 0 0, 241 0 1, 141 59 1, 235 59 1, 435 59 0, 435 281 1, 435 412 0, 356 466 1, 333 482 0, 301 488 1, 263 496 0, 199 496 1, 141 496 1, 141 314 1, 266 314 1, 266 255 1, 141 255 1
+427 32 -9 425 592;295 472 1, 175 472 1, 175 518 1, 295 518 1, 295 592 1, 369 592 1, 369 518 1, 425 518 1, 425 472 1, 369 472 1, 369 0 1, 295 0 1, 295 76 1, 274 38 0, 251 18 1, 218 -9 0, 173 -9 1, 110 -9 0, 71 46 1, 32 101 0, 32 193 1, 32 299 0, 83 358 1, 133 416 0, 224 416 1, 259 416 0, 295 407 1, 295 143 1, 295 351 1, 243 361 0, 218 361 1, 112 361 0, 112 200 1, 112 133 0, 133 94 1, 154 56 0, 189 56 1, 236 56 0
+512 72 0 491 657;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 150 602 1, 150 657 1, 391 657 1, 391 602 1
+427 32 -9 383 537;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 72 481 1, 72 537 1, 312 537 1, 312 481 1
+512 72 0 491 722;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 152 722 1, 198 722 1, 206 687 0, 226 672 1, 245 657 0, 276 657 1, 312 657 0, 332 675 1, 348 690 0, 355 722 1, 401 722 1, 395 672 0, 368 641 1, 333 602 0, 276 602 1, 218 602 0, 182 645 1, 158 674 0
+427 32 -9 383 602;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 89 602 1, 135 602 1, 143 567 0, 163 551 1, 182 537 0, 213 537 1, 249 537 0, 269 555 1, 285 570 0, 292 602 1, 338 602 1, 332 551 0, 305 521 1, 269 481 0, 213 481 1, 155 481 0, 119 524 1, 95 553 0
+512 72 0 491 675;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 238 602 1, 238 675 1, 312 675 1, 312 602 1
+427 32 -9 383 555;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 155 481 1, 155 555 1, 229 555 1, 229 481 1
+512 72 -139 491 555;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 403 0 1, 443 0 1, 395 -30 0, 395 -67 1, 395 -103 0, 438 -103 1, 458 -103 0, 472 -98 1, 472 -128 1, 449 -139 0, 420 -139 1, 344 -139 0, 344 -80 1, 344 -34 0
+427 32 -139 383 416;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 251 0 1, 291 0 1, 243 -30 0, 243 -67 1, 243 -103 0, 286 -103 1, 306 -103 0, 320 -98 1, 320 -128 1, 297 -139 0, 268 -139 1, 192 -139 0, 192 -80 1, 192 -34 0
+512 72 0 491 722;72 0 1, 72 555 1, 474 555 1, 474 496 1, 150 496 1, 150 318 1, 437 318 1, 437 260 1, 150 260 1, 150 59 1, 491 59 1, 491 0 1, 406 722 1, 315 602 1, 234 602 1, 143 722 1, 199 722 1, 274 646 1, 275 646 1, 350 722 1
+427 32 -9 383 602;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0, 323 602 1, 233 481 1, 151 481 1, 61 602 1, 116 602 1, 192 526 1, 192 526 1, 268 602 1
+597 35 -14 527 722;527 258 1, 527 15 1, 424 -14 0, 327 -14 1, 35 -14 0, 35 276 1, 35 417 0, 110 493 1, 186 569 0, 329 569 1, 421 569 0, 526 544 1, 526 471 1, 406 510 0, 326 510 1, 119 510 0, 119 279 1, 119 165 0, 176 105 1, 233 45 0, 338 45 1, 381 45 0, 449 59 1, 449 200 1, 356 200 1, 356 258 1, 194 602 1, 284 722 1, 366 722 1, 456 602 1, 401 602 1, 326 677 1, 325 677 1, 249 602 1
+427 35 -158 372 602;298 162 1, 298 351 1, 245 361 0, 222 361 1, 115 361 0, 115 215 1, 115 150 0, 136 112 1, 157 74 0, 192 74 1, 239 74 0, 298 95 1, 277 57 0, 254 37 1, 221 9 0, 176 9 1, 113 9 0, 74 64 1, 35 119 0, 35 207 1, 35 306 0, 85 361 1, 135 416 0, 226 416 1, 261 416 0, 298 407 1, 372 407 1, 372 111 1, 372 15 0, 362 -31 1, 334 -158 0, 174 -158 1, 106 -158 0, 38 -135 1, 38 -71 1, 118 -102 0, 173 -102 1, 298 -102 0, 298 31 1, 93 481 1, 184 602 1, 266 602 1, 356 481 1, 300 481 1, 225 557 1, 224 557 1, 149 481 1
+597 35 -14 527 722;527 258 1, 527 15 1, 424 -14 0, 327 -14 1, 35 -14 0, 35 276 1, 35 417 0, 110 493 1, 186 569 0, 329 569 1, 421 569 0, 526 544 1, 526 471 1, 406 510 0, 326 510 1, 119 510 0, 119 279 1, 119 165 0, 176 105 1, 233 45 0, 338 45 1, 381 45 0, 449 59 1, 449 200 1, 356 200 1, 356 258 1, 200 722 1, 246 722 1, 254 687 0, 275 672 1, 294 657 0, 325 657 1, 360 657 0, 381 675 1, 397 690 0, 404 722 1, 450 722 1, 444 672 0, 417 641 1, 381 602 0, 325 602 1, 266 602 0, 231 645 1, 206 674 0
+427 35 -158 381 602;298 162 1, 298 351 1, 245 361 0, 222 361 1, 115 361 0, 115 215 1, 115 150 0, 136 112 1, 157 74 0, 192 74 1, 239 74 0, 298 95 1, 277 57 0, 254 37 1, 221 9 0, 176 9 1, 113 9 0, 74 64 1, 35 119 0, 35 207 1, 35 306 0, 85 361 1, 135 416 0, 226 416 1, 261 416 0, 298 407 1, 372 407 1, 372 111 1, 372 15 0, 362 -31 1, 334 -158 0, 174 -158 1, 106 -158 0, 38 -135 1, 38 -71 1, 118 -102 0, 173 -102 1, 298 -102 0, 298 31 1, 131 602 1, 177 602 1, 185 566 0, 205 551 1, 225 537 0, 256 537 1, 291 537 0, 311 555 1, 328 570 0, 335 602 1, 381 602 1, 375 551 0, 347 521 1, 312 481 0, 256 481 1, 197 481 0, 161 524 1, 137 554 0
+597 35 -14 527 675;527 258 1, 527 15 1, 424 -14 0, 327 -14 1, 35 -14 0, 35 276 1, 35 417 0, 110 493 1, 186 569 0, 329 569 1, 421 569 0, 526 544 1, 526 471 1, 406 510 0, 326 510 1, 119 510 0, 119 279 1, 119 165 0, 176 105 1, 233 45 0, 338 45 1, 381 45 0, 449 59 1, 449 200 1, 356 200 1, 356 258 1, 288 602 1, 288 675 1, 362 675 1, 362 602 1
+427 35 -158 372 555;298 162 1, 298 351 1, 245 361 0, 222 361 1, 115 361 0, 115 215 1, 115 150 0, 136 112 1, 157 74 0, 192 74 1, 239 74 0, 298 95 1, 277 57 0, 254 37 1, 221 9 0, 176 9 1, 113 9 0, 74 64 1, 35 119 0, 35 207 1, 35 306 0, 85 361 1, 135 416 0, 226 416 1, 261 416 0, 298 407 1, 372 407 1, 372 111 1, 372 15 0, 362 -31 1, 334 -158 0, 174 -158 1, 106 -158 0, 38 -135 1, 38 -71 1, 118 -102 0, 173 -102 1, 298 -102 0, 298 31 1, 183 481 1, 183 555 1, 257 555 1, 257 481 1
+597 35 -162 527 569;527 258 1, 527 15 1, 423 -14 0, 327 -14 1, 35 -14 0, 35 276 1, 35 417 0, 110 493 1, 186 569 0, 329 569 1, 421 569 0, 526 544 1, 526 471 1, 406 510 0, 326 510 1, 119 510 0, 119 279 1, 119 165 0, 176 105 1, 233 45 0, 338 45 1, 381 45 0, 449 59 1, 449 200 1, 356 200 1, 356 258 1, 263 -158 1, 263 -126 1, 284 -129 0, 299 -129 1, 340 -129 0, 340 -104 1, 340 -77 0, 281 -71 1, 281 -42 1, 331 -43 0, 356 -54 1, 391 -69 0, 391 -105 1, 391 -162 0, 309 -162 1, 287 -162 0
+427 35 -158 372 651;298 162 1, 298 351 1, 245 361 0, 222 361 1, 115 361 0, 115 215 1, 115 150 0, 136 112 1, 157 74 0, 192 74 1, 239 74 0, 298 95 1, 277 57 0, 254 37 1, 221 9 0, 176 9 1, 113 9 0, 74 64 1, 35 119 0, 35 207 1, 35 306 0, 85 361 1, 135 416 0, 226 416 1, 261 416 0, 298 407 1, 372 407 1, 372 111 1, 372 15 0, 362 -31 1, 334 -158 0, 174 -158 1, 106 -158 0, 38 -135 1, 38 -71 1, 118 -102 0, 173 -102 1, 298 -102 0, 298 31 1, 257 651 1, 257 629 1, 228 621 0, 228 561 1, 228 555 1, 257 555 1, 257 481 1, 183 481 1, 183 545 1, 183 644 0
+555 62 0 492 722;62 0 1, 62 555 1, 141 555 1, 141 321 1, 414 321 1, 414 555 1, 492 555 1, 492 0 1, 414 0 1, 414 262 1, 141 262 1, 141 0 1, 146 602 1, 236 722 1, 318 722 1, 408 602 1, 353 602 1, 278 677 1, 277 677 1, 201 602 1
+427 58 0 374 750;58 0 1, 58 592 1, 132 592 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1, 86 629 1, 176 750 1, 258 750 1, 348 629 1, 293 629 1, 217 705 1, 216 705 1, 141 629 1
+555 6 0 548 555;141 321 1, 414 321 1, 414 416 1, 141 416 1, 62 0 1, 62 416 1, 6 416 1, 6 463 1, 62 463 1, 62 555 1, 141 555 1, 141 463 1, 414 463 1, 414 555 1, 492 555 1, 492 463 1, 548 463 1, 548 416 1, 492 416 1, 492 0 1, 414 0 1, 414 262 1, 141 262 1, 141 0 1
+427 2 0 374 592;58 0 1, 58 472 1, 2 472 1, 2 518 1, 58 518 1, 58 592 1, 132 592 1, 132 518 1, 243 518 1, 243 472 1, 132 472 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1
+213 -18 0 232 689;68 0 1, 68 555 1, 146 555 1, 146 0 1, -18 602 1, -15 636 0, -6 656 1, 11 689 0, 52 689 1, 79 689 0, 102 675 1, 125 661 1, 146 648 0, 157 648 1, 182 648 0, 186 689 1, 232 689 1, 229 654 0, 220 635 1, 203 602 0, 162 602 1, 135 602 0, 112 616 1, 89 630 1, 69 643 0, 57 643 1, 32 643 0, 28 602 1
+171 -40 0 210 569;48 0 1, 48 407 1, 122 407 1, 122 0 1, -40 481 1, -37 516 0, -28 535 1, -11 569 0, 30 569 1, 57 569 0, 80 555 1, 103 541 1, 124 528 0, 135 528 1, 160 528 0, 164 569 1, 210 569 1, 207 534 0, 198 515 1, 181 481 0, 141 481 1, 114 481 0, 90 496 1, 68 510 1, 47 522 0, 35 522 1, 11 522 0, 6 481 1
+213 -14 0 227 657;68 0 1, 68 555 1, 146 555 1, 146 0 1, -14 602 1, -14 657 1, 227 657 1, 227 602 1
+171 -56 0 184 537;48 0 1, 48 407 1, 122 407 1, 122 0 1, -56 481 1, -56 537 1, 184 537 1, 184 481 1
+213 -18 0 232 722;68 0 1, 68 555 1, 146 555 1, 146 0 1, -18 722 1, 28 722 1, 36 687 0, 56 672 1, 76 657 0, 107 657 1, 142 657 0, 162 675 1, 179 690 0, 186 722 1, 232 722 1, 226 672 0, 198 641 1, 163 602 0, 107 602 1, 48 602 0, 12 645 1, -12 674 0
+171 -40 0 210 602;48 0 1, 48 407 1, 122 407 1, 122 0 1, -40 602 1, 6 602 1, 14 566 0, 35 551 1, 54 537 0, 85 537 1, 120 537 0, 141 555 1, 157 570 0, 164 602 1, 210 602 1, 204 551 0, 177 521 1, 141 481 0, 85 481 1, 26 481 0, -9 524 1, -34 554 0
+213 45 -139 173 555;68 0 1, 68 555 1, 146 555 1, 146 0 1, 104 0 1, 144 0 1, 96 -30 0, 96 -67 1, 96 -103 0, 140 -103 1, 159 -103 0, 173 -98 1, 173 -128 1, 150 -139 0, 121 -139 1, 45 -139 0, 45 -80 1, 45 -34 0
+171 0 -139 128 555;48 0 1, 48 407 1, 122 407 1, 122 0 1, 48 481 1, 48 555 1, 122 555 1, 122 481 1, 59 0 1, 99 0 1, 51 -30 0, 51 -67 1, 51 -103 0, 94 -103 1, 114 -103 0, 128 -98 1, 128 -128 1, 105 -139 0, 76 -139 1, 0 -139 0, 0 -80 1, 0 -34 0
+213 68 0 146 675;68 0 1, 68 555 1, 146 555 1, 146 0 1, 70 602 1, 70 675 1, 144 675 1, 144 602 1
+564 68 -111 507 555;68 0 1, 68 555 1, 146 555 1, 146 0 1, 210 -87 1, 210 -19 1, 275 -48 0, 330 -48 1, 395 -48 0, 413 -18 1, 428 7 0, 428 68 1, 428 555 1, 507 555 1, 507 70 1, 507 -111 0, 327 -111 1, 266 -111 0
+341 48 -157 316 555;48 0 1, 48 407 1, 122 407 1, 122 0 1, 48 481 1, 48 555 1, 122 555 1, 122 481 1, 134 -145 1, 134 -87 1, 164 -102 0, 190 -102 1, 227 -102 0, 235 -74 1, 242 -51 0, 242 0 1, 242 407 1, 316 407 1, 316 0 1, 316 -157 0, 196 -157 1, 163 -157 0, 242 481 1, 242 555 1, 316 555 1, 316 481 1
+384 18 -111 398 722;18 -87 1, 18 -19 1, 83 -48 0, 138 -48 1, 203 -48 0, 221 -18 1, 236 7 0, 236 68 1, 236 555 1, 315 555 1, 315 70 1, 315 -111 0, 135 -111 1, 74 -111 0, 135 602 1, 226 722 1, 308 722 1, 398 602 1, 342 602 1, 267 677 1, 266 677 1, 191 602 1
+171 -58 -157 212 602;-58 -145 1, -58 -87 1, -28 -102 0, -2 -102 1, 35 -102 0, 43 -74 1, 50 -51 0, 50 0 1, 50 407 1, 124 407 1, 124 0 1, 124 -157 0, 4 -157 1, -29 -157 0, -50 481 1, 40 602 1, 122 602 1, 212 481 1, 156 481 1, 81 557 1, 80 557 1, 5 481 1
+512 72 -162 494 555;72 0 1, 72 555 1, 146 555 1, 146 282 1, 376 555 1, 455 555 1, 232 290 1, 494 0 1, 394 0 1, 146 281 1, 146 0 1, 183 -158 1, 183 -126 1, 204 -129 0, 219 -129 1, 260 -129 0, 260 -104 1, 260 -77 0, 201 -71 1, 201 -42 1, 251 -43 0, 276 -54 1, 311 -69 0, 311 -105 1, 311 -162 0, 230 -162 1, 207 -162 0
+384 58 -162 377 592;58 0 1, 58 592 1, 132 592 1, 132 210 1, 268 407 1, 339 407 1, 209 215 1, 377 0 1, 287 0 1, 132 209 1, 132 0 1, 128 -158 1, 128 -126 1, 149 -129 0, 164 -129 1, 205 -129 0, 205 -104 1, 205 -77 0, 146 -71 1, 146 -42 1, 196 -43 0, 221 -54 1, 256 -69 0, 256 -105 1, 256 -162 0, 175 -162 1, 153 -162 0
+384 58 0 377 407;58 0 1, 58 407 1, 132 407 1, 132 210 1, 268 407 1, 339 407 1, 209 215 1, 377 0 1, 287 0 1, 132 209 1, 132 0 1
+427 62 0 413 722;62 0 1, 62 555 1, 141 555 1, 141 59 1, 413 59 1, 413 0 1, 66 602 1, 157 722 1, 242 722 1, 122 602 1
+171 40 0 216 730;48 0 1, 48 592 1, 122 592 1, 122 0 1, 40 609 1, 131 730 1, 216 730 1, 96 609 1
+427 62 -162 413 555;62 0 1, 62 555 1, 141 555 1, 141 59 1, 413 59 1, 413 0 1, 168 -158 1, 168 -126 1, 190 -129 0, 205 -129 1, 246 -129 0, 246 -104 1, 246 -77 0, 187 -71 1, 187 -42 1, 237 -43 0, 262 -54 1, 297 -69 0, 297 -105 1, 297 -162 0, 215 -162 1, 193 -162 0
+171 0 -162 128 592;48 0 1, 48 592 1, 122 592 1, 122 0 1, 0 -158 1, 0 -126 1, 21 -129 0, 36 -129 1, 77 -129 0, 77 -104 1, 77 -77 0, 18 -71 1, 18 -42 1, 68 -43 0, 93 -54 1, 128 -69 0, 128 -105 1, 128 -162 0, 47 -162 1, 25 -162 0
+427 62 0 413 555;62 0 1, 62 555 1, 141 555 1, 141 59 1, 413 59 1, 413 0 1, 252 385 1, 252 407 1, 280 415 0, 280 475 1, 280 481 1, 252 481 1, 252 555 1, 326 555 1, 326 491 1, 325 393 0
+224 48 0 229 592;48 0 1, 48 592 1, 122 592 1, 122 0 1, 155 422 1, 155 444 1, 183 452 0, 183 512 1, 183 518 1, 155 518 1, 155 592 1, 229 592 1, 229 528 1, 228 430 0
+427 62 0 413 555;62 0 1, 62 555 1, 141 555 1, 141 59 1, 413 59 1, 413 0 1, 279 241 1, 279 315 1, 353 315 1, 353 241 1
+257 48 0 252 592;48 0 1, 48 592 1, 122 592 1, 122 0 1, 178 241 1, 178 315 1, 252 315 1, 252 241 1
+427 6 0 413 555;62 0 1, 62 260 1, 6 230 1, 6 293 1, 62 323 1, 62 555 1, 141 555 1, 141 366 1, 233 416 1, 233 353 1, 141 303 1, 141 59 1, 413 59 1, 413 0 1
+171 -3 0 173 592;48 0 1, 48 270 1, -3 243 1, -3 305 1, 48 333 1, 48 592 1, 123 592 1, 123 374 1, 173 399 1, 173 338 1, 123 311 1, 123 0 1
+555 62 0 492 722;62 0 1, 62 555 1, 139 555 1, 425 126 1, 425 555 1, 492 555 1, 492 0 1, 415 0 1, 129 429 1, 129 0 1, 222 602 1, 312 722 1, 398 722 1, 277 602 1
+427 58 0 374 602;58 0 1, 58 407 1, 132 407 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+555 62 -162 492 555;62 0 1, 62 555 1, 139 555 1, 425 126 1, 425 555 1, 492 555 1, 492 0 1, 415 0 1, 129 429 1, 129 0 1, 194 -158 1, 194 -126 1, 216 -129 0, 231 -129 1, 272 -129 0, 272 -104 1, 272 -77 0, 213 -71 1, 213 -42 1, 263 -43 0, 288 -54 1, 323 -69 0, 323 -105 1, 323 -162 0, 241 -162 1, 219 -162 0
+427 58 -162 374 416;58 0 1, 58 407 1, 132 407 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1, 128 -158 1, 128 -126 1, 149 -129 0, 164 -129 1, 205 -129 0, 205 -104 1, 205 -77 0, 146 -71 1, 146 -42 1, 196 -43 0, 221 -54 1, 256 -69 0, 256 -105 1, 256 -162 0, 175 -162 1, 153 -162 0
+555 62 0 492 722;62 0 1, 62 555 1, 139 555 1, 425 126 1, 425 555 1, 492 555 1, 492 0 1, 415 0 1, 129 429 1, 129 0 1, 408 722 1, 318 602 1, 236 602 1, 146 722 1, 201 722 1, 277 646 1, 278 646 1, 353 722 1
+427 58 0 374 602;58 0 1, 58 407 1, 132 407 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 0 1, 300 0 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1, 323 602 1, 233 481 1, 151 481 1, 61 602 1, 116 602 1, 192 526 1, 192 526 1, 268 602 1
+464 0 0 411 592;95 0 1, 95 407 1, 168 407 1, 168 331 1, 196 369 0, 222 388 1, 261 416 0, 307 416 1, 411 416 0, 411 293 1, 411 0 1, 336 0 1, 336 269 1, 336 318 0, 326 335 1, 315 353 0, 287 353 1, 227 353 0, 168 264 1, 168 0 1, 0 422 1, 0 444 1, 29 452 0, 29 512 1, 29 518 1, 0 518 1, 0 592 1, 74 592 1, 74 528 1, 74 430 0
+555 62 -158 492 555;62 0 1, 62 555 1, 139 555 1, 425 126 1, 425 555 1, 492 555 1, 492 -35 1, 492 -158 0, 373 -158 1, 345 -158 0, 317 -150 1, 317 -92 1, 341 -102 0, 369 -102 1, 425 -102 0, 425 -21 1, 425 -15 1, 129 429 1, 129 0 1
+427 58 -158 374 416;58 0 1, 58 407 1, 132 407 1, 132 331 1, 159 369 0, 186 388 1, 224 416 0, 270 416 1, 374 416 0, 374 293 1, 374 -35 1, 374 -158 0, 255 -158 1, 227 -158 0, 198 -150 1, 198 -92 1, 222 -102 0, 244 -102 1, 300 -102 0, 300 -21 1, 300 269 1, 300 318 0, 290 335 1, 279 353 0, 251 353 1, 190 353 0, 132 264 1, 132 0 1
+597 35 -14 563 657;299 569 1, 419 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 419 -14 0, 295 -14 1, 189 -14 0, 121 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 214 510 0, 167 449 1, 119 388 0, 119 278 1, 119 169 0, 167 107 1, 213 45 0, 297 45 1, 375 45 0, 421 95 1, 479 156 0, 479 278 1, 479 388 0, 431 449 1, 383 510 0, 179 602 1, 179 657 1, 419 657 1, 419 602 1
+427 32 -9 395 537;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 72 481 1, 72 537 1, 312 537 1, 312 481 1
+597 35 -14 563 722;299 569 1, 419 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 419 -14 0, 295 -14 1, 189 -14 0, 121 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 214 510 0, 167 449 1, 119 388 0, 119 278 1, 119 169 0, 167 107 1, 213 45 0, 297 45 1, 375 45 0, 421 95 1, 479 156 0, 479 278 1, 479 388 0, 431 449 1, 383 510 0, 174 722 1, 220 722 1, 228 687 0, 248 672 1, 268 657 0, 299 657 1, 334 657 0, 354 675 1, 371 690 0, 378 722 1, 424 722 1, 418 672 0, 390 641 1, 355 602 0, 299 602 1, 240 602 0, 204 645 1, 180 674 0
+427 32 -9 395 602;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 89 602 1, 135 602 1, 143 567 0, 163 551 1, 182 537 0, 213 537 1, 249 537 0, 269 555 1, 285 570 0, 292 602 1, 338 602 1, 332 551 0, 305 521 1, 269 481 0, 213 481 1, 155 481 0, 119 524 1, 95 553 0
+597 35 -14 563 722;299 569 1, 419 569 0, 491 490 1, 563 410 0, 563 278 1, 563 144 0, 491 65 1, 419 -14 0, 295 -14 1, 189 -14 0, 121 51 1, 35 132 0, 35 278 1, 35 411 0, 107 490 1, 179 569 0, 299 510 1, 214 510 0, 167 449 1, 119 388 0, 119 278 1, 119 169 0, 167 107 1, 213 45 0, 297 45 1, 375 45 0, 421 95 1, 479 156 0, 479 278 1, 479 388 0, 431 449 1, 383 510 0, 212 602 1, 303 722 1, 374 722 1, 254 602 1, 344 602 1, 434 722 1, 506 722 1, 386 602 1
+427 32 -9 403 602;213 416 1, 297 416 0, 346 359 1, 395 303 0, 395 204 1, 395 104 0, 346 47 1, 297 -9 0, 211 -9 1, 137 -9 0, 91 38 1, 32 96 0, 32 204 1, 32 302 0, 81 359 1, 130 416 0, 213 361 1, 112 361 0, 112 204 1, 112 46 0, 213 46 1, 315 46 0, 315 205 1, 315 361 0, 109 481 1, 199 602 1, 271 602 1, 151 481 1, 241 481 1, 331 602 1, 403 602 1, 283 481 1
+555 62 0 538 722;62 0 1, 62 555 1, 294 555 1, 465 555 0, 465 417 1, 465 350 0, 423 306 1, 399 281 0, 353 260 1, 538 0 1, 441 0 1, 283 235 1, 141 235 1, 141 0 1, 141 294 1, 229 294 1, 309 294 0, 346 321 1, 384 350 0, 384 408 1, 384 456 0, 353 476 1, 323 496 0, 253 496 1, 141 496 1, 196 602 1, 287 722 1, 372 722 1, 252 602 1
+256 58 0 280 602;58 0 1, 58 407 1, 132 407 1, 132 331 1, 148 369 0, 166 389 1, 193 416 0, 230 416 1, 237 416 0, 251 414 1, 251 345 1, 231 352 0, 219 352 1, 178 352 0, 132 269 1, 132 0 1, 104 481 1, 195 602 1, 280 602 1, 160 481 1
+555 62 -162 538 555;62 0 1, 62 555 1, 294 555 1, 465 555 0, 465 417 1, 465 350 0, 423 306 1, 399 281 0, 353 260 1, 538 0 1, 441 0 1, 283 235 1, 141 235 1, 141 0 1, 141 294 1, 229 294 1, 309 294 0, 346 321 1, 384 350 0, 384 408 1, 384 456 0, 353 476 1, 323 496 0, 253 496 1, 141 496 1, 196 -158 1, 196 -126 1, 218 -129 0, 233 -129 1, 274 -129 0, 274 -104 1, 274 -77 0, 215 -71 1, 215 -42 1, 265 -43 0, 290 -54 1, 324 -69 0, 324 -105 1, 324 -162 0, 243 -162 1, 221 -162 0
+256 58 -162 251 416;58 0 1, 58 407 1, 132 407 1, 132 331 1, 148 369 0, 166 389 1, 193 416 0, 230 416 1, 237 416 0, 251 414 1, 251 345 1, 231 352 0, 219 352 1, 178 352 0, 132 269 1, 132 0 1, 64 -158 1, 64 -126 1, 85 -129 0, 100 -129 1, 141 -129 0, 141 -104 1, 141 -77 0, 82 -71 1, 82 -42 1, 132 -43 0, 157 -54 1, 192 -69 0, 192 -105 1, 192 -162 0, 111 -162 1, 89 -162 0
+555 62 0 538 722;62 0 1, 62 555 1, 294 555 1, 465 555 0, 465 417 1, 465 350 0, 423 306 1, 399 281 0, 353 260 1, 538 0 1, 441 0 1, 283 235 1, 141 235 1, 141 0 1, 141 294 1, 229 294 1, 309 294 0, 346 321 1, 384 350 0, 384 408 1, 384 456 0, 353 476 1, 323 496 0, 253 496 1, 141 496 1, 368 722 1, 278 602 1, 196 602 1, 106 722 1, 161 722 1, 237 646 1, 237 646 1, 313 722 1
+256 -3 0 259 602;58 0 1, 58 407 1, 132 407 1, 132 331 1, 148 369 0, 166 389 1, 193 416 0, 230 416 1, 237 416 0, 251 414 1, 251 345 1, 231 352 0, 219 352 1, 178 352 0, 132 269 1, 132 0 1, 259 602 1, 169 481 1, 87 481 1, -3 602 1, 52 602 1, 128 526 1, 128 526 1, 204 602 1
+512 45 -14 466 722;45 20 1, 45 98 1, 156 45 0, 264 45 1, 385 45 0, 385 135 1, 385 181 0, 352 203 1, 326 220 0, 269 239 1, 193 264 1, 48 311 0, 48 421 1, 48 569 0, 251 569 1, 338 569 0, 432 545 1, 432 473 1, 334 510 0, 246 510 1, 124 510 0, 124 427 1, 124 394 0, 147 374 1, 171 354 0, 230 334 1, 308 309 1, 395 281 0, 431 244 1, 466 207 0, 466 146 1, 466 72 0, 411 29 1, 357 -14 0, 261 -14 1, 167 -14 0, 196 602 1, 287 722 1, 372 722 1, 252 602 1
+384 44 -9 344 602;44 14 1, 44 82 1, 118 46 0, 181 46 1, 266 46 0, 266 106 1, 266 147 0, 207 167 1, 141 189 1, 46 220 0, 46 303 1, 46 416 0, 201 416 1, 246 416 0, 309 404 1, 309 342 1, 253 361 0, 196 361 1, 119 361 0, 119 310 1, 119 273 0, 172 256 1, 231 237 1, 341 201 0, 341 113 1, 341 57 0, 297 24 1, 254 -9 0, 178 -9 1, 119 -9 0, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+512 45 -14 466 722;45 20 1, 45 98 1, 156 45 0, 264 45 1, 385 45 0, 385 135 1, 385 181 0, 352 203 1, 326 220 0, 269 239 1, 193 264 1, 48 311 0, 48 421 1, 48 569 0, 251 569 1, 338 569 0, 432 545 1, 432 473 1, 334 510 0, 246 510 1, 124 510 0, 124 427 1, 124 394 0, 147 374 1, 171 354 0, 230 334 1, 308 309 1, 395 281 0, 431 244 1, 466 207 0, 466 146 1, 466 72 0, 411 29 1, 357 -14 0, 261 -14 1, 167 -14 0, 120 602 1, 211 722 1, 293 722 1, 383 602 1, 327 602 1, 252 677 1, 251 677 1, 176 602 1
+384 44 -9 341 602;44 14 1, 44 82 1, 118 46 0, 181 46 1, 266 46 0, 266 106 1, 266 147 0, 207 167 1, 141 189 1, 46 220 0, 46 303 1, 46 416 0, 201 416 1, 246 416 0, 309 404 1, 309 342 1, 253 361 0, 196 361 1, 119 361 0, 119 310 1, 119 273 0, 172 256 1, 231 237 1, 341 201 0, 341 113 1, 341 57 0, 297 24 1, 254 -9 0, 178 -9 1, 119 -9 0, 75 481 1, 165 602 1, 247 602 1, 337 481 1, 282 481 1, 206 557 1, 206 557 1, 130 481 1
+512 45 -162 466 569;45 20 1, 45 98 1, 156 45 0, 264 45 1, 385 45 0, 385 135 1, 385 181 0, 352 203 1, 326 220 0, 269 239 1, 193 264 1, 48 311 0, 48 421 1, 48 569 0, 251 569 1, 338 569 0, 432 545 1, 432 473 1, 334 510 0, 246 510 1, 124 510 0, 124 427 1, 124 394 0, 147 374 1, 171 354 0, 230 334 1, 308 309 1, 395 281 0, 431 244 1, 466 207 0, 466 147 1, 466 72 0, 411 29 1, 357 -14 0, 261 -14 1, 167 -14 0, 225 0 1, 262 0 1, 239 -41 1, 266 -42 0, 286 -56 1, 312 -74 0, 312 -101 1, 312 -126 0, 290 -144 1, 268 -162 0, 236 -162 1, 211 -162 0, 182 -154 1, 182 -124 1, 201 -129 0, 221 -129 1, 260 -129 0, 260 -102 1, 260 -67 0, 190 -66 1
+384 44 -162 341 416;44 14 1, 44 82 1, 118 46 0, 181 46 1, 266 46 0, 266 106 1, 266 147 0, 207 167 1, 141 189 1, 46 220 0, 46 303 1, 46 416 0, 201 416 1, 246 416 0, 309 404 1, 309 342 1, 253 361 0, 196 361 1, 119 361 0, 119 310 1, 119 273 0, 172 256 1, 231 237 1, 341 201 0, 341 113 1, 341 57 0, 297 24 1, 254 -9 0, 178 -9 1, 119 -9 0, 171 0 1, 207 0 1, 184 -41 1, 211 -42 0, 231 -56 1, 257 -74 0, 257 -101 1, 257 -126 0, 235 -144 1, 213 -162 0, 181 -162 1, 156 -162 0, 127 -154 1, 127 -124 1, 146 -129 0, 166 -129 1, 205 -129 0, 205 -102 1, 205 -67 0, 135 -66 1
+512 45 -14 466 722;45 20 1, 45 98 1, 156 45 0, 264 45 1, 385 45 0, 385 135 1, 385 181 0, 352 203 1, 326 220 0, 269 239 1, 193 264 1, 48 311 0, 48 421 1, 48 569 0, 251 569 1, 338 569 0, 432 545 1, 432 473 1, 334 510 0, 246 510 1, 124 510 0, 124 427 1, 124 394 0, 147 374 1, 171 354 0, 230 334 1, 308 309 1, 395 281 0, 431 244 1, 466 207 0, 466 146 1, 466 72 0, 411 29 1, 357 -14 0, 261 -14 1, 167 -14 0, 383 722 1, 293 602 1, 211 602 1, 120 722 1, 176 722 1, 251 646 1, 252 646 1, 327 722 1
+384 44 -9 341 602;44 14 1, 44 82 1, 118 46 0, 181 46 1, 266 46 0, 266 106 1, 266 147 0, 207 167 1, 141 189 1, 46 220 0, 46 303 1, 46 416 0, 201 416 1, 246 416 0, 309 404 1, 309 342 1, 253 361 0, 196 361 1, 119 361 0, 119 310 1, 119 273 0, 172 256 1, 231 237 1, 341 201 0, 341 113 1, 341 57 0, 297 24 1, 254 -9 0, 178 -9 1, 119 -9 0, 323 602 1, 233 481 1, 151 481 1, 61 602 1, 116 602 1, 192 526 1, 192 526 1, 268 602 1
+469 8 -162 461 555;195 0 1, 195 496 1, 8 496 1, 8 555 1, 461 555 1, 461 496 1, 274 496 1, 274 0 1, 220 0 1, 256 0 1, 234 -41 1, 261 -42 0, 280 -56 1, 306 -74 0, 306 -101 1, 306 -126 0, 285 -144 1, 263 -162 0, 230 -162 1, 205 -162 0, 176 -154 1, 176 -124 1, 195 -129 0, 215 -129 1, 254 -129 0, 254 -102 1, 254 -67 0, 184 -66 1
+213 11 -162 210 488;199 -2 1, 176 -9 0, 156 -9 1, 57 -9 0, 57 113 1, 57 352 1, 11 352 1, 11 407 1, 57 407 1, 57 481 1, 131 488 1, 131 407 1, 210 407 1, 210 352 1, 131 352 1, 131 126 1, 131 78 0, 139 62 1, 147 46 0, 174 46 1, 188 46 0, 199 50 1, 112 0 1, 149 0 1, 126 -41 1, 153 -42 0, 173 -56 1, 199 -74 0, 199 -101 1, 199 -126 0, 177 -144 1, 155 -162 0, 123 -162 1, 97 -162 0, 69 -154 1, 69 -124 1, 87 -129 0, 108 -129 1, 147 -129 0, 147 -102 1, 147 -67 0, 77 -66 1
+469 8 0 461 722;195 0 1, 195 496 1, 8 496 1, 8 555 1, 461 555 1, 461 496 1, 274 496 1, 274 0 1, 366 722 1, 275 602 1, 194 602 1, 103 722 1, 159 722 1, 234 646 1, 235 646 1, 310 722 1
+288 11 -9 270 633;199 -2 1, 176 -9 0, 156 -9 1, 57 -9 0, 57 113 1, 57 352 1, 11 352 1, 11 407 1, 57 407 1, 57 481 1, 131 488 1, 131 407 1, 210 407 1, 210 352 1, 131 352 1, 131 126 1, 131 78 0, 139 62 1, 147 46 0, 174 46 1, 188 46 0, 199 50 1, 196 463 1, 196 485 1, 224 493 0, 224 553 1, 224 559 1, 196 559 1, 196 633 1, 270 633 1, 270 569 1, 269 471 0
+469 8 0 461 555;195 0 1, 195 268 1, 81 268 1, 81 324 1, 195 324 1, 195 496 1, 8 496 1, 8 555 1, 461 555 1, 461 496 1, 274 496 1, 274 324 1, 387 324 1, 387 268 1, 274 268 1, 274 0 1
+213 11 -9 210 488;57 213 1, 11 213 1, 11 259 1, 57 259 1, 57 352 1, 11 352 1, 11 407 1, 57 407 1, 57 481 1, 131 488 1, 131 407 1, 210 407 1, 210 352 1, 131 352 1, 131 259 1, 210 259 1, 210 213 1, 131 213 1, 131 126 1, 131 78 0, 139 62 1, 147 46 0, 174 46 1, 188 46 0, 199 50 1, 199 -2 1, 176 -9 0, 156 -9 1, 57 -9 0, 57 113 1
+555 62 -14 492 689;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 157 602 1, 160 636 0, 169 656 1, 186 689 0, 227 689 1, 254 689 0, 277 675 1, 300 661 1, 321 648 0, 332 648 1, 357 648 0, 361 689 1, 407 689 1, 404 654 0, 395 635 1, 378 602 0, 338 602 1, 311 602 0, 287 616 1, 264 630 1, 244 643 0, 232 643 1, 207 643 0, 203 602 1
+427 53 -9 369 569;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 86 481 1, 89 516 0, 98 535 1, 116 569 0, 156 569 1, 183 569 0, 206 555 1, 229 541 1, 250 528 0, 261 528 1, 286 528 0, 290 569 1, 336 569 1, 333 534 0, 324 515 1, 307 481 0, 267 481 1, 240 481 0, 216 496 1, 194 510 1, 173 522 0, 161 522 1, 137 522 0, 132 481 1
+555 62 -14 492 657;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 162 602 1, 162 657 1, 402 657 1, 402 602 1
+427 53 -9 369 537;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 72 481 1, 72 537 1, 312 537 1, 312 481 1
+555 62 -14 492 722;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 157 722 1, 203 722 1, 211 687 0, 231 672 1, 251 657 0, 282 657 1, 317 657 0, 338 675 1, 354 690 0, 361 722 1, 407 722 1, 401 672 0, 374 641 1, 338 602 0, 282 602 1, 223 602 0, 188 645 1, 163 674 0
+427 53 -9 369 602;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 86 602 1, 132 602 1, 140 567 0, 161 551 1, 180 537 0, 211 537 1, 246 537 0, 267 555 1, 283 570 0, 290 602 1, 336 602 1, 330 551 0, 303 521 1, 267 481 0, 211 481 1, 152 481 0, 117 524 1, 93 553 0
+555 62 -14 492 762;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 282 762 1, 317 762 0, 342 738 1, 367 713 0, 367 678 1, 367 642 0, 342 617 1, 317 592 0, 281 592 1, 250 592 0, 227 612 1, 197 638 0, 197 677 1, 197 713 0, 222 737 1, 247 762 0, 282 730 1, 260 730 0, 245 714 1, 229 699 0, 229 677 1, 229 656 0, 245 640 1, 260 624 0, 281 624 1, 302 624 0, 316 637 1, 335 653 0, 335 678 1, 335 699 0, 319 714 1, 304 730 0
+427 53 -9 369 651;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 192 651 1, 227 651 0, 252 627 1, 277 602 0, 277 567 1, 277 531 0, 252 506 1, 227 481 0, 191 481 1, 160 481 0, 137 501 1, 107 527 0, 107 566 1, 107 602 0, 132 626 1, 156 651 0, 192 619 1, 170 619 0, 154 603 1, 139 588 0, 139 566 1, 139 545 0, 154 529 1, 170 513 0, 191 513 1, 211 513 0, 226 526 1, 245 542 0, 245 567 1, 245 588 0, 229 603 1, 214 619 0
+555 62 -14 492 722;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 187 602 1, 278 722 1, 349 722 1, 229 602 1, 319 602 1, 409 722 1, 481 722 1, 361 602 1
+427 53 -9 403 602;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 109 481 1, 199 602 1, 271 602 1, 151 481 1, 241 481 1, 331 602 1, 403 602 1, 283 481 1
+555 62 -139 492 555;62 555 1, 141 555 1, 141 205 1, 141 146 0, 151 118 1, 160 90 0, 187 71 1, 225 45 0, 288 45 1, 363 45 0, 393 80 1, 423 115 0, 423 202 1, 423 555 1, 492 555 1, 492 203 1, 492 129 0, 477 91 1, 463 52 0, 423 24 1, 370 -14 0, 281 -14 1, 168 -14 0, 115 39 1, 62 91 0, 62 206 1, 300 0 1, 340 0 1, 292 -30 0, 292 -67 1, 292 -103 0, 335 -103 1, 355 -103 0, 369 -98 1, 369 -128 1, 346 -139 0, 317 -139 1, 241 -139 0, 241 -80 1, 241 -34 0
+427 53 -139 384 407;295 0 1, 295 76 1, 268 38 0, 242 19 1, 203 -9 0, 157 -9 1, 53 -9 0, 53 115 1, 53 407 1, 127 407 1, 127 139 1, 127 90 0, 137 72 1, 148 54 0, 176 54 1, 237 54 0, 295 143 1, 295 407 1, 369 407 1, 369 0 1, 315 0 1, 355 0 1, 307 -30 0, 307 -67 1, 307 -103 0, 350 -103 1, 370 -103 0, 384 -98 1, 384 -128 1, 361 -139 0, 332 -139 1, 256 -139 0, 256 -80 1, 256 -34 0
+725 9 0 716 722;152 0 1, 9 555 1, 85 555 1, 199 117 1, 329 555 1, 405 555 1, 530 121 1, 651 555 1, 716 555 1, 560 0 1, 482 0 1, 358 428 1, 230 0 1, 236 602 1, 326 722 1, 408 722 1, 498 602 1, 443 602 1, 367 677 1, 366 677 1, 291 602 1
+555 4 0 549 602;102 0 1, 4 407 1, 77 407 1, 150 101 1, 244 407 1, 318 407 1, 400 99 1, 486 407 1, 549 407 1, 435 0 1, 361 0 1, 275 315 1, 177 0 1, 149 481 1, 240 602 1, 321 602 1, 412 481 1, 356 481 1, 281 557 1, 280 557 1, 205 481 1
+512 11 0 501 722;210 0 1, 210 231 1, 11 555 1, 101 555 1, 259 298 1, 428 555 1, 501 555 1, 289 233 1, 289 0 1, 134 602 1, 224 722 1, 306 722 1, 396 602 1, 341 602 1, 265 677 1, 264 677 1, 189 602 1
+384 7 -148 380 602;152 0 1, 7 407 1, 82 407 1, 193 95 1, 314 407 1, 380 407 1, 164 -148 1, 87 -148 1, 67 481 1, 157 602 1, 239 602 1, 329 481 1, 274 481 1, 198 557 1, 198 557 1, 122 481 1
+469 38 0 431 722;38 0 1, 38 63 1, 336 496 1, 56 496 1, 56 555 1, 431 555 1, 431 496 1, 132 63 1, 431 63 1, 431 0 1, 179 602 1, 269 722 1, 355 722 1, 234 602 1
+384 28 0 356 602;28 0 1, 28 56 1, 261 352 1, 39 352 1, 39 407 1, 352 407 1, 352 352 1, 119 56 1, 356 56 1, 356 0 1, 168 481 1, 259 602 1, 344 602 1, 224 481 1
+469 38 0 431 675;38 0 1, 38 63 1, 336 496 1, 56 496 1, 56 555 1, 431 555 1, 431 496 1, 132 63 1, 431 63 1, 431 0 1, 202 602 1, 202 675 1, 276 675 1, 276 602 1
+384 28 0 356 555;28 0 1, 28 56 1, 261 352 1, 39 352 1, 39 407 1, 352 407 1, 352 352 1, 119 56 1, 356 56 1, 356 0 1, 155 481 1, 155 555 1, 229 555 1, 229 481 1
+469 38 0 431 722;38 0 1, 38 63 1, 336 496 1, 56 496 1, 56 555 1, 431 555 1, 431 496 1, 132 63 1, 431 63 1, 431 0 1, 370 722 1, 280 602 1, 198 602 1, 108 722 1, 163 722 1, 239 646 1, 239 646 1, 315 722 1
+384 28 0 356 602;28 0 1, 28 56 1, 261 352 1, 39 352 1, 39 407 1, 352 407 1, 352 352 1, 119 56 1, 356 56 1, 356 0 1, 323 602 1, 233 481 1, 151 481 1, 61 602 1, 116 602 1, 192 526 1, 192 526 1, 268 602 1
+171 3 0 192 602;54 0 1, 54 352 1, 3 352 1, 3 407 1, 54 407 1, 54 456 1, 54 525 0, 84 563 1, 114 602 0, 167 602 1, 175 602 0, 192 600 1, 192 545 1, 181 546 0, 175 546 1, 128 546 0, 128 464 1, 128 0 1
+512 45 -162 466 569;45 20 1, 45 98 1, 156 45 0, 264 45 1, 385 45 0, 385 135 1, 385 181 0, 352 203 1, 326 220 0, 269 239 1, 193 264 1, 48 311 0, 48 421 1, 48 569 0, 251 569 1, 338 569 0, 432 545 1, 432 473 1, 334 510 0, 246 510 1, 124 510 0, 124 427 1, 124 394 0, 147 374 1, 171 354 0, 230 334 1, 308 309 1, 395 281 0, 431 244 1, 466 207 0, 466 147 1, 466 72 0, 411 29 1, 357 -14 0, 261 -14 1, 167 -14 0, 197 -158 1, 197 -126 1, 218 -129 0, 233 -129 1, 274 -129 0, 274 -104 1, 274 -77 0, 215 -71 1, 215 -42 1, 265 -43 0, 290 -54 1, 325 -69 0, 325 -105 1, 325 -162 0, 243 -162 1, 221 -162 0
+384 44 -162 341 416;44 14 1, 44 82 1, 118 46 0, 181 46 1, 266 46 0, 266 106 1, 266 147 0, 207 167 1, 141 189 1, 46 220 0, 46 303 1, 46 416 0, 201 416 1, 246 416 0, 309 404 1, 309 342 1, 253 361 0, 196 361 1, 119 361 0, 119 310 1, 119 273 0, 172 256 1, 231 237 1, 341 201 0, 341 113 1, 341 57 0, 297 24 1, 254 -9 0, 178 -9 1, 119 -9 0, 128 -158 1, 128 -126 1, 149 -129 0, 164 -129 1, 205 -129 0, 205 -104 1, 205 -77 0, 146 -71 1, 146 -42 1, 196 -43 0, 221 -54 1, 256 -69 0, 256 -105 1, 256 -162 0, 175 -162 1, 153 -162 0
+469 8 -162 461 555;195 0 1, 195 496 1, 8 496 1, 8 555 1, 461 555 1, 461 496 1, 274 496 1, 274 0 1, 177 -158 1, 177 -126 1, 198 -129 0, 213 -129 1, 254 -129 0, 254 -104 1, 254 -77 0, 195 -71 1, 195 -42 1, 245 -43 0, 270 -54 1, 305 -69 0, 305 -105 1, 305 -162 0, 224 -162 1, 201 -162 0
+213 11 -162 210 488;199 -2 1, 176 -9 0, 156 -9 1, 57 -9 0, 57 113 1, 57 352 1, 11 352 1, 11 407 1, 57 407 1, 57 481 1, 131 488 1, 131 407 1, 210 407 1, 210 352 1, 131 352 1, 131 126 1, 131 78 0, 139 62 1, 147 46 0, 174 46 1, 188 46 0, 199 50 1, 64 -158 1, 64 -126 1, 85 -129 0, 100 -129 1, 141 -129 0, 141 -104 1, 141 -77 0, 82 -71 1, 82 -42 1, 132 -43 0, 157 -54 1, 192 -69 0, 192 -105 1, 192 -162 0, 111 -162 1, 89 -162 0
+256 64 -162 192 -42;64 -158 1, 64 -126 1, 85 -129 0, 100 -129 1, 141 -129 0, 141 -104 1, 141 -77 0, 82 -71 1, 82 -42 1, 132 -43 0, 157 -54 1, 192 -69 0, 192 -105 1, 192 -162 0, 111 -162 1, 89 -162 0
+213 70 -120 144 407;70 -120 1, 70 -93 1, 96 -79 0, 96 -9 1, 96 0 1, 70 0 1, 70 74 1, 144 74 1, 144 12 1, 143 -102 0, 70 333 1, 70 407 1, 144 407 1, 144 333 1
+213 60 184 153 277;60 184 1, 60 277 1, 153 277 1, 153 184 1
+256 33 194 223 250;33 194 1, 33 250 1, 223 250 1, 223 194 1
+256 33 194 223 250;33 194 1, 33 250 1, 223 250 1, 223 194 1
+427 38 204 390 250;38 204 1, 38 250 1, 390 250 1, 390 204 1
+768 37 204 731 241;37 204 1, 37 241 1, 731 241 1, 731 204 1
+213 0 0 0 0;
+427 37 546 390 602;37 546 1, 37 602 1, 390 602 1, 390 546 1
+427 32 -9 383 416;307 248 1, 306 284 0, 299 303 1, 280 361 0, 215 361 1, 169 361 0, 143 334 1, 117 308 0, 111 248 1, 380 72 1, 380 13 1, 304 -9 0, 240 -9 1, 145 -9 0, 89 50 1, 32 109 0, 32 209 1, 32 304 0, 82 360 1, 132 416 0, 216 416 1, 314 416 0, 354 347 1, 383 296 0, 382 215 1, 382 192 1, 110 192 1, 114 147 0, 125 124 1, 158 47 0, 256 47 1, 312 47 0
+449 39 194 409 250;39 194 1, 39 250 1, 409 250 1, 409 194 1
+128 -165 -14 293 569;-165 -14 1, 243 569 1, 293 569 1, -114 -14 1
+213 60 184 153 277;60 184 1, 60 277 1, 153 277 1, 153 184 1
+384 12 0 336 602;66 0 1, 66 352 1, 12 352 1, 12 407 1, 66 407 1, 66 456 1, 66 602 0, 181 602 1, 206 602 0, 236 592 1, 236 533 1, 209 546 0, 189 546 1, 162 546 0, 151 528 1, 140 510 0, 140 464 1, 140 407 1, 336 407 1, 336 0 1, 262 0 1, 262 352 1, 140 352 1, 140 0 1, 262 481 1, 262 555 1, 336 555 1, 336 481 1
+384 12 0 336 602;66 0 1, 66 352 1, 12 352 1, 12 407 1, 66 407 1, 66 456 1, 66 602 0, 179 602 1, 262 592 1, 336 592 1, 336 0 1, 262 0 1, 262 537 1, 246 540 1, 214 546 0, 192 546 1, 159 546 0, 148 524 1, 140 505 0, 140 464 1, 140 407 1, 206 407 1, 206 352 1, 140 352 1, 140 0 1
+256 1 222 251 555;154 222 1, 154 313 1, 1 313 1, 1 356 1, 152 555 1, 205 555 1, 205 357 1, 251 357 1, 251 313 1, 205 313 1, 205 222 1, 50 357 1, 154 357 1, 154 493 1
+171 -58 -157 124 407;-58 -145 1, -58 -87 1, -28 -102 0, -2 -102 1, 35 -102 0, 43 -74 1, 50 -51 0, 50 0 1, 50 407 1, 124 407 1, 124 0 1, 124 -157 0, 4 -157 1, -29 -157 0
+213 0 0 0 0;
diff --git a/vendor/github.com/golang/freetype/testdata/luxisr-12pt-with-hinting.txt b/vendor/github.com/golang/freetype/testdata/luxisr-12pt-with-hinting.txt
new file mode 100644
index 000000000..9c30f6773
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luxisr-12pt-with-hinting.txt
@@ -0,0 +1,392 @@
+freetype version 2.5.1
+192 0 0 192 576;0 0 1, 0 576 1, 192 576 1, 192 0 1, 128 64 1, 128 512 1, 64 512 1, 64 64 1
+0 0 0 0 0;
+192 0 0 0 0;
+192 0 0 0 0;
+192 64 0 128 576;64 0 1, 64 64 1, 128 64 1, 128 0 1, 72 128 1, 64 454 1, 64 576 1, 128 576 1, 128 454 1, 120 128 1
+256 0 384 256 576;44 384 1, 35 576 1, 108 576 1, 99 384 1, 173 384 1, 164 576 1, 238 576 1, 229 384 1
+448 0 0 448 576;47 25 1, 89 192 1, 9 192 1, 18 256 1, 100 256 1, 133 320 1, 44 320 1, 54 384 1, 144 384 1, 186 551 1, 234 551 1, 192 384 1, 291 384 1, 332 551 1, 380 551 1, 339 384 1, 418 384 1, 409 320 1, 327 320 1, 294 256 1, 383 256 1, 374 192 1, 283 192 1, 242 25 1, 194 25 1, 235 192 1, 137 192 1, 95 25 1, 148 256 1, 247 256 1, 279 320 1, 180 320 1
+448 64 -64 320 640;192 -46 1, 192 0 1, 135 0 0, 64 31 1, 64 95 1, 137 56 0, 192 56 1, 192 255 1, 124 298 0, 96 331 1, 64 368 0, 64 422 1, 64 486 0, 110 524 1, 142 550 0, 192 555 1, 192 602 1, 256 602 1, 256 555 1, 285 555 0, 320 530 1, 320 470 1, 282 500 0, 256 504 1, 256 307 1, 258 304 1, 263 298 0, 267 293 1, 270 290 1, 293 262 0, 305 237 1, 320 205 0, 320 155 1, 320 87 0, 297 42 1, 282 12 0, 256 0 1, 256 -46 1, 256 60 1, 256 85 0, 256 144 1, 256 175 0, 256 195 1, 256 210 0, 256 233 1, 192 331 1, 192 502 1, 128 479 0, 128 425 1, 128 376 0
+704 64 0 640 576;94 0 1, 531 576 1, 589 576 1, 152 0 1, 160 576 1, 204 576 0, 230 542 1, 256 507 0, 256 448 1, 256 389 0, 230 355 1, 204 320 0, 160 320 1, 115 320 0, 90 355 1, 64 389 0, 64 450 1, 64 502 0, 85 535 1, 112 576 0, 160 512 1, 146 512 0, 137 495 1, 128 477 0, 128 449 1, 128 422 0, 135 405 1, 144 384 0, 160 384 1, 174 384 0, 183 402 1, 192 419 0, 192 448 1, 192 477 0, 183 494 1, 174 512 0, 512 320 1, 571 320 0, 606 277 1, 640 234 0, 640 160 1, 640 86 0, 606 43 1, 571 0 0, 512 0 1, 453 0 0, 418 43 1, 384 86 0, 384 162 1, 384 228 0, 412 269 1, 448 320 0, 512 256 1, 483 256 0, 466 230 1, 448 203 0, 448 162 1, 448 122 0, 462 96 1, 480 64 0, 512 64 1, 541 64 0, 558 91 1, 576 117 0, 576 160 1, 576 203 0, 558 229 1, 541 256 0
+512 0 0 512 576;384 0 1, 357 35 1, 277 0 0, 205 0 1, 118 0 0, 59 52 1, 0 105 0, 0 185 1, 0 264 0, 56 313 1, 89 341 0, 152 363 1, 128 420 0, 128 461 1, 128 513 0, 163 545 1, 199 576 0, 260 576 1, 317 576 0, 351 548 1, 384 519 0, 384 472 1, 384 419 0, 335 381 1, 305 358 0, 248 337 1, 311 214 0, 373 133 1, 410 185 0, 410 287 1, 410 320 1, 483 320 1, 483 179 0, 408 90 1, 441 44 0, 485 0 1, 325 82 1, 251 173 0, 178 321 1, 127 303 0, 102 281 1, 64 249 0, 64 203 1, 64 145 0, 107 104 1, 151 64 0, 212 64 1, 260 64 0, 220 383 1, 266 396 0, 288 411 1, 320 433 0, 320 464 1, 320 512 0, 258 512 1, 192 512 0, 192 461 1, 192 431 0, 217 388 1
+128 0 384 128 576;45 384 1, 27 576 1, 120 576 1, 101 384 1
+256 64 -128 256 640;225 -60 1, 225 -111 1, 156 -58 0, 117 21 1, 64 123 0, 64 241 1, 64 364 0, 121 469 1, 160 541 0, 225 592 1, 225 541 1, 177 485 0, 155 426 1, 128 353 0, 128 241 1, 128 124 0, 158 48 1, 180 -7 0
+256 0 -128 192 640;31 541 1, 31 592 1, 100 539 0, 140 460 1, 192 358 0, 192 241 1, 192 117 0, 135 12 1, 96 -60 0, 31 -111 1, 31 -60 1, 79 -3 0, 101 55 1, 128 129 0, 128 241 1, 128 357 0, 98 433 1, 77 487 0
+320 0 256 320 576;267 483 1, 284 415 1, 180 383 1, 180 384 1, 180 389 0, 192 390 1, 192 390 1, 192 411 0, 170 423 1, 255 296 1, 210 266 1, 152 360 1, 171 362 0, 178 378 1, 88 266 1, 43 296 1, 120 378 1, 128 362 0, 147 360 1, 15 415 1, 32 483 1, 129 423 1, 118 410 0, 118 389 1, 118 389 1, 118 389 0, 118 387 1, 119 386 1, 119 384 0, 119 383 1, 122 576 1, 177 576 1, 165 427 1, 157 448 0, 149 448 1, 140 448 0, 133 427 1
+448 64 64 384 384;192 64 1, 192 192 1, 64 192 1, 64 256 1, 192 256 1, 192 384 1, 256 384 1, 256 256 1, 384 256 1, 384 192 1, 256 192 1, 256 64 1
+192 64 -192 128 64;64 -149 1, 64 -121 1, 89 -111 0, 89 -36 1, 89 -29 1, 64 -29 1, 64 64 1, 128 64 1, 128 -16 1, 128 -139 0
+256 64 192 192 256;64 192 1, 64 256 1, 192 256 1, 192 192 1
+192 64 0 128 64;64 0 1, 64 64 1, 128 64 1, 128 0 1
+192 -64 -128 256 576;-22 -128 1, 178 576 1, 236 576 1, 36 -128 1
+448 0 0 384 576;192 576 1, 280 576 0, 332 499 1, 384 422 0, 384 289 1, 384 154 0, 332 77 1, 280 0 0, 190 0 1, 112 0 0, 63 63 1, 0 142 0, 0 289 1, 0 422 0, 52 499 1, 104 576 0, 192 512 1, 130 512 0, 97 454 1, 64 395 0, 64 288 1, 64 183 0, 97 123 1, 130 64 0, 192 64 1, 248 64 0, 279 107 1, 320 165 0, 320 289 1, 320 397 0, 287 454 1, 252 512 0
+448 64 0 384 640;64 0 1, 64 64 1, 192 64 1, 192 502 1, 64 474 1, 64 531 1, 256 577 1, 256 64 1, 384 64 1, 384 0 1
+448 64 0 320 576;64 0 1, 64 64 1, 85 124 0, 134 187 1, 167 228 1, 197 266 1, 256 339 0, 256 414 1, 256 466 0, 232 491 1, 213 512 0, 178 512 1, 133 512 0, 64 486 1, 64 554 1, 129 576 0, 185 576 1, 247 576 0, 283 533 1, 320 490 0, 320 418 1, 320 368 0, 301 330 1, 282 290 0, 230 234 1, 208 211 1, 142 139 0, 129 64 1, 320 64 1, 320 0 1
+448 64 0 384 576;64 4 1, 64 76 1, 67 76 1, 78 74 0, 83 74 1, 129 68 0, 146 66 1, 173 64 0, 196 64 1, 260 64 0, 292 94 1, 320 119 0, 320 167 1, 320 222 0, 272 251 1, 225 280 0, 137 280 1, 108 280 1, 108 332 1, 131 332 1, 191 333 0, 223 360 1, 256 387 0, 256 435 1, 256 512 0, 172 512 1, 129 512 0, 64 500 1, 64 568 1, 126 576 0, 174 576 1, 257 576 0, 293 534 1, 320 502 0, 320 450 1, 320 391 0, 287 353 1, 267 331 0, 228 312 1, 278 301 0, 303 288 1, 384 248 0, 384 165 1, 384 90 0, 332 45 1, 279 0 0, 194 0 1, 148 0 0
+448 0 0 384 576;256 0 1, 256 128 1, 0 128 1, 0 187 1, 256 576 1, 320 576 1, 320 192 1, 384 192 1, 384 128 1, 320 128 1, 320 0 1, 75 192 1, 256 192 1, 256 473 1
+448 64 -64 320 576;64 -2 1, 64 67 1, 113 64 0, 154 64 1, 202 64 0, 229 98 1, 256 132 0, 256 189 1, 256 320 0, 102 320 1, 83 320 0, 64 297 1, 64 576 1, 320 576 1, 320 512 1, 128 512 1, 128 359 1, 212 357 0, 259 319 1, 320 269 0, 320 173 1, 320 92 0, 274 46 1, 227 0 0, 146 0 1, 111 0 0
+448 64 0 384 576;141 303 1, 187 384 0, 253 384 1, 314 384 0, 349 336 1, 384 288 0, 384 203 1, 384 110 0, 342 55 1, 300 0 0, 229 0 1, 152 0 0, 108 72 1, 64 144 0, 64 270 1, 64 414 0, 121 495 1, 179 576 0, 281 576 1, 327 576 0, 384 569 1, 384 502 1, 316 512 0, 278 512 1, 195 512 0, 162 434 1, 149 403 0, 144 364 1, 142 344 0, 229 320 1, 184 320 0, 156 288 1, 128 257 0, 128 203 1, 128 143 0, 157 103 1, 185 64 0, 231 64 1, 320 64 0, 320 187 1, 320 320 0
+448 64 0 384 576;93 0 1, 103 68 0, 121 118 1, 139 168 0, 185 255 1, 321 512 1, 64 512 1, 64 576 1, 384 576 1, 384 512 1, 192 180 0, 169 0 1
+448 64 0 384 576;147 313 1, 110 339 0, 91 363 1, 64 398 0, 64 438 1, 64 499 0, 110 537 1, 156 576 0, 230 576 1, 299 576 0, 342 543 1, 384 511 0, 384 457 1, 384 410 0, 347 367 1, 325 341 0, 283 313 1, 328 284 0, 351 254 1, 384 211 0, 384 155 1, 384 87 0, 338 43 1, 293 0 0, 221 0 1, 150 0 0, 107 41 1, 64 82 0, 64 150 1, 64 210 0, 94 257 1, 113 285 0, 242 338 1, 320 387 0, 320 441 1, 320 473 0, 294 493 1, 267 512 0, 222 512 1, 180 512 0, 154 494 1, 128 476 0, 128 445 1, 128 409 0, 173 378 1, 195 362 0, 188 282 1, 156 252 0, 143 229 1, 128 204 0, 128 165 1, 128 120 0, 155 92 1, 181 64 0, 225 64 1, 267 64 0, 293 88 1, 320 111 0, 320 149 1, 320 183 0, 298 206 1, 280 225 0, 236 253 1
+448 64 0 384 576;308 273 1, 262 192 0, 195 192 1, 134 192 0, 99 240 1, 64 288 0, 64 373 1, 64 466 0, 106 521 1, 148 576 0, 218 576 1, 296 576 0, 340 504 1, 384 432 0, 384 306 1, 384 162 0, 327 81 1, 269 0 0, 168 0 1, 120 0 0, 64 7 1, 64 74 1, 133 64 0, 171 64 1, 254 64 0, 287 143 1, 300 173 0, 305 212 1, 307 232 0, 217 512 1, 128 512 0, 128 390 1, 128 256 0, 219 256 1, 264 256 0, 292 288 1, 320 320 0, 320 374 1, 320 433 0, 291 473 1, 262 512 0
+192 64 0 128 384;64 0 1, 64 64 1, 128 64 1, 128 0 1, 64 320 1, 64 384 1, 128 384 1, 128 320 1
+192 64 -128 128 384;64 -120 1, 64 -93 1, 87 -79 0, 87 -9 1, 87 0 1, 64 0 1, 64 64 1, 128 64 1, 128 10 1, 128 -102 0, 64 320 1, 64 384 1, 128 384 1, 128 320 1
+448 0 0 384 448;384 37 1, 14 222 1, 384 407 1, 384 345 1, 139 222 1, 139 222 1, 384 99 1
+448 64 128 384 320;64 128 1, 64 192 1, 384 192 1, 384 128 1, 64 256 1, 64 320 1, 384 320 1, 384 256 1
+448 64 0 448 448;64 407 1, 434 222 1, 64 37 1, 64 99 1, 309 222 1, 309 222 1, 64 345 1
+448 64 0 384 576;128 0 1, 128 64 1, 192 64 1, 192 0 1, 128 128 1, 128 150 1, 128 246 0, 201 297 1, 241 324 1, 320 377 0, 320 435 1, 320 512 0, 215 512 1, 150 512 0, 64 500 1, 64 568 1, 145 576 0, 213 576 1, 287 576 0, 330 550 1, 384 515 0, 384 441 1, 384 366 0, 301 319 1, 266 299 1, 222 275 0, 207 248 1, 192 222 0, 192 173 1, 192 128 1
+768 64 0 704 576;470 17 1, 394 0 0, 325 0 1, 213 0 0, 138 64 1, 64 129 0, 64 229 1, 64 365 0, 177 471 1, 291 576 0, 439 576 1, 553 576 0, 628 510 1, 704 444 0, 704 346 1, 704 255 0, 647 191 1, 591 128 0, 511 128 1, 448 128 0, 448 167 1, 448 180 0, 451 202 1, 458 245 1, 453 245 1, 424 192 0, 398 166 1, 361 128 0, 320 128 1, 256 128 0, 256 210 1, 256 301 0, 312 374 1, 368 448 0, 439 448 1, 447 448 0, 461 448 1, 465 448 0, 469 448 1, 483 448 0, 492 448 1, 543 448 1, 513 235 1, 512 225 0, 512 215 1, 512 192 0, 536 192 1, 576 192 0, 608 237 1, 640 283 0, 640 341 1, 640 415 0, 581 463 1, 521 512 0, 430 512 1, 312 512 0, 220 428 1, 128 344 0, 128 238 1, 128 160 0, 188 112 1, 247 64 0, 339 64 1, 398 64 0, 456 56 1, 462 318 1, 477 393 1, 447 384 0, 426 384 1, 380 384 0, 350 341 1, 320 298 0, 320 237 1, 320 192 0, 345 192 1, 387 192 0
+512 0 0 512 576;7 0 1, 218 576 1, 296 576 1, 503 0 1, 419 0 1, 361 128 1, 138 128 1, 80 0 1, 161 192 1, 339 192 1, 250 458 1
+512 64 0 448 576;64 0 1, 64 576 1, 227 576 1, 348 576 0, 398 546 1, 448 516 0, 448 443 1, 448 377 0, 396 336 1, 364 311 0, 304 292 1, 369 272 0, 401 244 1, 448 204 0, 448 140 1, 448 80 0, 410 41 1, 383 13 0, 340 6 1, 305 0 0, 247 0 1, 128 64 1, 186 64 1, 308 64 0, 346 80 1, 384 95 0, 384 144 1, 384 199 0, 335 227 1, 285 256 0, 192 256 1, 128 256 1, 128 320 1, 195 320 1, 384 320 0, 384 430 1, 384 486 0, 330 501 1, 288 512 0, 201 512 1, 128 512 1
+576 64 0 512 576;512 30 1, 429 0 0, 334 0 1, 202 0 0, 133 73 1, 64 147 0, 64 287 1, 64 427 0, 134 502 1, 205 576 0, 338 576 1, 413 576 0, 512 566 1, 512 489 1, 394 512 0, 326 512 1, 230 512 0, 179 454 1, 128 396 0, 128 287 1, 128 180 0, 182 122 1, 237 64 0, 335 64 1, 417 64 0, 512 100 1
+576 64 0 512 576;64 0 1, 64 576 1, 227 576 1, 512 576 0, 512 301 1, 512 158 0, 438 79 1, 364 0 0, 228 0 1, 128 64 1, 223 64 1, 448 64 0, 448 292 1, 448 426 0, 360 481 1, 335 497 0, 299 504 1, 257 512 0, 186 512 1, 128 512 1
+512 64 0 512 576;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1
+448 64 0 448 576;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 384 320 1, 384 256 1, 128 256 1, 128 0 1
+576 64 0 512 576;512 256 1, 512 14 1, 418 0 0, 330 0 1, 64 0 0, 64 286 1, 64 426 0, 133 501 1, 202 576 0, 332 576 1, 416 576 0, 512 564 1, 512 485 1, 398 512 0, 323 512 1, 128 512 0, 128 289 1, 128 180 0, 183 122 1, 238 64 0, 340 64 1, 382 64 0, 448 57 1, 448 192 1, 384 192 1, 384 256 1
+576 64 0 512 576;64 0 1, 64 576 1, 128 576 1, 128 320 1, 448 320 1, 448 576 1, 512 576 1, 512 0 1, 448 0 1, 448 256 1, 128 256 1, 128 0 1
+192 64 0 128 576;64 0 1, 64 576 1, 128 576 1, 128 0 1
+384 0 -128 320 576;0 -87 1, 0 -19 1, 75 -64 0, 141 -64 1, 216 -64 0, 238 -29 1, 256 0 0, 256 71 1, 256 576 1, 320 576 1, 320 73 1, 320 -128 0, 125 -128 1, 60 -128 0
+512 64 0 512 576;64 0 1, 64 576 1, 128 576 1, 128 293 1, 359 576 1, 438 576 1, 214 301 1, 476 0 1, 377 0 1, 128 292 1, 128 0 1
+448 64 0 384 576;64 0 1, 64 576 1, 128 576 1, 128 64 1, 384 64 1, 384 0 1
+640 64 0 576 576;64 0 1, 64 576 1, 170 576 1, 327 151 1, 487 576 1, 576 576 1, 576 0 1, 512 0 1, 512 473 1, 357 64 1, 279 64 1, 128 475 1, 128 0 1
+576 64 0 512 576;64 0 1, 64 576 1, 138 576 1, 448 131 1, 448 576 1, 512 576 1, 512 0 1, 437 0 1, 128 445 1, 128 0 1
+576 64 0 576 576;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0
+512 64 0 512 576;64 0 1, 64 576 1, 267 576 1, 365 576 0, 408 565 1, 451 553 0, 478 520 1, 512 479 0, 512 408 1, 512 192 0, 244 192 1, 128 192 1, 128 0 1, 128 256 1, 240 256 1, 448 256 0, 448 402 1, 448 473 0, 394 494 1, 348 512 0, 242 512 1, 128 512 1
+576 64 -128 640 576;615 -48 1, 565 -111 1, 434 -68 0, 346 -10 1, 311 0 0, 293 0 1, 193 0 0, 128 81 1, 64 161 0, 64 289 1, 64 419 0, 133 497 1, 203 576 0, 319 576 1, 436 576 0, 506 495 1, 576 415 0, 576 280 1, 576 162 0, 517 87 1, 494 58 0, 464 38 1, 449 27 0, 418 11 1, 510 -30 0, 318 512 1, 229 512 0, 179 452 1, 128 393 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 409 64 0, 460 123 1, 512 181 0, 512 286 1, 512 383 0, 471 441 1, 420 512 0
+576 64 0 576 576;64 0 1, 64 576 1, 281 576 1, 448 576 0, 448 439 1, 448 372 0, 408 329 1, 384 303 0, 340 283 1, 525 0 1, 428 0 1, 271 256 1, 128 256 1, 128 0 1, 128 320 1, 216 320 1, 303 320 0, 343 346 1, 384 373 0, 384 429 1, 384 474 0, 351 493 1, 318 512 0, 241 512 1, 128 512 1
+512 64 0 512 576;64 21 1, 64 102 1, 189 64 0, 311 64 1, 448 64 0, 448 152 1, 448 197 0, 410 218 1, 381 235 0, 315 253 1, 229 278 1, 64 324 0, 64 431 1, 64 576 0, 267 576 1, 355 576 0, 448 566 1, 448 491 1, 347 512 0, 255 512 1, 128 512 0, 128 431 1, 128 399 0, 154 379 1, 180 359 0, 247 340 1, 334 316 1, 432 288 0, 472 252 1, 512 216 0, 512 156 1, 512 84 0, 454 42 1, 396 0 0, 294 0 1, 193 0 0
+448 0 0 448 576;192 0 1, 192 512 1, 0 512 1, 0 576 1, 448 576 1, 448 512 1, 256 512 1, 256 0 1
+576 64 0 512 576;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1
+512 0 0 512 576;228 0 1, 14 576 1, 95 576 1, 272 103 1, 441 576 1, 508 576 1, 302 0 1
+704 0 0 768 576;152 0 1, 9 576 1, 85 576 1, 199 121 1, 329 576 1, 405 576 1, 530 125 1, 651 576 1, 716 576 1, 560 0 1, 482 0 1, 358 444 1, 230 0 1
+512 0 0 512 576;11 0 1, 215 286 1, 20 576 1, 113 576 1, 263 352 1, 423 576 1, 498 576 1, 299 300 1, 502 0 1, 409 0 1, 251 233 1, 85 0 1
+512 -64 0 512 576;192 0 1, 192 240 1, -7 576 1, 83 576 1, 232 309 1, 395 576 1, 468 576 1, 256 242 1, 256 0 1
+448 64 0 448 576;64 0 1, 64 64 1, 351 512 1, 64 512 1, 64 576 1, 448 576 1, 448 512 1, 142 64 1, 448 64 1, 448 0 1
+192 64 -128 192 576;64 -128 1, 64 576 1, 192 576 1, 192 512 1, 128 512 1, 128 -64 1, 192 -64 1, 192 -128 1
+192 -64 -128 256 576;236 -128 1, 178 -128 1, -22 576 1, 36 576 1
+192 0 -128 128 576;128 576 1, 128 -128 1, 0 -128 1, 0 -64 1, 64 -64 1, 64 512 1, 0 512 1, 0 576 1
+384 0 192 384 576;180 401 1, 75 192 1, 14 192 1, 180 525 1, 347 192 1, 284 192 1
+448 0 -64 448 0;0 -64 1, 0 0 1, 448 0 1, 448 -64 1
+256 0 512 256 576;216 512 1, 160 512 1, 40 576 1, 125 576 1
+448 0 0 448 384;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0
+448 64 -64 384 576;128 249 1, 128 53 1, 182 64 0, 209 64 1, 320 64 0, 320 199 1, 320 256 0, 298 288 1, 276 320 0, 239 320 1, 190 320 0, 128 312 1, 148 344 0, 171 361 1, 204 384 0, 247 384 1, 308 384 0, 346 334 1, 384 285 0, 384 202 1, 384 106 0, 335 53 1, 286 0 0, 197 0 1, 164 0 0, 128 0 1, 64 -5 1, 64 576 1, 128 576 1
+384 0 0 320 384;320 11 1, 251 0 0, 190 0 1, 104 0 0, 52 53 1, 0 107 0, 0 192 1, 0 282 0, 54 333 1, 108 384 0, 205 384 1, 254 384 0, 320 380 1, 320 322 1, 251 320 0, 209 320 1, 64 320 0, 64 191 1, 64 130 0, 101 97 1, 137 64 0, 203 64 1, 253 64 0, 320 72 1
+448 64 0 384 576;320 135 1, 320 331 1, 265 320 0, 239 320 1, 128 320 0, 128 185 1, 128 129 0, 150 96 1, 172 64 0, 209 64 1, 258 64 0, 320 72 1, 300 40 0, 277 23 1, 245 0 0, 201 0 1, 140 0 0, 102 50 1, 64 100 0, 64 182 1, 64 278 0, 113 331 1, 162 384 0, 251 384 1, 285 384 0, 320 384 1, 320 576 1, 384 576 1, 384 0 1, 320 0 1
+448 64 0 448 384;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0
+192 0 0 256 576;64 0 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 433 1, 64 576 0, 194 576 1, 221 576 0, 256 569 1, 256 510 1, 219 512 0, 193 512 1, 157 512 0, 142 496 1, 128 481 0, 128 441 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 0 1
+448 64 -192 384 384;320 153 1, 320 331 1, 265 320 0, 240 320 1, 128 320 0, 128 190 1, 128 132 0, 150 98 1, 172 64 0, 209 64 1, 258 64 0, 320 90 1, 300 50 0, 277 29 1, 245 0 0, 202 0 1, 140 0 0, 102 52 1, 64 103 0, 64 186 1, 64 280 0, 113 332 1, 162 384 0, 250 384 1, 285 384 0, 320 384 1, 384 384 1, 384 105 1, 384 22 0, 374 -18 1, 348 -128 0, 194 -128 1, 130 -128 0, 64 -135 1, 64 -71 1, 143 -64 0, 198 -64 1, 320 -64 0, 320 29 1
+448 64 0 384 576;64 0 1, 64 576 1, 128 576 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 254 1, 320 293 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1
+192 64 0 128 576;64 0 1, 64 384 1, 128 384 1, 128 0 1, 64 512 1, 64 576 1, 128 576 1, 128 512 1
+192 -64 -192 128 576;-64 -145 1, -64 -87 1, -28 -64 0, 3 -64 1, 46 -64 0, 56 -47 1, 64 -32 0, 64 0 1, 64 384 1, 128 384 1, 128 0 1, 128 -128 0, 2 -128 1, -33 -128 0, 64 512 1, 64 576 1, 128 576 1, 128 512 1
+384 64 0 384 576;64 0 1, 64 576 1, 128 576 1, 128 198 1, 265 384 1, 335 384 1, 205 203 1, 374 0 1, 284 0 1, 128 197 1, 128 0 1
+192 64 0 128 576;64 0 1, 64 576 1, 128 576 1, 128 0 1
+640 64 0 576 384;64 0 1, 64 384 1, 128 384 1, 128 312 1, 156 353 0, 173 368 1, 194 384 0, 227 384 1, 268 384 0, 294 357 1, 309 342 0, 320 312 1, 357 354 0, 380 368 1, 408 384 0, 453 384 1, 576 384 0, 576 279 1, 576 0 1, 493 0 1, 493 257 1, 493 320 0, 432 320 1, 378 320 0, 320 257 1, 320 0 1, 256 0 1, 256 268 1, 256 320 0, 211 320 1, 171 320 0, 128 257 1, 128 0 1
+448 64 0 384 384;64 0 1, 64 384 1, 128 384 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 253 1, 320 292 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1
+448 64 0 384 384;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0
+448 64 -128 384 384;128 -128 1, 64 -128 1, 64 384 1, 128 384 1, 128 312 1, 148 344 0, 171 361 1, 203 384 0, 247 384 1, 308 384 0, 346 334 1, 384 285 0, 384 202 1, 384 106 0, 335 53 1, 286 0 0, 197 0 1, 164 0 0, 128 0 1, 128 249 1, 128 53 1, 182 64 0, 209 64 1, 320 64 0, 320 199 1, 320 256 0, 298 288 1, 276 320 0, 239 320 1, 190 320 0
+448 64 -128 384 384;320 384 1, 384 384 1, 384 -128 1, 320 -128 1, 320 72 1, 300 40 0, 277 23 1, 245 0 0, 201 0 1, 140 0 0, 102 50 1, 64 100 0, 64 182 1, 64 278 0, 113 331 1, 162 384 0, 251 384 1, 285 384 0, 320 135 1, 320 331 1, 265 320 0, 239 320 1, 128 320 0, 128 185 1, 128 129 0, 150 96 1, 172 64 0, 209 64 1, 258 64 0
+256 64 0 256 448;64 0 1, 64 384 1, 128 384 1, 128 312 1, 145 345 0, 165 361 1, 194 384 0, 233 384 1, 241 384 0, 256 391 1, 256 326 1, 235 320 0, 222 320 1, 178 320 0, 128 253 1, 128 0 1
+384 64 0 320 384;64 13 1, 64 77 1, 128 64 0, 183 64 1, 256 64 0, 256 116 1, 256 152 0, 204 168 1, 147 187 1, 64 214 0, 64 286 1, 64 384 0, 215 384 1, 258 384 0, 320 381 1, 320 323 1, 263 320 0, 206 320 1, 128 320 0, 128 276 1, 128 244 0, 174 230 1, 225 213 1, 320 182 0, 320 106 1, 320 57 0, 283 29 1, 245 0 0, 180 0 1, 129 0 0
+192 0 -64 192 512;192 -2 1, 172 0 0, 154 0 1, 64 0 0, 64 103 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 458 1, 128 465 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 115 1, 128 84 0, 136 74 1, 144 64 0, 168 64 1, 182 64 0, 192 45 1
+448 64 0 384 384;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1
+384 0 0 384 384;152 0 1, 7 384 1, 82 384 1, 195 85 1, 314 384 1, 380 384 1, 225 0 1
+576 0 0 576 384;102 0 1, 4 384 1, 77 384 1, 150 95 1, 244 384 1, 318 384 1, 400 94 1, 486 384 1, 549 384 1, 435 0 1, 361 0 1, 275 297 1, 177 0 1
+384 0 0 384 384;11 0 1, 143 203 1, 15 384 1, 101 384 1, 203 240 1, 294 384 1, 362 384 1, 238 191 1, 372 0 1, 287 0 1, 177 154 1, 79 0 1
+384 0 -128 384 384;152 0 1, 7 384 1, 82 384 1, 193 90 1, 314 384 1, 380 384 1, 164 -128 1, 87 -128 1
+384 0 0 384 384;0 0 1, 0 64 1, 291 320 1, 64 320 1, 64 384 1, 384 384 1, 384 320 1, 145 64 1, 384 64 1, 384 0 1
+256 0 -128 192 640;0 269 1, 22 269 1, 64 269 0, 64 330 1, 64 354 0, 64 382 1, 64 414 1, 64 447 0, 64 476 1, 64 537 0, 109 569 1, 141 591 0, 192 592 1, 192 537 1, 173 537 1, 153 537 0, 141 524 1, 128 510 0, 128 490 1, 128 483 0, 128 455 1, 128 417 1, 128 391 0, 128 361 1, 128 290 0, 80 241 1, 128 192 0, 128 120 1, 128 90 0, 128 65 1, 128 26 1, 128 -1 0, 128 -9 1, 128 -29 0, 141 -43 1, 154 -56 0, 173 -56 1, 192 -56 1, 192 -111 1, 139 -110 0, 106 -85 1, 64 -52 0, 64 6 1, 64 35 0, 64 67 1, 64 100 1, 64 127 0, 64 152 1, 64 213 0, 22 213 1, 0 213 1
+192 64 -128 128 576;64 -128 1, 64 576 1, 128 576 1, 128 -128 1
+256 64 -128 256 640;256 213 1, 234 213 1, 192 213 0, 192 152 1, 192 124 0, 192 100 1, 192 67 1, 192 36 0, 192 6 1, 192 -55 0, 146 -88 1, 114 -110 0, 64 -111 1, 64 -56 1, 82 -56 1, 102 -56 0, 115 -43 1, 128 -29 0, 128 -9 1, 128 1 0, 128 26 1, 128 65 1, 128 88 0, 128 120 1, 128 192 0, 176 241 1, 154 263 0, 144 285 1, 128 318 0, 128 361 1, 128 393 0, 128 417 1, 128 455 1, 128 480 0, 128 491 1, 128 510 0, 115 524 1, 102 537 0, 82 537 1, 64 537 1, 64 592 1, 117 591 0, 150 566 1, 192 534 0, 192 475 1, 192 445 0, 192 414 1, 192 382 1, 192 357 0, 192 329 1, 192 269 0, 234 269 1, 256 269 1
+448 0 192 448 256;95 192 1, 39 192 1, 40 213 0, 47 223 1, 69 256 0, 139 256 1, 176 256 0, 214 256 1, 256 256 1, 280 256 1, 291 256 0, 309 256 1, 352 256 0, 354 256 1, 409 256 1, 408 235 0, 401 225 1, 379 192 0, 310 192 1, 273 192 0, 235 192 1, 193 192 1, 168 192 1, 158 192 0, 140 192 1, 96 192 0
+512 -64 0 576 640;-15 0 1, 196 576 1, 316 576 1, 524 0 1, 439 0 1, 381 128 1, 116 128 1, 58 0 1, 138 192 1, 360 192 1, 246 458 1, 128 576 1, 128 640 1, 192 640 1, 192 576 1, 320 576 1, 320 640 1, 384 640 1, 384 576 1
+512 0 0 512 768;7 0 1, 218 576 1, 296 576 1, 503 0 1, 419 0 1, 361 128 1, 138 128 1, 80 0 1, 161 192 1, 339 192 1, 250 458 1, 256 768 1, 283 768 0, 301 740 1, 320 712 0, 320 672 1, 320 632 0, 301 604 1, 282 576 0, 255 576 1, 232 576 0, 215 599 1, 192 628 0, 192 672 1, 192 712 0, 211 740 1, 229 768 0, 256 704 1, 256 704 0, 256 695 1, 256 686 0, 256 672 1, 256 659 0, 256 650 1, 256 640 0, 256 640 1, 256 640 0, 256 648 1, 256 657 0, 256 672 1, 256 686 0, 256 695 1, 256 704 0
+576 64 -192 512 576;512 30 1, 429 0 0, 334 0 1, 202 0 0, 133 73 1, 64 147 0, 64 287 1, 64 427 0, 134 502 1, 205 576 0, 338 576 1, 413 576 0, 512 566 1, 512 489 1, 394 512 0, 326 512 1, 230 512 0, 179 454 1, 128 396 0, 128 287 1, 128 180 0, 182 122 1, 237 64 0, 335 64 1, 417 64 0, 512 100 1, 293 0 1, 330 0 1, 307 -41 1, 336 -42 0, 356 -59 1, 384 -82 0, 384 -116 1, 384 -148 0, 361 -170 1, 338 -192 0, 306 -192 1, 280 -192 0, 250 -154 1, 250 -124 1, 267 -128 0, 285 -128 1, 320 -128 0, 320 -101 1, 320 -67 0, 258 -66 1
+512 64 0 512 704;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 211 576 1, 311 704 1, 407 704 1, 273 576 1
+576 64 0 512 768;64 0 1, 64 576 1, 138 576 1, 448 131 1, 448 576 1, 512 576 1, 512 0 1, 437 0 1, 128 445 1, 128 0 1, 163 623 1, 166 656 0, 176 673 1, 195 704 0, 239 704 1, 268 704 0, 293 704 1, 318 704 1, 341 704 0, 353 704 1, 380 704 0, 384 710 1, 434 710 1, 431 682 0, 421 667 1, 403 640 0, 359 640 1, 329 640 0, 304 640 1, 279 640 1, 257 640 0, 244 640 1, 217 640 0, 213 623 1
+576 64 0 512 640;288 576 1, 389 576 0, 451 498 1, 512 419 0, 512 289 1, 512 156 0, 451 78 1, 389 0 0, 285 0 1, 195 0 0, 137 64 1, 64 145 0, 64 288 1, 64 420 0, 125 498 1, 186 576 0, 288 512 1, 212 512 0, 170 453 1, 128 394 0, 128 288 1, 128 183 0, 170 124 1, 212 64 0, 286 64 1, 355 64 0, 397 112 1, 448 171 0, 448 289 1, 448 394 0, 406 453 1, 363 512 0, 192 576 1, 192 640 1, 256 640 1, 256 576 1, 320 576 1, 320 640 1, 384 640 1, 384 576 1
+576 64 0 512 640;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 192 576 1, 192 640 1, 256 640 1, 256 576 1, 320 576 1, 320 640 1, 384 640 1, 384 576 1
+448 0 0 448 576;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+448 0 0 448 576;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 280 512 1, 224 512 1, 104 576 1, 189 576 1
+448 0 0 448 576;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 61 512 1, 151 576 1, 233 576 1, 323 512 1, 268 512 1, 192 552 1, 192 552 1, 116 512 1
+448 0 0 448 576;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+448 0 0 448 640;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 67 502 1, 70 531 0, 79 548 1, 96 576 0, 137 576 1, 164 576 0, 187 576 1, 210 576 1, 231 576 0, 242 576 1, 267 576 0, 271 590 1, 317 590 1, 314 559 0, 305 542 1, 288 512 0, 247 512 1, 220 512 0, 197 512 1, 174 512 1, 154 512 0, 142 512 1, 117 512 0, 113 502 1
+448 0 0 448 640;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 192 640 1, 219 640 0, 237 621 1, 256 603 0, 256 576 1, 256 549 0, 237 531 1, 219 512 0, 191 512 1, 168 512 0, 151 527 1, 128 547 0, 128 576 1, 128 603 0, 147 621 1, 165 640 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0
+384 0 -192 320 384;320 11 1, 251 0 0, 190 0 1, 104 0 0, 52 53 1, 0 107 0, 0 192 1, 0 282 0, 54 333 1, 108 384 0, 205 384 1, 254 384 0, 320 380 1, 320 322 1, 251 320 0, 209 320 1, 64 320 0, 64 191 1, 64 130 0, 101 97 1, 137 64 0, 203 64 1, 253 64 0, 320 72 1, 235 0 1, 271 0 1, 248 -41 1, 275 -42 0, 294 -59 1, 320 -82 0, 320 -116 1, 320 -148 0, 298 -170 1, 277 -192 0, 244 -192 1, 219 -192 0, 191 -154 1, 191 -124 1, 207 -128 0, 224 -128 1, 256 -128 0, 256 -101 1, 256 -67 0, 199 -66 1
+448 64 0 448 576;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+448 64 0 448 576;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 280 512 1, 224 512 1, 104 576 1, 189 576 1
+448 0 0 448 576;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 61 512 1, 151 576 1, 233 576 1, 323 512 1, 268 512 1, 192 552 1, 192 552 1, 116 512 1
+448 64 0 448 576;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+192 0 0 256 576;64 0 1, 64 384 1, 128 384 1, 128 0 1, 40 512 1, 131 576 1, 216 576 1, 96 512 1
+192 -64 0 192 576;64 0 1, 64 384 1, 128 384 1, 128 0 1, 152 512 1, 96 512 1, -24 576 1, 61 576 1
+192 -128 0 256 576;64 0 1, 64 384 1, 128 384 1, 128 0 1, -67 512 1, 23 576 1, 105 576 1, 195 512 1, 140 512 1, 64 552 1, 64 552 1, -12 512 1
+192 0 0 192 576;64 0 1, 64 384 1, 128 384 1, 128 0 1, 0 512 1, 0 576 1, 64 576 1, 64 512 1, 128 512 1, 128 576 1, 192 576 1, 192 512 1
+448 64 0 384 640;64 0 1, 64 384 1, 128 384 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 253 1, 320 292 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1, 67 502 1, 70 531 0, 79 548 1, 96 576 0, 137 576 1, 164 576 0, 187 576 1, 210 576 1, 231 576 0, 242 576 1, 267 576 0, 271 590 1, 317 590 1, 314 559 0, 305 542 1, 288 512 0, 247 512 1, 220 512 0, 197 512 1, 174 512 1, 154 512 0, 142 512 1, 117 512 0, 113 502 1
+448 64 0 384 576;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+448 64 0 384 576;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 280 512 1, 224 512 1, 104 576 1, 189 576 1
+448 0 0 384 576;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 61 512 1, 151 576 1, 233 576 1, 323 512 1, 268 512 1, 192 552 1, 192 552 1, 116 512 1
+448 64 0 384 576;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+448 64 0 384 640;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 67 502 1, 70 531 0, 79 548 1, 96 576 0, 137 576 1, 164 576 0, 187 576 1, 210 576 1, 231 576 0, 242 576 1, 267 576 0, 271 590 1, 317 590 1, 314 559 0, 305 542 1, 288 512 0, 247 512 1, 220 512 0, 197 512 1, 174 512 1, 154 512 0, 142 512 1, 117 512 0, 113 502 1
+448 64 0 384 576;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+448 64 0 384 576;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 280 512 1, 224 512 1, 104 576 1, 189 576 1
+448 0 0 384 576;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 61 512 1, 151 576 1, 233 576 1, 323 512 1, 268 512 1, 192 552 1, 192 552 1, 116 512 1
+448 64 0 384 576;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+448 64 -128 384 576;186 -128 1, 196 327 1, 64 317 1, 64 375 1, 196 365 1, 186 576 1, 262 576 1, 252 365 1, 384 375 1, 384 317 1, 252 327 1, 262 -128 1
+320 64 384 256 576;160 576 1, 199 576 0, 228 548 1, 256 520 0, 256 480 1, 256 440 0, 228 412 1, 199 384 0, 159 384 1, 124 384 0, 98 407 1, 64 437 0, 64 480 1, 64 520 0, 92 548 1, 121 576 0, 160 512 1, 147 512 0, 137 503 1, 128 493 0, 128 480 1, 128 467 0, 137 457 1, 147 448 0, 160 448 1, 172 448 0, 181 456 1, 192 465 0, 192 480 1, 192 493 0, 183 503 1, 173 512 0
+448 0 0 384 576;192 0 1, 192 65 1, 113 74 0, 65 120 1, 0 181 0, 0 278 1, 0 379 0, 66 436 1, 112 475 0, 192 486 1, 192 555 1, 256 555 1, 256 486 1, 316 484 0, 384 468 1, 384 406 1, 304 428 0, 256 432 1, 256 117 1, 317 117 0, 384 143 1, 384 87 1, 317 65 0, 256 65 1, 256 0 1, 192 429 1, 161 426 0, 145 420 1, 64 390 0, 64 277 1, 64 199 0, 112 159 1, 140 136 0, 192 122 1
+448 64 0 384 640;64 0 1, 64 64 1, 128 88 0, 128 176 1, 128 256 1, 64 256 1, 64 320 1, 128 320 1, 128 410 1, 128 491 0, 170 533 1, 211 576 0, 291 576 1, 333 576 0, 384 579 1, 384 510 1, 325 512 0, 277 512 1, 192 512 0, 192 434 1, 192 320 1, 256 320 1, 256 256 1, 192 256 1, 192 211 1, 192 147 0, 176 116 1, 164 89 0, 136 64 1, 384 64 1, 384 0 1
+448 64 -128 384 576;64 -77 1, 64 -9 1, 155 -64 0, 214 -64 1, 260 -64 0, 290 -45 1, 320 -25 0, 320 7 1, 320 36 0, 298 52 1, 279 66 0, 235 86 1, 170 116 1, 64 164 0, 64 247 1, 64 303 0, 123 363 1, 64 398 0, 64 449 1, 64 506 0, 115 541 1, 166 576 0, 249 576 1, 306 576 0, 384 572 1, 384 512 1, 301 512 0, 245 512 1, 192 512 0, 160 494 1, 128 476 0, 128 447 1, 128 409 0, 194 383 1, 246 364 1, 324 334 0, 354 306 1, 384 278 0, 384 236 1, 384 186 0, 342 125 1, 384 83 0, 384 14 1, 384 -51 0, 335 -89 1, 287 -128 0, 207 -128 1, 151 -128 0, 304 149 1, 320 187 0, 320 221 1, 320 249 0, 303 266 1, 285 284 0, 241 303 1, 161 338 1, 128 302 0, 128 270 1, 128 219 0, 220 183 1
+256 0 192 192 384;96 384 1, 136 384 0, 164 356 1, 192 327 0, 192 287 1, 192 248 0, 164 220 1, 135 192 0, 94 192 1, 60 192 0, 34 215 1, 0 245 0, 0 288 1, 0 328 0, 28 356 1, 56 384 0
+384 64 -128 320 576;192 -111 1, 192 280 1, 136 287 0, 105 321 1, 64 366 0, 64 446 1, 64 516 0, 93 546 1, 123 576 0, 192 576 1, 320 576 1, 320 -111 1, 256 -111 1, 256 512 1, 256 512 1, 256 -111 1
+448 64 0 448 576;64 0 1, 64 432 1, 64 513 0, 100 545 1, 138 576 0, 232 576 1, 384 576 0, 384 480 1, 384 434 0, 313 385 1, 256 345 0, 256 327 1, 256 303 0, 302 274 1, 377 225 1, 448 180 0, 448 113 1, 448 0 0, 306 0 1, 244 0 0, 192 11 1, 192 76 1, 265 64 0, 310 64 1, 384 64 0, 384 115 1, 384 149 0, 336 179 1, 246 234 1, 192 267 0, 192 305 1, 192 337 0, 261 387 1, 320 430 0, 320 459 1, 320 512 0, 227 512 1, 172 512 0, 150 501 1, 128 490 0, 128 463 1, 128 0 1
+576 0 0 576 576;288 576 1, 407 576 0, 492 492 1, 576 407 0, 576 288 1, 576 168 0, 491 84 1, 407 0 0, 284 0 1, 180 0 0, 102 68 1, 0 157 0, 0 288 1, 0 407 0, 84 492 1, 169 576 0, 288 512 1, 196 512 0, 130 446 1, 64 380 0, 64 288 1, 64 197 0, 129 130 1, 195 64 0, 285 64 1, 370 64 0, 432 117 1, 512 185 0, 512 288 1, 512 381 0, 446 446 1, 380 512 0, 192 128 1, 192 448 1, 302 448 1, 384 448 0, 384 370 1, 384 315 0, 340 277 1, 431 128 1, 375 128 1, 294 262 1, 256 262 1, 256 128 1, 256 301 1, 267 301 1, 320 301 0, 320 363 1, 320 415 0, 280 415 1, 256 415 1
+576 0 0 576 576;288 576 1, 407 576 0, 492 492 1, 576 407 0, 576 288 1, 576 168 0, 491 84 1, 407 0 0, 284 0 1, 180 0 0, 102 68 1, 0 157 0, 0 288 1, 0 407 0, 84 492 1, 169 576 0, 288 512 1, 196 512 0, 130 446 1, 64 380 0, 64 288 1, 64 197 0, 129 130 1, 195 64 0, 285 64 1, 370 64 0, 432 117 1, 512 185 0, 512 288 1, 512 381 0, 446 446 1, 380 512 0, 384 142 1, 330 128 0, 288 128 1, 218 128 0, 173 173 1, 128 217 0, 128 288 1, 128 360 0, 172 404 1, 216 448 0, 291 448 1, 329 448 0, 375 441 1, 384 439 1, 384 393 1, 335 384 0, 297 384 1, 250 384 0, 221 357 1, 192 330 0, 192 287 1, 192 243 0, 222 218 1, 252 192 0, 303 192 1, 342 192 0, 384 188 1
+768 64 256 640 576;192 256 1, 192 512 1, 99 512 1, 99 576 1, 341 576 1, 341 512 1, 256 512 1, 256 256 1, 384 256 1, 384 576 1, 476 576 1, 521 372 1, 564 576 1, 640 576 1, 640 256 1, 576 256 1, 576 474 1, 529 279 1, 495 279 1, 448 454 1, 448 256 1
+256 0 512 256 576;40 512 1, 131 576 1, 216 576 1, 96 512 1
+256 0 512 256 576;0 512 1, 0 576 1, 64 576 1, 64 512 1, 192 512 1, 192 576 1, 256 576 1, 256 512 1
+192 0 0 0 0;
+768 0 0 768 576;227 192 1, 384 192 1, 384 473 1, 10 0 1, 363 576 1, 704 576 1, 704 512 1, 448 512 1, 448 320 1, 704 320 1, 704 256 1, 448 256 1, 448 64 1, 768 64 1, 768 0 1, 384 0 1, 384 128 1, 190 128 1, 92 0 1
+576 0 0 576 576;39 0 1, 104 65 1, 86 104 0, 77 144 1, 64 203 0, 64 279 1, 64 414 0, 131 495 1, 198 576 0, 309 576 1, 394 576 0, 459 529 1, 498 576 1, 563 576 1, 496 484 1, 531 447 0, 550 409 1, 576 353 0, 576 283 1, 576 154 0, 502 77 1, 428 0 0, 304 0 1, 213 0 0, 142 32 1, 104 0 1, 184 83 1, 238 64 0, 312 64 1, 406 64 0, 459 119 1, 512 174 0, 512 273 1, 512 351 0, 448 405 1, 416 459 1, 367 512 0, 302 512 1, 220 512 0, 174 449 1, 128 387 0, 128 275 1, 128 184 0, 152 122 1
+192 0 0 0 0;
+448 64 0 384 448;192 128 1, 192 256 1, 64 256 1, 64 320 1, 192 320 1, 192 448 1, 256 448 1, 256 320 1, 384 320 1, 384 256 1, 256 256 1, 256 128 1, 64 0 1, 64 64 1, 384 64 1, 384 0 1
+192 0 0 0 0;
+192 0 0 0 0;
+448 0 0 448 576;192 0 1, 192 128 1, 81 128 1, 81 192 1, 192 192 1, 192 192 1, 81 192 1, 81 256 1, 192 256 1, 31 576 1, 117 576 1, 232 335 1, 232 335 1, 350 576 1, 416 576 1, 256 256 1, 367 256 1, 367 192 1, 256 192 1, 256 192 1, 367 192 1, 367 128 1, 256 128 1, 256 0 1
+448 64 -128 384 384;64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 320 0 1, 320 72 1, 252 0 0, 184 0 1, 156 0 0, 128 9 1, 128 -128 1, 64 -128 1
+192 0 0 0 0;
+192 0 0 0 0;
+192 0 0 0 0;
+192 0 0 0 0;
+192 0 0 0 0;
+256 64 320 320 576;196 364 1, 162 320 0, 129 320 1, 100 320 0, 82 341 1, 64 363 0, 64 394 1, 64 485 0, 174 485 1, 192 485 1, 192 511 1, 192 512 0, 147 512 1, 110 512 0, 68 530 1, 68 572 1, 118 576 0, 161 576 1, 256 576 0, 256 513 1, 256 401 1, 256 383 0, 276 384 1, 279 384 1, 280 384 0, 282 384 1, 284 384 0, 286 368 1, 289 336 1, 268 320 0, 250 320 1, 209 320 0, 198 364 1, 192 395 1, 192 452 1, 178 452 1, 128 452 0, 128 413 1, 128 384 0, 154 384 1, 172 384 0
+256 0 320 256 576;128 576 1, 187 576 0, 222 542 1, 256 507 0, 256 449 1, 256 389 0, 222 354 1, 187 320 0, 127 320 1, 74 320 0, 41 348 1, 0 384 0, 0 448 1, 0 507 0, 35 541 1, 69 576 0, 128 512 1, 64 512 0, 64 448 1, 64 384 0, 128 384 1, 192 384 0, 192 449 1, 192 512 0
+192 0 0 0 0;
+704 0 0 704 384;320 92 1, 320 198 1, 290 199 1, 263 200 0, 233 196 1, 128 183 0, 128 121 1, 128 64 0, 208 64 1, 264 64 0, 371 353 1, 423 384 0, 489 384 1, 642 384 0, 642 218 1, 642 192 1, 387 192 1, 391 153 0, 400 133 1, 431 64 0, 526 64 1, 578 64 0, 640 72 1, 640 13 1, 569 0 0, 510 0 1, 444 0 0, 399 29 1, 374 45 0, 351 77 1, 298 36 0, 260 19 1, 215 0 0, 153 0 1, 84 0 0, 42 30 1, 0 61 0, 0 110 1, 0 248 0, 300 248 1, 320 248 1, 320 290 1, 320 307 0, 298 313 1, 277 320 0, 223 320 1, 147 320 0, 64 318 1, 64 367 1, 151 384 0, 230 384 1, 325 384 0, 390 256 1, 574 256 1, 573 276 0, 567 287 1, 549 320 0, 487 320 1, 444 320 0, 419 305 1, 396 290 0
+448 0 0 448 448;131 21 1, 108 0 1, 54 0 1, 99 50 1, 64 108 0, 64 189 1, 64 280 0, 111 332 1, 158 384 0, 240 384 1, 298 384 0, 339 363 1, 362 448 1, 416 448 1, 371 334 1, 448 276 0, 448 196 1, 448 105 0, 394 53 1, 340 0 0, 246 0 1, 180 0 0, 169 71 1, 170 71 1, 190 67 0, 207 66 1, 229 64 0, 253 64 1, 384 64 0, 384 200 1, 384 241 0, 325 275 1, 301 313 1, 300 313 1, 271 320 0, 233 320 1, 128 320 0, 128 186 1, 128 140 0, 145 109 1
+448 64 -192 384 384;320 384 1, 320 320 1, 256 320 1, 256 384 1, 320 256 1, 320 236 1, 320 139 0, 247 89 1, 207 62 1, 128 7 0, 128 -50 1, 128 -128 0, 234 -128 1, 298 -128 0, 384 -78 1, 384 -141 1, 304 -192 0, 236 -192 1, 161 -192 0, 118 -165 1, 64 -131 0, 64 -55 1, 64 21 0, 147 68 1, 182 88 1, 226 113 0, 241 139 1, 256 166 0, 256 215 1, 256 256 1
+256 64 -128 128 384;128 384 1, 128 320 1, 64 320 1, 64 384 1, 120 256 1, 128 -32 1, 128 -128 1, 64 -128 1, 64 -32 1, 72 256 1
+448 64 128 384 320;64 256 1, 64 320 1, 384 320 1, 384 128 1, 320 128 1, 320 256 1
+192 0 0 0 0;
+448 0 -128 448 640;51 -128 1, 118 256 1, 64 256 1, 64 320 1, 128 320 1, 135 361 1, 174 576 0, 310 576 1, 346 576 0, 389 579 1, 378 515 1, 339 512 0, 307 512 1, 230 512 0, 208 394 1, 194 320 1, 256 320 1, 256 256 1, 184 256 1, 118 -128 1
+192 0 0 0 0;
+192 0 0 0 0;
+448 0 0 384 384;376 342 1, 265 204 1, 376 65 1, 339 37 1, 191 204 1, 339 370 1, 228 342 1, 117 204 1, 228 65 1, 191 37 1, 43 204 1, 191 370 1
+448 0 0 384 384;51 65 1, 162 204 1, 51 342 1, 88 370 1, 236 204 1, 88 37 1, 199 65 1, 310 204 1, 199 342 1, 236 370 1, 384 204 1, 236 37 1
+768 64 0 704 64;64 0 1, 64 64 1, 128 64 1, 128 0 1, 320 0 1, 320 64 1, 384 64 1, 384 0 1, 640 0 1, 640 64 1, 704 64 1, 704 0 1
+448 0 0 0 0;
+512 0 0 512 704;7 0 1, 218 576 1, 296 576 1, 503 0 1, 419 0 1, 361 128 1, 138 128 1, 80 0 1, 161 192 1, 339 192 1, 250 458 1, 312 576 1, 257 576 1, 137 704 1, 222 704 1
+512 0 0 512 768;7 0 1, 218 576 1, 296 576 1, 503 0 1, 419 0 1, 361 128 1, 138 128 1, 80 0 1, 161 192 1, 339 192 1, 250 458 1, 132 623 1, 135 655 0, 144 673 1, 161 704 0, 202 704 1, 229 704 0, 252 704 1, 275 704 1, 296 704 0, 307 704 1, 332 704 0, 336 710 1, 382 710 1, 379 682 0, 370 667 1, 353 640 0, 312 640 1, 285 640 0, 262 640 1, 239 640 1, 219 640 0, 207 640 1, 182 640 0, 178 623 1
+576 64 0 576 768;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0, 174 623 1, 177 655 0, 186 673 1, 203 704 0, 244 704 1, 271 704 0, 294 704 1, 316 704 1, 337 704 0, 349 704 1, 373 704 0, 377 710 1, 423 710 1, 420 682 0, 411 667 1, 394 640 0, 354 640 1, 327 640 0, 303 640 1, 281 640 1, 260 640 0, 248 640 1, 224 640 0, 220 623 1
+768 64 0 768 576;448 0 1, 448 24 1, 387 0 0, 317 0 1, 203 0 0, 134 79 1, 64 159 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 576 1, 388 576 0, 448 553 1, 448 576 1, 704 576 1, 704 512 1, 512 512 1, 512 320 1, 704 320 1, 704 256 1, 512 256 1, 512 64 1, 768 64 1, 768 0 1, 448 212 1, 448 345 1, 448 433 0, 416 472 1, 384 512 0, 314 512 1, 226 512 0, 177 453 1, 128 394 0, 128 288 1, 128 182 0, 177 123 1, 227 64 0, 314 64 1, 448 64 0
+704 64 0 704 384;396 332 1, 420 355 0, 447 367 1, 486 384 0, 540 384 1, 637 384 0, 675 325 1, 703 282 0, 704 192 1, 437 192 1, 444 129 0, 471 100 1, 506 64 0, 585 64 1, 643 64 0, 704 73 1, 704 14 1, 632 0 0, 566 0 1, 499 0 0, 459 19 1, 429 33 0, 398 65 1, 376 36 0, 349 22 1, 310 0 0, 255 0 1, 168 0 0, 116 52 1, 64 104 0, 64 192 1, 64 281 0, 116 332 1, 168 384 0, 256 384 1, 313 384 0, 353 364 1, 375 353 0, 261 320 1, 128 320 0, 128 193 1, 128 138 0, 154 106 1, 187 64 0, 262 64 1, 384 64 0, 384 192 1, 384 251 0, 359 283 1, 329 320 0, 439 256 1, 625 256 1, 624 282 0, 612 296 1, 592 320 0, 539 320 1, 487 320 0, 462 299 1, 445 284 0
+448 0 192 448 256;38 192 1, 38 256 1, 390 256 1, 390 192 1
+768 0 192 768 256;37 192 1, 37 256 1, 731 256 1, 731 192 1
+256 0 384 256 640;256 578 1, 256 551 1, 233 537 0, 233 467 1, 233 458 1, 256 458 1, 256 384 1, 192 384 1, 192 446 1, 192 559 0, 64 578 1, 64 551 1, 41 537 0, 41 467 1, 41 458 1, 64 458 1, 64 384 1, 0 384 1, 0 446 1, 0 559 0
+256 0 320 256 576;0 382 1, 0 409 1, 23 423 0, 23 493 1, 23 502 1, 0 502 1, 0 576 1, 64 576 1, 64 514 1, 64 401 0, 192 382 1, 192 409 1, 215 423 0, 215 493 1, 215 502 1, 192 502 1, 192 576 1, 256 576 1, 256 514 1, 256 401 0
+192 64 384 128 640;128 597 1, 128 569 1, 103 559 0, 103 484 1, 103 476 1, 128 476 1, 128 384 1, 64 384 1, 64 464 1, 64 586 0
+192 64 320 128 576;64 363 1, 64 391 1, 89 401 0, 89 476 1, 89 483 1, 64 483 1, 64 576 1, 128 576 1, 128 496 1, 128 372 0
+448 64 0 384 448;64 192 1, 64 256 1, 384 256 1, 384 192 1, 192 384 1, 192 448 1, 256 448 1, 256 384 1, 192 0 1, 192 64 1, 256 64 1, 256 0 1
+192 0 0 0 0;
+384 0 -128 384 576;152 0 1, 7 384 1, 82 384 1, 193 90 1, 314 384 1, 380 384 1, 164 -128 1, 87 -128 1, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+512 -64 0 576 640;192 0 1, 192 240 1, -19 576 1, 71 576 1, 227 309 1, 441 576 1, 514 576 1, 256 242 1, 256 0 1, 128 576 1, 128 640 1, 192 640 1, 192 576 1, 320 576 1, 320 640 1, 384 640 1, 384 576 1
+128 -192 -64 320 576;-165 -14 1, 243 569 1, 293 569 1, -114 -14 1
+448 0 64 384 448;137 145 1, 78 87 1, 46 120 1, 104 178 1, 64 217 0, 64 255 1, 64 292 0, 104 331 1, 46 390 1, 78 423 1, 137 364 1, 174 384 0, 214 384 1, 253 384 0, 290 364 1, 348 423 1, 381 390 1, 323 331 1, 320 292 0, 320 255 1, 320 217 0, 323 178 1, 381 120 1, 348 87 1, 290 145 1, 253 128 0, 214 128 1, 174 128 0, 192 320 1, 165 320 0, 146 302 1, 128 283 0, 128 256 1, 128 229 0, 146 211 1, 165 192 0, 191 192 1, 216 192 0, 233 207 1, 256 226 0, 256 256 1, 256 283 0, 238 302 1, 219 320 0
+256 0 0 256 384;213 342 1, 102 204 1, 213 65 1, 176 37 1, 28 204 1, 176 370 1
+256 0 0 256 384;43 65 1, 154 204 1, 43 342 1, 80 370 1, 228 204 1, 80 37 1
+384 0 0 320 640;64 0 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 468 1, 64 640 0, 194 640 1, 221 640 0, 256 613 1, 256 557 1, 219 576 0, 193 576 1, 157 576 0, 142 555 1, 128 534 0, 128 482 1, 128 384 1, 320 384 1, 320 0 1, 256 0 1, 256 320 1, 128 320 1, 128 0 1, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+384 0 0 320 576;64 0 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 435 1, 64 576 0, 175 576 1, 256 576 1, 320 576 1, 320 0 1, 256 0 1, 256 518 1, 240 516 1, 206 512 0, 183 512 1, 148 512 0, 137 493 1, 128 477 0, 128 443 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 0 1
+448 64 -128 384 576;183 -128 1, 192 97 1, 64 86 1, 64 144 1, 192 134 1, 192 327 1, 64 317 1, 64 375 1, 192 365 1, 183 576 1, 265 576 1, 256 365 1, 384 375 1, 384 317 1, 256 327 1, 256 134 1, 384 144 1, 384 86 1, 256 97 1, 265 -128 1
+192 64 192 128 256;64 192 1, 64 256 1, 128 256 1, 128 192 1
+192 64 -192 128 64;64 -140 1, 64 -112 1, 89 -102 0, 89 -36 1, 89 -29 1, 64 -29 1, 64 64 1, 128 64 1, 128 -16 1, 128 -130 0
+256 0 -192 256 64;0 -130 1, 0 -103 1, 23 -89 0, 23 -19 1, 23 -10 1, 0 -10 1, 0 64 1, 64 64 1, 64 2 1, 64 -111 0, 192 -130 1, 192 -103 1, 215 -89 0, 215 -19 1, 215 -10 1, 192 -10 1, 192 64 1, 256 64 1, 256 2 1, 256 -111 0
+768 0 -64 768 640;128 576 1, 186 576 0, 221 541 1, 256 507 0, 256 448 1, 256 388 0, 221 354 1, 187 320 0, 126 320 1, 75 320 0, 42 348 1, 0 384 0, 0 448 1, 0 507 0, 35 541 1, 70 576 0, 127 512 1, 64 512 0, 64 448 1, 64 384 0, 128 384 1, 192 384 0, 192 448 1, 192 477 0, 175 495 1, 157 512 0, 384 320 1, 443 320 0, 477 277 1, 512 234 0, 512 160 1, 512 86 0, 477 43 1, 443 0 0, 383 0 1, 330 0 0, 298 35 1, 256 80 0, 256 160 1, 256 234 0, 291 277 1, 326 320 0, 383 256 1, 320 256 0, 320 160 1, 320 64 0, 384 64 1, 448 64 0, 448 159 1, 448 204 0, 431 230 1, 413 256 0, 640 320 1, 699 320 0, 733 277 1, 768 234 0, 768 161 1, 768 86 0, 733 43 1, 698 0 0, 639 0 1, 587 0 0, 553 35 1, 512 80 0, 512 160 1, 512 234 0, 547 277 1, 581 320 0, 639 256 1, 576 256 0, 576 160 1, 576 64 0, 640 64 1, 704 64 0, 704 160 1, 704 204 0, 686 230 1, 669 256 0, 23 -14 1, 431 590 1, 482 590 1, 74 -14 1
+512 0 0 512 704;7 0 1, 218 576 1, 296 576 1, 503 0 1, 419 0 1, 361 128 1, 138 128 1, 80 0 1, 161 192 1, 339 192 1, 250 458 1, 126 576 1, 216 704 1, 298 704 1, 388 576 1, 333 576 1, 257 657 1, 257 657 1, 181 576 1
+512 64 0 512 704;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 127 576 1, 228 704 1, 319 704 1, 420 576 1, 358 576 1, 274 657 1, 273 657 1, 189 576 1
+512 0 0 512 704;7 0 1, 218 576 1, 296 576 1, 503 0 1, 419 0 1, 361 128 1, 138 128 1, 80 0 1, 161 192 1, 339 192 1, 250 458 1, 201 576 1, 292 704 1, 377 704 1, 257 576 1
+512 64 0 512 640;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 192 576 1, 192 640 1, 256 640 1, 256 576 1, 320 576 1, 320 640 1, 384 640 1, 384 576 1
+512 64 0 512 704;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 334 576 1, 273 576 1, 138 704 1, 234 704 1
+192 0 0 256 704;64 0 1, 64 576 1, 128 576 1, 128 0 1, 48 576 1, 124 704 1, 209 704 1, 96 576 1
+192 -64 0 256 704;64 0 1, 64 576 1, 128 576 1, 128 0 1, -28 576 1, 62 704 1, 130 704 1, 220 576 1, 164 576 1, 96 657 1, 96 657 1, 28 576 1
+192 0 0 192 640;64 0 1, 64 576 1, 128 576 1, 128 0 1, 0 576 1, 0 640 1, 64 640 1, 64 576 1, 128 576 1, 128 640 1, 192 640 1, 192 576 1
+192 -64 0 192 704;64 0 1, 64 576 1, 128 576 1, 128 0 1, 144 576 1, 96 576 1, -17 704 1, 68 704 1
+576 64 0 576 704;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0, 243 576 1, 333 704 1, 419 704 1, 299 576 1
+576 64 0 576 704;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0, 167 576 1, 258 704 1, 339 704 1, 430 576 1, 374 576 1, 299 657 1, 298 657 1, 223 576 1
+448 -64 0 384 576;121 192 1, 136 142 0, 158 114 1, 198 64 0, 269 64 1, 316 64 0, 384 72 1, 384 10 1, 311 0 0, 260 0 1, 173 0 0, 119 46 1, 81 78 0, 62 132 1, 55 151 0, 46 192 1, -21 192 1, -2 256 1, 40 256 1, 39 280 1, 39 282 0, 39 288 1, 40 302 0, 41 320 1, -21 320 1, -2 384 1, 48 384 1, 63 444 0, 81 474 1, 140 576 0, 273 576 1, 320 576 0, 384 573 1, 384 502 1, 321 512 0, 273 512 1, 207 512 0, 168 469 1, 145 444 0, 133 413 1, 128 401 0, 123 384 1, 336 384 1, 316 320 1, 115 320 1, 113 296 0, 113 281 1, 114 256 1, 286 256 1, 267 192 1
+576 64 0 576 704;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0, 354 576 1, 299 576 1, 178 704 1, 264 704 1
+576 64 0 512 704;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 225 576 1, 328 704 1, 425 704 1, 288 576 1
+576 64 0 512 704;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 139 576 1, 242 704 1, 334 704 1, 437 576 1, 374 576 1, 288 657 1, 288 657 1, 202 576 1
+576 64 0 512 704;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 351 576 1, 288 576 1, 151 704 1, 248 704 1
+192 64 0 128 384;64 0 1, 64 384 1, 128 384 1, 128 0 1
+256 -64 512 320 576;-3 512 1, 87 576 1, 169 576 1, 259 512 1, 204 512 1, 128 552 1, 128 552 1, 52 512 1
+256 0 448 256 640;3 502 1, 6 531 0, 15 548 1, 32 576 0, 73 576 1, 100 576 0, 123 576 1, 146 576 1, 167 576 0, 178 576 1, 203 576 0, 207 590 1, 253 590 1, 250 559 0, 241 542 1, 224 512 0, 183 512 1, 156 512 0, 133 512 1, 110 512 1, 90 512 0, 78 512 1, 53 512 0, 49 502 1
+256 0 448 256 512;0 448 1, 0 512 1, 256 512 1, 256 448 1
+256 0 512 256 640;3 602 1, 49 602 1, 57 588 0, 77 582 1, 97 576 0, 128 576 1, 163 576 0, 184 583 1, 200 589 0, 207 602 1, 253 602 1, 247 564 0, 220 542 1, 184 512 0, 128 512 1, 69 512 0, 33 544 1, 9 566 0
+256 64 512 128 576;64 512 1, 64 576 1, 128 576 1, 128 512 1
+256 64 512 192 640;128 640 1, 155 640 0, 173 621 1, 192 603 0, 192 576 1, 192 549 0, 173 531 1, 155 512 0, 127 512 1, 104 512 0, 87 527 1, 64 547 0, 64 576 1, 64 603 0, 83 621 1, 101 640 0, 128 576 1, 128 576 0, 128 576 1, 128 576 0, 128 576 1, 128 576 0, 128 576 1, 128 576 0, 128 576 1, 128 576 0, 128 576 1, 128 576 0, 128 576 1, 128 576 0, 128 576 1, 128 576 0
+256 0 -192 192 0;107 0 1, 143 0 1, 120 -41 1, 147 -42 0, 166 -59 1, 192 -82 0, 192 -116 1, 192 -148 0, 170 -170 1, 149 -192 0, 116 -192 1, 91 -192 0, 63 -154 1, 63 -124 1, 79 -128 0, 96 -128 1, 128 -128 0, 128 -101 1, 128 -67 0, 71 -66 1
+256 -64 448 320 576;-19 456 1, 71 576 1, 143 576 1, 23 456 1, 113 456 1, 203 576 1, 275 576 1, 155 456 1
+256 64 -128 192 0;123 0 1, 163 0 1, 128 -19 0, 128 -42 1, 128 -64 0, 164 -64 1, 180 -64 0, 192 -98 1, 192 -128 1, 169 -128 0, 140 -128 1, 64 -128 0, 64 -73 1, 64 -31 0
+256 -64 512 320 576;259 576 1, 169 512 1, 87 512 1, -3 576 1, 52 576 1, 128 536 1, 128 536 1, 204 576 1
+448 -64 0 384 576;121 192 1, 136 142 0, 158 114 1, 198 64 0, 269 64 1, 316 64 0, 384 72 1, 384 10 1, 311 0 0, 260 0 1, 173 0 0, 119 46 1, 81 78 0, 62 132 1, 55 151 0, 46 192 1, -21 192 1, -2 256 1, 40 256 1, 39 280 1, 39 282 0, 39 288 1, 40 302 0, 41 320 1, -21 320 1, -2 384 1, 48 384 1, 63 444 0, 81 474 1, 140 576 0, 273 576 1, 320 576 0, 384 573 1, 384 502 1, 321 512 0, 273 512 1, 207 512 0, 168 469 1, 145 444 0, 133 413 1, 128 401 0, 123 384 1, 336 384 1, 316 320 1, 115 320 1, 113 296 0, 113 281 1, 114 256 1, 286 256 1, 267 192 1
+192 0 0 0 0;
+192 64 -128 128 576;64 -128 1, 64 192 1, 128 192 1, 128 -128 1, 64 320 1, 64 576 1, 128 576 1, 128 320 1
+256 64 192 192 256;64 192 1, 64 256 1, 192 256 1, 192 192 1
+448 64 512 384 576;64 512 1, 64 576 1, 384 576 1, 384 512 1
+256 0 192 256 576;28 192 1, 28 256 1, 55 300 0, 101 338 1, 129 361 1, 192 412 0, 192 458 1, 192 512 0, 127 512 1, 89 512 0, 36 488 1, 36 532 1, 89 576 0, 138 576 1, 191 576 0, 224 548 1, 256 521 0, 256 477 1, 256 421 0, 179 359 1, 157 341 1, 102 296 0, 92 256 1, 238 256 1, 238 192 1
+256 0 192 256 576;32 507 1, 32 549 1, 68 576 0, 103 576 1, 192 576 0, 192 492 1, 192 454 0, 177 429 1, 168 414 0, 151 402 1, 212 388 0, 236 360 1, 256 336 0, 256 302 1, 256 251 0, 220 222 1, 184 192 0, 121 192 1, 79 192 0, 28 225 1, 28 270 1, 84 256 0, 117 256 1, 192 256 0, 192 314 1, 192 381 0, 78 381 1, 59 381 1, 59 416 1, 75 416 1, 128 416 0, 128 470 1, 128 512 0, 86 512 1, 62 512 0
+192 64 192 128 256;64 192 1, 64 256 1, 128 256 1, 128 192 1
+256 0 192 192 576;128 192 1, 128 477 1, 54 458 1, 54 501 1, 192 534 1, 192 192 1
+640 0 -64 640 576;128 192 1, 128 494 1, 54 475 1, 54 518 1, 192 551 1, 192 192 1, 512 -27 1, 512 64 1, 361 64 1, 361 126 1, 511 320 1, 576 320 1, 576 128 1, 622 128 1, 622 64 1, 576 64 1, 576 -27 1, 409 128 1, 512 128 1, 512 249 1, 82 -41 1, 495 556 1, 554 556 1, 134 -41 1
+640 0 -64 640 576;401 0 1, 401 64 1, 428 95 0, 479 125 1, 509 143 1, 576 181 0, 576 215 1, 576 256 0, 507 256 1, 467 256 0, 410 248 1, 410 291 1, 466 320 0, 516 320 1, 572 320 0, 606 298 1, 640 276 0, 640 241 1, 640 194 0, 559 146 1, 535 132 1, 476 96 0, 466 64 1, 612 64 1, 612 0 1, 63 -14 1, 480 539 1, 531 539 1, 114 -14 1, 128 192 1, 128 477 1, 54 458 1, 54 501 1, 192 534 1, 192 192 1
+640 0 -64 640 576;56 494 1, 56 536 1, 101 576 0, 145 576 1, 256 576 0, 256 486 1, 256 444 0, 227 418 1, 209 402 0, 175 389 1, 222 376 0, 241 349 1, 256 327 0, 256 295 1, 256 247 0, 224 220 1, 192 192 0, 135 192 1, 97 192 0, 52 215 1, 52 259 1, 100 256 0, 128 256 1, 192 256 0, 192 308 1, 192 368 0, 102 368 1, 83 368 1, 83 403 1, 99 403 1, 192 403 0, 192 465 1, 192 512 0, 133 512 1, 99 512 0, 512 -27 1, 512 64 1, 359 64 1, 359 126 1, 510 320 1, 576 320 1, 576 128 1, 623 128 1, 623 64 1, 576 64 1, 576 -27 1, 408 128 1, 512 128 1, 512 260 1, 117 -41 1, 528 556 1, 589 556 1, 167 -41 1
+576 0 0 512 576;64 0 1, 64 256 1, 0 256 1, 0 320 1, 64 320 1, 64 576 1, 229 576 1, 512 576 0, 512 301 1, 512 158 0, 438 79 1, 365 0 0, 231 0 1, 128 64 1, 225 64 1, 448 64 0, 448 292 1, 448 426 0, 361 481 1, 336 497 0, 300 504 1, 258 512 0, 188 512 1, 128 512 1, 128 320 1, 256 320 1, 256 256 1, 128 256 1
+448 0 0 448 384;44 58 1, 185 199 1, 44 340 1, 84 379 1, 224 238 1, 365 379 1, 404 340 1, 264 199 1, 404 58 1, 365 19 1, 224 160 1, 84 19 1
+512 -64 0 512 704;192 0 1, 192 240 1, -7 576 1, 83 576 1, 232 309 1, 395 576 1, 468 576 1, 256 242 1, 256 0 1, 185 576 1, 261 704 1, 346 704 1, 232 576 1
+512 64 0 512 576;64 0 1, 64 576 1, 128 576 1, 128 448 1, 267 448 1, 365 448 0, 408 438 1, 451 429 0, 478 401 1, 512 367 0, 512 308 1, 512 128 0, 244 128 1, 128 128 1, 128 0 1, 128 192 1, 240 192 1, 448 192 0, 448 302 1, 448 355 0, 394 371 1, 348 384 0, 242 384 1, 128 384 1
+448 64 0 384 704;64 554 1, 64 615 1, 139 615 0, 200 586 1, 258 650 1, 287 617 1, 238 559 1, 278 523 0, 299 494 1, 384 380 0, 384 219 1, 384 116 0, 342 58 1, 299 0 0, 226 0 1, 152 0 0, 108 53 1, 64 105 0, 64 194 1, 64 283 0, 110 333 1, 155 384 0, 234 384 1, 253 384 0, 276 379 1, 247 449 0, 194 497 1, 138 416 1, 109 459 1, 157 528 1, 119 554 0, 223 320 1, 178 320 0, 153 287 1, 128 253 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 192 1, 320 320 0
+384 0 -128 384 576;152 0 1, 7 384 1, 82 384 1, 193 90 1, 314 384 1, 380 384 1, 164 -128 1, 87 -128 1, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+448 64 -128 384 576;128 -128 1, 64 -128 1, 64 576 1, 128 576 1, 128 312 1, 148 344 0, 171 361 1, 203 384 0, 247 384 1, 308 384 0, 346 334 1, 384 285 0, 384 202 1, 384 106 0, 335 53 1, 286 0 0, 197 0 1, 164 0 0, 128 0 1, 128 249 1, 128 53 1, 182 64 0, 209 64 1, 320 64 0, 320 199 1, 320 256 0, 298 288 1, 276 320 0, 239 320 1, 190 320 0
+512 -64 0 512 640;-1 0 1, 215 576 1, 297 576 1, 510 0 1, 425 0 1, 366 128 1, 130 128 1, 72 0 1, 154 192 1, 343 192 1, 249 458 1, 128 576 1, 128 640 1, 384 640 1, 384 576 1
+448 0 0 448 512;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 64 448 1, 64 512 1, 320 512 1, 320 448 1
+512 0 0 512 768;8 0 1, 219 576 1, 297 576 1, 504 0 1, 419 0 1, 362 128 1, 139 128 1, 81 0 1, 161 192 1, 340 192 1, 251 458 1, 133 743 1, 179 743 1, 187 722 0, 207 713 1, 226 704 0, 258 704 1, 293 704 0, 313 715 1, 329 724 0, 336 743 1, 383 743 1, 377 700 0, 350 674 1, 314 640 0, 258 640 1, 199 640 0, 163 677 1, 139 702 0
+448 0 0 448 640;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 67 602 1, 113 602 1, 121 588 0, 141 582 1, 161 576 0, 192 576 1, 227 576 0, 248 583 1, 264 589 0, 271 602 1, 317 602 1, 311 564 0, 284 542 1, 248 512 0, 192 512 1, 133 512 0, 97 544 1, 73 566 0
+512 0 -128 512 576;7 0 1, 218 576 1, 296 576 1, 503 0 1, 419 0 1, 361 128 1, 138 128 1, 80 0 1, 161 192 1, 339 192 1, 250 458 1, 419 0 1, 459 0 1, 448 -19 0, 448 -42 1, 448 -64 0, 470 -64 1, 481 -64 0, 488 -98 1, 488 -128 1, 469 -128 0, 446 -128 1, 384 -128 0, 384 -73 1, 384 -31 0
+448 0 -128 448 384;329 49 1, 239 0 0, 155 0 1, 86 0 0, 43 28 1, 0 57 0, 0 101 1, 0 227 0, 299 227 1, 320 227 1, 320 274 1, 320 320 0, 224 320 1, 149 320 0, 64 307 1, 64 364 1, 151 384 0, 228 384 1, 309 384 0, 347 358 1, 384 331 0, 384 274 1, 384 99 1, 384 64 0, 423 64 1, 428 64 0, 437 42 1, 443 3 1, 417 0 0, 392 0 1, 368 0 0, 352 11 1, 337 23 0, 320 87 1, 320 186 1, 283 187 1, 248 188 0, 206 184 1, 64 173 0, 64 116 1, 64 64 0, 168 64 1, 240 64 0, 315 0 1, 355 0 1, 320 -19 0, 320 -42 1, 320 -64 0, 356 -64 1, 372 -64 0, 384 -98 1, 384 -128 1, 361 -128 0, 332 -128 1, 256 -128 0, 256 -73 1, 256 -31 0
+576 64 0 512 704;512 30 1, 429 0 0, 334 0 1, 202 0 0, 133 73 1, 64 147 0, 64 287 1, 64 427 0, 134 502 1, 205 576 0, 338 576 1, 413 576 0, 512 566 1, 512 489 1, 394 512 0, 326 512 1, 230 512 0, 179 454 1, 128 396 0, 128 287 1, 128 180 0, 182 122 1, 237 64 0, 335 64 1, 417 64 0, 512 100 1, 270 576 1, 360 704 1, 446 704 1, 326 576 1
+384 0 0 384 576;320 11 1, 251 0 0, 190 0 1, 104 0 0, 52 53 1, 0 107 0, 0 192 1, 0 282 0, 54 333 1, 108 384 0, 205 384 1, 254 384 0, 320 380 1, 320 322 1, 251 320 0, 209 320 1, 64 320 0, 64 191 1, 64 130 0, 101 97 1, 137 64 0, 203 64 1, 253 64 0, 320 72 1, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+576 64 0 512 704;512 30 1, 429 0 0, 334 0 1, 202 0 0, 133 73 1, 64 147 0, 64 287 1, 64 427 0, 134 502 1, 205 576 0, 338 576 1, 413 576 0, 512 566 1, 512 489 1, 394 512 0, 326 512 1, 230 512 0, 179 454 1, 128 396 0, 128 287 1, 128 180 0, 182 122 1, 237 64 0, 335 64 1, 417 64 0, 512 100 1, 194 576 1, 285 704 1, 366 704 1, 457 576 1, 401 576 1, 326 657 1, 325 657 1, 250 576 1
+384 0 0 384 576;320 11 1, 251 0 0, 190 0 1, 104 0 0, 52 53 1, 0 107 0, 0 192 1, 0 282 0, 54 333 1, 108 384 0, 205 384 1, 254 384 0, 320 380 1, 320 322 1, 251 320 0, 209 320 1, 64 320 0, 64 191 1, 64 130 0, 101 97 1, 137 64 0, 203 64 1, 253 64 0, 320 72 1, 74 512 1, 164 576 1, 246 576 1, 332 512 1, 281 512 1, 205 552 1, 204 552 1, 129 512 1
+576 64 0 512 704;512 30 1, 429 0 0, 334 0 1, 202 0 0, 133 73 1, 64 147 0, 64 287 1, 64 427 0, 134 502 1, 205 576 0, 338 576 1, 413 576 0, 512 566 1, 512 489 1, 394 512 0, 326 512 1, 230 512 0, 179 454 1, 128 396 0, 128 287 1, 128 180 0, 182 122 1, 237 64 0, 335 64 1, 417 64 0, 512 100 1, 320 640 1, 320 704 1, 384 704 1, 384 640 1
+384 64 0 320 576;320 11 1, 265 0 0, 216 0 1, 148 0 0, 106 53 1, 64 107 0, 64 192 1, 64 282 0, 107 333 1, 150 384 0, 228 384 1, 267 384 0, 320 380 1, 320 322 1, 268 320 0, 237 320 1, 128 320 0, 128 191 1, 128 130 0, 156 97 1, 183 64 0, 232 64 1, 270 64 0, 320 72 1, 192 512 1, 192 576 1, 256 576 1, 256 512 1
+576 64 0 512 704;512 30 1, 429 0 0, 334 0 1, 202 0 0, 133 73 1, 64 147 0, 64 287 1, 64 427 0, 134 502 1, 205 576 0, 338 576 1, 413 576 0, 512 566 1, 512 489 1, 394 512 0, 326 512 1, 230 512 0, 179 454 1, 128 396 0, 128 287 1, 128 180 0, 182 122 1, 237 64 0, 335 64 1, 417 64 0, 512 100 1, 457 704 1, 366 576 1, 285 576 1, 194 704 1, 250 704 1, 325 623 1, 326 623 1, 401 704 1
+384 0 0 448 576;320 11 1, 251 0 0, 190 0 1, 104 0 0, 52 53 1, 0 107 0, 0 192 1, 0 282 0, 54 333 1, 108 384 0, 205 384 1, 254 384 0, 320 380 1, 320 322 1, 251 320 0, 209 320 1, 64 320 0, 64 191 1, 64 130 0, 101 97 1, 137 64 0, 203 64 1, 253 64 0, 320 72 1, 387 576 1, 297 512 1, 215 512 1, 125 576 1, 180 576 1, 256 536 1, 256 536 1, 332 576 1
+576 64 0 512 704;64 0 1, 64 576 1, 227 576 1, 512 576 0, 512 301 1, 512 158 0, 438 79 1, 364 0 0, 228 0 1, 128 64 1, 223 64 1, 448 64 0, 448 292 1, 448 426 0, 360 481 1, 335 497 0, 299 504 1, 257 512 0, 186 512 1, 128 512 1, 374 704 1, 284 576 1, 202 576 1, 115 704 1, 167 704 1, 243 623 1, 244 623 1, 319 704 1
+448 64 0 448 576;320 135 1, 320 331 1, 265 320 0, 239 320 1, 128 320 0, 128 185 1, 128 129 0, 150 96 1, 172 64 0, 209 64 1, 258 64 0, 320 72 1, 300 40 0, 277 23 1, 245 0 0, 201 0 1, 140 0 0, 102 50 1, 64 100 0, 64 182 1, 64 278 0, 113 331 1, 162 384 0, 251 384 1, 285 384 0, 320 384 1, 320 576 1, 384 576 1, 384 0 1, 320 0 1, 384 400 1, 384 422 1, 409 430 0, 409 493 1, 409 499 1, 384 499 1, 384 576 1, 448 576 1, 448 510 1, 448 408 0
+576 0 0 512 576;64 0 1, 64 256 1, 0 256 1, 0 320 1, 64 320 1, 64 576 1, 229 576 1, 512 576 0, 512 301 1, 512 158 0, 438 79 1, 365 0 0, 231 0 1, 128 64 1, 225 64 1, 448 64 0, 448 292 1, 448 426 0, 361 481 1, 336 497 0, 300 504 1, 258 512 0, 188 512 1, 128 512 1, 128 320 1, 256 320 1, 256 256 1, 128 256 1
+448 64 0 448 576;320 448 1, 200 448 1, 200 512 1, 320 512 1, 320 576 1, 384 576 1, 384 512 1, 440 512 1, 440 448 1, 384 448 1, 384 0 1, 320 0 1, 320 72 1, 300 40 0, 277 23 1, 245 0 0, 201 0 1, 140 0 0, 102 50 1, 64 100 0, 64 182 1, 64 278 0, 113 331 1, 162 384 0, 251 384 1, 285 384 0, 320 384 1, 320 135 1, 320 331 1, 265 320 0, 239 320 1, 128 320 0, 128 185 1, 128 129 0, 150 96 1, 172 64 0, 209 64 1, 258 64 0
+512 64 0 512 640;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 128 576 1, 128 640 1, 384 640 1, 384 576 1
+448 64 0 448 512;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 64 448 1, 64 512 1, 320 512 1, 320 448 1
+512 64 0 512 768;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 129 743 1, 181 743 1, 190 722 0, 212 713 1, 234 704 0, 269 704 1, 308 704 0, 331 715 1, 349 724 0, 357 743 1, 408 743 1, 401 700 0, 371 674 1, 331 640 0, 268 640 1, 203 640 0, 163 677 1, 136 702 0
+448 64 0 448 640;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 93 579 1, 139 579 1, 147 543 0, 167 527 1, 186 512 0, 218 512 1, 253 512 0, 273 531 1, 289 546 0, 296 579 1, 342 579 1, 336 524 0, 309 491 1, 273 448 0, 217 448 1, 159 448 0, 123 495 1, 99 526 0
+512 64 0 512 704;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 256 640 1, 256 704 1, 320 704 1, 320 640 1
+448 64 0 448 576;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 128 512 1, 128 576 1, 192 576 1, 192 512 1
+512 64 -128 512 576;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 410 0 1, 448 0 1, 384 -19 0, 384 -42 1, 384 -64 0, 420 -64 1, 436 -64 0, 448 -98 1, 448 -128 1, 425 -128 0, 396 -128 1, 320 -128 0, 320 -73 1, 320 -31 0
+448 64 -128 448 384;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 251 0 1, 291 0 1, 256 -19 0, 256 -42 1, 256 -64 0, 292 -64 1, 308 -64 0, 320 -98 1, 320 -128 1, 297 -128 0, 268 -128 1, 192 -128 0, 192 -73 1, 192 -31 0
+512 64 0 512 704;64 0 1, 64 576 1, 448 576 1, 448 512 1, 128 512 1, 128 320 1, 448 320 1, 448 256 1, 128 256 1, 128 64 1, 512 64 1, 512 0 1, 413 704 1, 312 576 1, 221 576 1, 122 704 1, 182 704 1, 266 623 1, 267 623 1, 351 704 1
+448 0 0 448 576;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0, 323 576 1, 233 512 1, 151 512 1, 61 576 1, 116 576 1, 192 536 1, 192 536 1, 268 576 1
+576 64 0 512 704;512 256 1, 512 14 1, 418 0 0, 330 0 1, 64 0 0, 64 286 1, 64 426 0, 133 501 1, 202 576 0, 332 576 1, 416 576 0, 512 564 1, 512 485 1, 398 512 0, 323 512 1, 128 512 0, 128 289 1, 128 180 0, 183 122 1, 238 64 0, 340 64 1, 382 64 0, 448 57 1, 448 192 1, 384 192 1, 384 256 1, 222 576 1, 312 704 1, 391 704 1, 454 576 1, 415 576 1, 354 657 1, 353 657 1, 277 576 1
+448 64 -192 384 576;320 153 1, 320 331 1, 265 320 0, 240 320 1, 128 320 0, 128 190 1, 128 132 0, 150 98 1, 172 64 0, 209 64 1, 258 64 0, 320 90 1, 300 50 0, 277 29 1, 245 0 0, 202 0 1, 140 0 0, 102 52 1, 64 103 0, 64 186 1, 64 280 0, 113 332 1, 162 384 0, 250 384 1, 285 384 0, 320 384 1, 384 384 1, 384 105 1, 384 22 0, 374 -18 1, 348 -128 0, 194 -128 1, 130 -128 0, 64 -135 1, 64 -71 1, 143 -64 0, 198 -64 1, 320 -64 0, 320 29 1, 119 512 1, 208 576 1, 288 576 1, 370 512 1, 322 512 1, 248 552 1, 248 552 1, 174 512 1
+576 64 0 512 768;512 256 1, 512 14 1, 418 0 0, 330 0 1, 64 0 0, 64 286 1, 64 426 0, 133 501 1, 202 576 0, 332 576 1, 416 576 0, 512 564 1, 512 485 1, 398 512 0, 323 512 1, 128 512 0, 128 289 1, 128 180 0, 183 122 1, 238 64 0, 340 64 1, 382 64 0, 448 57 1, 448 192 1, 384 192 1, 384 256 1, 228 743 1, 274 743 1, 281 722 0, 300 713 1, 317 704 0, 345 704 1, 378 704 0, 396 715 1, 411 724 0, 417 743 1, 449 743 1, 444 700 0, 419 674 1, 388 640 0, 339 640 1, 286 640 0, 255 677 1, 233 702 0
+448 64 -192 384 640;320 153 1, 320 331 1, 265 320 0, 240 320 1, 128 320 0, 128 190 1, 128 132 0, 150 98 1, 172 64 0, 209 64 1, 258 64 0, 320 90 1, 300 50 0, 277 29 1, 245 0 0, 202 0 1, 140 0 0, 102 52 1, 64 103 0, 64 186 1, 64 280 0, 113 332 1, 162 384 0, 250 384 1, 285 384 0, 320 384 1, 384 384 1, 384 105 1, 384 22 0, 374 -18 1, 348 -128 0, 194 -128 1, 130 -128 0, 64 -135 1, 64 -71 1, 143 -64 0, 198 -64 1, 320 -64 0, 320 29 1, 131 602 1, 177 602 1, 185 588 0, 205 582 1, 225 576 0, 256 576 1, 291 576 0, 312 583 1, 328 589 0, 335 602 1, 381 602 1, 375 564 0, 348 542 1, 312 512 0, 256 512 1, 197 512 0, 161 544 1, 137 566 0
+576 64 0 512 704;512 256 1, 512 14 1, 418 0 0, 330 0 1, 64 0 0, 64 286 1, 64 426 0, 133 501 1, 202 576 0, 332 576 1, 416 576 0, 512 564 1, 512 485 1, 398 512 0, 323 512 1, 128 512 0, 128 289 1, 128 180 0, 183 122 1, 238 64 0, 340 64 1, 382 64 0, 448 57 1, 448 192 1, 384 192 1, 384 256 1, 320 640 1, 320 704 1, 384 704 1, 384 640 1
+448 64 -192 384 576;320 153 1, 320 331 1, 265 320 0, 240 320 1, 128 320 0, 128 190 1, 128 132 0, 150 98 1, 172 64 0, 209 64 1, 258 64 0, 320 90 1, 300 50 0, 277 29 1, 245 0 0, 202 0 1, 140 0 0, 102 52 1, 64 103 0, 64 186 1, 64 280 0, 113 332 1, 162 384 0, 250 384 1, 285 384 0, 320 384 1, 384 384 1, 384 105 1, 384 22 0, 374 -18 1, 348 -128 0, 194 -128 1, 130 -128 0, 64 -135 1, 64 -71 1, 143 -64 0, 198 -64 1, 320 -64 0, 320 29 1, 192 512 1, 192 576 1, 256 576 1, 256 512 1
+576 64 -192 512 576;512 256 1, 512 14 1, 417 0 0, 330 0 1, 64 0 0, 64 286 1, 64 426 0, 133 501 1, 202 576 0, 332 576 1, 416 576 0, 512 564 1, 512 485 1, 398 512 0, 323 512 1, 128 512 0, 128 289 1, 128 180 0, 183 122 1, 238 64 0, 340 64 1, 382 64 0, 448 57 1, 448 192 1, 384 192 1, 384 256 1, 291 -158 1, 291 -126 1, 299 -128 0, 305 -128 1, 320 -128 0, 320 -104 1, 320 -77 0, 309 -71 1, 309 -42 1, 343 -43 0, 360 -57 1, 384 -77 0, 384 -121 1, 384 -192 0, 325 -192 1, 309 -192 0
+448 64 -192 384 704;320 153 1, 320 331 1, 265 320 0, 240 320 1, 128 320 0, 128 190 1, 128 132 0, 150 98 1, 172 64 0, 209 64 1, 258 64 0, 320 90 1, 300 50 0, 277 29 1, 245 0 0, 202 0 1, 140 0 0, 102 52 1, 64 103 0, 64 186 1, 64 280 0, 113 332 1, 162 384 0, 250 384 1, 285 384 0, 320 384 1, 384 384 1, 384 105 1, 384 22 0, 374 -18 1, 348 -128 0, 194 -128 1, 130 -128 0, 64 -135 1, 64 -71 1, 143 -64 0, 198 -64 1, 320 -64 0, 320 29 1, 256 682 1, 256 660 1, 231 652 0, 231 592 1, 231 586 1, 256 586 1, 256 512 1, 192 512 1, 192 576 1, 192 674 0
+576 64 0 512 704;64 0 1, 64 576 1, 128 576 1, 128 320 1, 448 320 1, 448 576 1, 512 576 1, 512 0 1, 448 0 1, 448 256 1, 128 256 1, 128 0 1, 134 576 1, 240 704 1, 336 704 1, 441 576 1, 376 576 1, 288 657 1, 287 657 1, 199 576 1
+448 64 0 384 768;64 0 1, 64 576 1, 128 576 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 254 1, 320 293 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1, 88 640 1, 179 768 1, 272 768 1, 362 640 1, 312 640 1, 226 721 1, 225 721 1, 139 640 1
+576 0 0 576 576;128 320 1, 448 320 1, 448 384 1, 128 384 1, 64 0 1, 64 384 1, 8 384 1, 8 448 1, 64 448 1, 64 576 1, 128 576 1, 128 448 1, 448 448 1, 448 576 1, 512 576 1, 512 448 1, 568 448 1, 568 384 1, 512 384 1, 512 0 1, 448 0 1, 448 256 1, 128 256 1, 128 0 1
+448 0 0 384 576;64 0 1, 64 448 1, 8 448 1, 8 512 1, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 255 512 1, 255 448 1, 128 448 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 254 1, 320 293 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1
+192 -64 0 256 768;64 0 1, 64 576 1, 128 576 1, 128 0 1, -22 623 1, -20 655 0, -11 673 1, 5 704 0, 43 704 1, 68 704 0, 89 704 1, 110 704 1, 130 704 0, 141 704 1, 163 704 0, 167 710 1, 214 710 1, 212 682 0, 203 667 1, 187 640 0, 150 640 1, 125 640 0, 103 640 1, 82 640 1, 63 640 0, 51 640 1, 29 640 0, 25 623 1
+192 -64 0 256 640;64 0 1, 64 384 1, 128 384 1, 128 0 1, -24 480 1, -21 518 0, -13 539 1, 4 576 0, 43 576 1, 69 576 0, 90 576 1, 112 576 1, 132 576 0, 143 576 1, 166 576 0, 170 590 1, 216 590 1, 213 559 0, 205 542 1, 188 512 0, 150 512 1, 124 512 0, 102 512 1, 80 512 1, 61 512 0, 49 512 1, 26 512 0, 22 480 1
+192 0 0 256 640;64 0 1, 64 576 1, 128 576 1, 128 0 1, 0 576 1, 0 640 1, 256 640 1, 256 576 1
+192 -64 0 192 512;64 0 1, 64 384 1, 128 384 1, 128 0 1, -64 448 1, -64 512 1, 192 512 1, 192 448 1
+192 -64 0 256 768;64 0 1, 64 576 1, 128 576 1, 128 0 1, -22 743 1, 25 743 1, 32 722 0, 50 713 1, 68 704 0, 96 704 1, 128 704 0, 146 715 1, 161 724 0, 167 743 1, 214 743 1, 208 700 0, 182 674 1, 149 640 0, 96 640 1, 40 640 0, 7 677 1, -16 702 0
+192 -64 0 256 640;64 0 1, 64 384 1, 128 384 1, 128 0 1, -24 578 1, 22 578 1, 29 542 0, 48 527 1, 67 512 0, 96 512 1, 129 512 0, 148 531 1, 163 546 0, 170 578 1, 216 578 1, 210 524 0, 184 491 1, 150 448 0, 96 448 1, 39 448 0, 5 495 1, -18 526 0
+192 64 -128 192 576;64 0 1, 64 576 1, 128 576 1, 128 0 1, 94 0 1, 126 0 1, 128 -19 0, 128 -42 1, 128 -64 0, 143 -64 1, 150 -64 0, 155 -98 1, 155 -128 1, 139 -128 0, 118 -128 1, 64 -128 0, 64 -73 1, 64 -31 0
+192 0 -128 128 576;64 0 1, 64 384 1, 128 384 1, 128 0 1, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 59 0 1, 99 0 1, 64 -19 0, 64 -42 1, 64 -64 0, 100 -64 1, 116 -64 0, 128 -98 1, 128 -128 1, 105 -128 0, 76 -128 1, 0 -128 0, 0 -73 1, 0 -31 0
+192 64 0 128 704;64 0 1, 64 576 1, 128 576 1, 128 0 1, 64 640 1, 64 704 1, 128 704 1, 128 640 1
+576 64 -128 512 576;64 0 1, 64 576 1, 128 576 1, 128 0 1, 192 -87 1, 192 -19 1, 267 -64 0, 333 -64 1, 408 -64 0, 430 -29 1, 448 0 0, 448 71 1, 448 576 1, 512 576 1, 512 73 1, 512 -128 0, 317 -128 1, 252 -128 0
+320 64 -192 320 576;64 0 1, 64 384 1, 128 384 1, 128 0 1, 64 512 1, 64 576 1, 128 576 1, 128 512 1, 128 -145 1, 128 -87 1, 164 -64 0, 195 -64 1, 238 -64 0, 248 -47 1, 256 -32 0, 256 0 1, 256 384 1, 320 384 1, 320 0 1, 320 -128 0, 194 -128 1, 159 -128 0, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+384 0 -128 448 704;0 -87 1, 0 -19 1, 75 -64 0, 141 -64 1, 216 -64 0, 238 -29 1, 256 0 0, 256 71 1, 256 576 1, 320 576 1, 320 73 1, 320 -128 0, 125 -128 1, 60 -128 0, 137 576 1, 244 704 1, 314 704 1, 403 576 1, 347 576 1, 281 657 1, 280 657 1, 203 576 1
+192 -64 -192 256 576;-64 -145 1, -64 -87 1, -28 -64 0, 3 -64 1, 46 -64 0, 56 -47 1, 64 -32 0, 64 0 1, 64 384 1, 128 384 1, 128 0 1, 128 -128 0, 2 -128 1, -33 -128 0, -55 512 1, 52 576 1, 126 576 1, 216 512 1, 160 512 1, 91 552 1, 90 552 1, 11 512 1
+512 64 -192 512 576;64 0 1, 64 576 1, 128 576 1, 128 293 1, 359 576 1, 438 576 1, 214 301 1, 476 0 1, 377 0 1, 128 292 1, 128 0 1, 165 -158 1, 165 -126 1, 190 -128 0, 208 -128 1, 256 -128 0, 256 -104 1, 256 -77 0, 184 -71 1, 184 -42 1, 246 -43 0, 277 -57 1, 320 -77 0, 320 -121 1, 320 -192 0, 222 -192 1, 195 -192 0
+384 64 -192 384 576;64 0 1, 64 576 1, 128 576 1, 128 198 1, 265 384 1, 335 384 1, 205 203 1, 374 0 1, 284 0 1, 128 197 1, 128 0 1, 128 -158 1, 128 -126 1, 146 -128 0, 158 -128 1, 192 -128 0, 192 -104 1, 192 -77 0, 146 -71 1, 146 -42 1, 196 -43 0, 221 -57 1, 256 -77 0, 256 -121 1, 256 -192 0, 175 -192 1, 153 -192 0
+384 64 0 384 384;64 0 1, 64 384 1, 128 384 1, 128 198 1, 265 384 1, 335 384 1, 205 203 1, 374 0 1, 284 0 1, 128 197 1, 128 0 1
+448 64 0 384 704;64 0 1, 64 576 1, 128 576 1, 128 64 1, 384 64 1, 384 0 1, 68 576 1, 143 704 1, 224 704 1, 113 576 1
+192 0 0 256 704;64 0 1, 64 576 1, 128 576 1, 128 0 1, 40 640 1, 131 704 1, 216 704 1, 96 640 1
+448 64 -192 384 576;64 0 1, 64 576 1, 128 576 1, 128 64 1, 384 64 1, 384 0 1, 154 -158 1, 154 -126 1, 164 -128 0, 172 -128 1, 192 -128 0, 192 -104 1, 192 -77 0, 171 -71 1, 171 -42 1, 210 -43 0, 229 -57 1, 256 -77 0, 256 -121 1, 256 -192 0, 191 -192 1, 174 -192 0
+192 0 -192 128 576;64 0 1, 64 576 1, 128 576 1, 128 0 1, 0 -158 1, 0 -126 1, 18 -128 0, 30 -128 1, 64 -128 0, 64 -104 1, 64 -77 0, 18 -71 1, 18 -42 1, 68 -43 0, 93 -57 1, 128 -77 0, 128 -121 1, 128 -192 0, 47 -192 1, 25 -192 0
+448 64 0 384 576;64 0 1, 64 576 1, 128 576 1, 128 64 1, 384 64 1, 384 0 1, 256 400 1, 256 423 1, 281 431 0, 281 493 1, 281 500 1, 256 500 1, 256 576 1, 320 576 1, 320 510 1, 320 408 0
+256 64 0 256 576;64 0 1, 64 576 1, 128 576 1, 128 0 1, 192 410 1, 192 432 1, 217 440 0, 217 498 1, 217 504 1, 192 504 1, 192 576 1, 256 576 1, 256 514 1, 256 418 0
+448 64 0 384 576;64 0 1, 64 576 1, 128 576 1, 128 64 1, 384 64 1, 384 0 1, 320 256 1, 320 320 1, 384 320 1, 384 256 1
+256 64 0 256 576;64 0 1, 64 576 1, 128 576 1, 128 0 1, 192 256 1, 192 320 1, 256 320 1, 256 256 1
+448 0 0 384 576;64 0 1, 64 271 1, 0 240 1, 0 305 1, 64 337 1, 64 576 1, 128 576 1, 128 381 1, 256 433 1, 256 367 1, 128 316 1, 128 64 1, 384 64 1, 384 0 1
+192 0 0 192 576;64 0 1, 64 263 1, 0 237 1, 0 297 1, 64 324 1, 64 576 1, 128 576 1, 128 364 1, 192 388 1, 192 329 1, 128 303 1, 128 0 1
+576 64 0 512 704;64 0 1, 64 576 1, 138 576 1, 448 131 1, 448 576 1, 512 576 1, 512 0 1, 437 0 1, 128 445 1, 128 0 1, 228 576 1, 326 704 1, 418 704 1, 288 576 1
+448 64 0 384 576;64 0 1, 64 384 1, 128 384 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 253 1, 320 292 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+576 64 -192 512 576;64 0 1, 64 576 1, 138 576 1, 448 131 1, 448 576 1, 512 576 1, 512 0 1, 437 0 1, 128 445 1, 128 0 1, 198 -158 1, 198 -126 1, 214 -128 0, 225 -128 1, 256 -128 0, 256 -104 1, 256 -77 0, 218 -71 1, 218 -42 1, 265 -43 0, 288 -57 1, 320 -77 0, 320 -121 1, 320 -192 0, 243 -192 1, 222 -192 0
+448 64 -192 384 384;64 0 1, 64 384 1, 128 384 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 253 1, 320 292 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1, 128 -158 1, 128 -126 1, 146 -128 0, 158 -128 1, 192 -128 0, 192 -104 1, 192 -77 0, 146 -71 1, 146 -42 1, 196 -43 0, 221 -57 1, 256 -77 0, 256 -121 1, 256 -192 0, 175 -192 1, 153 -192 0
+576 64 0 512 704;64 0 1, 64 576 1, 138 576 1, 448 131 1, 448 576 1, 512 576 1, 512 0 1, 437 0 1, 128 445 1, 128 0 1, 430 704 1, 332 576 1, 244 576 1, 146 704 1, 206 704 1, 288 623 1, 288 623 1, 370 704 1
+448 0 0 384 576;64 0 1, 64 384 1, 128 384 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 253 1, 320 292 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1, 323 576 1, 233 512 1, 151 512 1, 61 576 1, 116 576 1, 192 536 1, 192 536 1, 268 576 1
+448 0 0 384 576;64 0 1, 64 384 1, 128 384 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 0 1, 320 0 1, 320 253 1, 320 292 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1, 0 399 1, 0 422 1, 25 430 0, 25 493 1, 25 499 1, 0 499 1, 0 576 1, 64 576 1, 64 509 1, 64 407 0
+576 64 -192 512 576;64 0 1, 64 576 1, 138 576 1, 448 131 1, 448 576 1, 512 576 1, 512 -35 1, 512 -128 0, 382 -128 1, 352 -128 0, 320 -150 1, 320 -92 1, 349 -64 0, 382 -64 1, 448 -64 0, 448 -21 1, 448 -15 1, 128 445 1, 128 0 1
+448 64 -192 384 384;64 0 1, 64 384 1, 128 384 1, 128 312 1, 157 344 0, 185 360 1, 226 384 0, 275 384 1, 384 384 0, 384 276 1, 384 -35 1, 384 -128 0, 254 -128 1, 224 -128 0, 192 -150 1, 192 -92 1, 223 -64 0, 250 -64 1, 320 -64 0, 320 -21 1, 320 253 1, 320 292 0, 308 306 1, 296 320 0, 264 320 1, 194 320 0, 128 249 1, 128 0 1
+576 64 0 576 640;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0, 192 576 1, 192 640 1, 448 640 1, 448 576 1
+448 64 0 384 512;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 64 448 1, 64 512 1, 320 512 1, 320 448 1
+576 64 0 576 768;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0, 174 743 1, 220 743 1, 228 722 0, 248 713 1, 268 704 0, 299 704 1, 334 704 0, 355 715 1, 371 724 0, 378 743 1, 424 743 1, 418 700 0, 391 674 1, 355 640 0, 299 640 1, 240 640 0, 204 677 1, 180 702 0
+448 64 0 384 640;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 89 579 1, 135 579 1, 143 543 0, 163 527 1, 182 512 0, 214 512 1, 249 512 0, 269 531 1, 285 546 0, 292 579 1, 338 579 1, 332 524 0, 305 491 1, 269 448 0, 213 448 1, 155 448 0, 119 495 1, 95 526 0
+576 64 0 576 704;320 576 1, 436 576 0, 506 498 1, 576 419 0, 576 289 1, 576 156 0, 506 78 1, 436 0 0, 316 0 1, 214 0 0, 147 64 1, 64 145 0, 64 288 1, 64 420 0, 134 498 1, 204 576 0, 320 512 1, 229 512 0, 179 453 1, 128 394 0, 128 288 1, 128 183 0, 179 124 1, 229 64 0, 318 64 1, 401 64 0, 450 112 1, 512 171 0, 512 289 1, 512 394 0, 461 453 1, 410 512 0, 212 612 1, 303 704 1, 374 704 1, 254 612 1, 344 612 1, 434 704 1, 506 704 1, 386 612 1
+448 64 0 448 576;224 384 1, 298 384 0, 341 333 1, 384 281 0, 384 193 1, 384 102 0, 341 51 1, 298 0 0, 222 0 1, 156 0 0, 116 42 1, 64 95 0, 64 192 1, 64 281 0, 107 333 1, 150 384 0, 224 320 1, 128 320 0, 128 192 1, 128 64 0, 224 64 1, 320 64 0, 320 193 1, 320 320 0, 109 456 1, 199 576 1, 271 576 1, 151 456 1, 241 456 1, 331 576 1, 403 576 1, 283 456 1
+576 64 0 576 704;64 0 1, 64 576 1, 281 576 1, 448 576 0, 448 439 1, 448 372 0, 408 329 1, 384 303 0, 340 283 1, 525 0 1, 428 0 1, 271 256 1, 128 256 1, 128 0 1, 128 320 1, 216 320 1, 303 320 0, 343 346 1, 384 373 0, 384 429 1, 384 474 0, 351 493 1, 318 512 0, 241 512 1, 128 512 1, 184 576 1, 274 704 1, 359 704 1, 239 576 1
+256 64 0 320 576;64 0 1, 64 384 1, 128 384 1, 128 312 1, 145 345 0, 165 361 1, 194 384 0, 233 384 1, 241 384 0, 256 391 1, 256 326 1, 235 320 0, 222 320 1, 178 320 0, 128 253 1, 128 0 1, 104 512 1, 195 576 1, 280 576 1, 160 512 1
+576 64 -192 576 576;64 0 1, 64 576 1, 281 576 1, 448 576 0, 448 439 1, 448 372 0, 408 329 1, 384 303 0, 340 283 1, 525 0 1, 428 0 1, 271 256 1, 128 256 1, 128 0 1, 128 320 1, 216 320 1, 303 320 0, 343 346 1, 384 373 0, 384 429 1, 384 474 0, 351 493 1, 318 512 0, 241 512 1, 128 512 1, 184 -158 1, 184 -126 1, 204 -128 0, 218 -128 1, 256 -128 0, 256 -104 1, 256 -77 0, 202 -71 1, 202 -42 1, 256 -43 0, 283 -57 1, 320 -77 0, 320 -121 1, 320 -192 0, 234 -192 1, 210 -192 0
+256 64 -192 256 448;64 0 1, 64 384 1, 128 384 1, 128 312 1, 145 345 0, 165 361 1, 194 384 0, 233 384 1, 241 384 0, 256 391 1, 256 326 1, 235 320 0, 222 320 1, 178 320 0, 128 253 1, 128 0 1, 64 -158 1, 64 -126 1, 82 -128 0, 94 -128 1, 128 -128 0, 128 -104 1, 128 -77 0, 82 -71 1, 82 -42 1, 132 -43 0, 157 -57 1, 192 -77 0, 192 -121 1, 192 -192 0, 111 -192 1, 89 -192 0
+576 64 0 576 704;64 0 1, 64 576 1, 281 576 1, 448 576 0, 448 439 1, 448 372 0, 408 329 1, 384 303 0, 340 283 1, 525 0 1, 428 0 1, 271 256 1, 128 256 1, 128 0 1, 128 320 1, 216 320 1, 303 320 0, 343 346 1, 384 373 0, 384 429 1, 384 474 0, 351 493 1, 318 512 0, 241 512 1, 128 512 1, 356 704 1, 265 576 1, 184 576 1, 100 704 1, 149 704 1, 224 623 1, 225 623 1, 300 704 1
+256 -64 0 320 576;64 0 1, 64 384 1, 128 384 1, 128 312 1, 145 345 0, 165 361 1, 194 384 0, 233 384 1, 241 384 0, 256 391 1, 256 326 1, 235 320 0, 222 320 1, 178 320 0, 128 253 1, 128 0 1, 259 576 1, 169 512 1, 87 512 1, -3 576 1, 52 576 1, 128 536 1, 128 536 1, 204 576 1
+512 64 0 512 704;64 21 1, 64 102 1, 189 64 0, 311 64 1, 448 64 0, 448 152 1, 448 197 0, 410 218 1, 381 235 0, 315 253 1, 229 278 1, 64 324 0, 64 431 1, 64 576 0, 267 576 1, 355 576 0, 448 566 1, 448 491 1, 347 512 0, 255 512 1, 128 512 0, 128 431 1, 128 399 0, 154 379 1, 180 359 0, 247 340 1, 334 316 1, 432 288 0, 472 252 1, 512 216 0, 512 156 1, 512 84 0, 454 42 1, 396 0 0, 294 0 1, 193 0 0, 214 576 1, 304 704 1, 389 704 1, 269 576 1
+384 64 0 384 576;64 13 1, 64 77 1, 128 64 0, 183 64 1, 256 64 0, 256 116 1, 256 152 0, 204 168 1, 147 187 1, 64 214 0, 64 286 1, 64 384 0, 215 384 1, 258 384 0, 320 381 1, 320 323 1, 263 320 0, 206 320 1, 128 320 0, 128 276 1, 128 244 0, 174 230 1, 225 213 1, 320 182 0, 320 106 1, 320 57 0, 283 29 1, 245 0 0, 180 0 1, 129 0 0, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+512 64 0 512 704;64 21 1, 64 102 1, 189 64 0, 311 64 1, 448 64 0, 448 152 1, 448 197 0, 410 218 1, 381 235 0, 315 253 1, 229 278 1, 64 324 0, 64 431 1, 64 576 0, 267 576 1, 355 576 0, 448 566 1, 448 491 1, 347 512 0, 255 512 1, 128 512 0, 128 431 1, 128 399 0, 154 379 1, 180 359 0, 247 340 1, 334 316 1, 432 288 0, 472 252 1, 512 216 0, 512 156 1, 512 84 0, 454 42 1, 396 0 0, 294 0 1, 193 0 0, 139 576 1, 229 704 1, 310 704 1, 400 576 1, 344 576 1, 270 657 1, 269 657 1, 194 576 1
+384 64 0 384 576;64 13 1, 64 77 1, 128 64 0, 183 64 1, 256 64 0, 256 116 1, 256 152 0, 204 168 1, 147 187 1, 64 214 0, 64 286 1, 64 384 0, 215 384 1, 258 384 0, 320 381 1, 320 323 1, 263 320 0, 206 320 1, 128 320 0, 128 276 1, 128 244 0, 174 230 1, 225 213 1, 320 182 0, 320 106 1, 320 57 0, 283 29 1, 245 0 0, 180 0 1, 129 0 0, 94 512 1, 181 576 1, 260 576 1, 348 512 1, 293 512 1, 221 552 1, 220 552 1, 147 512 1
+512 64 -192 512 576;64 21 1, 64 102 1, 189 64 0, 311 64 1, 448 64 0, 448 152 1, 448 197 0, 410 218 1, 381 235 0, 315 253 1, 229 278 1, 64 324 0, 64 431 1, 64 576 0, 267 576 1, 355 576 0, 448 566 1, 448 491 1, 347 512 0, 255 512 1, 128 512 0, 128 431 1, 128 399 0, 154 379 1, 180 359 0, 247 340 1, 334 316 1, 432 288 0, 472 252 1, 512 216 0, 512 157 1, 512 84 0, 454 42 1, 396 0 0, 294 0 1, 193 0 0, 243 0 1, 279 0 1, 257 -41 1, 280 -42 0, 297 -59 1, 320 -82 0, 320 -116 1, 320 -148 0, 300 -170 1, 279 -192 0, 250 -192 1, 227 -192 0, 200 -154 1, 200 -124 1, 213 -128 0, 228 -128 1, 256 -128 0, 256 -101 1, 256 -67 0, 208 -66 1
+384 64 -192 320 384;64 13 1, 64 77 1, 128 64 0, 183 64 1, 256 64 0, 256 116 1, 256 152 0, 204 168 1, 147 187 1, 64 214 0, 64 286 1, 64 384 0, 215 384 1, 258 384 0, 320 381 1, 320 323 1, 263 320 0, 206 320 1, 128 320 0, 128 276 1, 128 244 0, 174 230 1, 225 213 1, 320 182 0, 320 106 1, 320 57 0, 283 29 1, 245 0 0, 180 0 1, 129 0 0, 171 0 1, 207 0 1, 184 -41 1, 211 -42 0, 230 -59 1, 256 -82 0, 256 -116 1, 256 -148 0, 234 -170 1, 213 -192 0, 180 -192 1, 155 -192 0, 127 -154 1, 127 -124 1, 143 -128 0, 160 -128 1, 192 -128 0, 192 -101 1, 192 -67 0, 135 -66 1
+512 64 0 512 704;64 21 1, 64 102 1, 189 64 0, 311 64 1, 448 64 0, 448 152 1, 448 197 0, 410 218 1, 381 235 0, 315 253 1, 229 278 1, 64 324 0, 64 431 1, 64 576 0, 267 576 1, 355 576 0, 448 566 1, 448 491 1, 347 512 0, 255 512 1, 128 512 0, 128 431 1, 128 399 0, 154 379 1, 180 359 0, 247 340 1, 334 316 1, 432 288 0, 472 252 1, 512 216 0, 512 156 1, 512 84 0, 454 42 1, 396 0 0, 294 0 1, 193 0 0, 400 704 1, 310 576 1, 229 576 1, 139 704 1, 194 704 1, 269 623 1, 270 623 1, 344 704 1
+384 0 0 384 576;64 13 1, 64 77 1, 128 64 0, 183 64 1, 256 64 0, 256 116 1, 256 152 0, 204 168 1, 147 187 1, 64 214 0, 64 286 1, 64 384 0, 215 384 1, 258 384 0, 320 381 1, 320 323 1, 263 320 0, 206 320 1, 128 320 0, 128 276 1, 128 244 0, 174 230 1, 225 213 1, 320 182 0, 320 106 1, 320 57 0, 283 29 1, 245 0 0, 180 0 1, 129 0 0, 323 576 1, 233 512 1, 151 512 1, 61 576 1, 116 576 1, 192 536 1, 192 536 1, 268 576 1
+448 0 -192 448 576;192 0 1, 192 512 1, 0 512 1, 0 576 1, 448 576 1, 448 512 1, 256 512 1, 256 0 1, 212 0 1, 242 0 1, 223 -41 1, 259 -42 0, 285 -59 1, 320 -82 0, 320 -115 1, 320 -148 0, 295 -170 1, 270 -192 0, 234 -192 1, 205 -192 0, 173 -154 1, 173 -124 1, 193 -128 0, 214 -128 1, 256 -128 0, 256 -101 1, 256 -67 0, 181 -66 1
+192 0 -192 192 512;192 -2 1, 172 0 0, 154 0 1, 64 0 0, 64 103 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 458 1, 128 465 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 115 1, 128 84 0, 136 74 1, 144 64 0, 168 64 1, 182 64 0, 192 45 1, 112 0 1, 145 0 1, 124 -41 1, 149 -42 0, 167 -59 1, 192 -82 0, 192 -115 1, 192 -148 0, 172 -170 1, 152 -192 0, 123 -192 1, 100 -192 0, 74 -154 1, 74 -124 1, 87 -128 0, 101 -128 1, 128 -128 0, 128 -101 1, 128 -67 0, 81 -66 1
+448 0 0 448 704;192 0 1, 192 512 1, 0 512 1, 0 576 1, 448 576 1, 448 512 1, 256 512 1, 256 0 1, 350 704 1, 258 576 1, 190 576 1, 98 704 1, 155 704 1, 224 623 1, 224 623 1, 293 704 1
+320 0 -64 256 640;192 -2 1, 172 0 0, 154 0 1, 64 0 0, 64 103 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 468 1, 128 476 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 115 1, 128 84 0, 136 74 1, 144 64 0, 168 64 1, 182 64 0, 192 45 1, 192 447 1, 192 472 1, 208 481 0, 208 549 1, 208 556 1, 192 556 1, 192 640 1, 256 640 1, 256 567 1, 256 456 0
+448 0 0 448 576;192 0 1, 192 256 1, 64 256 1, 64 320 1, 192 320 1, 192 512 1, 0 512 1, 0 576 1, 448 576 1, 448 512 1, 256 512 1, 256 320 1, 384 320 1, 384 256 1, 256 256 1, 256 0 1
+192 0 -64 192 512;64 192 1, 0 192 1, 0 256 1, 64 256 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 458 1, 128 465 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 256 1, 192 256 1, 192 192 1, 128 192 1, 128 114 1, 128 84 0, 136 74 1, 144 64 0, 168 64 1, 182 64 0, 192 45 1, 192 -2 1, 172 0 0, 154 0 1, 64 0 0, 64 102 1
+576 64 0 512 768;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 146 623 1, 149 655 0, 160 673 1, 179 704 0, 226 704 1, 256 704 0, 282 704 1, 308 704 1, 332 704 0, 345 704 1, 372 704 0, 377 710 1, 430 710 1, 427 682 0, 416 667 1, 397 640 0, 351 640 1, 321 640 0, 294 640 1, 268 640 1, 245 640 0, 231 640 1, 204 640 0, 199 623 1
+448 64 0 384 640;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 93 480 1, 96 519 0, 106 539 1, 125 576 0, 169 576 1, 198 576 0, 223 576 1, 248 576 1, 271 576 0, 283 576 1, 310 576 0, 314 590 1, 355 590 1, 352 559 0, 342 542 1, 324 512 0, 280 512 1, 250 512 0, 225 512 1, 200 512 1, 178 512 0, 165 512 1, 138 512 0, 134 480 1
+576 64 0 512 640;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 192 576 1, 192 640 1, 384 640 1, 384 576 1
+448 64 0 384 512;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 64 448 1, 64 512 1, 320 512 1, 320 448 1
+576 64 0 512 768;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 146 743 1, 199 743 1, 208 722 0, 231 713 1, 253 704 0, 288 704 1, 328 704 0, 351 715 1, 369 724 0, 377 743 1, 430 743 1, 423 700 0, 392 674 1, 352 640 0, 288 640 1, 221 640 0, 181 677 1, 153 702 0
+448 64 0 384 640;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 93 578 1, 134 578 1, 143 543 0, 166 527 1, 188 512 0, 224 512 1, 264 512 0, 287 531 1, 306 546 0, 314 578 1, 355 578 1, 349 524 0, 320 491 1, 283 448 0, 224 448 1, 162 448 0, 125 495 1, 100 526 0
+576 64 0 512 768;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 288 768 1, 328 768 0, 356 749 1, 384 731 0, 384 704 1, 384 677 0, 356 659 1, 328 640 0, 287 640 1, 252 640 0, 226 655 1, 192 675 0, 192 704 1, 192 731 0, 220 749 1, 248 768 0, 288 704 1, 275 704 0, 265 704 1, 256 704 0, 256 704 1, 256 704 0, 265 704 1, 275 704 0, 288 704 1, 300 704 0, 309 704 1, 320 704 0, 320 704 1, 320 704 0, 310 704 1, 301 704 0
+448 64 0 384 640;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 192 640 1, 219 640 0, 237 621 1, 256 603 0, 256 576 1, 256 549 0, 237 531 1, 219 512 0, 191 512 1, 168 512 0, 151 527 1, 128 547 0, 128 576 1, 128 603 0, 147 621 1, 165 640 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0, 192 576 1, 192 576 0
+576 64 0 512 704;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 180 612 1, 283 704 1, 364 704 1, 228 612 1, 330 612 1, 432 704 1, 502 704 1, 377 612 1
+448 64 0 448 576;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 109 456 1, 199 576 1, 271 576 1, 151 456 1, 241 456 1, 331 576 1, 403 576 1, 283 456 1
+576 64 -128 512 576;64 576 1, 128 576 1, 128 213 1, 128 158 0, 139 132 1, 150 106 0, 180 88 1, 223 64 0, 295 64 1, 379 64 0, 414 97 1, 448 129 0, 448 210 1, 448 576 1, 512 576 1, 512 211 1, 512 139 0, 497 102 1, 482 64 0, 440 37 1, 385 0 0, 292 0 1, 174 0 0, 119 51 1, 64 102 0, 64 214 1, 308 0 1, 354 0 1, 320 -19 0, 320 -42 1, 320 -64 0, 358 -64 1, 375 -64 0, 387 -98 1, 387 -128 1, 363 -128 0, 333 -128 1, 256 -128 0, 256 -73 1, 256 -31 0
+448 64 -128 384 384;320 0 1, 320 72 1, 291 40 0, 263 24 1, 222 0 0, 174 0 1, 64 0 0, 64 108 1, 64 384 1, 128 384 1, 128 131 1, 128 92 0, 140 78 1, 152 64 0, 184 64 1, 254 64 0, 320 135 1, 320 384 1, 384 384 1, 384 0 1, 315 0 1, 355 0 1, 320 -19 0, 320 -42 1, 320 -64 0, 356 -64 1, 372 -64 0, 384 -98 1, 384 -128 1, 361 -128 0, 332 -128 1, 256 -128 0, 256 -73 1, 256 -31 0
+704 0 0 768 704;152 0 1, 9 576 1, 85 576 1, 199 121 1, 329 576 1, 405 576 1, 530 125 1, 651 576 1, 716 576 1, 560 0 1, 482 0 1, 358 444 1, 230 0 1, 236 576 1, 326 704 1, 408 704 1, 498 576 1, 443 576 1, 367 657 1, 366 657 1, 291 576 1
+576 0 0 576 576;102 0 1, 4 384 1, 77 384 1, 150 95 1, 244 384 1, 318 384 1, 400 94 1, 486 384 1, 549 384 1, 435 0 1, 361 0 1, 275 297 1, 177 0 1, 149 512 1, 240 576 1, 321 576 1, 412 512 1, 356 512 1, 281 552 1, 280 552 1, 205 512 1
+512 -64 0 512 704;192 0 1, 192 240 1, -7 576 1, 83 576 1, 232 309 1, 395 576 1, 468 576 1, 256 242 1, 256 0 1, 115 576 1, 203 704 1, 273 704 1, 363 576 1, 307 576 1, 236 657 1, 236 657 1, 171 576 1
+384 0 -128 384 576;152 0 1, 7 384 1, 82 384 1, 193 90 1, 314 384 1, 380 384 1, 164 -128 1, 87 -128 1, 67 512 1, 157 576 1, 239 576 1, 329 512 1, 274 512 1, 198 552 1, 198 552 1, 122 512 1
+448 64 0 448 704;64 0 1, 64 64 1, 351 512 1, 64 512 1, 64 576 1, 448 576 1, 448 512 1, 142 64 1, 448 64 1, 448 0 1, 190 576 1, 283 704 1, 370 704 1, 247 576 1
+384 0 0 384 576;0 0 1, 0 64 1, 291 320 1, 64 320 1, 64 384 1, 384 384 1, 384 320 1, 145 64 1, 384 64 1, 384 0 1, 168 512 1, 259 576 1, 344 576 1, 224 512 1
+448 64 0 448 704;64 0 1, 64 64 1, 331 512 1, 64 512 1, 64 576 1, 448 576 1, 448 512 1, 131 64 1, 448 64 1, 448 0 1, 192 640 1, 192 704 1, 256 704 1, 256 640 1
+384 0 0 384 576;0 0 1, 0 64 1, 291 320 1, 64 320 1, 64 384 1, 384 384 1, 384 320 1, 145 64 1, 384 64 1, 384 0 1, 128 512 1, 128 576 1, 192 576 1, 192 512 1
+448 64 0 448 704;64 0 1, 64 64 1, 351 512 1, 64 512 1, 64 576 1, 448 576 1, 448 512 1, 142 64 1, 448 64 1, 448 0 1, 386 704 1, 293 576 1, 209 576 1, 117 704 1, 174 704 1, 251 623 1, 252 623 1, 329 704 1
+384 0 0 384 576;0 0 1, 0 64 1, 291 320 1, 64 320 1, 64 384 1, 384 384 1, 384 320 1, 145 64 1, 384 64 1, 384 0 1, 323 576 1, 233 512 1, 151 512 1, 61 576 1, 116 576 1, 192 536 1, 192 536 1, 268 576 1
+192 0 0 192 640;64 0 1, 64 352 1, 0 352 1, 0 407 1, 64 407 1, 64 456 1, 64 513 0, 91 544 1, 119 576 0, 169 576 1, 176 576 0, 192 600 1, 192 545 1, 181 512 0, 175 512 1, 128 512 0, 128 464 1, 128 0 1
+512 64 -192 512 576;64 21 1, 64 102 1, 189 64 0, 311 64 1, 448 64 0, 448 152 1, 448 197 0, 410 218 1, 381 235 0, 315 253 1, 229 278 1, 64 324 0, 64 431 1, 64 576 0, 267 576 1, 355 576 0, 448 566 1, 448 491 1, 347 512 0, 255 512 1, 128 512 0, 128 431 1, 128 399 0, 154 379 1, 180 359 0, 247 340 1, 334 316 1, 432 288 0, 472 252 1, 512 216 0, 512 157 1, 512 84 0, 454 42 1, 396 0 0, 294 0 1, 193 0 0, 214 -158 1, 214 -126 1, 226 -128 0, 234 -128 1, 256 -128 0, 256 -104 1, 256 -77 0, 233 -71 1, 233 -42 1, 273 -43 0, 292 -57 1, 320 -77 0, 320 -121 1, 320 -192 0, 253 -192 1, 234 -192 0
+384 64 -192 320 384;64 13 1, 64 77 1, 128 64 0, 183 64 1, 256 64 0, 256 116 1, 256 152 0, 204 168 1, 147 187 1, 64 214 0, 64 286 1, 64 384 0, 215 384 1, 258 384 0, 320 381 1, 320 323 1, 263 320 0, 206 320 1, 128 320 0, 128 276 1, 128 244 0, 174 230 1, 225 213 1, 320 182 0, 320 106 1, 320 57 0, 283 29 1, 245 0 0, 180 0 1, 129 0 0, 128 -158 1, 128 -126 1, 146 -128 0, 158 -128 1, 192 -128 0, 192 -104 1, 192 -77 0, 146 -71 1, 146 -42 1, 196 -43 0, 221 -57 1, 256 -77 0, 256 -121 1, 256 -192 0, 175 -192 1, 153 -192 0
+448 0 -192 448 576;192 0 1, 192 512 1, 0 512 1, 0 576 1, 448 576 1, 448 512 1, 256 512 1, 256 0 1, 173 -158 1, 173 -126 1, 196 -128 0, 212 -128 1, 256 -128 0, 256 -104 1, 256 -77 0, 192 -71 1, 192 -42 1, 251 -43 0, 279 -57 1, 320 -77 0, 320 -121 1, 320 -192 0, 227 -192 1, 201 -192 0
+192 0 -192 192 512;192 -2 1, 172 0 0, 154 0 1, 64 0 0, 64 103 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 458 1, 128 465 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 115 1, 128 84 0, 136 74 1, 144 64 0, 168 64 1, 182 64 0, 192 45 1, 64 -158 1, 64 -126 1, 82 -128 0, 94 -128 1, 128 -128 0, 128 -104 1, 128 -77 0, 82 -71 1, 82 -42 1, 132 -43 0, 157 -57 1, 192 -77 0, 192 -121 1, 192 -192 0, 111 -192 1, 89 -192 0
+256 64 -192 192 0;64 -158 1, 64 -126 1, 82 -128 0, 94 -128 1, 128 -128 0, 128 -104 1, 128 -77 0, 82 -71 1, 82 -42 1, 132 -43 0, 157 -57 1, 192 -77 0, 192 -121 1, 192 -192 0, 111 -192 1, 89 -192 0
+192 64 -128 128 384;64 -120 1, 64 -93 1, 87 -79 0, 87 -9 1, 87 0 1, 64 0 1, 64 64 1, 128 64 1, 128 10 1, 128 -102 0, 64 320 1, 64 384 1, 128 384 1, 128 320 1
+192 64 192 128 256;64 192 1, 64 256 1, 128 256 1, 128 192 1
+256 64 192 192 256;64 192 1, 64 256 1, 192 256 1, 192 192 1
+256 64 192 192 256;64 192 1, 64 256 1, 192 256 1, 192 192 1
+448 0 192 448 256;38 192 1, 38 256 1, 390 256 1, 390 192 1
+768 0 192 768 256;37 192 1, 37 256 1, 731 256 1, 731 192 1
+192 0 0 0 0;
+448 64 512 384 576;64 512 1, 64 576 1, 384 576 1, 384 512 1
+448 64 0 448 384;311 256 1, 310 277 0, 303 287 1, 284 320 0, 219 320 1, 173 320 0, 147 305 1, 121 290 0, 115 256 1, 384 72 1, 384 13 1, 314 0 0, 256 0 1, 168 0 0, 116 53 1, 64 107 0, 64 197 1, 64 283 0, 110 333 1, 156 384 0, 234 384 1, 323 384 0, 360 325 1, 387 281 0, 386 212 1, 386 192 1, 114 192 1, 119 153 0, 129 132 1, 162 64 0, 260 64 1, 316 64 0
+448 64 192 384 256;64 192 1, 64 256 1, 384 256 1, 384 192 1
+128 -192 -64 320 576;-165 -14 1, 243 569 1, 293 569 1, -114 -14 1
+192 64 192 128 256;64 192 1, 64 256 1, 128 256 1, 128 192 1
+384 0 0 320 640;64 0 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 468 1, 64 640 0, 194 640 1, 221 640 0, 256 613 1, 256 557 1, 219 576 0, 193 576 1, 157 576 0, 142 555 1, 128 534 0, 128 482 1, 128 384 1, 320 384 1, 320 0 1, 256 0 1, 256 320 1, 128 320 1, 128 0 1, 256 512 1, 256 576 1, 320 576 1, 320 512 1
+384 0 0 320 576;64 0 1, 64 320 1, 0 320 1, 0 384 1, 64 384 1, 64 435 1, 64 576 0, 175 576 1, 256 576 1, 320 576 1, 320 0 1, 256 0 1, 256 518 1, 240 516 1, 206 512 0, 183 512 1, 148 512 0, 137 493 1, 128 477 0, 128 443 1, 128 384 1, 192 384 1, 192 320 1, 128 320 1, 128 0 1
+256 -64 192 256 576;128 229 1, 128 320 1, -25 320 1, -25 382 1, 126 576 1, 192 576 1, 192 384 1, 238 384 1, 238 320 1, 192 320 1, 192 229 1, 24 384 1, 128 384 1, 128 516 1
+192 -64 -192 128 384;-64 -145 1, -64 -87 1, -28 -64 0, 3 -64 1, 46 -64 0, 56 -47 1, 64 -32 0, 64 0 1, 64 384 1, 128 384 1, 128 0 1, 128 -128 0, 2 -128 1, -33 -128 0
+192 0 0 0 0;
diff --git a/vendor/github.com/golang/freetype/testdata/luxisr.ttf b/vendor/github.com/golang/freetype/testdata/luxisr.ttf
new file mode 100644
index 000000000..c47fd20be
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luxisr.ttf
Binary files differ
diff --git a/vendor/github.com/golang/freetype/testdata/luxisr.ttx b/vendor/github.com/golang/freetype/testdata/luxisr.ttx
new file mode 100644
index 000000000..98eea53e4
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/luxisr.ttx
@@ -0,0 +1,22503 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="2.4">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name=".notdef#1"/>
+ <GlyphID id="2" name=".notdef#2"/>
+ <GlyphID id="3" name="space"/>
+ <GlyphID id="4" name="exclam"/>
+ <GlyphID id="5" name="quotedbl"/>
+ <GlyphID id="6" name="numbersign"/>
+ <GlyphID id="7" name="dollar"/>
+ <GlyphID id="8" name="percent"/>
+ <GlyphID id="9" name="ampersand"/>
+ <GlyphID id="10" name="quotesingle"/>
+ <GlyphID id="11" name="parenleft"/>
+ <GlyphID id="12" name="parenright"/>
+ <GlyphID id="13" name="asterisk"/>
+ <GlyphID id="14" name="plus"/>
+ <GlyphID id="15" name="comma"/>
+ <GlyphID id="16" name="hyphen"/>
+ <GlyphID id="17" name="period"/>
+ <GlyphID id="18" name="slash"/>
+ <GlyphID id="19" name="zero"/>
+ <GlyphID id="20" name="one"/>
+ <GlyphID id="21" name="two"/>
+ <GlyphID id="22" name="three"/>
+ <GlyphID id="23" name="four"/>
+ <GlyphID id="24" name="five"/>
+ <GlyphID id="25" name="six"/>
+ <GlyphID id="26" name="seven"/>
+ <GlyphID id="27" name="eight"/>
+ <GlyphID id="28" name="nine"/>
+ <GlyphID id="29" name="colon"/>
+ <GlyphID id="30" name="semicolon"/>
+ <GlyphID id="31" name="less"/>
+ <GlyphID id="32" name="equal"/>
+ <GlyphID id="33" name="greater"/>
+ <GlyphID id="34" name="question"/>
+ <GlyphID id="35" name="at"/>
+ <GlyphID id="36" name="A"/>
+ <GlyphID id="37" name="B"/>
+ <GlyphID id="38" name="C"/>
+ <GlyphID id="39" name="D"/>
+ <GlyphID id="40" name="E"/>
+ <GlyphID id="41" name="F"/>
+ <GlyphID id="42" name="G"/>
+ <GlyphID id="43" name="H"/>
+ <GlyphID id="44" name="I"/>
+ <GlyphID id="45" name="J"/>
+ <GlyphID id="46" name="K"/>
+ <GlyphID id="47" name="L"/>
+ <GlyphID id="48" name="M"/>
+ <GlyphID id="49" name="N"/>
+ <GlyphID id="50" name="O"/>
+ <GlyphID id="51" name="P"/>
+ <GlyphID id="52" name="Q"/>
+ <GlyphID id="53" name="R"/>
+ <GlyphID id="54" name="S"/>
+ <GlyphID id="55" name="T"/>
+ <GlyphID id="56" name="U"/>
+ <GlyphID id="57" name="V"/>
+ <GlyphID id="58" name="W"/>
+ <GlyphID id="59" name="X"/>
+ <GlyphID id="60" name="Y"/>
+ <GlyphID id="61" name="Z"/>
+ <GlyphID id="62" name="bracketleft"/>
+ <GlyphID id="63" name="backslash"/>
+ <GlyphID id="64" name="bracketright"/>
+ <GlyphID id="65" name="asciicircum"/>
+ <GlyphID id="66" name="underscore"/>
+ <GlyphID id="67" name="grave"/>
+ <GlyphID id="68" name="a"/>
+ <GlyphID id="69" name="b"/>
+ <GlyphID id="70" name="c"/>
+ <GlyphID id="71" name="d"/>
+ <GlyphID id="72" name="e"/>
+ <GlyphID id="73" name="f"/>
+ <GlyphID id="74" name="g"/>
+ <GlyphID id="75" name="h"/>
+ <GlyphID id="76" name="i"/>
+ <GlyphID id="77" name="j"/>
+ <GlyphID id="78" name="k"/>
+ <GlyphID id="79" name="l"/>
+ <GlyphID id="80" name="m"/>
+ <GlyphID id="81" name="n"/>
+ <GlyphID id="82" name="o"/>
+ <GlyphID id="83" name="p"/>
+ <GlyphID id="84" name="q"/>
+ <GlyphID id="85" name="r"/>
+ <GlyphID id="86" name="s"/>
+ <GlyphID id="87" name="t"/>
+ <GlyphID id="88" name="u"/>
+ <GlyphID id="89" name="v"/>
+ <GlyphID id="90" name="w"/>
+ <GlyphID id="91" name="x"/>
+ <GlyphID id="92" name="y"/>
+ <GlyphID id="93" name="z"/>
+ <GlyphID id="94" name="braceleft"/>
+ <GlyphID id="95" name="bar"/>
+ <GlyphID id="96" name="braceright"/>
+ <GlyphID id="97" name="asciitilde"/>
+ <GlyphID id="98" name="Adieresis"/>
+ <GlyphID id="99" name="Aring"/>
+ <GlyphID id="100" name="Ccedilla"/>
+ <GlyphID id="101" name="Eacute"/>
+ <GlyphID id="102" name="Ntilde"/>
+ <GlyphID id="103" name="Odieresis"/>
+ <GlyphID id="104" name="Udieresis"/>
+ <GlyphID id="105" name="aacute"/>
+ <GlyphID id="106" name="agrave"/>
+ <GlyphID id="107" name="acircumflex"/>
+ <GlyphID id="108" name="adieresis"/>
+ <GlyphID id="109" name="atilde"/>
+ <GlyphID id="110" name="aring"/>
+ <GlyphID id="111" name="ccedilla"/>
+ <GlyphID id="112" name="eacute"/>
+ <GlyphID id="113" name="egrave"/>
+ <GlyphID id="114" name="ecircumflex"/>
+ <GlyphID id="115" name="edieresis"/>
+ <GlyphID id="116" name="iacute"/>
+ <GlyphID id="117" name="igrave"/>
+ <GlyphID id="118" name="icircumflex"/>
+ <GlyphID id="119" name="idieresis"/>
+ <GlyphID id="120" name="ntilde"/>
+ <GlyphID id="121" name="oacute"/>
+ <GlyphID id="122" name="ograve"/>
+ <GlyphID id="123" name="ocircumflex"/>
+ <GlyphID id="124" name="odieresis"/>
+ <GlyphID id="125" name="otilde"/>
+ <GlyphID id="126" name="uacute"/>
+ <GlyphID id="127" name="ugrave"/>
+ <GlyphID id="128" name="ucircumflex"/>
+ <GlyphID id="129" name="udieresis"/>
+ <GlyphID id="130" name="dagger"/>
+ <GlyphID id="131" name="degree"/>
+ <GlyphID id="132" name="cent"/>
+ <GlyphID id="133" name="sterling"/>
+ <GlyphID id="134" name="section"/>
+ <GlyphID id="135" name="bullet"/>
+ <GlyphID id="136" name="paragraph"/>
+ <GlyphID id="137" name="germandbls"/>
+ <GlyphID id="138" name="registered"/>
+ <GlyphID id="139" name="copyright"/>
+ <GlyphID id="140" name="trademark"/>
+ <GlyphID id="141" name="acute"/>
+ <GlyphID id="142" name="dieresis"/>
+ <GlyphID id="143" name=".notdef#3"/>
+ <GlyphID id="144" name="AE"/>
+ <GlyphID id="145" name="Oslash"/>
+ <GlyphID id="146" name=".notdef#4"/>
+ <GlyphID id="147" name="plusminus"/>
+ <GlyphID id="148" name=".notdef#5"/>
+ <GlyphID id="149" name=".notdef#6"/>
+ <GlyphID id="150" name="yen"/>
+ <GlyphID id="151" name="mu"/>
+ <GlyphID id="152" name=".notdef#7"/>
+ <GlyphID id="153" name=".notdef#8"/>
+ <GlyphID id="154" name=".notdef#9"/>
+ <GlyphID id="155" name=".notdef#10"/>
+ <GlyphID id="156" name=".notdef#11"/>
+ <GlyphID id="157" name="ordfeminine"/>
+ <GlyphID id="158" name="ordmasculine"/>
+ <GlyphID id="159" name=".notdef#12"/>
+ <GlyphID id="160" name="ae"/>
+ <GlyphID id="161" name="oslash"/>
+ <GlyphID id="162" name="questiondown"/>
+ <GlyphID id="163" name="exclamdown"/>
+ <GlyphID id="164" name="logicalnot"/>
+ <GlyphID id="165" name=".notdef#13"/>
+ <GlyphID id="166" name="florin"/>
+ <GlyphID id="167" name=".notdef#14"/>
+ <GlyphID id="168" name=".notdef#15"/>
+ <GlyphID id="169" name="guillemotleft"/>
+ <GlyphID id="170" name="guillemotright"/>
+ <GlyphID id="171" name="ellipsis"/>
+ <GlyphID id="172" name=".notdef#16"/>
+ <GlyphID id="173" name="Agrave"/>
+ <GlyphID id="174" name="Atilde"/>
+ <GlyphID id="175" name="Otilde"/>
+ <GlyphID id="176" name="OE"/>
+ <GlyphID id="177" name="oe"/>
+ <GlyphID id="178" name="endash"/>
+ <GlyphID id="179" name="emdash"/>
+ <GlyphID id="180" name="quotedblleft"/>
+ <GlyphID id="181" name="quotedblright"/>
+ <GlyphID id="182" name="quoteleft"/>
+ <GlyphID id="183" name="quoteright"/>
+ <GlyphID id="184" name="divide"/>
+ <GlyphID id="185" name=".notdef#17"/>
+ <GlyphID id="186" name="ydieresis"/>
+ <GlyphID id="187" name="Ydieresis"/>
+ <GlyphID id="188" name="fraction"/>
+ <GlyphID id="189" name="currency"/>
+ <GlyphID id="190" name="guilsinglleft"/>
+ <GlyphID id="191" name="guilsinglright"/>
+ <GlyphID id="192" name="fi"/>
+ <GlyphID id="193" name="fl"/>
+ <GlyphID id="194" name="daggerdbl"/>
+ <GlyphID id="195" name="periodcentered"/>
+ <GlyphID id="196" name="quotesinglbase"/>
+ <GlyphID id="197" name="quotedblbase"/>
+ <GlyphID id="198" name="perthousand"/>
+ <GlyphID id="199" name="Acircumflex"/>
+ <GlyphID id="200" name="Ecircumflex"/>
+ <GlyphID id="201" name="Aacute"/>
+ <GlyphID id="202" name="Edieresis"/>
+ <GlyphID id="203" name="Egrave"/>
+ <GlyphID id="204" name="Iacute"/>
+ <GlyphID id="205" name="Icircumflex"/>
+ <GlyphID id="206" name="Idieresis"/>
+ <GlyphID id="207" name="Igrave"/>
+ <GlyphID id="208" name="Oacute"/>
+ <GlyphID id="209" name="Ocircumflex"/>
+ <GlyphID id="210" name="Euro"/>
+ <GlyphID id="211" name="Ograve"/>
+ <GlyphID id="212" name="Uacute"/>
+ <GlyphID id="213" name="Ucircumflex"/>
+ <GlyphID id="214" name="Ugrave"/>
+ <GlyphID id="215" name="dotlessi"/>
+ <GlyphID id="216" name="circumflex"/>
+ <GlyphID id="217" name="tilde"/>
+ <GlyphID id="218" name="macron"/>
+ <GlyphID id="219" name="breve"/>
+ <GlyphID id="220" name="dotaccent"/>
+ <GlyphID id="221" name="ring"/>
+ <GlyphID id="222" name="cedilla"/>
+ <GlyphID id="223" name="hungarumlaut"/>
+ <GlyphID id="224" name="ogonek"/>
+ <GlyphID id="225" name="caron"/>
+ <GlyphID id="226" name="Euro#1"/>
+ <GlyphID id="227" name="nonbreakingspace"/>
+ <GlyphID id="228" name="brokenbar"/>
+ <GlyphID id="229" name="sfthyphen"/>
+ <GlyphID id="230" name="macron#1"/>
+ <GlyphID id="231" name="twosuperior"/>
+ <GlyphID id="232" name="threesuperior"/>
+ <GlyphID id="233" name="periodcentered#1"/>
+ <GlyphID id="234" name="onesuperior"/>
+ <GlyphID id="235" name="onequarter"/>
+ <GlyphID id="236" name="onehalf"/>
+ <GlyphID id="237" name="threequarters"/>
+ <GlyphID id="238" name="Eth"/>
+ <GlyphID id="239" name="multiply"/>
+ <GlyphID id="240" name="Yacute"/>
+ <GlyphID id="241" name="Thorn"/>
+ <GlyphID id="242" name="eth"/>
+ <GlyphID id="243" name="yacute"/>
+ <GlyphID id="244" name="thorn"/>
+ <GlyphID id="245" name="Amacron"/>
+ <GlyphID id="246" name="amacron"/>
+ <GlyphID id="247" name="Abreve"/>
+ <GlyphID id="248" name="abreve"/>
+ <GlyphID id="249" name="Aogonek"/>
+ <GlyphID id="250" name="aogonek"/>
+ <GlyphID id="251" name="Cacute"/>
+ <GlyphID id="252" name="cacute"/>
+ <GlyphID id="253" name="Ccircumflex"/>
+ <GlyphID id="254" name="ccircumflex"/>
+ <GlyphID id="255" name="Cdotaccent"/>
+ <GlyphID id="256" name="cdotaccent"/>
+ <GlyphID id="257" name="Ccaron"/>
+ <GlyphID id="258" name="ccaron"/>
+ <GlyphID id="259" name="Dcaron"/>
+ <GlyphID id="260" name="dcaron"/>
+ <GlyphID id="261" name="Dcroat"/>
+ <GlyphID id="262" name="dcroat"/>
+ <GlyphID id="263" name="Emacron"/>
+ <GlyphID id="264" name="emacron"/>
+ <GlyphID id="265" name="Ebreve"/>
+ <GlyphID id="266" name="ebreve"/>
+ <GlyphID id="267" name="Edotaccent"/>
+ <GlyphID id="268" name="edotaccent"/>
+ <GlyphID id="269" name="Eogonek"/>
+ <GlyphID id="270" name="eogonek"/>
+ <GlyphID id="271" name="Ecaron"/>
+ <GlyphID id="272" name="ecaron"/>
+ <GlyphID id="273" name="Gcircumflex"/>
+ <GlyphID id="274" name="gcircumflex"/>
+ <GlyphID id="275" name="Gbreve"/>
+ <GlyphID id="276" name="gbreve"/>
+ <GlyphID id="277" name="Gdotaccent"/>
+ <GlyphID id="278" name="gdotaccent"/>
+ <GlyphID id="279" name="Gcommaaccent"/>
+ <GlyphID id="280" name="gcommaaccent"/>
+ <GlyphID id="281" name="Hcircumflex"/>
+ <GlyphID id="282" name="hcircumflex"/>
+ <GlyphID id="283" name="Hbar"/>
+ <GlyphID id="284" name="hbar"/>
+ <GlyphID id="285" name="Itilde"/>
+ <GlyphID id="286" name="itilde"/>
+ <GlyphID id="287" name="Imacron"/>
+ <GlyphID id="288" name="imacron"/>
+ <GlyphID id="289" name="Ibreve"/>
+ <GlyphID id="290" name="ibreve"/>
+ <GlyphID id="291" name="Iogonek"/>
+ <GlyphID id="292" name="iogonek"/>
+ <GlyphID id="293" name="Idotaccent"/>
+ <GlyphID id="294" name="IJ"/>
+ <GlyphID id="295" name="ij"/>
+ <GlyphID id="296" name="Jcircumflex"/>
+ <GlyphID id="297" name="jcircumflex"/>
+ <GlyphID id="298" name="Kcommaaccent"/>
+ <GlyphID id="299" name="kcommaaccent"/>
+ <GlyphID id="300" name="kgreenlandic"/>
+ <GlyphID id="301" name="Lacute"/>
+ <GlyphID id="302" name="lacute"/>
+ <GlyphID id="303" name="Lcommaaccent"/>
+ <GlyphID id="304" name="lcommaaccent"/>
+ <GlyphID id="305" name="Lcaron"/>
+ <GlyphID id="306" name="lcaron"/>
+ <GlyphID id="307" name="Ldot"/>
+ <GlyphID id="308" name="ldot"/>
+ <GlyphID id="309" name="Lslash"/>
+ <GlyphID id="310" name="lslash"/>
+ <GlyphID id="311" name="Nacute"/>
+ <GlyphID id="312" name="nacute"/>
+ <GlyphID id="313" name="Ncommaaccent"/>
+ <GlyphID id="314" name="ncommaaccent"/>
+ <GlyphID id="315" name="Ncaron"/>
+ <GlyphID id="316" name="ncaron"/>
+ <GlyphID id="317" name="napostrophe"/>
+ <GlyphID id="318" name="Eng"/>
+ <GlyphID id="319" name="eng"/>
+ <GlyphID id="320" name="Omacron"/>
+ <GlyphID id="321" name="omacron"/>
+ <GlyphID id="322" name="Obreve"/>
+ <GlyphID id="323" name="obreve"/>
+ <GlyphID id="324" name="Ohungarumlaut"/>
+ <GlyphID id="325" name="ohungarumlaut"/>
+ <GlyphID id="326" name="Racute"/>
+ <GlyphID id="327" name="racute"/>
+ <GlyphID id="328" name="Rcommaaccent"/>
+ <GlyphID id="329" name="rcommaaccent"/>
+ <GlyphID id="330" name="Rcaron"/>
+ <GlyphID id="331" name="rcaron"/>
+ <GlyphID id="332" name="Sacute"/>
+ <GlyphID id="333" name="sacute"/>
+ <GlyphID id="334" name="Scircumflex"/>
+ <GlyphID id="335" name="scircumflex"/>
+ <GlyphID id="336" name="Scedilla"/>
+ <GlyphID id="337" name="scedilla"/>
+ <GlyphID id="338" name="Scaron"/>
+ <GlyphID id="339" name="scaron"/>
+ <GlyphID id="340" name="Tcommaaccent"/>
+ <GlyphID id="341" name="tcommaaccent"/>
+ <GlyphID id="342" name="Tcaron"/>
+ <GlyphID id="343" name="tcaron"/>
+ <GlyphID id="344" name="Tbar"/>
+ <GlyphID id="345" name="tbar"/>
+ <GlyphID id="346" name="Utilde"/>
+ <GlyphID id="347" name="utilde"/>
+ <GlyphID id="348" name="Umacron"/>
+ <GlyphID id="349" name="umacron"/>
+ <GlyphID id="350" name="Ubreve"/>
+ <GlyphID id="351" name="ubreve"/>
+ <GlyphID id="352" name="Uring"/>
+ <GlyphID id="353" name="uring"/>
+ <GlyphID id="354" name="Uhungarumlaut"/>
+ <GlyphID id="355" name="uhungarumlaut"/>
+ <GlyphID id="356" name="Uogonek"/>
+ <GlyphID id="357" name="uogonek"/>
+ <GlyphID id="358" name="Wcircumflex"/>
+ <GlyphID id="359" name="wcircumflex"/>
+ <GlyphID id="360" name="Ycircumflex"/>
+ <GlyphID id="361" name="ycircumflex"/>
+ <GlyphID id="362" name="Zacute"/>
+ <GlyphID id="363" name="zacute"/>
+ <GlyphID id="364" name="Zdotaccent"/>
+ <GlyphID id="365" name="zdotaccent"/>
+ <GlyphID id="366" name="Zcaron"/>
+ <GlyphID id="367" name="zcaron"/>
+ <GlyphID id="368" name="longs"/>
+ <GlyphID id="369" name="Scommaaccent"/>
+ <GlyphID id="370" name="scommaaccent"/>
+ <GlyphID id="371" name="Tcommabelow"/>
+ <GlyphID id="372" name="tcommabelow"/>
+ <GlyphID id="373" name="Unterkomma"/>
+ <GlyphID id="374" name="semicolon#1"/>
+ <GlyphID id="375" name="anoteleia"/>
+ <GlyphID id="376" name="hyphen#1"/>
+ <GlyphID id="377" name="nbhyphen"/>
+ <GlyphID id="378" name="figuredash"/>
+ <GlyphID id="379" name="afii00208"/>
+ <GlyphID id="380" name="quotereversed"/>
+ <GlyphID id="381" name="radicalex"/>
+ <GlyphID id="382" name="estimated"/>
+ <GlyphID id="383" name="minus"/>
+ <GlyphID id="384" name="fraction#1"/>
+ <GlyphID id="385" name="dotmath"/>
+ <GlyphID id="386" name="fi#1"/>
+ <GlyphID id="387" name="fl#1"/>
+ <GlyphID id="388" name="foursuperiour"/>
+ <GlyphID id="389" name="dotlessj"/>
+ <GlyphID id="390" name=".notdef#18"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.19999694824"/>
+ <checkSumAdjustment value="0x78bacbf6"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00001111"/>
+ <unitsPerEm value="2048"/>
+ <created value="Fri Oct 12 14:06:12 2001"/>
+ <modified value="Fri Oct 12 11:04:28 2001"/>
+ <xMin value="-441"/>
+ <yMin value="-432"/>
+ <xMax value="2024"/>
+ <yMax value="2033"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="12"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="2033"/>
+ <descent value="-432"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="2079"/>
+ <minLeftSideBearing value="-441"/>
+ <minRightSideBearing value="-440"/>
+ <xMaxExtent value="2024"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="391"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="391"/>
+ <maxPoints value="82"/>
+ <maxContours value="7"/>
+ <maxCompositePoints value="75"/>
+ <maxCompositeContours value="4"/>
+ <maxZones value="2"/>
+ <maxTwilightPoints value="4"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="15"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="2048"/>
+ <maxSizeOfInstructions value="183"/>
+ <maxComponentElements value="2"/>
+ <maxComponentDepth value="1"/>
+ </maxp>
+
+ <OS_2>
+ <version value="2"/>
+ <xAvgCharWidth value="904"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00000000"/>
+ <ySubscriptXSize value="1434"/>
+ <ySubscriptYSize value="1331"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="283"/>
+ <ySuperscriptXSize value="1434"/>
+ <ySuperscriptYSize value="1331"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="977"/>
+ <yStrikeoutSize value="0"/>
+ <yStrikeoutPosition value="0"/>
+ <sFamilyClass value="2048"/>
+ <panose>
+ <bFamilyType value="2"/>
+ <bSerifStyle value="11"/>
+ <bWeight value="6"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000111"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="B&amp;H "/>
+ <fsSelection value="00000000 01000000"/>
+ <fsFirstCharIndex value="32"/>
+ <fsLastCharIndex value="64258"/>
+ <sTypoAscender value="1604"/>
+ <sTypoDescender value="-420"/>
+ <sTypoLineGap value="167"/>
+ <usWinAscent value="1935"/>
+ <usWinDescent value="432"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 10010011"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="0"/>
+ <sCapHeight value="0"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="0"/>
+ <usMaxContex value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="569" lsb="57"/>
+ <mtx name=".notdef#1" width="0" lsb="0"/>
+ <mtx name=".notdef#10" width="569" lsb="0"/>
+ <mtx name=".notdef#11" width="569" lsb="0"/>
+ <mtx name=".notdef#12" width="569" lsb="0"/>
+ <mtx name=".notdef#13" width="569" lsb="0"/>
+ <mtx name=".notdef#14" width="569" lsb="0"/>
+ <mtx name=".notdef#15" width="569" lsb="0"/>
+ <mtx name=".notdef#16" width="1139" lsb="0"/>
+ <mtx name=".notdef#17" width="569" lsb="0"/>
+ <mtx name=".notdef#18" width="569" lsb="0"/>
+ <mtx name=".notdef#2" width="569" lsb="0"/>
+ <mtx name=".notdef#3" width="569" lsb="0"/>
+ <mtx name=".notdef#4" width="569" lsb="0"/>
+ <mtx name=".notdef#5" width="569" lsb="0"/>
+ <mtx name=".notdef#6" width="569" lsb="0"/>
+ <mtx name=".notdef#7" width="569" lsb="0"/>
+ <mtx name=".notdef#8" width="569" lsb="0"/>
+ <mtx name=".notdef#9" width="569" lsb="0"/>
+ <mtx name="A" width="1366" lsb="19"/>
+ <mtx name="AE" width="2048" lsb="19"/>
+ <mtx name="Aacute" width="1366" lsb="19"/>
+ <mtx name="Abreve" width="1371" lsb="21"/>
+ <mtx name="Acircumflex" width="1366" lsb="19"/>
+ <mtx name="Adieresis" width="1366" lsb="19"/>
+ <mtx name="Agrave" width="1366" lsb="19"/>
+ <mtx name="Amacron" width="1371" lsb="21"/>
+ <mtx name="Aogonek" width="1366" lsb="19"/>
+ <mtx name="Aring" width="1366" lsb="19"/>
+ <mtx name="Atilde" width="1366" lsb="19"/>
+ <mtx name="B" width="1366" lsb="165"/>
+ <mtx name="C" width="1479" lsb="116"/>
+ <mtx name="Cacute" width="1479" lsb="116"/>
+ <mtx name="Ccaron" width="1479" lsb="116"/>
+ <mtx name="Ccedilla" width="1479" lsb="116"/>
+ <mtx name="Ccircumflex" width="1479" lsb="116"/>
+ <mtx name="Cdotaccent" width="1479" lsb="116"/>
+ <mtx name="D" width="1479" lsb="165"/>
+ <mtx name="Dcaron" width="1479" lsb="165"/>
+ <mtx name="Dcroat" width="1479" lsb="5"/>
+ <mtx name="E" width="1366" lsb="191"/>
+ <mtx name="Eacute" width="1366" lsb="191"/>
+ <mtx name="Ebreve" width="1366" lsb="191"/>
+ <mtx name="Ecaron" width="1366" lsb="191"/>
+ <mtx name="Ecircumflex" width="1366" lsb="191"/>
+ <mtx name="Edieresis" width="1366" lsb="191"/>
+ <mtx name="Edotaccent" width="1366" lsb="191"/>
+ <mtx name="Egrave" width="1366" lsb="191"/>
+ <mtx name="Emacron" width="1366" lsb="191"/>
+ <mtx name="Eng" width="1479" lsb="165"/>
+ <mtx name="Eogonek" width="1366" lsb="191"/>
+ <mtx name="Eth" width="1479" lsb="5"/>
+ <mtx name="Euro" width="1139" lsb="0"/>
+ <mtx name="Euro#1" width="1139" lsb="0"/>
+ <mtx name="F" width="1251" lsb="191"/>
+ <mtx name="G" width="1593" lsb="93"/>
+ <mtx name="Gbreve" width="1593" lsb="93"/>
+ <mtx name="Gcircumflex" width="1593" lsb="93"/>
+ <mtx name="Gcommaaccent" width="1593" lsb="93"/>
+ <mtx name="Gdotaccent" width="1593" lsb="93"/>
+ <mtx name="H" width="1479" lsb="165"/>
+ <mtx name="Hbar" width="1479" lsb="17"/>
+ <mtx name="Hcircumflex" width="1479" lsb="165"/>
+ <mtx name="I" width="569" lsb="180"/>
+ <mtx name="IJ" width="1505" lsb="180"/>
+ <mtx name="Iacute" width="569" lsb="137"/>
+ <mtx name="Ibreve" width="569" lsb="-48"/>
+ <mtx name="Icircumflex" width="569" lsb="-65"/>
+ <mtx name="Idieresis" width="569" lsb="1"/>
+ <mtx name="Idotaccent" width="569" lsb="180"/>
+ <mtx name="Igrave" width="569" lsb="-36"/>
+ <mtx name="Imacron" width="569" lsb="-36"/>
+ <mtx name="Iogonek" width="569" lsb="120"/>
+ <mtx name="Itilde" width="569" lsb="-48"/>
+ <mtx name="J" width="1024" lsb="49"/>
+ <mtx name="Jcircumflex" width="1024" lsb="49"/>
+ <mtx name="K" width="1366" lsb="191"/>
+ <mtx name="Kcommaaccent" width="1366" lsb="191"/>
+ <mtx name="L" width="1139" lsb="165"/>
+ <mtx name="Lacute" width="1139" lsb="165"/>
+ <mtx name="Lcaron" width="1139" lsb="165"/>
+ <mtx name="Lcommaaccent" width="1139" lsb="165"/>
+ <mtx name="Ldot" width="1139" lsb="165"/>
+ <mtx name="Lslash" width="1139" lsb="17"/>
+ <mtx name="M" width="1706" lsb="165"/>
+ <mtx name="N" width="1479" lsb="165"/>
+ <mtx name="Nacute" width="1479" lsb="165"/>
+ <mtx name="Ncaron" width="1479" lsb="165"/>
+ <mtx name="Ncommaaccent" width="1479" lsb="165"/>
+ <mtx name="Ntilde" width="1479" lsb="165"/>
+ <mtx name="O" width="1593" lsb="93"/>
+ <mtx name="OE" width="2048" lsb="93"/>
+ <mtx name="Oacute" width="1593" lsb="92"/>
+ <mtx name="Obreve" width="1593" lsb="93"/>
+ <mtx name="Ocircumflex" width="1593" lsb="92"/>
+ <mtx name="Odieresis" width="1593" lsb="92"/>
+ <mtx name="Ograve" width="1593" lsb="92"/>
+ <mtx name="Ohungarumlaut" width="1593" lsb="93"/>
+ <mtx name="Omacron" width="1593" lsb="93"/>
+ <mtx name="Oslash" width="1593" lsb="93"/>
+ <mtx name="Otilde" width="1593" lsb="92"/>
+ <mtx name="P" width="1366" lsb="167"/>
+ <mtx name="Q" width="1593" lsb="93"/>
+ <mtx name="R" width="1479" lsb="165"/>
+ <mtx name="Racute" width="1479" lsb="165"/>
+ <mtx name="Rcaron" width="1479" lsb="165"/>
+ <mtx name="Rcommaaccent" width="1479" lsb="165"/>
+ <mtx name="S" width="1366" lsb="120"/>
+ <mtx name="Sacute" width="1366" lsb="120"/>
+ <mtx name="Scaron" width="1366" lsb="120"/>
+ <mtx name="Scedilla" width="1366" lsb="120"/>
+ <mtx name="Scircumflex" width="1366" lsb="120"/>
+ <mtx name="Scommaaccent" width="1366" lsb="120"/>
+ <mtx name="T" width="1251" lsb="20"/>
+ <mtx name="Tbar" width="1251" lsb="20"/>
+ <mtx name="Tcaron" width="1251" lsb="20"/>
+ <mtx name="Tcommaaccent" width="1251" lsb="20"/>
+ <mtx name="Tcommabelow" width="1251" lsb="20"/>
+ <mtx name="Thorn" width="1366" lsb="167"/>
+ <mtx name="U" width="1479" lsb="166"/>
+ <mtx name="Uacute" width="1479" lsb="166"/>
+ <mtx name="Ubreve" width="1479" lsb="166"/>
+ <mtx name="Ucircumflex" width="1479" lsb="166"/>
+ <mtx name="Udieresis" width="1479" lsb="166"/>
+ <mtx name="Ugrave" width="1479" lsb="166"/>
+ <mtx name="Uhungarumlaut" width="1479" lsb="166"/>
+ <mtx name="Umacron" width="1479" lsb="166"/>
+ <mtx name="Unterkomma" width="682" lsb="170"/>
+ <mtx name="Uogonek" width="1479" lsb="166"/>
+ <mtx name="Uring" width="1479" lsb="166"/>
+ <mtx name="Utilde" width="1479" lsb="166"/>
+ <mtx name="V" width="1366" lsb="36"/>
+ <mtx name="W" width="1933" lsb="25"/>
+ <mtx name="Wcircumflex" width="1933" lsb="25"/>
+ <mtx name="X" width="1366" lsb="28"/>
+ <mtx name="Y" width="1366" lsb="30"/>
+ <mtx name="Yacute" width="1366" lsb="30"/>
+ <mtx name="Ycircumflex" width="1366" lsb="30"/>
+ <mtx name="Ydieresis" width="1366" lsb="30"/>
+ <mtx name="Z" width="1251" lsb="101"/>
+ <mtx name="Zacute" width="1251" lsb="101"/>
+ <mtx name="Zcaron" width="1251" lsb="101"/>
+ <mtx name="Zdotaccent" width="1251" lsb="101"/>
+ <mtx name="a" width="1139" lsb="95"/>
+ <mtx name="aacute" width="1139" lsb="95"/>
+ <mtx name="abreve" width="1153" lsb="105"/>
+ <mtx name="acircumflex" width="1139" lsb="95"/>
+ <mtx name="acute" width="682" lsb="107"/>
+ <mtx name="adieresis" width="1139" lsb="95"/>
+ <mtx name="ae" width="1821" lsb="95"/>
+ <mtx name="afii00208" width="2048" lsb="99"/>
+ <mtx name="agrave" width="1139" lsb="95"/>
+ <mtx name="amacron" width="1153" lsb="105"/>
+ <mtx name="ampersand" width="1366" lsb="56"/>
+ <mtx name="anoteleia" width="569" lsb="161"/>
+ <mtx name="aogonek" width="1139" lsb="95"/>
+ <mtx name="aring" width="1139" lsb="95"/>
+ <mtx name="asciicircum" width="960" lsb="36"/>
+ <mtx name="asciitilde" width="1196" lsb="104"/>
+ <mtx name="asterisk" width="797" lsb="39"/>
+ <mtx name="at" width="2079" lsb="253"/>
+ <mtx name="atilde" width="1139" lsb="95"/>
+ <mtx name="b" width="1139" lsb="154"/>
+ <mtx name="backslash" width="569" lsb="-59"/>
+ <mtx name="bar" width="532" lsb="192"/>
+ <mtx name="braceleft" width="684" lsb="25"/>
+ <mtx name="braceright" width="684" lsb="116"/>
+ <mtx name="bracketleft" width="569" lsb="149"/>
+ <mtx name="bracketright" width="569" lsb="26"/>
+ <mtx name="breve" width="682" lsb="8"/>
+ <mtx name="brokenbar" width="532" lsb="192"/>
+ <mtx name="bullet" width="717" lsb="81"/>
+ <mtx name="c" width="1024" lsb="86"/>
+ <mtx name="cacute" width="1024" lsb="86"/>
+ <mtx name="caron" width="682" lsb="-9"/>
+ <mtx name="ccaron" width="1024" lsb="86"/>
+ <mtx name="ccedilla" width="1024" lsb="86"/>
+ <mtx name="ccircumflex" width="1024" lsb="86"/>
+ <mtx name="cdotaccent" width="1024" lsb="86"/>
+ <mtx name="cedilla" width="682" lsb="168"/>
+ <mtx name="cent" width="1139" lsb="173"/>
+ <mtx name="circumflex" width="682" lsb="-9"/>
+ <mtx name="colon" width="569" lsb="186"/>
+ <mtx name="comma" width="569" lsb="161"/>
+ <mtx name="copyright" width="1509" lsb="15"/>
+ <mtx name="currency" width="1139" lsb="122"/>
+ <mtx name="d" width="1139" lsb="86"/>
+ <mtx name="dagger" width="1139" lsb="150"/>
+ <mtx name="daggerdbl" width="1139" lsb="150"/>
+ <mtx name="dcaron" width="1259" lsb="86"/>
+ <mtx name="dcroat" width="1139" lsb="86"/>
+ <mtx name="degree" width="819" lsb="114"/>
+ <mtx name="dieresis" width="682" lsb="57"/>
+ <mtx name="divide" width="1196" lsb="104"/>
+ <mtx name="dollar" width="1139" lsb="103"/>
+ <mtx name="dotaccent" width="682" lsb="242"/>
+ <mtx name="dotlessi" width="455" lsb="129"/>
+ <mtx name="dotlessj" width="455" lsb="-155"/>
+ <mtx name="dotmath" width="569" lsb="161"/>
+ <mtx name="e" width="1139" lsb="86"/>
+ <mtx name="eacute" width="1139" lsb="86"/>
+ <mtx name="ebreve" width="1139" lsb="86"/>
+ <mtx name="ecaron" width="1139" lsb="86"/>
+ <mtx name="ecircumflex" width="1139" lsb="86"/>
+ <mtx name="edieresis" width="1139" lsb="86"/>
+ <mtx name="edotaccent" width="1139" lsb="86"/>
+ <mtx name="egrave" width="1139" lsb="86"/>
+ <mtx name="eight" width="1139" lsb="99"/>
+ <mtx name="ellipsis" width="2048" lsb="247"/>
+ <mtx name="emacron" width="1139" lsb="86"/>
+ <mtx name="emdash" width="2048" lsb="99"/>
+ <mtx name="endash" width="1139" lsb="101"/>
+ <mtx name="eng" width="1139" lsb="154"/>
+ <mtx name="eogonek" width="1139" lsb="86"/>
+ <mtx name="equal" width="1196" lsb="104"/>
+ <mtx name="estimated" width="1139" lsb="86"/>
+ <mtx name="eth" width="1139" lsb="86"/>
+ <mtx name="exclam" width="569" lsb="186"/>
+ <mtx name="exclamdown" width="682" lsb="242"/>
+ <mtx name="f" width="569" lsb="31"/>
+ <mtx name="fi" width="1024" lsb="31"/>
+ <mtx name="fi#1" width="1024" lsb="31"/>
+ <mtx name="figuredash" width="1139" lsb="101"/>
+ <mtx name="five" width="1139" lsb="163"/>
+ <mtx name="fl" width="1024" lsb="31"/>
+ <mtx name="fl#1" width="1024" lsb="31"/>
+ <mtx name="florin" width="1139" lsb="49"/>
+ <mtx name="four" width="1139" lsb="31"/>
+ <mtx name="foursuperiour" width="682" lsb="3"/>
+ <mtx name="fraction" width="342" lsb="-441"/>
+ <mtx name="fraction#1" width="342" lsb="-441"/>
+ <mtx name="g" width="1139" lsb="93"/>
+ <mtx name="gbreve" width="1139" lsb="93"/>
+ <mtx name="gcircumflex" width="1139" lsb="93"/>
+ <mtx name="gcommaaccent" width="1139" lsb="93"/>
+ <mtx name="gdotaccent" width="1139" lsb="93"/>
+ <mtx name="germandbls" width="1251" lsb="129"/>
+ <mtx name="grave" width="682" lsb="106"/>
+ <mtx name="greater" width="1196" lsb="104"/>
+ <mtx name="guillemotleft" width="1139" lsb="115"/>
+ <mtx name="guillemotright" width="1139" lsb="136"/>
+ <mtx name="guilsinglleft" width="682" lsb="74"/>
+ <mtx name="guilsinglright" width="682" lsb="114"/>
+ <mtx name="h" width="1139" lsb="154"/>
+ <mtx name="hbar" width="1139" lsb="6"/>
+ <mtx name="hcircumflex" width="1139" lsb="154"/>
+ <mtx name="hungarumlaut" width="682" lsb="-51"/>
+ <mtx name="hyphen" width="682" lsb="88"/>
+ <mtx name="hyphen#1" width="682" lsb="88"/>
+ <mtx name="i" width="455" lsb="129"/>
+ <mtx name="iacute" width="455" lsb="79"/>
+ <mtx name="ibreve" width="455" lsb="-106"/>
+ <mtx name="icircumflex" width="455" lsb="-123"/>
+ <mtx name="idieresis" width="455" lsb="-56"/>
+ <mtx name="igrave" width="455" lsb="-94"/>
+ <mtx name="ij" width="909" lsb="129"/>
+ <mtx name="imacron" width="455" lsb="-94"/>
+ <mtx name="iogonek" width="455" lsb="61"/>
+ <mtx name="itilde" width="455" lsb="-106"/>
+ <mtx name="j" width="455" lsb="-155"/>
+ <mtx name="jcircumflex" width="455" lsb="-155"/>
+ <mtx name="k" width="1024" lsb="154"/>
+ <mtx name="kcommaaccent" width="1024" lsb="154"/>
+ <mtx name="kgreenlandic" width="1024" lsb="154"/>
+ <mtx name="l" width="455" lsb="129"/>
+ <mtx name="lacute" width="455" lsb="79"/>
+ <mtx name="lcaron" width="597" lsb="129"/>
+ <mtx name="lcommaaccent" width="455" lsb="79"/>
+ <mtx name="ldot" width="684" lsb="129"/>
+ <mtx name="less" width="1196" lsb="104"/>
+ <mtx name="logicalnot" width="1196" lsb="86"/>
+ <mtx name="longs" width="455" lsb="8"/>
+ <mtx name="lslash" width="455" lsb="-7"/>
+ <mtx name="m" width="1706" lsb="154"/>
+ <mtx name="macron" width="682" lsb="20"/>
+ <mtx name="macron#1" width="1139" lsb="99"/>
+ <mtx name="minus" width="1196" lsb="104"/>
+ <mtx name="mu" width="1139" lsb="142"/>
+ <mtx name="multiply" width="1196" lsb="118"/>
+ <mtx name="n" width="1139" lsb="154"/>
+ <mtx name="nacute" width="1139" lsb="154"/>
+ <mtx name="napostrophe" width="1237" lsb="0"/>
+ <mtx name="nbhyphen" width="682" lsb="88"/>
+ <mtx name="ncaron" width="1139" lsb="154"/>
+ <mtx name="ncommaaccent" width="1139" lsb="154"/>
+ <mtx name="nine" width="1139" lsb="84"/>
+ <mtx name="nonbreakingspace" width="569" lsb="0"/>
+ <mtx name="ntilde" width="1139" lsb="154"/>
+ <mtx name="numbersign" width="1139" lsb="25"/>
+ <mtx name="o" width="1139" lsb="86"/>
+ <mtx name="oacute" width="1139" lsb="86"/>
+ <mtx name="obreve" width="1139" lsb="86"/>
+ <mtx name="ocircumflex" width="1139" lsb="86"/>
+ <mtx name="odieresis" width="1139" lsb="86"/>
+ <mtx name="oe" width="1933" lsb="86"/>
+ <mtx name="ogonek" width="682" lsb="170"/>
+ <mtx name="ograve" width="1139" lsb="86"/>
+ <mtx name="ohungarumlaut" width="1139" lsb="86"/>
+ <mtx name="omacron" width="1139" lsb="86"/>
+ <mtx name="one" width="1139" lsb="230"/>
+ <mtx name="onehalf" width="1708" lsb="116"/>
+ <mtx name="onequarter" width="1708" lsb="116"/>
+ <mtx name="onesuperior" width="682" lsb="123"/>
+ <mtx name="ordfeminine" width="758" lsb="86"/>
+ <mtx name="ordmasculine" width="748" lsb="74"/>
+ <mtx name="oslash" width="1251" lsb="143"/>
+ <mtx name="otilde" width="1139" lsb="86"/>
+ <mtx name="p" width="1139" lsb="154"/>
+ <mtx name="paragraph" width="1100" lsb="88"/>
+ <mtx name="parenleft" width="682" lsb="131"/>
+ <mtx name="parenright" width="682" lsb="82"/>
+ <mtx name="percent" width="1821" lsb="112"/>
+ <mtx name="period" width="569" lsb="161"/>
+ <mtx name="periodcentered" width="569" lsb="161"/>
+ <mtx name="periodcentered#1" width="569" lsb="161"/>
+ <mtx name="perthousand" width="2048" lsb="25"/>
+ <mtx name="plus" width="1196" lsb="104"/>
+ <mtx name="plusminus" width="1196" lsb="104"/>
+ <mtx name="q" width="1139" lsb="86"/>
+ <mtx name="question" width="1139" lsb="138"/>
+ <mtx name="questiondown" width="1251" lsb="185"/>
+ <mtx name="quotedbl" width="727" lsb="92"/>
+ <mtx name="quotedblbase" width="682" lsb="70"/>
+ <mtx name="quotedblleft" width="682" lsb="57"/>
+ <mtx name="quotedblright" width="682" lsb="82"/>
+ <mtx name="quoteleft" width="455" lsb="92"/>
+ <mtx name="quotereversed" width="569" lsb="0"/>
+ <mtx name="quoteright" width="455" lsb="116"/>
+ <mtx name="quotesinglbase" width="455" lsb="104"/>
+ <mtx name="quotesingle" width="391" lsb="72"/>
+ <mtx name="r" width="682" lsb="154"/>
+ <mtx name="racute" width="682" lsb="154"/>
+ <mtx name="radicalex" width="1139" lsb="99"/>
+ <mtx name="rcaron" width="682" lsb="2"/>
+ <mtx name="rcommaaccent" width="682" lsb="154"/>
+ <mtx name="registered" width="1509" lsb="15"/>
+ <mtx name="ring" width="682" lsb="114"/>
+ <mtx name="s" width="1024" lsb="116"/>
+ <mtx name="sacute" width="1024" lsb="116"/>
+ <mtx name="scaron" width="1024" lsb="116"/>
+ <mtx name="scedilla" width="1024" lsb="116"/>
+ <mtx name="scircumflex" width="1024" lsb="116"/>
+ <mtx name="scommaaccent" width="1024" lsb="116"/>
+ <mtx name="section" width="1139" lsb="129"/>
+ <mtx name="semicolon" width="569" lsb="186"/>
+ <mtx name="semicolon#1" width="569" lsb="186"/>
+ <mtx name="seven" width="1139" lsb="136"/>
+ <mtx name="sfthyphen" width="682" lsb="88"/>
+ <mtx name="six" width="1139" lsb="84"/>
+ <mtx name="slash" width="569" lsb="-59"/>
+ <mtx name="space" width="569" lsb="0"/>
+ <mtx name="sterling" width="1139" lsb="121"/>
+ <mtx name="t" width="569" lsb="29"/>
+ <mtx name="tbar" width="569" lsb="29"/>
+ <mtx name="tcaron" width="768" lsb="29"/>
+ <mtx name="tcommaaccent" width="569" lsb="29"/>
+ <mtx name="tcommabelow" width="569" lsb="29"/>
+ <mtx name="thorn" width="1139" lsb="154"/>
+ <mtx name="three" width="1139" lsb="153"/>
+ <mtx name="threequarters" width="1708" lsb="111"/>
+ <mtx name="threesuperior" width="682" lsb="74"/>
+ <mtx name="tilde" width="682" lsb="8"/>
+ <mtx name="trademark" width="2048" lsb="222"/>
+ <mtx name="two" width="1139" lsb="102"/>
+ <mtx name="twosuperior" width="682" lsb="74"/>
+ <mtx name="u" width="1139" lsb="142"/>
+ <mtx name="uacute" width="1139" lsb="142"/>
+ <mtx name="ubreve" width="1139" lsb="142"/>
+ <mtx name="ucircumflex" width="1139" lsb="142"/>
+ <mtx name="udieresis" width="1139" lsb="142"/>
+ <mtx name="ugrave" width="1139" lsb="142"/>
+ <mtx name="uhungarumlaut" width="1139" lsb="142"/>
+ <mtx name="umacron" width="1139" lsb="142"/>
+ <mtx name="underscore" width="1139" lsb="0"/>
+ <mtx name="uogonek" width="1139" lsb="142"/>
+ <mtx name="uring" width="1139" lsb="142"/>
+ <mtx name="utilde" width="1139" lsb="142"/>
+ <mtx name="v" width="1024" lsb="19"/>
+ <mtx name="w" width="1479" lsb="11"/>
+ <mtx name="wcircumflex" width="1479" lsb="11"/>
+ <mtx name="x" width="1024" lsb="28"/>
+ <mtx name="y" width="1024" lsb="19"/>
+ <mtx name="yacute" width="1024" lsb="19"/>
+ <mtx name="ycircumflex" width="1024" lsb="19"/>
+ <mtx name="ydieresis" width="1024" lsb="19"/>
+ <mtx name="yen" width="1139" lsb="25"/>
+ <mtx name="z" width="1024" lsb="74"/>
+ <mtx name="zacute" width="1024" lsb="74"/>
+ <mtx name="zcaron" width="1024" lsb="74"/>
+ <mtx name="zdotaccent" width="1024" lsb="74"/>
+ <mtx name="zero" width="1139" lsb="80"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_0 platformID="1" platEncID="0" language="0">
+ <map code="0x0" name=".notdef#1"/>
+ <map code="0x1" name=".notdef"/>
+ <map code="0x2" name=".notdef"/>
+ <map code="0x3" name=".notdef"/>
+ <map code="0x4" name=".notdef"/>
+ <map code="0x5" name=".notdef"/>
+ <map code="0x6" name=".notdef"/>
+ <map code="0x7" name=".notdef"/>
+ <map code="0x8" name=".notdef#1"/>
+ <map code="0x9" name="space"/>
+ <map code="0xa" name=".notdef"/>
+ <map code="0xb" name=".notdef"/>
+ <map code="0xc" name=".notdef"/>
+ <map code="0xd" name=".notdef#2"/>
+ <map code="0xe" name=".notdef"/>
+ <map code="0xf" name=".notdef"/>
+ <map code="0x10" name=".notdef"/>
+ <map code="0x11" name=".notdef"/>
+ <map code="0x12" name=".notdef"/>
+ <map code="0x13" name=".notdef"/>
+ <map code="0x14" name=".notdef"/>
+ <map code="0x15" name=".notdef"/>
+ <map code="0x16" name=".notdef"/>
+ <map code="0x17" name=".notdef"/>
+ <map code="0x18" name=".notdef"/>
+ <map code="0x19" name=".notdef"/>
+ <map code="0x1a" name=".notdef"/>
+ <map code="0x1b" name=".notdef"/>
+ <map code="0x1c" name=".notdef"/>
+ <map code="0x1d" name=".notdef#1"/>
+ <map code="0x1e" name=".notdef"/>
+ <map code="0x1f" name=".notdef"/>
+ <map code="0x20" name="space"/>
+ <map code="0x21" name="exclam"/>
+ <map code="0x22" name="quotedbl"/>
+ <map code="0x23" name="numbersign"/>
+ <map code="0x24" name="dollar"/>
+ <map code="0x25" name="percent"/>
+ <map code="0x26" name="ampersand"/>
+ <map code="0x27" name="quotesingle"/>
+ <map code="0x28" name="parenleft"/>
+ <map code="0x29" name="parenright"/>
+ <map code="0x2a" name="asterisk"/>
+ <map code="0x2b" name="plus"/>
+ <map code="0x2c" name="comma"/>
+ <map code="0x2d" name="hyphen"/>
+ <map code="0x2e" name="period"/>
+ <map code="0x2f" name="slash"/>
+ <map code="0x30" name="zero"/>
+ <map code="0x31" name="one"/>
+ <map code="0x32" name="two"/>
+ <map code="0x33" name="three"/>
+ <map code="0x34" name="four"/>
+ <map code="0x35" name="five"/>
+ <map code="0x36" name="six"/>
+ <map code="0x37" name="seven"/>
+ <map code="0x38" name="eight"/>
+ <map code="0x39" name="nine"/>
+ <map code="0x3a" name="colon"/>
+ <map code="0x3b" name="semicolon"/>
+ <map code="0x3c" name="less"/>
+ <map code="0x3d" name="equal"/>
+ <map code="0x3e" name="greater"/>
+ <map code="0x3f" name="question"/>
+ <map code="0x40" name="at"/>
+ <map code="0x41" name="A"/>
+ <map code="0x42" name="B"/>
+ <map code="0x43" name="C"/>
+ <map code="0x44" name="D"/>
+ <map code="0x45" name="E"/>
+ <map code="0x46" name="F"/>
+ <map code="0x47" name="G"/>
+ <map code="0x48" name="H"/>
+ <map code="0x49" name="I"/>
+ <map code="0x4a" name="J"/>
+ <map code="0x4b" name="K"/>
+ <map code="0x4c" name="L"/>
+ <map code="0x4d" name="M"/>
+ <map code="0x4e" name="N"/>
+ <map code="0x4f" name="O"/>
+ <map code="0x50" name="P"/>
+ <map code="0x51" name="Q"/>
+ <map code="0x52" name="R"/>
+ <map code="0x53" name="S"/>
+ <map code="0x54" name="T"/>
+ <map code="0x55" name="U"/>
+ <map code="0x56" name="V"/>
+ <map code="0x57" name="W"/>
+ <map code="0x58" name="X"/>
+ <map code="0x59" name="Y"/>
+ <map code="0x5a" name="Z"/>
+ <map code="0x5b" name="bracketleft"/>
+ <map code="0x5c" name="backslash"/>
+ <map code="0x5d" name="bracketright"/>
+ <map code="0x5e" name="asciicircum"/>
+ <map code="0x5f" name="underscore"/>
+ <map code="0x60" name="grave"/>
+ <map code="0x61" name="a"/>
+ <map code="0x62" name="b"/>
+ <map code="0x63" name="c"/>
+ <map code="0x64" name="d"/>
+ <map code="0x65" name="e"/>
+ <map code="0x66" name="f"/>
+ <map code="0x67" name="g"/>
+ <map code="0x68" name="h"/>
+ <map code="0x69" name="i"/>
+ <map code="0x6a" name="j"/>
+ <map code="0x6b" name="k"/>
+ <map code="0x6c" name="l"/>
+ <map code="0x6d" name="m"/>
+ <map code="0x6e" name="n"/>
+ <map code="0x6f" name="o"/>
+ <map code="0x70" name="p"/>
+ <map code="0x71" name="q"/>
+ <map code="0x72" name="r"/>
+ <map code="0x73" name="s"/>
+ <map code="0x74" name="t"/>
+ <map code="0x75" name="u"/>
+ <map code="0x76" name="v"/>
+ <map code="0x77" name="w"/>
+ <map code="0x78" name="x"/>
+ <map code="0x79" name="y"/>
+ <map code="0x7a" name="z"/>
+ <map code="0x7b" name="braceleft"/>
+ <map code="0x7c" name="bar"/>
+ <map code="0x7d" name="braceright"/>
+ <map code="0x7e" name="asciitilde"/>
+ <map code="0x7f" name=".notdef"/>
+ <map code="0x80" name="Adieresis"/>
+ <map code="0x81" name="Aring"/>
+ <map code="0x82" name="Ccedilla"/>
+ <map code="0x83" name="Eacute"/>
+ <map code="0x84" name="Ntilde"/>
+ <map code="0x85" name="Odieresis"/>
+ <map code="0x86" name="Udieresis"/>
+ <map code="0x87" name="aacute"/>
+ <map code="0x88" name="agrave"/>
+ <map code="0x89" name="acircumflex"/>
+ <map code="0x8a" name="adieresis"/>
+ <map code="0x8b" name="atilde"/>
+ <map code="0x8c" name="aring"/>
+ <map code="0x8d" name="ccedilla"/>
+ <map code="0x8e" name="eacute"/>
+ <map code="0x8f" name="egrave"/>
+ <map code="0x90" name="ecircumflex"/>
+ <map code="0x91" name="edieresis"/>
+ <map code="0x92" name="iacute"/>
+ <map code="0x93" name="igrave"/>
+ <map code="0x94" name="icircumflex"/>
+ <map code="0x95" name="idieresis"/>
+ <map code="0x96" name="ntilde"/>
+ <map code="0x97" name="oacute"/>
+ <map code="0x98" name="ograve"/>
+ <map code="0x99" name="ocircumflex"/>
+ <map code="0x9a" name="odieresis"/>
+ <map code="0x9b" name="otilde"/>
+ <map code="0x9c" name="uacute"/>
+ <map code="0x9d" name="ugrave"/>
+ <map code="0x9e" name="ucircumflex"/>
+ <map code="0x9f" name="udieresis"/>
+ <map code="0xa0" name="dagger"/>
+ <map code="0xa1" name="degree"/>
+ <map code="0xa2" name="cent"/>
+ <map code="0xa3" name="sterling"/>
+ <map code="0xa4" name="section"/>
+ <map code="0xa5" name="bullet"/>
+ <map code="0xa6" name="paragraph"/>
+ <map code="0xa7" name="germandbls"/>
+ <map code="0xa8" name="registered"/>
+ <map code="0xa9" name="copyright"/>
+ <map code="0xaa" name="trademark"/>
+ <map code="0xab" name="acute"/>
+ <map code="0xac" name="dieresis"/>
+ <map code="0xad" name=".notdef"/>
+ <map code="0xae" name="AE"/>
+ <map code="0xaf" name="Oslash"/>
+ <map code="0xb0" name=".notdef"/>
+ <map code="0xb1" name="plusminus"/>
+ <map code="0xb2" name=".notdef"/>
+ <map code="0xb3" name=".notdef"/>
+ <map code="0xb4" name="yen"/>
+ <map code="0xb5" name="mu"/>
+ <map code="0xb6" name=".notdef"/>
+ <map code="0xb7" name=".notdef"/>
+ <map code="0xb8" name=".notdef"/>
+ <map code="0xb9" name=".notdef"/>
+ <map code="0xba" name=".notdef"/>
+ <map code="0xbb" name="ordfeminine"/>
+ <map code="0xbc" name="ordmasculine"/>
+ <map code="0xbd" name=".notdef"/>
+ <map code="0xbe" name="ae"/>
+ <map code="0xbf" name="oslash"/>
+ <map code="0xc0" name="questiondown"/>
+ <map code="0xc1" name="exclamdown"/>
+ <map code="0xc2" name="logicalnot"/>
+ <map code="0xc3" name=".notdef"/>
+ <map code="0xc4" name="florin"/>
+ <map code="0xc5" name=".notdef"/>
+ <map code="0xc6" name=".notdef"/>
+ <map code="0xc7" name="guillemotleft"/>
+ <map code="0xc8" name="guillemotright"/>
+ <map code="0xc9" name="ellipsis"/>
+ <map code="0xca" name=".notdef#16"/>
+ <map code="0xcb" name="Agrave"/>
+ <map code="0xcc" name="Atilde"/>
+ <map code="0xcd" name="Otilde"/>
+ <map code="0xce" name="OE"/>
+ <map code="0xcf" name="oe"/>
+ <map code="0xd0" name="endash"/>
+ <map code="0xd1" name="emdash"/>
+ <map code="0xd2" name="quotedblleft"/>
+ <map code="0xd3" name="quotedblright"/>
+ <map code="0xd4" name="quoteleft"/>
+ <map code="0xd5" name="quoteright"/>
+ <map code="0xd6" name="divide"/>
+ <map code="0xd7" name=".notdef"/>
+ <map code="0xd8" name="ydieresis"/>
+ <map code="0xd9" name="Ydieresis"/>
+ <map code="0xda" name="fraction"/>
+ <map code="0xdb" name="currency"/>
+ <map code="0xdc" name="guilsinglleft"/>
+ <map code="0xdd" name="guilsinglright"/>
+ <map code="0xde" name="fi"/>
+ <map code="0xdf" name="fl"/>
+ <map code="0xe0" name="daggerdbl"/>
+ <map code="0xe1" name="periodcentered"/>
+ <map code="0xe2" name="quotesinglbase"/>
+ <map code="0xe3" name="quotedblbase"/>
+ <map code="0xe4" name="perthousand"/>
+ <map code="0xe5" name="Acircumflex"/>
+ <map code="0xe6" name="Ecircumflex"/>
+ <map code="0xe7" name="Aacute"/>
+ <map code="0xe8" name="Edieresis"/>
+ <map code="0xe9" name="Egrave"/>
+ <map code="0xea" name="Iacute"/>
+ <map code="0xeb" name="Icircumflex"/>
+ <map code="0xec" name="Idieresis"/>
+ <map code="0xed" name="Igrave"/>
+ <map code="0xee" name="Oacute"/>
+ <map code="0xef" name="Ocircumflex"/>
+ <map code="0xf0" name="Euro"/>
+ <map code="0xf1" name="Ograve"/>
+ <map code="0xf2" name="Uacute"/>
+ <map code="0xf3" name="Ucircumflex"/>
+ <map code="0xf4" name="Ugrave"/>
+ <map code="0xf5" name="dotlessi"/>
+ <map code="0xf6" name="circumflex"/>
+ <map code="0xf7" name="tilde"/>
+ <map code="0xf8" name="macron"/>
+ <map code="0xf9" name="breve"/>
+ <map code="0xfa" name="dotaccent"/>
+ <map code="0xfb" name="ring"/>
+ <map code="0xfc" name="cedilla"/>
+ <map code="0xfd" name="hungarumlaut"/>
+ <map code="0xfe" name="ogonek"/>
+ <map code="0xff" name="caron"/>
+ </cmap_format_0>
+ <cmap_format_4 platformID="3" platEncID="1" language="0">
+ <map code="0x20" name="space"/><!-- SPACE -->
+ <map code="0x21" name="exclam"/><!-- EXCLAMATION MARK -->
+ <map code="0x22" name="quotedbl"/><!-- QUOTATION MARK -->
+ <map code="0x23" name="numbersign"/><!-- NUMBER SIGN -->
+ <map code="0x24" name="dollar"/><!-- DOLLAR SIGN -->
+ <map code="0x25" name="percent"/><!-- PERCENT SIGN -->
+ <map code="0x26" name="ampersand"/><!-- AMPERSAND -->
+ <map code="0x27" name="quotesingle"/><!-- APOSTROPHE -->
+ <map code="0x28" name="parenleft"/><!-- LEFT PARENTHESIS -->
+ <map code="0x29" name="parenright"/><!-- RIGHT PARENTHESIS -->
+ <map code="0x2a" name="asterisk"/><!-- ASTERISK -->
+ <map code="0x2b" name="plus"/><!-- PLUS SIGN -->
+ <map code="0x2c" name="comma"/><!-- COMMA -->
+ <map code="0x2d" name="hyphen"/><!-- HYPHEN-MINUS -->
+ <map code="0x2e" name="period"/><!-- FULL STOP -->
+ <map code="0x2f" name="slash"/><!-- SOLIDUS -->
+ <map code="0x30" name="zero"/><!-- DIGIT ZERO -->
+ <map code="0x31" name="one"/><!-- DIGIT ONE -->
+ <map code="0x32" name="two"/><!-- DIGIT TWO -->
+ <map code="0x33" name="three"/><!-- DIGIT THREE -->
+ <map code="0x34" name="four"/><!-- DIGIT FOUR -->
+ <map code="0x35" name="five"/><!-- DIGIT FIVE -->
+ <map code="0x36" name="six"/><!-- DIGIT SIX -->
+ <map code="0x37" name="seven"/><!-- DIGIT SEVEN -->
+ <map code="0x38" name="eight"/><!-- DIGIT EIGHT -->
+ <map code="0x39" name="nine"/><!-- DIGIT NINE -->
+ <map code="0x3a" name="colon"/><!-- COLON -->
+ <map code="0x3b" name="semicolon"/><!-- SEMICOLON -->
+ <map code="0x3c" name="less"/><!-- LESS-THAN SIGN -->
+ <map code="0x3d" name="equal"/><!-- EQUALS SIGN -->
+ <map code="0x3e" name="greater"/><!-- GREATER-THAN SIGN -->
+ <map code="0x3f" name="question"/><!-- QUESTION MARK -->
+ <map code="0x40" name="at"/><!-- COMMERCIAL AT -->
+ <map code="0x41" name="A"/><!-- LATIN CAPITAL LETTER A -->
+ <map code="0x42" name="B"/><!-- LATIN CAPITAL LETTER B -->
+ <map code="0x43" name="C"/><!-- LATIN CAPITAL LETTER C -->
+ <map code="0x44" name="D"/><!-- LATIN CAPITAL LETTER D -->
+ <map code="0x45" name="E"/><!-- LATIN CAPITAL LETTER E -->
+ <map code="0x46" name="F"/><!-- LATIN CAPITAL LETTER F -->
+ <map code="0x47" name="G"/><!-- LATIN CAPITAL LETTER G -->
+ <map code="0x48" name="H"/><!-- LATIN CAPITAL LETTER H -->
+ <map code="0x49" name="I"/><!-- LATIN CAPITAL LETTER I -->
+ <map code="0x4a" name="J"/><!-- LATIN CAPITAL LETTER J -->
+ <map code="0x4b" name="K"/><!-- LATIN CAPITAL LETTER K -->
+ <map code="0x4c" name="L"/><!-- LATIN CAPITAL LETTER L -->
+ <map code="0x4d" name="M"/><!-- LATIN CAPITAL LETTER M -->
+ <map code="0x4e" name="N"/><!-- LATIN CAPITAL LETTER N -->
+ <map code="0x4f" name="O"/><!-- LATIN CAPITAL LETTER O -->
+ <map code="0x50" name="P"/><!-- LATIN CAPITAL LETTER P -->
+ <map code="0x51" name="Q"/><!-- LATIN CAPITAL LETTER Q -->
+ <map code="0x52" name="R"/><!-- LATIN CAPITAL LETTER R -->
+ <map code="0x53" name="S"/><!-- LATIN CAPITAL LETTER S -->
+ <map code="0x54" name="T"/><!-- LATIN CAPITAL LETTER T -->
+ <map code="0x55" name="U"/><!-- LATIN CAPITAL LETTER U -->
+ <map code="0x56" name="V"/><!-- LATIN CAPITAL LETTER V -->
+ <map code="0x57" name="W"/><!-- LATIN CAPITAL LETTER W -->
+ <map code="0x58" name="X"/><!-- LATIN CAPITAL LETTER X -->
+ <map code="0x59" name="Y"/><!-- LATIN CAPITAL LETTER Y -->
+ <map code="0x5a" name="Z"/><!-- LATIN CAPITAL LETTER Z -->
+ <map code="0x5b" name="bracketleft"/><!-- LEFT SQUARE BRACKET -->
+ <map code="0x5c" name="backslash"/><!-- REVERSE SOLIDUS -->
+ <map code="0x5d" name="bracketright"/><!-- RIGHT SQUARE BRACKET -->
+ <map code="0x5e" name="asciicircum"/><!-- CIRCUMFLEX ACCENT -->
+ <map code="0x5f" name="underscore"/><!-- LOW LINE -->
+ <map code="0x60" name="grave"/><!-- GRAVE ACCENT -->
+ <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
+ <map code="0x62" name="b"/><!-- LATIN SMALL LETTER B -->
+ <map code="0x63" name="c"/><!-- LATIN SMALL LETTER C -->
+ <map code="0x64" name="d"/><!-- LATIN SMALL LETTER D -->
+ <map code="0x65" name="e"/><!-- LATIN SMALL LETTER E -->
+ <map code="0x66" name="f"/><!-- LATIN SMALL LETTER F -->
+ <map code="0x67" name="g"/><!-- LATIN SMALL LETTER G -->
+ <map code="0x68" name="h"/><!-- LATIN SMALL LETTER H -->
+ <map code="0x69" name="i"/><!-- LATIN SMALL LETTER I -->
+ <map code="0x6a" name="j"/><!-- LATIN SMALL LETTER J -->
+ <map code="0x6b" name="k"/><!-- LATIN SMALL LETTER K -->
+ <map code="0x6c" name="l"/><!-- LATIN SMALL LETTER L -->
+ <map code="0x6d" name="m"/><!-- LATIN SMALL LETTER M -->
+ <map code="0x6e" name="n"/><!-- LATIN SMALL LETTER N -->
+ <map code="0x6f" name="o"/><!-- LATIN SMALL LETTER O -->
+ <map code="0x70" name="p"/><!-- LATIN SMALL LETTER P -->
+ <map code="0x71" name="q"/><!-- LATIN SMALL LETTER Q -->
+ <map code="0x72" name="r"/><!-- LATIN SMALL LETTER R -->
+ <map code="0x73" name="s"/><!-- LATIN SMALL LETTER S -->
+ <map code="0x74" name="t"/><!-- LATIN SMALL LETTER T -->
+ <map code="0x75" name="u"/><!-- LATIN SMALL LETTER U -->
+ <map code="0x76" name="v"/><!-- LATIN SMALL LETTER V -->
+ <map code="0x77" name="w"/><!-- LATIN SMALL LETTER W -->
+ <map code="0x78" name="x"/><!-- LATIN SMALL LETTER X -->
+ <map code="0x79" name="y"/><!-- LATIN SMALL LETTER Y -->
+ <map code="0x7a" name="z"/><!-- LATIN SMALL LETTER Z -->
+ <map code="0x7b" name="braceleft"/><!-- LEFT CURLY BRACKET -->
+ <map code="0x7c" name="bar"/><!-- VERTICAL LINE -->
+ <map code="0x7d" name="braceright"/><!-- RIGHT CURLY BRACKET -->
+ <map code="0x7e" name="asciitilde"/><!-- TILDE -->
+ <map code="0x80" name="Euro#1"/><!-- &lt;control> -->
+ <map code="0xa0" name="nonbreakingspace"/><!-- NO-BREAK SPACE -->
+ <map code="0xa1" name="exclamdown"/><!-- INVERTED EXCLAMATION MARK -->
+ <map code="0xa2" name="cent"/><!-- CENT SIGN -->
+ <map code="0xa3" name="sterling"/><!-- POUND SIGN -->
+ <map code="0xa4" name="currency"/><!-- CURRENCY SIGN -->
+ <map code="0xa5" name="yen"/><!-- YEN SIGN -->
+ <map code="0xa6" name="brokenbar"/><!-- BROKEN BAR -->
+ <map code="0xa7" name="section"/><!-- SECTION SIGN -->
+ <map code="0xa8" name="dieresis"/><!-- DIAERESIS -->
+ <map code="0xa9" name="copyright"/><!-- COPYRIGHT SIGN -->
+ <map code="0xaa" name="ordfeminine"/><!-- FEMININE ORDINAL INDICATOR -->
+ <map code="0xab" name="guillemotleft"/><!-- LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <map code="0xac" name="logicalnot"/><!-- NOT SIGN -->
+ <map code="0xad" name="sfthyphen"/><!-- SOFT HYPHEN -->
+ <map code="0xae" name="registered"/><!-- REGISTERED SIGN -->
+ <map code="0xaf" name="macron#1"/><!-- MACRON -->
+ <map code="0xb0" name="degree"/><!-- DEGREE SIGN -->
+ <map code="0xb1" name="plusminus"/><!-- PLUS-MINUS SIGN -->
+ <map code="0xb2" name="twosuperior"/><!-- SUPERSCRIPT TWO -->
+ <map code="0xb3" name="threesuperior"/><!-- SUPERSCRIPT THREE -->
+ <map code="0xb4" name="acute"/><!-- ACUTE ACCENT -->
+ <map code="0xb5" name="mu"/><!-- MICRO SIGN -->
+ <map code="0xb6" name="paragraph"/><!-- PILCROW SIGN -->
+ <map code="0xb7" name="periodcentered#1"/><!-- MIDDLE DOT -->
+ <map code="0xb8" name="cedilla"/><!-- CEDILLA -->
+ <map code="0xb9" name="onesuperior"/><!-- SUPERSCRIPT ONE -->
+ <map code="0xba" name="ordmasculine"/><!-- MASCULINE ORDINAL INDICATOR -->
+ <map code="0xbb" name="guillemotright"/><!-- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
+ <map code="0xbc" name="onequarter"/><!-- VULGAR FRACTION ONE QUARTER -->
+ <map code="0xbd" name="onehalf"/><!-- VULGAR FRACTION ONE HALF -->
+ <map code="0xbe" name="threequarters"/><!-- VULGAR FRACTION THREE QUARTERS -->
+ <map code="0xbf" name="questiondown"/><!-- INVERTED QUESTION MARK -->
+ <map code="0xc0" name="Agrave"/><!-- LATIN CAPITAL LETTER A WITH GRAVE -->
+ <map code="0xc1" name="Aacute"/><!-- LATIN CAPITAL LETTER A WITH ACUTE -->
+ <map code="0xc2" name="Acircumflex"/><!-- LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
+ <map code="0xc3" name="Atilde"/><!-- LATIN CAPITAL LETTER A WITH TILDE -->
+ <map code="0xc4" name="Adieresis"/><!-- LATIN CAPITAL LETTER A WITH DIAERESIS -->
+ <map code="0xc5" name="Aring"/><!-- LATIN CAPITAL LETTER A WITH RING ABOVE -->
+ <map code="0xc6" name="AE"/><!-- LATIN CAPITAL LETTER AE -->
+ <map code="0xc7" name="Ccedilla"/><!-- LATIN CAPITAL LETTER C WITH CEDILLA -->
+ <map code="0xc8" name="Egrave"/><!-- LATIN CAPITAL LETTER E WITH GRAVE -->
+ <map code="0xc9" name="Eacute"/><!-- LATIN CAPITAL LETTER E WITH ACUTE -->
+ <map code="0xca" name="Ecircumflex"/><!-- LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
+ <map code="0xcb" name="Edieresis"/><!-- LATIN CAPITAL LETTER E WITH DIAERESIS -->
+ <map code="0xcc" name="Igrave"/><!-- LATIN CAPITAL LETTER I WITH GRAVE -->
+ <map code="0xcd" name="Iacute"/><!-- LATIN CAPITAL LETTER I WITH ACUTE -->
+ <map code="0xce" name="Icircumflex"/><!-- LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
+ <map code="0xcf" name="Idieresis"/><!-- LATIN CAPITAL LETTER I WITH DIAERESIS -->
+ <map code="0xd0" name="Eth"/><!-- LATIN CAPITAL LETTER ETH -->
+ <map code="0xd1" name="Ntilde"/><!-- LATIN CAPITAL LETTER N WITH TILDE -->
+ <map code="0xd2" name="Ograve"/><!-- LATIN CAPITAL LETTER O WITH GRAVE -->
+ <map code="0xd3" name="Oacute"/><!-- LATIN CAPITAL LETTER O WITH ACUTE -->
+ <map code="0xd4" name="Ocircumflex"/><!-- LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
+ <map code="0xd5" name="Otilde"/><!-- LATIN CAPITAL LETTER O WITH TILDE -->
+ <map code="0xd6" name="Odieresis"/><!-- LATIN CAPITAL LETTER O WITH DIAERESIS -->
+ <map code="0xd7" name="multiply"/><!-- MULTIPLICATION SIGN -->
+ <map code="0xd8" name="Oslash"/><!-- LATIN CAPITAL LETTER O WITH STROKE -->
+ <map code="0xd9" name="Ugrave"/><!-- LATIN CAPITAL LETTER U WITH GRAVE -->
+ <map code="0xda" name="Uacute"/><!-- LATIN CAPITAL LETTER U WITH ACUTE -->
+ <map code="0xdb" name="Ucircumflex"/><!-- LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
+ <map code="0xdc" name="Udieresis"/><!-- LATIN CAPITAL LETTER U WITH DIAERESIS -->
+ <map code="0xdd" name="Yacute"/><!-- LATIN CAPITAL LETTER Y WITH ACUTE -->
+ <map code="0xde" name="Thorn"/><!-- LATIN CAPITAL LETTER THORN -->
+ <map code="0xdf" name="germandbls"/><!-- LATIN SMALL LETTER SHARP S -->
+ <map code="0xe0" name="agrave"/><!-- LATIN SMALL LETTER A WITH GRAVE -->
+ <map code="0xe1" name="aacute"/><!-- LATIN SMALL LETTER A WITH ACUTE -->
+ <map code="0xe2" name="acircumflex"/><!-- LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+ <map code="0xe3" name="atilde"/><!-- LATIN SMALL LETTER A WITH TILDE -->
+ <map code="0xe4" name="adieresis"/><!-- LATIN SMALL LETTER A WITH DIAERESIS -->
+ <map code="0xe5" name="aring"/><!-- LATIN SMALL LETTER A WITH RING ABOVE -->
+ <map code="0xe6" name="ae"/><!-- LATIN SMALL LETTER AE -->
+ <map code="0xe7" name="ccedilla"/><!-- LATIN SMALL LETTER C WITH CEDILLA -->
+ <map code="0xe8" name="egrave"/><!-- LATIN SMALL LETTER E WITH GRAVE -->
+ <map code="0xe9" name="eacute"/><!-- LATIN SMALL LETTER E WITH ACUTE -->
+ <map code="0xea" name="ecircumflex"/><!-- LATIN SMALL LETTER E WITH CIRCUMFLEX -->
+ <map code="0xeb" name="edieresis"/><!-- LATIN SMALL LETTER E WITH DIAERESIS -->
+ <map code="0xec" name="igrave"/><!-- LATIN SMALL LETTER I WITH GRAVE -->
+ <map code="0xed" name="iacute"/><!-- LATIN SMALL LETTER I WITH ACUTE -->
+ <map code="0xee" name="icircumflex"/><!-- LATIN SMALL LETTER I WITH CIRCUMFLEX -->
+ <map code="0xef" name="idieresis"/><!-- LATIN SMALL LETTER I WITH DIAERESIS -->
+ <map code="0xf0" name="eth"/><!-- LATIN SMALL LETTER ETH -->
+ <map code="0xf1" name="ntilde"/><!-- LATIN SMALL LETTER N WITH TILDE -->
+ <map code="0xf2" name="ograve"/><!-- LATIN SMALL LETTER O WITH GRAVE -->
+ <map code="0xf3" name="oacute"/><!-- LATIN SMALL LETTER O WITH ACUTE -->
+ <map code="0xf4" name="ocircumflex"/><!-- LATIN SMALL LETTER O WITH CIRCUMFLEX -->
+ <map code="0xf5" name="otilde"/><!-- LATIN SMALL LETTER O WITH TILDE -->
+ <map code="0xf6" name="odieresis"/><!-- LATIN SMALL LETTER O WITH DIAERESIS -->
+ <map code="0xf7" name="divide"/><!-- DIVISION SIGN -->
+ <map code="0xf8" name="oslash"/><!-- LATIN SMALL LETTER O WITH STROKE -->
+ <map code="0xf9" name="ugrave"/><!-- LATIN SMALL LETTER U WITH GRAVE -->
+ <map code="0xfa" name="uacute"/><!-- LATIN SMALL LETTER U WITH ACUTE -->
+ <map code="0xfb" name="ucircumflex"/><!-- LATIN SMALL LETTER U WITH CIRCUMFLEX -->
+ <map code="0xfc" name="udieresis"/><!-- LATIN SMALL LETTER U WITH DIAERESIS -->
+ <map code="0xfd" name="yacute"/><!-- LATIN SMALL LETTER Y WITH ACUTE -->
+ <map code="0xfe" name="thorn"/><!-- LATIN SMALL LETTER THORN -->
+ <map code="0xff" name="ydieresis"/><!-- LATIN SMALL LETTER Y WITH DIAERESIS -->
+ <map code="0x100" name="Amacron"/><!-- LATIN CAPITAL LETTER A WITH MACRON -->
+ <map code="0x101" name="amacron"/><!-- LATIN SMALL LETTER A WITH MACRON -->
+ <map code="0x102" name="Abreve"/><!-- LATIN CAPITAL LETTER A WITH BREVE -->
+ <map code="0x103" name="abreve"/><!-- LATIN SMALL LETTER A WITH BREVE -->
+ <map code="0x104" name="Aogonek"/><!-- LATIN CAPITAL LETTER A WITH OGONEK -->
+ <map code="0x105" name="aogonek"/><!-- LATIN SMALL LETTER A WITH OGONEK -->
+ <map code="0x106" name="Cacute"/><!-- LATIN CAPITAL LETTER C WITH ACUTE -->
+ <map code="0x107" name="cacute"/><!-- LATIN SMALL LETTER C WITH ACUTE -->
+ <map code="0x108" name="Ccircumflex"/><!-- LATIN CAPITAL LETTER C WITH CIRCUMFLEX -->
+ <map code="0x109" name="ccircumflex"/><!-- LATIN SMALL LETTER C WITH CIRCUMFLEX -->
+ <map code="0x10a" name="Cdotaccent"/><!-- LATIN CAPITAL LETTER C WITH DOT ABOVE -->
+ <map code="0x10b" name="cdotaccent"/><!-- LATIN SMALL LETTER C WITH DOT ABOVE -->
+ <map code="0x10c" name="Ccaron"/><!-- LATIN CAPITAL LETTER C WITH CARON -->
+ <map code="0x10d" name="ccaron"/><!-- LATIN SMALL LETTER C WITH CARON -->
+ <map code="0x10e" name="Dcaron"/><!-- LATIN CAPITAL LETTER D WITH CARON -->
+ <map code="0x10f" name="dcaron"/><!-- LATIN SMALL LETTER D WITH CARON -->
+ <map code="0x110" name="Dcroat"/><!-- LATIN CAPITAL LETTER D WITH STROKE -->
+ <map code="0x111" name="dcroat"/><!-- LATIN SMALL LETTER D WITH STROKE -->
+ <map code="0x112" name="Emacron"/><!-- LATIN CAPITAL LETTER E WITH MACRON -->
+ <map code="0x113" name="emacron"/><!-- LATIN SMALL LETTER E WITH MACRON -->
+ <map code="0x114" name="Ebreve"/><!-- LATIN CAPITAL LETTER E WITH BREVE -->
+ <map code="0x115" name="ebreve"/><!-- LATIN SMALL LETTER E WITH BREVE -->
+ <map code="0x116" name="Edotaccent"/><!-- LATIN CAPITAL LETTER E WITH DOT ABOVE -->
+ <map code="0x117" name="edotaccent"/><!-- LATIN SMALL LETTER E WITH DOT ABOVE -->
+ <map code="0x118" name="Eogonek"/><!-- LATIN CAPITAL LETTER E WITH OGONEK -->
+ <map code="0x119" name="eogonek"/><!-- LATIN SMALL LETTER E WITH OGONEK -->
+ <map code="0x11a" name="Ecaron"/><!-- LATIN CAPITAL LETTER E WITH CARON -->
+ <map code="0x11b" name="ecaron"/><!-- LATIN SMALL LETTER E WITH CARON -->
+ <map code="0x11c" name="Gcircumflex"/><!-- LATIN CAPITAL LETTER G WITH CIRCUMFLEX -->
+ <map code="0x11d" name="gcircumflex"/><!-- LATIN SMALL LETTER G WITH CIRCUMFLEX -->
+ <map code="0x11e" name="Gbreve"/><!-- LATIN CAPITAL LETTER G WITH BREVE -->
+ <map code="0x11f" name="gbreve"/><!-- LATIN SMALL LETTER G WITH BREVE -->
+ <map code="0x120" name="Gdotaccent"/><!-- LATIN CAPITAL LETTER G WITH DOT ABOVE -->
+ <map code="0x121" name="gdotaccent"/><!-- LATIN SMALL LETTER G WITH DOT ABOVE -->
+ <map code="0x122" name="Gcommaaccent"/><!-- LATIN CAPITAL LETTER G WITH CEDILLA -->
+ <map code="0x123" name="gcommaaccent"/><!-- LATIN SMALL LETTER G WITH CEDILLA -->
+ <map code="0x124" name="Hcircumflex"/><!-- LATIN CAPITAL LETTER H WITH CIRCUMFLEX -->
+ <map code="0x125" name="hcircumflex"/><!-- LATIN SMALL LETTER H WITH CIRCUMFLEX -->
+ <map code="0x126" name="Hbar"/><!-- LATIN CAPITAL LETTER H WITH STROKE -->
+ <map code="0x127" name="hbar"/><!-- LATIN SMALL LETTER H WITH STROKE -->
+ <map code="0x128" name="Itilde"/><!-- LATIN CAPITAL LETTER I WITH TILDE -->
+ <map code="0x129" name="itilde"/><!-- LATIN SMALL LETTER I WITH TILDE -->
+ <map code="0x12a" name="Imacron"/><!-- LATIN CAPITAL LETTER I WITH MACRON -->
+ <map code="0x12b" name="imacron"/><!-- LATIN SMALL LETTER I WITH MACRON -->
+ <map code="0x12c" name="Ibreve"/><!-- LATIN CAPITAL LETTER I WITH BREVE -->
+ <map code="0x12d" name="ibreve"/><!-- LATIN SMALL LETTER I WITH BREVE -->
+ <map code="0x12e" name="Iogonek"/><!-- LATIN CAPITAL LETTER I WITH OGONEK -->
+ <map code="0x12f" name="iogonek"/><!-- LATIN SMALL LETTER I WITH OGONEK -->
+ <map code="0x130" name="Idotaccent"/><!-- LATIN CAPITAL LETTER I WITH DOT ABOVE -->
+ <map code="0x131" name="dotlessi"/><!-- LATIN SMALL LETTER DOTLESS I -->
+ <map code="0x132" name="IJ"/><!-- LATIN CAPITAL LIGATURE IJ -->
+ <map code="0x133" name="ij"/><!-- LATIN SMALL LIGATURE IJ -->
+ <map code="0x134" name="Jcircumflex"/><!-- LATIN CAPITAL LETTER J WITH CIRCUMFLEX -->
+ <map code="0x135" name="jcircumflex"/><!-- LATIN SMALL LETTER J WITH CIRCUMFLEX -->
+ <map code="0x136" name="Kcommaaccent"/><!-- LATIN CAPITAL LETTER K WITH CEDILLA -->
+ <map code="0x137" name="kcommaaccent"/><!-- LATIN SMALL LETTER K WITH CEDILLA -->
+ <map code="0x138" name="kgreenlandic"/><!-- LATIN SMALL LETTER KRA -->
+ <map code="0x139" name="Lacute"/><!-- LATIN CAPITAL LETTER L WITH ACUTE -->
+ <map code="0x13a" name="lacute"/><!-- LATIN SMALL LETTER L WITH ACUTE -->
+ <map code="0x13b" name="Lcommaaccent"/><!-- LATIN CAPITAL LETTER L WITH CEDILLA -->
+ <map code="0x13c" name="lcommaaccent"/><!-- LATIN SMALL LETTER L WITH CEDILLA -->
+ <map code="0x13d" name="Lcaron"/><!-- LATIN CAPITAL LETTER L WITH CARON -->
+ <map code="0x13e" name="lcaron"/><!-- LATIN SMALL LETTER L WITH CARON -->
+ <map code="0x13f" name="Ldot"/><!-- LATIN CAPITAL LETTER L WITH MIDDLE DOT -->
+ <map code="0x140" name="ldot"/><!-- LATIN SMALL LETTER L WITH MIDDLE DOT -->
+ <map code="0x141" name="Lslash"/><!-- LATIN CAPITAL LETTER L WITH STROKE -->
+ <map code="0x142" name="lslash"/><!-- LATIN SMALL LETTER L WITH STROKE -->
+ <map code="0x143" name="Nacute"/><!-- LATIN CAPITAL LETTER N WITH ACUTE -->
+ <map code="0x144" name="nacute"/><!-- LATIN SMALL LETTER N WITH ACUTE -->
+ <map code="0x145" name="Ncommaaccent"/><!-- LATIN CAPITAL LETTER N WITH CEDILLA -->
+ <map code="0x146" name="ncommaaccent"/><!-- LATIN SMALL LETTER N WITH CEDILLA -->
+ <map code="0x147" name="Ncaron"/><!-- LATIN CAPITAL LETTER N WITH CARON -->
+ <map code="0x148" name="ncaron"/><!-- LATIN SMALL LETTER N WITH CARON -->
+ <map code="0x149" name="napostrophe"/><!-- LATIN SMALL LETTER N PRECEDED BY APOSTROPHE -->
+ <map code="0x14a" name="Eng"/><!-- LATIN CAPITAL LETTER ENG -->
+ <map code="0x14b" name="eng"/><!-- LATIN SMALL LETTER ENG -->
+ <map code="0x14c" name="Omacron"/><!-- LATIN CAPITAL LETTER O WITH MACRON -->
+ <map code="0x14d" name="omacron"/><!-- LATIN SMALL LETTER O WITH MACRON -->
+ <map code="0x14e" name="Obreve"/><!-- LATIN CAPITAL LETTER O WITH BREVE -->
+ <map code="0x14f" name="obreve"/><!-- LATIN SMALL LETTER O WITH BREVE -->
+ <map code="0x150" name="Ohungarumlaut"/><!-- LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -->
+ <map code="0x151" name="ohungarumlaut"/><!-- LATIN SMALL LETTER O WITH DOUBLE ACUTE -->
+ <map code="0x152" name="OE"/><!-- LATIN CAPITAL LIGATURE OE -->
+ <map code="0x153" name="oe"/><!-- LATIN SMALL LIGATURE OE -->
+ <map code="0x154" name="Racute"/><!-- LATIN CAPITAL LETTER R WITH ACUTE -->
+ <map code="0x155" name="racute"/><!-- LATIN SMALL LETTER R WITH ACUTE -->
+ <map code="0x156" name="Rcommaaccent"/><!-- LATIN CAPITAL LETTER R WITH CEDILLA -->
+ <map code="0x157" name="rcommaaccent"/><!-- LATIN SMALL LETTER R WITH CEDILLA -->
+ <map code="0x158" name="Rcaron"/><!-- LATIN CAPITAL LETTER R WITH CARON -->
+ <map code="0x159" name="rcaron"/><!-- LATIN SMALL LETTER R WITH CARON -->
+ <map code="0x15a" name="Sacute"/><!-- LATIN CAPITAL LETTER S WITH ACUTE -->
+ <map code="0x15b" name="sacute"/><!-- LATIN SMALL LETTER S WITH ACUTE -->
+ <map code="0x15c" name="Scircumflex"/><!-- LATIN CAPITAL LETTER S WITH CIRCUMFLEX -->
+ <map code="0x15d" name="scircumflex"/><!-- LATIN SMALL LETTER S WITH CIRCUMFLEX -->
+ <map code="0x15e" name="Scedilla"/><!-- LATIN CAPITAL LETTER S WITH CEDILLA -->
+ <map code="0x15f" name="scedilla"/><!-- LATIN SMALL LETTER S WITH CEDILLA -->
+ <map code="0x160" name="Scaron"/><!-- LATIN CAPITAL LETTER S WITH CARON -->
+ <map code="0x161" name="scaron"/><!-- LATIN SMALL LETTER S WITH CARON -->
+ <map code="0x162" name="Tcommaaccent"/><!-- LATIN CAPITAL LETTER T WITH CEDILLA -->
+ <map code="0x163" name="tcommaaccent"/><!-- LATIN SMALL LETTER T WITH CEDILLA -->
+ <map code="0x164" name="Tcaron"/><!-- LATIN CAPITAL LETTER T WITH CARON -->
+ <map code="0x165" name="tcaron"/><!-- LATIN SMALL LETTER T WITH CARON -->
+ <map code="0x166" name="Tbar"/><!-- LATIN CAPITAL LETTER T WITH STROKE -->
+ <map code="0x167" name="tbar"/><!-- LATIN SMALL LETTER T WITH STROKE -->
+ <map code="0x168" name="Utilde"/><!-- LATIN CAPITAL LETTER U WITH TILDE -->
+ <map code="0x169" name="utilde"/><!-- LATIN SMALL LETTER U WITH TILDE -->
+ <map code="0x16a" name="Umacron"/><!-- LATIN CAPITAL LETTER U WITH MACRON -->
+ <map code="0x16b" name="umacron"/><!-- LATIN SMALL LETTER U WITH MACRON -->
+ <map code="0x16c" name="Ubreve"/><!-- LATIN CAPITAL LETTER U WITH BREVE -->
+ <map code="0x16d" name="ubreve"/><!-- LATIN SMALL LETTER U WITH BREVE -->
+ <map code="0x16e" name="Uring"/><!-- LATIN CAPITAL LETTER U WITH RING ABOVE -->
+ <map code="0x16f" name="uring"/><!-- LATIN SMALL LETTER U WITH RING ABOVE -->
+ <map code="0x170" name="Uhungarumlaut"/><!-- LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -->
+ <map code="0x171" name="uhungarumlaut"/><!-- LATIN SMALL LETTER U WITH DOUBLE ACUTE -->
+ <map code="0x172" name="Uogonek"/><!-- LATIN CAPITAL LETTER U WITH OGONEK -->
+ <map code="0x173" name="uogonek"/><!-- LATIN SMALL LETTER U WITH OGONEK -->
+ <map code="0x174" name="Wcircumflex"/><!-- LATIN CAPITAL LETTER W WITH CIRCUMFLEX -->
+ <map code="0x175" name="wcircumflex"/><!-- LATIN SMALL LETTER W WITH CIRCUMFLEX -->
+ <map code="0x176" name="Ycircumflex"/><!-- LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -->
+ <map code="0x177" name="ycircumflex"/><!-- LATIN SMALL LETTER Y WITH CIRCUMFLEX -->
+ <map code="0x178" name="Ydieresis"/><!-- LATIN CAPITAL LETTER Y WITH DIAERESIS -->
+ <map code="0x179" name="Zacute"/><!-- LATIN CAPITAL LETTER Z WITH ACUTE -->
+ <map code="0x17a" name="zacute"/><!-- LATIN SMALL LETTER Z WITH ACUTE -->
+ <map code="0x17b" name="Zdotaccent"/><!-- LATIN CAPITAL LETTER Z WITH DOT ABOVE -->
+ <map code="0x17c" name="zdotaccent"/><!-- LATIN SMALL LETTER Z WITH DOT ABOVE -->
+ <map code="0x17d" name="Zcaron"/><!-- LATIN CAPITAL LETTER Z WITH CARON -->
+ <map code="0x17e" name="zcaron"/><!-- LATIN SMALL LETTER Z WITH CARON -->
+ <map code="0x17f" name="longs"/><!-- LATIN SMALL LETTER LONG S -->
+ <map code="0x192" name="florin"/><!-- LATIN SMALL LETTER F WITH HOOK -->
+ <map code="0x218" name="Scommaaccent"/><!-- LATIN CAPITAL LETTER S WITH COMMA BELOW -->
+ <map code="0x219" name="scommaaccent"/><!-- LATIN SMALL LETTER S WITH COMMA BELOW -->
+ <map code="0x21a" name="Tcommabelow"/><!-- LATIN CAPITAL LETTER T WITH COMMA BELOW -->
+ <map code="0x21b" name="tcommabelow"/><!-- LATIN SMALL LETTER T WITH COMMA BELOW -->
+ <map code="0x2c6" name="circumflex"/><!-- MODIFIER LETTER CIRCUMFLEX ACCENT -->
+ <map code="0x2c7" name="caron"/><!-- CARON -->
+ <map code="0x2c9" name="macron"/><!-- MODIFIER LETTER MACRON -->
+ <map code="0x2d8" name="breve"/><!-- BREVE -->
+ <map code="0x2d9" name="dotaccent"/><!-- DOT ABOVE -->
+ <map code="0x2da" name="ring"/><!-- RING ABOVE -->
+ <map code="0x2db" name="ogonek"/><!-- OGONEK -->
+ <map code="0x2dc" name="tilde"/><!-- SMALL TILDE -->
+ <map code="0x2dd" name="hungarumlaut"/><!-- DOUBLE ACUTE ACCENT -->
+ <map code="0x326" name="Unterkomma"/><!-- COMBINING COMMA BELOW -->
+ <map code="0x37e" name="semicolon#1"/><!-- GREEK QUESTION MARK -->
+ <map code="0x387" name="anoteleia"/><!-- GREEK ANO TELEIA -->
+ <map code="0x2010" name="hyphen#1"/><!-- HYPHEN -->
+ <map code="0x2011" name="nbhyphen"/><!-- NON-BREAKING HYPHEN -->
+ <map code="0x2012" name="figuredash"/><!-- FIGURE DASH -->
+ <map code="0x2013" name="endash"/><!-- EN DASH -->
+ <map code="0x2014" name="emdash"/><!-- EM DASH -->
+ <map code="0x2015" name="afii00208"/><!-- HORIZONTAL BAR -->
+ <map code="0x2018" name="quoteleft"/><!-- LEFT SINGLE QUOTATION MARK -->
+ <map code="0x2019" name="quoteright"/><!-- RIGHT SINGLE QUOTATION MARK -->
+ <map code="0x201a" name="quotesinglbase"/><!-- SINGLE LOW-9 QUOTATION MARK -->
+ <map code="0x201b" name="quotereversed"/><!-- SINGLE HIGH-REVERSED-9 QUOTATION MARK -->
+ <map code="0x201c" name="quotedblleft"/><!-- LEFT DOUBLE QUOTATION MARK -->
+ <map code="0x201d" name="quotedblright"/><!-- RIGHT DOUBLE QUOTATION MARK -->
+ <map code="0x201e" name="quotedblbase"/><!-- DOUBLE LOW-9 QUOTATION MARK -->
+ <map code="0x2020" name="dagger"/><!-- DAGGER -->
+ <map code="0x2021" name="daggerdbl"/><!-- DOUBLE DAGGER -->
+ <map code="0x2022" name="bullet"/><!-- BULLET -->
+ <map code="0x2026" name="ellipsis"/><!-- HORIZONTAL ELLIPSIS -->
+ <map code="0x2030" name="perthousand"/><!-- PER MILLE SIGN -->
+ <map code="0x2039" name="guilsinglleft"/><!-- SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
+ <map code="0x203a" name="guilsinglright"/><!-- SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
+ <map code="0x203e" name="radicalex"/><!-- OVERLINE -->
+ <map code="0x2044" name="fraction"/><!-- FRACTION SLASH -->
+ <map code="0x20ac" name="Euro"/><!-- EURO SIGN -->
+ <map code="0x2122" name="trademark"/><!-- TRADE MARK SIGN -->
+ <map code="0x212e" name="estimated"/><!-- ESTIMATED SYMBOL -->
+ <map code="0x2212" name="minus"/><!-- MINUS SIGN -->
+ <map code="0x2215" name="fraction#1"/><!-- DIVISION SLASH -->
+ <map code="0x2219" name="periodcentered"/><!-- BULLET OPERATOR -->
+ <map code="0x22c5" name="dotmath"/><!-- DOT OPERATOR -->
+ <map code="0xea01" name="fi#1"/><!-- Private Use -->
+ <map code="0xea02" name="fl#1"/><!-- Private Use -->
+ <map code="0xf001" name="fi"/><!-- Private Use -->
+ <map code="0xf002" name="fl"/><!-- Private Use -->
+ <map code="0xf004" name="foursuperiour"/><!-- Private Use -->
+ <map code="0xf6be" name="dotlessj"/><!-- Private Use -->
+ <map code="0xfb01" name="fi"/><!-- LATIN SMALL LIGATURE FI -->
+ <map code="0xfb02" name="fl"/><!-- LATIN SMALL LIGATURE FL -->
+ </cmap_format_4>
+ </cmap>
+
+ <fpgm>
+ <assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ FDEF[ ]
+ SLOOP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP1[ ]
+ SRP2[ ]
+ IP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP1[ ]
+ SRP2[ ]
+ SLOOP[ ]
+ IP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MIRP[11101]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MIRP[10100]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MDRP[11101]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ SLOOP[ ]
+ MDRP[10100]
+ ALIGNRP[ ]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MIRP[11101]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MIRP[10100]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MDRP[11101]
+ ENDF[ ]
+ FDEF[ ]
+ SRP0[ ]
+ MDRP[10100]
+ ENDF[ ]
+ FDEF[ ]
+ MDRP[00100]
+ ENDF[ ]
+ FDEF[ ]
+ MDRP[00000]
+ ENDF[ ]
+ FDEF[ ]
+ SVTCA[0]
+ NPUSHB[ ] /* 10 values pushed */
+ 1 0 0 1 1 2 2 3 3 0
+ SZPS[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SZPS[ ]
+ ENDF[ ]
+ </assembly>
+ </fpgm>
+
+ <prep>
+ <assembly>
+ PUSHB[ ] /* 2 values pushed */
+ 48 1
+ PUSHW[ ] /* 1 value pushed */
+ 329
+ RTG[ ]
+ SCANCTRL[ ]
+ SCANTYPE[ ]
+ SCVTCI[ ]
+ </assembly>
+ </prep>
+
+ <cvt>
+ <cv index="0" value="1480"/>
+ <cv index="1" value="1086"/>
+ <cv index="2" value="0"/>
+ <cv index="3" value="-512"/>
+ <cv index="4" value="196"/>
+ <cv index="5" value="200"/>
+ <cv index="6" value="125"/>
+ <cv index="7" value="149"/>
+ <cv index="8" value="247"/>
+ <cv index="9" value="213"/>
+ <cv index="10" value="150"/>
+ <cv index="11" value="101"/>
+ <cv index="12" value="196"/>
+ <cv index="13" value="172"/>
+ <cv index="14" value="181"/>
+ <cv index="15" value="157"/>
+ <cv index="16" value="113"/>
+ <cv index="17" value="109"/>
+ <cv index="18" value="133"/>
+ <cv index="19" value="121"/>
+ <cv index="20" value="104"/>
+ <cv index="21" value="97"/>
+ <cv index="22" value="138"/>
+ <cv index="23" value="22"/>
+ <cv index="24" value="183"/>
+ <cv index="25" value="140"/>
+ <cv index="26" value="224"/>
+ <cv index="27" value="186"/>
+ <cv index="28" value="206"/>
+ <cv index="29" value="160"/>
+ <cv index="30" value="171"/>
+ <cv index="31" value="135"/>
+ <cv index="32" value="87"/>
+ <cv index="33" value="210"/>
+ <cv index="34" value="167"/>
+ <cv index="35" value="155"/>
+ <cv index="36" value="227"/>
+ <cv index="37" value="159"/>
+ <cv index="38" value="119"/>
+ <cv index="39" value="152"/>
+ <cv index="40" value="149"/>
+ <cv index="41" value="195"/>
+ <cv index="42" value="137"/>
+ <cv index="43" value="205"/>
+ <cv index="44" value="89"/>
+ <cv index="45" value="165"/>
+ </cvt>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef" xMin="57" yMin="0" xMax="512" yMax="1480">
+ <contour>
+ <pt x="57" y="0" on="1"/>
+ <pt x="57" y="1480" on="1"/>
+ <pt x="512" y="1480" on="1"/>
+ <pt x="512" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="455" y="57" on="1"/>
+ <pt x="455" y="1423" on="1"/>
+ <pt x="114" y="1423" on="1"/>
+ <pt x="114" y="57" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 16 values pushed */
+ 5 6 2 1 4 7 3 0 5 4 2 3 6 7 1 0
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ SVTCA[0]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ MDAP[1]
+ ALIGNRP[ ]
+ MDRP[11100]
+ ALIGNRP[ ]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name=".notdef#1"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#10"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#11"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#12"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#13"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#14"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#15"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#16"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#17"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#18"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#2"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#3"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#4"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#5"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#6"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#7"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#8"/><!-- contains no outline data -->
+
+ <TTGlyph name=".notdef#9"/><!-- contains no outline data -->
+
+ <TTGlyph name="A" xMin="19" yMin="0" xMax="1342" yMax="1480">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 40 values pushed */
+ 10 1 8 2 0 0 9 8 15 1 5 1 4 48 196 6 5 1 7 4 3 0 3 2 0
+ 2 1 0 14 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="AE" xMin="19" yMin="0" xMax="1990" yMax="1480">
+ <contour>
+ <pt x="597" y="569" on="1"/>
+ <pt x="1015" y="569" on="1"/>
+ <pt x="1015" y="1227" on="1"/>
+ </contour>
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="959" y="1480" on="1"/>
+ <pt x="1947" y="1480" on="1"/>
+ <pt x="1947" y="1323" on="1"/>
+ <pt x="1225" y="1323" on="1"/>
+ <pt x="1225" y="848" on="1"/>
+ <pt x="1847" y="848" on="1"/>
+ <pt x="1847" y="693" on="1"/>
+ <pt x="1225" y="693" on="1"/>
+ <pt x="1225" y="157" on="1"/>
+ <pt x="1990" y="157" on="1"/>
+ <pt x="1990" y="0" on="1"/>
+ <pt x="1015" y="0" on="1"/>
+ <pt x="1015" y="414" on="1"/>
+ <pt x="498" y="414" on="1"/>
+ <pt x="236" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 2 6 8 2 0 0 7 6 15 1 4 11 10 15 1 8 13 12 15 1 3 3 4 48 196
+ 9 8 1 17 16 1 18 15 14 3 3 1 0 1 4 0 5 4 0 14 18 17 4 3 0
+ 5 13 1 0 0 16 15 2 1 33 3 7 1 4 48 196 14 13 1 6 5 1 10 9 1
+ 12 11 8 7 3 16 15 2 1 3 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aacute" xMin="19" yMin="0" xMax="1342" yMax="1925">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="537" y="1604" on="1"/>
+ <pt x="778" y="1925" on="1"/>
+ <pt x="1006" y="1925" on="1"/>
+ <pt x="685" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 10 1 8 2 0 0 9 8 15 1 5 1 4 48 196 13 12 1 14 11 1 6 5 1 7
+ 4 3 0 3 4 0 2 1 0 14 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Abreve" xMin="21" yMin="0" xMax="1344" yMax="1925">
+ <contour>
+ <pt x="21" y="0" on="1"/>
+ <pt x="583" y="1480" on="1"/>
+ <pt x="791" y="1480" on="1"/>
+ <pt x="1344" y="0" on="1"/>
+ <pt x="1118" y="0" on="1"/>
+ <pt x="964" y="410" on="1"/>
+ <pt x="370" y="410" on="1"/>
+ <pt x="216" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="430" y="566" on="1"/>
+ <pt x="906" y="566" on="1"/>
+ <pt x="669" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="354" y="1925" on="1"/>
+ <pt x="477" y="1925" on="1"/>
+ <pt x="498" y="1831" on="0"/>
+ <pt x="552" y="1791" on="1"/>
+ <pt x="604" y="1752" on="0"/>
+ <pt x="687" y="1752" on="1"/>
+ <pt x="781" y="1752" on="0"/>
+ <pt x="835" y="1801" on="1"/>
+ <pt x="878" y="1841" on="0"/>
+ <pt x="897" y="1925" on="1"/>
+ <pt x="1020" y="1925" on="1"/>
+ <pt x="1004" y="1791" on="0"/>
+ <pt x="931" y="1710" on="1"/>
+ <pt x="837" y="1604" on="0"/>
+ <pt x="687" y="1604" on="1"/>
+ <pt x="530" y="1604" on="0"/>
+ <pt x="435" y="1719" on="1"/>
+ <pt x="370" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 0 0 16 40 25 48 196 10 1 8 2 21 20 12 11 4 13 25 1 0 0 9 8 15 1
+ 5 1 4 48 196 6 5 1 7 4 3 0 3 2 0 2 1 0 14 21 20 12 11 10 9
+ 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Acircumflex" xMin="19" yMin="0" xMax="1342" yMax="1925">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="335" y="1604" on="1"/>
+ <pt x="576" y="1925" on="1"/>
+ <pt x="794" y="1925" on="1"/>
+ <pt x="1035" y="1604" on="1"/>
+ <pt x="887" y="1604" on="1"/>
+ <pt x="686" y="1806" on="1"/>
+ <pt x="684" y="1806" on="1"/>
+ <pt x="483" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 17 16 2 12 11 3 10 1 8 2 0 0 9 8 15 1 5 1 4 48 196 13 12 1 18
+ 15 14 11 3 6 5 1 7 4 3 0 3 4 0 2 1 0 14 18 17 16 15 14 13 12
+ 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Adieresis" xMin="19" yMin="0" xMax="1342" yMax="1777">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="401" y="1604" on="1"/>
+ <pt x="401" y="1777" on="1"/>
+ <pt x="574" y="1777" on="1"/>
+ <pt x="574" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="796" y="1604" on="1"/>
+ <pt x="796" y="1777" on="1"/>
+ <pt x="969" y="1777" on="1"/>
+ <pt x="969" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 93 values pushed */
+ 10 1 8 2 0 0 18 15 14 11 13 3 12 9 8 15 1 5 2 4 48 196 17 16 13
+ 12 3 6 5 1 7 4 3 0 3 3 0 2 1 0 14 9 5 2 17 15 3 10 2 1
+ 3 15 13 3 8 13 11 2 4 3 2 13 17 7 6 0 3 13 11 0 0 16 15 13 1
+ 17 14 13 13 1 11 2 4 48 196 18 17 1 12 11 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Agrave" xMin="19" yMin="0" xMax="1342" yMax="1925">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="833" y="1604" on="1"/>
+ <pt x="685" y="1604" on="1"/>
+ <pt x="364" y="1925" on="1"/>
+ <pt x="592" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 10 1 8 2 0 0 9 8 15 1 5 1 4 48 196 14 13 1 12 11 1 6 5 1 7
+ 4 3 0 3 4 0 2 1 0 14 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Amacron" xMin="21" yMin="0" xMax="1344" yMax="1752">
+ <contour>
+ <pt x="21" y="0" on="1"/>
+ <pt x="583" y="1480" on="1"/>
+ <pt x="791" y="1480" on="1"/>
+ <pt x="1344" y="0" on="1"/>
+ <pt x="1118" y="0" on="1"/>
+ <pt x="964" y="410" on="1"/>
+ <pt x="370" y="410" on="1"/>
+ <pt x="216" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="430" y="566" on="1"/>
+ <pt x="906" y="566" on="1"/>
+ <pt x="669" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="366" y="1604" on="1"/>
+ <pt x="366" y="1752" on="1"/>
+ <pt x="1008" y="1752" on="1"/>
+ <pt x="1008" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 64 values pushed */
+ 10 1 8 2 0 0 14 11 7 1 12 9 8 15 1 5 2 4 48 196 13 12 1 6 5
+ 1 7 4 3 0 3 3 0 2 1 0 14 10 9 8 6 5 2 1 7 13 11 3 4 3
+ 2 13 13 7 0 11 14 13 1 12 11 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aogonek" xMin="19" yMin="-370" xMax="1342" yMax="1480">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="1223" y="0" on="1"/>
+ <pt x="1095" y="-81" on="0"/>
+ <pt x="1095" y="-179" on="1"/>
+ <pt x="1095" y="-275" on="0"/>
+ <pt x="1210" y="-275" on="1"/>
+ <pt x="1263" y="-275" on="0"/>
+ <pt x="1300" y="-260" on="1"/>
+ <pt x="1300" y="-341" on="1"/>
+ <pt x="1238" y="-370" on="0"/>
+ <pt x="1161" y="-370" on="1"/>
+ <pt x="958" y="-370" on="0"/>
+ <pt x="958" y="-212" on="1"/>
+ <pt x="958" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 16 21 21 48 196 10 1 8 2 19 18 21 0 0 0 9 8 15 1 5 1 4 48
+ 196 6 5 1 12 11 7 4 3 0 5 2 0 2 1 0 14 0 0 14 42 23 48 196 23
+ 19 18 12 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Aring" xMin="19" yMin="0" xMax="1342" yMax="1935">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="685" y="1935" on="1"/>
+ <pt x="779" y="1935" on="0"/>
+ <pt x="845" y="1869" on="1"/>
+ <pt x="912" y="1803" on="0"/>
+ <pt x="912" y="1709" on="1"/>
+ <pt x="912" y="1614" on="0"/>
+ <pt x="845" y="1547" on="1"/>
+ <pt x="778" y="1481" on="0"/>
+ <pt x="683" y="1481" on="1"/>
+ <pt x="600" y="1481" on="0"/>
+ <pt x="538" y="1535" on="1"/>
+ <pt x="458" y="1604" on="0"/>
+ <pt x="458" y="1708" on="1"/>
+ <pt x="458" y="1802" on="0"/>
+ <pt x="524" y="1868" on="1"/>
+ <pt x="591" y="1935" on="0"/>
+ </contour>
+ <contour>
+ <pt x="685" y="1848" on="1"/>
+ <pt x="626" y="1848" on="0"/>
+ <pt x="585" y="1808" on="1"/>
+ <pt x="544" y="1767" on="0"/>
+ <pt x="544" y="1708" on="1"/>
+ <pt x="544" y="1650" on="0"/>
+ <pt x="585" y="1609" on="1"/>
+ <pt x="627" y="1567" on="0"/>
+ <pt x="683" y="1567" on="1"/>
+ <pt x="737" y="1567" on="0"/>
+ <pt x="776" y="1600" on="1"/>
+ <pt x="826" y="1643" on="0"/>
+ <pt x="826" y="1709" on="1"/>
+ <pt x="826" y="1767" on="0"/>
+ <pt x="784" y="1808" on="1"/>
+ <pt x="743" y="1848" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 35 44 19 27 44 11 48 196 19 0 10 1 8 2 11 1 0 0 9 8 15 1 5
+ 1 4 48 196 6 5 1 7 4 3 0 3 2 0 2 1 0 14 0 0 39 32 15 31 32
+ 23 48 196 23 15 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Atilde" xMin="19" yMin="0" xMax="1342" yMax="1838">
+ <contour>
+ <pt x="19" y="0" on="1"/>
+ <pt x="581" y="1480" on="1"/>
+ <pt x="789" y="1480" on="1"/>
+ <pt x="1342" y="0" on="1"/>
+ <pt x="1116" y="0" on="1"/>
+ <pt x="962" y="410" on="1"/>
+ <pt x="368" y="410" on="1"/>
+ <pt x="214" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="428" y="566" on="1"/>
+ <pt x="904" y="566" on="1"/>
+ <pt x="667" y="1200" on="1"/>
+ </contour>
+ <contour>
+ <pt x="352" y="1604" on="1"/>
+ <pt x="359" y="1697" on="0"/>
+ <pt x="384" y="1748" on="1"/>
+ <pt x="430" y="1838" on="0"/>
+ <pt x="539" y="1838" on="1"/>
+ <pt x="611" y="1838" on="0"/>
+ <pt x="672" y="1800" on="1"/>
+ <pt x="732" y="1763" on="1"/>
+ <pt x="789" y="1728" on="0"/>
+ <pt x="819" y="1728" on="1"/>
+ <pt x="884" y="1728" on="0"/>
+ <pt x="895" y="1838" on="1"/>
+ <pt x="1018" y="1838" on="1"/>
+ <pt x="1011" y="1744" on="0"/>
+ <pt x="986" y="1694" on="1"/>
+ <pt x="941" y="1604" on="0"/>
+ <pt x="833" y="1604" on="1"/>
+ <pt x="761" y="1604" on="0"/>
+ <pt x="698" y="1643" on="1"/>
+ <pt x="638" y="1680" on="1"/>
+ <pt x="583" y="1714" on="0"/>
+ <pt x="551" y="1714" on="1"/>
+ <pt x="486" y="1714" on="0"/>
+ <pt x="475" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 0 0 32 6 15 20 6 27 48 196 10 1 8 2 34 23 22 11 4 13 27 15 1 0 0
+ 9 8 15 1 5 1 4 48 196 6 5 1 7 4 3 0 3 2 0 2 1 0 14 34 23
+ 22 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="B" xMin="165" yMin="0" xMax="1231" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="639" y="1480" on="1"/>
+ <pt x="931" y="1480" on="0"/>
+ <pt x="1051" y="1405" on="1"/>
+ <pt x="1172" y="1329" on="0"/>
+ <pt x="1172" y="1149" on="1"/>
+ <pt x="1172" y="983" on="0"/>
+ <pt x="1053" y="880" on="1"/>
+ <pt x="981" y="818" on="0"/>
+ <pt x="844" y="771" on="1"/>
+ <pt x="1018" y="719" on="0"/>
+ <pt x="1106" y="644" on="1"/>
+ <pt x="1231" y="538" on="0"/>
+ <pt x="1231" y="369" on="1"/>
+ <pt x="1231" y="212" on="0"/>
+ <pt x="1129" y="108" on="1"/>
+ <pt x="1057" y="34" on="0"/>
+ <pt x="940" y="15" on="1"/>
+ <pt x="847" y="0" on="0"/>
+ <pt x="691" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="157" on="1"/>
+ <pt x="530" y="157" on="1"/>
+ <pt x="824" y="157" on="0"/>
+ <pt x="917" y="201" on="1"/>
+ <pt x="1009" y="244" on="0"/>
+ <pt x="1009" y="383" on="1"/>
+ <pt x="1009" y="536" on="0"/>
+ <pt x="890" y="616" on="1"/>
+ <pt x="771" y="697" on="0"/>
+ <pt x="546" y="697" on="1"/>
+ <pt x="375" y="697" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="830" on="1"/>
+ <pt x="554" y="830" on="1"/>
+ <pt x="956" y="830" on="0"/>
+ <pt x="956" y="1113" on="1"/>
+ <pt x="956" y="1256" on="0"/>
+ <pt x="841" y="1294" on="1"/>
+ <pt x="753" y="1323" on="0"/>
+ <pt x="569" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 10 32 30 2 0 0 40 39 15 1 1 31 30 31 1 32 22 21 15 1 0 3 4 48 196
+ 33 32 1 20 0 1 2 0 2 1 0 14 0 0 35 9 6 26 26 14 48 196 39 33 30
+ 22 20 10 2 7 13 14 6 21 0 0 40 32 31 21 33 3 0 1 4 48 196 1 0 1
+ 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="C" xMin="116" yMin="-37" xMax="1352" yMax="1517">
+ <contour>
+ <pt x="1352" y="76" on="1"/>
+ <pt x="1123" y="-37" on="0"/>
+ <pt x="862" y="-37" on="1"/>
+ <pt x="497" y="-37" on="0"/>
+ <pt x="307" y="161" on="1"/>
+ <pt x="116" y="359" on="0"/>
+ <pt x="116" y="738" on="1"/>
+ <pt x="116" y="1116" on="0"/>
+ <pt x="310" y="1317" on="1"/>
+ <pt x="504" y="1517" on="0"/>
+ <pt x="871" y="1517" on="1"/>
+ <pt x="1076" y="1517" on="0"/>
+ <pt x="1350" y="1452" on="1"/>
+ <pt x="1350" y="1255" on="1"/>
+ <pt x="1039" y="1360" on="0"/>
+ <pt x="860" y="1360" on="1"/>
+ <pt x="609" y="1360" on="0"/>
+ <pt x="475" y="1200" on="1"/>
+ <pt x="341" y="1041" on="0"/>
+ <pt x="341" y="740" on="1"/>
+ <pt x="341" y="446" on="0"/>
+ <pt x="484" y="287" on="1"/>
+ <pt x="627" y="127" on="0"/>
+ <pt x="886" y="127" on="1"/>
+ <pt x="1103" y="127" on="0"/>
+ <pt x="1352" y="256" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 23 29 2 15 29 10 48 196 10 0 2 2 1 1 25 13 12 0 4 0 2 3 0
+ 0 14 0 0 19 26 6 48 196 6 12 25 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Cacute" xMin="116" yMin="-37" xMax="1352" yMax="1925">
+ <contour>
+ <pt x="1352" y="76" on="1"/>
+ <pt x="1123" y="-37" on="0"/>
+ <pt x="862" y="-37" on="1"/>
+ <pt x="497" y="-37" on="0"/>
+ <pt x="307" y="161" on="1"/>
+ <pt x="116" y="359" on="0"/>
+ <pt x="116" y="738" on="1"/>
+ <pt x="116" y="1116" on="0"/>
+ <pt x="310" y="1317" on="1"/>
+ <pt x="504" y="1517" on="0"/>
+ <pt x="871" y="1517" on="1"/>
+ <pt x="1076" y="1517" on="0"/>
+ <pt x="1350" y="1452" on="1"/>
+ <pt x="1350" y="1255" on="1"/>
+ <pt x="1039" y="1360" on="0"/>
+ <pt x="860" y="1360" on="1"/>
+ <pt x="609" y="1360" on="0"/>
+ <pt x="475" y="1200" on="1"/>
+ <pt x="341" y="1041" on="0"/>
+ <pt x="341" y="740" on="1"/>
+ <pt x="341" y="446" on="0"/>
+ <pt x="484" y="287" on="1"/>
+ <pt x="627" y="127" on="0"/>
+ <pt x="886" y="127" on="1"/>
+ <pt x="1103" y="127" on="0"/>
+ <pt x="1352" y="256" on="1"/>
+ </contour>
+ <contour>
+ <pt x="705" y="1604" on="1"/>
+ <pt x="946" y="1925" on="1"/>
+ <pt x="1174" y="1925" on="1"/>
+ <pt x="853" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 0 23 29 2 15 29 10 48 196 10 0 2 2 1 1 25 13 12 0 4 0 2 3 0
+ 0 28 27 1 29 26 1 2 0 14 0 0 19 26 6 48 196 29 28 27 26 4 13 6 12
+ 25 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccaron" xMin="116" yMin="-37" xMax="1352" yMax="1925">
+ <contour>
+ <pt x="1352" y="76" on="1"/>
+ <pt x="1123" y="-37" on="0"/>
+ <pt x="862" y="-37" on="1"/>
+ <pt x="497" y="-37" on="0"/>
+ <pt x="307" y="161" on="1"/>
+ <pt x="116" y="359" on="0"/>
+ <pt x="116" y="738" on="1"/>
+ <pt x="116" y="1116" on="0"/>
+ <pt x="310" y="1317" on="1"/>
+ <pt x="504" y="1517" on="0"/>
+ <pt x="871" y="1517" on="1"/>
+ <pt x="1076" y="1517" on="0"/>
+ <pt x="1350" y="1452" on="1"/>
+ <pt x="1350" y="1255" on="1"/>
+ <pt x="1039" y="1360" on="0"/>
+ <pt x="860" y="1360" on="1"/>
+ <pt x="609" y="1360" on="0"/>
+ <pt x="475" y="1200" on="1"/>
+ <pt x="341" y="1041" on="0"/>
+ <pt x="341" y="740" on="1"/>
+ <pt x="341" y="446" on="0"/>
+ <pt x="484" y="287" on="1"/>
+ <pt x="627" y="127" on="0"/>
+ <pt x="886" y="127" on="1"/>
+ <pt x="1103" y="127" on="0"/>
+ <pt x="1352" y="256" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1203" y="1925" on="1"/>
+ <pt x="962" y="1604" on="1"/>
+ <pt x="744" y="1604" on="1"/>
+ <pt x="503" y="1925" on="1"/>
+ <pt x="651" y="1925" on="1"/>
+ <pt x="852" y="1723" on="1"/>
+ <pt x="854" y="1723" on="1"/>
+ <pt x="1055" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 23 29 2 15 29 10 48 196 10 0 2 2 32 31 2 26 27 3 1 1 25 13 12
+ 0 4 0 2 3 0 0 33 30 29 26 3 28 27 1 2 0 14 0 0 19 26 6 48 196
+ 33 32 31 30 29 28 27 26 8 13 6 12 25 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccedilla" xMin="116" yMin="-432" xMax="1352" yMax="1517">
+ <contour>
+ <pt x="1352" y="76" on="1"/>
+ <pt x="1123" y="-37" on="0"/>
+ <pt x="862" y="-37" on="1"/>
+ <pt x="497" y="-37" on="0"/>
+ <pt x="307" y="161" on="1"/>
+ <pt x="116" y="359" on="0"/>
+ <pt x="116" y="738" on="1"/>
+ <pt x="116" y="1116" on="0"/>
+ <pt x="310" y="1317" on="1"/>
+ <pt x="504" y="1517" on="0"/>
+ <pt x="871" y="1517" on="1"/>
+ <pt x="1076" y="1517" on="0"/>
+ <pt x="1350" y="1452" on="1"/>
+ <pt x="1350" y="1255" on="1"/>
+ <pt x="1039" y="1360" on="0"/>
+ <pt x="860" y="1360" on="1"/>
+ <pt x="609" y="1360" on="0"/>
+ <pt x="475" y="1200" on="1"/>
+ <pt x="341" y="1041" on="0"/>
+ <pt x="341" y="740" on="1"/>
+ <pt x="341" y="446" on="0"/>
+ <pt x="484" y="287" on="1"/>
+ <pt x="627" y="127" on="0"/>
+ <pt x="886" y="127" on="1"/>
+ <pt x="1103" y="127" on="0"/>
+ <pt x="1352" y="256" on="1"/>
+ </contour>
+ <contour>
+ <pt x="767" y="0" on="1"/>
+ <pt x="864" y="0" on="1"/>
+ <pt x="804" y="-109" on="1"/>
+ <pt x="876" y="-111" on="0"/>
+ <pt x="928" y="-148" on="1"/>
+ <pt x="998" y="-197" on="0"/>
+ <pt x="998" y="-269" on="1"/>
+ <pt x="998" y="-337" on="0"/>
+ <pt x="939" y="-384" on="1"/>
+ <pt x="880" y="-432" on="0"/>
+ <pt x="795" y="-432" on="1"/>
+ <pt x="728" y="-432" on="0"/>
+ <pt x="651" y="-411" on="1"/>
+ <pt x="651" y="-330" on="1"/>
+ <pt x="701" y="-345" on="0"/>
+ <pt x="755" y="-345" on="1"/>
+ <pt x="859" y="-345" on="0"/>
+ <pt x="859" y="-271" on="1"/>
+ <pt x="859" y="-178" on="0"/>
+ <pt x="672" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 41 44 36 23 29 2 15 29 10 48 196 10 0 2 2 1 1 25 13 12 0 4 0
+ 2 3 0 0 1 45 39 38 28 27 26 6 13 36 2 0 14 0 0 43 42 32 19 26 6
+ 48 196 45 39 38 28 27 26 6 13 32 6 12 25 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ccircumflex" xMin="116" yMin="-37" xMax="1352" yMax="1925">
+ <contour>
+ <pt x="1352" y="76" on="1"/>
+ <pt x="1123" y="-37" on="0"/>
+ <pt x="862" y="-37" on="1"/>
+ <pt x="497" y="-37" on="0"/>
+ <pt x="307" y="161" on="1"/>
+ <pt x="116" y="359" on="0"/>
+ <pt x="116" y="738" on="1"/>
+ <pt x="116" y="1116" on="0"/>
+ <pt x="310" y="1317" on="1"/>
+ <pt x="504" y="1517" on="0"/>
+ <pt x="871" y="1517" on="1"/>
+ <pt x="1076" y="1517" on="0"/>
+ <pt x="1350" y="1452" on="1"/>
+ <pt x="1350" y="1255" on="1"/>
+ <pt x="1039" y="1360" on="0"/>
+ <pt x="860" y="1360" on="1"/>
+ <pt x="609" y="1360" on="0"/>
+ <pt x="475" y="1200" on="1"/>
+ <pt x="341" y="1041" on="0"/>
+ <pt x="341" y="740" on="1"/>
+ <pt x="341" y="446" on="0"/>
+ <pt x="484" y="287" on="1"/>
+ <pt x="627" y="127" on="0"/>
+ <pt x="886" y="127" on="1"/>
+ <pt x="1103" y="127" on="0"/>
+ <pt x="1352" y="256" on="1"/>
+ </contour>
+ <contour>
+ <pt x="503" y="1604" on="1"/>
+ <pt x="744" y="1925" on="1"/>
+ <pt x="962" y="1925" on="1"/>
+ <pt x="1203" y="1604" on="1"/>
+ <pt x="1055" y="1604" on="1"/>
+ <pt x="854" y="1806" on="1"/>
+ <pt x="852" y="1806" on="1"/>
+ <pt x="651" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 23 29 2 15 29 10 48 196 10 0 2 2 32 31 2 27 26 3 1 1 25 13 12
+ 0 4 0 2 3 0 0 28 27 1 33 30 29 26 3 2 0 14 0 0 19 26 6 48 196
+ 33 32 31 30 29 28 27 26 8 13 6 12 25 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Cdotaccent" xMin="116" yMin="-37" xMax="1352" yMax="1801">
+ <contour>
+ <pt x="1352" y="76" on="1"/>
+ <pt x="1123" y="-37" on="0"/>
+ <pt x="862" y="-37" on="1"/>
+ <pt x="497" y="-37" on="0"/>
+ <pt x="307" y="161" on="1"/>
+ <pt x="116" y="359" on="0"/>
+ <pt x="116" y="738" on="1"/>
+ <pt x="116" y="1116" on="0"/>
+ <pt x="310" y="1317" on="1"/>
+ <pt x="504" y="1517" on="0"/>
+ <pt x="871" y="1517" on="1"/>
+ <pt x="1076" y="1517" on="0"/>
+ <pt x="1350" y="1452" on="1"/>
+ <pt x="1350" y="1255" on="1"/>
+ <pt x="1039" y="1360" on="0"/>
+ <pt x="860" y="1360" on="1"/>
+ <pt x="609" y="1360" on="0"/>
+ <pt x="475" y="1200" on="1"/>
+ <pt x="341" y="1041" on="0"/>
+ <pt x="341" y="740" on="1"/>
+ <pt x="341" y="446" on="0"/>
+ <pt x="484" y="287" on="1"/>
+ <pt x="627" y="127" on="0"/>
+ <pt x="886" y="127" on="1"/>
+ <pt x="1103" y="127" on="0"/>
+ <pt x="1352" y="256" on="1"/>
+ </contour>
+ <contour>
+ <pt x="754" y="1604" on="1"/>
+ <pt x="754" y="1801" on="1"/>
+ <pt x="951" y="1801" on="1"/>
+ <pt x="951" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 0 0 23 29 2 15 29 10 48 196 10 0 2 2 1 1 25 13 12 0 4 0 2 3 0
+ 0 0 0 29 26 5 1 27 1 4 48 196 28 27 1 0 14 0 0 19 26 6 48 196 6
+ 26 0 0 27 26 4 1 28 1 4 48 196 29 28 1 25 0 1 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="D" xMin="165" yMin="0" xMax="1386" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="639" y="1480" on="1"/>
+ <pt x="1386" y="1480" on="0"/>
+ <pt x="1386" y="774" on="1"/>
+ <pt x="1386" y="406" on="0"/>
+ <pt x="1191" y="203" on="1"/>
+ <pt x="997" y="0" on="0"/>
+ <pt x="642" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="157" on="1"/>
+ <pt x="627" y="157" on="1"/>
+ <pt x="1161" y="157" on="0"/>
+ <pt x="1161" y="750" on="1"/>
+ <pt x="1161" y="1099" on="0"/>
+ <pt x="950" y="1242" on="1"/>
+ <pt x="888" y="1284" on="0"/>
+ <pt x="803" y="1302" on="1"/>
+ <pt x="700" y="1323" on="0"/>
+ <pt x="530" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 0 0 19 18 15 1 1 10 9 15 1 0 2 4 48 196 8 0 1 0 2 1 0 14 0
+ 0 12 26 4 48 196 18 10 8 2 4 13 4 9 0 0 19 9 33 1 0 1 4 48 196
+ 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Dcaron" xMin="165" yMin="0" xMax="1386" yMax="1925">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="639" y="1480" on="1"/>
+ <pt x="1386" y="1480" on="0"/>
+ <pt x="1386" y="774" on="1"/>
+ <pt x="1386" y="406" on="0"/>
+ <pt x="1191" y="203" on="1"/>
+ <pt x="997" y="0" on="0"/>
+ <pt x="642" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="157" on="1"/>
+ <pt x="627" y="157" on="1"/>
+ <pt x="1161" y="157" on="0"/>
+ <pt x="1161" y="750" on="1"/>
+ <pt x="1161" y="1099" on="0"/>
+ <pt x="950" y="1242" on="1"/>
+ <pt x="888" y="1284" on="0"/>
+ <pt x="803" y="1302" on="1"/>
+ <pt x="700" y="1323" on="0"/>
+ <pt x="530" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1032" y="1925" on="1"/>
+ <pt x="791" y="1604" on="1"/>
+ <pt x="573" y="1604" on="1"/>
+ <pt x="332" y="1925" on="1"/>
+ <pt x="480" y="1925" on="1"/>
+ <pt x="681" y="1723" on="1"/>
+ <pt x="683" y="1723" on="1"/>
+ <pt x="884" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 26 25 2 20 21 3 0 0 19 18 15 1 1 10 9 15 1 0 2 4 48 196 27 24 23
+ 20 3 22 21 1 8 0 1 3 0 2 1 0 14 0 0 12 26 4 48 196 23 9 0 2
+ 27 26 25 24 22 21 20 18 10 8 2 11 13 4 9 0 0 19 9 33 1 0 1 4 48
+ 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Dcroat" xMin="5" yMin="0" xMax="1386" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="679" on="1"/>
+ <pt x="5" y="679" on="1"/>
+ <pt x="5" y="836" on="1"/>
+ <pt x="165" y="836" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="639" y="1480" on="1"/>
+ <pt x="1386" y="1480" on="0"/>
+ <pt x="1386" y="774" on="1"/>
+ <pt x="1386" y="406" on="0"/>
+ <pt x="1191" y="203" on="1"/>
+ <pt x="996" y="0" on="0"/>
+ <pt x="642" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="157" on="1"/>
+ <pt x="627" y="157" on="1"/>
+ <pt x="1161" y="157" on="0"/>
+ <pt x="1161" y="750" on="1"/>
+ <pt x="1161" y="1099" on="0"/>
+ <pt x="950" y="1242" on="1"/>
+ <pt x="888" y="1284" on="0"/>
+ <pt x="803" y="1302" on="1"/>
+ <pt x="700" y="1323" on="0"/>
+ <pt x="530" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ <pt x="375" y="836" on="1"/>
+ <pt x="708" y="836" on="1"/>
+ <pt x="708" y="679" on="1"/>
+ <pt x="375" y="679" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 23 22 15 1 5 27 26 2 1 15 3 3 14 13 15 1 0 3 4 48 196 25 24
+ 4 3 3 12 0 1 2 0 6 5 0 14 0 0 16 26 8 48 196 22 14 12 6 4 25
+ 13 3 8 25 0 0 27 24 23 13 33 3 0 1 4 48 196 26 25 1 5 4 1 0 3
+ 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="E" xMin="191" yMin="0" xMax="1308" yMax="1480">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 0 0 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 3 4 48 196 6 5 1 11
+ 0 1 2 0 2 1 0 14 0 0 9 8 5 4 33 3 0 1 4 48 196 11 10 1 3
+ 2 1 7 6 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eacute" xMin="191" yMin="0" xMax="1308" yMax="1925">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="598" y="1604" on="1"/>
+ <pt x="839" y="1925" on="1"/>
+ <pt x="1067" y="1925" on="1"/>
+ <pt x="746" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 0 0 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 3 4 48 196 14 13 1 15
+ 12 1 6 5 1 11 0 1 4 0 2 1 0 14 15 14 13 12 4 6 4 3 0 0 9
+ 8 5 4 33 3 0 1 4 48 196 11 10 1 3 2 1 7 6 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ebreve" xMin="191" yMin="0" xMax="1308" yMax="1925">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="404" y="1925" on="1"/>
+ <pt x="527" y="1925" on="1"/>
+ <pt x="548" y="1831" on="0"/>
+ <pt x="602" y="1791" on="1"/>
+ <pt x="654" y="1752" on="0"/>
+ <pt x="737" y="1752" on="1"/>
+ <pt x="831" y="1752" on="0"/>
+ <pt x="885" y="1801" on="1"/>
+ <pt x="928" y="1841" on="0"/>
+ <pt x="947" y="1925" on="1"/>
+ <pt x="1070" y="1925" on="1"/>
+ <pt x="1054" y="1791" on="0"/>
+ <pt x="981" y="1710" on="1"/>
+ <pt x="887" y="1604" on="0"/>
+ <pt x="737" y="1604" on="1"/>
+ <pt x="580" y="1604" on="0"/>
+ <pt x="485" y="1719" on="1"/>
+ <pt x="420" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 17 40 26 48 196 22 21 13 12 4 13 26 1 0 0 4 3 15 1 1 8 7 15
+ 1 5 10 9 15 1 0 3 4 48 196 6 5 1 11 0 1 2 0 2 1 0 14 22 21
+ 13 12 4 6 4 3 0 0 9 8 5 4 33 3 0 1 4 48 196 11 10 1 3 2 1
+ 7 6 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ecaron" xMin="191" yMin="0" xMax="1308" yMax="1925">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1082" y="1925" on="1"/>
+ <pt x="841" y="1604" on="1"/>
+ <pt x="623" y="1604" on="1"/>
+ <pt x="382" y="1925" on="1"/>
+ <pt x="530" y="1925" on="1"/>
+ <pt x="731" y="1723" on="1"/>
+ <pt x="733" y="1723" on="1"/>
+ <pt x="934" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 18 17 2 12 13 3 0 0 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 3 4
+ 48 196 19 16 15 12 3 14 13 1 6 5 1 11 0 1 4 0 2 1 0 14 19 18 17
+ 16 14 13 12 7 6 4 3 15 4 0 2 0 0 9 8 5 4 33 3 0 1 4 48 196
+ 11 10 1 3 2 1 7 6 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ecircumflex" xMin="191" yMin="0" xMax="1308" yMax="1925">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="399" y="1604" on="1"/>
+ <pt x="640" y="1925" on="1"/>
+ <pt x="858" y="1925" on="1"/>
+ <pt x="1099" y="1604" on="1"/>
+ <pt x="951" y="1604" on="1"/>
+ <pt x="750" y="1806" on="1"/>
+ <pt x="748" y="1806" on="1"/>
+ <pt x="547" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 89 values pushed */
+ 18 17 2 13 12 3 0 0 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 3 4
+ 48 196 14 13 1 19 16 15 12 3 6 5 1 11 0 1 4 0 2 1 0 14 19 18 17
+ 16 15 14 13 7 6 4 3 12 4 0 2 0 0 9 8 5 4 33 3 0 1 4 48 196
+ 11 10 1 3 2 1 7 6 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Edieresis" xMin="191" yMin="0" xMax="1308" yMax="1777">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="450" y="1604" on="1"/>
+ <pt x="450" y="1777" on="1"/>
+ <pt x="623" y="1777" on="1"/>
+ <pt x="623" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="845" y="1604" on="1"/>
+ <pt x="845" y="1777" on="1"/>
+ <pt x="1018" y="1777" on="1"/>
+ <pt x="1018" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 88 values pushed */
+ 0 0 19 16 15 12 13 3 13 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 4
+ 4 48 196 18 17 14 13 3 6 5 1 11 0 1 3 0 2 1 0 14 0 0 17 16 13
+ 1 18 15 14 13 1 12 9 8 5 4 33 3 0 3 4 48 196 19 18 1 13 12 1 11
+ 10 1 3 2 1 7 6 1 1 0 1 6 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Edotaccent" xMin="191" yMin="0" xMax="1308" yMax="1801">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="635" y="1604" on="1"/>
+ <pt x="635" y="1801" on="1"/>
+ <pt x="832" y="1801" on="1"/>
+ <pt x="832" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 0 0 15 12 5 1 13 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 4 4 48
+ 196 14 13 1 6 5 1 11 0 1 3 0 2 1 0 14 0 0 15 14 4 1 12 9 8
+ 5 4 33 3 0 2 4 48 196 13 12 1 11 10 1 3 2 1 7 6 1 1 0 1 5
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Egrave" xMin="191" yMin="0" xMax="1308" yMax="1925">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="894" y="1604" on="1"/>
+ <pt x="746" y="1604" on="1"/>
+ <pt x="425" y="1925" on="1"/>
+ <pt x="653" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 74 values pushed */
+ 0 0 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 3 4 48 196 15 14 1 13
+ 12 1 6 5 1 11 0 1 4 0 2 1 0 14 15 14 13 12 4 6 4 3 0 0 9
+ 8 5 4 33 3 0 1 4 48 196 11 10 1 3 2 1 7 6 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Emacron" xMin="191" yMin="0" xMax="1308" yMax="1752">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="401" y="1604" on="1"/>
+ <pt x="401" y="1752" on="1"/>
+ <pt x="1043" y="1752" on="1"/>
+ <pt x="1043" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 15 12 7 1 13 4 3 15 1 1 8 7 15 1 5 10 9 15 1 0 4 4 48
+ 196 14 13 1 6 5 1 11 0 1 3 0 2 1 0 14 0 0 13 12 9 8 5 4 33
+ 5 0 1 4 48 196 15 14 1 13 12 9 8 5 4 5 11 10 1 3 2 1 7 6 1
+ 1 0 1 6 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eng" xMin="165" yMin="-420" xMax="1313" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="370" y="1480" on="1"/>
+ <pt x="1133" y="337" on="1"/>
+ <pt x="1133" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="-92" on="1"/>
+ <pt x="1313" y="-420" on="0"/>
+ <pt x="995" y="-420" on="1"/>
+ <pt x="921" y="-420" on="0"/>
+ <pt x="844" y="-399" on="1"/>
+ <pt x="844" y="-245" on="1"/>
+ <pt x="910" y="-272" on="0"/>
+ <pt x="985" y="-272" on="1"/>
+ <pt x="1133" y="-272" on="0"/>
+ <pt x="1133" y="-55" on="1"/>
+ <pt x="1133" y="-40" on="1"/>
+ <pt x="345" y="1143" on="1"/>
+ <pt x="345" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 13 40 8 48 196 17 3 2 1 0 3 16 15 11 10 6 5 13 8 0 18 0 1
+ 0 5 4 2 1 0 3 14 2 10 17 2 0 0 16 15 4 3 24 3 5 18 17 24 1
+ 0 2 4 48 196 6 5 1 11 10 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eogonek" xMin="191" yMin="-370" xMax="1308" yMax="1480">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1264" y="1480" on="1"/>
+ <pt x="1264" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="848" on="1"/>
+ <pt x="1165" y="848" on="1"/>
+ <pt x="1165" y="693" on="1"/>
+ <pt x="401" y="693" on="1"/>
+ <pt x="401" y="157" on="1"/>
+ <pt x="1308" y="157" on="1"/>
+ <pt x="1308" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1075" y="0" on="1"/>
+ <pt x="1182" y="0" on="1"/>
+ <pt x="1054" y="-81" on="0"/>
+ <pt x="1054" y="-179" on="1"/>
+ <pt x="1054" y="-275" on="0"/>
+ <pt x="1169" y="-275" on="1"/>
+ <pt x="1222" y="-275" on="0"/>
+ <pt x="1259" y="-260" on="1"/>
+ <pt x="1259" y="-341" on="1"/>
+ <pt x="1197" y="-370" on="0"/>
+ <pt x="1120" y="-370" on="1"/>
+ <pt x="917" y="-370" on="0"/>
+ <pt x="917" y="-212" on="1"/>
+ <pt x="917" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 94 values pushed */
+ 0 0 17 21 22 48 196 20 19 22 0 0 0 4 3 15 1 1 8 7 15 1 5 10 9
+ 15 1 0 3 4 48 196 6 5 1 13 12 11 0 3 2 0 2 1 0 14 0 0 15 42
+ 24 48 196 20 19 13 3 2 6 3 24 24 12 2 6 4 3 0 0 9 8 5 4 33 3
+ 0 1 4 48 196 11 10 1 3 2 1 7 6 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Eth" xMin="5" yMin="0" xMax="1386" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="679" on="1"/>
+ <pt x="5" y="679" on="1"/>
+ <pt x="5" y="836" on="1"/>
+ <pt x="165" y="836" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="639" y="1480" on="1"/>
+ <pt x="1386" y="1480" on="0"/>
+ <pt x="1386" y="774" on="1"/>
+ <pt x="1386" y="406" on="0"/>
+ <pt x="1191" y="203" on="1"/>
+ <pt x="996" y="0" on="0"/>
+ <pt x="642" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="157" on="1"/>
+ <pt x="627" y="157" on="1"/>
+ <pt x="1161" y="157" on="0"/>
+ <pt x="1161" y="750" on="1"/>
+ <pt x="1161" y="1099" on="0"/>
+ <pt x="950" y="1242" on="1"/>
+ <pt x="888" y="1284" on="0"/>
+ <pt x="803" y="1302" on="1"/>
+ <pt x="700" y="1323" on="0"/>
+ <pt x="530" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ <pt x="375" y="836" on="1"/>
+ <pt x="708" y="836" on="1"/>
+ <pt x="708" y="679" on="1"/>
+ <pt x="375" y="679" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 23 22 15 1 5 27 26 2 1 15 3 3 14 13 15 1 0 3 4 48 196 25 24
+ 4 3 3 12 0 1 2 0 6 5 0 14 0 0 16 26 8 48 196 22 14 12 6 4 25
+ 13 3 8 25 0 0 27 24 23 13 33 3 0 1 4 48 196 26 25 1 5 4 1 0 3
+ 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Euro" xMin="0" yMin="-37" xMax="1080" yMax="1515">
+ <contour>
+ <pt x="377" y="537" on="1"/>
+ <pt x="416" y="376" on="0"/>
+ <pt x="475" y="288" on="1"/>
+ <pt x="582" y="127" on="0"/>
+ <pt x="773" y="127" on="1"/>
+ <pt x="898" y="127" on="0"/>
+ <pt x="1080" y="199" on="1"/>
+ <pt x="1080" y="27" on="1"/>
+ <pt x="884" y="-37" on="0"/>
+ <pt x="748" y="-37" on="1"/>
+ <pt x="516" y="-37" on="0"/>
+ <pt x="372" y="100" on="1"/>
+ <pt x="270" y="197" on="0"/>
+ <pt x="219" y="357" on="1"/>
+ <pt x="200" y="415" on="0"/>
+ <pt x="177" y="537" on="1"/>
+ <pt x="0" y="537" on="1"/>
+ <pt x="51" y="660" on="1"/>
+ <pt x="162" y="660" on="1"/>
+ <pt x="160" y="735" on="1"/>
+ <pt x="160" y="739" on="0"/>
+ <pt x="161" y="758" on="1"/>
+ <pt x="162" y="801" on="0"/>
+ <pt x="165" y="857" on="1"/>
+ <pt x="0" y="857" on="1"/>
+ <pt x="51" y="981" on="1"/>
+ <pt x="183" y="981" on="1"/>
+ <pt x="223" y="1147" on="0"/>
+ <pt x="271" y="1232" on="1"/>
+ <pt x="429" y="1515" on="0"/>
+ <pt x="782" y="1515" on="1"/>
+ <pt x="908" y="1515" on="0"/>
+ <pt x="1079" y="1471" on="1"/>
+ <pt x="1079" y="1289" on="1"/>
+ <pt x="911" y="1360" on="0"/>
+ <pt x="784" y="1360" on="1"/>
+ <pt x="607" y="1360" on="0"/>
+ <pt x="502" y="1232" on="1"/>
+ <pt x="442" y="1158" on="0"/>
+ <pt x="410" y="1066" on="1"/>
+ <pt x="397" y="1030" on="0"/>
+ <pt x="383" y="981" on="1"/>
+ <pt x="950" y="981" on="1"/>
+ <pt x="899" y="857" on="1"/>
+ <pt x="362" y="857" on="1"/>
+ <pt x="358" y="783" on="0"/>
+ <pt x="357" y="736" on="1"/>
+ <pt x="359" y="660" on="1"/>
+ <pt x="818" y="660" on="1"/>
+ <pt x="767" y="537" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 0 0 35 35 30 4 45 9 48 196 30 0 9 2 1 33 32 2 0 25 3 0 1 7 6
+ 2 0 2 3 0 0 0 44 43 24 23 6 3 25 49 16 15 0 6 3 17 2 4 48 196
+ 42 41 26 25 3 48 47 18 17 3 2 0 14 49 48 47 44 43 42 41 26 25 24 23 18
+ 17 16 15 0 16 13 32 7 6 1 33 32 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Euro#1" xMin="0" yMin="-37" xMax="1080" yMax="1515">
+ <contour>
+ <pt x="377" y="537" on="1"/>
+ <pt x="416" y="376" on="0"/>
+ <pt x="475" y="288" on="1"/>
+ <pt x="582" y="127" on="0"/>
+ <pt x="773" y="127" on="1"/>
+ <pt x="898" y="127" on="0"/>
+ <pt x="1080" y="199" on="1"/>
+ <pt x="1080" y="27" on="1"/>
+ <pt x="884" y="-37" on="0"/>
+ <pt x="748" y="-37" on="1"/>
+ <pt x="516" y="-37" on="0"/>
+ <pt x="372" y="100" on="1"/>
+ <pt x="270" y="197" on="0"/>
+ <pt x="219" y="357" on="1"/>
+ <pt x="200" y="415" on="0"/>
+ <pt x="177" y="537" on="1"/>
+ <pt x="0" y="537" on="1"/>
+ <pt x="51" y="660" on="1"/>
+ <pt x="162" y="660" on="1"/>
+ <pt x="160" y="735" on="1"/>
+ <pt x="160" y="739" on="0"/>
+ <pt x="161" y="758" on="1"/>
+ <pt x="162" y="801" on="0"/>
+ <pt x="165" y="857" on="1"/>
+ <pt x="0" y="857" on="1"/>
+ <pt x="51" y="981" on="1"/>
+ <pt x="183" y="981" on="1"/>
+ <pt x="223" y="1147" on="0"/>
+ <pt x="271" y="1232" on="1"/>
+ <pt x="429" y="1515" on="0"/>
+ <pt x="782" y="1515" on="1"/>
+ <pt x="908" y="1515" on="0"/>
+ <pt x="1079" y="1471" on="1"/>
+ <pt x="1079" y="1289" on="1"/>
+ <pt x="911" y="1360" on="0"/>
+ <pt x="784" y="1360" on="1"/>
+ <pt x="607" y="1360" on="0"/>
+ <pt x="502" y="1232" on="1"/>
+ <pt x="442" y="1158" on="0"/>
+ <pt x="410" y="1066" on="1"/>
+ <pt x="397" y="1030" on="0"/>
+ <pt x="383" y="981" on="1"/>
+ <pt x="950" y="981" on="1"/>
+ <pt x="899" y="857" on="1"/>
+ <pt x="362" y="857" on="1"/>
+ <pt x="358" y="783" on="0"/>
+ <pt x="357" y="736" on="1"/>
+ <pt x="359" y="660" on="1"/>
+ <pt x="818" y="660" on="1"/>
+ <pt x="767" y="537" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 0 0 35 35 30 4 45 9 48 196 30 0 9 2 1 33 32 2 0 25 3 0 1 7 6
+ 2 0 2 3 0 0 0 44 43 24 23 6 3 25 49 16 15 0 6 3 17 2 4 48 196
+ 42 41 26 25 3 48 47 18 17 3 2 0 14 49 48 47 44 43 42 41 26 25 24 23 18
+ 17 16 15 0 16 13 32 7 6 1 33 32 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="F" xMin="191" yMin="0" xMax="1196" yMax="1480">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="1196" y="1480" on="1"/>
+ <pt x="1196" y="1323" on="1"/>
+ <pt x="401" y="1323" on="1"/>
+ <pt x="401" y="827" on="1"/>
+ <pt x="1096" y="827" on="1"/>
+ <pt x="1096" y="672" on="1"/>
+ <pt x="401" y="672" on="1"/>
+ <pt x="401" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 0 0 4 3 15 1 1 8 7 15 1 5 2 4 48 196 6 5 1 9 0 1 2 0 2
+ 1 0 14 0 0 9 8 5 4 33 3 0 1 4 48 196 3 2 1 7 6 1 1 0 1
+ 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="G" xMin="93" yMin="-37" xMax="1405" yMax="1517">
+ <contour>
+ <pt x="1405" y="688" on="1"/>
+ <pt x="1405" y="40" on="1"/>
+ <pt x="1131" y="-37" on="0"/>
+ <pt x="871" y="-37" on="1"/>
+ <pt x="93" y="-37" on="0"/>
+ <pt x="93" y="735" on="1"/>
+ <pt x="93" y="1113" on="0"/>
+ <pt x="294" y="1315" on="1"/>
+ <pt x="496" y="1517" on="0"/>
+ <pt x="877" y="1517" on="1"/>
+ <pt x="1123" y="1517" on="0"/>
+ <pt x="1403" y="1450" on="1"/>
+ <pt x="1403" y="1256" on="1"/>
+ <pt x="1082" y="1360" on="0"/>
+ <pt x="868" y="1360" on="1"/>
+ <pt x="318" y="1360" on="0"/>
+ <pt x="318" y="744" on="1"/>
+ <pt x="318" y="440" on="0"/>
+ <pt x="470" y="280" on="1"/>
+ <pt x="621" y="120" on="0"/>
+ <pt x="900" y="120" on="1"/>
+ <pt x="1015" y="120" on="0"/>
+ <pt x="1196" y="157" on="1"/>
+ <pt x="1196" y="534" on="1"/>
+ <pt x="949" y="534" on="1"/>
+ <pt x="949" y="688" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 20 29 3 14 29 9 48 196 9 0 3 2 1 12 11 2 0 0 3 0 1 22 1
+ 2 23 2 3 0 0 0 24 23 15 1 0 1 4 48 196 25 0 1 0 14 0 0 16 26
+ 5 48 196 5 24 0 0 23 22 33 1 0 1 4 48 196 1 0 1 12 11 1 25 24 1
+ 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gbreve" xMin="93" yMin="-37" xMax="1405" yMax="1925">
+ <contour>
+ <pt x="1405" y="688" on="1"/>
+ <pt x="1405" y="40" on="1"/>
+ <pt x="1131" y="-37" on="0"/>
+ <pt x="871" y="-37" on="1"/>
+ <pt x="93" y="-37" on="0"/>
+ <pt x="93" y="735" on="1"/>
+ <pt x="93" y="1113" on="0"/>
+ <pt x="294" y="1315" on="1"/>
+ <pt x="496" y="1517" on="0"/>
+ <pt x="877" y="1517" on="1"/>
+ <pt x="1123" y="1517" on="0"/>
+ <pt x="1403" y="1450" on="1"/>
+ <pt x="1403" y="1256" on="1"/>
+ <pt x="1082" y="1360" on="0"/>
+ <pt x="868" y="1360" on="1"/>
+ <pt x="318" y="1360" on="0"/>
+ <pt x="318" y="744" on="1"/>
+ <pt x="318" y="440" on="0"/>
+ <pt x="470" y="280" on="1"/>
+ <pt x="621" y="120" on="0"/>
+ <pt x="900" y="120" on="1"/>
+ <pt x="1015" y="120" on="0"/>
+ <pt x="1196" y="157" on="1"/>
+ <pt x="1196" y="534" on="1"/>
+ <pt x="949" y="534" on="1"/>
+ <pt x="949" y="688" on="1"/>
+ </contour>
+ <contour>
+ <pt x="534" y="1925" on="1"/>
+ <pt x="657" y="1925" on="1"/>
+ <pt x="678" y="1831" on="0"/>
+ <pt x="732" y="1791" on="1"/>
+ <pt x="784" y="1752" on="0"/>
+ <pt x="867" y="1752" on="1"/>
+ <pt x="961" y="1752" on="0"/>
+ <pt x="1015" y="1801" on="1"/>
+ <pt x="1058" y="1841" on="0"/>
+ <pt x="1077" y="1925" on="1"/>
+ <pt x="1200" y="1925" on="1"/>
+ <pt x="1184" y="1791" on="0"/>
+ <pt x="1111" y="1710" on="1"/>
+ <pt x="1017" y="1604" on="0"/>
+ <pt x="867" y="1604" on="1"/>
+ <pt x="710" y="1604" on="0"/>
+ <pt x="615" y="1719" on="1"/>
+ <pt x="550" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 100 values pushed */
+ 0 0 31 40 40 20 29 3 14 29 9 48 196 9 0 3 2 1 12 11 2 0 0 3 0
+ 1 22 1 2 23 2 3 0 1 36 35 27 26 4 13 40 0 0 0 0 24 23 15 1 0
+ 1 4 48 196 25 0 1 0 14 0 0 16 26 5 48 196 36 11 22 2 35 22 24 2 27
+ 26 5 24 0 0 23 22 33 1 0 1 4 48 196 1 0 1 12 11 1 25 24 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gcircumflex" xMin="93" yMin="-37" xMax="1405" yMax="1925">
+ <contour>
+ <pt x="1405" y="688" on="1"/>
+ <pt x="1405" y="40" on="1"/>
+ <pt x="1131" y="-37" on="0"/>
+ <pt x="871" y="-37" on="1"/>
+ <pt x="93" y="-37" on="0"/>
+ <pt x="93" y="735" on="1"/>
+ <pt x="93" y="1113" on="0"/>
+ <pt x="294" y="1315" on="1"/>
+ <pt x="496" y="1517" on="0"/>
+ <pt x="877" y="1517" on="1"/>
+ <pt x="1123" y="1517" on="0"/>
+ <pt x="1403" y="1450" on="1"/>
+ <pt x="1403" y="1256" on="1"/>
+ <pt x="1082" y="1360" on="0"/>
+ <pt x="868" y="1360" on="1"/>
+ <pt x="318" y="1360" on="0"/>
+ <pt x="318" y="744" on="1"/>
+ <pt x="318" y="440" on="0"/>
+ <pt x="470" y="280" on="1"/>
+ <pt x="621" y="120" on="0"/>
+ <pt x="900" y="120" on="1"/>
+ <pt x="1015" y="120" on="0"/>
+ <pt x="1196" y="157" on="1"/>
+ <pt x="1196" y="534" on="1"/>
+ <pt x="949" y="534" on="1"/>
+ <pt x="949" y="688" on="1"/>
+ </contour>
+ <contour>
+ <pt x="517" y="1604" on="1"/>
+ <pt x="758" y="1925" on="1"/>
+ <pt x="976" y="1925" on="1"/>
+ <pt x="1217" y="1604" on="1"/>
+ <pt x="1069" y="1604" on="1"/>
+ <pt x="868" y="1806" on="1"/>
+ <pt x="866" y="1806" on="1"/>
+ <pt x="665" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 20 29 3 14 29 9 48 196 9 0 3 2 32 31 2 27 26 3 1 12 11 2 0
+ 0 3 0 1 22 1 2 23 2 3 0 0 0 24 23 15 1 0 1 4 48 196 28 27 1
+ 33 30 29 26 3 25 0 1 3 0 14 0 0 16 26 5 48 196 29 11 22 2 30 28 2
+ 22 24 3 33 32 31 27 26 5 13 5 24 0 0 23 22 33 1 0 1 4 48 196 1 0
+ 1 12 11 1 25 24 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gcommaaccent" xMin="93" yMin="-432" xMax="1405" yMax="1517">
+ <contour>
+ <pt x="1405" y="688" on="1"/>
+ <pt x="1405" y="40" on="1"/>
+ <pt x="1128" y="-37" on="0"/>
+ <pt x="871" y="-37" on="1"/>
+ <pt x="93" y="-37" on="0"/>
+ <pt x="93" y="735" on="1"/>
+ <pt x="93" y="1113" on="0"/>
+ <pt x="294" y="1315" on="1"/>
+ <pt x="496" y="1517" on="0"/>
+ <pt x="877" y="1517" on="1"/>
+ <pt x="1123" y="1517" on="0"/>
+ <pt x="1403" y="1450" on="1"/>
+ <pt x="1403" y="1256" on="1"/>
+ <pt x="1082" y="1360" on="0"/>
+ <pt x="868" y="1360" on="1"/>
+ <pt x="318" y="1360" on="0"/>
+ <pt x="318" y="744" on="1"/>
+ <pt x="318" y="440" on="0"/>
+ <pt x="470" y="280" on="1"/>
+ <pt x="621" y="120" on="0"/>
+ <pt x="900" y="120" on="1"/>
+ <pt x="1016" y="120" on="0"/>
+ <pt x="1196" y="157" on="1"/>
+ <pt x="1196" y="534" on="1"/>
+ <pt x="949" y="534" on="1"/>
+ <pt x="949" y="688" on="1"/>
+ </contour>
+ <contour>
+ <pt x="700" y="-421" on="1"/>
+ <pt x="700" y="-336" on="1"/>
+ <pt x="757" y="-345" on="0"/>
+ <pt x="798" y="-345" on="1"/>
+ <pt x="907" y="-345" on="0"/>
+ <pt x="907" y="-278" on="1"/>
+ <pt x="907" y="-204" on="0"/>
+ <pt x="749" y="-188" on="1"/>
+ <pt x="749" y="-111" on="1"/>
+ <pt x="883" y="-114" on="0"/>
+ <pt x="949" y="-143" on="1"/>
+ <pt x="1042" y="-185" on="0"/>
+ <pt x="1042" y="-280" on="1"/>
+ <pt x="1042" y="-432" on="0"/>
+ <pt x="825" y="-432" on="1"/>
+ <pt x="765" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 104 values pushed */
+ 0 0 29 44 40 20 29 3 14 29 9 48 196 9 0 3 2 1 12 11 2 0 0 3 0
+ 1 22 1 2 23 2 3 0 1 34 33 27 26 4 13 40 2 0 0 0 24 23 15 1 0
+ 1 4 48 196 25 0 1 0 14 0 0 31 42 38 16 26 5 48 196 38 38 22 24 2 34
+ 33 27 26 4 13 5 24 0 0 23 22 33 1 0 1 4 48 196 1 0 1 12 11 1 25
+ 24 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Gdotaccent" xMin="93" yMin="-37" xMax="1405" yMax="1801">
+ <contour>
+ <pt x="1405" y="688" on="1"/>
+ <pt x="1405" y="40" on="1"/>
+ <pt x="1131" y="-37" on="0"/>
+ <pt x="871" y="-37" on="1"/>
+ <pt x="93" y="-37" on="0"/>
+ <pt x="93" y="735" on="1"/>
+ <pt x="93" y="1113" on="0"/>
+ <pt x="294" y="1315" on="1"/>
+ <pt x="496" y="1517" on="0"/>
+ <pt x="877" y="1517" on="1"/>
+ <pt x="1123" y="1517" on="0"/>
+ <pt x="1403" y="1450" on="1"/>
+ <pt x="1403" y="1256" on="1"/>
+ <pt x="1082" y="1360" on="0"/>
+ <pt x="868" y="1360" on="1"/>
+ <pt x="318" y="1360" on="0"/>
+ <pt x="318" y="744" on="1"/>
+ <pt x="318" y="440" on="0"/>
+ <pt x="470" y="280" on="1"/>
+ <pt x="621" y="120" on="0"/>
+ <pt x="900" y="120" on="1"/>
+ <pt x="1015" y="120" on="0"/>
+ <pt x="1196" y="157" on="1"/>
+ <pt x="1196" y="534" on="1"/>
+ <pt x="949" y="534" on="1"/>
+ <pt x="949" y="688" on="1"/>
+ </contour>
+ <contour>
+ <pt x="768" y="1604" on="1"/>
+ <pt x="768" y="1801" on="1"/>
+ <pt x="965" y="1801" on="1"/>
+ <pt x="965" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 94 values pushed */
+ 0 0 20 29 3 14 29 9 48 196 9 0 3 2 1 12 11 2 0 0 3 0 1 22 1
+ 2 23 2 3 0 0 0 29 26 5 1 27 24 23 15 1 0 2 4 48 196 28 27 1 25
+ 0 1 2 0 14 0 0 16 26 5 48 196 5 26 0 0 27 26 4 1 28 23 22 33 1
+ 0 2 4 48 196 29 28 1 1 0 1 12 11 1 25 24 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="H" xMin="165" yMin="0" xMax="1313" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="856" on="1"/>
+ <pt x="1104" y="856" on="1"/>
+ <pt x="1104" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1104" y="0" on="1"/>
+ <pt x="1104" y="699" on="1"/>
+ <pt x="375" y="699" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 10 9 15 1 3 1 4 48 196 4 3 1 11 8 7 0 3 2 0 6 5 2 1
+ 0 3 14 0 0 9 8 5 4 33 3 6 11 10 3 2 33 3 0 2 4 48 196 7 6
+ 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Hbar" xMin="17" yMin="0" xMax="1461" yMax="1480">
+ <contour>
+ <pt x="375" y="856" on="1"/>
+ <pt x="1104" y="856" on="1"/>
+ <pt x="1104" y="1110" on="1"/>
+ <pt x="375" y="1110" on="1"/>
+ </contour>
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1110" on="1"/>
+ <pt x="17" y="1110" on="1"/>
+ <pt x="17" y="1234" on="1"/>
+ <pt x="165" y="1234" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="1234" on="1"/>
+ <pt x="1104" y="1234" on="1"/>
+ <pt x="1104" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="1234" on="1"/>
+ <pt x="1461" y="1234" on="1"/>
+ <pt x="1461" y="1110" on="1"/>
+ <pt x="1313" y="1110" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1104" y="0" on="1"/>
+ <pt x="1104" y="699" on="1"/>
+ <pt x="375" y="699" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 107 values pushed */
+ 0 0 18 17 6 5 3 2 6 5 7 1 4 48 196 16 15 12 11 8 7 5 22 21 1
+ 23 20 19 4 3 18 17 6 5 3 2 5 1 0 1 5 0 14 13 10 9 0 3 14 17
+ 16 2 13 14 7 6 4 0 0 21 20 13 12 2 1 33 5 14 23 22 11 10 3 0 33
+ 5 4 2 4 48 196 19 18 15 14 3 9 8 5 4 3 21 20 13 12 2 1 5 23 22
+ 11 10 3 0 5 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Hcircumflex" xMin="165" yMin="0" xMax="1313" yMax="1925">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="856" on="1"/>
+ <pt x="1104" y="856" on="1"/>
+ <pt x="1104" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1104" y="0" on="1"/>
+ <pt x="1104" y="699" on="1"/>
+ <pt x="375" y="699" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="389" y="1604" on="1"/>
+ <pt x="630" y="1925" on="1"/>
+ <pt x="848" y="1925" on="1"/>
+ <pt x="1089" y="1604" on="1"/>
+ <pt x="941" y="1604" on="1"/>
+ <pt x="740" y="1806" on="1"/>
+ <pt x="738" y="1806" on="1"/>
+ <pt x="537" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 18 17 2 13 12 3 0 0 10 9 15 1 3 1 4 48 196 14 13 1 19 16 15 12 3
+ 4 3 1 11 8 7 0 3 4 0 6 5 2 1 0 3 14 19 18 17 16 15 14 13 12
+ 8 4 2 3 0 0 9 8 5 4 33 3 6 11 10 3 2 33 3 0 2 4 48 196 7
+ 6 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="I" xMin="180" yMin="0" xMax="390" yMax="1480">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 23 values pushed */
+ 3 0 1 0 2 1 0 14 0 0 3 2 33 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="IJ" xMin="180" yMin="-296" xMax="1322" yMax="1480">
+ <component glyphName="I" x="0" y="0" flags="0x4"/>
+ <component glyphName="J" x="482" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="Iacute" xMin="137" yMin="0" xMax="606" yMax="1925">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="137" y="1604" on="1"/>
+ <pt x="378" y="1925" on="1"/>
+ <pt x="606" y="1925" on="1"/>
+ <pt x="285" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 40 values pushed */
+ 6 5 1 7 4 1 3 0 1 3 0 2 1 0 14 7 5 2 2 0 3 6 2 4 0
+ 0 0 3 2 33 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ibreve" xMin="-48" yMin="0" xMax="618" yMax="1925">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-48" y="1925" on="1"/>
+ <pt x="75" y="1925" on="1"/>
+ <pt x="96" y="1831" on="0"/>
+ <pt x="150" y="1791" on="1"/>
+ <pt x="202" y="1752" on="0"/>
+ <pt x="285" y="1752" on="1"/>
+ <pt x="379" y="1752" on="0"/>
+ <pt x="433" y="1801" on="1"/>
+ <pt x="476" y="1841" on="0"/>
+ <pt x="495" y="1925" on="1"/>
+ <pt x="618" y="1925" on="1"/>
+ <pt x="602" y="1791" on="0"/>
+ <pt x="529" y="1710" on="1"/>
+ <pt x="435" y="1604" on="0"/>
+ <pt x="285" y="1604" on="1"/>
+ <pt x="128" y="1604" on="0"/>
+ <pt x="33" y="1719" on="1"/>
+ <pt x="-32" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 9 7 18 48 196 14 13 5 4 4 13 18 1 3 0 1 0 2 1 0 14 14 13
+ 2 13 2 5 4 0 0 0 3 2 9 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Icircumflex" xMin="-65" yMin="0" xMax="635" yMax="1925">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-65" y="1604" on="1"/>
+ <pt x="176" y="1925" on="1"/>
+ <pt x="394" y="1925" on="1"/>
+ <pt x="635" y="1604" on="1"/>
+ <pt x="487" y="1604" on="1"/>
+ <pt x="286" y="1806" on="1"/>
+ <pt x="284" y="1806" on="1"/>
+ <pt x="83" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 10 9 2 5 4 3 6 5 1 11 8 7 4 3 3 0 1 3 0 2 1 0 14 10 9
+ 2 2 0 3 8 7 6 3 13 2 11 5 4 3 13 0 0 0 3 2 33 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Idieresis" xMin="1" yMin="0" xMax="569" yMax="1777">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1" y="1604" on="1"/>
+ <pt x="1" y="1777" on="1"/>
+ <pt x="174" y="1777" on="1"/>
+ <pt x="174" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="396" y="1604" on="1"/>
+ <pt x="396" y="1777" on="1"/>
+ <pt x="569" y="1777" on="1"/>
+ <pt x="569" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 0 0 11 8 7 4 13 3 5 1 4 48 196 10 9 6 5 3 3 0 1 2 0 2 1
+ 0 14 0 0 9 8 13 1 10 7 6 13 1 4 3 2 33 1 0 3 4 48 196 11 10
+ 1 5 4 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Idotaccent" xMin="180" yMin="0" xMax="390" yMax="1801">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="186" y="1604" on="1"/>
+ <pt x="186" y="1801" on="1"/>
+ <pt x="383" y="1801" on="1"/>
+ <pt x="383" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 7 4 5 1 5 1 4 48 196 6 5 1 3 0 1 2 0 2 1 0 14 0 0
+ 7 6 4 1 4 3 2 33 1 0 2 4 48 196 5 4 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Igrave" xMin="-36" yMin="0" xMax="433" yMax="1925">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="433" y="1604" on="1"/>
+ <pt x="285" y="1604" on="1"/>
+ <pt x="-36" y="1925" on="1"/>
+ <pt x="192" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 40 values pushed */
+ 7 6 1 5 4 1 3 0 1 3 0 2 1 0 14 7 5 2 2 0 3 4 2 6 0
+ 0 0 3 2 33 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Imacron" xMin="-36" yMin="0" xMax="606" yMax="1752">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-36" y="1604" on="1"/>
+ <pt x="-36" y="1752" on="1"/>
+ <pt x="606" y="1752" on="1"/>
+ <pt x="606" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 45 values pushed */
+ 0 0 7 4 7 1 5 1 4 48 196 6 5 1 3 0 1 2 0 2 1 0 14 0 0
+ 3 2 33 1 0 1 4 48 196 7 6 1 5 4 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Iogonek" xMin="120" yMin="-370" xMax="462" yMax="1480">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="278" y="0" on="1"/>
+ <pt x="385" y="0" on="1"/>
+ <pt x="257" y="-80" on="0"/>
+ <pt x="257" y="-179" on="1"/>
+ <pt x="257" y="-275" on="0"/>
+ <pt x="372" y="-275" on="1"/>
+ <pt x="425" y="-275" on="0"/>
+ <pt x="462" y="-260" on="1"/>
+ <pt x="462" y="-341" on="1"/>
+ <pt x="400" y="-370" on="0"/>
+ <pt x="322" y="-370" on="1"/>
+ <pt x="120" y="-370" on="0"/>
+ <pt x="120" y="-212" on="1"/>
+ <pt x="120" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 9 21 14 48 196 12 11 14 0 5 4 3 0 3 0 2 1 0 14 0 0 7 42
+ 16 48 196 5 4 2 2 0 3 12 11 2 13 2 16 0 0 0 3 2 33 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Itilde" xMin="-48" yMin="0" xMax="618" yMax="1838">
+ <contour>
+ <pt x="180" y="0" on="1"/>
+ <pt x="180" y="1480" on="1"/>
+ <pt x="390" y="1480" on="1"/>
+ <pt x="390" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-48" y="1604" on="1"/>
+ <pt x="-41" y="1697" on="0"/>
+ <pt x="-16" y="1748" on="1"/>
+ <pt x="30" y="1838" on="0"/>
+ <pt x="139" y="1838" on="1"/>
+ <pt x="211" y="1838" on="0"/>
+ <pt x="272" y="1800" on="1"/>
+ <pt x="332" y="1763" on="1"/>
+ <pt x="389" y="1728" on="0"/>
+ <pt x="419" y="1728" on="1"/>
+ <pt x="484" y="1728" on="0"/>
+ <pt x="495" y="1838" on="1"/>
+ <pt x="618" y="1838" on="1"/>
+ <pt x="611" y="1744" on="0"/>
+ <pt x="586" y="1694" on="1"/>
+ <pt x="541" y="1604" on="0"/>
+ <pt x="433" y="1604" on="1"/>
+ <pt x="361" y="1604" on="0"/>
+ <pt x="298" y="1643" on="1"/>
+ <pt x="238" y="1680" on="1"/>
+ <pt x="183" y="1714" on="0"/>
+ <pt x="151" y="1714" on="1"/>
+ <pt x="86" y="1714" on="0"/>
+ <pt x="75" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 0 0 25 6 8 13 6 20 48 196 27 16 15 4 4 13 20 8 1 3 0 1 0 2 1
+ 0 14 16 15 2 13 2 27 4 0 0 0 3 2 9 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="J" xMin="49" yMin="-296" xMax="840" yMax="1480">
+ <contour>
+ <pt x="49" y="-232" on="1"/>
+ <pt x="49" y="-51" on="1"/>
+ <pt x="220" y="-128" on="0"/>
+ <pt x="369" y="-128" on="1"/>
+ <pt x="540" y="-128" on="0"/>
+ <pt x="589" y="-49" on="1"/>
+ <pt x="630" y="19" on="0"/>
+ <pt x="630" y="180" on="1"/>
+ <pt x="630" y="1480" on="1"/>
+ <pt x="840" y="1480" on="1"/>
+ <pt x="840" y="187" on="1"/>
+ <pt x="840" y="-296" on="0"/>
+ <pt x="359" y="-296" on="1"/>
+ <pt x="197" y="-296" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 3 30 12 48 196 1 10 7 2 8 2 3 0 1 1 0 12 2 0 9 8 0 14
+ 0 0 8 7 33 1 9 1 4 48 196 10 9 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Jcircumflex" xMin="49" yMin="-296" xMax="1061" yMax="1925">
+ <contour>
+ <pt x="49" y="-232" on="1"/>
+ <pt x="49" y="-51" on="1"/>
+ <pt x="220" y="-128" on="0"/>
+ <pt x="369" y="-128" on="1"/>
+ <pt x="540" y="-128" on="0"/>
+ <pt x="589" y="-49" on="1"/>
+ <pt x="630" y="19" on="0"/>
+ <pt x="630" y="180" on="1"/>
+ <pt x="630" y="1480" on="1"/>
+ <pt x="840" y="1480" on="1"/>
+ <pt x="840" y="187" on="1"/>
+ <pt x="840" y="-296" on="0"/>
+ <pt x="359" y="-296" on="1"/>
+ <pt x="197" y="-296" on="0"/>
+ </contour>
+ <contour>
+ <pt x="361" y="1604" on="1"/>
+ <pt x="602" y="1925" on="1"/>
+ <pt x="820" y="1925" on="1"/>
+ <pt x="1061" y="1604" on="1"/>
+ <pt x="913" y="1604" on="1"/>
+ <pt x="712" y="1806" on="1"/>
+ <pt x="710" y="1806" on="1"/>
+ <pt x="509" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 0 0 3 30 12 48 196 20 19 2 15 14 3 1 10 7 2 8 2 3 0 1 1 0 12
+ 2 0 16 15 1 21 18 17 14 3 2 0 9 8 0 14 20 19 16 3 9 7 3 21 15
+ 14 3 7 0 3 18 17 2 13 9 0 0 8 7 33 1 9 1 4 48 196 10 9 1 1
+ 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="K" xMin="191" yMin="0" xMax="1317" yMax="1480">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="388" y="1480" on="1"/>
+ <pt x="388" y="752" on="1"/>
+ <pt x="1003" y="1480" on="1"/>
+ <pt x="1214" y="1480" on="1"/>
+ <pt x="618" y="774" on="1"/>
+ <pt x="1317" y="0" on="1"/>
+ <pt x="1051" y="0" on="1"/>
+ <pt x="388" y="750" on="1"/>
+ <pt x="388" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 45 values pushed */
+ 9 6 3 3 1 0 3 10 8 7 0 3 0 5 4 2 1 0 3 14 8 7 6 5 4
+ 5 13 2 0 0 10 9 3 2 4 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Kcommaaccent" xMin="191" yMin="-432" xMax="1317" yMax="1480">
+ <contour>
+ <pt x="191" y="0" on="1"/>
+ <pt x="191" y="1480" on="1"/>
+ <pt x="388" y="1480" on="1"/>
+ <pt x="388" y="752" on="1"/>
+ <pt x="1003" y="1480" on="1"/>
+ <pt x="1214" y="1480" on="1"/>
+ <pt x="618" y="774" on="1"/>
+ <pt x="1317" y="0" on="1"/>
+ <pt x="1051" y="0" on="1"/>
+ <pt x="388" y="750" on="1"/>
+ <pt x="388" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="487" y="-421" on="1"/>
+ <pt x="487" y="-336" on="1"/>
+ <pt x="544" y="-345" on="0"/>
+ <pt x="584" y="-345" on="1"/>
+ <pt x="694" y="-345" on="0"/>
+ <pt x="694" y="-278" on="1"/>
+ <pt x="694" y="-204" on="0"/>
+ <pt x="536" y="-188" on="1"/>
+ <pt x="536" y="-111" on="1"/>
+ <pt x="670" y="-114" on="0"/>
+ <pt x="736" y="-143" on="1"/>
+ <pt x="829" y="-185" on="0"/>
+ <pt x="829" y="-280" on="1"/>
+ <pt x="829" y="-432" on="0"/>
+ <pt x="612" y="-432" on="1"/>
+ <pt x="553" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 14 44 25 48 196 9 6 3 3 1 0 3 19 18 12 11 4 13 25 0 10 8 7
+ 0 3 0 5 4 2 1 0 3 14 0 0 16 42 23 48 196 19 18 12 11 8 7 6 5
+ 4 9 13 23 2 0 0 10 9 3 2 4 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="L" xMin="165" yMin="0" xMax="1101" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="157" on="1"/>
+ <pt x="1101" y="157" on="1"/>
+ <pt x="1101" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 38 values pushed */
+ 0 0 4 3 15 1 0 1 4 48 196 5 0 1 0 2 1 0 14 0 0 3 2 33 1
+ 0 1 4 48 196 5 4 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lacute" xMin="165" yMin="0" xMax="1101" yMax="1925">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="157" on="1"/>
+ <pt x="1101" y="157" on="1"/>
+ <pt x="1101" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="177" y="1604" on="1"/>
+ <pt x="418" y="1925" on="1"/>
+ <pt x="646" y="1925" on="1"/>
+ <pt x="325" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 0 0 4 3 15 1 0 1 4 48 196 8 7 1 9 6 1 5 0 1 3 0 2 1 0
+ 14 8 7 2 4 2 3 9 6 2 2 0 3 0 0 3 2 33 1 0 1 4 48 196 5
+ 4 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lcaron" xMin="165" yMin="0" xMax="1101" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="157" on="1"/>
+ <pt x="1101" y="157" on="1"/>
+ <pt x="1101" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="671" y="1026" on="1"/>
+ <pt x="671" y="1085" on="1"/>
+ <pt x="747" y="1106" on="0"/>
+ <pt x="747" y="1266" on="1"/>
+ <pt x="747" y="1283" on="1"/>
+ <pt x="671" y="1283" on="1"/>
+ <pt x="671" y="1480" on="1"/>
+ <pt x="868" y="1480" on="1"/>
+ <pt x="868" y="1309" on="1"/>
+ <pt x="867" y="1047" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 14 11 10 9 7 6 6 1 3 3 0 0 4 3 15 1 0 1 4 48 196 5 0 1 0
+ 13 12 2 1 0 3 14 10 9 2 13 6 3 0 0 12 11 7 6 4 3 13 3 2 33
+ 1 0 2 4 48 196 14 13 1 5 4 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lcommaaccent" xMin="165" yMin="-432" xMax="1101" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="157" on="1"/>
+ <pt x="1101" y="157" on="1"/>
+ <pt x="1101" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="449" y="-421" on="1"/>
+ <pt x="449" y="-336" on="1"/>
+ <pt x="506" y="-345" on="0"/>
+ <pt x="546" y="-345" on="1"/>
+ <pt x="656" y="-345" on="0"/>
+ <pt x="656" y="-278" on="1"/>
+ <pt x="656" y="-204" on="0"/>
+ <pt x="498" y="-188" on="1"/>
+ <pt x="498" y="-111" on="1"/>
+ <pt x="632" y="-114" on="0"/>
+ <pt x="698" y="-143" on="1"/>
+ <pt x="791" y="-185" on="0"/>
+ <pt x="791" y="-280" on="1"/>
+ <pt x="791" y="-432" on="0"/>
+ <pt x="574" y="-432" on="1"/>
+ <pt x="515" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 9 44 20 48 196 14 13 7 6 4 13 20 0 0 0 4 3 15 1 0 1 4 48
+ 196 5 0 1 0 2 1 0 14 0 0 11 42 18 48 196 18 18 14 13 7 6 5 4 2
+ 3 0 0 3 2 33 1 0 1 4 48 196 5 4 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ldot" xMin="165" yMin="0" xMax="1101" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="157" on="1"/>
+ <pt x="1101" y="157" on="1"/>
+ <pt x="1101" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="743" y="642" on="1"/>
+ <pt x="743" y="839" on="1"/>
+ <pt x="940" y="839" on="1"/>
+ <pt x="940" y="642" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 55 values pushed */
+ 0 0 9 6 5 1 7 4 3 15 1 0 2 4 48 196 8 7 1 5 0 1 2 0 2
+ 1 0 14 0 0 7 6 4 1 8 3 2 33 1 0 2 4 48 196 9 8 1 5 4 1
+ 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Lslash" xMin="17" yMin="0" xMax="1100" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="692" on="1"/>
+ <pt x="17" y="612" on="1"/>
+ <pt x="17" y="780" on="1"/>
+ <pt x="165" y="862" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="375" y="976" on="1"/>
+ <pt x="621" y="1110" on="1"/>
+ <pt x="621" y="941" on="1"/>
+ <pt x="375" y="807" on="1"/>
+ <pt x="375" y="157" on="1"/>
+ <pt x="1100" y="157" on="1"/>
+ <pt x="1100" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 10 9 8 7 4 3 2 1 8 5 11 3 0 0 12 11 15 1 0 1 4 48 196 13 0
+ 1 0 6 5 0 14 0 0 11 10 7 6 33 3 0 1 4 48 196 13 12 1 9 8 1
+ 5 4 1 0 3 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="M" xMin="165" yMin="0" xMax="1541" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="456" y="1480" on="1"/>
+ <pt x="863" y="335" on="1"/>
+ <pt x="1281" y="1480" on="1"/>
+ <pt x="1541" y="1480" on="1"/>
+ <pt x="1541" y="0" on="1"/>
+ <pt x="1345" y="0" on="1"/>
+ <pt x="1345" y="1203" on="1"/>
+ <pt x="941" y="99" on="1"/>
+ <pt x="738" y="99" on="1"/>
+ <pt x="346" y="1207" on="1"/>
+ <pt x="346" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 11 8 3 3 1 9 3 10 9 1 12 7 6 0 3 2 0 5 4 2 1 0 3 14 10
+ 9 4 3 2 5 7 11 3 0 0 8 7 4 1 5 12 11 24 1 0 2 4 48 196 6
+ 5 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="N" xMin="165" yMin="0" xMax="1313" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="370" y="1480" on="1"/>
+ <pt x="1133" y="337" on="1"/>
+ <pt x="1133" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1107" y="0" on="1"/>
+ <pt x="345" y="1143" on="1"/>
+ <pt x="345" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 49 values pushed */
+ 8 3 2 1 0 3 9 7 6 0 3 0 5 4 2 1 0 3 14 7 2 2 3 8 3
+ 0 0 4 3 24 1 5 9 8 24 1 0 2 4 48 196 6 5 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Nacute" xMin="165" yMin="0" xMax="1313" yMax="1925">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="370" y="1480" on="1"/>
+ <pt x="1133" y="337" on="1"/>
+ <pt x="1133" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1107" y="0" on="1"/>
+ <pt x="345" y="1143" on="1"/>
+ <pt x="345" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="591" y="1604" on="1"/>
+ <pt x="832" y="1925" on="1"/>
+ <pt x="1060" y="1925" on="1"/>
+ <pt x="739" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 8 3 2 1 0 3 12 11 1 13 10 1 9 7 6 0 3 3 0 5 4 2 1 0 3
+ 14 13 12 11 10 7 2 6 3 8 3 0 0 4 3 24 1 5 9 8 24 1 0 2 4
+ 48 196 6 5 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ncaron" xMin="165" yMin="0" xMax="1313" yMax="1925">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="370" y="1480" on="1"/>
+ <pt x="1133" y="337" on="1"/>
+ <pt x="1133" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1107" y="0" on="1"/>
+ <pt x="345" y="1143" on="1"/>
+ <pt x="345" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1089" y="1925" on="1"/>
+ <pt x="848" y="1604" on="1"/>
+ <pt x="630" y="1604" on="1"/>
+ <pt x="389" y="1925" on="1"/>
+ <pt x="537" y="1925" on="1"/>
+ <pt x="738" y="1723" on="1"/>
+ <pt x="740" y="1723" on="1"/>
+ <pt x="941" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 16 15 2 10 11 3 8 3 2 1 0 3 17 14 13 10 3 12 11 1 9 7 6 0 3
+ 3 0 5 4 2 1 0 3 14 17 16 15 14 13 12 11 10 7 2 10 3 8 3 0 0
+ 4 3 24 1 5 9 8 24 1 0 2 4 48 196 6 5 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ncommaaccent" xMin="165" yMin="-432" xMax="1313" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="370" y="1480" on="1"/>
+ <pt x="1133" y="337" on="1"/>
+ <pt x="1133" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1107" y="0" on="1"/>
+ <pt x="345" y="1143" on="1"/>
+ <pt x="345" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="518" y="-421" on="1"/>
+ <pt x="518" y="-336" on="1"/>
+ <pt x="575" y="-345" on="0"/>
+ <pt x="615" y="-345" on="1"/>
+ <pt x="725" y="-345" on="0"/>
+ <pt x="725" y="-278" on="1"/>
+ <pt x="725" y="-205" on="0"/>
+ <pt x="567" y="-188" on="1"/>
+ <pt x="567" y="-111" on="1"/>
+ <pt x="702" y="-114" on="0"/>
+ <pt x="767" y="-143" on="1"/>
+ <pt x="860" y="-185" on="0"/>
+ <pt x="860" y="-280" on="1"/>
+ <pt x="860" y="-432" on="0"/>
+ <pt x="643" y="-432" on="1"/>
+ <pt x="584" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 13 44 24 48 196 8 3 2 1 0 3 18 17 11 10 4 13 24 0 9 7 6 0
+ 3 0 5 4 2 1 0 3 14 0 0 15 42 22 48 196 22 22 18 17 11 10 7 2 7
+ 3 8 3 0 0 4 3 24 1 5 9 8 24 1 0 2 4 48 196 6 5 1 1 0 1
+ 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ntilde" xMin="165" yMin="0" xMax="1313" yMax="1838">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="370" y="1480" on="1"/>
+ <pt x="1133" y="337" on="1"/>
+ <pt x="1133" y="1480" on="1"/>
+ <pt x="1313" y="1480" on="1"/>
+ <pt x="1313" y="0" on="1"/>
+ <pt x="1107" y="0" on="1"/>
+ <pt x="345" y="1143" on="1"/>
+ <pt x="345" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="432" y="1604" on="1"/>
+ <pt x="439" y="1698" on="0"/>
+ <pt x="464" y="1748" on="1"/>
+ <pt x="510" y="1838" on="0"/>
+ <pt x="619" y="1838" on="1"/>
+ <pt x="690" y="1838" on="0"/>
+ <pt x="752" y="1800" on="1"/>
+ <pt x="812" y="1763" on="1"/>
+ <pt x="869" y="1728" on="0"/>
+ <pt x="899" y="1728" on="1"/>
+ <pt x="964" y="1728" on="0"/>
+ <pt x="975" y="1838" on="1"/>
+ <pt x="1098" y="1838" on="1"/>
+ <pt x="1091" y="1744" on="0"/>
+ <pt x="1066" y="1694" on="1"/>
+ <pt x="1021" y="1604" on="0"/>
+ <pt x="913" y="1604" on="1"/>
+ <pt x="841" y="1604" on="0"/>
+ <pt x="778" y="1643" on="1"/>
+ <pt x="718" y="1680" on="1"/>
+ <pt x="663" y="1714" on="0"/>
+ <pt x="631" y="1714" on="1"/>
+ <pt x="566" y="1714" on="0"/>
+ <pt x="555" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 31 6 14 19 6 26 48 196 8 3 2 1 0 3 33 22 21 10 4 13 26 14 1
+ 9 7 6 0 3 0 5 4 2 1 0 3 14 33 22 21 10 7 2 6 3 8 3 0 0
+ 4 3 24 1 5 9 8 24 1 0 2 4 48 196 6 5 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="O" xMin="93" yMin="-37" xMax="1501" yMax="1517">
+ <contour>
+ <pt x="797" y="1517" on="1"/>
+ <pt x="1116" y="1517" on="0"/>
+ <pt x="1309" y="1306" on="1"/>
+ <pt x="1501" y="1094" on="0"/>
+ <pt x="1501" y="742" on="1"/>
+ <pt x="1501" y="383" on="0"/>
+ <pt x="1309" y="173" on="1"/>
+ <pt x="1116" y="-37" on="0"/>
+ <pt x="787" y="-37" on="1"/>
+ <pt x="505" y="-37" on="0"/>
+ <pt x="322" y="136" on="1"/>
+ <pt x="93" y="353" on="0"/>
+ <pt x="93" y="740" on="1"/>
+ <pt x="93" y="1095" on="0"/>
+ <pt x="285" y="1306" on="1"/>
+ <pt x="477" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="797" y="1360" on="1"/>
+ <pt x="570" y="1360" on="0"/>
+ <pt x="444" y="1197" on="1"/>
+ <pt x="318" y="1034" on="0"/>
+ <pt x="318" y="741" on="1"/>
+ <pt x="318" y="450" on="0"/>
+ <pt x="444" y="285" on="1"/>
+ <pt x="569" y="120" on="0"/>
+ <pt x="792" y="120" on="1"/>
+ <pt x="999" y="120" on="0"/>
+ <pt x="1122" y="252" on="1"/>
+ <pt x="1276" y="415" on="0"/>
+ <pt x="1276" y="742" on="1"/>
+ <pt x="1276" y="1034" on="0"/>
+ <pt x="1149" y="1197" on="1"/>
+ <pt x="1022" y="1360" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 24 29 8 16 29 0 48 196 8 2 0 0 14 0 0 28 26 4 20 26 12 48 196
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="OE" xMin="93" yMin="-37" xMax="1991" yMax="1517">
+ <contour>
+ <pt x="1129" y="0" on="1"/>
+ <pt x="1129" y="58" on="1"/>
+ <pt x="965" y="-37" on="0"/>
+ <pt x="775" y="-37" on="1"/>
+ <pt x="469" y="-37" on="0"/>
+ <pt x="281" y="177" on="1"/>
+ <pt x="93" y="391" on="0"/>
+ <pt x="93" y="740" on="1"/>
+ <pt x="93" y="1095" on="0"/>
+ <pt x="282" y="1306" on="1"/>
+ <pt x="471" y="1517" on="0"/>
+ <pt x="785" y="1517" on="1"/>
+ <pt x="967" y="1517" on="0"/>
+ <pt x="1129" y="1423" on="1"/>
+ <pt x="1129" y="1480" on="1"/>
+ <pt x="1947" y="1480" on="1"/>
+ <pt x="1947" y="1323" on="1"/>
+ <pt x="1339" y="1323" on="1"/>
+ <pt x="1339" y="848" on="1"/>
+ <pt x="1848" y="848" on="1"/>
+ <pt x="1848" y="693" on="1"/>
+ <pt x="1339" y="693" on="1"/>
+ <pt x="1339" y="157" on="1"/>
+ <pt x="1991" y="157" on="1"/>
+ <pt x="1991" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1129" y="569" on="1"/>
+ <pt x="1129" y="911" on="1"/>
+ <pt x="1129" y="1147" on="0"/>
+ <pt x="1048" y="1253" on="1"/>
+ <pt x="967" y="1360" on="0"/>
+ <pt x="788" y="1360" on="1"/>
+ <pt x="565" y="1360" on="0"/>
+ <pt x="441" y="1197" on="1"/>
+ <pt x="316" y="1034" on="0"/>
+ <pt x="316" y="740" on="1"/>
+ <pt x="316" y="446" on="0"/>
+ <pt x="441" y="283" on="1"/>
+ <pt x="567" y="120" on="0"/>
+ <pt x="789" y="120" on="1"/>
+ <pt x="1129" y="120" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 38 29 3 30 29 11 48 196 11 0 3 2 13 14 16 2 26 16 18 2 25 20 22
+ 2 1 22 0 2 0 0 17 16 15 1 14 21 20 15 1 18 23 22 15 1 0 3 4 48
+ 196 19 18 1 24 0 1 2 0 15 14 0 14 0 0 34 26 7 48 196 7 0 0 0 26
+ 25 14 13 1 0 33 5 17 1 4 48 196 24 23 1 16 15 1 20 19 1 22 21 18 17
+ 3 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Oacute" xMin="92" yMin="-37" xMax="1500" yMax="1925">
+ <contour>
+ <pt x="796" y="1517" on="1"/>
+ <pt x="1115" y="1517" on="0"/>
+ <pt x="1308" y="1306" on="1"/>
+ <pt x="1500" y="1094" on="0"/>
+ <pt x="1500" y="742" on="1"/>
+ <pt x="1500" y="383" on="0"/>
+ <pt x="1308" y="173" on="1"/>
+ <pt x="1115" y="-37" on="0"/>
+ <pt x="786" y="-37" on="1"/>
+ <pt x="504" y="-37" on="0"/>
+ <pt x="321" y="136" on="1"/>
+ <pt x="92" y="353" on="0"/>
+ <pt x="92" y="740" on="1"/>
+ <pt x="92" y="1095" on="0"/>
+ <pt x="284" y="1306" on="1"/>
+ <pt x="476" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="796" y="1360" on="1"/>
+ <pt x="569" y="1360" on="0"/>
+ <pt x="443" y="1197" on="1"/>
+ <pt x="317" y="1034" on="0"/>
+ <pt x="317" y="741" on="1"/>
+ <pt x="317" y="450" on="0"/>
+ <pt x="443" y="285" on="1"/>
+ <pt x="568" y="120" on="0"/>
+ <pt x="791" y="120" on="1"/>
+ <pt x="998" y="120" on="0"/>
+ <pt x="1121" y="252" on="1"/>
+ <pt x="1275" y="415" on="0"/>
+ <pt x="1275" y="742" on="1"/>
+ <pt x="1275" y="1034" on="0"/>
+ <pt x="1148" y="1197" on="1"/>
+ <pt x="1021" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="648" y="1604" on="1"/>
+ <pt x="889" y="1925" on="1"/>
+ <pt x="1117" y="1925" on="1"/>
+ <pt x="796" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 39 values pushed */
+ 0 0 24 29 8 16 29 0 48 196 8 2 0 0 34 33 1 35 32 1 2 0 14 0 0
+ 28 26 4 20 26 12 48 196 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Obreve" xMin="93" yMin="-37" xMax="1501" yMax="1925">
+ <contour>
+ <pt x="797" y="1517" on="1"/>
+ <pt x="1116" y="1517" on="0"/>
+ <pt x="1309" y="1306" on="1"/>
+ <pt x="1501" y="1094" on="0"/>
+ <pt x="1501" y="742" on="1"/>
+ <pt x="1501" y="383" on="0"/>
+ <pt x="1309" y="173" on="1"/>
+ <pt x="1116" y="-37" on="0"/>
+ <pt x="787" y="-37" on="1"/>
+ <pt x="505" y="-37" on="0"/>
+ <pt x="322" y="136" on="1"/>
+ <pt x="93" y="353" on="0"/>
+ <pt x="93" y="740" on="1"/>
+ <pt x="93" y="1095" on="0"/>
+ <pt x="285" y="1306" on="1"/>
+ <pt x="477" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="797" y="1360" on="1"/>
+ <pt x="570" y="1360" on="0"/>
+ <pt x="444" y="1197" on="1"/>
+ <pt x="318" y="1034" on="0"/>
+ <pt x="318" y="741" on="1"/>
+ <pt x="318" y="450" on="0"/>
+ <pt x="444" y="285" on="1"/>
+ <pt x="569" y="120" on="0"/>
+ <pt x="792" y="120" on="1"/>
+ <pt x="999" y="120" on="0"/>
+ <pt x="1122" y="252" on="1"/>
+ <pt x="1276" y="415" on="0"/>
+ <pt x="1276" y="742" on="1"/>
+ <pt x="1276" y="1034" on="0"/>
+ <pt x="1149" y="1197" on="1"/>
+ <pt x="1022" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="464" y="1925" on="1"/>
+ <pt x="587" y="1925" on="1"/>
+ <pt x="608" y="1831" on="0"/>
+ <pt x="662" y="1791" on="1"/>
+ <pt x="714" y="1752" on="0"/>
+ <pt x="797" y="1752" on="1"/>
+ <pt x="890" y="1752" on="0"/>
+ <pt x="945" y="1801" on="1"/>
+ <pt x="988" y="1841" on="0"/>
+ <pt x="1007" y="1925" on="1"/>
+ <pt x="1130" y="1925" on="1"/>
+ <pt x="1114" y="1791" on="0"/>
+ <pt x="1041" y="1710" on="1"/>
+ <pt x="947" y="1604" on="0"/>
+ <pt x="797" y="1604" on="1"/>
+ <pt x="640" y="1604" on="0"/>
+ <pt x="545" y="1719" on="1"/>
+ <pt x="480" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 37 7 46 24 35 8 16 35 0 48 196 8 2 0 0 1 42 41 33 32 4 13 46
+ 0 0 14 0 0 28 36 4 20 36 12 48 196 42 41 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ocircumflex" xMin="92" yMin="-37" xMax="1500" yMax="1925">
+ <contour>
+ <pt x="796" y="1517" on="1"/>
+ <pt x="1115" y="1517" on="0"/>
+ <pt x="1308" y="1306" on="1"/>
+ <pt x="1500" y="1094" on="0"/>
+ <pt x="1500" y="742" on="1"/>
+ <pt x="1500" y="383" on="0"/>
+ <pt x="1308" y="173" on="1"/>
+ <pt x="1115" y="-37" on="0"/>
+ <pt x="786" y="-37" on="1"/>
+ <pt x="504" y="-37" on="0"/>
+ <pt x="321" y="136" on="1"/>
+ <pt x="92" y="353" on="0"/>
+ <pt x="92" y="740" on="1"/>
+ <pt x="92" y="1095" on="0"/>
+ <pt x="284" y="1306" on="1"/>
+ <pt x="476" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="796" y="1360" on="1"/>
+ <pt x="569" y="1360" on="0"/>
+ <pt x="443" y="1197" on="1"/>
+ <pt x="317" y="1034" on="0"/>
+ <pt x="317" y="741" on="1"/>
+ <pt x="317" y="450" on="0"/>
+ <pt x="443" y="285" on="1"/>
+ <pt x="568" y="120" on="0"/>
+ <pt x="791" y="120" on="1"/>
+ <pt x="998" y="120" on="0"/>
+ <pt x="1121" y="252" on="1"/>
+ <pt x="1275" y="415" on="0"/>
+ <pt x="1275" y="742" on="1"/>
+ <pt x="1275" y="1034" on="0"/>
+ <pt x="1148" y="1197" on="1"/>
+ <pt x="1021" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="446" y="1604" on="1"/>
+ <pt x="687" y="1925" on="1"/>
+ <pt x="905" y="1925" on="1"/>
+ <pt x="1146" y="1604" on="1"/>
+ <pt x="998" y="1604" on="1"/>
+ <pt x="797" y="1806" on="1"/>
+ <pt x="795" y="1806" on="1"/>
+ <pt x="594" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 51 values pushed */
+ 0 0 24 29 8 16 29 0 48 196 8 2 0 0 38 37 2 33 32 3 34 33 1 39 36
+ 35 32 3 2 0 14 0 0 28 26 4 20 26 12 48 196 39 38 37 36 35 34 33 32 12
+ 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Odieresis" xMin="92" yMin="-37" xMax="1500" yMax="1777">
+ <contour>
+ <pt x="796" y="1517" on="1"/>
+ <pt x="1115" y="1517" on="0"/>
+ <pt x="1308" y="1306" on="1"/>
+ <pt x="1500" y="1094" on="0"/>
+ <pt x="1500" y="742" on="1"/>
+ <pt x="1500" y="383" on="0"/>
+ <pt x="1308" y="173" on="1"/>
+ <pt x="1115" y="-37" on="0"/>
+ <pt x="786" y="-37" on="1"/>
+ <pt x="504" y="-37" on="0"/>
+ <pt x="321" y="136" on="1"/>
+ <pt x="92" y="353" on="0"/>
+ <pt x="92" y="740" on="1"/>
+ <pt x="92" y="1095" on="0"/>
+ <pt x="284" y="1306" on="1"/>
+ <pt x="476" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="796" y="1360" on="1"/>
+ <pt x="569" y="1360" on="0"/>
+ <pt x="443" y="1197" on="1"/>
+ <pt x="317" y="1034" on="0"/>
+ <pt x="317" y="741" on="1"/>
+ <pt x="317" y="450" on="0"/>
+ <pt x="443" y="285" on="1"/>
+ <pt x="568" y="120" on="0"/>
+ <pt x="791" y="120" on="1"/>
+ <pt x="998" y="120" on="0"/>
+ <pt x="1121" y="252" on="1"/>
+ <pt x="1275" y="415" on="0"/>
+ <pt x="1275" y="742" on="1"/>
+ <pt x="1275" y="1034" on="0"/>
+ <pt x="1148" y="1197" on="1"/>
+ <pt x="1021" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="512" y="1604" on="1"/>
+ <pt x="512" y="1777" on="1"/>
+ <pt x="685" y="1777" on="1"/>
+ <pt x="685" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="907" y="1604" on="1"/>
+ <pt x="907" y="1777" on="1"/>
+ <pt x="1080" y="1777" on="1"/>
+ <pt x="1080" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 24 29 8 16 29 0 48 196 8 2 0 0 0 0 39 36 35 32 13 3 33 1 4
+ 48 196 38 37 34 33 3 0 14 0 0 28 26 4 20 26 12 48 196 4 38 12 32 0 0
+ 37 36 13 1 38 35 34 13 1 32 2 4 48 196 39 38 1 33 32 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ograve" xMin="92" yMin="-37" xMax="1500" yMax="1925">
+ <contour>
+ <pt x="796" y="1517" on="1"/>
+ <pt x="1115" y="1517" on="0"/>
+ <pt x="1308" y="1306" on="1"/>
+ <pt x="1500" y="1094" on="0"/>
+ <pt x="1500" y="742" on="1"/>
+ <pt x="1500" y="383" on="0"/>
+ <pt x="1308" y="173" on="1"/>
+ <pt x="1115" y="-37" on="0"/>
+ <pt x="786" y="-37" on="1"/>
+ <pt x="504" y="-37" on="0"/>
+ <pt x="321" y="136" on="1"/>
+ <pt x="92" y="353" on="0"/>
+ <pt x="92" y="740" on="1"/>
+ <pt x="92" y="1095" on="0"/>
+ <pt x="284" y="1306" on="1"/>
+ <pt x="476" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="796" y="1360" on="1"/>
+ <pt x="569" y="1360" on="0"/>
+ <pt x="443" y="1197" on="1"/>
+ <pt x="317" y="1034" on="0"/>
+ <pt x="317" y="741" on="1"/>
+ <pt x="317" y="450" on="0"/>
+ <pt x="443" y="285" on="1"/>
+ <pt x="568" y="120" on="0"/>
+ <pt x="791" y="120" on="1"/>
+ <pt x="998" y="120" on="0"/>
+ <pt x="1121" y="252" on="1"/>
+ <pt x="1275" y="415" on="0"/>
+ <pt x="1275" y="742" on="1"/>
+ <pt x="1275" y="1034" on="0"/>
+ <pt x="1148" y="1197" on="1"/>
+ <pt x="1021" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="944" y="1604" on="1"/>
+ <pt x="796" y="1604" on="1"/>
+ <pt x="475" y="1925" on="1"/>
+ <pt x="703" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 39 values pushed */
+ 0 0 24 29 8 16 29 0 48 196 8 2 0 0 35 34 1 33 32 1 2 0 14 0 0
+ 28 26 4 20 26 12 48 196 35 34 33 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ohungarumlaut" xMin="93" yMin="-37" xMax="1501" yMax="1925">
+ <contour>
+ <pt x="797" y="1517" on="1"/>
+ <pt x="1116" y="1517" on="0"/>
+ <pt x="1309" y="1306" on="1"/>
+ <pt x="1501" y="1094" on="0"/>
+ <pt x="1501" y="742" on="1"/>
+ <pt x="1501" y="383" on="0"/>
+ <pt x="1309" y="173" on="1"/>
+ <pt x="1116" y="-37" on="0"/>
+ <pt x="787" y="-37" on="1"/>
+ <pt x="505" y="-37" on="0"/>
+ <pt x="322" y="136" on="1"/>
+ <pt x="93" y="353" on="0"/>
+ <pt x="93" y="740" on="1"/>
+ <pt x="93" y="1095" on="0"/>
+ <pt x="285" y="1306" on="1"/>
+ <pt x="477" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="797" y="1360" on="1"/>
+ <pt x="570" y="1360" on="0"/>
+ <pt x="444" y="1197" on="1"/>
+ <pt x="318" y="1034" on="0"/>
+ <pt x="318" y="741" on="1"/>
+ <pt x="318" y="450" on="0"/>
+ <pt x="444" y="285" on="1"/>
+ <pt x="569" y="120" on="0"/>
+ <pt x="792" y="120" on="1"/>
+ <pt x="999" y="120" on="0"/>
+ <pt x="1122" y="252" on="1"/>
+ <pt x="1276" y="415" on="0"/>
+ <pt x="1276" y="742" on="1"/>
+ <pt x="1276" y="1034" on="0"/>
+ <pt x="1149" y="1197" on="1"/>
+ <pt x="1022" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="566" y="1604" on="1"/>
+ <pt x="807" y="1925" on="1"/>
+ <pt x="998" y="1925" on="1"/>
+ <pt x="677" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="918" y="1604" on="1"/>
+ <pt x="1158" y="1925" on="1"/>
+ <pt x="1349" y="1925" on="1"/>
+ <pt x="1029" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 51 values pushed */
+ 0 0 24 29 8 16 29 0 48 196 8 2 0 0 1 39 36 35 32 4 33 0 3 0 38
+ 37 34 33 3 0 14 0 0 28 26 4 20 26 12 48 196 39 38 37 36 35 34 33 32 12
+ 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Omacron" xMin="93" yMin="-37" xMax="1501" yMax="1752">
+ <contour>
+ <pt x="797" y="1517" on="1"/>
+ <pt x="1116" y="1517" on="0"/>
+ <pt x="1309" y="1306" on="1"/>
+ <pt x="1501" y="1094" on="0"/>
+ <pt x="1501" y="742" on="1"/>
+ <pt x="1501" y="383" on="0"/>
+ <pt x="1309" y="173" on="1"/>
+ <pt x="1116" y="-37" on="0"/>
+ <pt x="787" y="-37" on="1"/>
+ <pt x="505" y="-37" on="0"/>
+ <pt x="322" y="136" on="1"/>
+ <pt x="93" y="353" on="0"/>
+ <pt x="93" y="740" on="1"/>
+ <pt x="93" y="1095" on="0"/>
+ <pt x="285" y="1306" on="1"/>
+ <pt x="477" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="797" y="1360" on="1"/>
+ <pt x="570" y="1360" on="0"/>
+ <pt x="444" y="1197" on="1"/>
+ <pt x="318" y="1034" on="0"/>
+ <pt x="318" y="741" on="1"/>
+ <pt x="318" y="450" on="0"/>
+ <pt x="444" y="285" on="1"/>
+ <pt x="569" y="120" on="0"/>
+ <pt x="792" y="120" on="1"/>
+ <pt x="999" y="120" on="0"/>
+ <pt x="1122" y="252" on="1"/>
+ <pt x="1276" y="415" on="0"/>
+ <pt x="1276" y="742" on="1"/>
+ <pt x="1276" y="1034" on="0"/>
+ <pt x="1149" y="1197" on="1"/>
+ <pt x="1022" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="476" y="1604" on="1"/>
+ <pt x="476" y="1752" on="1"/>
+ <pt x="1118" y="1752" on="1"/>
+ <pt x="1118" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 0 0 24 29 8 16 29 0 48 196 8 2 0 0 0 0 35 32 7 1 33 1 4 48 196
+ 34 33 1 0 14 0 0 28 26 4 20 26 12 48 196 4 34 12 32 35 34 1 33 32 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Oslash" xMin="93" yMin="-37" xMax="1501" yMax="1517">
+ <contour>
+ <pt x="104" y="-37" on="1"/>
+ <pt x="278" y="184" on="1"/>
+ <pt x="196" y="286" on="0"/>
+ <pt x="154" y="390" on="1"/>
+ <pt x="93" y="545" on="0"/>
+ <pt x="93" y="742" on="1"/>
+ <pt x="93" y="1094" on="0"/>
+ <pt x="285" y="1306" on="1"/>
+ <pt x="476" y="1517" on="0"/>
+ <pt x="795" y="1517" on="1"/>
+ <pt x="1038" y="1517" on="0"/>
+ <pt x="1223" y="1384" on="1"/>
+ <pt x="1329" y="1517" on="1"/>
+ <pt x="1501" y="1517" on="1"/>
+ <pt x="1322" y="1290" on="1"/>
+ <pt x="1401" y="1188" on="0"/>
+ <pt x="1442" y="1085" on="1"/>
+ <pt x="1501" y="932" on="0"/>
+ <pt x="1501" y="738" on="1"/>
+ <pt x="1501" y="385" on="0"/>
+ <pt x="1309" y="174" on="1"/>
+ <pt x="1118" y="-37" on="0"/>
+ <pt x="798" y="-37" on="1"/>
+ <pt x="563" y="-37" on="0"/>
+ <pt x="378" y="91" on="1"/>
+ <pt x="276" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="491" y="235" on="1"/>
+ <pt x="621" y="120" on="0"/>
+ <pt x="798" y="120" on="1"/>
+ <pt x="1023" y="120" on="0"/>
+ <pt x="1149" y="283" on="1"/>
+ <pt x="1276" y="446" on="0"/>
+ <pt x="1276" y="737" on="1"/>
+ <pt x="1276" y="969" on="0"/>
+ <pt x="1194" y="1127" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1110" y="1240" on="1"/>
+ <pt x="976" y="1360" on="0"/>
+ <pt x="796" y="1360" on="1"/>
+ <pt x="571" y="1360" on="0"/>
+ <pt x="445" y="1197" on="1"/>
+ <pt x="318" y="1034" on="0"/>
+ <pt x="318" y="743" on="1"/>
+ <pt x="318" y="507" on="0"/>
+ <pt x="405" y="345" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 37 29 9 28 29 22 48 196 22 2 9 0 1 1 35 34 14 11 4 0 1 3 0
+ 0 1 1 43 26 24 1 4 1 2 3 0 0 13 12 1 25 0 1 2 0 14 0 0 41
+ 26 5 32 26 18 48 196 43 35 34 26 25 24 18 14 13 12 11 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Otilde" xMin="92" yMin="-37" xMax="1500" yMax="1838">
+ <contour>
+ <pt x="796" y="1517" on="1"/>
+ <pt x="1115" y="1517" on="0"/>
+ <pt x="1308" y="1306" on="1"/>
+ <pt x="1500" y="1094" on="0"/>
+ <pt x="1500" y="742" on="1"/>
+ <pt x="1500" y="383" on="0"/>
+ <pt x="1308" y="173" on="1"/>
+ <pt x="1115" y="-37" on="0"/>
+ <pt x="786" y="-37" on="1"/>
+ <pt x="504" y="-37" on="0"/>
+ <pt x="321" y="136" on="1"/>
+ <pt x="92" y="353" on="0"/>
+ <pt x="92" y="740" on="1"/>
+ <pt x="92" y="1095" on="0"/>
+ <pt x="284" y="1306" on="1"/>
+ <pt x="476" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="796" y="1360" on="1"/>
+ <pt x="569" y="1360" on="0"/>
+ <pt x="443" y="1197" on="1"/>
+ <pt x="317" y="1034" on="0"/>
+ <pt x="317" y="741" on="1"/>
+ <pt x="317" y="450" on="0"/>
+ <pt x="443" y="285" on="1"/>
+ <pt x="568" y="120" on="0"/>
+ <pt x="791" y="120" on="1"/>
+ <pt x="998" y="120" on="0"/>
+ <pt x="1121" y="252" on="1"/>
+ <pt x="1275" y="415" on="0"/>
+ <pt x="1275" y="742" on="1"/>
+ <pt x="1275" y="1034" on="0"/>
+ <pt x="1148" y="1197" on="1"/>
+ <pt x="1021" y="1360" on="0"/>
+ </contour>
+ <contour>
+ <pt x="463" y="1604" on="1"/>
+ <pt x="470" y="1697" on="0"/>
+ <pt x="495" y="1748" on="1"/>
+ <pt x="541" y="1838" on="0"/>
+ <pt x="650" y="1838" on="1"/>
+ <pt x="722" y="1838" on="0"/>
+ <pt x="783" y="1800" on="1"/>
+ <pt x="843" y="1763" on="1"/>
+ <pt x="900" y="1728" on="0"/>
+ <pt x="930" y="1728" on="1"/>
+ <pt x="995" y="1728" on="0"/>
+ <pt x="1006" y="1838" on="1"/>
+ <pt x="1129" y="1838" on="1"/>
+ <pt x="1122" y="1744" on="0"/>
+ <pt x="1097" y="1694" on="1"/>
+ <pt x="1052" y="1604" on="0"/>
+ <pt x="944" y="1604" on="1"/>
+ <pt x="872" y="1604" on="0"/>
+ <pt x="809" y="1643" on="1"/>
+ <pt x="749" y="1680" on="1"/>
+ <pt x="694" y="1714" on="0"/>
+ <pt x="662" y="1714" on="1"/>
+ <pt x="597" y="1714" on="0"/>
+ <pt x="586" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 0 0 53 6 36 41 6 48 24 29 8 16 29 0 48 196 8 2 0 0 1 55 44 43 32
+ 4 13 48 36 0 0 14 0 0 28 26 4 20 26 12 48 196 55 44 43 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="P" xMin="167" yMin="0" xMax="1318" yMax="1480">
+ <contour>
+ <pt x="167" y="0" on="1"/>
+ <pt x="167" y="1480" on="1"/>
+ <pt x="747" y="1480" on="1"/>
+ <pt x="976" y="1480" on="0"/>
+ <pt x="1075" y="1454" on="1"/>
+ <pt x="1176" y="1427" on="0"/>
+ <pt x="1239" y="1351" on="1"/>
+ <pt x="1318" y="1255" on="0"/>
+ <pt x="1318" y="1089" on="1"/>
+ <pt x="1318" y="588" on="0"/>
+ <pt x="685" y="588" on="1"/>
+ <pt x="377" y="588" on="1"/>
+ <pt x="377" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="377" y="747" on="1"/>
+ <pt x="676" y="747" on="1"/>
+ <pt x="1096" y="747" on="0"/>
+ <pt x="1096" y="1076" on="1"/>
+ <pt x="1096" y="1236" on="0"/>
+ <pt x="987" y="1283" on="1"/>
+ <pt x="894" y="1323" on="0"/>
+ <pt x="681" y="1323" on="1"/>
+ <pt x="377" y="1323" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 0 0 21 20 15 1 1 11 10 15 1 13 2 4 48 196 14 13 1 12 0 1 2 0 2
+ 1 0 14 0 0 16 26 8 48 196 20 14 10 2 4 13 8 11 0 0 21 13 12 11 33
+ 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Q" xMin="93" yMin="-296" xMax="1639" yMax="1517">
+ <contour>
+ <pt x="1639" y="-129" on="1"/>
+ <pt x="1506" y="-296" on="1"/>
+ <pt x="1156" y="-181" on="0"/>
+ <pt x="922" y="-27" on="1"/>
+ <pt x="819" y="-38" on="0"/>
+ <pt x="765" y="-38" on="1"/>
+ <pt x="471" y="-38" on="0"/>
+ <pt x="282" y="180" on="1"/>
+ <pt x="93" y="397" on="0"/>
+ <pt x="93" y="741" on="1"/>
+ <pt x="93" y="1093" on="0"/>
+ <pt x="284" y="1305" on="1"/>
+ <pt x="475" y="1517" on="0"/>
+ <pt x="794" y="1517" on="1"/>
+ <pt x="1116" y="1517" on="0"/>
+ <pt x="1309" y="1305" on="1"/>
+ <pt x="1502" y="1094" on="0"/>
+ <pt x="1502" y="738" on="1"/>
+ <pt x="1502" y="427" on="0"/>
+ <pt x="1356" y="231" on="1"/>
+ <pt x="1300" y="155" on="0"/>
+ <pt x="1227" y="100" on="1"/>
+ <pt x="1189" y="72" on="0"/>
+ <pt x="1114" y="30" on="1"/>
+ <pt x="1360" y="-80" on="0"/>
+ </contour>
+ <contour>
+ <pt x="793" y="1360" on="1"/>
+ <pt x="570" y="1360" on="0"/>
+ <pt x="444" y="1195" on="1"/>
+ <pt x="318" y="1031" on="0"/>
+ <pt x="318" y="740" on="1"/>
+ <pt x="318" y="450" on="0"/>
+ <pt x="444" y="285" on="1"/>
+ <pt x="570" y="120" on="0"/>
+ <pt x="793" y="120" on="1"/>
+ <pt x="1018" y="120" on="0"/>
+ <pt x="1147" y="282" on="1"/>
+ <pt x="1276" y="444" on="0"/>
+ <pt x="1276" y="734" on="1"/>
+ <pt x="1276" y="1003" on="0"/>
+ <pt x="1173" y="1163" on="1"/>
+ <pt x="1046" y="1360" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 33 29 5 25 29 13 48 196 13 0 5 2 1 1 23 0 2 2 0 0 1 3 1
+ 0 3 13 2 0 14 0 0 37 26 17 29 26 9 48 196 23 17 9 3 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="R" xMin="165" yMin="0" xMax="1434" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="783" y="1480" on="1"/>
+ <pt x="1239" y="1480" on="0"/>
+ <pt x="1239" y="1113" on="1"/>
+ <pt x="1239" y="933" on="0"/>
+ <pt x="1128" y="817" on="1"/>
+ <pt x="1063" y="748" on="0"/>
+ <pt x="940" y="693" on="1"/>
+ <pt x="1434" y="0" on="1"/>
+ <pt x="1176" y="0" on="1"/>
+ <pt x="755" y="626" on="1"/>
+ <pt x="375" y="626" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="783" on="1"/>
+ <pt x="610" y="783" on="1"/>
+ <pt x="824" y="783" on="0"/>
+ <pt x="923" y="857" on="1"/>
+ <pt x="1023" y="932" on="0"/>
+ <pt x="1023" y="1089" on="1"/>
+ <pt x="1023" y="1216" on="0"/>
+ <pt x="942" y="1269" on="1"/>
+ <pt x="862" y="1323" on="0"/>
+ <pt x="675" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 69 values pushed */
+ 8 14 11 2 0 0 24 23 15 1 1 12 11 15 1 14 2 4 48 196 15 14 1 13 10
+ 9 0 3 2 0 2 1 0 14 0 0 19 9 4 48 196 23 15 11 10 9 8 2 7 13
+ 4 12 0 0 24 14 13 12 33 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Racute" xMin="165" yMin="0" xMax="1434" yMax="1925">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="783" y="1480" on="1"/>
+ <pt x="1239" y="1480" on="0"/>
+ <pt x="1239" y="1113" on="1"/>
+ <pt x="1239" y="933" on="0"/>
+ <pt x="1128" y="817" on="1"/>
+ <pt x="1063" y="748" on="0"/>
+ <pt x="940" y="693" on="1"/>
+ <pt x="1434" y="0" on="1"/>
+ <pt x="1176" y="0" on="1"/>
+ <pt x="755" y="626" on="1"/>
+ <pt x="375" y="626" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="783" on="1"/>
+ <pt x="610" y="783" on="1"/>
+ <pt x="824" y="783" on="0"/>
+ <pt x="923" y="857" on="1"/>
+ <pt x="1023" y="932" on="0"/>
+ <pt x="1023" y="1089" on="1"/>
+ <pt x="1023" y="1216" on="0"/>
+ <pt x="942" y="1269" on="1"/>
+ <pt x="862" y="1323" on="0"/>
+ <pt x="675" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ </contour>
+ <contour>
+ <pt x="523" y="1604" on="1"/>
+ <pt x="764" y="1925" on="1"/>
+ <pt x="992" y="1925" on="1"/>
+ <pt x="671" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 8 14 11 2 0 0 24 23 15 1 1 12 11 15 1 14 2 4 48 196 27 26 1 28 25
+ 1 15 14 1 13 10 9 0 3 4 0 2 1 0 14 0 0 19 9 4 48 196 28 27 26
+ 25 23 15 11 10 9 8 2 11 13 4 12 0 0 24 14 13 12 33 3 0 1 4 48 196
+ 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Rcaron" xMin="165" yMin="0" xMax="1434" yMax="1925">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="783" y="1480" on="1"/>
+ <pt x="1239" y="1480" on="0"/>
+ <pt x="1239" y="1113" on="1"/>
+ <pt x="1239" y="933" on="0"/>
+ <pt x="1128" y="817" on="1"/>
+ <pt x="1063" y="748" on="0"/>
+ <pt x="940" y="693" on="1"/>
+ <pt x="1434" y="0" on="1"/>
+ <pt x="1176" y="0" on="1"/>
+ <pt x="755" y="626" on="1"/>
+ <pt x="375" y="626" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="783" on="1"/>
+ <pt x="610" y="783" on="1"/>
+ <pt x="824" y="783" on="0"/>
+ <pt x="923" y="857" on="1"/>
+ <pt x="1023" y="932" on="0"/>
+ <pt x="1023" y="1089" on="1"/>
+ <pt x="1023" y="1216" on="0"/>
+ <pt x="942" y="1269" on="1"/>
+ <pt x="862" y="1323" on="0"/>
+ <pt x="675" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ </contour>
+ <contour>
+ <pt x="982" y="1925" on="1"/>
+ <pt x="741" y="1604" on="1"/>
+ <pt x="523" y="1604" on="1"/>
+ <pt x="282" y="1925" on="1"/>
+ <pt x="430" y="1925" on="1"/>
+ <pt x="631" y="1723" on="1"/>
+ <pt x="633" y="1723" on="1"/>
+ <pt x="834" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 94 values pushed */
+ 31 30 2 25 26 3 8 14 11 2 0 0 24 23 15 1 1 12 11 15 1 14 2 4 48
+ 196 32 29 28 25 3 27 26 1 15 14 1 13 10 9 0 3 4 0 2 1 0 14 0 0
+ 19 9 4 48 196 28 12 0 2 32 31 30 29 27 26 25 23 15 11 10 9 8 2 14 13
+ 4 12 0 0 24 14 13 12 33 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Rcommaaccent" xMin="165" yMin="-432" xMax="1434" yMax="1480">
+ <contour>
+ <pt x="165" y="0" on="1"/>
+ <pt x="165" y="1480" on="1"/>
+ <pt x="783" y="1480" on="1"/>
+ <pt x="1239" y="1480" on="0"/>
+ <pt x="1239" y="1113" on="1"/>
+ <pt x="1239" y="933" on="0"/>
+ <pt x="1128" y="817" on="1"/>
+ <pt x="1063" y="748" on="0"/>
+ <pt x="940" y="693" on="1"/>
+ <pt x="1434" y="0" on="1"/>
+ <pt x="1176" y="0" on="1"/>
+ <pt x="755" y="626" on="1"/>
+ <pt x="375" y="626" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="783" on="1"/>
+ <pt x="610" y="783" on="1"/>
+ <pt x="824" y="783" on="0"/>
+ <pt x="923" y="857" on="1"/>
+ <pt x="1023" y="932" on="0"/>
+ <pt x="1023" y="1089" on="1"/>
+ <pt x="1023" y="1216" on="0"/>
+ <pt x="942" y="1269" on="1"/>
+ <pt x="862" y="1323" on="0"/>
+ <pt x="675" y="1323" on="1"/>
+ <pt x="375" y="1323" on="1"/>
+ </contour>
+ <contour>
+ <pt x="523" y="-421" on="1"/>
+ <pt x="523" y="-336" on="1"/>
+ <pt x="580" y="-345" on="0"/>
+ <pt x="620" y="-345" on="1"/>
+ <pt x="730" y="-345" on="0"/>
+ <pt x="730" y="-278" on="1"/>
+ <pt x="730" y="-204" on="0"/>
+ <pt x="572" y="-188" on="1"/>
+ <pt x="572" y="-111" on="1"/>
+ <pt x="706" y="-114" on="0"/>
+ <pt x="772" y="-143" on="1"/>
+ <pt x="865" y="-185" on="0"/>
+ <pt x="865" y="-280" on="1"/>
+ <pt x="865" y="-432" on="0"/>
+ <pt x="648" y="-432" on="1"/>
+ <pt x="589" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 0 0 28 44 39 48 196 8 14 11 2 33 32 26 25 4 13 39 0 0 0 24 23 15 1
+ 1 12 11 15 1 14 2 4 48 196 15 14 1 13 10 9 0 3 2 0 2 1 0 14 0
+ 0 30 42 37 19 9 4 48 196 33 32 26 25 23 15 11 10 9 8 2 11 13 37 4 12
+ 0 0 24 14 13 12 33 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="S" xMin="120" yMin="-37" xMax="1243" yMax="1517">
+ <contour>
+ <pt x="120" y="52" on="1"/>
+ <pt x="120" y="260" on="1"/>
+ <pt x="416" y="120" on="0"/>
+ <pt x="704" y="120" on="1"/>
+ <pt x="1027" y="120" on="0"/>
+ <pt x="1027" y="359" on="1"/>
+ <pt x="1027" y="483" on="0"/>
+ <pt x="938" y="541" on="1"/>
+ <pt x="869" y="587" on="0"/>
+ <pt x="716" y="637" on="1"/>
+ <pt x="515" y="703" on="1"/>
+ <pt x="128" y="830" on="0"/>
+ <pt x="128" y="1122" on="1"/>
+ <pt x="128" y="1517" on="0"/>
+ <pt x="670" y="1517" on="1"/>
+ <pt x="902" y="1517" on="0"/>
+ <pt x="1151" y="1454" on="1"/>
+ <pt x="1151" y="1261" on="1"/>
+ <pt x="891" y="1360" on="0"/>
+ <pt x="657" y="1360" on="1"/>
+ <pt x="331" y="1360" on="0"/>
+ <pt x="331" y="1138" on="1"/>
+ <pt x="331" y="1051" on="0"/>
+ <pt x="392" y="998" on="1"/>
+ <pt x="455" y="943" on="0"/>
+ <pt x="614" y="891" on="1"/>
+ <pt x="820" y="824" on="1"/>
+ <pt x="1053" y="748" on="0"/>
+ <pt x="1148" y="650" on="1"/>
+ <pt x="1243" y="553" on="0"/>
+ <pt x="1243" y="390" on="1"/>
+ <pt x="1243" y="193" on="0"/>
+ <pt x="1097" y="78" on="1"/>
+ <pt x="952" y="-37" on="0"/>
+ <pt x="696" y="-37" on="1"/>
+ <pt x="444" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 0 0 19 29 14 3 29 34 48 196 34 2 14 0 1 1 17 16 1 0 4 0 2 3 0
+ 0 14 0 0 21 43 12 5 9 30 48 196 12 12 16 0 2 30 16 17 16 1 1 0 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Sacute" xMin="120" yMin="-37" xMax="1243" yMax="1925">
+ <contour>
+ <pt x="120" y="52" on="1"/>
+ <pt x="120" y="260" on="1"/>
+ <pt x="416" y="120" on="0"/>
+ <pt x="704" y="120" on="1"/>
+ <pt x="1027" y="120" on="0"/>
+ <pt x="1027" y="359" on="1"/>
+ <pt x="1027" y="483" on="0"/>
+ <pt x="938" y="541" on="1"/>
+ <pt x="869" y="587" on="0"/>
+ <pt x="716" y="637" on="1"/>
+ <pt x="515" y="703" on="1"/>
+ <pt x="128" y="830" on="0"/>
+ <pt x="128" y="1122" on="1"/>
+ <pt x="128" y="1517" on="0"/>
+ <pt x="670" y="1517" on="1"/>
+ <pt x="902" y="1517" on="0"/>
+ <pt x="1151" y="1454" on="1"/>
+ <pt x="1151" y="1261" on="1"/>
+ <pt x="891" y="1360" on="0"/>
+ <pt x="657" y="1360" on="1"/>
+ <pt x="331" y="1360" on="0"/>
+ <pt x="331" y="1138" on="1"/>
+ <pt x="331" y="1051" on="0"/>
+ <pt x="392" y="998" on="1"/>
+ <pt x="455" y="943" on="0"/>
+ <pt x="614" y="891" on="1"/>
+ <pt x="820" y="824" on="1"/>
+ <pt x="1053" y="748" on="0"/>
+ <pt x="1148" y="650" on="1"/>
+ <pt x="1243" y="553" on="0"/>
+ <pt x="1243" y="390" on="1"/>
+ <pt x="1243" y="193" on="0"/>
+ <pt x="1097" y="78" on="1"/>
+ <pt x="952" y="-37" on="0"/>
+ <pt x="696" y="-37" on="1"/>
+ <pt x="444" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="523" y="1604" on="1"/>
+ <pt x="764" y="1925" on="1"/>
+ <pt x="992" y="1925" on="1"/>
+ <pt x="671" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 19 29 14 3 29 34 48 196 34 2 14 0 1 1 17 16 1 0 4 0 2 3 0
+ 0 38 37 1 39 36 1 2 0 14 0 0 21 43 12 5 9 30 48 196 12 39 38 37 36
+ 12 5 16 0 3 30 16 17 16 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scaron" xMin="120" yMin="-37" xMax="1243" yMax="1925">
+ <contour>
+ <pt x="120" y="52" on="1"/>
+ <pt x="120" y="260" on="1"/>
+ <pt x="416" y="120" on="0"/>
+ <pt x="704" y="120" on="1"/>
+ <pt x="1027" y="120" on="0"/>
+ <pt x="1027" y="359" on="1"/>
+ <pt x="1027" y="483" on="0"/>
+ <pt x="938" y="541" on="1"/>
+ <pt x="869" y="587" on="0"/>
+ <pt x="716" y="637" on="1"/>
+ <pt x="515" y="703" on="1"/>
+ <pt x="128" y="830" on="0"/>
+ <pt x="128" y="1122" on="1"/>
+ <pt x="128" y="1517" on="0"/>
+ <pt x="670" y="1517" on="1"/>
+ <pt x="902" y="1517" on="0"/>
+ <pt x="1151" y="1454" on="1"/>
+ <pt x="1151" y="1261" on="1"/>
+ <pt x="891" y="1360" on="0"/>
+ <pt x="657" y="1360" on="1"/>
+ <pt x="331" y="1360" on="0"/>
+ <pt x="331" y="1138" on="1"/>
+ <pt x="331" y="1051" on="0"/>
+ <pt x="392" y="998" on="1"/>
+ <pt x="455" y="943" on="0"/>
+ <pt x="614" y="891" on="1"/>
+ <pt x="820" y="824" on="1"/>
+ <pt x="1053" y="748" on="0"/>
+ <pt x="1148" y="650" on="1"/>
+ <pt x="1243" y="553" on="0"/>
+ <pt x="1243" y="390" on="1"/>
+ <pt x="1243" y="193" on="0"/>
+ <pt x="1097" y="78" on="1"/>
+ <pt x="952" y="-37" on="0"/>
+ <pt x="696" y="-37" on="1"/>
+ <pt x="444" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1021" y="1925" on="1"/>
+ <pt x="780" y="1604" on="1"/>
+ <pt x="562" y="1604" on="1"/>
+ <pt x="321" y="1925" on="1"/>
+ <pt x="469" y="1925" on="1"/>
+ <pt x="670" y="1723" on="1"/>
+ <pt x="672" y="1723" on="1"/>
+ <pt x="873" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 19 29 14 3 29 34 48 196 34 2 14 0 42 41 2 36 37 3 1 1 17 16 1
+ 0 4 0 2 3 0 0 43 40 39 36 3 38 37 1 2 0 14 0 0 21 43 12 5 9
+ 30 48 196 12 43 42 41 40 39 38 37 36 12 9 16 0 3 30 16 17 16 1 1 0 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scedilla" xMin="120" yMin="-432" xMax="1243" yMax="1517">
+ <contour>
+ <pt x="120" y="52" on="1"/>
+ <pt x="120" y="260" on="1"/>
+ <pt x="416" y="120" on="0"/>
+ <pt x="704" y="120" on="1"/>
+ <pt x="1027" y="120" on="0"/>
+ <pt x="1027" y="359" on="1"/>
+ <pt x="1027" y="483" on="0"/>
+ <pt x="938" y="541" on="1"/>
+ <pt x="870" y="587" on="0"/>
+ <pt x="716" y="637" on="1"/>
+ <pt x="515" y="703" on="1"/>
+ <pt x="128" y="830" on="0"/>
+ <pt x="128" y="1122" on="1"/>
+ <pt x="128" y="1517" on="0"/>
+ <pt x="670" y="1517" on="1"/>
+ <pt x="902" y="1517" on="0"/>
+ <pt x="1151" y="1454" on="1"/>
+ <pt x="1151" y="1261" on="1"/>
+ <pt x="891" y="1360" on="0"/>
+ <pt x="657" y="1360" on="1"/>
+ <pt x="331" y="1360" on="0"/>
+ <pt x="331" y="1138" on="1"/>
+ <pt x="331" y="1051" on="0"/>
+ <pt x="392" y="998" on="1"/>
+ <pt x="455" y="943" on="0"/>
+ <pt x="614" y="891" on="1"/>
+ <pt x="820" y="824" on="1"/>
+ <pt x="1053" y="748" on="0"/>
+ <pt x="1148" y="650" on="1"/>
+ <pt x="1243" y="553" on="0"/>
+ <pt x="1243" y="391" on="1"/>
+ <pt x="1243" y="192" on="0"/>
+ <pt x="1097" y="78" on="1"/>
+ <pt x="951" y="-37" on="0"/>
+ <pt x="696" y="-37" on="1"/>
+ <pt x="444" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="601" y="0" on="1"/>
+ <pt x="698" y="0" on="1"/>
+ <pt x="638" y="-109" on="1"/>
+ <pt x="710" y="-111" on="0"/>
+ <pt x="762" y="-148" on="1"/>
+ <pt x="832" y="-197" on="0"/>
+ <pt x="832" y="-269" on="1"/>
+ <pt x="832" y="-337" on="0"/>
+ <pt x="773" y="-384" on="1"/>
+ <pt x="714" y="-432" on="0"/>
+ <pt x="629" y="-432" on="1"/>
+ <pt x="562" y="-432" on="0"/>
+ <pt x="485" y="-411" on="1"/>
+ <pt x="485" y="-330" on="1"/>
+ <pt x="535" y="-345" on="0"/>
+ <pt x="589" y="-345" on="1"/>
+ <pt x="693" y="-345" on="0"/>
+ <pt x="693" y="-271" on="1"/>
+ <pt x="693" y="-178" on="0"/>
+ <pt x="506" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 0 0 51 44 46 19 29 14 3 29 34 48 196 34 2 14 0 1 1 17 16 1 0 4 0
+ 2 3 0 0 1 55 49 48 38 37 36 6 13 46 2 0 14 0 0 53 42 42 21 43 12
+ 5 9 30 48 196 42 12 55 49 48 42 38 37 36 12 8 16 0 3 30 16 17 16 1 1
+ 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scircumflex" xMin="120" yMin="-37" xMax="1243" yMax="1925">
+ <contour>
+ <pt x="120" y="52" on="1"/>
+ <pt x="120" y="260" on="1"/>
+ <pt x="416" y="120" on="0"/>
+ <pt x="704" y="120" on="1"/>
+ <pt x="1027" y="120" on="0"/>
+ <pt x="1027" y="359" on="1"/>
+ <pt x="1027" y="483" on="0"/>
+ <pt x="938" y="541" on="1"/>
+ <pt x="869" y="587" on="0"/>
+ <pt x="716" y="637" on="1"/>
+ <pt x="515" y="703" on="1"/>
+ <pt x="128" y="830" on="0"/>
+ <pt x="128" y="1122" on="1"/>
+ <pt x="128" y="1517" on="0"/>
+ <pt x="670" y="1517" on="1"/>
+ <pt x="902" y="1517" on="0"/>
+ <pt x="1151" y="1454" on="1"/>
+ <pt x="1151" y="1261" on="1"/>
+ <pt x="891" y="1360" on="0"/>
+ <pt x="657" y="1360" on="1"/>
+ <pt x="331" y="1360" on="0"/>
+ <pt x="331" y="1138" on="1"/>
+ <pt x="331" y="1051" on="0"/>
+ <pt x="392" y="998" on="1"/>
+ <pt x="455" y="943" on="0"/>
+ <pt x="614" y="891" on="1"/>
+ <pt x="820" y="824" on="1"/>
+ <pt x="1053" y="748" on="0"/>
+ <pt x="1148" y="650" on="1"/>
+ <pt x="1243" y="553" on="0"/>
+ <pt x="1243" y="390" on="1"/>
+ <pt x="1243" y="193" on="0"/>
+ <pt x="1097" y="78" on="1"/>
+ <pt x="952" y="-37" on="0"/>
+ <pt x="696" y="-37" on="1"/>
+ <pt x="444" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="321" y="1604" on="1"/>
+ <pt x="562" y="1925" on="1"/>
+ <pt x="780" y="1925" on="1"/>
+ <pt x="1021" y="1604" on="1"/>
+ <pt x="873" y="1604" on="1"/>
+ <pt x="672" y="1806" on="1"/>
+ <pt x="670" y="1806" on="1"/>
+ <pt x="469" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 19 29 14 3 29 34 48 196 34 2 14 0 42 41 2 37 36 3 1 1 17 16 1
+ 0 4 0 2 3 0 0 38 37 1 43 40 39 36 3 2 0 14 0 0 21 43 12 5 9
+ 30 48 196 12 43 42 41 40 39 38 37 36 12 9 16 0 3 30 16 17 16 1 1 0 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Scommaaccent" xMin="120" yMin="-432" xMax="1243" yMax="1517">
+ <contour>
+ <pt x="120" y="52" on="1"/>
+ <pt x="120" y="260" on="1"/>
+ <pt x="416" y="120" on="0"/>
+ <pt x="704" y="120" on="1"/>
+ <pt x="1027" y="120" on="0"/>
+ <pt x="1027" y="359" on="1"/>
+ <pt x="1027" y="483" on="0"/>
+ <pt x="938" y="541" on="1"/>
+ <pt x="870" y="587" on="0"/>
+ <pt x="716" y="637" on="1"/>
+ <pt x="515" y="703" on="1"/>
+ <pt x="128" y="830" on="0"/>
+ <pt x="128" y="1122" on="1"/>
+ <pt x="128" y="1517" on="0"/>
+ <pt x="670" y="1517" on="1"/>
+ <pt x="902" y="1517" on="0"/>
+ <pt x="1151" y="1454" on="1"/>
+ <pt x="1151" y="1261" on="1"/>
+ <pt x="891" y="1360" on="0"/>
+ <pt x="657" y="1360" on="1"/>
+ <pt x="331" y="1360" on="0"/>
+ <pt x="331" y="1138" on="1"/>
+ <pt x="331" y="1051" on="0"/>
+ <pt x="392" y="998" on="1"/>
+ <pt x="455" y="943" on="0"/>
+ <pt x="614" y="891" on="1"/>
+ <pt x="820" y="824" on="1"/>
+ <pt x="1053" y="748" on="0"/>
+ <pt x="1148" y="650" on="1"/>
+ <pt x="1243" y="553" on="0"/>
+ <pt x="1243" y="391" on="1"/>
+ <pt x="1243" y="192" on="0"/>
+ <pt x="1097" y="78" on="1"/>
+ <pt x="951" y="-37" on="0"/>
+ <pt x="696" y="-37" on="1"/>
+ <pt x="444" y="-37" on="0"/>
+ </contour>
+ <contour>
+ <pt x="524" y="-421" on="1"/>
+ <pt x="524" y="-336" on="1"/>
+ <pt x="581" y="-345" on="0"/>
+ <pt x="621" y="-345" on="1"/>
+ <pt x="731" y="-345" on="0"/>
+ <pt x="731" y="-278" on="1"/>
+ <pt x="731" y="-204" on="0"/>
+ <pt x="573" y="-188" on="1"/>
+ <pt x="573" y="-111" on="1"/>
+ <pt x="707" y="-114" on="0"/>
+ <pt x="773" y="-143" on="1"/>
+ <pt x="866" y="-185" on="0"/>
+ <pt x="866" y="-280" on="1"/>
+ <pt x="866" y="-432" on="0"/>
+ <pt x="649" y="-432" on="1"/>
+ <pt x="590" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 39 44 50 19 29 14 3 29 34 48 196 34 2 14 0 1 1 17 16 1 0 4 0
+ 2 3 0 0 1 44 43 37 36 4 13 50 2 0 14 0 0 41 42 48 21 43 12 5 9
+ 30 48 196 48 12 48 44 43 37 36 12 6 16 0 3 30 16 17 16 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="T" xMin="20" yMin="0" xMax="1230" yMax="1480">
+ <contour>
+ <pt x="520" y="0" on="1"/>
+ <pt x="520" y="1323" on="1"/>
+ <pt x="20" y="1323" on="1"/>
+ <pt x="20" y="1480" on="1"/>
+ <pt x="1230" y="1480" on="1"/>
+ <pt x="1230" y="1323" on="1"/>
+ <pt x="730" y="1323" on="1"/>
+ <pt x="730" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 6 5 2 1 15 3 3 1 4 48 196 7 0 1 0 4 3 0 14 0 0 7 6
+ 33 1 0 1 4 48 196 5 4 1 1 0 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tbar" xMin="20" yMin="0" xMax="1230" yMax="1480">
+ <contour>
+ <pt x="520" y="0" on="1"/>
+ <pt x="520" y="715" on="1"/>
+ <pt x="217" y="715" on="1"/>
+ <pt x="217" y="863" on="1"/>
+ <pt x="520" y="863" on="1"/>
+ <pt x="520" y="1323" on="1"/>
+ <pt x="20" y="1323" on="1"/>
+ <pt x="20" y="1480" on="1"/>
+ <pt x="1230" y="1480" on="1"/>
+ <pt x="1230" y="1323" on="1"/>
+ <pt x="730" y="1323" on="1"/>
+ <pt x="730" y="863" on="1"/>
+ <pt x="1033" y="863" on="1"/>
+ <pt x="1033" y="715" on="1"/>
+ <pt x="730" y="715" on="1"/>
+ <pt x="730" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 10 9 6 5 15 3 7 14 13 2 1 7 3 3 2 4 48 196 12 11 4 3 3
+ 15 0 1 2 0 8 7 0 14 0 0 15 14 11 10 33 3 0 1 4 48 196 9 8 1
+ 13 12 1 5 4 1 0 3 3 2 1 7 6 1 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcaron" xMin="20" yMin="0" xMax="1230" yMax="1925">
+ <contour>
+ <pt x="520" y="0" on="1"/>
+ <pt x="520" y="1323" on="1"/>
+ <pt x="20" y="1323" on="1"/>
+ <pt x="20" y="1480" on="1"/>
+ <pt x="1230" y="1480" on="1"/>
+ <pt x="1230" y="1323" on="1"/>
+ <pt x="730" y="1323" on="1"/>
+ <pt x="730" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="975" y="1925" on="1"/>
+ <pt x="734" y="1604" on="1"/>
+ <pt x="516" y="1604" on="1"/>
+ <pt x="275" y="1925" on="1"/>
+ <pt x="423" y="1925" on="1"/>
+ <pt x="624" y="1723" on="1"/>
+ <pt x="626" y="1723" on="1"/>
+ <pt x="827" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 78 values pushed */
+ 14 13 2 8 9 3 0 0 6 5 2 1 15 3 3 1 4 48 196 15 12 11 8 3 10
+ 9 1 7 0 1 3 0 4 3 0 14 15 9 8 3 4 6 3 14 13 2 6 0 3 12
+ 11 10 3 0 2 3 0 0 7 6 33 1 0 1 4 48 196 5 4 1 1 0 1 3 2
+ 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcommaaccent" xMin="20" yMin="-432" xMax="1230" yMax="1480">
+ <contour>
+ <pt x="520" y="0" on="1"/>
+ <pt x="520" y="1323" on="1"/>
+ <pt x="20" y="1323" on="1"/>
+ <pt x="20" y="1480" on="1"/>
+ <pt x="1230" y="1480" on="1"/>
+ <pt x="1230" y="1323" on="1"/>
+ <pt x="730" y="1323" on="1"/>
+ <pt x="730" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="586" y="0" on="1"/>
+ <pt x="683" y="0" on="1"/>
+ <pt x="623" y="-109" on="1"/>
+ <pt x="695" y="-111" on="0"/>
+ <pt x="747" y="-148" on="1"/>
+ <pt x="817" y="-197" on="0"/>
+ <pt x="817" y="-268" on="1"/>
+ <pt x="817" y="-337" on="0"/>
+ <pt x="759" y="-384" on="1"/>
+ <pt x="700" y="-432" on="0"/>
+ <pt x="614" y="-432" on="1"/>
+ <pt x="546" y="-432" on="0"/>
+ <pt x="470" y="-411" on="1"/>
+ <pt x="470" y="-330" on="1"/>
+ <pt x="520" y="-345" on="0"/>
+ <pt x="574" y="-345" on="1"/>
+ <pt x="678" y="-345" on="0"/>
+ <pt x="678" y="-271" on="1"/>
+ <pt x="678" y="-178" on="0"/>
+ <pt x="491" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 23 44 18 48 196 27 21 20 10 4 13 18 0 0 0 6 5 2 1 15 3 3 1
+ 4 48 196 9 8 7 0 3 0 4 3 0 14 0 0 25 42 14 48 196 14 14 4 6 2
+ 10 9 8 3 6 0 3 27 21 20 3 0 2 3 0 0 7 6 33 1 0 1 4 48 196
+ 5 4 1 1 0 1 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Tcommabelow" xMin="20" yMin="-432" xMax="1230" yMax="1480">
+ <contour>
+ <pt x="520" y="0" on="1"/>
+ <pt x="520" y="1323" on="1"/>
+ <pt x="20" y="1323" on="1"/>
+ <pt x="20" y="1480" on="1"/>
+ <pt x="1230" y="1480" on="1"/>
+ <pt x="1230" y="1323" on="1"/>
+ <pt x="730" y="1323" on="1"/>
+ <pt x="730" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="471" y="-421" on="1"/>
+ <pt x="471" y="-336" on="1"/>
+ <pt x="528" y="-345" on="0"/>
+ <pt x="568" y="-345" on="1"/>
+ <pt x="678" y="-345" on="0"/>
+ <pt x="678" y="-278" on="1"/>
+ <pt x="678" y="-204" on="0"/>
+ <pt x="520" y="-188" on="1"/>
+ <pt x="520" y="-111" on="1"/>
+ <pt x="654" y="-114" on="0"/>
+ <pt x="720" y="-143" on="1"/>
+ <pt x="813" y="-185" on="0"/>
+ <pt x="813" y="-280" on="1"/>
+ <pt x="813" y="-432" on="0"/>
+ <pt x="596" y="-432" on="1"/>
+ <pt x="537" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 78 values pushed */
+ 0 0 11 32 22 48 196 16 15 9 8 4 13 22 0 0 0 6 5 2 1 37 3 3 1
+ 4 48 196 7 0 1 0 4 3 0 14 0 0 13 22 20 48 196 20 20 4 6 2 9 8
+ 2 0 2 3 0 0 7 6 9 1 0 1 4 48 196 5 4 1 16 15 1 0 3 3 2
+ 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Thorn" xMin="167" yMin="0" xMax="1318" yMax="1480">
+ <contour>
+ <pt x="167" y="0" on="1"/>
+ <pt x="167" y="1480" on="1"/>
+ <pt x="377" y="1480" on="1"/>
+ <pt x="377" y="1201" on="1"/>
+ <pt x="747" y="1201" on="1"/>
+ <pt x="975" y="1201" on="0"/>
+ <pt x="1075" y="1174" on="1"/>
+ <pt x="1175" y="1148" on="0"/>
+ <pt x="1239" y="1071" on="1"/>
+ <pt x="1318" y="976" on="0"/>
+ <pt x="1318" y="810" on="1"/>
+ <pt x="1318" y="308" on="0"/>
+ <pt x="685" y="308" on="1"/>
+ <pt x="375" y="308" on="1"/>
+ <pt x="375" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="375" y="467" on="1"/>
+ <pt x="676" y="467" on="1"/>
+ <pt x="1096" y="467" on="0"/>
+ <pt x="1096" y="796" on="1"/>
+ <pt x="1096" y="956" on="0"/>
+ <pt x="987" y="1003" on="1"/>
+ <pt x="894" y="1043" on="0"/>
+ <pt x="681" y="1043" on="1"/>
+ <pt x="375" y="1043" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 0 23 22 15 1 3 16 15 15 1 12 2 4 48 196 4 3 1 13 12 1 14 0 1
+ 3 0 2 1 0 14 0 0 18 26 10 48 196 22 16 12 4 4 13 10 2 0 0 3 2
+ 33 1 0 23 15 14 13 33 3 0 2 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="U" xMin="166" yMin="-37" xMax="1312" yMax="1480">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 0 0 8 29 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0 14 13 1 0 0 3
+ 14 0 0 13 12 24 1 14 2 1 33 1 0 2 4 48 196 15 14 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uacute" xMin="166" yMin="-37" xMax="1312" yMax="1925">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="604" y="1604" on="1"/>
+ <pt x="845" y="1925" on="1"/>
+ <pt x="1073" y="1925" on="1"/>
+ <pt x="752" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 8 29 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0 28 27 1 29 26 1
+ 2 0 14 13 1 0 0 3 14 29 28 27 26 4 12 1 3 0 0 13 12 24 1 14 2
+ 1 33 1 0 2 4 48 196 15 14 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ubreve" xMin="166" yMin="-37" xMax="1312" yMax="1925">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="419" y="1925" on="1"/>
+ <pt x="542" y="1925" on="1"/>
+ <pt x="563" y="1831" on="0"/>
+ <pt x="617" y="1791" on="1"/>
+ <pt x="669" y="1752" on="0"/>
+ <pt x="752" y="1752" on="1"/>
+ <pt x="846" y="1752" on="0"/>
+ <pt x="900" y="1801" on="1"/>
+ <pt x="943" y="1841" on="0"/>
+ <pt x="962" y="1925" on="1"/>
+ <pt x="1085" y="1925" on="1"/>
+ <pt x="1069" y="1791" on="0"/>
+ <pt x="996" y="1710" on="1"/>
+ <pt x="902" y="1604" on="0"/>
+ <pt x="752" y="1604" on="1"/>
+ <pt x="595" y="1604" on="0"/>
+ <pt x="500" y="1719" on="1"/>
+ <pt x="435" y="1797" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 69 values pushed */
+ 0 0 31 7 40 8 35 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0 36 35 27
+ 26 4 13 40 0 14 13 1 0 0 3 14 36 35 27 26 4 12 1 3 0 0 13 12 27
+ 1 14 2 1 9 1 0 2 4 48 196 15 14 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ucircumflex" xMin="166" yMin="-37" xMax="1312" yMax="1925">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="402" y="1604" on="1"/>
+ <pt x="643" y="1925" on="1"/>
+ <pt x="861" y="1925" on="1"/>
+ <pt x="1102" y="1604" on="1"/>
+ <pt x="954" y="1604" on="1"/>
+ <pt x="753" y="1806" on="1"/>
+ <pt x="751" y="1806" on="1"/>
+ <pt x="550" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 78 values pushed */
+ 0 0 8 29 21 48 196 21 2 32 31 2 27 26 3 1 25 15 12 2 4 0 2 3 0
+ 28 27 1 33 30 29 26 3 2 0 14 13 1 0 0 3 14 33 32 31 30 29 28 27 26
+ 8 12 1 3 0 0 13 12 24 1 14 2 1 33 1 0 2 4 48 196 15 14 1 25 0
+ 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Udieresis" xMin="166" yMin="-37" xMax="1312" yMax="1777">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="468" y="1604" on="1"/>
+ <pt x="468" y="1777" on="1"/>
+ <pt x="641" y="1777" on="1"/>
+ <pt x="641" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="863" y="1604" on="1"/>
+ <pt x="863" y="1777" on="1"/>
+ <pt x="1036" y="1777" on="1"/>
+ <pt x="1036" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 8 29 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0 0 0 33 30 29 26
+ 13 3 27 1 4 48 196 32 31 28 27 3 0 14 13 1 0 0 3 14 0 0 31 30 13
+ 1 32 29 28 13 1 26 13 12 24 1 14 2 1 33 1 0 4 4 48 196 33 32 1 27
+ 26 1 15 14 1 25 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ugrave" xMin="166" yMin="-37" xMax="1312" yMax="1925">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="900" y="1604" on="1"/>
+ <pt x="752" y="1604" on="1"/>
+ <pt x="431" y="1925" on="1"/>
+ <pt x="659" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 8 29 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0 29 28 1 27 26 1
+ 2 0 14 13 1 0 0 3 14 29 28 27 26 4 12 1 3 0 0 13 12 24 1 14 2
+ 1 33 1 0 2 4 48 196 15 14 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uhungarumlaut" xMin="166" yMin="-37" xMax="1312" yMax="1925">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="499" y="1604" on="1"/>
+ <pt x="740" y="1925" on="1"/>
+ <pt x="931" y="1925" on="1"/>
+ <pt x="610" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="851" y="1604" on="1"/>
+ <pt x="1091" y="1925" on="1"/>
+ <pt x="1282" y="1925" on="1"/>
+ <pt x="962" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 0 0 8 29 21 48 196 21 2 33 30 29 26 4 27 0 3 1 25 15 12 2 4 0 2
+ 3 0 32 31 28 27 3 0 14 13 1 0 0 3 14 32 14 12 2 33 31 30 29 28 27
+ 26 7 12 1 3 0 0 13 12 24 1 14 2 1 33 1 0 2 4 48 196 15 14 1 25
+ 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Umacron" xMin="166" yMin="-37" xMax="1312" yMax="1752">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="431" y="1604" on="1"/>
+ <pt x="431" y="1752" on="1"/>
+ <pt x="1073" y="1752" on="1"/>
+ <pt x="1073" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 8 29 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0 0 0 29 26 7 1
+ 27 1 4 48 196 28 27 1 0 14 13 1 0 0 3 14 0 0 13 12 24 1 14 2 1
+ 33 1 0 2 4 48 196 29 28 1 27 26 1 15 14 1 25 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Unterkomma" xMin="170" yMin="-432" xMax="512" yMax="-111">
+ <contour>
+ <pt x="170" y="-421" on="1"/>
+ <pt x="170" y="-336" on="1"/>
+ <pt x="227" y="-345" on="0"/>
+ <pt x="267" y="-345" on="1"/>
+ <pt x="377" y="-345" on="0"/>
+ <pt x="377" y="-278" on="1"/>
+ <pt x="377" y="-204" on="0"/>
+ <pt x="219" y="-188" on="1"/>
+ <pt x="219" y="-111" on="1"/>
+ <pt x="353" y="-114" on="0"/>
+ <pt x="419" y="-143" on="1"/>
+ <pt x="512" y="-185" on="0"/>
+ <pt x="512" y="-280" on="1"/>
+ <pt x="512" y="-432" on="0"/>
+ <pt x="295" y="-432" on="1"/>
+ <pt x="236" y="-432" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 3 44 14 48 196 14 8 7 1 0 14 0 0 5 42 12 48 196 12 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uogonek" xMin="166" yMin="-370" xMax="1312" yMax="1480">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="800" y="0" on="1"/>
+ <pt x="907" y="0" on="1"/>
+ <pt x="779" y="-81" on="0"/>
+ <pt x="779" y="-179" on="1"/>
+ <pt x="779" y="-275" on="0"/>
+ <pt x="894" y="-275" on="1"/>
+ <pt x="947" y="-275" on="0"/>
+ <pt x="984" y="-260" on="1"/>
+ <pt x="984" y="-341" on="1"/>
+ <pt x="922" y="-370" on="0"/>
+ <pt x="844" y="-370" on="1"/>
+ <pt x="642" y="-370" on="0"/>
+ <pt x="642" y="-212" on="1"/>
+ <pt x="642" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 31 21 36 8 29 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0 1 34 33
+ 27 26 4 13 36 2 0 14 13 1 0 0 3 14 0 0 29 42 38 48 196 38 38 34 33
+ 27 26 5 12 1 3 0 0 13 12 24 1 14 2 1 33 1 0 2 4 48 196 15 14 1
+ 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Uring" xMin="166" yMin="-37" xMax="1312" yMax="2033">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="752" y="2033" on="1"/>
+ <pt x="846" y="2033" on="0"/>
+ <pt x="912" y="1967" on="1"/>
+ <pt x="979" y="1901" on="0"/>
+ <pt x="979" y="1807" on="1"/>
+ <pt x="979" y="1711" on="0"/>
+ <pt x="912" y="1645" on="1"/>
+ <pt x="846" y="1579" on="0"/>
+ <pt x="750" y="1579" on="1"/>
+ <pt x="667" y="1579" on="0"/>
+ <pt x="605" y="1633" on="1"/>
+ <pt x="525" y="1702" on="0"/>
+ <pt x="525" y="1806" on="1"/>
+ <pt x="525" y="1900" on="0"/>
+ <pt x="591" y="1966" on="1"/>
+ <pt x="658" y="2033" on="0"/>
+ </contour>
+ <contour>
+ <pt x="752" y="1946" on="1"/>
+ <pt x="693" y="1946" on="0"/>
+ <pt x="652" y="1905" on="1"/>
+ <pt x="611" y="1864" on="0"/>
+ <pt x="611" y="1806" on="1"/>
+ <pt x="611" y="1748" on="0"/>
+ <pt x="652" y="1707" on="1"/>
+ <pt x="694" y="1665" on="0"/>
+ <pt x="750" y="1665" on="1"/>
+ <pt x="804" y="1665" on="0"/>
+ <pt x="843" y="1698" on="1"/>
+ <pt x="893" y="1741" on="0"/>
+ <pt x="893" y="1807" on="1"/>
+ <pt x="893" y="1865" on="0"/>
+ <pt x="851" y="1905" on="1"/>
+ <pt x="810" y="1946" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 50 44 34 42 44 26 8 29 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0
+ 34 26 0 14 13 1 0 0 3 14 0 0 54 32 30 46 32 38 48 196 38 30 38 30 2
+ 12 1 3 0 0 13 12 24 1 14 2 1 33 1 0 2 4 48 196 15 14 1 25 0 1
+ 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Utilde" xMin="166" yMin="-37" xMax="1312" yMax="1838">
+ <contour>
+ <pt x="166" y="1480" on="1"/>
+ <pt x="376" y="1480" on="1"/>
+ <pt x="376" y="546" on="1"/>
+ <pt x="376" y="388" on="0"/>
+ <pt x="402" y="314" on="1"/>
+ <pt x="427" y="241" on="0"/>
+ <pt x="499" y="190" on="1"/>
+ <pt x="599" y="120" on="0"/>
+ <pt x="768" y="120" on="1"/>
+ <pt x="967" y="120" on="0"/>
+ <pt x="1047" y="214" on="1"/>
+ <pt x="1128" y="307" on="0"/>
+ <pt x="1128" y="539" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1312" y="1480" on="1"/>
+ <pt x="1312" y="542" on="1"/>
+ <pt x="1312" y="344" on="0"/>
+ <pt x="1273" y="242" on="1"/>
+ <pt x="1234" y="139" on="0"/>
+ <pt x="1129" y="64" on="1"/>
+ <pt x="987" y="-37" on="0"/>
+ <pt x="750" y="-37" on="1"/>
+ <pt x="448" y="-37" on="0"/>
+ <pt x="307" y="103" on="1"/>
+ <pt x="166" y="243" on="0"/>
+ <pt x="166" y="548" on="1"/>
+ </contour>
+ <contour>
+ <pt x="419" y="1604" on="1"/>
+ <pt x="426" y="1697" on="0"/>
+ <pt x="451" y="1748" on="1"/>
+ <pt x="497" y="1838" on="0"/>
+ <pt x="606" y="1838" on="1"/>
+ <pt x="678" y="1838" on="0"/>
+ <pt x="739" y="1800" on="1"/>
+ <pt x="799" y="1763" on="1"/>
+ <pt x="856" y="1728" on="0"/>
+ <pt x="886" y="1728" on="1"/>
+ <pt x="951" y="1728" on="0"/>
+ <pt x="962" y="1838" on="1"/>
+ <pt x="1085" y="1838" on="1"/>
+ <pt x="1078" y="1744" on="0"/>
+ <pt x="1053" y="1694" on="1"/>
+ <pt x="1008" y="1604" on="0"/>
+ <pt x="900" y="1604" on="1"/>
+ <pt x="828" y="1604" on="0"/>
+ <pt x="765" y="1643" on="1"/>
+ <pt x="705" y="1680" on="1"/>
+ <pt x="650" y="1714" on="0"/>
+ <pt x="618" y="1714" on="1"/>
+ <pt x="553" y="1714" on="0"/>
+ <pt x="542" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 73 values pushed */
+ 0 0 47 6 30 35 6 42 8 35 21 48 196 21 2 1 25 15 12 2 4 0 2 3 0
+ 49 38 37 26 4 13 42 30 0 14 13 1 0 0 3 14 49 38 37 26 4 12 1 3 0
+ 0 13 12 27 1 14 2 1 9 1 0 2 4 48 196 15 14 1 25 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="V" xMin="36" yMin="0" xMax="1355" yMax="1480">
+ <contour>
+ <pt x="607" y="0" on="1"/>
+ <pt x="36" y="1480" on="1"/>
+ <pt x="252" y="1480" on="1"/>
+ <pt x="724" y="265" on="1"/>
+ <pt x="1176" y="1480" on="1"/>
+ <pt x="1355" y="1480" on="1"/>
+ <pt x="805" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 3 1 0 2 6 0 1 0 5 4 2 1 0 3 14 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="W" xMin="25" yMin="0" xMax="1908" yMax="1480">
+ <contour>
+ <pt x="406" y="0" on="1"/>
+ <pt x="25" y="1480" on="1"/>
+ <pt x="227" y="1480" on="1"/>
+ <pt x="530" y="311" on="1"/>
+ <pt x="877" y="1480" on="1"/>
+ <pt x="1079" y="1480" on="1"/>
+ <pt x="1412" y="322" on="1"/>
+ <pt x="1737" y="1480" on="1"/>
+ <pt x="1908" y="1480" on="1"/>
+ <pt x="1492" y="0" on="1"/>
+ <pt x="1284" y="0" on="1"/>
+ <pt x="955" y="1141" on="1"/>
+ <pt x="614" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 35 values pushed */
+ 11 6 3 3 1 0 3 12 10 9 0 3 0 8 7 5 4 2 1 0 5 14 12 11 10
+ 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Wcircumflex" xMin="25" yMin="0" xMax="1908" yMax="1925">
+ <contour>
+ <pt x="406" y="0" on="1"/>
+ <pt x="25" y="1480" on="1"/>
+ <pt x="227" y="1480" on="1"/>
+ <pt x="530" y="311" on="1"/>
+ <pt x="877" y="1480" on="1"/>
+ <pt x="1079" y="1480" on="1"/>
+ <pt x="1412" y="322" on="1"/>
+ <pt x="1737" y="1480" on="1"/>
+ <pt x="1908" y="1480" on="1"/>
+ <pt x="1492" y="0" on="1"/>
+ <pt x="1284" y="0" on="1"/>
+ <pt x="955" y="1141" on="1"/>
+ <pt x="614" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="628" y="1604" on="1"/>
+ <pt x="869" y="1925" on="1"/>
+ <pt x="1087" y="1925" on="1"/>
+ <pt x="1328" y="1604" on="1"/>
+ <pt x="1180" y="1604" on="1"/>
+ <pt x="979" y="1806" on="1"/>
+ <pt x="977" y="1806" on="1"/>
+ <pt x="776" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 19 18 2 14 13 3 11 6 3 3 1 0 3 15 14 1 20 17 16 13 3 12 10 9 0
+ 3 3 0 8 7 5 4 2 1 0 5 14 20 19 18 17 16 15 14 13 12 11 10 9 8
+ 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="X" xMin="28" yMin="0" xMax="1338" yMax="1480">
+ <contour>
+ <pt x="28" y="0" on="1"/>
+ <pt x="573" y="735" on="1"/>
+ <pt x="52" y="1480" on="1"/>
+ <pt x="300" y="1480" on="1"/>
+ <pt x="701" y="905" on="1"/>
+ <pt x="1128" y="1480" on="1"/>
+ <pt x="1327" y="1480" on="1"/>
+ <pt x="798" y="770" on="1"/>
+ <pt x="1338" y="0" on="1"/>
+ <pt x="1090" y="0" on="1"/>
+ <pt x="670" y="598" on="1"/>
+ <pt x="226" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 33 values pushed */
+ 10 7 4 1 4 2 0 3 11 9 8 0 3 0 6 5 3 2 0 3 14 11 10 9 8
+ 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Y" xMin="30" yMin="0" xMax="1337" yMax="1480">
+ <contour>
+ <pt x="561" y="0" on="1"/>
+ <pt x="561" y="617" on="1"/>
+ <pt x="30" y="1480" on="1"/>
+ <pt x="270" y="1480" on="1"/>
+ <pt x="691" y="795" on="1"/>
+ <pt x="1142" y="1480" on="1"/>
+ <pt x="1337" y="1480" on="1"/>
+ <pt x="771" y="622" on="1"/>
+ <pt x="771" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 45 values pushed */
+ 7 4 1 3 2 0 3 8 0 1 0 6 5 3 2 0 3 14 4 7 0 2 6 5 2
+ 13 7 3 2 0 0 0 8 7 33 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Yacute" xMin="30" yMin="0" xMax="1337" yMax="1925">
+ <contour>
+ <pt x="561" y="0" on="1"/>
+ <pt x="561" y="617" on="1"/>
+ <pt x="30" y="1480" on="1"/>
+ <pt x="270" y="1480" on="1"/>
+ <pt x="691" y="795" on="1"/>
+ <pt x="1142" y="1480" on="1"/>
+ <pt x="1337" y="1480" on="1"/>
+ <pt x="771" y="622" on="1"/>
+ <pt x="771" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="543" y="1604" on="1"/>
+ <pt x="784" y="1925" on="1"/>
+ <pt x="1012" y="1925" on="1"/>
+ <pt x="691" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 7 4 1 3 2 0 3 11 10 1 12 9 1 8 0 1 3 0 6 5 3 2 0 3 14
+ 12 4 2 7 0 3 11 10 6 5 4 13 7 9 3 2 3 13 0 0 0 8 7 33 1
+ 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ycircumflex" xMin="30" yMin="0" xMax="1337" yMax="1925">
+ <contour>
+ <pt x="561" y="0" on="1"/>
+ <pt x="561" y="617" on="1"/>
+ <pt x="30" y="1480" on="1"/>
+ <pt x="270" y="1480" on="1"/>
+ <pt x="691" y="795" on="1"/>
+ <pt x="1142" y="1480" on="1"/>
+ <pt x="1337" y="1480" on="1"/>
+ <pt x="771" y="622" on="1"/>
+ <pt x="771" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="356" y="1604" on="1"/>
+ <pt x="597" y="1925" on="1"/>
+ <pt x="815" y="1925" on="1"/>
+ <pt x="1056" y="1604" on="1"/>
+ <pt x="908" y="1604" on="1"/>
+ <pt x="707" y="1806" on="1"/>
+ <pt x="705" y="1806" on="1"/>
+ <pt x="504" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 15 14 2 10 9 3 7 4 1 3 2 0 3 11 10 1 16 13 12 9 3 8 0 1 3
+ 0 6 5 3 2 0 3 14 15 14 10 4 4 7 0 3 13 12 11 6 5 5 13 7 16
+ 9 3 2 4 13 0 0 0 8 7 33 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Ydieresis" xMin="30" yMin="0" xMax="1337" yMax="1777">
+ <contour>
+ <pt x="561" y="0" on="1"/>
+ <pt x="561" y="617" on="1"/>
+ <pt x="30" y="1480" on="1"/>
+ <pt x="270" y="1480" on="1"/>
+ <pt x="691" y="795" on="1"/>
+ <pt x="1142" y="1480" on="1"/>
+ <pt x="1337" y="1480" on="1"/>
+ <pt x="771" y="622" on="1"/>
+ <pt x="771" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="422" y="1604" on="1"/>
+ <pt x="422" y="1777" on="1"/>
+ <pt x="595" y="1777" on="1"/>
+ <pt x="595" y="1604" on="1"/>
+ </contour>
+ <contour>
+ <pt x="817" y="1604" on="1"/>
+ <pt x="817" y="1777" on="1"/>
+ <pt x="990" y="1777" on="1"/>
+ <pt x="990" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 7 4 1 3 2 0 3 0 0 16 13 12 9 13 3 10 1 4 48 196 15 14 11 10 3
+ 8 0 1 2 0 6 5 3 2 0 3 14 4 7 11 2 6 5 2 13 15 3 2 9 0
+ 0 14 13 13 1 15 12 11 13 1 9 8 7 33 1 0 3 4 48 196 16 15 1 10 9
+ 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Z" xMin="101" yMin="0" xMax="1148" yMax="1480">
+ <contour>
+ <pt x="101" y="0" on="1"/>
+ <pt x="101" y="169" on="1"/>
+ <pt x="896" y="1323" on="1"/>
+ <pt x="150" y="1323" on="1"/>
+ <pt x="150" y="1480" on="1"/>
+ <pt x="1148" y="1480" on="1"/>
+ <pt x="1148" y="1323" on="1"/>
+ <pt x="353" y="169" on="1"/>
+ <pt x="1148" y="169" on="1"/>
+ <pt x="1148" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 6 3 2 15 2 4 1 4 8 7 1 2 0 1 6 48 196 9 0 1 0 5 4
+ 0 14 7 2 2 5 3 3 9 8 6 5 3 4 3 1 1 0 1 3 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zacute" xMin="101" yMin="0" xMax="1148" yMax="1925">
+ <contour>
+ <pt x="101" y="0" on="1"/>
+ <pt x="101" y="169" on="1"/>
+ <pt x="896" y="1323" on="1"/>
+ <pt x="150" y="1323" on="1"/>
+ <pt x="150" y="1480" on="1"/>
+ <pt x="1148" y="1480" on="1"/>
+ <pt x="1148" y="1323" on="1"/>
+ <pt x="353" y="169" on="1"/>
+ <pt x="1148" y="169" on="1"/>
+ <pt x="1148" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="477" y="1604" on="1"/>
+ <pt x="718" y="1925" on="1"/>
+ <pt x="946" y="1925" on="1"/>
+ <pt x="625" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 0 0 6 3 2 15 2 4 1 4 8 7 1 2 0 1 6 48 196 12 11 1 13 10 1
+ 9 0 1 3 0 5 4 0 14 13 12 11 10 7 2 6 5 3 3 9 8 6 5 3 4
+ 3 1 1 0 1 3 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zcaron" xMin="101" yMin="0" xMax="1148" yMax="1925">
+ <contour>
+ <pt x="101" y="0" on="1"/>
+ <pt x="101" y="169" on="1"/>
+ <pt x="896" y="1323" on="1"/>
+ <pt x="150" y="1323" on="1"/>
+ <pt x="150" y="1480" on="1"/>
+ <pt x="1148" y="1480" on="1"/>
+ <pt x="1148" y="1323" on="1"/>
+ <pt x="353" y="169" on="1"/>
+ <pt x="1148" y="169" on="1"/>
+ <pt x="1148" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="987" y="1925" on="1"/>
+ <pt x="746" y="1604" on="1"/>
+ <pt x="528" y="1604" on="1"/>
+ <pt x="287" y="1925" on="1"/>
+ <pt x="435" y="1925" on="1"/>
+ <pt x="636" y="1723" on="1"/>
+ <pt x="638" y="1723" on="1"/>
+ <pt x="839" y="1925" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 69 values pushed */
+ 16 15 2 10 11 3 0 0 6 3 2 15 2 4 1 4 8 7 1 2 0 1 6 48 196
+ 17 14 13 10 3 12 11 1 9 0 1 3 0 5 4 0 14 17 16 15 14 13 12 11 10
+ 7 2 10 5 3 3 9 8 6 5 3 4 3 1 1 0 1 3 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="Zdotaccent" xMin="101" yMin="0" xMax="1148" yMax="1801">
+ <contour>
+ <pt x="101" y="0" on="1"/>
+ <pt x="101" y="169" on="1"/>
+ <pt x="896" y="1323" on="1"/>
+ <pt x="150" y="1323" on="1"/>
+ <pt x="150" y="1480" on="1"/>
+ <pt x="1148" y="1480" on="1"/>
+ <pt x="1148" y="1323" on="1"/>
+ <pt x="353" y="169" on="1"/>
+ <pt x="1148" y="169" on="1"/>
+ <pt x="1148" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="538" y="1604" on="1"/>
+ <pt x="538" y="1801" on="1"/>
+ <pt x="735" y="1801" on="1"/>
+ <pt x="735" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 13 10 5 1 11 6 3 2 15 2 4 2 4 8 7 1 2 0 1 6 48 196 12
+ 11 1 9 0 1 2 0 5 4 0 14 2 5 12 2 7 10 3 2 0 0 13 12 4 1
+ 10 1 4 48 196 11 10 1 9 8 6 5 3 4 3 1 1 0 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="a" xMin="95" yMin="-25" xMax="1098" yMax="1110">
+ <contour>
+ <pt x="774" y="138" on="1"/>
+ <pt x="589" y="-25" on="0"/>
+ <pt x="414" y="-25" on="1"/>
+ <pt x="273" y="-25" on="0"/>
+ <pt x="184" y="58" on="1"/>
+ <pt x="95" y="142" on="0"/>
+ <pt x="95" y="273" on="1"/>
+ <pt x="95" y="642" on="0"/>
+ <pt x="699" y="642" on="1"/>
+ <pt x="745" y="642" on="1"/>
+ <pt x="745" y="773" on="1"/>
+ <pt x="745" y="962" on="0"/>
+ <pt x="536" y="962" on="1"/>
+ <pt x="374" y="962" on="0"/>
+ <pt x="189" y="866" on="1"/>
+ <pt x="189" y="1029" on="1"/>
+ <pt x="394" y="1110" on="0"/>
+ <pt x="574" y="1110" on="1"/>
+ <pt x="766" y="1110" on="0"/>
+ <pt x="854" y="1029" on="1"/>
+ <pt x="942" y="949" on="0"/>
+ <pt x="942" y="773" on="1"/>
+ <pt x="942" y="281" on="1"/>
+ <pt x="942" y="112" on="0"/>
+ <pt x="1046" y="112" on="1"/>
+ <pt x="1060" y="112" on="0"/>
+ <pt x="1084" y="116" on="1"/>
+ <pt x="1098" y="7" on="1"/>
+ <pt x="1025" y="-25" on="0"/>
+ <pt x="952" y="-25" on="1"/>
+ <pt x="884" y="-25" on="0"/>
+ <pt x="840" y="13" on="1"/>
+ <pt x="797" y="50" on="0"/>
+ </contour>
+ <contour>
+ <pt x="745" y="245" on="1"/>
+ <pt x="745" y="526" on="1"/>
+ <pt x="680" y="528" on="1"/>
+ <pt x="620" y="530" on="0"/>
+ <pt x="547" y="519" on="1"/>
+ <pt x="299" y="484" on="0"/>
+ <pt x="299" y="303" on="1"/>
+ <pt x="299" y="136" on="0"/>
+ <pt x="480" y="136" on="1"/>
+ <pt x="606" y="136" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 82 values pushed */
+ 0 0 41 29 2 12 40 17 48 196 29 2 17 1 2 2 24 1 1 34 33 27 26 24 22
+ 21 15 14 10 9 8 0 13 1 2 3 0 0 14 0 0 39 43 6 48 196 0 21 9 2
+ 8 9 14 2 27 26 2 13 21 6 14 0 0 34 33 10 9 4 3 21 1 4 48 196 22
+ 21 1 15 14 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="aacute" xMin="95" yMin="-25" xMax="1098" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="323" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="abreve" xMin="105" yMin="-25" xMax="1108" yMax="1604">
+ <component glyphName="a" x="10" y="0" flags="0x4"/>
+ <component glyphName="breve" x="248" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="acircumflex" xMin="95" yMin="-25" xMax="1098" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="238" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="acute" xMin="107" yMin="1283" xMax="576" yMax="1604">
+ <contour>
+ <pt x="107" y="1283" on="1"/>
+ <pt x="348" y="1604" on="1"/>
+ <pt x="576" y="1604" on="1"/>
+ <pt x="255" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 2 1 1 3 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="adieresis" xMin="95" yMin="-25" xMax="1098" yMax="1456">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="219" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ae" xMin="95" yMin="-25" xMax="1701" yMax="1110">
+ <contour>
+ <pt x="767" y="245" on="1"/>
+ <pt x="767" y="526" on="1"/>
+ <pt x="692" y="528" on="1"/>
+ <pt x="627" y="530" on="0"/>
+ <pt x="551" y="519" on="1"/>
+ <pt x="292" y="483" on="0"/>
+ <pt x="292" y="303" on="1"/>
+ <pt x="292" y="136" on="0"/>
+ <pt x="491" y="136" on="1"/>
+ <pt x="628" y="136" on="0"/>
+ </contour>
+ <contour>
+ <pt x="916" y="983" on="1"/>
+ <pt x="1067" y="1110" on="0"/>
+ <pt x="1259" y="1110" on="1"/>
+ <pt x="1701" y="1110" on="0"/>
+ <pt x="1701" y="573" on="1"/>
+ <pt x="1701" y="512" on="1"/>
+ <pt x="961" y="512" on="1"/>
+ <pt x="973" y="395" on="0"/>
+ <pt x="999" y="334" on="1"/>
+ <pt x="1089" y="125" on="0"/>
+ <pt x="1364" y="125" on="1"/>
+ <pt x="1515" y="125" on="0"/>
+ <pt x="1696" y="191" on="1"/>
+ <pt x="1696" y="35" on="1"/>
+ <pt x="1491" y="-25" on="0"/>
+ <pt x="1318" y="-25" on="1"/>
+ <pt x="1127" y="-25" on="0"/>
+ <pt x="997" y="62" on="1"/>
+ <pt x="925" y="110" on="0"/>
+ <pt x="858" y="205" on="1"/>
+ <pt x="743" y="82" on="0"/>
+ <pt x="661" y="33" on="1"/>
+ <pt x="562" y="-25" on="0"/>
+ <pt x="427" y="-25" on="1"/>
+ <pt x="277" y="-25" on="0"/>
+ <pt x="186" y="57" on="1"/>
+ <pt x="95" y="140" on="0"/>
+ <pt x="95" y="272" on="1"/>
+ <pt x="95" y="642" on="0"/>
+ <pt x="721" y="642" on="1"/>
+ <pt x="767" y="642" on="1"/>
+ <pt x="767" y="773" on="1"/>
+ <pt x="767" y="878" on="0"/>
+ <pt x="718" y="920" on="1"/>
+ <pt x="669" y="962" on="0"/>
+ <pt x="547" y="962" on="1"/>
+ <pt x="376" y="962" on="0"/>
+ <pt x="189" y="866" on="1"/>
+ <pt x="189" y="1029" on="1"/>
+ <pt x="395" y="1110" on="0"/>
+ <pt x="581" y="1110" on="1"/>
+ <pt x="807" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="971" y="660" on="1"/>
+ <pt x="1503" y="660" on="1"/>
+ <pt x="1500" y="756" on="0"/>
+ <pt x="1483" y="806" on="1"/>
+ <pt x="1430" y="962" on="0"/>
+ <pt x="1251" y="962" on="1"/>
+ <pt x="1126" y="962" on="0"/>
+ <pt x="1056" y="889" on="1"/>
+ <pt x="989" y="820" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 57 40 12 45 40 50 20 40 25 48 196 50 1 33 2 25 2 12 1 1 48 47 41
+ 10 4 1 52 3 0 40 39 14 1 4 52 15 3 8 1 29 23 22 8 0 5 15 2 3
+ 0 0 0 16 15 7 1 52 1 4 48 196 53 52 1 0 14 53 52 29 16 10 5 22 0
+ 3 6 39 6 2 0 47 3 15 14 2 13 22 37 47 23 22 1 48 47 1 41 40 1 0
+ 3 3 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="afii00208" xMin="99" yMin="543" xMax="1950" yMax="642">
+ <contour>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="642" on="1"/>
+ <pt x="1950" y="642" on="1"/>
+ <pt x="1950" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 11 1 1 1 4 48 196 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="agrave" xMin="95" yMin="-25" xMax="1098" yMax="1604">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="152" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="amacron" xMin="105" yMin="-25" xMax="1108" yMax="1431">
+ <component glyphName="a" x="10" y="0" flags="0x4"/>
+ <component glyphName="macron" x="217" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ampersand" xMin="56" yMin="-37" xMax="1293" yMax="1517">
+ <contour>
+ <pt x="1025" y="0" on="1"/>
+ <pt x="952" y="87" on="1"/>
+ <pt x="752" y="-37" on="0"/>
+ <pt x="570" y="-37" on="1"/>
+ <pt x="352" y="-37" on="0"/>
+ <pt x="204" y="99" on="1"/>
+ <pt x="56" y="235" on="0"/>
+ <pt x="56" y="442" on="1"/>
+ <pt x="56" y="647" on="0"/>
+ <pt x="185" y="774" on="1"/>
+ <pt x="261" y="848" on="0"/>
+ <pt x="405" y="904" on="1"/>
+ <pt x="317" y="1067" on="0"/>
+ <pt x="317" y="1187" on="1"/>
+ <pt x="317" y="1337" on="0"/>
+ <pt x="409" y="1427" on="1"/>
+ <pt x="502" y="1517" on="0"/>
+ <pt x="659" y="1517" on="1"/>
+ <pt x="808" y="1517" on="0"/>
+ <pt x="895" y="1436" on="1"/>
+ <pt x="982" y="1355" on="0"/>
+ <pt x="982" y="1219" on="1"/>
+ <pt x="982" y="1068" on="0"/>
+ <pt x="866" y="959" on="1"/>
+ <pt x="795" y="893" on="0"/>
+ <pt x="661" y="832" on="1"/>
+ <pt x="829" y="527" on="0"/>
+ <pt x="995" y="328" on="1"/>
+ <pt x="1094" y="455" on="0"/>
+ <pt x="1094" y="707" on="1"/>
+ <pt x="1094" y="787" on="1"/>
+ <pt x="1289" y="787" on="1"/>
+ <pt x="1289" y="441" on="0"/>
+ <pt x="1087" y="221" on="1"/>
+ <pt x="1175" y="109" on="0"/>
+ <pt x="1293" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="866" y="202" on="1"/>
+ <pt x="669" y="427" on="0"/>
+ <pt x="475" y="790" on="1"/>
+ <pt x="377" y="743" on="0"/>
+ <pt x="327" y="684" on="1"/>
+ <pt x="254" y="600" on="0"/>
+ <pt x="254" y="477" on="1"/>
+ <pt x="254" y="324" on="0"/>
+ <pt x="356" y="218" on="1"/>
+ <pt x="459" y="111" on="0"/>
+ <pt x="602" y="111" on="1"/>
+ <pt x="714" y="111" on="0"/>
+ </contour>
+ <contour>
+ <pt x="587" y="956" on="1"/>
+ <pt x="683" y="998" on="0"/>
+ <pt x="729" y="1046" on="1"/>
+ <pt x="797" y="1116" on="0"/>
+ <pt x="797" y="1215" on="1"/>
+ <pt x="797" y="1369" on="0"/>
+ <pt x="657" y="1369" on="1"/>
+ <pt x="509" y="1369" on="0"/>
+ <pt x="509" y="1207" on="1"/>
+ <pt x="509" y="1109" on="0"/>
+ <pt x="579" y="972" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 54 40 17 46 40 3 48 196 17 0 3 2 1 48 38 25 11 4 0 30 3 0 36
+ 33 29 27 1 5 30 0 3 31 30 1 35 0 1 2 0 14 0 0 56 41 13 52 14 21
+ 42 41 7 48 196 48 38 36 35 33 31 30 29 27 25 21 13 11 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="anoteleia" xMin="161" yMin="491" xMax="408" yMax="738">
+ <contour>
+ <pt x="161" y="491" on="1"/>
+ <pt x="161" y="738" on="1"/>
+ <pt x="408" y="738" on="1"/>
+ <pt x="408" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 8 1 1 1 4 48 196 2 1 1 0 14 0 0 3 2 8 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="aogonek" xMin="95" yMin="-370" xMax="1098" yMax="1110">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="537" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="aring" xMin="95" yMin="-25" xMax="1098" yMax="1737">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="ring" x="238" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="asciicircum" xMin="36" yMin="592" xMax="924" yMax="1480">
+ <contour>
+ <pt x="480" y="1149" on="1"/>
+ <pt x="201" y="592" on="1"/>
+ <pt x="36" y="592" on="1"/>
+ <pt x="480" y="1480" on="1"/>
+ <pt x="924" y="592" on="1"/>
+ <pt x="758" y="592" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 18 values pushed */
+ 3 0 2 13 1 5 4 2 1 3 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="asciitilde" xMin="104" yMin="412" xMax="1091" yMax="772">
+ <contour>
+ <pt x="252" y="444" on="1"/>
+ <pt x="104" y="444" on="1"/>
+ <pt x="107" y="550" on="0"/>
+ <pt x="126" y="605" on="1"/>
+ <pt x="184" y="772" on="0"/>
+ <pt x="370" y="772" on="1"/>
+ <pt x="469" y="772" on="0"/>
+ <pt x="569" y="703" on="1"/>
+ <pt x="681" y="626" on="1"/>
+ <pt x="747" y="580" on="1"/>
+ <pt x="776" y="560" on="0"/>
+ <pt x="824" y="560" on="1"/>
+ <pt x="939" y="560" on="0"/>
+ <pt x="943" y="740" on="1"/>
+ <pt x="1091" y="740" on="1"/>
+ <pt x="1088" y="634" on="0"/>
+ <pt x="1069" y="579" on="1"/>
+ <pt x="1011" y="412" on="0"/>
+ <pt x="826" y="412" on="1"/>
+ <pt x="727" y="412" on="0"/>
+ <pt x="627" y="481" on="1"/>
+ <pt x="515" y="558" on="1"/>
+ <pt x="448" y="604" on="1"/>
+ <pt x="419" y="624" on="0"/>
+ <pt x="372" y="624" on="1"/>
+ <pt x="256" y="624" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 24 7 5 11 7 18 48 196 5 13 18 0 14 13 1 1 0 1 2 0 14 14 13
+ 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="asterisk" xMin="39" yMin="751" xMax="757" yMax="1480">
+ <contour>
+ <pt x="711" y="1289" on="1"/>
+ <pt x="757" y="1148" on="1"/>
+ <pt x="479" y="1082" on="1"/>
+ <pt x="479" y="1084" on="1"/>
+ <pt x="481" y="1095" on="0"/>
+ <pt x="481" y="1096" on="1"/>
+ <pt x="481" y="1097" on="1"/>
+ <pt x="479" y="1139" on="0"/>
+ <pt x="452" y="1164" on="1"/>
+ </contour>
+ <contour>
+ <pt x="681" y="838" on="1"/>
+ <pt x="561" y="751" on="1"/>
+ <pt x="404" y="1018" on="1"/>
+ <pt x="454" y="1024" on="0"/>
+ <pt x="474" y="1069" on="1"/>
+ </contour>
+ <contour>
+ <pt x="235" y="751" on="1"/>
+ <pt x="115" y="838" on="1"/>
+ <pt x="321" y="1069" on="1"/>
+ <pt x="341" y="1024" on="0"/>
+ <pt x="391" y="1018" on="1"/>
+ </contour>
+ <contour>
+ <pt x="39" y="1148" on="1"/>
+ <pt x="84" y="1289" on="1"/>
+ <pt x="344" y="1164" on="1"/>
+ <pt x="315" y="1138" on="0"/>
+ <pt x="315" y="1097" on="1"/>
+ <pt x="315" y="1096" on="1"/>
+ <pt x="315" y="1095" on="0"/>
+ <pt x="315" y="1091" on="1"/>
+ <pt x="316" y="1088" on="1"/>
+ <pt x="317" y="1084" on="0"/>
+ <pt x="317" y="1082" on="1"/>
+ </contour>
+ <contour>
+ <pt x="324" y="1480" on="1"/>
+ <pt x="472" y="1480" on="1"/>
+ <pt x="441" y="1172" on="1"/>
+ <pt x="419" y="1183" on="0"/>
+ <pt x="398" y="1183" on="1"/>
+ <pt x="375" y="1183" on="0"/>
+ <pt x="355" y="1172" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 34 1 36 34 32 24 23 21 20 19 8 1 0 11 30 1 3 0 1 1 29 18 16 15 14
+ 13 11 10 9 3 2 11 1 2 3 0 0 31 30 0 14 36 32 31 30 29 24 23 21 20
+ 19 18 16 15 14 13 11 10 9 8 5 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="at" xMin="253" yMin="-37" xMax="1844" yMax="1517">
+ <contour>
+ <pt x="1253" y="44" on="1"/>
+ <pt x="1067" y="-37" on="0"/>
+ <pt x="897" y="-37" on="1"/>
+ <pt x="619" y="-37" on="0"/>
+ <pt x="436" y="137" on="1"/>
+ <pt x="253" y="310" on="0"/>
+ <pt x="253" y="582" on="1"/>
+ <pt x="253" y="949" on="0"/>
+ <pt x="535" y="1233" on="1"/>
+ <pt x="817" y="1517" on="0"/>
+ <pt x="1186" y="1517" on="1"/>
+ <pt x="1468" y="1517" on="0"/>
+ <pt x="1656" y="1337" on="1"/>
+ <pt x="1844" y="1157" on="0"/>
+ <pt x="1844" y="889" on="1"/>
+ <pt x="1844" y="643" on="0"/>
+ <pt x="1693" y="469" on="1"/>
+ <pt x="1542" y="296" on="0"/>
+ <pt x="1327" y="296" on="1"/>
+ <pt x="1160" y="296" on="0"/>
+ <pt x="1160" y="411" on="1"/>
+ <pt x="1160" y="450" on="0"/>
+ <pt x="1181" y="516" on="1"/>
+ <pt x="1221" y="642" on="1"/>
+ <pt x="1209" y="642" on="1"/>
+ <pt x="1124" y="486" on="0"/>
+ <pt x="1048" y="408" on="1"/>
+ <pt x="939" y="296" on="0"/>
+ <pt x="818" y="296" on="1"/>
+ <pt x="629" y="296" on="0"/>
+ <pt x="629" y="523" on="1"/>
+ <pt x="629" y="772" on="0"/>
+ <pt x="791" y="975" on="1"/>
+ <pt x="952" y="1178" on="0"/>
+ <pt x="1157" y="1178" on="1"/>
+ <pt x="1182" y="1178" on="0"/>
+ <pt x="1222" y="1176" on="1"/>
+ <pt x="1232" y="1175" on="0"/>
+ <pt x="1245" y="1174" on="1"/>
+ <pt x="1284" y="1172" on="0"/>
+ <pt x="1311" y="1172" on="1"/>
+ <pt x="1448" y="1172" on="1"/>
+ <pt x="1322" y="536" on="1"/>
+ <pt x="1316" y="506" on="0"/>
+ <pt x="1316" y="475" on="1"/>
+ <pt x="1316" y="407" on="0"/>
+ <pt x="1393" y="407" on="1"/>
+ <pt x="1525" y="407" on="0"/>
+ <pt x="1629" y="549" on="1"/>
+ <pt x="1733" y="692" on="0"/>
+ <pt x="1733" y="874" on="1"/>
+ <pt x="1733" y="1103" on="0"/>
+ <pt x="1574" y="1255" on="1"/>
+ <pt x="1415" y="1407" on="0"/>
+ <pt x="1172" y="1407" on="1"/>
+ <pt x="856" y="1407" on="0"/>
+ <pt x="610" y="1158" on="1"/>
+ <pt x="364" y="908" on="0"/>
+ <pt x="364" y="591" on="1"/>
+ <pt x="364" y="361" on="0"/>
+ <pt x="519" y="218" on="1"/>
+ <pt x="673" y="74" on="0"/>
+ <pt x="913" y="74" on="1"/>
+ <pt x="1067" y="74" on="0"/>
+ <pt x="1217" y="146" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1233" y="833" on="1"/>
+ <pt x="1272" y="1028" on="1"/>
+ <pt x="1178" y="1061" on="0"/>
+ <pt x="1112" y="1061" on="1"/>
+ <pt x="971" y="1061" on="0"/>
+ <pt x="877" y="918" on="1"/>
+ <pt x="783" y="775" on="0"/>
+ <pt x="783" y="568" on="1"/>
+ <pt x="783" y="419" on="0"/>
+ <pt x="863" y="419" on="1"/>
+ <pt x="996" y="419" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 74 6 28 68 16 34 62 16 2 54 16 10 46 16 18 48 196 10 0 2 2 34 1
+ 34 0 40 2 0 28 18 1 66 65 64 28 24 23 18 0 8 40 2 3 0 41 40 1 0
+ 14 0 0 72 15 30 58 17 6 50 17 14 48 196 66 65 64 44 41 40 30 24 23 20 14
+ 6 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ MDAP[1]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="atilde" xMin="95" yMin="-25" xMax="1098" yMax="1517">
+ <component glyphName="a" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="206" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="b" xMin="154" yMin="-25" xMax="1052" yMax="1579">
+ <contour>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="149" on="1"/>
+ <pt x="488" y="123" on="0"/>
+ <pt x="557" y="123" on="1"/>
+ <pt x="839" y="123" on="0"/>
+ <pt x="839" y="552" on="1"/>
+ <pt x="839" y="733" on="0"/>
+ <pt x="783" y="835" on="1"/>
+ <pt x="728" y="938" on="0"/>
+ <pt x="634" y="938" on="1"/>
+ <pt x="508" y="938" on="0"/>
+ </contour>
+ <contour>
+ <pt x="351" y="882" on="1"/>
+ <pt x="407" y="984" on="0"/>
+ <pt x="469" y="1036" on="1"/>
+ <pt x="558" y="1110" on="0"/>
+ <pt x="676" y="1110" on="1"/>
+ <pt x="845" y="1110" on="0"/>
+ <pt x="948" y="963" on="1"/>
+ <pt x="1052" y="816" on="0"/>
+ <pt x="1052" y="572" on="1"/>
+ <pt x="1052" y="287" on="0"/>
+ <pt x="918" y="131" on="1"/>
+ <pt x="785" y="-25" on="0"/>
+ <pt x="540" y="-25" on="1"/>
+ <pt x="449" y="-25" on="0"/>
+ <pt x="351" y="0" on="1"/>
+ <pt x="154" y="-12" on="1"/>
+ <pt x="154" y="1579" on="1"/>
+ <pt x="351" y="1579" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 23 2 15 1 9 3 1 1 11 9 3 1 0 5 1 2 3 0 0 1 26 25 2 0 28
+ 27 1 0 14 19 5 0 0 0 28 25 11 1 0 4 4 26 1 4 48 196 27 26 1 28
+ 25 11 1 0 4 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="backslash" xMin="-59" yMin="-296" xMax="629" yMax="1480">
+ <contour>
+ <pt x="629" y="-296" on="1"/>
+ <pt x="474" y="-296" on="1"/>
+ <pt x="-59" y="1480" on="1"/>
+ <pt x="96" y="1480" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 12 values pushed */
+ 1 0 1 0 3 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bar" xMin="192" yMin="-296" xMax="340" yMax="1579">
+ <contour>
+ <pt x="192" y="-296" on="1"/>
+ <pt x="192" y="1579" on="1"/>
+ <pt x="340" y="1579" on="1"/>
+ <pt x="340" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 2 1 1 3 0 1 2 0 14 0 0 3 2 7 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="braceleft" xMin="25" yMin="-296" xMax="568" yMax="1579">
+ <contour>
+ <pt x="25" y="716" on="1"/>
+ <pt x="86" y="716" on="1"/>
+ <pt x="239" y="716" on="0"/>
+ <pt x="239" y="880" on="1"/>
+ <pt x="239" y="944" on="0"/>
+ <pt x="223" y="1017" on="1"/>
+ <pt x="204" y="1104" on="1"/>
+ <pt x="185" y="1191" on="0"/>
+ <pt x="185" y="1268" on="1"/>
+ <pt x="185" y="1431" on="0"/>
+ <pt x="321" y="1517" on="1"/>
+ <pt x="416" y="1576" on="0"/>
+ <pt x="568" y="1579" on="1"/>
+ <pt x="568" y="1431" on="1"/>
+ <pt x="515" y="1431" on="1"/>
+ <pt x="446" y="1431" on="0"/>
+ <pt x="402" y="1396" on="1"/>
+ <pt x="357" y="1360" on="0"/>
+ <pt x="357" y="1306" on="1"/>
+ <pt x="357" y="1286" on="0"/>
+ <pt x="370" y="1212" on="1"/>
+ <pt x="387" y="1110" on="1"/>
+ <pt x="398" y="1043" on="0"/>
+ <pt x="398" y="962" on="1"/>
+ <pt x="398" y="773" on="0"/>
+ <pt x="251" y="642" on="1"/>
+ <pt x="398" y="511" on="0"/>
+ <pt x="398" y="320" on="1"/>
+ <pt x="398" y="240" on="0"/>
+ <pt x="387" y="173" on="1"/>
+ <pt x="370" y="71" on="1"/>
+ <pt x="357" y="-3" on="0"/>
+ <pt x="357" y="-24" on="1"/>
+ <pt x="357" y="-77" on="0"/>
+ <pt x="403" y="-113" on="1"/>
+ <pt x="447" y="-148" on="0"/>
+ <pt x="515" y="-148" on="1"/>
+ <pt x="568" y="-148" on="1"/>
+ <pt x="568" y="-296" on="1"/>
+ <pt x="408" y="-293" on="0"/>
+ <pt x="311" y="-227" on="1"/>
+ <pt x="185" y="-140" on="0"/>
+ <pt x="185" y="17" on="1"/>
+ <pt x="185" y="92" on="0"/>
+ <pt x="204" y="179" on="1"/>
+ <pt x="223" y="266" on="1"/>
+ <pt x="239" y="339" on="0"/>
+ <pt x="239" y="406" on="1"/>
+ <pt x="239" y="568" on="0"/>
+ <pt x="86" y="568" on="1"/>
+ <pt x="25" y="568" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 55 values pushed */
+ 50 49 38 37 36 25 14 13 12 1 0 14 0 0 47 15 27 32 13 42 18 13 8 3 15
+ 23 48 196 42 27 23 8 49 42 36 27 25 23 14 8 1 9 12 0 3 38 37 13 12 3
+ 50 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="braceright" xMin="116" yMin="-296" xMax="659" yMax="1579">
+ <contour>
+ <pt x="659" y="568" on="1"/>
+ <pt x="597" y="568" on="1"/>
+ <pt x="445" y="568" on="0"/>
+ <pt x="445" y="404" on="1"/>
+ <pt x="445" y="331" on="0"/>
+ <pt x="460" y="266" on="1"/>
+ <pt x="480" y="179" on="1"/>
+ <pt x="499" y="96" on="0"/>
+ <pt x="499" y="15" on="1"/>
+ <pt x="499" y="-148" on="0"/>
+ <pt x="361" y="-234" on="1"/>
+ <pt x="267" y="-293" on="0"/>
+ <pt x="116" y="-296" on="1"/>
+ <pt x="116" y="-148" on="1"/>
+ <pt x="168" y="-148" on="1"/>
+ <pt x="236" y="-148" on="0"/>
+ <pt x="281" y="-113" on="1"/>
+ <pt x="326" y="-77" on="0"/>
+ <pt x="326" y="-23" on="1"/>
+ <pt x="326" y="3" on="0"/>
+ <pt x="314" y="71" on="1"/>
+ <pt x="296" y="173" on="1"/>
+ <pt x="285" y="235" on="0"/>
+ <pt x="285" y="321" on="1"/>
+ <pt x="285" y="511" on="0"/>
+ <pt x="432" y="642" on="1"/>
+ <pt x="366" y="701" on="0"/>
+ <pt x="333" y="760" on="1"/>
+ <pt x="285" y="848" on="0"/>
+ <pt x="285" y="963" on="1"/>
+ <pt x="285" y="1048" on="0"/>
+ <pt x="296" y="1110" on="1"/>
+ <pt x="314" y="1212" on="1"/>
+ <pt x="326" y="1280" on="0"/>
+ <pt x="326" y="1308" on="1"/>
+ <pt x="326" y="1360" on="0"/>
+ <pt x="280" y="1396" on="1"/>
+ <pt x="235" y="1431" on="0"/>
+ <pt x="168" y="1431" on="1"/>
+ <pt x="116" y="1431" on="1"/>
+ <pt x="116" y="1579" on="1"/>
+ <pt x="276" y="1576" on="0"/>
+ <pt x="372" y="1510" on="1"/>
+ <pt x="499" y="1423" on="0"/>
+ <pt x="499" y="1266" on="1"/>
+ <pt x="499" y="1187" on="0"/>
+ <pt x="480" y="1104" on="1"/>
+ <pt x="460" y="1017" on="1"/>
+ <pt x="445" y="952" on="0"/>
+ <pt x="445" y="877" on="1"/>
+ <pt x="445" y="716" on="0"/>
+ <pt x="597" y="716" on="1"/>
+ <pt x="659" y="716" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 55 values pushed */
+ 52 51 40 39 38 25 14 13 12 1 0 14 0 0 49 15 29 34 13 44 18 13 8 3 15
+ 23 48 196 44 29 23 8 51 44 38 29 25 23 14 8 1 9 0 12 3 52 0 1 40 39
+ 13 12 3 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bracketleft" xMin="149" yMin="-296" xMax="544" yMax="1579">
+ <contour>
+ <pt x="149" y="-296" on="1"/>
+ <pt x="149" y="1579" on="1"/>
+ <pt x="544" y="1579" on="1"/>
+ <pt x="544" y="1431" on="1"/>
+ <pt x="322" y="1431" on="1"/>
+ <pt x="322" y="-148" on="1"/>
+ <pt x="544" y="-148" on="1"/>
+ <pt x="544" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 4 3 7 1 1 6 5 7 1 0 2 4 48 196 2 1 1 7 0 1 2 0 14
+ 0 0 5 4 13 1 0 1 4 48 196 7 6 3 2 3 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bracketright" xMin="26" yMin="-296" xMax="421" yMax="1579">
+ <contour>
+ <pt x="421" y="1579" on="1"/>
+ <pt x="421" y="-296" on="1"/>
+ <pt x="26" y="-296" on="1"/>
+ <pt x="26" y="-148" on="1"/>
+ <pt x="248" y="-148" on="1"/>
+ <pt x="248" y="1431" on="1"/>
+ <pt x="26" y="1431" on="1"/>
+ <pt x="26" y="1579" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 6 5 7 1 0 4 3 7 1 1 2 4 48 196 7 0 1 2 1 1 2 0 14
+ 0 0 5 4 13 1 0 1 4 48 196 1 0 1 7 6 3 2 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="breve" xMin="8" yMin="1283" xMax="674" yMax="1604">
+ <contour>
+ <pt x="8" y="1604" on="1"/>
+ <pt x="131" y="1604" on="1"/>
+ <pt x="152" y="1510" on="0"/>
+ <pt x="206" y="1470" on="1"/>
+ <pt x="258" y="1431" on="0"/>
+ <pt x="341" y="1431" on="1"/>
+ <pt x="435" y="1431" on="0"/>
+ <pt x="489" y="1480" on="1"/>
+ <pt x="532" y="1520" on="0"/>
+ <pt x="551" y="1604" on="1"/>
+ <pt x="674" y="1604" on="1"/>
+ <pt x="658" y="1470" on="0"/>
+ <pt x="585" y="1389" on="1"/>
+ <pt x="491" y="1283" on="0"/>
+ <pt x="341" y="1283" on="1"/>
+ <pt x="184" y="1283" on="0"/>
+ <pt x="89" y="1398" on="1"/>
+ <pt x="24" y="1476" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 0 0 5 40 14 48 196 14 10 9 1 0 14 10 9 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="brokenbar" xMin="192" yMin="-296" xMax="340" yMax="1579">
+ <contour>
+ <pt x="192" y="-296" on="1"/>
+ <pt x="192" y="444" on="1"/>
+ <pt x="340" y="444" on="1"/>
+ <pt x="340" y="-296" on="1"/>
+ </contour>
+ <contour>
+ <pt x="192" y="839" on="1"/>
+ <pt x="192" y="1579" on="1"/>
+ <pt x="340" y="1579" on="1"/>
+ <pt x="340" y="839" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 34 values pushed */
+ 6 5 1 7 4 1 2 1 1 3 0 1 4 0 14 0 0 7 6 3 2 7 3 0 1
+ 4 48 196 5 4 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="bullet" xMin="81" yMin="555" xMax="636" yMax="1110">
+ <contour>
+ <pt x="359" y="1110" on="1"/>
+ <pt x="474" y="1110" on="0"/>
+ <pt x="555" y="1028" on="1"/>
+ <pt x="636" y="946" on="0"/>
+ <pt x="636" y="831" on="1"/>
+ <pt x="636" y="717" on="0"/>
+ <pt x="554" y="636" on="1"/>
+ <pt x="472" y="555" on="0"/>
+ <pt x="354" y="555" on="1"/>
+ <pt x="255" y="555" on="0"/>
+ <pt x="179" y="621" on="1"/>
+ <pt x="81" y="707" on="0"/>
+ <pt x="81" y="833" on="1"/>
+ <pt x="81" y="948" on="0"/>
+ <pt x="163" y="1029" on="1"/>
+ <pt x="244" y="1110" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 15 values pushed */
+ 0 0 0 8 48 196 8 14 0 0 4 12 48 196 12
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="c" xMin="86" yMin="-25" xMax="926" yMax="1110">
+ <contour>
+ <pt x="926" y="33" on="1"/>
+ <pt x="745" y="-25" on="0"/>
+ <pt x="585" y="-25" on="1"/>
+ <pt x="360" y="-25" on="0"/>
+ <pt x="223" y="133" on="1"/>
+ <pt x="86" y="290" on="0"/>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="809" on="0"/>
+ <pt x="226" y="959" on="1"/>
+ <pt x="365" y="1110" on="0"/>
+ <pt x="616" y="1110" on="1"/>
+ <pt x="742" y="1110" on="0"/>
+ <pt x="914" y="1074" on="1"/>
+ <pt x="914" y="910" on="1"/>
+ <pt x="750" y="959" on="0"/>
+ <pt x="652" y="959" on="1"/>
+ <pt x="308" y="959" on="0"/>
+ <pt x="308" y="543" on="1"/>
+ <pt x="308" y="347" on="0"/>
+ <pt x="397" y="241" on="1"/>
+ <pt x="485" y="134" on="0"/>
+ <pt x="644" y="134" on="1"/>
+ <pt x="765" y="134" on="0"/>
+ <pt x="926" y="203" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 21 29 2 15 40 10 48 196 10 1 2 2 1 1 23 13 12 0 4 1 2 3 0
+ 0 14 0 0 17 26 6 48 196 6 12 23 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cacute" xMin="86" yMin="-25" xMax="928" yMax="1604">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="352" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="caron" xMin="-9" yMin="1283" xMax="691" yMax="1604">
+ <contour>
+ <pt x="691" y="1604" on="1"/>
+ <pt x="450" y="1283" on="1"/>
+ <pt x="232" y="1283" on="1"/>
+ <pt x="-9" y="1604" on="1"/>
+ <pt x="139" y="1604" on="1"/>
+ <pt x="340" y="1402" on="1"/>
+ <pt x="342" y="1402" on="1"/>
+ <pt x="543" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 6 5 2 0 1 3 7 4 3 0 3 2 1 1 2 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ccaron" xMin="86" yMin="-25" xMax="957" yMax="1604">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="266" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ccedilla" xMin="86" yMin="-432" xMax="926" yMax="1110">
+ <component glyphName="c" x="0" y="0" flags="0x4"/>
+ <component glyphName="cedilla" x="260" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ccircumflex" xMin="86" yMin="-25" xMax="957" yMax="1604">
+ <contour>
+ <pt x="926" y="33" on="1"/>
+ <pt x="745" y="-25" on="0"/>
+ <pt x="585" y="-25" on="1"/>
+ <pt x="360" y="-25" on="0"/>
+ <pt x="223" y="133" on="1"/>
+ <pt x="86" y="290" on="0"/>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="809" on="0"/>
+ <pt x="226" y="959" on="1"/>
+ <pt x="365" y="1110" on="0"/>
+ <pt x="616" y="1110" on="1"/>
+ <pt x="742" y="1110" on="0"/>
+ <pt x="914" y="1074" on="1"/>
+ <pt x="914" y="910" on="1"/>
+ <pt x="750" y="959" on="0"/>
+ <pt x="652" y="959" on="1"/>
+ <pt x="308" y="959" on="0"/>
+ <pt x="308" y="543" on="1"/>
+ <pt x="308" y="347" on="0"/>
+ <pt x="397" y="241" on="1"/>
+ <pt x="485" y="134" on="0"/>
+ <pt x="644" y="134" on="1"/>
+ <pt x="765" y="134" on="0"/>
+ <pt x="926" y="203" on="1"/>
+ </contour>
+ <contour>
+ <pt x="257" y="1283" on="1"/>
+ <pt x="498" y="1604" on="1"/>
+ <pt x="716" y="1604" on="1"/>
+ <pt x="957" y="1283" on="1"/>
+ <pt x="809" y="1283" on="1"/>
+ <pt x="608" y="1485" on="1"/>
+ <pt x="606" y="1485" on="1"/>
+ <pt x="405" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 21 29 2 15 40 10 48 196 10 1 2 2 30 29 2 25 24 3 1 1 23 13 12
+ 0 4 1 2 3 0 0 26 25 1 31 28 27 24 3 2 0 14 0 0 17 26 6 48 196
+ 27 0 31 30 29 28 26 25 24 7 13 6 12 23 0 1 13 12 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cdotaccent" xMin="86" yMin="-25" xMax="926" yMax="1480">
+ <contour>
+ <pt x="926" y="33" on="1"/>
+ <pt x="745" y="-25" on="0"/>
+ <pt x="585" y="-25" on="1"/>
+ <pt x="360" y="-25" on="0"/>
+ <pt x="223" y="133" on="1"/>
+ <pt x="86" y="290" on="0"/>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="809" on="0"/>
+ <pt x="226" y="959" on="1"/>
+ <pt x="365" y="1110" on="0"/>
+ <pt x="616" y="1110" on="1"/>
+ <pt x="742" y="1110" on="0"/>
+ <pt x="914" y="1074" on="1"/>
+ <pt x="914" y="910" on="1"/>
+ <pt x="750" y="959" on="0"/>
+ <pt x="652" y="959" on="1"/>
+ <pt x="308" y="959" on="0"/>
+ <pt x="308" y="543" on="1"/>
+ <pt x="308" y="347" on="0"/>
+ <pt x="397" y="241" on="1"/>
+ <pt x="485" y="134" on="0"/>
+ <pt x="644" y="134" on="1"/>
+ <pt x="765" y="134" on="0"/>
+ <pt x="926" y="203" on="1"/>
+ </contour>
+ <contour>
+ <pt x="508" y="1283" on="1"/>
+ <pt x="508" y="1480" on="1"/>
+ <pt x="705" y="1480" on="1"/>
+ <pt x="705" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 21 29 2 15 40 10 48 196 10 1 2 2 1 1 23 13 12 0 4 1 2 3 0
+ 0 0 0 27 24 5 1 25 1 4 48 196 26 25 0 14 0 0 17 26 6 48 196 6 24
+ 0 0 25 24 4 1 26 1 4 48 196 27 26 1 23 0 1 13 12 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cedilla" xMin="168" yMin="-432" xMax="515" yMax="0">
+ <contour>
+ <pt x="284" y="0" on="1"/>
+ <pt x="381" y="0" on="1"/>
+ <pt x="321" y="-109" on="1"/>
+ <pt x="393" y="-111" on="0"/>
+ <pt x="445" y="-148" on="1"/>
+ <pt x="515" y="-197" on="0"/>
+ <pt x="515" y="-269" on="1"/>
+ <pt x="515" y="-337" on="0"/>
+ <pt x="456" y="-384" on="1"/>
+ <pt x="398" y="-432" on="0"/>
+ <pt x="311" y="-432" on="1"/>
+ <pt x="244" y="-432" on="0"/>
+ <pt x="168" y="-411" on="1"/>
+ <pt x="168" y="-330" on="1"/>
+ <pt x="218" y="-345" on="0"/>
+ <pt x="272" y="-345" on="1"/>
+ <pt x="376" y="-345" on="0"/>
+ <pt x="376" y="-271" on="1"/>
+ <pt x="376" y="-178" on="0"/>
+ <pt x="189" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 15 44 10 48 196 19 13 12 10 2 1 0 14 0 0 17 42 6 48 196 19 13 12
+ 6 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="cent" xMin="173" yMin="0" xMax="1014" yMax="1480">
+ <contour>
+ <pt x="631" y="0" on="1"/>
+ <pt x="631" y="173" on="1"/>
+ <pt x="443" y="197" on="0"/>
+ <pt x="327" y="320" on="1"/>
+ <pt x="173" y="483" on="0"/>
+ <pt x="173" y="740" on="1"/>
+ <pt x="173" y="1010" on="0"/>
+ <pt x="331" y="1161" on="1"/>
+ <pt x="441" y="1266" on="0"/>
+ <pt x="631" y="1295" on="1"/>
+ <pt x="631" y="1480" on="1"/>
+ <pt x="730" y="1480" on="1"/>
+ <pt x="730" y="1295" on="1"/>
+ <pt x="863" y="1289" on="0"/>
+ <pt x="1014" y="1249" on="1"/>
+ <pt x="1014" y="1083" on="1"/>
+ <pt x="836" y="1143" on="0"/>
+ <pt x="730" y="1153" on="1"/>
+ <pt x="730" y="313" on="1"/>
+ <pt x="866" y="313" on="0"/>
+ <pt x="1014" y="380" on="1"/>
+ <pt x="1014" y="231" on="1"/>
+ <pt x="865" y="173" on="0"/>
+ <pt x="730" y="173" on="1"/>
+ <pt x="730" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="631" y="1144" on="1"/>
+ <pt x="572" y="1135" on="0"/>
+ <pt x="542" y="1120" on="1"/>
+ <pt x="389" y="1041" on="0"/>
+ <pt x="389" y="739" on="1"/>
+ <pt x="389" y="530" on="0"/>
+ <pt x="480" y="422" on="1"/>
+ <pt x="532" y="361" on="0"/>
+ <pt x="631" y="324" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 55 values pushed */
+ 33 25 24 23 21 20 18 17 15 14 12 11 10 9 1 0 14 0 0 29 9 5 48 196 5
+ 0 0 0 33 25 10 9 1 0 11 5 11 1 4 48 196 21 20 15 14 3 24 23 18 17
+ 12 11 5 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="circumflex" xMin="-9" yMin="1283" xMax="691" yMax="1604">
+ <contour>
+ <pt x="-9" y="1283" on="1"/>
+ <pt x="232" y="1604" on="1"/>
+ <pt x="450" y="1604" on="1"/>
+ <pt x="691" y="1283" on="1"/>
+ <pt x="543" y="1283" on="1"/>
+ <pt x="342" y="1485" on="1"/>
+ <pt x="340" y="1485" on="1"/>
+ <pt x="139" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 6 5 2 1 0 3 2 1 1 7 4 3 0 3 2 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="colon" xMin="186" yMin="0" xMax="383" yMax="1086">
+ <contour>
+ <pt x="186" y="0" on="1"/>
+ <pt x="186" y="197" on="1"/>
+ <pt x="383" y="197" on="1"/>
+ <pt x="383" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="186" y="888" on="1"/>
+ <pt x="186" y="1086" on="1"/>
+ <pt x="383" y="1086" on="1"/>
+ <pt x="383" y="888" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 7 4 5 1 5 2 1 5 1 0 2 4 48 196 3 0 1 0 6 5 1 14 0
+ 0 7 6 3 2 4 3 0 1 4 48 196 5 4 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="comma" xMin="161" yMin="-321" xMax="408" yMax="247">
+ <contour>
+ <pt x="161" y="-321" on="1"/>
+ <pt x="161" y="-247" on="1"/>
+ <pt x="257" y="-220" on="0"/>
+ <pt x="257" y="-20" on="1"/>
+ <pt x="257" y="0" on="1"/>
+ <pt x="161" y="0" on="1"/>
+ <pt x="161" y="247" on="1"/>
+ <pt x="408" y="247" on="1"/>
+ <pt x="408" y="33" on="1"/>
+ <pt x="407" y="-294" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 8 5 4 3 1 0 6 13 6 7 6 1 0 14 4 3 2 7 0 3 0 0 8 7 8
+ 1 0 1 4 48 196 6 5 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="copyright" xMin="15" yMin="0" xMax="1495" yMax="1480">
+ <contour>
+ <pt x="755" y="1480" on="1"/>
+ <pt x="1060" y="1480" on="0"/>
+ <pt x="1278" y="1263" on="1"/>
+ <pt x="1495" y="1047" on="0"/>
+ <pt x="1495" y="741" on="1"/>
+ <pt x="1495" y="431" on="0"/>
+ <pt x="1277" y="216" on="1"/>
+ <pt x="1060" y="0" on="0"/>
+ <pt x="746" y="0" on="1"/>
+ <pt x="478" y="0" on="0"/>
+ <pt x="277" y="176" on="1"/>
+ <pt x="15" y="404" on="0"/>
+ <pt x="15" y="741" on="1"/>
+ <pt x="15" y="1047" on="0"/>
+ <pt x="232" y="1263" on="1"/>
+ <pt x="450" y="1480" on="0"/>
+ </contour>
+ <contour>
+ <pt x="755" y="1375" on="1"/>
+ <pt x="494" y="1375" on="0"/>
+ <pt x="307" y="1188" on="1"/>
+ <pt x="121" y="1002" on="0"/>
+ <pt x="121" y="740" on="1"/>
+ <pt x="121" y="482" on="0"/>
+ <pt x="306" y="294" on="1"/>
+ <pt x="491" y="106" on="0"/>
+ <pt x="748" y="106" on="1"/>
+ <pt x="987" y="106" on="0"/>
+ <pt x="1164" y="256" on="1"/>
+ <pt x="1390" y="448" on="0"/>
+ <pt x="1390" y="741" on="1"/>
+ <pt x="1390" y="1003" on="0"/>
+ <pt x="1203" y="1188" on="1"/>
+ <pt x="1016" y="1375" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1025" y="364" on="1"/>
+ <pt x="887" y="317" on="0"/>
+ <pt x="781" y="317" on="1"/>
+ <pt x="603" y="317" on="0"/>
+ <pt x="488" y="434" on="1"/>
+ <pt x="373" y="551" on="0"/>
+ <pt x="373" y="736" on="1"/>
+ <pt x="373" y="927" on="0"/>
+ <pt x="485" y="1042" on="1"/>
+ <pt x="597" y="1157" on="0"/>
+ <pt x="787" y="1157" on="1"/>
+ <pt x="884" y="1157" on="0"/>
+ <pt x="1001" y="1133" on="1"/>
+ <pt x="1025" y="1128" on="1"/>
+ <pt x="1025" y="1010" on="1"/>
+ <pt x="895" y="1063" on="0"/>
+ <pt x="794" y="1063" on="1"/>
+ <pt x="668" y="1063" on="0"/>
+ <pt x="591" y="974" on="1"/>
+ <pt x="514" y="884" on="0"/>
+ <pt x="514" y="739" on="1"/>
+ <pt x="514" y="593" on="0"/>
+ <pt x="594" y="508" on="1"/>
+ <pt x="674" y="423" on="0"/>
+ <pt x="809" y="423" on="1"/>
+ <pt x="914" y="423" on="0"/>
+ <pt x="1025" y="482" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 0 0 56 20 34 48 21 42 24 20 8 16 20 0 48 196 8 2 0 0 42 34 1 1 58
+ 46 45 42 34 32 6 0 2 3 0 0 14 0 0 52 42 38 28 17 4 20 17 12 48 196
+ 58 46 45 38 32 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="currency" xMin="122" yMin="293" xMax="1016" yMax="1188">
+ <contour>
+ <pt x="365" y="449" on="1"/>
+ <pt x="209" y="293" on="1"/>
+ <pt x="122" y="380" on="1"/>
+ <pt x="277" y="536" on="1"/>
+ <pt x="214" y="640" on="0"/>
+ <pt x="214" y="740" on="1"/>
+ <pt x="214" y="841" on="0"/>
+ <pt x="278" y="944" on="1"/>
+ <pt x="122" y="1100" on="1"/>
+ <pt x="209" y="1188" on="1"/>
+ <pt x="365" y="1032" on="1"/>
+ <pt x="463" y="1095" on="0"/>
+ <pt x="569" y="1095" on="1"/>
+ <pt x="675" y="1095" on="0"/>
+ <pt x="773" y="1032" on="1"/>
+ <pt x="929" y="1188" on="1"/>
+ <pt x="1016" y="1100" on="1"/>
+ <pt x="860" y="944" on="1"/>
+ <pt x="924" y="841" on="0"/>
+ <pt x="924" y="740" on="1"/>
+ <pt x="924" y="639" on="0"/>
+ <pt x="861" y="536" on="1"/>
+ <pt x="1016" y="380" on="1"/>
+ <pt x="929" y="293" on="1"/>
+ <pt x="773" y="449" on="1"/>
+ <pt x="674" y="385" on="0"/>
+ <pt x="569" y="385" on="1"/>
+ <pt x="464" y="385" on="0"/>
+ </contour>
+ <contour>
+ <pt x="569" y="972" on="1"/>
+ <pt x="471" y="972" on="0"/>
+ <pt x="404" y="905" on="1"/>
+ <pt x="337" y="838" on="0"/>
+ <pt x="337" y="739" on="1"/>
+ <pt x="337" y="643" on="0"/>
+ <pt x="404" y="576" on="1"/>
+ <pt x="470" y="508" on="0"/>
+ <pt x="566" y="508" on="1"/>
+ <pt x="655" y="508" on="0"/>
+ <pt x="719" y="562" on="1"/>
+ <pt x="801" y="631" on="0"/>
+ <pt x="801" y="741" on="1"/>
+ <pt x="801" y="838" on="0"/>
+ <pt x="734" y="905" on="1"/>
+ <pt x="666" y="972" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 0 36 6 26 28 6 12 48 196 12 1 1 16 15 9 8 4 13 1 0 1 24 23 22
+ 21 17 14 10 7 3 2 1 0 12 13 26 1 0 14 0 0 40 6 19 32 6 5 48 196
+ 24 23 22 21 19 17 16 15 14 10 9 8 7 5 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="d" xMin="86" yMin="-25" xMax="984" yMax="1579">
+ <contour>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="937" on="1"/>
+ <pt x="648" y="962" on="0"/>
+ <pt x="582" y="962" on="1"/>
+ <pt x="299" y="962" on="0"/>
+ <pt x="299" y="532" on="1"/>
+ <pt x="299" y="354" on="0"/>
+ <pt x="355" y="251" on="1"/>
+ <pt x="410" y="148" on="0"/>
+ <pt x="504" y="148" on="1"/>
+ <pt x="630" y="148" on="0"/>
+ </contour>
+ <contour>
+ <pt x="787" y="203" on="1"/>
+ <pt x="731" y="101" on="0"/>
+ <pt x="669" y="49" on="1"/>
+ <pt x="581" y="-25" on="0"/>
+ <pt x="462" y="-25" on="1"/>
+ <pt x="293" y="-25" on="0"/>
+ <pt x="190" y="123" on="1"/>
+ <pt x="86" y="270" on="0"/>
+ <pt x="86" y="514" on="1"/>
+ <pt x="86" y="798" on="0"/>
+ <pt x="220" y="954" on="1"/>
+ <pt x="354" y="1110" on="0"/>
+ <pt x="597" y="1110" on="1"/>
+ <pt x="691" y="1110" on="0"/>
+ <pt x="787" y="1086" on="1"/>
+ <pt x="787" y="1579" on="1"/>
+ <pt x="984" y="1579" on="1"/>
+ <pt x="984" y="0" on="1"/>
+ <pt x="787" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 23 1 15 2 9 3 1 25 11 9 3 1 0 6 1 28 3 0 27 26 1 29 28 1 2
+ 0 14 19 5 0 0 0 29 26 25 11 1 0 4 5 27 1 4 48 196 28 27 1 29 26
+ 25 11 1 0 5 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dagger" xMin="150" yMin="-296" xMax="989" yMax="1480">
+ <contour>
+ <pt x="471" y="-296" on="1"/>
+ <pt x="495" y="839" on="1"/>
+ <pt x="150" y="814" on="1"/>
+ <pt x="150" y="962" on="1"/>
+ <pt x="495" y="938" on="1"/>
+ <pt x="471" y="1480" on="1"/>
+ <pt x="668" y="1480" on="1"/>
+ <pt x="643" y="938" on="1"/>
+ <pt x="989" y="962" on="1"/>
+ <pt x="989" y="814" on="1"/>
+ <pt x="643" y="839" on="1"/>
+ <pt x="668" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 42 values pushed */
+ 1 10 9 8 7 4 3 2 1 8 5 2 3 0 11 0 1 0 6 5 0 14 11 10 7
+ 6 5 4 1 0 8 8 2 3 9 8 1 3 2 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="daggerdbl" xMin="150" yMin="-296" xMax="989" yMax="1480">
+ <contour>
+ <pt x="471" y="-296" on="1"/>
+ <pt x="495" y="247" on="1"/>
+ <pt x="150" y="222" on="1"/>
+ <pt x="150" y="370" on="1"/>
+ <pt x="495" y="345" on="1"/>
+ <pt x="495" y="839" on="1"/>
+ <pt x="150" y="814" on="1"/>
+ <pt x="150" y="962" on="1"/>
+ <pt x="495" y="938" on="1"/>
+ <pt x="471" y="1480" on="1"/>
+ <pt x="668" y="1480" on="1"/>
+ <pt x="643" y="938" on="1"/>
+ <pt x="989" y="962" on="1"/>
+ <pt x="989" y="814" on="1"/>
+ <pt x="643" y="839" on="1"/>
+ <pt x="643" y="345" on="1"/>
+ <pt x="989" y="370" on="1"/>
+ <pt x="989" y="222" on="1"/>
+ <pt x="643" y="247" on="1"/>
+ <pt x="668" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 1 18 17 16 15 14 13 12 11 8 7 6 5 4 3 2 1 16 9 2 3 0 19 0 1
+ 0 10 9 0 14 19 10 2 12 11 3 9 0 2 1 2 3 0 0 18 15 14 11 7 3
+ 1 1 4 48 196 17 16 13 12 3 8 5 4 1 3 7 6 3 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dcaron" xMin="86" yMin="-25" xMax="1259" yMax="1579">
+ <contour>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="937" on="1"/>
+ <pt x="648" y="962" on="0"/>
+ <pt x="582" y="962" on="1"/>
+ <pt x="299" y="962" on="0"/>
+ <pt x="299" y="532" on="1"/>
+ <pt x="299" y="354" on="0"/>
+ <pt x="355" y="251" on="1"/>
+ <pt x="410" y="148" on="0"/>
+ <pt x="504" y="148" on="1"/>
+ <pt x="630" y="148" on="0"/>
+ </contour>
+ <contour>
+ <pt x="787" y="203" on="1"/>
+ <pt x="731" y="101" on="0"/>
+ <pt x="669" y="49" on="1"/>
+ <pt x="581" y="-25" on="0"/>
+ <pt x="462" y="-25" on="1"/>
+ <pt x="293" y="-25" on="0"/>
+ <pt x="190" y="123" on="1"/>
+ <pt x="86" y="270" on="0"/>
+ <pt x="86" y="514" on="1"/>
+ <pt x="86" y="798" on="0"/>
+ <pt x="220" y="954" on="1"/>
+ <pt x="354" y="1110" on="0"/>
+ <pt x="597" y="1110" on="1"/>
+ <pt x="691" y="1110" on="0"/>
+ <pt x="787" y="1086" on="1"/>
+ <pt x="787" y="1579" on="1"/>
+ <pt x="984" y="1579" on="1"/>
+ <pt x="984" y="0" on="1"/>
+ <pt x="787" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1061" y="1125" on="1"/>
+ <pt x="1061" y="1184" on="1"/>
+ <pt x="1138" y="1205" on="0"/>
+ <pt x="1138" y="1365" on="1"/>
+ <pt x="1138" y="1382" on="1"/>
+ <pt x="1061" y="1382" on="1"/>
+ <pt x="1061" y="1579" on="1"/>
+ <pt x="1259" y="1579" on="1"/>
+ <pt x="1259" y="1408" on="1"/>
+ <pt x="1258" y="1146" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 23 1 15 2 1 38 35 34 33 31 30 6 26 1 3 0 9 3 1 25 11 9 3 1 0
+ 6 1 28 3 0 37 36 27 26 3 29 28 1 2 0 14 34 33 2 37 30 3 19 5 0
+ 0 0 36 35 31 30 4 3 37 29 26 25 11 1 0 4 5 27 2 4 48 196 38 37 1
+ 28 27 1 29 26 25 11 1 0 5 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dcroat" xMin="86" yMin="-25" xMax="1132" yMax="1579">
+ <contour>
+ <pt x="787" y="1258" on="1"/>
+ <pt x="466" y="1258" on="1"/>
+ <pt x="466" y="1382" on="1"/>
+ <pt x="787" y="1382" on="1"/>
+ <pt x="787" y="1579" on="1"/>
+ <pt x="984" y="1579" on="1"/>
+ <pt x="984" y="1382" on="1"/>
+ <pt x="1132" y="1382" on="1"/>
+ <pt x="1132" y="1258" on="1"/>
+ <pt x="984" y="1258" on="1"/>
+ <pt x="984" y="0" on="1"/>
+ <pt x="787" y="0" on="1"/>
+ <pt x="787" y="203" on="1"/>
+ <pt x="731" y="101" on="0"/>
+ <pt x="669" y="49" on="1"/>
+ <pt x="581" y="-25" on="0"/>
+ <pt x="462" y="-25" on="1"/>
+ <pt x="293" y="-25" on="0"/>
+ <pt x="190" y="123" on="1"/>
+ <pt x="86" y="270" on="0"/>
+ <pt x="86" y="514" on="1"/>
+ <pt x="86" y="798" on="0"/>
+ <pt x="220" y="954" on="1"/>
+ <pt x="354" y="1110" on="0"/>
+ <pt x="597" y="1110" on="1"/>
+ <pt x="691" y="1110" on="0"/>
+ <pt x="787" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="937" on="1"/>
+ <pt x="648" y="962" on="0"/>
+ <pt x="582" y="962" on="1"/>
+ <pt x="299" y="962" on="0"/>
+ <pt x="299" y="532" on="1"/>
+ <pt x="299" y="354" on="0"/>
+ <pt x="355" y="251" on="1"/>
+ <pt x="410" y="148" on="0"/>
+ <pt x="504" y="148" on="1"/>
+ <pt x="630" y="148" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 90 values pushed */
+ 0 0 36 30 16 30 40 24 48 196 24 1 16 2 1 28 27 26 12 4 1 10 3 0 0
+ 0 9 8 1 0 6 3 2 1 4 48 196 5 4 1 7 6 3 2 3 11 10 1 3 0
+ 14 0 0 32 9 20 48 196 8 7 2 13 5 2 1 20 0 0 0 28 27 26 12 11 4
+ 3 0 4 7 5 1 4 48 196 10 9 6 5 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="degree" xMin="114" yMin="925" xMax="706" yMax="1517">
+ <contour>
+ <pt x="410" y="1517" on="1"/>
+ <pt x="531" y="1517" on="0"/>
+ <pt x="619" y="1430" on="1"/>
+ <pt x="706" y="1344" on="0"/>
+ <pt x="706" y="1222" on="1"/>
+ <pt x="706" y="1098" on="0"/>
+ <pt x="619" y="1012" on="1"/>
+ <pt x="531" y="925" on="0"/>
+ <pt x="406" y="925" on="1"/>
+ <pt x="300" y="925" on="0"/>
+ <pt x="219" y="995" on="1"/>
+ <pt x="114" y="1087" on="0"/>
+ <pt x="114" y="1221" on="1"/>
+ <pt x="114" y="1344" on="0"/>
+ <pt x="201" y="1430" on="1"/>
+ <pt x="289" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="410" y="1394" on="1"/>
+ <pt x="339" y="1394" on="0"/>
+ <pt x="288" y="1343" on="1"/>
+ <pt x="237" y="1293" on="0"/>
+ <pt x="237" y="1222" on="1"/>
+ <pt x="237" y="1151" on="0"/>
+ <pt x="288" y="1100" on="1"/>
+ <pt x="338" y="1049" on="0"/>
+ <pt x="408" y="1049" on="1"/>
+ <pt x="473" y="1049" on="0"/>
+ <pt x="521" y="1090" on="1"/>
+ <pt x="583" y="1142" on="0"/>
+ <pt x="583" y="1222" on="1"/>
+ <pt x="583" y="1293" on="0"/>
+ <pt x="532" y="1343" on="1"/>
+ <pt x="481" y="1394" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 24 6 8 16 6 0 48 196 0 0 1 8 0 0 14 0 0 28 6 4 20 6 12
+ 48 196 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dieresis" xMin="57" yMin="1283" xMax="625" yMax="1456">
+ <contour>
+ <pt x="57" y="1283" on="1"/>
+ <pt x="57" y="1456" on="1"/>
+ <pt x="230" y="1456" on="1"/>
+ <pt x="230" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="452" y="1283" on="1"/>
+ <pt x="452" y="1456" on="1"/>
+ <pt x="625" y="1456" on="1"/>
+ <pt x="625" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 7 4 3 0 13 3 1 1 4 48 196 6 5 2 1 3 0 14 0 0 5 4 13
+ 1 6 3 2 13 1 0 2 4 48 196 7 6 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="divide" xMin="104" yMin="0" xMax="1091" yMax="1184">
+ <contour>
+ <pt x="104" y="518" on="1"/>
+ <pt x="104" y="666" on="1"/>
+ <pt x="1091" y="666" on="1"/>
+ <pt x="1091" y="518" on="1"/>
+ </contour>
+ <contour>
+ <pt x="474" y="938" on="1"/>
+ <pt x="474" y="1184" on="1"/>
+ <pt x="721" y="1184" on="1"/>
+ <pt x="721" y="938" on="1"/>
+ </contour>
+ <contour>
+ <pt x="474" y="0" on="1"/>
+ <pt x="474" y="247" on="1"/>
+ <pt x="721" y="247" on="1"/>
+ <pt x="721" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 0 0 10 9 8 1 8 7 4 8 1 5 3 0 7 1 1 3 4 48 196 11 8 1 6
+ 5 1 2 1 1 3 0 14 0 0 11 10 7 6 8 3 4 1 4 48 196 9 8 5 4
+ 3 3 2 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dollar" xMin="103" yMin="-123" xMax="942" yMax="1604">
+ <contour>
+ <pt x="498" y="-123" on="1"/>
+ <pt x="498" y="0" on="1"/>
+ <pt x="322" y="0" on="0"/>
+ <pt x="103" y="83" on="1"/>
+ <pt x="103" y="253" on="1"/>
+ <pt x="328" y="148" on="0"/>
+ <pt x="498" y="148" on="1"/>
+ <pt x="498" y="679" on="1"/>
+ <pt x="312" y="795" on="0"/>
+ <pt x="235" y="881" on="1"/>
+ <pt x="147" y="981" on="0"/>
+ <pt x="147" y="1125" on="1"/>
+ <pt x="147" y="1296" on="0"/>
+ <pt x="274" y="1398" on="1"/>
+ <pt x="360" y="1467" on="0"/>
+ <pt x="498" y="1480" on="1"/>
+ <pt x="498" y="1604" on="1"/>
+ <pt x="597" y="1604" on="1"/>
+ <pt x="597" y="1480" on="1"/>
+ <pt x="741" y="1480" on="0"/>
+ <pt x="918" y="1413" on="1"/>
+ <pt x="918" y="1252" on="1"/>
+ <pt x="727" y="1335" on="0"/>
+ <pt x="597" y="1345" on="1"/>
+ <pt x="597" y="818" on="1"/>
+ <pt x="609" y="810" on="1"/>
+ <pt x="635" y="794" on="0"/>
+ <pt x="658" y="781" on="1"/>
+ <pt x="670" y="773" on="1"/>
+ <pt x="796" y="698" on="0"/>
+ <pt x="859" y="632" on="1"/>
+ <pt x="942" y="546" on="0"/>
+ <pt x="942" y="413" on="1"/>
+ <pt x="942" y="232" on="0"/>
+ <pt x="820" y="113" on="1"/>
+ <pt x="735" y="31" on="0"/>
+ <pt x="597" y="0" on="1"/>
+ <pt x="597" y="-123" on="1"/>
+ </contour>
+ <contour>
+ <pt x="597" y="160" on="1"/>
+ <pt x="769" y="227" on="0"/>
+ <pt x="769" y="385" on="1"/>
+ <pt x="769" y="467" on="0"/>
+ <pt x="721" y="520" on="1"/>
+ <pt x="684" y="560" on="0"/>
+ <pt x="597" y="621" on="1"/>
+ </contour>
+ <contour>
+ <pt x="498" y="883" on="1"/>
+ <pt x="498" y="1339" on="1"/>
+ <pt x="319" y="1278" on="0"/>
+ <pt x="319" y="1133" on="1"/>
+ <pt x="319" y="1002" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 46 45 44 38 37 36 24 23 21 20 18 17 16 15 7 6 4 3 1 0 14 0 0 48 13
+ 11 40 13 32 48 196 11 11 0 3 2 32 20 0 0 44 38 37 36 24 23 18 17 11 7
+ 0 1 4 48 196 21 20 1 46 45 16 15 7 6 1 0 7 4 3 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotaccent" xMin="242" yMin="1283" xMax="439" yMax="1480">
+ <contour>
+ <pt x="242" y="1283" on="1"/>
+ <pt x="242" y="1480" on="1"/>
+ <pt x="439" y="1480" on="1"/>
+ <pt x="439" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 0 0 3 0 5 1 1 1 4 48 196 2 1 0 14 0 0 3 2 4 1 0 1 4 48
+ 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotlessi" xMin="129" yMin="0" xMax="326" yMax="1086">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="1086" on="1"/>
+ <pt x="326" y="1086" on="1"/>
+ <pt x="326" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 23 values pushed */
+ 3 0 1 0 2 1 1 14 0 0 3 2 4 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotlessj" xMin="-155" yMin="-419" xMax="331" yMax="1086">
+ <contour>
+ <pt x="-155" y="-387" on="1"/>
+ <pt x="-155" y="-231" on="1"/>
+ <pt x="-75" y="-271" on="0"/>
+ <pt x="-5" y="-271" on="1"/>
+ <pt x="92" y="-271" on="0"/>
+ <pt x="115" y="-197" on="1"/>
+ <pt x="133" y="-136" on="0"/>
+ <pt x="133" y="0" on="1"/>
+ <pt x="133" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="0" on="1"/>
+ <pt x="331" y="-419" on="0"/>
+ <pt x="11" y="-419" on="1"/>
+ <pt x="-77" y="-419" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 40 values pushed */
+ 0 0 3 40 12 48 196 1 10 7 1 0 4 13 12 2 0 9 8 1 14 0 0 8 7
+ 4 1 9 1 4 48 196 10 9 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="dotmath" xMin="161" yMin="491" xMax="408" yMax="738">
+ <contour>
+ <pt x="161" y="491" on="1"/>
+ <pt x="161" y="738" on="1"/>
+ <pt x="408" y="738" on="1"/>
+ <pt x="408" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 8 1 1 1 4 48 196 2 1 1 0 14 0 0 3 2 8 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="e" xMin="86" yMin="-25" xMax="1022" yMax="1110">
+ <contour>
+ <pt x="818" y="660" on="1"/>
+ <pt x="815" y="758" on="0"/>
+ <pt x="798" y="809" on="1"/>
+ <pt x="746" y="963" on="0"/>
+ <pt x="572" y="963" on="1"/>
+ <pt x="451" y="963" on="0"/>
+ <pt x="381" y="891" on="1"/>
+ <pt x="313" y="822" on="0"/>
+ <pt x="296" y="660" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1013" y="191" on="1"/>
+ <pt x="1013" y="35" on="1"/>
+ <pt x="810" y="-25" on="0"/>
+ <pt x="641" y="-25" on="1"/>
+ <pt x="386" y="-25" on="0"/>
+ <pt x="236" y="133" on="1"/>
+ <pt x="86" y="291" on="0"/>
+ <pt x="86" y="557" on="1"/>
+ <pt x="86" y="810" on="0"/>
+ <pt x="219" y="960" on="1"/>
+ <pt x="351" y="1110" on="0"/>
+ <pt x="577" y="1110" on="1"/>
+ <pt x="836" y="1110" on="0"/>
+ <pt x="943" y="926" on="1"/>
+ <pt x="1022" y="789" on="0"/>
+ <pt x="1019" y="573" on="1"/>
+ <pt x="1018" y="512" on="1"/>
+ <pt x="293" y="512" on="1"/>
+ <pt x="305" y="393" on="0"/>
+ <pt x="332" y="331" on="1"/>
+ <pt x="420" y="125" on="0"/>
+ <pt x="683" y="125" on="1"/>
+ <pt x="832" y="125" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 0 0 30 40 12 48 196 20 1 12 2 4 1 4 1 0 2 0 1 10 9 2 25 2 3
+ 0 26 25 1 8 0 1 2 0 14 25 9 26 8 0 3 13 16 9 10 9 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eacute" xMin="86" yMin="-25" xMax="1022" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="315" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ebreve" xMin="86" yMin="-25" xMax="1022" yMax="1604">
+ <contour>
+ <pt x="818" y="660" on="1"/>
+ <pt x="815" y="758" on="0"/>
+ <pt x="798" y="809" on="1"/>
+ <pt x="746" y="963" on="0"/>
+ <pt x="572" y="963" on="1"/>
+ <pt x="451" y="963" on="0"/>
+ <pt x="381" y="891" on="1"/>
+ <pt x="313" y="822" on="0"/>
+ <pt x="296" y="660" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1013" y="191" on="1"/>
+ <pt x="1013" y="35" on="1"/>
+ <pt x="810" y="-25" on="0"/>
+ <pt x="641" y="-25" on="1"/>
+ <pt x="386" y="-25" on="0"/>
+ <pt x="236" y="133" on="1"/>
+ <pt x="86" y="291" on="0"/>
+ <pt x="86" y="557" on="1"/>
+ <pt x="86" y="810" on="0"/>
+ <pt x="219" y="960" on="1"/>
+ <pt x="351" y="1110" on="0"/>
+ <pt x="577" y="1110" on="1"/>
+ <pt x="836" y="1110" on="0"/>
+ <pt x="943" y="926" on="1"/>
+ <pt x="1022" y="789" on="0"/>
+ <pt x="1019" y="573" on="1"/>
+ <pt x="1018" y="512" on="1"/>
+ <pt x="293" y="512" on="1"/>
+ <pt x="305" y="393" on="0"/>
+ <pt x="332" y="331" on="1"/>
+ <pt x="420" y="125" on="0"/>
+ <pt x="683" y="125" on="1"/>
+ <pt x="832" y="125" on="0"/>
+ </contour>
+ <contour>
+ <pt x="236" y="1604" on="1"/>
+ <pt x="359" y="1604" on="1"/>
+ <pt x="380" y="1511" on="0"/>
+ <pt x="434" y="1470" on="1"/>
+ <pt x="486" y="1431" on="0"/>
+ <pt x="569" y="1431" on="1"/>
+ <pt x="663" y="1431" on="0"/>
+ <pt x="717" y="1480" on="1"/>
+ <pt x="760" y="1520" on="0"/>
+ <pt x="779" y="1604" on="1"/>
+ <pt x="902" y="1604" on="1"/>
+ <pt x="885" y="1469" on="0"/>
+ <pt x="813" y="1389" on="1"/>
+ <pt x="718" y="1283" on="0"/>
+ <pt x="569" y="1283" on="1"/>
+ <pt x="412" y="1283" on="0"/>
+ <pt x="317" y="1398" on="1"/>
+ <pt x="253" y="1475" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 37 40 46 30 40 12 48 196 20 1 12 2 4 1 4 1 0 2 0 1 10 9 2
+ 25 2 3 0 1 42 41 33 32 4 13 46 1 0 26 25 1 8 0 1 2 0 14 25 9
+ 42 41 33 32 26 8 0 7 13 16 9 10 9 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ecaron" xMin="86" yMin="-25" xMax="1022" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="228" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ecircumflex" xMin="86" yMin="-25" xMax="1022" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="240" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="edieresis" xMin="86" yMin="-25" xMax="1022" yMax="1456">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="241" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="edotaccent" xMin="86" yMin="-25" xMax="1022" yMax="1480">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="dotaccent" x="228" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="egrave" xMin="86" yMin="-25" xMax="1022" yMax="1604">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="143" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="eight" xMin="99" yMin="-37" xMax="1089" yMax="1517">
+ <contour>
+ <pt x="393" y="806" on="1"/>
+ <pt x="295" y="877" on="0"/>
+ <pt x="246" y="942" on="1"/>
+ <pt x="176" y="1036" on="0"/>
+ <pt x="176" y="1145" on="1"/>
+ <pt x="176" y="1308" on="0"/>
+ <pt x="299" y="1412" on="1"/>
+ <pt x="422" y="1517" on="0"/>
+ <pt x="620" y="1517" on="1"/>
+ <pt x="804" y="1517" on="0"/>
+ <pt x="917" y="1428" on="1"/>
+ <pt x="1030" y="1340" on="0"/>
+ <pt x="1030" y="1196" on="1"/>
+ <pt x="1030" y="1067" on="0"/>
+ <pt x="930" y="952" on="1"/>
+ <pt x="869" y="883" on="0"/>
+ <pt x="754" y="806" on="1"/>
+ <pt x="904" y="729" on="0"/>
+ <pt x="981" y="647" on="1"/>
+ <pt x="1089" y="531" on="0"/>
+ <pt x="1089" y="380" on="1"/>
+ <pt x="1089" y="197" on="0"/>
+ <pt x="948" y="80" on="1"/>
+ <pt x="808" y="-37" on="0"/>
+ <pt x="585" y="-37" on="1"/>
+ <pt x="366" y="-37" on="0"/>
+ <pt x="233" y="74" on="1"/>
+ <pt x="99" y="185" on="0"/>
+ <pt x="99" y="368" on="1"/>
+ <pt x="99" y="528" on="0"/>
+ <pt x="207" y="654" on="1"/>
+ <pt x="271" y="730" on="0"/>
+ </contour>
+ <contour>
+ <pt x="644" y="868" on="1"/>
+ <pt x="851" y="1010" on="0"/>
+ <pt x="851" y="1164" on="1"/>
+ <pt x="851" y="1258" on="0"/>
+ <pt x="783" y="1313" on="1"/>
+ <pt x="715" y="1369" on="0"/>
+ <pt x="599" y="1369" on="1"/>
+ <pt x="489" y="1369" on="0"/>
+ <pt x="422" y="1316" on="1"/>
+ <pt x="355" y="1264" on="0"/>
+ <pt x="355" y="1176" on="1"/>
+ <pt x="355" y="1071" on="0"/>
+ <pt x="468" y="982" on="1"/>
+ <pt x="526" y="936" on="0"/>
+ </contour>
+ <contour>
+ <pt x="500" y="726" on="1"/>
+ <pt x="390" y="640" on="0"/>
+ <pt x="346" y="577" on="1"/>
+ <pt x="296" y="505" on="0"/>
+ <pt x="296" y="397" on="1"/>
+ <pt x="296" y="268" on="0"/>
+ <pt x="378" y="190" on="1"/>
+ <pt x="460" y="111" on="0"/>
+ <pt x="595" y="111" on="1"/>
+ <pt x="723" y="111" on="0"/>
+ <pt x="804" y="178" on="1"/>
+ <pt x="886" y="245" on="0"/>
+ <pt x="886" y="352" on="1"/>
+ <pt x="886" y="447" on="0"/>
+ <pt x="823" y="512" on="1"/>
+ <pt x="770" y="566" on="0"/>
+ <pt x="640" y="643" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 51 values pushed */
+ 0 0 54 40 24 38 40 8 48 196 24 2 8 0 1 1 46 32 16 0 4 0 2 3 0
+ 0 14 0 0 58 43 20 50 41 28 42 14 4 34 14 12 48 196 46 32 28 20 16 12 4
+ 0
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ellipsis" xMin="247" yMin="0" xMax="1802" yMax="197">
+ <contour>
+ <pt x="247" y="0" on="1"/>
+ <pt x="247" y="197" on="1"/>
+ <pt x="444" y="197" on="1"/>
+ <pt x="444" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="926" y="0" on="1"/>
+ <pt x="926" y="197" on="1"/>
+ <pt x="1123" y="197" on="1"/>
+ <pt x="1123" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1604" y="0" on="1"/>
+ <pt x="1604" y="197" on="1"/>
+ <pt x="1802" y="197" on="1"/>
+ <pt x="1802" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 10 9 6 5 2 1 5 5 0 1 4 48 196 11 8 7 4 3 0 5 0 14 0
+ 0 9 8 4 1 10 7 6 4 1 4 3 2 4 1 0 3 4 48 196 11 10 1 5 4
+ 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="emacron" xMin="86" yMin="-25" xMax="1022" yMax="1431">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="228" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="emdash" xMin="99" yMin="543" xMax="1950" yMax="642">
+ <contour>
+ <pt x="99" y="543" on="1"/>
+ <pt x="99" y="642" on="1"/>
+ <pt x="1950" y="642" on="1"/>
+ <pt x="1950" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 11 1 1 1 4 48 196 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="endash" xMin="101" yMin="543" xMax="1039" yMax="666">
+ <contour>
+ <pt x="101" y="543" on="1"/>
+ <pt x="101" y="666" on="1"/>
+ <pt x="1039" y="666" on="1"/>
+ <pt x="1039" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 196 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eng" xMin="154" yMin="-420" xMax="997" yMax="1110">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1086" on="1"/>
+ <pt x="351" y="1086" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="424" y="984" on="0"/>
+ <pt x="495" y="1035" on="1"/>
+ <pt x="598" y="1110" on="0"/>
+ <pt x="721" y="1110" on="1"/>
+ <pt x="997" y="1110" on="0"/>
+ <pt x="997" y="780" on="1"/>
+ <pt x="997" y="-92" on="1"/>
+ <pt x="997" y="-420" on="0"/>
+ <pt x="679" y="-420" on="1"/>
+ <pt x="605" y="-420" on="0"/>
+ <pt x="528" y="-399" on="1"/>
+ <pt x="528" y="-245" on="1"/>
+ <pt x="593" y="-272" on="0"/>
+ <pt x="651" y="-272" on="1"/>
+ <pt x="799" y="-272" on="0"/>
+ <pt x="799" y="-55" on="1"/>
+ <pt x="799" y="716" on="1"/>
+ <pt x="799" y="847" on="0"/>
+ <pt x="772" y="894" on="1"/>
+ <pt x="744" y="941" on="0"/>
+ <pt x="668" y="941" on="1"/>
+ <pt x="506" y="941" on="0"/>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 24 30 7 17 40 12 48 196 7 1 26 20 9 3 4 1 0 3 19 15 14 10 4
+ 13 12 0 27 0 1 0 2 1 1 14 0 0 20 19 4 1 9 27 26 3 2 4 3 0
+ 2 4 48 196 10 9 1 15 14 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eogonek" xMin="86" yMin="-370" xMax="1022" yMax="1110">
+ <component glyphName="e" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="356" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="equal" xMin="104" yMin="333" xMax="1091" yMax="851">
+ <contour>
+ <pt x="104" y="333" on="1"/>
+ <pt x="104" y="481" on="1"/>
+ <pt x="1091" y="481" on="1"/>
+ <pt x="1091" y="333" on="1"/>
+ </contour>
+ <contour>
+ <pt x="104" y="703" on="1"/>
+ <pt x="104" y="851" on="1"/>
+ <pt x="1091" y="851" on="1"/>
+ <pt x="1091" y="703" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 0 0 7 4 7 1 5 2 1 7 1 0 2 4 48 196 6 5 1 3 0 1 2 0 14
+ 7 6 3 2 3 5 4 1 0 3 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="estimated" xMin="86" yMin="-25" xMax="1022" yMax="1110">
+ <contour>
+ <pt x="818" y="660" on="1"/>
+ <pt x="815" y="758" on="0"/>
+ <pt x="798" y="809" on="1"/>
+ <pt x="746" y="963" on="0"/>
+ <pt x="572" y="963" on="1"/>
+ <pt x="451" y="963" on="0"/>
+ <pt x="381" y="891" on="1"/>
+ <pt x="313" y="822" on="0"/>
+ <pt x="296" y="660" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1013" y="191" on="1"/>
+ <pt x="1013" y="35" on="1"/>
+ <pt x="810" y="-25" on="0"/>
+ <pt x="641" y="-25" on="1"/>
+ <pt x="386" y="-25" on="0"/>
+ <pt x="236" y="133" on="1"/>
+ <pt x="86" y="291" on="0"/>
+ <pt x="86" y="557" on="1"/>
+ <pt x="86" y="810" on="0"/>
+ <pt x="219" y="960" on="1"/>
+ <pt x="351" y="1110" on="0"/>
+ <pt x="577" y="1110" on="1"/>
+ <pt x="836" y="1110" on="0"/>
+ <pt x="943" y="926" on="1"/>
+ <pt x="1022" y="789" on="0"/>
+ <pt x="1019" y="573" on="1"/>
+ <pt x="1018" y="512" on="1"/>
+ <pt x="293" y="512" on="1"/>
+ <pt x="305" y="393" on="0"/>
+ <pt x="332" y="331" on="1"/>
+ <pt x="420" y="125" on="0"/>
+ <pt x="683" y="125" on="1"/>
+ <pt x="832" y="125" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 0 0 30 40 12 48 196 20 1 12 2 4 1 4 1 0 2 0 1 10 9 2 25 2 3
+ 0 26 25 1 8 0 1 2 0 14 25 9 26 8 0 3 13 16 9 10 9 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="eth" xMin="86" yMin="-25" xMax="1052" yMax="1676">
+ <contour>
+ <pt x="126" y="1434" on="1"/>
+ <pt x="126" y="1583" on="1"/>
+ <pt x="326" y="1583" on="0"/>
+ <pt x="488" y="1507" on="1"/>
+ <pt x="642" y="1676" on="1"/>
+ <pt x="721" y="1588" on="1"/>
+ <pt x="591" y="1445" on="1"/>
+ <pt x="716" y="1349" on="0"/>
+ <pt x="783" y="1274" on="1"/>
+ <pt x="1052" y="975" on="0"/>
+ <pt x="1052" y="550" on="1"/>
+ <pt x="1052" y="281" on="0"/>
+ <pt x="924" y="128" on="1"/>
+ <pt x="796" y="-25" on="0"/>
+ <pt x="575" y="-25" on="1"/>
+ <pt x="351" y="-25" on="0"/>
+ <pt x="219" y="127" on="1"/>
+ <pt x="86" y="279" on="0"/>
+ <pt x="86" y="535" on="1"/>
+ <pt x="86" y="793" on="0"/>
+ <pt x="216" y="939" on="1"/>
+ <pt x="345" y="1086" on="0"/>
+ <pt x="570" y="1086" on="1"/>
+ <pt x="624" y="1086" on="0"/>
+ <pt x="690" y="1072" on="1"/>
+ <pt x="613" y="1217" on="0"/>
+ <pt x="473" y="1316" on="1"/>
+ <pt x="324" y="1152" on="1"/>
+ <pt x="245" y="1239" on="1"/>
+ <pt x="373" y="1380" on="1"/>
+ <pt x="271" y="1434" on="0"/>
+ </contour>
+ <contour>
+ <pt x="566" y="938" on="1"/>
+ <pt x="439" y="938" on="0"/>
+ <pt x="368" y="832" on="1"/>
+ <pt x="296" y="726" on="0"/>
+ <pt x="296" y="531" on="1"/>
+ <pt x="296" y="123" on="0"/>
+ <pt x="570" y="123" on="1"/>
+ <pt x="842" y="123" on="0"/>
+ <pt x="842" y="530" on="1"/>
+ <pt x="842" y="938" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 37 40 14 31 40 22 48 196 22 1 14 2 1 1 29 28 27 26 6 0 6 0 1
+ 3 0 0 1 1 24 1 2 2 0 0 1 5 4 3 1 4 13 0 0 14 0 0 39 9
+ 10 35 9 18 48 196 29 28 27 26 24 6 5 4 3 9 13 10 0 18 0 1 0 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="exclam" xMin="186" yMin="0" xMax="383" yMax="1480">
+ <contour>
+ <pt x="186" y="0" on="1"/>
+ <pt x="186" y="197" on="1"/>
+ <pt x="383" y="197" on="1"/>
+ <pt x="383" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="211" y="395" on="1"/>
+ <pt x="186" y="1184" on="1"/>
+ <pt x="186" y="1480" on="1"/>
+ <pt x="383" y="1480" on="1"/>
+ <pt x="383" y="1184" on="1"/>
+ <pt x="359" y="395" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 8 5 2 6 4 3 0 0 2 1 5 1 0 1 4 48 196 9 4 1 3 0 1 2 0
+ 7 6 0 14 9 4 2 2 0 3 0 0 8 7 3 2 4 3 0 1 4 48 196 6 5
+ 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="exclamdown" xMin="242" yMin="-395" xMax="439" yMax="1086">
+ <contour>
+ <pt x="439" y="1086" on="1"/>
+ <pt x="439" y="888" on="1"/>
+ <pt x="242" y="888" on="1"/>
+ <pt x="242" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="415" y="691" on="1"/>
+ <pt x="439" y="-99" on="1"/>
+ <pt x="439" y="-395" on="1"/>
+ <pt x="242" y="-395" on="1"/>
+ <pt x="242" y="-99" on="1"/>
+ <pt x="267" y="691" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 1 8 5 2 2 6 3 0 0 0 2 1 5 1 0 1 4 48 196 9 4 1 7 6 1
+ 2 0 3 0 1 14 9 4 2 0 2 3 0 0 6 5 1 0 4 3 2 1 4 48 196
+ 8 7 3 2 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="f" xMin="31" yMin="0" xMax="630" yMax="1604">
+ <contour>
+ <pt x="175" y="0" on="1"/>
+ <pt x="175" y="938" on="1"/>
+ <pt x="31" y="938" on="1"/>
+ <pt x="31" y="1086" on="1"/>
+ <pt x="175" y="1086" on="1"/>
+ <pt x="175" y="1216" on="1"/>
+ <pt x="175" y="1604" on="0"/>
+ <pt x="483" y="1604" on="1"/>
+ <pt x="548" y="1604" on="0"/>
+ <pt x="630" y="1578" on="1"/>
+ <pt x="630" y="1421" on="1"/>
+ <pt x="556" y="1456" on="0"/>
+ <pt x="504" y="1456" on="1"/>
+ <pt x="431" y="1456" on="0"/>
+ <pt x="402" y="1407" on="1"/>
+ <pt x="373" y="1359" on="0"/>
+ <pt x="373" y="1237" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="568" y="1086" on="1"/>
+ <pt x="568" y="938" on="1"/>
+ <pt x="373" y="938" on="1"/>
+ <pt x="373" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 0 12 40 7 48 196 16 10 9 5 4 13 7 3 0 0 20 19 2 1 7 3 3 1
+ 4 48 196 21 0 1 0 18 17 4 3 1 3 14 0 0 21 20 17 16 4 3 0 1 4
+ 48 196 10 9 1 19 18 1 5 4 1 0 3 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fi" xMin="31" yMin="0" xMax="896" yMax="1604">
+ <contour>
+ <pt x="175" y="0" on="1"/>
+ <pt x="175" y="938" on="1"/>
+ <pt x="31" y="938" on="1"/>
+ <pt x="31" y="1086" on="1"/>
+ <pt x="175" y="1086" on="1"/>
+ <pt x="175" y="1216" on="1"/>
+ <pt x="175" y="1604" on="0"/>
+ <pt x="483" y="1604" on="1"/>
+ <pt x="548" y="1604" on="0"/>
+ <pt x="630" y="1578" on="1"/>
+ <pt x="630" y="1421" on="1"/>
+ <pt x="556" y="1456" on="0"/>
+ <pt x="504" y="1456" on="1"/>
+ <pt x="431" y="1456" on="0"/>
+ <pt x="402" y="1407" on="1"/>
+ <pt x="373" y="1359" on="0"/>
+ <pt x="373" y="1237" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="896" y="1086" on="1"/>
+ <pt x="896" y="0" on="1"/>
+ <pt x="699" y="0" on="1"/>
+ <pt x="699" y="938" on="1"/>
+ <pt x="373" y="938" on="1"/>
+ <pt x="373" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="699" y="1283" on="1"/>
+ <pt x="699" y="1480" on="1"/>
+ <pt x="896" y="1480" on="1"/>
+ <pt x="896" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 0 0 12 40 7 48 196 10 25 24 2 16 5 2 24 3 3 9 7 25 0 0 27 24 5
+ 1 25 22 21 2 1 7 3 3 2 4 48 196 23 20 19 0 3 0 26 25 0 18 17 4
+ 3 1 3 14 0 0 25 24 21 20 4 3 18 23 22 17 16 4 3 0 2 4 48 196 27
+ 26 19 18 3 10 9 1 5 4 1 0 3 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fi#1" xMin="31" yMin="0" xMax="896" yMax="1604">
+ <contour>
+ <pt x="175" y="0" on="1"/>
+ <pt x="175" y="938" on="1"/>
+ <pt x="31" y="938" on="1"/>
+ <pt x="31" y="1086" on="1"/>
+ <pt x="175" y="1086" on="1"/>
+ <pt x="175" y="1216" on="1"/>
+ <pt x="175" y="1604" on="0"/>
+ <pt x="483" y="1604" on="1"/>
+ <pt x="548" y="1604" on="0"/>
+ <pt x="630" y="1578" on="1"/>
+ <pt x="630" y="1421" on="1"/>
+ <pt x="556" y="1456" on="0"/>
+ <pt x="504" y="1456" on="1"/>
+ <pt x="431" y="1456" on="0"/>
+ <pt x="402" y="1407" on="1"/>
+ <pt x="373" y="1359" on="0"/>
+ <pt x="373" y="1237" on="1"/>
+ <pt x="373" y="1086" on="1"/>
+ <pt x="896" y="1086" on="1"/>
+ <pt x="896" y="0" on="1"/>
+ <pt x="699" y="0" on="1"/>
+ <pt x="699" y="938" on="1"/>
+ <pt x="373" y="938" on="1"/>
+ <pt x="373" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="699" y="1283" on="1"/>
+ <pt x="699" y="1480" on="1"/>
+ <pt x="896" y="1480" on="1"/>
+ <pt x="896" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 0 0 12 40 7 48 196 10 25 24 2 16 5 2 24 3 3 9 7 25 0 0 27 24 5
+ 1 25 22 21 2 1 7 3 3 2 4 48 196 23 20 19 0 3 0 26 25 0 18 17 4
+ 3 1 3 14 0 0 25 24 21 20 4 3 18 23 22 17 16 4 3 0 2 4 48 196 27
+ 26 19 18 3 10 9 1 5 4 1 0 3 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="figuredash" xMin="101" yMin="543" xMax="1039" yMax="666">
+ <contour>
+ <pt x="101" y="543" on="1"/>
+ <pt x="101" y="666" on="1"/>
+ <pt x="1039" y="666" on="1"/>
+ <pt x="1039" y="543" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 0 0 3 0 6 1 1 1 4 48 196 2 1 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="five" xMin="163" yMin="-37" xMax="966" yMax="1480">
+ <contour>
+ <pt x="163" y="-6" on="1"/>
+ <pt x="163" y="170" on="1"/>
+ <pt x="315" y="111" on="0"/>
+ <pt x="442" y="111" on="1"/>
+ <pt x="589" y="111" on="0"/>
+ <pt x="672" y="197" on="1"/>
+ <pt x="756" y="284" on="0"/>
+ <pt x="756" y="431" on="1"/>
+ <pt x="756" y="767" on="0"/>
+ <pt x="300" y="767" on="1"/>
+ <pt x="245" y="767" on="0"/>
+ <pt x="188" y="760" on="1"/>
+ <pt x="188" y="1480" on="1"/>
+ <pt x="936" y="1480" on="1"/>
+ <pt x="936" y="1308" on="1"/>
+ <pt x="361" y="1308" on="1"/>
+ <pt x="361" y="918" on="1"/>
+ <pt x="625" y="914" on="0"/>
+ <pt x="775" y="811" on="1"/>
+ <pt x="966" y="679" on="0"/>
+ <pt x="966" y="424" on="1"/>
+ <pt x="966" y="208" on="0"/>
+ <pt x="821" y="86" on="1"/>
+ <pt x="675" y="-37" on="0"/>
+ <pt x="420" y="-37" on="1"/>
+ <pt x="310" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 3 40 24 48 196 24 2 9 1 16 11 9 1 4 14 2 3 0 1 0 2 0 0
+ 0 15 14 13 1 12 1 4 48 196 13 12 0 14 0 0 7 9 20 48 196 20 13 0 0
+ 16 15 13 1 11 1 4 48 196 14 13 1 12 11 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fl" xMin="31" yMin="0" xMax="896" yMax="1604">
+ <contour>
+ <pt x="175" y="0" on="1"/>
+ <pt x="175" y="938" on="1"/>
+ <pt x="31" y="938" on="1"/>
+ <pt x="31" y="1086" on="1"/>
+ <pt x="175" y="1086" on="1"/>
+ <pt x="175" y="1216" on="1"/>
+ <pt x="175" y="1604" on="0"/>
+ <pt x="478" y="1604" on="1"/>
+ <pt x="698" y="1579" on="1"/>
+ <pt x="896" y="1579" on="1"/>
+ <pt x="896" y="0" on="1"/>
+ <pt x="698" y="0" on="1"/>
+ <pt x="698" y="1431" on="1"/>
+ <pt x="657" y="1439" on="1"/>
+ <pt x="571" y="1456" on="0"/>
+ <pt x="512" y="1456" on="1"/>
+ <pt x="423" y="1456" on="0"/>
+ <pt x="395" y="1396" on="1"/>
+ <pt x="372" y="1346" on="0"/>
+ <pt x="372" y="1237" on="1"/>
+ <pt x="372" y="1086" on="1"/>
+ <pt x="550" y="1086" on="1"/>
+ <pt x="550" y="938" on="1"/>
+ <pt x="372" y="938" on="1"/>
+ <pt x="372" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 15 40 7 48 196 19 12 5 3 8 3 3 7 8 0 0 23 22 2 1 7 3 3
+ 1 4 48 196 9 8 1 24 11 10 0 3 2 0 21 20 4 3 1 3 14 0 0 12 11
+ 8 4 2 9 24 23 20 19 4 3 0 2 4 48 196 10 9 1 22 21 1 5 4 1 0
+ 3 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fl#1" xMin="31" yMin="0" xMax="896" yMax="1604">
+ <contour>
+ <pt x="175" y="0" on="1"/>
+ <pt x="175" y="938" on="1"/>
+ <pt x="31" y="938" on="1"/>
+ <pt x="31" y="1086" on="1"/>
+ <pt x="175" y="1086" on="1"/>
+ <pt x="175" y="1216" on="1"/>
+ <pt x="175" y="1604" on="0"/>
+ <pt x="478" y="1604" on="1"/>
+ <pt x="698" y="1579" on="1"/>
+ <pt x="896" y="1579" on="1"/>
+ <pt x="896" y="0" on="1"/>
+ <pt x="698" y="0" on="1"/>
+ <pt x="698" y="1431" on="1"/>
+ <pt x="657" y="1439" on="1"/>
+ <pt x="571" y="1456" on="0"/>
+ <pt x="512" y="1456" on="1"/>
+ <pt x="423" y="1456" on="0"/>
+ <pt x="395" y="1396" on="1"/>
+ <pt x="372" y="1346" on="0"/>
+ <pt x="372" y="1237" on="1"/>
+ <pt x="372" y="1086" on="1"/>
+ <pt x="550" y="1086" on="1"/>
+ <pt x="550" y="938" on="1"/>
+ <pt x="372" y="938" on="1"/>
+ <pt x="372" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 81 values pushed */
+ 0 0 15 40 7 48 196 19 12 5 3 8 3 3 7 8 0 0 23 22 2 1 7 3 3
+ 1 4 48 196 9 8 1 24 11 10 0 3 2 0 21 20 4 3 1 3 14 0 0 12 11
+ 8 4 2 9 24 23 20 19 4 3 0 2 4 48 196 10 9 1 22 21 1 5 4 1 0
+ 3 3 2 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="florin" xMin="49" yMin="-296" xMax="1025" yMax="1517">
+ <contour>
+ <pt x="49" y="-296" on="1"/>
+ <pt x="250" y="716" on="1"/>
+ <pt x="84" y="716" on="1"/>
+ <pt x="84" y="864" on="1"/>
+ <pt x="280" y="864" on="1"/>
+ <pt x="301" y="969" on="1"/>
+ <pt x="411" y="1517" on="0"/>
+ <pt x="799" y="1517" on="1"/>
+ <pt x="903" y="1517" on="0"/>
+ <pt x="1025" y="1489" on="1"/>
+ <pt x="995" y="1332" on="1"/>
+ <pt x="885" y="1370" on="0"/>
+ <pt x="798" y="1370" on="1"/>
+ <pt x="582" y="1370" on="0"/>
+ <pt x="520" y="1060" on="1"/>
+ <pt x="481" y="864" on="1"/>
+ <pt x="670" y="864" on="1"/>
+ <pt x="670" y="716" on="1"/>
+ <pt x="451" y="716" on="1"/>
+ <pt x="250" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 67 values pushed */
+ 0 0 12 40 7 48 196 7 0 1 10 0 3 2 0 1 9 0 0 0 0 18 17 2 1
+ 7 3 3 1 4 48 196 16 15 4 3 3 19 0 1 2 0 14 19 18 15 4 1 5 16
+ 2 3 10 9 2 13 16 0 2 17 16 1 3 2 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="four" xMin="31" yMin="0" xMax="1071" yMax="1480">
+ <contour>
+ <pt x="688" y="0" on="1"/>
+ <pt x="688" y="419" on="1"/>
+ <pt x="31" y="419" on="1"/>
+ <pt x="31" y="568" on="1"/>
+ <pt x="688" y="1480" on="1"/>
+ <pt x="873" y="1480" on="1"/>
+ <pt x="873" y="580" on="1"/>
+ <pt x="1071" y="580" on="1"/>
+ <pt x="1071" y="419" on="1"/>
+ <pt x="873" y="419" on="1"/>
+ <pt x="873" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="224" y="580" on="1"/>
+ <pt x="701" y="580" on="1"/>
+ <pt x="701" y="1238" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 69 values pushed */
+ 13 4 6 2 3 6 1 2 0 0 12 11 7 6 15 3 1 1 4 48 196 9 8 2 1
+ 3 10 0 1 2 0 5 4 0 14 11 0 2 2 0 0 4 1 0 24 2 5 13 12 13
+ 1 5 2 4 48 196 8 7 1 10 9 6 5 3 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="foursuperiour" xMin="3" yMin="592" xMax="669" yMax="1480">
+ <contour>
+ <pt x="410" y="592" on="1"/>
+ <pt x="410" y="834" on="1"/>
+ <pt x="3" y="834" on="1"/>
+ <pt x="3" y="948" on="1"/>
+ <pt x="406" y="1480" on="1"/>
+ <pt x="546" y="1480" on="1"/>
+ <pt x="546" y="951" on="1"/>
+ <pt x="669" y="951" on="1"/>
+ <pt x="669" y="834" on="1"/>
+ <pt x="546" y="834" on="1"/>
+ <pt x="546" y="592" on="1"/>
+ </contour>
+ <contour>
+ <pt x="132" y="951" on="1"/>
+ <pt x="410" y="951" on="1"/>
+ <pt x="410" y="1315" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 13 4 6 2 3 6 1 2 10 0 1 0 0 9 8 2 1 38 3 6 1 4 48 196 5
+ 4 1 12 11 7 6 3 2 0 14 8 7 2 13 5 11 4 3 2 4 13 0 0 0 13
+ 12 1 0 22 3 5 1 4 48 196 10 9 6 5 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fraction" xMin="-441" yMin="-37" xMax="782" yMax="1517">
+ <contour>
+ <pt x="-441" y="-37" on="1"/>
+ <pt x="647" y="1517" on="1"/>
+ <pt x="782" y="1517" on="1"/>
+ <pt x="-305" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 9 values pushed */
+ 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="fraction#1" xMin="-441" yMin="-37" xMax="782" yMax="1517">
+ <contour>
+ <pt x="-441" y="-37" on="1"/>
+ <pt x="647" y="1517" on="1"/>
+ <pt x="782" y="1517" on="1"/>
+ <pt x="-305" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 9 values pushed */
+ 3 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="g" xMin="93" yMin="-420" xMax="991" yMax="1110">
+ <contour>
+ <pt x="794" y="432" on="1"/>
+ <pt x="794" y="937" on="1"/>
+ <pt x="653" y="962" on="0"/>
+ <pt x="591" y="962" on="1"/>
+ <pt x="306" y="962" on="0"/>
+ <pt x="306" y="574" on="1"/>
+ <pt x="306" y="401" on="0"/>
+ <pt x="362" y="299" on="1"/>
+ <pt x="418" y="197" on="0"/>
+ <pt x="511" y="197" on="1"/>
+ <pt x="637" y="197" on="0"/>
+ </contour>
+ <contour>
+ <pt x="794" y="253" on="1"/>
+ <pt x="739" y="151" on="0"/>
+ <pt x="677" y="99" on="1"/>
+ <pt x="588" y="25" on="0"/>
+ <pt x="470" y="25" on="1"/>
+ <pt x="302" y="25" on="0"/>
+ <pt x="198" y="171" on="1"/>
+ <pt x="93" y="316" on="0"/>
+ <pt x="93" y="551" on="1"/>
+ <pt x="93" y="817" on="0"/>
+ <pt x="227" y="963" on="1"/>
+ <pt x="361" y="1110" on="0"/>
+ <pt x="603" y="1110" on="1"/>
+ <pt x="697" y="1110" on="0"/>
+ <pt x="794" y="1086" on="1"/>
+ <pt x="991" y="1086" on="1"/>
+ <pt x="991" y="296" on="1"/>
+ <pt x="991" y="40" on="0"/>
+ <pt x="964" y="-82" on="1"/>
+ <pt x="891" y="-420" on="0"/>
+ <pt x="463" y="-420" on="1"/>
+ <pt x="283" y="-420" on="0"/>
+ <pt x="100" y="-361" on="1"/>
+ <pt x="100" y="-190" on="1"/>
+ <pt x="315" y="-271" on="0"/>
+ <pt x="462" y="-271" on="1"/>
+ <pt x="794" y="-271" on="0"/>
+ <pt x="794" y="82" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 0 0 36 40 31 48 196 23 1 15 2 9 3 1 38 27 11 9 3 1 0 7 25 2 3
+ 0 1 34 33 31 2 0 26 25 1 14 5 5 0 33 2 19 33 27 26 1 34 33 1 38
+ 25 11 1 0 4 3 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gbreve" xMin="93" yMin="-420" xMax="991" yMax="1604">
+ <component glyphName="g" x="0" y="0" flags="0x4"/>
+ <component glyphName="breve" x="258" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="gcircumflex" xMin="93" yMin="-420" xMax="991" yMax="1604">
+ <contour>
+ <pt x="794" y="432" on="1"/>
+ <pt x="794" y="937" on="1"/>
+ <pt x="653" y="962" on="0"/>
+ <pt x="591" y="962" on="1"/>
+ <pt x="306" y="962" on="0"/>
+ <pt x="306" y="574" on="1"/>
+ <pt x="306" y="401" on="0"/>
+ <pt x="362" y="299" on="1"/>
+ <pt x="418" y="197" on="0"/>
+ <pt x="511" y="197" on="1"/>
+ <pt x="637" y="197" on="0"/>
+ </contour>
+ <contour>
+ <pt x="794" y="253" on="1"/>
+ <pt x="739" y="151" on="0"/>
+ <pt x="677" y="99" on="1"/>
+ <pt x="588" y="25" on="0"/>
+ <pt x="470" y="25" on="1"/>
+ <pt x="302" y="25" on="0"/>
+ <pt x="198" y="171" on="1"/>
+ <pt x="93" y="316" on="0"/>
+ <pt x="93" y="551" on="1"/>
+ <pt x="93" y="817" on="0"/>
+ <pt x="227" y="963" on="1"/>
+ <pt x="361" y="1110" on="0"/>
+ <pt x="603" y="1110" on="1"/>
+ <pt x="697" y="1110" on="0"/>
+ <pt x="794" y="1086" on="1"/>
+ <pt x="991" y="1086" on="1"/>
+ <pt x="991" y="296" on="1"/>
+ <pt x="991" y="40" on="0"/>
+ <pt x="964" y="-82" on="1"/>
+ <pt x="891" y="-420" on="0"/>
+ <pt x="463" y="-420" on="1"/>
+ <pt x="283" y="-420" on="0"/>
+ <pt x="100" y="-361" on="1"/>
+ <pt x="100" y="-190" on="1"/>
+ <pt x="315" y="-271" on="0"/>
+ <pt x="462" y="-271" on="1"/>
+ <pt x="794" y="-271" on="0"/>
+ <pt x="794" y="82" on="1"/>
+ </contour>
+ <contour>
+ <pt x="249" y="1283" on="1"/>
+ <pt x="490" y="1604" on="1"/>
+ <pt x="708" y="1604" on="1"/>
+ <pt x="949" y="1283" on="1"/>
+ <pt x="801" y="1283" on="1"/>
+ <pt x="600" y="1485" on="1"/>
+ <pt x="598" y="1485" on="1"/>
+ <pt x="397" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 86 values pushed */
+ 0 0 36 40 31 48 196 23 1 15 2 45 44 2 40 39 3 9 3 1 38 27 11 9 3
+ 1 0 7 25 2 3 0 1 34 33 31 2 0 41 40 1 46 43 42 39 3 2 0 26 25
+ 1 14 43 42 2 26 0 3 5 46 45 44 41 40 39 5 7 0 33 3 19 33 27 26 1
+ 34 33 1 38 25 11 1 0 4 3 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ MDAP[1]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gcommaaccent" xMin="93" yMin="-420" xMax="991" yMax="1737">
+ <contour>
+ <pt x="794" y="432" on="1"/>
+ <pt x="794" y="937" on="1"/>
+ <pt x="653" y="962" on="0"/>
+ <pt x="591" y="962" on="1"/>
+ <pt x="306" y="962" on="0"/>
+ <pt x="306" y="574" on="1"/>
+ <pt x="306" y="401" on="0"/>
+ <pt x="362" y="299" on="1"/>
+ <pt x="418" y="197" on="0"/>
+ <pt x="511" y="197" on="1"/>
+ <pt x="637" y="197" on="0"/>
+ </contour>
+ <contour>
+ <pt x="794" y="253" on="1"/>
+ <pt x="739" y="151" on="0"/>
+ <pt x="677" y="99" on="1"/>
+ <pt x="588" y="25" on="0"/>
+ <pt x="470" y="25" on="1"/>
+ <pt x="302" y="25" on="0"/>
+ <pt x="198" y="171" on="1"/>
+ <pt x="93" y="316" on="0"/>
+ <pt x="93" y="551" on="1"/>
+ <pt x="93" y="817" on="0"/>
+ <pt x="227" y="963" on="1"/>
+ <pt x="361" y="1110" on="0"/>
+ <pt x="603" y="1110" on="1"/>
+ <pt x="697" y="1110" on="0"/>
+ <pt x="794" y="1086" on="1"/>
+ <pt x="991" y="1086" on="1"/>
+ <pt x="991" y="296" on="1"/>
+ <pt x="991" y="40" on="0"/>
+ <pt x="964" y="-82" on="1"/>
+ <pt x="891" y="-420" on="0"/>
+ <pt x="463" y="-420" on="1"/>
+ <pt x="283" y="-420" on="0"/>
+ <pt x="100" y="-361" on="1"/>
+ <pt x="100" y="-190" on="1"/>
+ <pt x="315" y="-271" on="0"/>
+ <pt x="462" y="-271" on="1"/>
+ <pt x="794" y="-271" on="0"/>
+ <pt x="794" y="82" on="1"/>
+ </contour>
+ <contour>
+ <pt x="686" y="1737" on="1"/>
+ <pt x="686" y="1678" on="1"/>
+ <pt x="609" y="1657" on="0"/>
+ <pt x="609" y="1497" on="1"/>
+ <pt x="609" y="1480" on="1"/>
+ <pt x="686" y="1480" on="1"/>
+ <pt x="686" y="1283" on="1"/>
+ <pt x="488" y="1283" on="1"/>
+ <pt x="488" y="1454" on="1"/>
+ <pt x="489" y="1716" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 92 values pushed */
+ 0 0 36 40 31 48 196 23 1 15 2 9 3 1 38 27 11 9 3 1 0 7 25 2 3
+ 0 47 44 43 42 40 39 6 13 45 1 34 33 31 2 0 46 45 1 0 26 25 1 14 43
+ 42 2 39 46 3 5 5 46 33 2 19 33 0 0 45 44 40 39 4 3 46 1 4 48 196
+ 47 46 1 27 26 1 34 33 1 38 25 11 1 0 4 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="gdotaccent" xMin="93" yMin="-420" xMax="991" yMax="1480">
+ <contour>
+ <pt x="794" y="432" on="1"/>
+ <pt x="794" y="937" on="1"/>
+ <pt x="653" y="962" on="0"/>
+ <pt x="591" y="962" on="1"/>
+ <pt x="306" y="962" on="0"/>
+ <pt x="306" y="574" on="1"/>
+ <pt x="306" y="401" on="0"/>
+ <pt x="362" y="299" on="1"/>
+ <pt x="418" y="197" on="0"/>
+ <pt x="511" y="197" on="1"/>
+ <pt x="637" y="197" on="0"/>
+ </contour>
+ <contour>
+ <pt x="794" y="253" on="1"/>
+ <pt x="739" y="151" on="0"/>
+ <pt x="677" y="99" on="1"/>
+ <pt x="588" y="25" on="0"/>
+ <pt x="470" y="25" on="1"/>
+ <pt x="302" y="25" on="0"/>
+ <pt x="198" y="171" on="1"/>
+ <pt x="93" y="316" on="0"/>
+ <pt x="93" y="551" on="1"/>
+ <pt x="93" y="817" on="0"/>
+ <pt x="227" y="963" on="1"/>
+ <pt x="361" y="1110" on="0"/>
+ <pt x="603" y="1110" on="1"/>
+ <pt x="697" y="1110" on="0"/>
+ <pt x="794" y="1086" on="1"/>
+ <pt x="991" y="1086" on="1"/>
+ <pt x="991" y="296" on="1"/>
+ <pt x="991" y="40" on="0"/>
+ <pt x="964" y="-82" on="1"/>
+ <pt x="891" y="-420" on="0"/>
+ <pt x="463" y="-420" on="1"/>
+ <pt x="283" y="-420" on="0"/>
+ <pt x="100" y="-361" on="1"/>
+ <pt x="100" y="-190" on="1"/>
+ <pt x="315" y="-271" on="0"/>
+ <pt x="462" y="-271" on="1"/>
+ <pt x="794" y="-271" on="0"/>
+ <pt x="794" y="82" on="1"/>
+ </contour>
+ <contour>
+ <pt x="488" y="1283" on="1"/>
+ <pt x="488" y="1480" on="1"/>
+ <pt x="685" y="1480" on="1"/>
+ <pt x="685" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 36 40 31 48 196 23 1 15 2 9 3 1 38 27 11 9 3 1 0 7 25 2 3
+ 0 1 34 33 31 2 0 0 0 42 39 5 1 40 1 4 48 196 41 40 0 26 25 1 14
+ 5 5 39 33 2 19 33 0 0 42 41 4 1 39 1 4 48 196 40 39 1 27 26 1 34
+ 33 1 38 25 11 1 0 4 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="germandbls" xMin="129" yMin="-25" xMax="1165" yMax="1604">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="1151" on="1"/>
+ <pt x="129" y="1406" on="0"/>
+ <pt x="220" y="1505" on="1"/>
+ <pt x="313" y="1604" on="0"/>
+ <pt x="549" y="1604" on="1"/>
+ <pt x="930" y="1604" on="0"/>
+ <pt x="930" y="1333" on="1"/>
+ <pt x="930" y="1203" on="0"/>
+ <pt x="800" y="1063" on="1"/>
+ <pt x="697" y="951" on="0"/>
+ <pt x="697" y="899" on="1"/>
+ <pt x="697" y="831" on="0"/>
+ <pt x="808" y="749" on="1"/>
+ <pt x="993" y="612" on="1"/>
+ <pt x="1165" y="485" on="0"/>
+ <pt x="1165" y="295" on="1"/>
+ <pt x="1165" y="-25" on="0"/>
+ <pt x="789" y="-25" on="1"/>
+ <pt x="624" y="-25" on="0"/>
+ <pt x="487" y="30" on="1"/>
+ <pt x="487" y="202" on="1"/>
+ <pt x="674" y="123" on="0"/>
+ <pt x="789" y="123" on="1"/>
+ <pt x="980" y="123" on="0"/>
+ <pt x="980" y="276" on="1"/>
+ <pt x="980" y="377" on="0"/>
+ <pt x="865" y="465" on="1"/>
+ <pt x="650" y="629" on="1"/>
+ <pt x="521" y="727" on="0"/>
+ <pt x="521" y="841" on="1"/>
+ <pt x="521" y="936" on="0"/>
+ <pt x="635" y="1084" on="1"/>
+ <pt x="733" y="1212" on="0"/>
+ <pt x="733" y="1299" on="1"/>
+ <pt x="733" y="1456" on="0"/>
+ <pt x="536" y="1456" on="1"/>
+ <pt x="419" y="1456" on="0"/>
+ <pt x="372" y="1407" on="1"/>
+ <pt x="326" y="1358" on="0"/>
+ <pt x="326" y="1234" on="1"/>
+ <pt x="326" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 0 0 36 40 5 23 40 18 48 196 18 2 40 21 20 1 4 13 5 0 41 0 1 0 14
+ 0 0 34 41 7 25 14 16 11 14 30 48 196 30 16 7 3 12 20 0 0 41 40 4 1
+ 0 1 4 48 196 21 20 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="grave" xMin="106" yMin="1283" xMax="575" yMax="1604">
+ <contour>
+ <pt x="575" y="1283" on="1"/>
+ <pt x="427" y="1283" on="1"/>
+ <pt x="106" y="1604" on="1"/>
+ <pt x="334" y="1604" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 3 2 1 1 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="greater" xMin="104" yMin="99" xMax="1091" yMax="1086">
+ <contour>
+ <pt x="104" y="1086" on="1"/>
+ <pt x="1091" y="592" on="1"/>
+ <pt x="104" y="99" on="1"/>
+ <pt x="104" y="264" on="1"/>
+ <pt x="758" y="591" on="1"/>
+ <pt x="758" y="593" on="1"/>
+ <pt x="104" y="920" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 6 5 4 3 2 1 0 14 5 4 1 3 13 0 6 3 2 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guillemotleft" xMin="115" yMin="99" xMax="1003" yMax="987">
+ <contour>
+ <pt x="1003" y="913" on="1"/>
+ <pt x="707" y="543" on="1"/>
+ <pt x="1003" y="173" on="1"/>
+ <pt x="905" y="99" on="1"/>
+ <pt x="510" y="543" on="1"/>
+ <pt x="905" y="987" on="1"/>
+ </contour>
+ <contour>
+ <pt x="608" y="913" on="1"/>
+ <pt x="312" y="543" on="1"/>
+ <pt x="608" y="173" on="1"/>
+ <pt x="510" y="99" on="1"/>
+ <pt x="115" y="543" on="1"/>
+ <pt x="510" y="987" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 11 10 9 8 7 6 5 4 3 2 1 0 14 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guillemotright" xMin="136" yMin="99" xMax="1024" yMax="987">
+ <contour>
+ <pt x="136" y="173" on="1"/>
+ <pt x="432" y="543" on="1"/>
+ <pt x="136" y="913" on="1"/>
+ <pt x="235" y="987" on="1"/>
+ <pt x="629" y="543" on="1"/>
+ <pt x="235" y="99" on="1"/>
+ </contour>
+ <contour>
+ <pt x="531" y="173" on="1"/>
+ <pt x="827" y="543" on="1"/>
+ <pt x="531" y="913" on="1"/>
+ <pt x="629" y="987" on="1"/>
+ <pt x="1024" y="543" on="1"/>
+ <pt x="629" y="99" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 11 10 9 8 7 6 5 4 3 2 1 0 14 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guilsinglleft" xMin="74" yMin="99" xMax="567" yMax="987">
+ <contour>
+ <pt x="567" y="913" on="1"/>
+ <pt x="271" y="543" on="1"/>
+ <pt x="567" y="173" on="1"/>
+ <pt x="469" y="99" on="1"/>
+ <pt x="74" y="543" on="1"/>
+ <pt x="469" y="987" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 5 4 3 2 1 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="guilsinglright" xMin="114" yMin="99" xMax="607" yMax="987">
+ <contour>
+ <pt x="114" y="173" on="1"/>
+ <pt x="410" y="543" on="1"/>
+ <pt x="114" y="913" on="1"/>
+ <pt x="213" y="987" on="1"/>
+ <pt x="607" y="543" on="1"/>
+ <pt x="213" y="99" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 5 4 3 2 1 0 14 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="h" xMin="154" yMin="0" xMax="997" yMax="1579">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1579" on="1"/>
+ <pt x="351" y="1579" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="424" y="983" on="0"/>
+ <pt x="495" y="1035" on="1"/>
+ <pt x="598" y="1110" on="0"/>
+ <pt x="721" y="1110" on="1"/>
+ <pt x="997" y="1110" on="0"/>
+ <pt x="997" y="780" on="1"/>
+ <pt x="997" y="0" on="1"/>
+ <pt x="799" y="0" on="1"/>
+ <pt x="799" y="716" on="1"/>
+ <pt x="799" y="848" on="0"/>
+ <pt x="772" y="894" on="1"/>
+ <pt x="744" y="941" on="0"/>
+ <pt x="668" y="941" on="1"/>
+ <pt x="506" y="941" on="0"/>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 56 values pushed */
+ 0 0 16 30 7 48 196 7 1 1 18 12 9 3 4 1 0 3 0 2 1 1 19 11 10
+ 0 3 2 0 14 0 0 12 11 4 1 9 19 18 3 2 4 3 0 2 4 48 196 10 9
+ 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hbar" xMin="6" yMin="0" xMax="997" yMax="1579">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1258" on="1"/>
+ <pt x="6" y="1258" on="1"/>
+ <pt x="6" y="1382" on="1"/>
+ <pt x="154" y="1382" on="1"/>
+ <pt x="154" y="1579" on="1"/>
+ <pt x="351" y="1579" on="1"/>
+ <pt x="351" y="1382" on="1"/>
+ <pt x="647" y="1382" on="1"/>
+ <pt x="647" y="1258" on="1"/>
+ <pt x="351" y="1258" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="424" y="983" on="0"/>
+ <pt x="495" y="1035" on="1"/>
+ <pt x="598" y="1110" on="0"/>
+ <pt x="721" y="1110" on="1"/>
+ <pt x="997" y="1110" on="0"/>
+ <pt x="997" y="780" on="1"/>
+ <pt x="997" y="0" on="1"/>
+ <pt x="799" y="0" on="1"/>
+ <pt x="799" y="716" on="1"/>
+ <pt x="799" y="848" on="0"/>
+ <pt x="772" y="894" on="1"/>
+ <pt x="744" y="941" on="0"/>
+ <pt x="668" y="941" on="1"/>
+ <pt x="506" y="941" on="0"/>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 24 30 15 48 196 15 1 1 26 20 17 11 4 1 0 3 0 0 0 10 9 2 1
+ 6 3 3 1 4 48 196 6 5 1 8 7 4 3 3 27 19 18 0 3 3 0 14 9 8
+ 2 19 6 3 3 2 0 0 0 20 19 4 1 17 27 26 11 10 7 6 4 5 0 2 4
+ 48 196 18 17 1 5 4 1 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hcircumflex" xMin="154" yMin="0" xMax="997" yMax="1999">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1579" on="1"/>
+ <pt x="351" y="1579" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="424" y="983" on="0"/>
+ <pt x="495" y="1035" on="1"/>
+ <pt x="598" y="1110" on="0"/>
+ <pt x="721" y="1110" on="1"/>
+ <pt x="997" y="1110" on="0"/>
+ <pt x="997" y="780" on="1"/>
+ <pt x="997" y="0" on="1"/>
+ <pt x="799" y="0" on="1"/>
+ <pt x="799" y="716" on="1"/>
+ <pt x="799" y="848" on="0"/>
+ <pt x="772" y="894" on="1"/>
+ <pt x="744" y="941" on="0"/>
+ <pt x="668" y="941" on="1"/>
+ <pt x="506" y="941" on="0"/>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="228" y="1678" on="1"/>
+ <pt x="469" y="1999" on="1"/>
+ <pt x="687" y="1999" on="1"/>
+ <pt x="928" y="1678" on="1"/>
+ <pt x="780" y="1678" on="1"/>
+ <pt x="579" y="1880" on="1"/>
+ <pt x="577" y="1880" on="1"/>
+ <pt x="376" y="1678" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 16 7 48 196 7 1 26 25 2 21 20 3 1 18 12 9 3 4 1 0 3 0 22
+ 21 1 27 24 23 20 3 2 1 1 19 11 10 0 3 4 0 14 23 9 11 2 27 26 25
+ 24 22 21 6 11 2 3 20 2 0 2 0 0 12 11 5 1 9 19 18 3 2 5 3 0
+ 2 4 48 196 10 9 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hungarumlaut" xMin="-51" yMin="1283" xMax="732" yMax="1604">
+ <contour>
+ <pt x="-51" y="1283" on="1"/>
+ <pt x="190" y="1604" on="1"/>
+ <pt x="381" y="1604" on="1"/>
+ <pt x="60" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="301" y="1283" on="1"/>
+ <pt x="541" y="1604" on="1"/>
+ <pt x="732" y="1604" on="1"/>
+ <pt x="412" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 7 4 3 0 4 13 1 6 5 2 1 3 0 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hyphen" xMin="88" yMin="518" xMax="594" yMax="666">
+ <contour>
+ <pt x="88" y="518" on="1"/>
+ <pt x="88" y="666" on="1"/>
+ <pt x="594" y="666" on="1"/>
+ <pt x="594" y="518" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="hyphen#1" xMin="88" yMin="518" xMax="594" yMax="666">
+ <contour>
+ <pt x="88" y="518" on="1"/>
+ <pt x="88" y="666" on="1"/>
+ <pt x="594" y="666" on="1"/>
+ <pt x="594" y="518" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="i" xMin="129" yMin="0" xMax="326" yMax="1480">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="1086" on="1"/>
+ <pt x="326" y="1086" on="1"/>
+ <pt x="326" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="129" y="1283" on="1"/>
+ <pt x="129" y="1480" on="1"/>
+ <pt x="326" y="1480" on="1"/>
+ <pt x="326" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 41 values pushed */
+ 0 0 7 4 5 1 5 1 4 48 196 3 0 1 0 6 5 0 2 1 1 14 0 0 7
+ 6 3 2 4 3 0 1 4 48 196 5 4 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="iacute" xMin="79" yMin="0" xMax="548" yMax="1604">
+ <component glyphName="dotlessi" x="-1" y="0" flags="0x4"/>
+ <component glyphName="acute" x="-28" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ibreve" xMin="-106" yMin="0" xMax="560" yMax="1604">
+ <contour>
+ <pt x="128" y="0" on="1"/>
+ <pt x="128" y="1086" on="1"/>
+ <pt x="325" y="1086" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-106" y="1604" on="1"/>
+ <pt x="17" y="1604" on="1"/>
+ <pt x="38" y="1510" on="0"/>
+ <pt x="92" y="1470" on="1"/>
+ <pt x="144" y="1431" on="0"/>
+ <pt x="227" y="1431" on="1"/>
+ <pt x="321" y="1431" on="0"/>
+ <pt x="375" y="1480" on="1"/>
+ <pt x="418" y="1520" on="0"/>
+ <pt x="437" y="1604" on="1"/>
+ <pt x="560" y="1604" on="1"/>
+ <pt x="544" y="1470" on="0"/>
+ <pt x="471" y="1389" on="1"/>
+ <pt x="377" y="1283" on="0"/>
+ <pt x="227" y="1283" on="1"/>
+ <pt x="70" y="1283" on="0"/>
+ <pt x="-25" y="1398" on="1"/>
+ <pt x="-90" y="1476" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 9 40 18 48 196 14 13 5 4 4 13 18 1 3 0 1 0 2 1 1 14 14 13
+ 2 13 2 5 4 0 0 0 3 2 4 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="icircumflex" xMin="-123" yMin="0" xMax="577" yMax="1604">
+ <component glyphName="dotlessi" x="-1" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="-114" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="idieresis" xMin="-56" yMin="0" xMax="512" yMax="1456">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="1086" on="1"/>
+ <pt x="326" y="1086" on="1"/>
+ <pt x="326" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-56" y="1283" on="1"/>
+ <pt x="-56" y="1456" on="1"/>
+ <pt x="117" y="1456" on="1"/>
+ <pt x="117" y="1283" on="1"/>
+ </contour>
+ <contour>
+ <pt x="339" y="1283" on="1"/>
+ <pt x="339" y="1456" on="1"/>
+ <pt x="512" y="1456" on="1"/>
+ <pt x="512" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 59 values pushed */
+ 0 0 11 8 7 4 13 3 5 1 4 48 196 10 9 6 5 3 3 0 1 2 0 2 1
+ 1 14 0 0 9 8 13 1 10 7 6 13 1 4 3 2 4 1 0 3 4 48 196 11 10
+ 1 5 4 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="igrave" xMin="-94" yMin="0" xMax="375" yMax="1604">
+ <component glyphName="dotlessi" x="-1" y="0" flags="0x4"/>
+ <component glyphName="grave" x="-200" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ij" xMin="129" yMin="-419" xMax="786" yMax="1480">
+ <component glyphName="i" x="0" y="0" flags="0x4"/>
+ <component glyphName="j" x="455" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="imacron" xMin="-94" yMin="0" xMax="548" yMax="1431">
+ <component glyphName="dotlessi" x="-1" y="0" flags="0x4"/>
+ <component glyphName="macron" x="-114" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="iogonek" xMin="61" yMin="-370" xMax="403" yMax="1480">
+ <component glyphName="i" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="-109" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="itilde" xMin="-106" yMin="0" xMax="560" yMax="1517">
+ <contour>
+ <pt x="128" y="0" on="1"/>
+ <pt x="128" y="1086" on="1"/>
+ <pt x="325" y="1086" on="1"/>
+ <pt x="325" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="-106" y="1283" on="1"/>
+ <pt x="-99" y="1376" on="0"/>
+ <pt x="-74" y="1427" on="1"/>
+ <pt x="-28" y="1517" on="0"/>
+ <pt x="81" y="1517" on="1"/>
+ <pt x="153" y="1517" on="0"/>
+ <pt x="214" y="1479" on="1"/>
+ <pt x="274" y="1442" on="1"/>
+ <pt x="331" y="1407" on="0"/>
+ <pt x="361" y="1407" on="1"/>
+ <pt x="426" y="1407" on="0"/>
+ <pt x="437" y="1517" on="1"/>
+ <pt x="560" y="1517" on="1"/>
+ <pt x="553" y="1423" on="0"/>
+ <pt x="528" y="1373" on="1"/>
+ <pt x="483" y="1283" on="0"/>
+ <pt x="375" y="1283" on="1"/>
+ <pt x="303" y="1283" on="0"/>
+ <pt x="240" y="1322" on="1"/>
+ <pt x="180" y="1359" on="1"/>
+ <pt x="125" y="1393" on="0"/>
+ <pt x="93" y="1393" on="1"/>
+ <pt x="28" y="1393" on="0"/>
+ <pt x="17" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 0 0 25 6 8 13 6 20 48 196 8 0 20 1 27 20 4 3 0 1 3 0 1 16 15
+ 2 13 0 0 3 0 1 0 2 1 1 14 16 15 2 13 2 27 4 0 0 0 3 2 5
+ 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="j" xMin="-155" yMin="-419" xMax="331" yMax="1480">
+ <contour>
+ <pt x="-155" y="-387" on="1"/>
+ <pt x="-155" y="-231" on="1"/>
+ <pt x="-75" y="-271" on="0"/>
+ <pt x="-5" y="-271" on="1"/>
+ <pt x="92" y="-271" on="0"/>
+ <pt x="115" y="-197" on="1"/>
+ <pt x="133" y="-136" on="0"/>
+ <pt x="133" y="0" on="1"/>
+ <pt x="133" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="0" on="1"/>
+ <pt x="331" y="-419" on="0"/>
+ <pt x="11" y="-419" on="1"/>
+ <pt x="-77" y="-419" on="0"/>
+ </contour>
+ <contour>
+ <pt x="133" y="1283" on="1"/>
+ <pt x="133" y="1480" on="1"/>
+ <pt x="331" y="1480" on="1"/>
+ <pt x="331" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 0 3 40 12 48 196 1 10 7 1 0 4 13 12 2 0 0 0 17 14 5 1 15 1
+ 4 48 196 16 15 0 9 8 1 14 0 0 15 14 8 7 4 3 9 1 4 48 196 17 16
+ 10 9 3 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="jcircumflex" xMin="-155" yMin="-419" xMax="565" yMax="1604">
+ <contour>
+ <pt x="-155" y="-387" on="1"/>
+ <pt x="-155" y="-231" on="1"/>
+ <pt x="-75" y="-271" on="0"/>
+ <pt x="-5" y="-271" on="1"/>
+ <pt x="92" y="-271" on="0"/>
+ <pt x="115" y="-197" on="1"/>
+ <pt x="133" y="-136" on="0"/>
+ <pt x="133" y="0" on="1"/>
+ <pt x="133" y="1086" on="1"/>
+ <pt x="331" y="1086" on="1"/>
+ <pt x="331" y="0" on="1"/>
+ <pt x="331" y="-419" on="0"/>
+ <pt x="11" y="-419" on="1"/>
+ <pt x="-77" y="-419" on="0"/>
+ </contour>
+ <contour>
+ <pt x="-134" y="1283" on="1"/>
+ <pt x="106" y="1604" on="1"/>
+ <pt x="325" y="1604" on="1"/>
+ <pt x="565" y="1283" on="1"/>
+ <pt x="417" y="1283" on="1"/>
+ <pt x="217" y="1485" on="1"/>
+ <pt x="214" y="1485" on="1"/>
+ <pt x="14" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 75 values pushed */
+ 0 0 3 40 12 48 196 20 19 2 15 14 3 1 10 7 1 0 4 13 12 2 0 16 15
+ 1 21 18 17 14 3 2 0 9 8 1 14 20 19 16 3 9 7 3 21 15 14 3 7 0
+ 3 18 17 2 13 9 0 0 10 9 4 1 7 1 4 48 196 8 7 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="k" xMin="154" yMin="0" xMax="1006" yMax="1579">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1579" on="1"/>
+ <pt x="351" y="1579" on="1"/>
+ <pt x="351" y="559" on="1"/>
+ <pt x="715" y="1086" on="1"/>
+ <pt x="903" y="1086" on="1"/>
+ <pt x="556" y="573" on="1"/>
+ <pt x="1006" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="351" y="557" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 9 6 3 3 4 0 3 2 1 1 10 8 7 0 3 2 0 5 4 1 14 8 7 6 5
+ 4 5 13 2 0 0 10 9 3 2 4 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="kcommaaccent" xMin="154" yMin="-432" xMax="1006" yMax="1579">
+ <component glyphName="k" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="218" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="kgreenlandic" xMin="154" yMin="0" xMax="1006" yMax="1086">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1086" on="1"/>
+ <pt x="351" y="1086" on="1"/>
+ <pt x="351" y="559" on="1"/>
+ <pt x="715" y="1086" on="1"/>
+ <pt x="903" y="1086" on="1"/>
+ <pt x="556" y="573" on="1"/>
+ <pt x="1006" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="351" y="557" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 45 values pushed */
+ 9 6 3 3 1 0 3 10 8 7 0 3 0 5 4 2 1 1 3 14 8 7 6 5 4
+ 5 13 2 0 0 10 9 3 2 4 3 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="l" xMin="129" yMin="0" xMax="326" yMax="1579">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="1579" on="1"/>
+ <pt x="326" y="1579" on="1"/>
+ <pt x="326" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 2 1 1 3 0 1 2 0 14 0 0 3 2 4 1 0 1 4 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lacute" xMin="79" yMin="0" xMax="548" yMax="1999">
+ <component glyphName="l" x="-1" y="0" flags="0x4"/>
+ <component glyphName="acute" x="-28" y="395" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="lcaron" xMin="129" yMin="0" xMax="610" yMax="1579">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="1579" on="1"/>
+ <pt x="326" y="1579" on="1"/>
+ <pt x="326" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="413" y="1125" on="1"/>
+ <pt x="413" y="1184" on="1"/>
+ <pt x="489" y="1205" on="0"/>
+ <pt x="489" y="1365" on="1"/>
+ <pt x="489" y="1382" on="1"/>
+ <pt x="413" y="1382" on="1"/>
+ <pt x="413" y="1579" on="1"/>
+ <pt x="610" y="1579" on="1"/>
+ <pt x="610" y="1408" on="1"/>
+ <pt x="609" y="1146" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 53 values pushed */
+ 12 9 8 7 5 4 6 1 0 3 11 10 2 1 3 3 0 1 2 0 14 8 7 2 11
+ 4 3 0 0 10 9 5 4 4 3 11 3 2 4 1 0 2 4 48 196 12 11 1 1 0
+ 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lcommaaccent" xMin="79" yMin="-432" xMax="421" yMax="1579">
+ <component glyphName="l" x="-1" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="-91" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ldot" xMin="129" yMin="0" xMax="672" yMax="1579">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="1579" on="1"/>
+ <pt x="326" y="1579" on="1"/>
+ <pt x="326" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="474" y="642" on="1"/>
+ <pt x="474" y="839" on="1"/>
+ <pt x="672" y="839" on="1"/>
+ <pt x="672" y="642" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 7 4 5 1 5 1 4 48 196 6 5 1 2 1 1 3 0 1 3 0 14 0 0
+ 5 4 4 1 6 3 2 4 1 0 2 4 48 196 7 6 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="less" xMin="104" yMin="99" xMax="1091" yMax="1086">
+ <contour>
+ <pt x="1091" y="99" on="1"/>
+ <pt x="104" y="592" on="1"/>
+ <pt x="1091" y="1086" on="1"/>
+ <pt x="1091" y="920" on="1"/>
+ <pt x="437" y="593" on="1"/>
+ <pt x="437" y="591" on="1"/>
+ <pt x="1091" y="264" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 20 values pushed */
+ 6 5 4 3 2 1 0 14 5 4 1 3 13 0 6 3 2 0 3 0
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="logicalnot" xMin="86" yMin="296" xMax="1073" yMax="888">
+ <contour>
+ <pt x="86" y="740" on="1"/>
+ <pt x="86" y="888" on="1"/>
+ <pt x="1073" y="888" on="1"/>
+ <pt x="1073" y="296" on="1"/>
+ <pt x="925" y="296" on="1"/>
+ <pt x="925" y="740" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 39 values pushed */
+ 0 0 5 0 7 1 1 1 4 48 196 2 1 1 4 3 1 2 0 14 0 0 5 4 7
+ 1 2 1 4 48 196 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="longs" xMin="8" yMin="0" xMax="512" yMax="1604">
+ <contour>
+ <pt x="144" y="0" on="1"/>
+ <pt x="144" y="938" on="1"/>
+ <pt x="8" y="938" on="1"/>
+ <pt x="8" y="1086" on="1"/>
+ <pt x="144" y="1086" on="1"/>
+ <pt x="144" y="1216" on="1"/>
+ <pt x="144" y="1399" on="0"/>
+ <pt x="223" y="1501" on="1"/>
+ <pt x="303" y="1604" on="0"/>
+ <pt x="446" y="1604" on="1"/>
+ <pt x="466" y="1604" on="0"/>
+ <pt x="512" y="1599" on="1"/>
+ <pt x="512" y="1452" on="1"/>
+ <pt x="482" y="1456" on="0"/>
+ <pt x="466" y="1456" on="1"/>
+ <pt x="341" y="1456" on="0"/>
+ <pt x="341" y="1237" on="1"/>
+ <pt x="341" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 48 values pushed */
+ 0 0 14 7 9 48 196 16 12 11 5 4 3 2 1 8 13 9 0 17 0 1 0 14 0
+ 0 17 16 5 1 0 1 4 48 196 12 11 1 5 4 1 0 3 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="lslash" xMin="-7" yMin="0" xMax="462" yMax="1579">
+ <contour>
+ <pt x="129" y="0" on="1"/>
+ <pt x="129" y="721" on="1"/>
+ <pt x="-7" y="649" on="1"/>
+ <pt x="-7" y="814" on="1"/>
+ <pt x="129" y="889" on="1"/>
+ <pt x="129" y="1579" on="1"/>
+ <pt x="327" y="1579" on="1"/>
+ <pt x="327" y="998" on="1"/>
+ <pt x="462" y="1065" on="1"/>
+ <pt x="462" y="901" on="1"/>
+ <pt x="327" y="830" on="1"/>
+ <pt x="327" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 10 9 8 7 4 3 2 1 8 5 0 3 6 5 1 11 0 1 2 0 14 0 0 11 10
+ 7 6 4 3 0 1 4 48 196 9 8 1 5 4 1 0 3 3 2 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="m" xMin="154" yMin="0" xMax="1564" yMax="1110">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1086" on="1"/>
+ <pt x="351" y="1086" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="438" y="1012" on="0"/>
+ <pt x="494" y="1058" on="1"/>
+ <pt x="559" y="1110" on="0"/>
+ <pt x="665" y="1110" on="1"/>
+ <pt x="795" y="1110" on="0"/>
+ <pt x="876" y="1026" on="1"/>
+ <pt x="923" y="977" on="0"/>
+ <pt x="958" y="882" on="1"/>
+ <pt x="1046" y="1014" on="0"/>
+ <pt x="1101" y="1058" on="1"/>
+ <pt x="1166" y="1110" on="0"/>
+ <pt x="1273" y="1110" on="1"/>
+ <pt x="1564" y="1110" on="0"/>
+ <pt x="1564" y="790" on="1"/>
+ <pt x="1564" y="0" on="1"/>
+ <pt x="1367" y="0" on="1"/>
+ <pt x="1366" y="759" on="1"/>
+ <pt x="1366" y="946" on="0"/>
+ <pt x="1222" y="946" on="1"/>
+ <pt x="1094" y="946" on="0"/>
+ <pt x="958" y="728" on="1"/>
+ <pt x="958" y="0" on="1"/>
+ <pt x="760" y="0" on="1"/>
+ <pt x="760" y="759" on="1"/>
+ <pt x="760" y="946" on="0"/>
+ <pt x="615" y="946" on="1"/>
+ <pt x="487" y="946" on="0"/>
+ <pt x="351" y="728" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 70 values pushed */
+ 0 0 29 29 7 22 29 15 48 196 15 1 7 1 31 27 24 17 11 3 6 1 0 3 32
+ 26 25 19 18 0 5 0 2 1 1 14 19 17 11 2 0 0 25 24 11 4 2 26 32 31
+ 3 2 4 3 0 2 4 48 196 18 17 1 27 26 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="macron" xMin="20" yMin="1283" xMax="662" yMax="1431">
+ <contour>
+ <pt x="20" y="1283" on="1"/>
+ <pt x="20" y="1431" on="1"/>
+ <pt x="662" y="1431" on="1"/>
+ <pt x="662" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="macron#1" xMin="99" yMin="1456" xMax="1040" yMax="1604">
+ <contour>
+ <pt x="99" y="1456" on="1"/>
+ <pt x="99" y="1604" on="1"/>
+ <pt x="1040" y="1604" on="1"/>
+ <pt x="1040" y="1456" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="minus" xMin="104" yMin="518" xMax="1091" yMax="666">
+ <contour>
+ <pt x="104" y="518" on="1"/>
+ <pt x="104" y="666" on="1"/>
+ <pt x="1091" y="666" on="1"/>
+ <pt x="1091" y="518" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="mu" xMin="142" yMin="-395" xMax="984" yMax="1086">
+ <contour>
+ <pt x="142" y="1086" on="1"/>
+ <pt x="339" y="1086" on="1"/>
+ <pt x="339" y="370" on="1"/>
+ <pt x="339" y="239" on="0"/>
+ <pt x="366" y="192" on="1"/>
+ <pt x="394" y="145" on="0"/>
+ <pt x="470" y="145" on="1"/>
+ <pt x="632" y="145" on="0"/>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="1086" on="1"/>
+ <pt x="984" y="1086" on="1"/>
+ <pt x="984" y="0" on="1"/>
+ <pt x="787" y="0" on="1"/>
+ <pt x="787" y="203" on="1"/>
+ <pt x="629" y="-19" on="0"/>
+ <pt x="469" y="-19" on="1"/>
+ <pt x="404" y="-19" on="0"/>
+ <pt x="339" y="25" on="1"/>
+ <pt x="339" y="-395" on="1"/>
+ <pt x="142" y="-395" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 60 values pushed */
+ 0 0 6 29 15 48 196 15 2 17 13 8 2 4 0 11 3 12 11 1 19 18 1 2 0
+ 10 9 1 0 1 3 14 0 0 13 12 9 8 4 3 10 18 17 2 1 4 3 0 2 4
+ 48 196 11 10 1 19 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="multiply" xMin="118" yMin="112" xMax="1078" yMax="1072">
+ <contour>
+ <pt x="118" y="217" on="1"/>
+ <pt x="493" y="592" on="1"/>
+ <pt x="118" y="967" on="1"/>
+ <pt x="223" y="1072" on="1"/>
+ <pt x="598" y="697" on="1"/>
+ <pt x="973" y="1072" on="1"/>
+ <pt x="1078" y="967" on="1"/>
+ <pt x="703" y="592" on="1"/>
+ <pt x="1078" y="217" on="1"/>
+ <pt x="973" y="112" on="1"/>
+ <pt x="598" y="487" on="1"/>
+ <pt x="223" y="112" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 1 11 10 9 8 7 6 5 4 3 2 1 0 12 13 1 0 14 11 10 9 8 7 6 5
+ 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="n" xMin="154" yMin="0" xMax="997" yMax="1110">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1086" on="1"/>
+ <pt x="351" y="1086" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="424" y="983" on="0"/>
+ <pt x="495" y="1035" on="1"/>
+ <pt x="598" y="1110" on="0"/>
+ <pt x="721" y="1110" on="1"/>
+ <pt x="997" y="1110" on="0"/>
+ <pt x="997" y="780" on="1"/>
+ <pt x="997" y="0" on="1"/>
+ <pt x="799" y="0" on="1"/>
+ <pt x="799" y="716" on="1"/>
+ <pt x="799" y="848" on="0"/>
+ <pt x="772" y="894" on="1"/>
+ <pt x="744" y="941" on="0"/>
+ <pt x="668" y="941" on="1"/>
+ <pt x="506" y="941" on="0"/>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 53 values pushed */
+ 0 0 16 30 7 48 196 7 1 18 12 9 3 4 1 0 3 19 11 10 0 3 0 2 1
+ 1 14 0 0 12 11 4 1 9 19 18 3 2 4 3 0 2 4 48 196 10 9 1 1 0
+ 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nacute" xMin="154" yMin="0" xMax="997" yMax="1604">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="306" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="napostrophe" xMin="0" yMin="0" xMax="1095" yMax="1579">
+ <contour>
+ <pt x="252" y="0" on="1"/>
+ <pt x="252" y="1086" on="1"/>
+ <pt x="449" y="1086" on="1"/>
+ <pt x="449" y="882" on="1"/>
+ <pt x="522" y="983" on="0"/>
+ <pt x="593" y="1035" on="1"/>
+ <pt x="696" y="1110" on="0"/>
+ <pt x="819" y="1110" on="1"/>
+ <pt x="1095" y="1110" on="0"/>
+ <pt x="1095" y="780" on="1"/>
+ <pt x="1095" y="0" on="1"/>
+ <pt x="897" y="0" on="1"/>
+ <pt x="897" y="716" on="1"/>
+ <pt x="897" y="847" on="0"/>
+ <pt x="869" y="894" on="1"/>
+ <pt x="841" y="941" on="0"/>
+ <pt x="766" y="941" on="1"/>
+ <pt x="604" y="941" on="0"/>
+ <pt x="449" y="703" on="1"/>
+ <pt x="449" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="0" y="1125" on="1"/>
+ <pt x="0" y="1184" on="1"/>
+ <pt x="76" y="1205" on="0"/>
+ <pt x="76" y="1365" on="1"/>
+ <pt x="76" y="1382" on="1"/>
+ <pt x="0" y="1382" on="1"/>
+ <pt x="0" y="1579" on="1"/>
+ <pt x="197" y="1579" on="1"/>
+ <pt x="197" y="1408" on="1"/>
+ <pt x="196" y="1146" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 16 30 7 48 196 7 1 28 25 24 23 21 20 6 26 1 3 18 12 9 3 4 1
+ 0 3 27 26 1 19 11 10 0 3 2 0 2 1 1 14 24 23 2 27 20 3 0 0 28
+ 27 4 1 20 12 11 4 1 9 19 18 3 2 4 3 0 3 4 48 196 26 25 21 20 3
+ 10 9 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nbhyphen" xMin="88" yMin="518" xMax="594" yMax="666">
+ <contour>
+ <pt x="88" y="518" on="1"/>
+ <pt x="88" y="666" on="1"/>
+ <pt x="594" y="666" on="1"/>
+ <pt x="594" y="518" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ncaron" xMin="154" yMin="0" xMax="997" yMax="1604">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="243" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ncommaaccent" xMin="154" yMin="-432" xMax="997" yMax="1110">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="243" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="nine" xMin="84" yMin="-38" xMax="1027" yMax="1518">
+ <contour>
+ <pt x="813" y="702" on="1"/>
+ <pt x="675" y="530" on="0"/>
+ <pt x="476" y="530" on="1"/>
+ <pt x="294" y="530" on="0"/>
+ <pt x="189" y="654" on="1"/>
+ <pt x="84" y="778" on="0"/>
+ <pt x="84" y="995" on="1"/>
+ <pt x="84" y="1235" on="0"/>
+ <pt x="208" y="1376" on="1"/>
+ <pt x="331" y="1518" on="0"/>
+ <pt x="539" y="1518" on="1"/>
+ <pt x="767" y="1518" on="0"/>
+ <pt x="897" y="1323" on="1"/>
+ <pt x="1027" y="1128" on="0"/>
+ <pt x="1027" y="788" on="1"/>
+ <pt x="1027" y="400" on="0"/>
+ <pt x="872" y="181" on="1"/>
+ <pt x="717" y="-38" on="0"/>
+ <pt x="443" y="-38" on="1"/>
+ <pt x="315" y="-38" on="0"/>
+ <pt x="163" y="18" on="1"/>
+ <pt x="163" y="190" on="1"/>
+ <pt x="346" y="111" on="0"/>
+ <pt x="447" y="111" on="1"/>
+ <pt x="668" y="111" on="0"/>
+ <pt x="757" y="333" on="1"/>
+ <pt x="792" y="420" on="0"/>
+ <pt x="804" y="529" on="1"/>
+ <pt x="811" y="587" on="0"/>
+ </contour>
+ <contour>
+ <pt x="522" y="1369" on="1"/>
+ <pt x="278" y="1369" on="0"/>
+ <pt x="278" y="1036" on="1"/>
+ <pt x="278" y="672" on="0"/>
+ <pt x="529" y="672" on="1"/>
+ <pt x="653" y="672" on="0"/>
+ <pt x="729" y="758" on="1"/>
+ <pt x="806" y="845" on="0"/>
+ <pt x="806" y="992" on="1"/>
+ <pt x="806" y="1155" on="0"/>
+ <pt x="727" y="1262" on="1"/>
+ <pt x="647" y="1369" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 0 0 33 40 2 29 40 10 23 40 18 48 196 18 2 10 0 2 1 1 21 20 2 0 4
+ 0 2 3 0 0 14 0 0 37 26 14 31 41 6 48 196 0 14 20 6 20 21 20 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="nonbreakingspace"/><!-- contains no outline data -->
+
+ <TTGlyph name="ntilde" xMin="154" yMin="0" xMax="997" yMax="1517">
+ <component glyphName="n" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="221" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="numbersign" xMin="25" yMin="0" xMax="1114" yMax="1480">
+ <contour>
+ <pt x="125" y="0" on="1"/>
+ <pt x="236" y="444" on="1"/>
+ <pt x="25" y="444" on="1"/>
+ <pt x="49" y="568" on="1"/>
+ <pt x="267" y="568" on="1"/>
+ <pt x="354" y="913" on="1"/>
+ <pt x="118" y="913" on="1"/>
+ <pt x="143" y="1036" on="1"/>
+ <pt x="384" y="1036" on="1"/>
+ <pt x="496" y="1480" on="1"/>
+ <pt x="623" y="1480" on="1"/>
+ <pt x="512" y="1036" on="1"/>
+ <pt x="775" y="1036" on="1"/>
+ <pt x="886" y="1480" on="1"/>
+ <pt x="1014" y="1480" on="1"/>
+ <pt x="903" y="1036" on="1"/>
+ <pt x="1114" y="1036" on="1"/>
+ <pt x="1090" y="913" on="1"/>
+ <pt x="872" y="913" on="1"/>
+ <pt x="785" y="568" on="1"/>
+ <pt x="1021" y="568" on="1"/>
+ <pt x="997" y="444" on="1"/>
+ <pt x="755" y="444" on="1"/>
+ <pt x="644" y="0" on="1"/>
+ <pt x="516" y="0" on="1"/>
+ <pt x="627" y="444" on="1"/>
+ <pt x="364" y="444" on="1"/>
+ <pt x="253" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="394" y="568" on="1"/>
+ <pt x="658" y="568" on="1"/>
+ <pt x="745" y="913" on="1"/>
+ <pt x="481" y="913" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 14 13 10 9 4 13 7 27 24 23 0 4 13 1 0 0 31 30 18 17 6 5 6 5 7
+ 29 28 20 19 4 3 6 5 1 2 4 48 196 16 15 12 11 8 7 5 26 25 22 21 2
+ 1 5 2 0 14 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
+ 11 10 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="o" xMin="86" yMin="-25" xMax="1052" yMax="1110">
+ <contour>
+ <pt x="569" y="1110" on="1"/>
+ <pt x="792" y="1110" on="0"/>
+ <pt x="922" y="958" on="1"/>
+ <pt x="1052" y="807" on="0"/>
+ <pt x="1052" y="544" on="1"/>
+ <pt x="1052" y="277" on="0"/>
+ <pt x="922" y="126" on="1"/>
+ <pt x="792" y="-25" on="0"/>
+ <pt x="562" y="-25" on="1"/>
+ <pt x="365" y="-25" on="0"/>
+ <pt x="242" y="100" on="1"/>
+ <pt x="86" y="257" on="0"/>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="806" on="0"/>
+ <pt x="216" y="958" on="1"/>
+ <pt x="346" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="569" y="962" on="1"/>
+ <pt x="299" y="962" on="0"/>
+ <pt x="299" y="544" on="1"/>
+ <pt x="299" y="123" on="0"/>
+ <pt x="568" y="123" on="1"/>
+ <pt x="839" y="123" on="0"/>
+ <pt x="839" y="547" on="1"/>
+ <pt x="839" y="962" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 20 40 8 16 40 0 48 196 8 2 0 1 14 0 0 22 9 4 18 9 12 48 196
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="oacute" xMin="86" yMin="-25" xMax="1052" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="314" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="obreve" xMin="86" yMin="-25" xMax="1052" yMax="1604">
+ <contour>
+ <pt x="569" y="1110" on="1"/>
+ <pt x="792" y="1110" on="0"/>
+ <pt x="922" y="958" on="1"/>
+ <pt x="1052" y="807" on="0"/>
+ <pt x="1052" y="544" on="1"/>
+ <pt x="1052" y="277" on="0"/>
+ <pt x="922" y="126" on="1"/>
+ <pt x="792" y="-25" on="0"/>
+ <pt x="562" y="-25" on="1"/>
+ <pt x="365" y="-25" on="0"/>
+ <pt x="242" y="100" on="1"/>
+ <pt x="86" y="257" on="0"/>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="806" on="0"/>
+ <pt x="216" y="958" on="1"/>
+ <pt x="346" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="569" y="962" on="1"/>
+ <pt x="299" y="962" on="0"/>
+ <pt x="299" y="544" on="1"/>
+ <pt x="299" y="123" on="0"/>
+ <pt x="568" y="123" on="1"/>
+ <pt x="839" y="123" on="0"/>
+ <pt x="839" y="547" on="1"/>
+ <pt x="839" y="962" on="0"/>
+ </contour>
+ <contour>
+ <pt x="236" y="1604" on="1"/>
+ <pt x="359" y="1604" on="1"/>
+ <pt x="380" y="1511" on="0"/>
+ <pt x="434" y="1470" on="1"/>
+ <pt x="486" y="1431" on="0"/>
+ <pt x="569" y="1431" on="1"/>
+ <pt x="663" y="1431" on="0"/>
+ <pt x="717" y="1480" on="1"/>
+ <pt x="760" y="1520" on="0"/>
+ <pt x="779" y="1604" on="1"/>
+ <pt x="902" y="1604" on="1"/>
+ <pt x="885" y="1469" on="0"/>
+ <pt x="813" y="1389" on="1"/>
+ <pt x="718" y="1283" on="0"/>
+ <pt x="569" y="1283" on="1"/>
+ <pt x="412" y="1283" on="0"/>
+ <pt x="317" y="1398" on="1"/>
+ <pt x="253" y="1475" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 44 values pushed */
+ 0 0 29 7 38 20 7 8 16 7 0 48 196 8 2 0 1 1 34 33 25 24 4 13 38
+ 1 0 14 0 0 22 9 4 18 9 12 48 196 34 33 25 24 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ocircumflex" xMin="86" yMin="-25" xMax="1052" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="228" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="odieresis" xMin="86" yMin="-25" xMax="1052" yMax="1456">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="228" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="oe" xMin="86" yMin="-25" xMax="1812" yMax="1110">
+ <contour>
+ <pt x="990" y="910" on="1"/>
+ <pt x="1054" y="999" on="0"/>
+ <pt x="1125" y="1044" on="1"/>
+ <pt x="1230" y="1110" on="0"/>
+ <pt x="1375" y="1110" on="1"/>
+ <pt x="1633" y="1110" on="0"/>
+ <pt x="1734" y="927" on="1"/>
+ <pt x="1809" y="791" on="0"/>
+ <pt x="1812" y="512" on="1"/>
+ <pt x="1099" y="512" on="1"/>
+ <pt x="1117" y="321" on="0"/>
+ <pt x="1191" y="233" on="1"/>
+ <pt x="1283" y="123" on="0"/>
+ <pt x="1494" y="123" on="1"/>
+ <pt x="1649" y="123" on="0"/>
+ <pt x="1812" y="194" on="1"/>
+ <pt x="1812" y="37" on="1"/>
+ <pt x="1620" y="-25" on="0"/>
+ <pt x="1444" y="-25" on="1"/>
+ <pt x="1264" y="-25" on="0"/>
+ <pt x="1157" y="33" on="1"/>
+ <pt x="1077" y="77" on="0"/>
+ <pt x="995" y="174" on="1"/>
+ <pt x="934" y="86" on="0"/>
+ <pt x="862" y="41" on="1"/>
+ <pt x="755" y="-25" on="0"/>
+ <pt x="606" y="-25" on="1"/>
+ <pt x="368" y="-25" on="0"/>
+ <pt x="227" y="129" on="1"/>
+ <pt x="86" y="283" on="0"/>
+ <pt x="86" y="543" on="1"/>
+ <pt x="86" y="805" on="0"/>
+ <pt x="228" y="957" on="1"/>
+ <pt x="369" y="1110" on="0"/>
+ <pt x="608" y="1110" on="1"/>
+ <pt x="764" y="1110" on="0"/>
+ <pt x="872" y="1035" on="1"/>
+ <pt x="934" y="992" on="0"/>
+ </contour>
+ <contour>
+ <pt x="608" y="962" on="1"/>
+ <pt x="295" y="962" on="0"/>
+ <pt x="295" y="547" on="1"/>
+ <pt x="295" y="365" on="0"/>
+ <pt x="356" y="260" on="1"/>
+ <pt x="435" y="123" on="0"/>
+ <pt x="610" y="123" on="1"/>
+ <pt x="898" y="123" on="0"/>
+ <pt x="898" y="543" on="1"/>
+ <pt x="898" y="736" on="0"/>
+ <pt x="838" y="840" on="1"/>
+ <pt x="768" y="962" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1105" y="648" on="1"/>
+ <pt x="1602" y="648" on="1"/>
+ <pt x="1599" y="776" on="0"/>
+ <pt x="1568" y="844" on="1"/>
+ <pt x="1513" y="962" on="0"/>
+ <pt x="1371" y="962" on="1"/>
+ <pt x="1233" y="962" on="0"/>
+ <pt x="1166" y="857" on="1"/>
+ <pt x="1120" y="786" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 55 40 4 44 40 26 38 40 34 13 40 18 48 196 34 1 26 2 18 2 4 1 1
+ 0 1 50 2 0 1 22 16 15 3 8 2 3 0 0 0 9 8 31 1 50 1 4 48 196
+ 51 50 1 0 14 0 0 40 43 30 48 196 51 50 22 9 0 5 13 46 30 8 16 15 8
+ 2 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ogonek" xMin="170" yMin="-370" xMax="512" yMax="0">
+ <contour>
+ <pt x="328" y="0" on="1"/>
+ <pt x="435" y="0" on="1"/>
+ <pt x="307" y="-80" on="0"/>
+ <pt x="307" y="-179" on="1"/>
+ <pt x="307" y="-275" on="0"/>
+ <pt x="422" y="-275" on="1"/>
+ <pt x="475" y="-275" on="0"/>
+ <pt x="512" y="-260" on="1"/>
+ <pt x="512" y="-341" on="1"/>
+ <pt x="450" y="-370" on="0"/>
+ <pt x="372" y="-370" on="1"/>
+ <pt x="170" y="-370" on="0"/>
+ <pt x="170" y="-212" on="1"/>
+ <pt x="170" y="-90" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 5 21 10 48 196 10 8 7 1 0 14 0 0 3 42 12 48 196 12 8 7 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ograve" xMin="86" yMin="-25" xMax="1052" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="142" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ohungarumlaut" xMin="86" yMin="-25" xMax="1121" yMax="1604">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="hungarumlaut" x="389" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="omacron" xMin="86" yMin="-25" xMax="1052" yMax="1431">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="228" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="one" xMin="230" yMin="0" xMax="1020" yMax="1517">
+ <contour>
+ <pt x="230" y="0" on="1"/>
+ <pt x="230" y="148" on="1"/>
+ <pt x="526" y="148" on="1"/>
+ <pt x="526" y="1316" on="1"/>
+ <pt x="230" y="1242" on="1"/>
+ <pt x="230" y="1394" on="1"/>
+ <pt x="724" y="1517" on="1"/>
+ <pt x="724" y="148" on="1"/>
+ <pt x="1020" y="148" on="1"/>
+ <pt x="1020" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 49 values pushed */
+ 6 5 4 3 4 13 1 0 0 8 7 2 1 7 3 0 1 4 48 196 9 0 1 0 14
+ 0 0 7 6 4 1 2 1 4 48 196 9 8 1 3 2 1 5 4 1 0 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onehalf" xMin="116" yMin="-37" xMax="1584" yMax="1517">
+ <contour>
+ <pt x="1019" y="0" on="1"/>
+ <pt x="1019" y="122" on="1"/>
+ <pt x="1082" y="234" on="0"/>
+ <pt x="1201" y="341" on="1"/>
+ <pt x="1271" y="403" on="1"/>
+ <pt x="1427" y="541" on="0"/>
+ <pt x="1427" y="663" on="1"/>
+ <pt x="1427" y="809" on="0"/>
+ <pt x="1266" y="809" on="1"/>
+ <pt x="1174" y="809" on="0"/>
+ <pt x="1041" y="740" on="1"/>
+ <pt x="1041" y="857" on="1"/>
+ <pt x="1173" y="910" on="0"/>
+ <pt x="1292" y="910" on="1"/>
+ <pt x="1423" y="910" on="0"/>
+ <pt x="1504" y="842" on="1"/>
+ <pt x="1584" y="775" on="0"/>
+ <pt x="1584" y="667" on="1"/>
+ <pt x="1584" y="523" on="0"/>
+ <pt x="1400" y="374" on="1"/>
+ <pt x="1347" y="331" on="1"/>
+ <pt x="1214" y="222" on="0"/>
+ <pt x="1191" y="122" on="1"/>
+ <pt x="1580" y="122" on="1"/>
+ <pt x="1580" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="140" y="-37" on="1"/>
+ <pt x="1228" y="1517" on="1"/>
+ <pt x="1364" y="1517" on="1"/>
+ <pt x="276" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="313" y="592" on="1"/>
+ <pt x="313" y="1351" on="1"/>
+ <pt x="116" y="1302" on="1"/>
+ <pt x="116" y="1416" on="1"/>
+ <pt x="461" y="1503" on="1"/>
+ <pt x="461" y="592" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 85 values pushed */
+ 0 0 8 11 13 48 196 33 32 31 30 27 26 11 10 8 13 13 29 28 25 0 0 0 23
+ 22 1 38 2 0 1 4 48 196 34 29 1 24 0 1 2 0 14 0 0 6 37 17 48 196
+ 27 26 24 23 22 11 10 1 0 9 13 17 33 32 31 28 25 4 13 29 0 0 34 33 7
+ 1 29 1 4 48 196 30 29 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onequarter" xMin="116" yMin="-37" xMax="1584" yMax="1517">
+ <contour>
+ <pt x="313" y="592" on="1"/>
+ <pt x="313" y="1351" on="1"/>
+ <pt x="116" y="1302" on="1"/>
+ <pt x="116" y="1416" on="1"/>
+ <pt x="461" y="1503" on="1"/>
+ <pt x="461" y="592" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1325" y="0" on="1"/>
+ <pt x="1325" y="242" on="1"/>
+ <pt x="918" y="242" on="1"/>
+ <pt x="918" y="355" on="1"/>
+ <pt x="1321" y="888" on="1"/>
+ <pt x="1461" y="888" on="1"/>
+ <pt x="1461" y="359" on="1"/>
+ <pt x="1584" y="359" on="1"/>
+ <pt x="1584" y="242" on="1"/>
+ <pt x="1461" y="242" on="1"/>
+ <pt x="1461" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1047" y="359" on="1"/>
+ <pt x="1325" y="359" on="1"/>
+ <pt x="1325" y="723" on="1"/>
+ </contour>
+ <contour>
+ <pt x="191" y="-37" on="1"/>
+ <pt x="1279" y="1517" on="1"/>
+ <pt x="1414" y="1517" on="1"/>
+ <pt x="326" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 107 values pushed */
+ 19 10 0 2 9 12 7 2 22 21 4 3 2 1 6 13 10 23 20 16 6 4 13 7 0
+ 0 18 17 13 12 38 3 7 1 4 48 196 11 10 1 15 14 8 7 3 5 0 1 3 0
+ 14 22 11 6 2 21 17 10 9 8 5 6 4 3 23 4 0 2 14 13 2 13 11 20 3
+ 2 3 13 0 0 0 19 18 7 6 22 3 11 5 4 7 1 0 2 4 48 196 16 15 12
+ 11 3 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="onesuperior" xMin="123" yMin="592" xMax="468" yMax="1503">
+ <contour>
+ <pt x="320" y="592" on="1"/>
+ <pt x="320" y="1351" on="1"/>
+ <pt x="123" y="1302" on="1"/>
+ <pt x="123" y="1416" on="1"/>
+ <pt x="468" y="1503" on="1"/>
+ <pt x="468" y="592" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 4 3 2 1 4 13 0 5 0 1 0 14 3 2 0 0 0 1 0 7 1 4 1 4 48
+ 196 5 4 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ordfeminine" xMin="86" yMin="822" xMax="712" yMax="1518">
+ <contour>
+ <pt x="485" y="915" on="1"/>
+ <pt x="383" y="822" on="0"/>
+ <pt x="281" y="822" on="1"/>
+ <pt x="196" y="822" on="0"/>
+ <pt x="141" y="875" on="1"/>
+ <pt x="86" y="929" on="0"/>
+ <pt x="86" y="1009" on="1"/>
+ <pt x="86" y="1237" on="0"/>
+ <pt x="428" y="1237" on="1"/>
+ <pt x="476" y="1237" on="1"/>
+ <pt x="476" y="1307" on="1"/>
+ <pt x="476" y="1417" on="0"/>
+ <pt x="355" y="1417" on="1"/>
+ <pt x="258" y="1417" on="0"/>
+ <pt x="145" y="1358" on="1"/>
+ <pt x="145" y="1469" on="1"/>
+ <pt x="272" y="1518" on="0"/>
+ <pt x="383" y="1518" on="1"/>
+ <pt x="625" y="1518" on="0"/>
+ <pt x="625" y="1311" on="1"/>
+ <pt x="625" y="1013" on="1"/>
+ <pt x="625" y="919" on="0"/>
+ <pt x="680" y="922" on="1"/>
+ <pt x="686" y="922" on="1"/>
+ <pt x="689" y="922" on="0"/>
+ <pt x="695" y="923" on="1"/>
+ <pt x="700" y="923" on="0"/>
+ <pt x="706" y="924" on="1"/>
+ <pt x="712" y="841" on="1"/>
+ <pt x="661" y="822" on="0"/>
+ <pt x="616" y="822" on="1"/>
+ <pt x="518" y="822" on="0"/>
+ <pt x="490" y="915" on="1"/>
+ </contour>
+ <contour>
+ <pt x="476" y="996" on="1"/>
+ <pt x="476" y="1150" on="1"/>
+ <pt x="438" y="1150" on="1"/>
+ <pt x="234" y="1150" on="0"/>
+ <pt x="234" y="1026" on="1"/>
+ <pt x="234" y="932" on="0"/>
+ <pt x="331" y="932" on="1"/>
+ <pt x="399" y="932" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 80 values pushed */
+ 0 0 39 16 2 12 20 17 48 196 17 0 1 35 34 33 32 28 27 20 19 15 14 10 9
+ 8 0 14 13 30 22 2 3 12 0 0 14 0 0 37 7 6 48 196 32 0 2 19 9 3
+ 28 27 2 13 19 35 15 14 8 4 13 6 9 0 0 34 33 10 9 7 3 19 1 4 48
+ 196 20 19 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ordmasculine" xMin="74" yMin="822" xMax="673" yMax="1517">
+ <contour>
+ <pt x="374" y="1517" on="1"/>
+ <pt x="512" y="1517" on="0"/>
+ <pt x="593" y="1424" on="1"/>
+ <pt x="673" y="1331" on="0"/>
+ <pt x="673" y="1171" on="1"/>
+ <pt x="673" y="1008" on="0"/>
+ <pt x="593" y="915" on="1"/>
+ <pt x="512" y="822" on="0"/>
+ <pt x="371" y="822" on="1"/>
+ <pt x="248" y="822" on="0"/>
+ <pt x="171" y="899" on="1"/>
+ <pt x="74" y="995" on="0"/>
+ <pt x="74" y="1170" on="1"/>
+ <pt x="74" y="1330" on="0"/>
+ <pt x="155" y="1423" on="1"/>
+ <pt x="236" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="374" y="1416" on="1"/>
+ <pt x="231" y="1416" on="0"/>
+ <pt x="231" y="1170" on="1"/>
+ <pt x="231" y="924" on="0"/>
+ <pt x="374" y="924" on="1"/>
+ <pt x="516" y="924" on="0"/>
+ <pt x="516" y="1172" on="1"/>
+ <pt x="516" y="1416" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 29 values pushed */
+ 0 0 20 20 8 16 20 0 48 196 0 0 1 8 0 0 14 0 0 22 15 4 18 15 12
+ 48 196 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="oslash" xMin="143" yMin="-25" xMax="1109" yMax="1110">
+ <contour>
+ <pt x="348" y="59" on="1"/>
+ <pt x="287" y="-25" on="1"/>
+ <pt x="143" y="-25" on="1"/>
+ <pt x="264" y="142" on="1"/>
+ <pt x="143" y="309" on="0"/>
+ <pt x="143" y="544" on="1"/>
+ <pt x="143" y="808" on="0"/>
+ <pt x="273" y="959" on="1"/>
+ <pt x="403" y="1110" on="0"/>
+ <pt x="630" y="1110" on="1"/>
+ <pt x="790" y="1110" on="0"/>
+ <pt x="904" y="1027" on="1"/>
+ <pt x="965" y="1110" on="1"/>
+ <pt x="1109" y="1110" on="1"/>
+ <pt x="988" y="943" on="1"/>
+ <pt x="1109" y="775" on="0"/>
+ <pt x="1109" y="542" on="1"/>
+ <pt x="1109" y="280" on="0"/>
+ <pt x="979" y="128" on="1"/>
+ <pt x="850" y="-25" on="0"/>
+ <pt x="625" y="-25" on="1"/>
+ <pt x="465" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="450" y="201" on="1"/>
+ <pt x="452" y="199" on="1"/>
+ <pt x="494" y="157" on="0"/>
+ <pt x="529" y="142" on="1"/>
+ <pt x="574" y="123" on="0"/>
+ <pt x="625" y="123" on="1"/>
+ <pt x="896" y="123" on="0"/>
+ <pt x="896" y="544" on="1"/>
+ <pt x="896" y="669" on="0"/>
+ <pt x="866" y="775" on="1"/>
+ </contour>
+ <contour>
+ <pt x="802" y="885" on="1"/>
+ <pt x="800" y="887" on="1"/>
+ <pt x="725" y="962" on="0"/>
+ <pt x="627" y="962" on="1"/>
+ <pt x="356" y="962" on="0"/>
+ <pt x="356" y="547" on="1"/>
+ <pt x="356" y="405" on="0"/>
+ <pt x="386" y="310" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 63 values pushed */
+ 0 0 35 40 9 27 40 20 48 196 20 2 9 1 1 1 39 32 31 22 14 11 3 0 8
+ 1 2 3 0 0 13 12 1 2 1 1 2 0 14 0 0 37 9 5 29 9 16 48 196 39
+ 32 31 22 16 14 13 12 11 5 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="otilde" xMin="86" yMin="-25" xMax="1052" yMax="1517">
+ <component glyphName="o" x="0" y="0" flags="0x4"/>
+ <component glyphName="tilde" x="228" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="p" xMin="154" yMin="-395" xMax="1052" yMax="1110">
+ <contour>
+ <pt x="351" y="-395" on="1"/>
+ <pt x="154" y="-395" on="1"/>
+ <pt x="154" y="1086" on="1"/>
+ <pt x="351" y="1086" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="407" y="984" on="0"/>
+ <pt x="469" y="1036" on="1"/>
+ <pt x="557" y="1110" on="0"/>
+ <pt x="676" y="1110" on="1"/>
+ <pt x="845" y="1110" on="0"/>
+ <pt x="948" y="963" on="1"/>
+ <pt x="1052" y="816" on="0"/>
+ <pt x="1052" y="572" on="1"/>
+ <pt x="1052" y="287" on="0"/>
+ <pt x="918" y="131" on="1"/>
+ <pt x="785" y="-25" on="0"/>
+ <pt x="540" y="-25" on="1"/>
+ <pt x="449" y="-25" on="0"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="149" on="1"/>
+ <pt x="488" y="123" on="0"/>
+ <pt x="557" y="123" on="1"/>
+ <pt x="839" y="123" on="0"/>
+ <pt x="839" y="552" on="1"/>
+ <pt x="839" y="733" on="0"/>
+ <pt x="783" y="835" on="1"/>
+ <pt x="728" y="938" on="0"/>
+ <pt x="634" y="938" on="1"/>
+ <pt x="508" y="938" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 28 30 8 22 40 16 48 196 16 2 8 1 1 20 19 4 3 2 2 3 0 1 18
+ 2 0 2 0 1 0 1 0 3 2 1 14 0 0 24 9 12 48 196 12 0 0 0 20 19
+ 18 4 3 0 4 5 1 1 4 48 196 2 1 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="paragraph" xMin="88" yMin="-296" xMax="902" yMax="1480">
+ <contour>
+ <pt x="507" y="-296" on="1"/>
+ <pt x="507" y="740" on="1"/>
+ <pt x="325" y="757" on="0"/>
+ <pt x="222" y="843" on="1"/>
+ <pt x="88" y="954" on="0"/>
+ <pt x="88" y="1155" on="1"/>
+ <pt x="88" y="1331" on="0"/>
+ <pt x="184" y="1405" on="1"/>
+ <pt x="280" y="1480" on="0"/>
+ <pt x="507" y="1480" on="1"/>
+ <pt x="902" y="1480" on="1"/>
+ <pt x="902" y="-296" on="1"/>
+ <pt x="779" y="-296" on="1"/>
+ <pt x="779" y="1357" on="1"/>
+ <pt x="631" y="1357" on="1"/>
+ <pt x="631" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 57 values pushed */
+ 1 1 13 2 2 0 1 15 12 11 0 4 13 2 0 0 0 14 13 6 1 9 1 4 48
+ 196 10 9 0 14 5 0 0 0 13 12 19 1 10 9 1 0 19 2 14 2 4 48 196 11
+ 10 1 15 14 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="parenleft" xMin="131" yMin="-296" xMax="600" yMax="1579">
+ <contour>
+ <pt x="600" y="-160" on="1"/>
+ <pt x="600" y="-296" on="1"/>
+ <pt x="400" y="-154" on="0"/>
+ <pt x="284" y="55" on="1"/>
+ <pt x="131" y="328" on="0"/>
+ <pt x="131" y="642" on="1"/>
+ <pt x="131" y="970" on="0"/>
+ <pt x="297" y="1252" on="1"/>
+ <pt x="411" y="1444" on="0"/>
+ <pt x="600" y="1579" on="1"/>
+ <pt x="600" y="1443" on="1"/>
+ <pt x="465" y="1293" on="0"/>
+ <pt x="404" y="1136" on="1"/>
+ <pt x="328" y="941" on="0"/>
+ <pt x="328" y="642" on="1"/>
+ <pt x="328" y="330" on="0"/>
+ <pt x="411" y="129" on="1"/>
+ <pt x="473" y="-18" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 10 9 1 0 14 0 0 14 41 5 48 196 10 9 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="parenright" xMin="82" yMin="-296" xMax="551" yMax="1579">
+ <contour>
+ <pt x="82" y="1443" on="1"/>
+ <pt x="82" y="1579" on="1"/>
+ <pt x="282" y="1437" on="0"/>
+ <pt x="399" y="1228" on="1"/>
+ <pt x="551" y="956" on="0"/>
+ <pt x="551" y="642" on="1"/>
+ <pt x="551" y="312" on="0"/>
+ <pt x="385" y="31" on="1"/>
+ <pt x="271" y="-161" on="0"/>
+ <pt x="82" y="-296" on="1"/>
+ <pt x="82" y="-160" on="1"/>
+ <pt x="217" y="-9" on="0"/>
+ <pt x="278" y="148" on="1"/>
+ <pt x="353" y="343" on="0"/>
+ <pt x="353" y="642" on="1"/>
+ <pt x="353" y="953" on="0"/>
+ <pt x="270" y="1154" on="1"/>
+ <pt x="210" y="1299" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 17 values pushed */
+ 10 9 1 0 14 0 0 14 41 5 48 196 10 9 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="percent" xMin="112" yMin="-37" xMax="1709" yMax="1517">
+ <contour>
+ <pt x="250" y="-37" on="1"/>
+ <pt x="1416" y="1517" on="1"/>
+ <pt x="1570" y="1517" on="1"/>
+ <pt x="405" y="-37" on="1"/>
+ </contour>
+ <contour>
+ <pt x="429" y="1480" on="1"/>
+ <pt x="576" y="1480" on="0"/>
+ <pt x="661" y="1381" on="1"/>
+ <pt x="747" y="1281" on="0"/>
+ <pt x="747" y="1110" on="1"/>
+ <pt x="747" y="939" on="0"/>
+ <pt x="661" y="840" on="1"/>
+ <pt x="576" y="740" on="0"/>
+ <pt x="430" y="740" on="1"/>
+ <pt x="282" y="740" on="0"/>
+ <pt x="197" y="840" on="1"/>
+ <pt x="112" y="940" on="0"/>
+ <pt x="112" y="1115" on="1"/>
+ <pt x="112" y="1266" on="0"/>
+ <pt x="182" y="1362" on="1"/>
+ <pt x="270" y="1480" on="0"/>
+ </contour>
+ <contour>
+ <pt x="429" y="1382" on="1"/>
+ <pt x="356" y="1382" on="0"/>
+ <pt x="311" y="1308" on="1"/>
+ <pt x="266" y="1233" on="0"/>
+ <pt x="266" y="1116" on="1"/>
+ <pt x="266" y="1001" on="0"/>
+ <pt x="303" y="929" on="1"/>
+ <pt x="348" y="839" on="0"/>
+ <pt x="429" y="839" on="1"/>
+ <pt x="503" y="839" on="0"/>
+ <pt x="548" y="914" on="1"/>
+ <pt x="593" y="989" on="0"/>
+ <pt x="593" y="1110" on="1"/>
+ <pt x="593" y="1233" on="0"/>
+ <pt x="548" y="1307" on="1"/>
+ <pt x="502" y="1382" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1392" y="740" on="1"/>
+ <pt x="1539" y="740" on="0"/>
+ <pt x="1624" y="640" on="1"/>
+ <pt x="1709" y="541" on="0"/>
+ <pt x="1709" y="370" on="1"/>
+ <pt x="1709" y="199" on="0"/>
+ <pt x="1624" y="100" on="1"/>
+ <pt x="1538" y="0" on="0"/>
+ <pt x="1392" y="0" on="1"/>
+ <pt x="1244" y="0" on="0"/>
+ <pt x="1159" y="100" on="1"/>
+ <pt x="1074" y="200" on="0"/>
+ <pt x="1074" y="375" on="1"/>
+ <pt x="1074" y="527" on="0"/>
+ <pt x="1144" y="622" on="1"/>
+ <pt x="1232" y="740" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1392" y="642" on="1"/>
+ <pt x="1318" y="642" on="0"/>
+ <pt x="1273" y="568" on="1"/>
+ <pt x="1228" y="493" on="0"/>
+ <pt x="1228" y="376" on="1"/>
+ <pt x="1228" y="262" on="0"/>
+ <pt x="1265" y="189" on="1"/>
+ <pt x="1309" y="99" on="0"/>
+ <pt x="1392" y="99" on="1"/>
+ <pt x="1465" y="99" on="0"/>
+ <pt x="1510" y="174" on="1"/>
+ <pt x="1555" y="249" on="0"/>
+ <pt x="1555" y="370" on="1"/>
+ <pt x="1555" y="493" on="0"/>
+ <pt x="1510" y="567" on="1"/>
+ <pt x="1465" y="642" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 60 21 44 52 21 36 28 21 12 20 21 4 48 196 44 2 4 0 36 12 1 1 36
+ 12 2 0 2 3 0 0 2 1 1 3 0 1 2 0 14 0 0 64 15 40 56 15 48 32
+ 15 8 24 15 16 48 196 48 40 16 8 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="period" xMin="161" yMin="0" xMax="408" yMax="247">
+ <contour>
+ <pt x="161" y="0" on="1"/>
+ <pt x="161" y="247" on="1"/>
+ <pt x="408" y="247" on="1"/>
+ <pt x="408" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 2 1 8 1 0 1 4 48 196 3 0 1 0 14 0 0 3 2 8 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="periodcentered" xMin="161" yMin="491" xMax="408" yMax="738">
+ <contour>
+ <pt x="161" y="491" on="1"/>
+ <pt x="161" y="738" on="1"/>
+ <pt x="408" y="738" on="1"/>
+ <pt x="408" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 8 1 1 1 4 48 196 2 1 1 0 14 0 0 3 2 8 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="periodcentered#1" xMin="161" yMin="491" xMax="408" yMax="738">
+ <contour>
+ <pt x="161" y="491" on="1"/>
+ <pt x="161" y="738" on="1"/>
+ <pt x="408" y="738" on="1"/>
+ <pt x="408" y="491" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 0 0 3 0 8 1 1 1 4 48 196 2 1 1 0 14 0 0 3 2 8 1 0 1 4
+ 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="perthousand" xMin="25" yMin="-37" xMax="2024" yMax="1517">
+ <contour>
+ <pt x="340" y="1480" on="1"/>
+ <pt x="483" y="1480" on="0"/>
+ <pt x="569" y="1380" on="1"/>
+ <pt x="654" y="1281" on="0"/>
+ <pt x="654" y="1111" on="1"/>
+ <pt x="654" y="938" on="0"/>
+ <pt x="569" y="839" on="1"/>
+ <pt x="484" y="740" on="0"/>
+ <pt x="335" y="740" on="1"/>
+ <pt x="209" y="740" on="0"/>
+ <pt x="127" y="822" on="1"/>
+ <pt x="25" y="925" on="0"/>
+ <pt x="25" y="1110" on="1"/>
+ <pt x="25" y="1280" on="0"/>
+ <pt x="110" y="1380" on="1"/>
+ <pt x="196" y="1480" on="0"/>
+ </contour>
+ <contour>
+ <pt x="338" y="1382" on="1"/>
+ <pt x="173" y="1382" on="0"/>
+ <pt x="173" y="1111" on="1"/>
+ <pt x="173" y="839" on="0"/>
+ <pt x="340" y="839" on="1"/>
+ <pt x="506" y="839" on="0"/>
+ <pt x="506" y="1109" on="1"/>
+ <pt x="506" y="1235" on="0"/>
+ <pt x="461" y="1308" on="1"/>
+ <pt x="415" y="1382" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1006" y="740" on="1"/>
+ <pt x="1150" y="740" on="0"/>
+ <pt x="1235" y="640" on="1"/>
+ <pt x="1320" y="541" on="0"/>
+ <pt x="1320" y="371" on="1"/>
+ <pt x="1320" y="198" on="0"/>
+ <pt x="1235" y="99" on="1"/>
+ <pt x="1150" y="0" on="0"/>
+ <pt x="1002" y="0" on="1"/>
+ <pt x="874" y="0" on="0"/>
+ <pt x="793" y="81" on="1"/>
+ <pt x="691" y="184" on="0"/>
+ <pt x="691" y="370" on="1"/>
+ <pt x="691" y="540" on="0"/>
+ <pt x="776" y="640" on="1"/>
+ <pt x="862" y="740" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1004" y="642" on="1"/>
+ <pt x="839" y="642" on="0"/>
+ <pt x="839" y="370" on="1"/>
+ <pt x="839" y="99" on="0"/>
+ <pt x="1006" y="99" on="1"/>
+ <pt x="1172" y="99" on="0"/>
+ <pt x="1172" y="369" on="1"/>
+ <pt x="1172" y="495" on="0"/>
+ <pt x="1127" y="569" on="1"/>
+ <pt x="1081" y="642" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1709" y="740" on="1"/>
+ <pt x="1853" y="740" on="0"/>
+ <pt x="1938" y="640" on="1"/>
+ <pt x="2024" y="541" on="0"/>
+ <pt x="2024" y="372" on="1"/>
+ <pt x="2024" y="198" on="0"/>
+ <pt x="1938" y="99" on="1"/>
+ <pt x="1852" y="0" on="0"/>
+ <pt x="1706" y="0" on="1"/>
+ <pt x="1578" y="0" on="0"/>
+ <pt x="1496" y="82" on="1"/>
+ <pt x="1394" y="185" on="0"/>
+ <pt x="1394" y="370" on="1"/>
+ <pt x="1394" y="540" on="0"/>
+ <pt x="1479" y="640" on="1"/>
+ <pt x="1565" y="740" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1707" y="642" on="1"/>
+ <pt x="1542" y="642" on="0"/>
+ <pt x="1542" y="370" on="1"/>
+ <pt x="1542" y="99" on="0"/>
+ <pt x="1709" y="99" on="1"/>
+ <pt x="1876" y="99" on="0"/>
+ <pt x="1876" y="370" on="1"/>
+ <pt x="1876" y="495" on="0"/>
+ <pt x="1830" y="569" on="1"/>
+ <pt x="1785" y="642" on="0"/>
+ </contour>
+ <contour>
+ <pt x="61" y="-37" on="1"/>
+ <pt x="1149" y="1517" on="1"/>
+ <pt x="1284" y="1517" on="1"/>
+ <pt x="196" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 87 values pushed */
+ 0 0 72 21 60 68 21 52 46 21 34 42 21 26 20 21 8 16 21 0 48 196 60 2 34
+ 2 0 0 52 26 8 1 1 52 26 8 3 0 2 3 0 0 1 80 79 2 13 0 0 1
+ 81 78 2 0 14 0 0 74 7 56 70 7 64 48 7 30 44 7 38 22 7 4 18 7 12
+ 48 196 81 80 79 78 64 56 38 30 12 4
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MDAP[1]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="plus" xMin="104" yMin="99" xMax="1091" yMax="1086">
+ <contour>
+ <pt x="523" y="99" on="1"/>
+ <pt x="523" y="518" on="1"/>
+ <pt x="104" y="518" on="1"/>
+ <pt x="104" y="666" on="1"/>
+ <pt x="523" y="666" on="1"/>
+ <pt x="523" y="1086" on="1"/>
+ <pt x="671" y="1086" on="1"/>
+ <pt x="671" y="666" on="1"/>
+ <pt x="1091" y="666" on="1"/>
+ <pt x="1091" y="518" on="1"/>
+ <pt x="671" y="518" on="1"/>
+ <pt x="671" y="99" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 53 values pushed */
+ 0 0 10 9 2 1 7 3 3 1 4 48 196 8 7 4 3 3 11 0 1 2 0 6 5
+ 1 14 0 0 11 10 7 6 7 3 0 1 4 48 196 9 8 1 5 4 1 0 3 3 2
+ 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="plusminus" xMin="104" yMin="0" xMax="1091" yMax="1184">
+ <contour>
+ <pt x="523" y="296" on="1"/>
+ <pt x="523" y="666" on="1"/>
+ <pt x="104" y="666" on="1"/>
+ <pt x="104" y="814" on="1"/>
+ <pt x="523" y="814" on="1"/>
+ <pt x="523" y="1184" on="1"/>
+ <pt x="672" y="1184" on="1"/>
+ <pt x="672" y="814" on="1"/>
+ <pt x="1091" y="814" on="1"/>
+ <pt x="1091" y="666" on="1"/>
+ <pt x="672" y="666" on="1"/>
+ <pt x="672" y="296" on="1"/>
+ </contour>
+ <contour>
+ <pt x="104" y="0" on="1"/>
+ <pt x="104" y="148" on="1"/>
+ <pt x="1091" y="148" on="1"/>
+ <pt x="1091" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 14 13 7 1 12 10 9 2 1 7 3 3 2 4 48 196 15 12 1 6 5 1 8
+ 7 4 3 3 11 0 1 4 0 14 0 0 11 10 7 6 7 3 0 1 4 48 196 15 14
+ 9 8 3 5 4 1 0 3 13 12 3 2 3 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="q" xMin="86" yMin="-395" xMax="984" yMax="1110">
+ <contour>
+ <pt x="787" y="1086" on="1"/>
+ <pt x="984" y="1086" on="1"/>
+ <pt x="984" y="-395" on="1"/>
+ <pt x="787" y="-395" on="1"/>
+ <pt x="787" y="203" on="1"/>
+ <pt x="731" y="101" on="0"/>
+ <pt x="669" y="49" on="1"/>
+ <pt x="581" y="-25" on="0"/>
+ <pt x="462" y="-25" on="1"/>
+ <pt x="293" y="-25" on="0"/>
+ <pt x="190" y="123" on="1"/>
+ <pt x="86" y="270" on="0"/>
+ <pt x="86" y="514" on="1"/>
+ <pt x="86" y="798" on="0"/>
+ <pt x="220" y="954" on="1"/>
+ <pt x="354" y="1110" on="0"/>
+ <pt x="597" y="1110" on="1"/>
+ <pt x="691" y="1110" on="0"/>
+ </contour>
+ <contour>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="937" on="1"/>
+ <pt x="648" y="962" on="0"/>
+ <pt x="582" y="962" on="1"/>
+ <pt x="299" y="962" on="0"/>
+ <pt x="299" y="532" on="1"/>
+ <pt x="299" y="354" on="0"/>
+ <pt x="355" y="251" on="1"/>
+ <pt x="410" y="148" on="0"/>
+ <pt x="504" y="148" on="1"/>
+ <pt x="630" y="148" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 0 27 30 8 21 40 16 48 196 16 1 8 2 1 19 18 4 3 0 2 3 0 3 2
+ 1 0 1 0 1 14 0 0 23 9 12 48 196 12 0 0 0 19 18 4 3 0 4 4 1
+ 1 4 48 196 2 1 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="question" xMin="138" yMin="0" xMax="1014" yMax="1517">
+ <contour>
+ <pt x="376" y="0" on="1"/>
+ <pt x="376" y="197" on="1"/>
+ <pt x="573" y="197" on="1"/>
+ <pt x="573" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="376" y="395" on="1"/>
+ <pt x="376" y="449" on="1"/>
+ <pt x="375" y="694" on="0"/>
+ <pt x="539" y="822" on="1"/>
+ <pt x="628" y="891" on="1"/>
+ <pt x="804" y="1027" on="0"/>
+ <pt x="804" y="1174" on="1"/>
+ <pt x="804" y="1369" on="0"/>
+ <pt x="530" y="1369" on="1"/>
+ <pt x="362" y="1369" on="0"/>
+ <pt x="138" y="1295" on="1"/>
+ <pt x="138" y="1462" on="1"/>
+ <pt x="359" y="1517" on="0"/>
+ <pt x="545" y="1517" on="1"/>
+ <pt x="749" y="1517" on="0"/>
+ <pt x="865" y="1451" on="1"/>
+ <pt x="1014" y="1365" on="0"/>
+ <pt x="1014" y="1177" on="1"/>
+ <pt x="1014" y="989" on="0"/>
+ <pt x="823" y="871" on="1"/>
+ <pt x="742" y="821" on="1"/>
+ <pt x="643" y="760" on="0"/>
+ <pt x="608" y="694" on="1"/>
+ <pt x="573" y="629" on="0"/>
+ <pt x="573" y="505" on="1"/>
+ <pt x="573" y="395" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 71 values pushed */
+ 0 0 12 40 17 48 196 17 0 1 28 15 14 5 4 0 4 3 0 0 0 2 1 5 1
+ 0 1 4 48 196 29 4 1 3 0 1 2 0 14 0 0 10 9 21 48 196 21 2 0 0
+ 29 28 3 2 4 3 0 1 4 48 196 15 14 1 5 4 1 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="questiondown" xMin="185" yMin="-432" xMax="1061" yMax="1086">
+ <contour>
+ <pt x="823" y="1086" on="1"/>
+ <pt x="823" y="888" on="1"/>
+ <pt x="626" y="888" on="1"/>
+ <pt x="626" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="823" y="691" on="1"/>
+ <pt x="823" y="636" on="1"/>
+ <pt x="823" y="392" on="0"/>
+ <pt x="660" y="264" on="1"/>
+ <pt x="571" y="195" on="1"/>
+ <pt x="395" y="58" on="0"/>
+ <pt x="395" y="-88" on="1"/>
+ <pt x="395" y="-284" on="0"/>
+ <pt x="670" y="-284" on="1"/>
+ <pt x="838" y="-284" on="0"/>
+ <pt x="1061" y="-209" on="1"/>
+ <pt x="1061" y="-376" on="1"/>
+ <pt x="842" y="-432" on="0"/>
+ <pt x="655" y="-432" on="1"/>
+ <pt x="450" y="-432" on="0"/>
+ <pt x="334" y="-365" on="1"/>
+ <pt x="185" y="-280" on="0"/>
+ <pt x="185" y="-91" on="1"/>
+ <pt x="185" y="97" on="0"/>
+ <pt x="376" y="215" on="1"/>
+ <pt x="457" y="265" on="1"/>
+ <pt x="556" y="326" on="0"/>
+ <pt x="591" y="391" on="1"/>
+ <pt x="626" y="457" on="0"/>
+ <pt x="626" y="580" on="1"/>
+ <pt x="626" y="691" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 72 values pushed */
+ 0 0 12 40 17 48 196 1 28 5 2 4 2 3 0 1 15 14 17 2 0 0 0 2 1
+ 5 1 0 1 4 48 196 29 4 1 0 3 0 1 14 0 0 10 9 21 48 196 21 2 0
+ 0 29 28 3 2 4 3 0 1 4 48 196 15 14 1 5 4 1 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedbl" xMin="92" yMin="1086" xMax="635" yMax="1579">
+ <contour>
+ <pt x="117" y="1086" on="1"/>
+ <pt x="92" y="1579" on="1"/>
+ <pt x="289" y="1579" on="1"/>
+ <pt x="265" y="1086" on="1"/>
+ </contour>
+ <contour>
+ <pt x="462" y="1086" on="1"/>
+ <pt x="437" y="1579" on="1"/>
+ <pt x="635" y="1579" on="1"/>
+ <pt x="610" y="1086" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 21 values pushed */
+ 6 5 2 1 3 0 7 4 3 0 1 3 14 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblbase" xMin="70" yMin="-321" xMax="613" yMax="197">
+ <contour>
+ <pt x="70" y="-321" on="1"/>
+ <pt x="70" y="-247" on="1"/>
+ <pt x="141" y="-210" on="0"/>
+ <pt x="141" y="-23" on="1"/>
+ <pt x="141" y="0" on="1"/>
+ <pt x="70" y="0" on="1"/>
+ <pt x="70" y="197" on="1"/>
+ <pt x="267" y="197" on="1"/>
+ <pt x="267" y="31" on="1"/>
+ <pt x="266" y="-271" on="0"/>
+ </contour>
+ <contour>
+ <pt x="415" y="-321" on="1"/>
+ <pt x="415" y="-247" on="1"/>
+ <pt x="486" y="-209" on="0"/>
+ <pt x="486" y="-23" on="1"/>
+ <pt x="486" y="0" on="1"/>
+ <pt x="415" y="0" on="1"/>
+ <pt x="415" y="197" on="1"/>
+ <pt x="613" y="197" on="1"/>
+ <pt x="613" y="31" on="1"/>
+ <pt x="612" y="-271" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 18 15 14 13 11 10 8 5 4 3 1 0 12 13 6 17 16 7 6 3 0 14 14 13 2
+ 17 10 3 4 3 2 7 0 3 0 0 16 15 11 10 4 3 17 8 7 4 1 0 2 4
+ 48 196 18 17 1 6 5 1 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblleft" xMin="57" yMin="1061" xMax="600" yMax="1579">
+ <contour>
+ <pt x="600" y="1579" on="1"/>
+ <pt x="600" y="1505" on="1"/>
+ <pt x="529" y="1468" on="0"/>
+ <pt x="529" y="1281" on="1"/>
+ <pt x="529" y="1258" on="1"/>
+ <pt x="600" y="1258" on="1"/>
+ <pt x="600" y="1061" on="1"/>
+ <pt x="402" y="1061" on="1"/>
+ <pt x="402" y="1227" on="1"/>
+ <pt x="403" y="1529" on="0"/>
+ </contour>
+ <contour>
+ <pt x="254" y="1579" on="1"/>
+ <pt x="254" y="1505" on="1"/>
+ <pt x="184" y="1468" on="0"/>
+ <pt x="184" y="1281" on="1"/>
+ <pt x="184" y="1258" on="1"/>
+ <pt x="254" y="1258" on="1"/>
+ <pt x="254" y="1061" on="1"/>
+ <pt x="57" y="1061" on="1"/>
+ <pt x="57" y="1227" on="1"/>
+ <pt x="58" y="1529" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 18 15 14 13 11 10 8 5 4 3 1 0 12 13 6 17 16 7 6 3 0 14 4 3 2
+ 0 7 3 14 13 2 10 17 3 0 0 16 15 11 10 4 3 17 8 7 4 1 0 2 4
+ 48 196 18 17 1 6 5 1 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotedblright" xMin="82" yMin="1061" xMax="625" yMax="1579">
+ <contour>
+ <pt x="82" y="1061" on="1"/>
+ <pt x="82" y="1135" on="1"/>
+ <pt x="153" y="1172" on="0"/>
+ <pt x="153" y="1359" on="1"/>
+ <pt x="153" y="1382" on="1"/>
+ <pt x="82" y="1382" on="1"/>
+ <pt x="82" y="1579" on="1"/>
+ <pt x="279" y="1579" on="1"/>
+ <pt x="279" y="1413" on="1"/>
+ <pt x="278" y="1111" on="0"/>
+ </contour>
+ <contour>
+ <pt x="427" y="1061" on="1"/>
+ <pt x="427" y="1135" on="1"/>
+ <pt x="498" y="1172" on="0"/>
+ <pt x="498" y="1359" on="1"/>
+ <pt x="498" y="1382" on="1"/>
+ <pt x="427" y="1382" on="1"/>
+ <pt x="427" y="1579" on="1"/>
+ <pt x="625" y="1579" on="1"/>
+ <pt x="625" y="1413" on="1"/>
+ <pt x="624" y="1111" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 18 15 14 13 11 10 8 5 4 3 1 0 12 13 6 17 16 7 6 3 0 14 14 13 2
+ 17 10 3 4 3 2 7 0 3 0 0 16 15 11 10 4 3 17 8 7 4 1 0 2 4
+ 48 196 18 17 1 6 5 1 0 3 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quoteleft" xMin="92" yMin="1012" xMax="339" yMax="1579">
+ <contour>
+ <pt x="339" y="1579" on="1"/>
+ <pt x="339" y="1505" on="1"/>
+ <pt x="243" y="1478" on="0"/>
+ <pt x="243" y="1279" on="1"/>
+ <pt x="243" y="1258" on="1"/>
+ <pt x="339" y="1258" on="1"/>
+ <pt x="339" y="1012" on="1"/>
+ <pt x="92" y="1012" on="1"/>
+ <pt x="92" y="1226" on="1"/>
+ <pt x="93" y="1551" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 8 5 4 3 1 0 6 13 6 7 6 1 0 14 4 3 2 0 7 3 0 0 6 5 1
+ 0 8 3 7 1 4 48 196 8 7 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotereversed"/><!-- contains no outline data -->
+
+ <TTGlyph name="quoteright" xMin="116" yMin="1012" xMax="363" yMax="1579">
+ <contour>
+ <pt x="116" y="1012" on="1"/>
+ <pt x="116" y="1086" on="1"/>
+ <pt x="212" y="1113" on="0"/>
+ <pt x="212" y="1312" on="1"/>
+ <pt x="212" y="1332" on="1"/>
+ <pt x="116" y="1332" on="1"/>
+ <pt x="116" y="1579" on="1"/>
+ <pt x="363" y="1579" on="1"/>
+ <pt x="363" y="1365" on="1"/>
+ <pt x="362" y="1036" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 8 5 4 3 1 0 6 13 6 7 6 1 0 14 4 3 2 7 0 3 0 0 8 7 8
+ 1 0 1 4 48 196 6 5 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotesinglbase" xMin="104" yMin="-296" xMax="351" yMax="247">
+ <contour>
+ <pt x="104" y="-296" on="1"/>
+ <pt x="104" y="-222" on="1"/>
+ <pt x="200" y="-195" on="0"/>
+ <pt x="200" y="-20" on="1"/>
+ <pt x="200" y="0" on="1"/>
+ <pt x="104" y="0" on="1"/>
+ <pt x="104" y="247" on="1"/>
+ <pt x="351" y="247" on="1"/>
+ <pt x="351" y="33" on="1"/>
+ <pt x="350" y="-270" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 37 values pushed */
+ 8 5 4 3 1 0 6 13 6 7 6 1 0 14 4 3 2 7 0 3 0 0 8 7 8
+ 1 0 1 4 48 196 6 5 1 0 3 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="quotesingle" xMin="72" yMin="1036" xMax="319" yMax="1579">
+ <contour>
+ <pt x="121" y="1036" on="1"/>
+ <pt x="72" y="1579" on="1"/>
+ <pt x="319" y="1579" on="1"/>
+ <pt x="269" y="1036" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 13 values pushed */
+ 2 1 1 3 0 1 2 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ LOOPCALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="r" xMin="154" yMin="0" xMax="668" yMax="1110">
+ <contour>
+ <pt x="154" y="0" on="1"/>
+ <pt x="154" y="1086" on="1"/>
+ <pt x="351" y="1086" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="394" y="985" on="0"/>
+ <pt x="443" y="1036" on="1"/>
+ <pt x="514" y="1110" on="0"/>
+ <pt x="612" y="1110" on="1"/>
+ <pt x="631" y="1110" on="0"/>
+ <pt x="668" y="1105" on="1"/>
+ <pt x="668" y="921" on="1"/>
+ <pt x="616" y="938" on="0"/>
+ <pt x="584" y="938" on="1"/>
+ <pt x="475" y="938" on="0"/>
+ <pt x="351" y="716" on="1"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 47 values pushed */
+ 0 0 12 30 7 48 196 7 1 14 10 3 3 1 0 3 9 1 15 0 1 0 2 1 1
+ 14 0 0 15 14 3 2 4 3 0 1 4 48 196 10 9 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00000]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="racute" xMin="154" yMin="0" xMax="722" yMax="1604">
+ <component glyphName="r" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="146" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="radicalex" xMin="99" yMin="1456" xMax="1040" yMax="1604">
+ <contour>
+ <pt x="99" y="1456" on="1"/>
+ <pt x="99" y="1604" on="1"/>
+ <pt x="1040" y="1604" on="1"/>
+ <pt x="1040" y="1456" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="rcaron" xMin="2" yMin="0" xMax="702" yMax="1604">
+ <component glyphName="r" x="1" y="0" flags="0x4"/>
+ <component glyphName="caron" x="11" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="rcommaaccent" xMin="154" yMin="-432" xMax="668" yMax="1110">
+ <component glyphName="r" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="-16" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="registered" xMin="15" yMin="0" xMax="1495" yMax="1480">
+ <contour>
+ <pt x="755" y="1480" on="1"/>
+ <pt x="1060" y="1480" on="0"/>
+ <pt x="1278" y="1263" on="1"/>
+ <pt x="1495" y="1047" on="0"/>
+ <pt x="1495" y="741" on="1"/>
+ <pt x="1495" y="431" on="0"/>
+ <pt x="1277" y="216" on="1"/>
+ <pt x="1060" y="0" on="0"/>
+ <pt x="746" y="0" on="1"/>
+ <pt x="478" y="0" on="0"/>
+ <pt x="277" y="176" on="1"/>
+ <pt x="15" y="404" on="0"/>
+ <pt x="15" y="741" on="1"/>
+ <pt x="15" y="1047" on="0"/>
+ <pt x="232" y="1263" on="1"/>
+ <pt x="450" y="1480" on="0"/>
+ </contour>
+ <contour>
+ <pt x="755" y="1375" on="1"/>
+ <pt x="494" y="1375" on="0"/>
+ <pt x="307" y="1188" on="1"/>
+ <pt x="121" y="1002" on="0"/>
+ <pt x="121" y="740" on="1"/>
+ <pt x="121" y="482" on="0"/>
+ <pt x="306" y="294" on="1"/>
+ <pt x="491" y="106" on="0"/>
+ <pt x="748" y="106" on="1"/>
+ <pt x="987" y="106" on="0"/>
+ <pt x="1164" y="256" on="1"/>
+ <pt x="1390" y="448" on="0"/>
+ <pt x="1390" y="741" on="1"/>
+ <pt x="1390" y="1003" on="0"/>
+ <pt x="1203" y="1188" on="1"/>
+ <pt x="1016" y="1375" on="0"/>
+ </contour>
+ <contour>
+ <pt x="511" y="337" on="1"/>
+ <pt x="511" y="1137" on="1"/>
+ <pt x="763" y="1137" on="1"/>
+ <pt x="1005" y="1137" on="0"/>
+ <pt x="1005" y="942" on="1"/>
+ <pt x="1005" y="803" on="0"/>
+ <pt x="865" y="709" on="1"/>
+ <pt x="1106" y="337" on="1"/>
+ <pt x="957" y="337" on="1"/>
+ <pt x="741" y="671" on="1"/>
+ <pt x="640" y="671" on="1"/>
+ <pt x="640" y="337" on="1"/>
+ </contour>
+ <contour>
+ <pt x="632" y="770" on="1"/>
+ <pt x="668" y="770" on="1"/>
+ <pt x="880" y="770" on="0"/>
+ <pt x="880" y="925" on="1"/>
+ <pt x="880" y="1055" on="0"/>
+ <pt x="703" y="1055" on="1"/>
+ <pt x="632" y="1055" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 83 values pushed */
+ 0 0 24 20 8 16 20 0 48 196 8 2 0 0 50 49 45 44 42 41 38 7 33 32 3
+ 34 33 1 43 40 39 32 3 2 0 14 0 0 47 6 36 28 17 4 20 17 12 48 196 49
+ 45 41 40 39 38 34 7 13 36 4 42 12 32 0 0 43 42 18 1 32 50 44 19 1 32
+ 2 4 48 196 33 32 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ring" xMin="114" yMin="1283" xMax="568" yMax="1737">
+ <contour>
+ <pt x="341" y="1737" on="1"/>
+ <pt x="435" y="1737" on="0"/>
+ <pt x="501" y="1671" on="1"/>
+ <pt x="568" y="1605" on="0"/>
+ <pt x="568" y="1511" on="1"/>
+ <pt x="568" y="1415" on="0"/>
+ <pt x="501" y="1349" on="1"/>
+ <pt x="435" y="1283" on="0"/>
+ <pt x="339" y="1283" on="1"/>
+ <pt x="256" y="1283" on="0"/>
+ <pt x="194" y="1337" on="1"/>
+ <pt x="114" y="1406" on="0"/>
+ <pt x="114" y="1510" on="1"/>
+ <pt x="114" y="1604" on="0"/>
+ <pt x="180" y="1670" on="1"/>
+ <pt x="246" y="1737" on="0"/>
+ </contour>
+ <contour>
+ <pt x="341" y="1650" on="1"/>
+ <pt x="283" y="1650" on="0"/>
+ <pt x="241" y="1609" on="1"/>
+ <pt x="200" y="1569" on="0"/>
+ <pt x="200" y="1510" on="1"/>
+ <pt x="200" y="1452" on="0"/>
+ <pt x="241" y="1411" on="1"/>
+ <pt x="282" y="1369" on="0"/>
+ <pt x="339" y="1369" on="1"/>
+ <pt x="393" y="1369" on="0"/>
+ <pt x="432" y="1402" on="1"/>
+ <pt x="482" y="1445" on="0"/>
+ <pt x="482" y="1511" on="1"/>
+ <pt x="482" y="1569" on="0"/>
+ <pt x="440" y="1609" on="1"/>
+ <pt x="399" y="1650" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 25 values pushed */
+ 0 0 24 44 8 16 44 0 48 196 8 0 14 0 0 28 32 4 20 32 12 48 196 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="s" xMin="116" yMin="-25" xMax="908" yMax="1110">
+ <contour>
+ <pt x="116" y="38" on="1"/>
+ <pt x="116" y="219" on="1"/>
+ <pt x="315" y="123" on="0"/>
+ <pt x="483" y="123" on="1"/>
+ <pt x="710" y="123" on="0"/>
+ <pt x="710" y="283" on="1"/>
+ <pt x="710" y="393" on="0"/>
+ <pt x="551" y="445" on="1"/>
+ <pt x="375" y="503" on="1"/>
+ <pt x="122" y="586" on="0"/>
+ <pt x="122" y="807" on="1"/>
+ <pt x="122" y="1110" on="0"/>
+ <pt x="536" y="1110" on="1"/>
+ <pt x="655" y="1110" on="0"/>
+ <pt x="825" y="1078" on="1"/>
+ <pt x="825" y="913" on="1"/>
+ <pt x="674" y="962" on="0"/>
+ <pt x="523" y="962" on="1"/>
+ <pt x="317" y="962" on="0"/>
+ <pt x="317" y="827" on="1"/>
+ <pt x="317" y="729" on="0"/>
+ <pt x="458" y="683" on="1"/>
+ <pt x="615" y="632" on="1"/>
+ <pt x="908" y="537" on="0"/>
+ <pt x="908" y="302" on="1"/>
+ <pt x="908" y="151" on="0"/>
+ <pt x="792" y="63" on="1"/>
+ <pt x="676" y="-25" on="0"/>
+ <pt x="475" y="-25" on="1"/>
+ <pt x="316" y="-25" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 52 values pushed */
+ 0 0 17 40 12 3 40 28 48 196 28 2 12 1 1 1 15 14 1 0 4 1 2 3 0
+ 0 14 0 0 19 41 10 5 41 24 48 196 10 10 14 0 2 24 14 15 14 1 1 0 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="sacute" xMin="116" yMin="-25" xMax="908" yMax="1604">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="294" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scaron" xMin="116" yMin="-25" xMax="908" yMax="1604">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="208" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scedilla" xMin="116" yMin="-432" xMax="908" yMax="1110">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="cedilla" x="165" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="scircumflex" xMin="116" yMin="-25" xMax="908" yMax="1604">
+ <contour>
+ <pt x="116" y="38" on="1"/>
+ <pt x="116" y="219" on="1"/>
+ <pt x="315" y="123" on="0"/>
+ <pt x="483" y="123" on="1"/>
+ <pt x="710" y="123" on="0"/>
+ <pt x="710" y="283" on="1"/>
+ <pt x="710" y="393" on="0"/>
+ <pt x="551" y="445" on="1"/>
+ <pt x="375" y="503" on="1"/>
+ <pt x="122" y="586" on="0"/>
+ <pt x="122" y="807" on="1"/>
+ <pt x="122" y="1110" on="0"/>
+ <pt x="536" y="1110" on="1"/>
+ <pt x="655" y="1110" on="0"/>
+ <pt x="825" y="1078" on="1"/>
+ <pt x="825" y="913" on="1"/>
+ <pt x="674" y="962" on="0"/>
+ <pt x="523" y="962" on="1"/>
+ <pt x="317" y="962" on="0"/>
+ <pt x="317" y="827" on="1"/>
+ <pt x="317" y="729" on="0"/>
+ <pt x="458" y="683" on="1"/>
+ <pt x="615" y="632" on="1"/>
+ <pt x="908" y="537" on="0"/>
+ <pt x="908" y="302" on="1"/>
+ <pt x="908" y="151" on="0"/>
+ <pt x="792" y="63" on="1"/>
+ <pt x="676" y="-25" on="0"/>
+ <pt x="475" y="-25" on="1"/>
+ <pt x="316" y="-25" on="0"/>
+ </contour>
+ <contour>
+ <pt x="199" y="1283" on="1"/>
+ <pt x="440" y="1604" on="1"/>
+ <pt x="658" y="1604" on="1"/>
+ <pt x="899" y="1283" on="1"/>
+ <pt x="751" y="1283" on="1"/>
+ <pt x="550" y="1485" on="1"/>
+ <pt x="548" y="1485" on="1"/>
+ <pt x="347" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 77 values pushed */
+ 0 0 17 40 12 3 40 28 48 196 28 2 12 1 36 35 2 31 30 3 1 1 15 14 1
+ 0 4 1 2 3 0 0 32 31 1 37 34 33 30 3 2 0 14 0 0 19 41 10 5 41
+ 24 48 196 10 37 36 35 34 32 31 30 10 8 14 0 3 33 24 14 15 14 1 1 0 1
+ 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="scommaaccent" xMin="116" yMin="-432" xMax="908" yMax="1110">
+ <component glyphName="s" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="197" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="section" xMin="129" yMin="-334" xMax="1010" yMax="1517">
+ <contour>
+ <pt x="129" y="-260" on="1"/>
+ <pt x="129" y="-80" on="1"/>
+ <pt x="379" y="-185" on="0"/>
+ <pt x="541" y="-185" on="1"/>
+ <pt x="667" y="-185" on="0"/>
+ <pt x="749" y="-135" on="1"/>
+ <pt x="830" y="-85" on="0"/>
+ <pt x="830" y="-3" on="1"/>
+ <pt x="830" y="72" on="0"/>
+ <pt x="769" y="114" on="1"/>
+ <pt x="719" y="150" on="0"/>
+ <pt x="600" y="201" on="1"/>
+ <pt x="423" y="277" on="1"/>
+ <pt x="134" y="401" on="0"/>
+ <pt x="134" y="613" on="1"/>
+ <pt x="134" y="758" on="0"/>
+ <pt x="280" y="912" on="1"/>
+ <pt x="139" y="1011" on="0"/>
+ <pt x="139" y="1156" on="1"/>
+ <pt x="139" y="1317" on="0"/>
+ <pt x="269" y="1417" on="1"/>
+ <pt x="398" y="1517" on="0"/>
+ <pt x="611" y="1517" on="1"/>
+ <pt x="756" y="1517" on="0"/>
+ <pt x="954" y="1470" on="1"/>
+ <pt x="954" y="1310" on="1"/>
+ <pt x="747" y="1369" on="0"/>
+ <pt x="608" y="1369" on="1"/>
+ <pt x="478" y="1369" on="0"/>
+ <pt x="398" y="1318" on="1"/>
+ <pt x="318" y="1267" on="0"/>
+ <pt x="318" y="1186" on="1"/>
+ <pt x="318" y="1077" on="0"/>
+ <pt x="493" y="1006" on="1"/>
+ <pt x="629" y="951" on="1"/>
+ <pt x="837" y="867" on="0"/>
+ <pt x="915" y="789" on="1"/>
+ <pt x="995" y="709" on="0"/>
+ <pt x="995" y="589" on="1"/>
+ <pt x="995" y="448" on="0"/>
+ <pt x="846" y="277" on="1"/>
+ <pt x="1010" y="176" on="0"/>
+ <pt x="1010" y="9" on="1"/>
+ <pt x="1010" y="-148" on="0"/>
+ <pt x="876" y="-241" on="1"/>
+ <pt x="743" y="-334" on="0"/>
+ <pt x="523" y="-334" on="1"/>
+ <pt x="369" y="-334" on="0"/>
+ </contour>
+ <contour>
+ <pt x="748" y="341" on="1"/>
+ <pt x="822" y="443" on="0"/>
+ <pt x="822" y="534" on="1"/>
+ <pt x="822" y="607" on="0"/>
+ <pt x="774" y="654" on="1"/>
+ <pt x="726" y="701" on="0"/>
+ <pt x="602" y="753" on="1"/>
+ <pt x="380" y="846" on="1"/>
+ <pt x="306" y="751" on="0"/>
+ <pt x="306" y="664" on="1"/>
+ <pt x="306" y="529" on="0"/>
+ <pt x="536" y="431" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 66 values pushed */
+ 0 0 27 40 22 3 40 46 48 196 22 0 1 55 48 40 25 24 16 1 0 8 13 46 0
+ 0 14 0 0 57 13 14 50 13 38 31 14 18 7 14 42 48 196 18 14 55 48 40 18 16
+ 14 6 24 0 3 42 38 24 25 24 1 1 0 1 2 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ CALL[ ]
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="semicolon" xMin="186" yMin="-321" xMax="383" yMax="1086">
+ <contour>
+ <pt x="186" y="-321" on="1"/>
+ <pt x="186" y="-247" on="1"/>
+ <pt x="257" y="-210" on="0"/>
+ <pt x="257" y="-23" on="1"/>
+ <pt x="257" y="0" on="1"/>
+ <pt x="186" y="0" on="1"/>
+ <pt x="186" y="197" on="1"/>
+ <pt x="383" y="197" on="1"/>
+ <pt x="383" y="31" on="1"/>
+ <pt x="382" y="-271" on="0"/>
+ </contour>
+ <contour>
+ <pt x="186" y="888" on="1"/>
+ <pt x="186" y="1086" on="1"/>
+ <pt x="383" y="1086" on="1"/>
+ <pt x="383" y="888" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 1 8 6 2 2 0 1 5 4 3 1 0 5 13 2 0 0 0 13 10 5 1 11 1 4
+ 48 196 7 6 1 0 12 11 1 14 4 3 2 7 0 3 0 0 13 12 8 7 4 3 0
+ 1 4 48 196 11 10 6 5 1 0 5 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="semicolon#1" xMin="186" yMin="-321" xMax="383" yMax="1086">
+ <contour>
+ <pt x="186" y="-321" on="1"/>
+ <pt x="186" y="-247" on="1"/>
+ <pt x="257" y="-210" on="0"/>
+ <pt x="257" y="-23" on="1"/>
+ <pt x="257" y="0" on="1"/>
+ <pt x="186" y="0" on="1"/>
+ <pt x="186" y="197" on="1"/>
+ <pt x="383" y="197" on="1"/>
+ <pt x="383" y="31" on="1"/>
+ <pt x="382" y="-271" on="0"/>
+ </contour>
+ <contour>
+ <pt x="186" y="888" on="1"/>
+ <pt x="186" y="1086" on="1"/>
+ <pt x="383" y="1086" on="1"/>
+ <pt x="383" y="888" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 62 values pushed */
+ 1 8 6 2 2 0 1 5 4 3 1 0 5 13 2 0 0 0 13 10 5 1 11 1 4
+ 48 196 7 6 1 0 12 11 1 14 4 3 2 7 0 3 0 0 13 12 8 7 4 3 0
+ 1 4 48 196 11 10 6 5 1 0 5 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="seven" xMin="136" yMin="0" xMax="1086" yMax="1480">
+ <contour>
+ <pt x="222" y="0" on="1"/>
+ <pt x="251" y="173" on="0"/>
+ <pt x="304" y="299" on="1"/>
+ <pt x="357" y="424" on="0"/>
+ <pt x="494" y="645" on="1"/>
+ <pt x="898" y="1295" on="1"/>
+ <pt x="136" y="1295" on="1"/>
+ <pt x="136" y="1480" on="1"/>
+ <pt x="1086" y="1480" on="1"/>
+ <pt x="1086" y="1295" on="1"/>
+ <pt x="517" y="456" on="0"/>
+ <pt x="449" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 35 values pushed */
+ 0 0 9 6 5 27 2 7 1 4 48 196 11 0 1 0 8 7 0 14 11 5 0 3 8
+ 6 3 9 8 1 7 6 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="sfthyphen" xMin="88" yMin="518" xMax="594" yMax="666">
+ <contour>
+ <pt x="88" y="518" on="1"/>
+ <pt x="88" y="666" on="1"/>
+ <pt x="594" y="666" on="1"/>
+ <pt x="594" y="518" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="six" xMin="84" yMin="-37" xMax="1027" yMax="1518">
+ <contour>
+ <pt x="298" y="778" on="1"/>
+ <pt x="436" y="950" on="0"/>
+ <pt x="635" y="950" on="1"/>
+ <pt x="817" y="950" on="0"/>
+ <pt x="922" y="826" on="1"/>
+ <pt x="1027" y="703" on="0"/>
+ <pt x="1027" y="486" on="1"/>
+ <pt x="1027" y="245" on="0"/>
+ <pt x="903" y="104" on="1"/>
+ <pt x="779" y="-37" on="0"/>
+ <pt x="571" y="-37" on="1"/>
+ <pt x="344" y="-37" on="0"/>
+ <pt x="214" y="158" on="1"/>
+ <pt x="84" y="352" on="0"/>
+ <pt x="84" y="693" on="1"/>
+ <pt x="84" y="1080" on="0"/>
+ <pt x="239" y="1299" on="1"/>
+ <pt x="394" y="1518" on="0"/>
+ <pt x="668" y="1518" on="1"/>
+ <pt x="794" y="1518" on="0"/>
+ <pt x="947" y="1462" on="1"/>
+ <pt x="947" y="1290" on="1"/>
+ <pt x="766" y="1370" on="0"/>
+ <pt x="664" y="1370" on="1"/>
+ <pt x="443" y="1370" on="0"/>
+ <pt x="354" y="1148" on="1"/>
+ <pt x="319" y="1060" on="0"/>
+ <pt x="307" y="951" on="1"/>
+ <pt x="300" y="893" on="0"/>
+ </contour>
+ <contour>
+ <pt x="582" y="808" on="1"/>
+ <pt x="458" y="808" on="0"/>
+ <pt x="382" y="722" on="1"/>
+ <pt x="305" y="636" on="0"/>
+ <pt x="305" y="489" on="1"/>
+ <pt x="305" y="325" on="0"/>
+ <pt x="384" y="218" on="1"/>
+ <pt x="463" y="111" on="0"/>
+ <pt x="589" y="111" on="1"/>
+ <pt x="833" y="111" on="0"/>
+ <pt x="833" y="445" on="1"/>
+ <pt x="833" y="808" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 50 values pushed */
+ 0 0 37 40 10 29 40 2 23 40 18 48 196 18 0 10 2 2 1 1 21 20 2 0 4
+ 0 2 3 0 0 14 0 0 39 41 6 33 26 14 48 196 6 20 0 14 20 21 20 1 0
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="slash" xMin="-59" yMin="-296" xMax="629" yMax="1480">
+ <contour>
+ <pt x="-59" y="-296" on="1"/>
+ <pt x="474" y="1480" on="1"/>
+ <pt x="629" y="1480" on="1"/>
+ <pt x="96" y="-296" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 12 values pushed */
+ 3 0 1 0 2 1 0 14 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="space"/><!-- contains no outline data -->
+
+ <TTGlyph name="sterling" xMin="121" yMin="0" xMax="966" yMax="1517">
+ <contour>
+ <pt x="121" y="0" on="1"/>
+ <pt x="121" y="173" on="1"/>
+ <pt x="330" y="240" on="0"/>
+ <pt x="331" y="489" on="1"/>
+ <pt x="331" y="716" on="1"/>
+ <pt x="152" y="716" on="1"/>
+ <pt x="152" y="864" on="1"/>
+ <pt x="331" y="864" on="1"/>
+ <pt x="331" y="1079" on="1"/>
+ <pt x="331" y="1292" on="0"/>
+ <pt x="432" y="1404" on="1"/>
+ <pt x="533" y="1517" on="0"/>
+ <pt x="725" y="1517" on="1"/>
+ <pt x="827" y="1517" on="0"/>
+ <pt x="951" y="1487" on="1"/>
+ <pt x="951" y="1320" on="1"/>
+ <pt x="822" y="1369" on="0"/>
+ <pt x="716" y="1369" on="1"/>
+ <pt x="528" y="1369" on="0"/>
+ <pt x="528" y="1139" on="1"/>
+ <pt x="528" y="864" on="1"/>
+ <pt x="744" y="864" on="1"/>
+ <pt x="744" y="716" on="1"/>
+ <pt x="528" y="716" on="1"/>
+ <pt x="528" y="589" on="1"/>
+ <pt x="528" y="409" on="0"/>
+ <pt x="480" y="319" on="1"/>
+ <pt x="442" y="245" on="0"/>
+ <pt x="355" y="173" on="1"/>
+ <pt x="966" y="173" on="1"/>
+ <pt x="966" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 0 0 17 40 12 48 196 12 0 1 19 15 8 3 0 6 3 0 24 3 2 4 1 3 1
+ 14 0 0 0 0 23 22 5 4 7 3 6 29 28 1 13 2 0 2 4 48 196 21 20 7
+ 6 3 30 0 1 2 0 14 28 19 3 2 0 0 24 23 20 19 4 3 3 1 4 48 196
+ 30 29 1 15 14 1 22 21 1 8 7 4 3 3 6 5 1 1 0 1 6 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="t" xMin="29" yMin="-25" xMax="559" yMax="1302">
+ <contour>
+ <pt x="530" y="-6" on="1"/>
+ <pt x="470" y="-25" on="0"/>
+ <pt x="417" y="-25" on="1"/>
+ <pt x="152" y="-25" on="0"/>
+ <pt x="152" y="300" on="1"/>
+ <pt x="152" y="938" on="1"/>
+ <pt x="29" y="938" on="1"/>
+ <pt x="29" y="1086" on="1"/>
+ <pt x="152" y="1086" on="1"/>
+ <pt x="152" y="1283" on="1"/>
+ <pt x="349" y="1302" on="1"/>
+ <pt x="349" y="1086" on="1"/>
+ <pt x="559" y="1086" on="1"/>
+ <pt x="559" y="938" on="1"/>
+ <pt x="349" y="938" on="1"/>
+ <pt x="349" y="336" on="1"/>
+ <pt x="349" y="207" on="0"/>
+ <pt x="371" y="165" on="1"/>
+ <pt x="393" y="123" on="0"/>
+ <pt x="463" y="123" on="1"/>
+ <pt x="501" y="123" on="0"/>
+ <pt x="530" y="134" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 76 values pushed */
+ 0 0 19 40 2 48 196 2 2 1 21 15 4 3 5 2 3 0 10 9 2 13 7 1 0
+ 2 0 0 0 14 13 6 5 7 3 7 1 4 48 196 12 11 8 7 1 3 14 0 0 15
+ 14 11 10 4 3 4 1 4 48 196 13 12 1 21 0 1 9 8 5 4 3 7 6 1 4
+ 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tbar" xMin="29" yMin="-25" xMax="559" yMax="1302">
+ <contour>
+ <pt x="152" y="568" on="1"/>
+ <pt x="29" y="568" on="1"/>
+ <pt x="29" y="691" on="1"/>
+ <pt x="152" y="691" on="1"/>
+ <pt x="152" y="938" on="1"/>
+ <pt x="29" y="938" on="1"/>
+ <pt x="29" y="1086" on="1"/>
+ <pt x="152" y="1086" on="1"/>
+ <pt x="152" y="1283" on="1"/>
+ <pt x="349" y="1302" on="1"/>
+ <pt x="349" y="1086" on="1"/>
+ <pt x="559" y="1086" on="1"/>
+ <pt x="559" y="938" on="1"/>
+ <pt x="349" y="938" on="1"/>
+ <pt x="349" y="691" on="1"/>
+ <pt x="559" y="691" on="1"/>
+ <pt x="559" y="568" on="1"/>
+ <pt x="349" y="568" on="1"/>
+ <pt x="349" y="336" on="1"/>
+ <pt x="349" y="207" on="0"/>
+ <pt x="371" y="165" on="1"/>
+ <pt x="393" y="123" on="0"/>
+ <pt x="463" y="123" on="1"/>
+ <pt x="501" y="123" on="0"/>
+ <pt x="530" y="134" on="1"/>
+ <pt x="530" y="-6" on="1"/>
+ <pt x="470" y="-25" on="0"/>
+ <pt x="417" y="-25" on="1"/>
+ <pt x="152" y="-25" on="0"/>
+ <pt x="152" y="300" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 0 0 22 40 27 48 196 27 2 1 29 24 18 3 0 2 3 0 9 8 2 13 6 1 25
+ 2 0 0 0 13 12 5 4 7 3 6 17 16 1 0 6 3 2 2 4 48 196 15 14 3
+ 2 3 0 11 10 7 6 1 3 14 0 0 18 17 14 13 10 9 4 5 0 1 4 48 196
+ 16 15 12 11 3 25 24 1 29 8 7 4 3 0 5 6 5 2 1 3 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcaron" xMin="29" yMin="-25" xMax="719" yMax="1688">
+ <contour>
+ <pt x="530" y="-6" on="1"/>
+ <pt x="470" y="-25" on="0"/>
+ <pt x="417" y="-25" on="1"/>
+ <pt x="152" y="-25" on="0"/>
+ <pt x="152" y="300" on="1"/>
+ <pt x="152" y="938" on="1"/>
+ <pt x="29" y="938" on="1"/>
+ <pt x="29" y="1086" on="1"/>
+ <pt x="152" y="1086" on="1"/>
+ <pt x="152" y="1283" on="1"/>
+ <pt x="349" y="1302" on="1"/>
+ <pt x="349" y="1086" on="1"/>
+ <pt x="559" y="1086" on="1"/>
+ <pt x="559" y="938" on="1"/>
+ <pt x="349" y="938" on="1"/>
+ <pt x="349" y="336" on="1"/>
+ <pt x="349" y="207" on="0"/>
+ <pt x="371" y="165" on="1"/>
+ <pt x="393" y="123" on="0"/>
+ <pt x="463" y="123" on="1"/>
+ <pt x="501" y="123" on="0"/>
+ <pt x="530" y="134" on="1"/>
+ </contour>
+ <contour>
+ <pt x="522" y="1234" on="1"/>
+ <pt x="522" y="1293" on="1"/>
+ <pt x="598" y="1314" on="0"/>
+ <pt x="598" y="1474" on="1"/>
+ <pt x="598" y="1491" on="1"/>
+ <pt x="522" y="1491" on="1"/>
+ <pt x="522" y="1688" on="1"/>
+ <pt x="719" y="1688" on="1"/>
+ <pt x="719" y="1517" on="1"/>
+ <pt x="718" y="1255" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 103 values pushed */
+ 0 0 19 40 2 48 196 2 2 30 27 26 25 23 22 10 9 8 28 7 3 1 21 15 4
+ 3 5 2 3 0 1 0 2 0 0 0 14 13 6 5 7 3 7 1 4 48 196 29 28 1
+ 0 12 11 8 7 1 3 14 26 25 2 29 12 3 0 0 28 27 23 22 4 3 29 15 14
+ 11 10 4 3 4 2 4 48 196 30 29 1 13 12 1 21 0 1 9 8 5 4 3 7 6
+ 1 5 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcommaaccent" xMin="29" yMin="-432" xMax="559" yMax="1302">
+ <contour>
+ <pt x="530" y="-6" on="1"/>
+ <pt x="470" y="-25" on="0"/>
+ <pt x="417" y="-25" on="1"/>
+ <pt x="152" y="-25" on="0"/>
+ <pt x="152" y="300" on="1"/>
+ <pt x="152" y="938" on="1"/>
+ <pt x="29" y="938" on="1"/>
+ <pt x="29" y="1086" on="1"/>
+ <pt x="152" y="1086" on="1"/>
+ <pt x="152" y="1283" on="1"/>
+ <pt x="349" y="1302" on="1"/>
+ <pt x="349" y="1086" on="1"/>
+ <pt x="559" y="1086" on="1"/>
+ <pt x="559" y="938" on="1"/>
+ <pt x="349" y="938" on="1"/>
+ <pt x="349" y="336" on="1"/>
+ <pt x="349" y="207" on="0"/>
+ <pt x="371" y="165" on="1"/>
+ <pt x="393" y="123" on="0"/>
+ <pt x="463" y="123" on="1"/>
+ <pt x="501" y="123" on="0"/>
+ <pt x="530" y="134" on="1"/>
+ </contour>
+ <contour>
+ <pt x="299" y="0" on="1"/>
+ <pt x="396" y="0" on="1"/>
+ <pt x="336" y="-109" on="1"/>
+ <pt x="408" y="-111" on="0"/>
+ <pt x="460" y="-148" on="1"/>
+ <pt x="530" y="-197" on="0"/>
+ <pt x="530" y="-268" on="1"/>
+ <pt x="530" y="-337" on="0"/>
+ <pt x="472" y="-384" on="1"/>
+ <pt x="413" y="-432" on="0"/>
+ <pt x="327" y="-432" on="1"/>
+ <pt x="259" y="-432" on="0"/>
+ <pt x="183" y="-411" on="1"/>
+ <pt x="183" y="-330" on="1"/>
+ <pt x="233" y="-345" on="0"/>
+ <pt x="287" y="-345" on="1"/>
+ <pt x="391" y="-345" on="0"/>
+ <pt x="391" y="-271" on="1"/>
+ <pt x="391" y="-178" on="0"/>
+ <pt x="204" y="-175" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 109 values pushed */
+ 0 0 37 44 32 19 40 2 48 196 2 2 1 21 15 4 3 5 2 3 0 10 9 2 13
+ 7 1 41 35 34 24 23 22 0 7 13 32 2 0 0 0 14 13 6 5 7 3 7 1 4
+ 48 196 12 11 8 7 1 3 14 0 0 39 42 28 48 196 23 0 10 2 41 35 34 24 22
+ 5 10 4 3 0 0 15 14 11 10 4 3 4 1 4 48 196 13 12 1 28 21 0 2 9
+ 8 5 4 3 7 6 1 4 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tcommabelow" xMin="29" yMin="-432" xMax="559" yMax="1302">
+ <component glyphName="t" x="0" y="0" flags="0x4"/>
+ <component glyphName="Unterkomma" x="7" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="thorn" xMin="154" yMin="-395" xMax="1052" yMax="1579">
+ <contour>
+ <pt x="351" y="-395" on="1"/>
+ <pt x="154" y="-395" on="1"/>
+ <pt x="154" y="1579" on="1"/>
+ <pt x="351" y="1579" on="1"/>
+ <pt x="351" y="882" on="1"/>
+ <pt x="407" y="984" on="0"/>
+ <pt x="469" y="1036" on="1"/>
+ <pt x="557" y="1110" on="0"/>
+ <pt x="676" y="1110" on="1"/>
+ <pt x="845" y="1110" on="0"/>
+ <pt x="948" y="963" on="1"/>
+ <pt x="1052" y="816" on="0"/>
+ <pt x="1052" y="572" on="1"/>
+ <pt x="1052" y="287" on="0"/>
+ <pt x="918" y="131" on="1"/>
+ <pt x="785" y="-25" on="0"/>
+ <pt x="540" y="-25" on="1"/>
+ <pt x="449" y="-25" on="0"/>
+ <pt x="351" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="351" y="703" on="1"/>
+ <pt x="351" y="149" on="1"/>
+ <pt x="488" y="123" on="0"/>
+ <pt x="557" y="123" on="1"/>
+ <pt x="839" y="123" on="0"/>
+ <pt x="839" y="552" on="1"/>
+ <pt x="839" y="733" on="0"/>
+ <pt x="783" y="835" on="1"/>
+ <pt x="728" y="938" on="0"/>
+ <pt x="634" y="938" on="1"/>
+ <pt x="508" y="938" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 68 values pushed */
+ 0 0 28 30 8 22 40 16 48 196 16 2 8 1 1 1 20 19 4 3 1 2 3 0 0
+ 1 18 2 0 2 0 3 2 1 1 0 1 2 0 14 0 0 24 9 12 48 196 12 0 0
+ 0 20 19 18 4 3 0 4 5 1 1 4 48 196 2 1 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="three" xMin="153" yMin="-37" xMax="966" yMax="1517">
+ <contour>
+ <pt x="153" y="11" on="1"/>
+ <pt x="153" y="195" on="1"/>
+ <pt x="160" y="192" on="1"/>
+ <pt x="186" y="181" on="0"/>
+ <pt x="197" y="178" on="1"/>
+ <pt x="306" y="138" on="0"/>
+ <pt x="345" y="128" on="1"/>
+ <pt x="410" y="111" on="0"/>
+ <pt x="463" y="111" on="1"/>
+ <pt x="614" y="111" on="0"/>
+ <pt x="689" y="195" on="1"/>
+ <pt x="755" y="267" on="0"/>
+ <pt x="755" y="400" on="1"/>
+ <pt x="755" y="555" on="0"/>
+ <pt x="654" y="637" on="1"/>
+ <pt x="554" y="719" on="0"/>
+ <pt x="368" y="719" on="1"/>
+ <pt x="290" y="719" on="1"/>
+ <pt x="290" y="852" on="1"/>
+ <pt x="358" y="853" on="1"/>
+ <pt x="530" y="856" on="0"/>
+ <pt x="623" y="932" on="1"/>
+ <pt x="720" y="1010" on="0"/>
+ <pt x="720" y="1147" on="1"/>
+ <pt x="720" y="1369" on="0"/>
+ <pt x="481" y="1369" on="1"/>
+ <pt x="358" y="1369" on="0"/>
+ <pt x="173" y="1286" on="1"/>
+ <pt x="173" y="1458" on="1"/>
+ <pt x="354" y="1517" on="0"/>
+ <pt x="493" y="1517" on="1"/>
+ <pt x="734" y="1517" on="0"/>
+ <pt x="839" y="1402" on="1"/>
+ <pt x="917" y="1317" on="0"/>
+ <pt x="917" y="1176" on="1"/>
+ <pt x="917" y="1017" on="0"/>
+ <pt x="805" y="914" on="1"/>
+ <pt x="739" y="853" on="0"/>
+ <pt x="609" y="802" on="1"/>
+ <pt x="723" y="772" on="0"/>
+ <pt x="781" y="738" on="1"/>
+ <pt x="966" y="631" on="0"/>
+ <pt x="966" y="408" on="1"/>
+ <pt x="966" y="206" on="0"/>
+ <pt x="833" y="85" on="1"/>
+ <pt x="700" y="-37" on="0"/>
+ <pt x="483" y="-37" on="1"/>
+ <pt x="366" y="-37" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 65 values pushed */
+ 0 0 25 40 30 8 40 46 48 196 46 2 30 0 1 1 38 28 27 18 17 16 1 0 8
+ 0 2 3 0 0 14 0 0 23 41 34 12 9 42 48 196 38 18 17 16 4 13 42 34 27
+ 0 0 28 27 23 1 0 1 5 48 196 1 0 1 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP0[ ]
+ SZP1[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="threequarters" xMin="111" yMin="-37" xMax="1597" yMax="1517">
+ <contour>
+ <pt x="123" y="1353" on="1"/>
+ <pt x="123" y="1465" on="1"/>
+ <pt x="237" y="1503" on="0"/>
+ <pt x="349" y="1503" on="1"/>
+ <pt x="631" y="1503" on="0"/>
+ <pt x="631" y="1295" on="1"/>
+ <pt x="631" y="1199" on="0"/>
+ <pt x="562" y="1137" on="1"/>
+ <pt x="521" y="1101" on="0"/>
+ <pt x="440" y="1071" on="1"/>
+ <pt x="568" y="1038" on="0"/>
+ <pt x="619" y="970" on="1"/>
+ <pt x="660" y="914" on="0"/>
+ <pt x="660" y="832" on="1"/>
+ <pt x="660" y="711" on="0"/>
+ <pt x="573" y="641" on="1"/>
+ <pt x="487" y="570" on="0"/>
+ <pt x="335" y="570" on="1"/>
+ <pt x="233" y="570" on="0"/>
+ <pt x="111" y="599" on="1"/>
+ <pt x="111" y="721" on="1"/>
+ <pt x="246" y="670" on="0"/>
+ <pt x="324" y="670" on="1"/>
+ <pt x="504" y="670" on="0"/>
+ <pt x="504" y="831" on="1"/>
+ <pt x="504" y="1015" on="0"/>
+ <pt x="244" y="1015" on="1"/>
+ <pt x="193" y="1015" on="1"/>
+ <pt x="193" y="1108" on="1"/>
+ <pt x="237" y="1108" on="1"/>
+ <pt x="481" y="1108" on="0"/>
+ <pt x="481" y="1275" on="1"/>
+ <pt x="481" y="1403" on="0"/>
+ <pt x="326" y="1403" on="1"/>
+ <pt x="235" y="1403" on="0"/>
+ </contour>
+ <contour>
+ <pt x="1338" y="0" on="1"/>
+ <pt x="1338" y="242" on="1"/>
+ <pt x="931" y="242" on="1"/>
+ <pt x="931" y="355" on="1"/>
+ <pt x="1334" y="888" on="1"/>
+ <pt x="1473" y="888" on="1"/>
+ <pt x="1473" y="359" on="1"/>
+ <pt x="1597" y="359" on="1"/>
+ <pt x="1597" y="242" on="1"/>
+ <pt x="1473" y="242" on="1"/>
+ <pt x="1473" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1060" y="359" on="1"/>
+ <pt x="1338" y="359" on="1"/>
+ <pt x="1338" y="723" on="1"/>
+ </contour>
+ <contour>
+ <pt x="284" y="-37" on="1"/>
+ <pt x="1372" y="1517" on="1"/>
+ <pt x="1507" y="1517" on="1"/>
+ <pt x="419" y="-37" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 126 values pushed */
+ 0 0 33 11 3 22 11 17 48 196 17 48 20 19 17 4 39 41 3 38 41 36 2 51 50
+ 29 28 27 26 9 1 0 9 13 3 39 52 49 45 35 4 13 36 0 0 47 46 42 41 38
+ 3 36 1 4 48 196 40 39 1 44 43 37 36 3 2 0 14 0 0 31 39 5 24 37 13
+ 48 196 50 40 35 2 51 43 42 3 13 40 52 49 46 39 38 37 29 28 27 26 20 19 9
+ 1 0 15 13 13 5 35 0 0 48 47 36 35 22 3 40 1 4 48 196 45 44 41 40 3
+ 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="threesuperior" xMin="74" yMin="570" xMax="623" yMax="1503">
+ <contour>
+ <pt x="86" y="1353" on="1"/>
+ <pt x="86" y="1465" on="1"/>
+ <pt x="200" y="1503" on="0"/>
+ <pt x="312" y="1503" on="1"/>
+ <pt x="594" y="1503" on="0"/>
+ <pt x="594" y="1295" on="1"/>
+ <pt x="594" y="1199" on="0"/>
+ <pt x="525" y="1137" on="1"/>
+ <pt x="484" y="1101" on="0"/>
+ <pt x="403" y="1071" on="1"/>
+ <pt x="531" y="1038" on="0"/>
+ <pt x="582" y="970" on="1"/>
+ <pt x="623" y="914" on="0"/>
+ <pt x="623" y="832" on="1"/>
+ <pt x="623" y="711" on="0"/>
+ <pt x="536" y="641" on="1"/>
+ <pt x="450" y="570" on="0"/>
+ <pt x="298" y="570" on="1"/>
+ <pt x="196" y="570" on="0"/>
+ <pt x="74" y="599" on="1"/>
+ <pt x="74" y="721" on="1"/>
+ <pt x="209" y="670" on="0"/>
+ <pt x="287" y="670" on="1"/>
+ <pt x="467" y="670" on="0"/>
+ <pt x="467" y="831" on="1"/>
+ <pt x="467" y="1015" on="0"/>
+ <pt x="207" y="1015" on="1"/>
+ <pt x="156" y="1015" on="1"/>
+ <pt x="156" y="1108" on="1"/>
+ <pt x="200" y="1108" on="1"/>
+ <pt x="444" y="1108" on="0"/>
+ <pt x="444" y="1275" on="1"/>
+ <pt x="444" y="1403" on="0"/>
+ <pt x="289" y="1403" on="1"/>
+ <pt x="198" y="1403" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 43 values pushed */
+ 0 0 33 11 3 22 11 17 48 196 29 28 27 26 20 19 17 9 3 1 0 14 0 0 31
+ 39 5 24 37 13 48 196 29 28 27 26 20 19 13 9 5 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="tilde" xMin="8" yMin="1283" xMax="674" yMax="1517">
+ <contour>
+ <pt x="8" y="1283" on="1"/>
+ <pt x="15" y="1376" on="0"/>
+ <pt x="40" y="1427" on="1"/>
+ <pt x="86" y="1517" on="0"/>
+ <pt x="195" y="1517" on="1"/>
+ <pt x="267" y="1517" on="0"/>
+ <pt x="328" y="1479" on="1"/>
+ <pt x="388" y="1442" on="1"/>
+ <pt x="445" y="1407" on="0"/>
+ <pt x="475" y="1407" on="1"/>
+ <pt x="540" y="1407" on="0"/>
+ <pt x="551" y="1517" on="1"/>
+ <pt x="674" y="1517" on="1"/>
+ <pt x="667" y="1423" on="0"/>
+ <pt x="642" y="1373" on="1"/>
+ <pt x="597" y="1283" on="0"/>
+ <pt x="489" y="1283" on="1"/>
+ <pt x="417" y="1283" on="0"/>
+ <pt x="354" y="1322" on="1"/>
+ <pt x="294" y="1359" on="1"/>
+ <pt x="239" y="1393" on="0"/>
+ <pt x="207" y="1393" on="1"/>
+ <pt x="142" y="1393" on="0"/>
+ <pt x="131" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 30 values pushed */
+ 0 0 21 6 4 9 6 16 48 196 4 0 1 12 11 2 13 0 0 1 23 0 16 0 0
+ 14 23 12 11 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ MDRP[00100]
+ MDRP[00000]
+ MDRP[00000]
+ SZP0[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="trademark" xMin="222" yMin="740" xMax="1764" yMax="1480">
+ <contour>
+ <pt x="469" y="740" on="1"/>
+ <pt x="469" y="1357" on="1"/>
+ <pt x="222" y="1357" on="1"/>
+ <pt x="222" y="1480" on="1"/>
+ <pt x="888" y="1480" on="1"/>
+ <pt x="888" y="1357" on="1"/>
+ <pt x="641" y="1357" on="1"/>
+ <pt x="641" y="740" on="1"/>
+ </contour>
+ <contour>
+ <pt x="1012" y="740" on="1"/>
+ <pt x="1012" y="1480" on="1"/>
+ <pt x="1245" y="1480" on="1"/>
+ <pt x="1401" y="1053" on="1"/>
+ <pt x="1551" y="1480" on="1"/>
+ <pt x="1764" y="1480" on="1"/>
+ <pt x="1764" y="740" on="1"/>
+ <pt x="1591" y="740" on="1"/>
+ <pt x="1591" y="1277" on="1"/>
+ <pt x="1428" y="802" on="1"/>
+ <pt x="1310" y="802" on="1"/>
+ <pt x="1147" y="1234" on="1"/>
+ <pt x="1147" y="740" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 97 values pushed */
+ 1 19 16 2 1 1 3 0 1 18 17 11 3 1 0 3 0 0 0 6 5 2 1 6 3
+ 3 1 4 48 196 20 15 14 8 7 0 5 0 13 12 10 9 4 3 0 5 14 18 17 12
+ 11 10 5 15 19 3 5 4 2 8 6 3 3 2 0 0 0 16 15 13 1 13 9 8 18
+ 1 19 7 6 13 1 0 3 4 48 196 14 13 1 20 19 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00000]
+ MDRP[00000]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="two" xMin="102" yMin="0" xMax="941" yMax="1517">
+ <contour>
+ <pt x="102" y="0" on="1"/>
+ <pt x="102" y="173" on="1"/>
+ <pt x="170" y="333" on="0"/>
+ <pt x="332" y="502" on="1"/>
+ <pt x="440" y="612" on="1"/>
+ <pt x="538" y="712" on="1"/>
+ <pt x="731" y="909" on="0"/>
+ <pt x="731" y="1107" on="1"/>
+ <pt x="731" y="1248" on="0"/>
+ <pt x="657" y="1315" on="1"/>
+ <pt x="597" y="1370" on="0"/>
+ <pt x="491" y="1370" on="1"/>
+ <pt x="353" y="1370" on="0"/>
+ <pt x="139" y="1250" on="1"/>
+ <pt x="139" y="1424" on="1"/>
+ <pt x="342" y="1517" on="0"/>
+ <pt x="517" y="1517" on="1"/>
+ <pt x="711" y="1517" on="0"/>
+ <pt x="826" y="1404" on="1"/>
+ <pt x="941" y="1292" on="0"/>
+ <pt x="941" y="1102" on="1"/>
+ <pt x="941" y="971" on="0"/>
+ <pt x="882" y="870" on="1"/>
+ <pt x="820" y="766" on="0"/>
+ <pt x="658" y="620" on="1"/>
+ <pt x="589" y="558" on="1"/>
+ <pt x="382" y="370" on="0"/>
+ <pt x="340" y="173" on="1"/>
+ <pt x="933" y="173" on="1"/>
+ <pt x="933" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 0 0 11 40 16 48 196 16 0 1 14 13 2 0 1 3 0 0 0 28 27 1 13 2 0
+ 1 4 48 196 29 0 1 0 14 0 0 7 9 20 48 196 27 28 13 2 20 28 29 28 1
+ 14 13 1 1 0 1 3 0
+ LOOPCALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="twosuperior" xMin="74" yMin="592" xMax="639" yMax="1503">
+ <contour>
+ <pt x="74" y="592" on="1"/>
+ <pt x="74" y="714" on="1"/>
+ <pt x="142" y="832" on="0"/>
+ <pt x="256" y="933" on="1"/>
+ <pt x="326" y="995" on="1"/>
+ <pt x="482" y="1133" on="0"/>
+ <pt x="482" y="1255" on="1"/>
+ <pt x="482" y="1401" on="0"/>
+ <pt x="321" y="1401" on="1"/>
+ <pt x="226" y="1401" on="0"/>
+ <pt x="96" y="1332" on="1"/>
+ <pt x="96" y="1449" on="1"/>
+ <pt x="227" y="1503" on="0"/>
+ <pt x="347" y="1503" on="1"/>
+ <pt x="478" y="1503" on="0"/>
+ <pt x="559" y="1435" on="1"/>
+ <pt x="639" y="1367" on="0"/>
+ <pt x="639" y="1260" on="1"/>
+ <pt x="639" y="1120" on="0"/>
+ <pt x="455" y="967" on="1"/>
+ <pt x="402" y="923" on="1"/>
+ <pt x="269" y="813" on="0"/>
+ <pt x="246" y="714" on="1"/>
+ <pt x="635" y="714" on="1"/>
+ <pt x="635" y="592" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 45 values pushed */
+ 0 0 8 11 13 48 196 11 10 2 13 13 1 0 0 24 0 38 1 1 1 4 48 196 23
+ 22 1 2 0 14 0 0 6 37 17 48 196 24 23 22 17 11 10 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[1]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="u" xMin="142" yMin="-25" xMax="984" yMax="1086">
+ <contour>
+ <pt x="787" y="0" on="1"/>
+ <pt x="787" y="203" on="1"/>
+ <pt x="714" y="102" on="0"/>
+ <pt x="644" y="50" on="1"/>
+ <pt x="541" y="-25" on="0"/>
+ <pt x="418" y="-25" on="1"/>
+ <pt x="142" y="-25" on="0"/>
+ <pt x="142" y="306" on="1"/>
+ <pt x="142" y="1086" on="1"/>
+ <pt x="339" y="1086" on="1"/>
+ <pt x="339" y="370" on="1"/>
+ <pt x="339" y="239" on="0"/>
+ <pt x="366" y="192" on="1"/>
+ <pt x="394" y="145" on="0"/>
+ <pt x="470" y="145" on="1"/>
+ <pt x="632" y="145" on="0"/>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="1086" on="1"/>
+ <pt x="984" y="1086" on="1"/>
+ <pt x="984" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 0 0 14 30 5 48 196 5 2 16 10 7 1 4 8 0 3 19 0 1 0 18 17 9 8
+ 1 3 14 0 0 17 16 1 0 4 3 18 10 9 4 1 7 2 4 48 196 19 18 1 8
+ 7 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="uacute" xMin="142" yMin="-25" xMax="984" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="308" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ubreve" xMin="142" yMin="-25" xMax="984" yMax="1604">
+ <contour>
+ <pt x="787" y="0" on="1"/>
+ <pt x="787" y="203" on="1"/>
+ <pt x="714" y="102" on="0"/>
+ <pt x="644" y="50" on="1"/>
+ <pt x="541" y="-25" on="0"/>
+ <pt x="418" y="-25" on="1"/>
+ <pt x="142" y="-25" on="0"/>
+ <pt x="142" y="306" on="1"/>
+ <pt x="142" y="1086" on="1"/>
+ <pt x="339" y="1086" on="1"/>
+ <pt x="339" y="370" on="1"/>
+ <pt x="339" y="239" on="0"/>
+ <pt x="366" y="192" on="1"/>
+ <pt x="394" y="145" on="0"/>
+ <pt x="470" y="145" on="1"/>
+ <pt x="632" y="145" on="0"/>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="1086" on="1"/>
+ <pt x="984" y="1086" on="1"/>
+ <pt x="984" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="230" y="1604" on="1"/>
+ <pt x="353" y="1604" on="1"/>
+ <pt x="374" y="1511" on="0"/>
+ <pt x="428" y="1470" on="1"/>
+ <pt x="480" y="1431" on="0"/>
+ <pt x="563" y="1431" on="1"/>
+ <pt x="657" y="1431" on="0"/>
+ <pt x="711" y="1480" on="1"/>
+ <pt x="754" y="1520" on="0"/>
+ <pt x="773" y="1604" on="1"/>
+ <pt x="896" y="1604" on="1"/>
+ <pt x="880" y="1470" on="0"/>
+ <pt x="807" y="1389" on="1"/>
+ <pt x="713" y="1283" on="0"/>
+ <pt x="563" y="1283" on="1"/>
+ <pt x="406" y="1283" on="0"/>
+ <pt x="311" y="1398" on="1"/>
+ <pt x="247" y="1475" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 79 values pushed */
+ 0 0 25 40 34 14 30 5 48 196 5 2 16 10 7 1 4 8 0 3 30 29 21 20 4
+ 13 34 8 19 0 1 0 18 17 9 8 1 3 14 30 18 0 2 29 21 2 0 9 3 20
+ 9 7 2 0 0 17 16 1 0 4 3 18 10 9 4 1 7 2 4 48 196 19 18 1 8
+ 7 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SRP0[ ]
+ MDRP[00100]
+ LOOPCALL[ ]
+ CALL[ ]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ucircumflex" xMin="142" yMin="-25" xMax="984" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="circumflex" x="222" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="udieresis" xMin="142" yMin="-25" xMax="984" yMax="1456">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="222" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ugrave" xMin="142" yMin="-25" xMax="984" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="grave" x="148" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="uhungarumlaut" xMin="142" yMin="-25" xMax="1073" yMax="1604">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="hungarumlaut" x="341" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="umacron" xMin="142" yMin="-25" xMax="984" yMax="1431">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="macron" x="222" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="underscore" xMin="0" yMin="-148" xMax="1139" yMax="0">
+ <contour>
+ <pt x="0" y="-148" on="1"/>
+ <pt x="0" y="0" on="1"/>
+ <pt x="1139" y="0" on="1"/>
+ <pt x="1139" y="-148" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 24 values pushed */
+ 0 0 3 0 7 1 1 1 4 48 196 2 1 1 0 14 3 2 1 1 0 1 2 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="uogonek" xMin="142" yMin="-370" xMax="984" yMax="1086">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="ogonek" x="465" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="uring" xMin="142" yMin="-25" xMax="984" yMax="1737">
+ <component glyphName="u" x="0" y="0" flags="0x4"/>
+ <component glyphName="ring" x="222" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="utilde" xMin="142" yMin="-25" xMax="984" yMax="1517">
+ <contour>
+ <pt x="787" y="0" on="1"/>
+ <pt x="787" y="203" on="1"/>
+ <pt x="714" y="102" on="0"/>
+ <pt x="644" y="50" on="1"/>
+ <pt x="541" y="-25" on="0"/>
+ <pt x="418" y="-25" on="1"/>
+ <pt x="142" y="-25" on="0"/>
+ <pt x="142" y="306" on="1"/>
+ <pt x="142" y="1086" on="1"/>
+ <pt x="339" y="1086" on="1"/>
+ <pt x="339" y="370" on="1"/>
+ <pt x="339" y="239" on="0"/>
+ <pt x="366" y="192" on="1"/>
+ <pt x="394" y="145" on="0"/>
+ <pt x="470" y="145" on="1"/>
+ <pt x="632" y="145" on="0"/>
+ <pt x="787" y="382" on="1"/>
+ <pt x="787" y="1086" on="1"/>
+ <pt x="984" y="1086" on="1"/>
+ <pt x="984" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="230" y="1283" on="1"/>
+ <pt x="237" y="1377" on="0"/>
+ <pt x="262" y="1427" on="1"/>
+ <pt x="308" y="1517" on="0"/>
+ <pt x="417" y="1517" on="1"/>
+ <pt x="488" y="1517" on="0"/>
+ <pt x="550" y="1479" on="1"/>
+ <pt x="610" y="1442" on="1"/>
+ <pt x="667" y="1407" on="0"/>
+ <pt x="697" y="1407" on="1"/>
+ <pt x="762" y="1407" on="0"/>
+ <pt x="773" y="1517" on="1"/>
+ <pt x="896" y="1517" on="1"/>
+ <pt x="889" y="1423" on="0"/>
+ <pt x="864" y="1373" on="1"/>
+ <pt x="819" y="1283" on="0"/>
+ <pt x="711" y="1283" on="1"/>
+ <pt x="639" y="1283" on="0"/>
+ <pt x="576" y="1322" on="1"/>
+ <pt x="516" y="1359" on="1"/>
+ <pt x="461" y="1393" on="0"/>
+ <pt x="429" y="1393" on="1"/>
+ <pt x="364" y="1393" on="0"/>
+ <pt x="353" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 93 values pushed */
+ 0 0 41 6 24 29 6 36 14 30 5 48 196 24 0 5 2 36 1 43 36 20 3 0 8
+ 3 0 16 10 7 1 4 8 0 3 1 32 31 2 13 0 0 19 0 1 0 18 17 9 8
+ 1 3 14 32 18 0 2 43 31 2 0 9 3 20 9 7 2 0 0 17 16 1 0 4 3
+ 18 10 9 4 1 7 2 4 48 196 19 18 1 8 7 1 2 0
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP0[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ MDAP[1]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="v" xMin="19" yMin="0" xMax="1012" yMax="1086">
+ <contour>
+ <pt x="404" y="0" on="1"/>
+ <pt x="19" y="1086" on="1"/>
+ <pt x="218" y="1086" on="1"/>
+ <pt x="519" y="241" on="1"/>
+ <pt x="837" y="1086" on="1"/>
+ <pt x="1012" y="1086" on="1"/>
+ <pt x="601" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 22 values pushed */
+ 3 1 0 2 6 0 1 0 5 4 2 1 1 3 14 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="w" xMin="11" yMin="0" xMax="1465" yMax="1086">
+ <contour>
+ <pt x="273" y="0" on="1"/>
+ <pt x="11" y="1086" on="1"/>
+ <pt x="204" y="1086" on="1"/>
+ <pt x="400" y="268" on="1"/>
+ <pt x="650" y="1086" on="1"/>
+ <pt x="847" y="1086" on="1"/>
+ <pt x="1067" y="265" on="1"/>
+ <pt x="1295" y="1086" on="1"/>
+ <pt x="1465" y="1086" on="1"/>
+ <pt x="1160" y="0" on="1"/>
+ <pt x="962" y="0" on="1"/>
+ <pt x="732" y="841" on="1"/>
+ <pt x="472" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 35 values pushed */
+ 11 6 3 3 1 0 3 12 10 9 0 3 0 8 7 5 4 2 1 1 5 14 12 11 10
+ 9 8 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="wcircumflex" xMin="11" yMin="0" xMax="1465" yMax="1604">
+ <contour>
+ <pt x="273" y="0" on="1"/>
+ <pt x="11" y="1086" on="1"/>
+ <pt x="204" y="1086" on="1"/>
+ <pt x="400" y="268" on="1"/>
+ <pt x="650" y="1086" on="1"/>
+ <pt x="847" y="1086" on="1"/>
+ <pt x="1067" y="265" on="1"/>
+ <pt x="1295" y="1086" on="1"/>
+ <pt x="1465" y="1086" on="1"/>
+ <pt x="1160" y="0" on="1"/>
+ <pt x="962" y="0" on="1"/>
+ <pt x="732" y="841" on="1"/>
+ <pt x="472" y="0" on="1"/>
+ </contour>
+ <contour>
+ <pt x="398" y="1283" on="1"/>
+ <pt x="639" y="1604" on="1"/>
+ <pt x="857" y="1604" on="1"/>
+ <pt x="1098" y="1283" on="1"/>
+ <pt x="950" y="1283" on="1"/>
+ <pt x="749" y="1485" on="1"/>
+ <pt x="747" y="1485" on="1"/>
+ <pt x="546" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 58 values pushed */
+ 19 18 2 14 13 3 11 6 3 3 1 0 3 15 14 1 20 17 16 13 3 12 10 9 0
+ 3 3 0 8 7 5 4 2 1 1 5 14 20 19 18 17 16 15 14 13 12 11 10 9 8
+ 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="x" xMin="28" yMin="0" xMax="993" yMax="1086">
+ <contour>
+ <pt x="28" y="0" on="1"/>
+ <pt x="381" y="574" on="1"/>
+ <pt x="40" y="1086" on="1"/>
+ <pt x="268" y="1086" on="1"/>
+ <pt x="540" y="679" on="1"/>
+ <pt x="784" y="1086" on="1"/>
+ <pt x="966" y="1086" on="1"/>
+ <pt x="634" y="539" on="1"/>
+ <pt x="993" y="0" on="1"/>
+ <pt x="766" y="0" on="1"/>
+ <pt x="472" y="436" on="1"/>
+ <pt x="210" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 33 values pushed */
+ 10 7 4 1 4 2 0 3 11 9 8 0 3 0 6 5 3 2 1 3 14 11 10 9 8
+ 7 6 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="y" xMin="19" yMin="-395" xMax="1012" yMax="1086">
+ <contour>
+ <pt x="404" y="0" on="1"/>
+ <pt x="19" y="1086" on="1"/>
+ <pt x="219" y="1086" on="1"/>
+ <pt x="514" y="253" on="1"/>
+ <pt x="838" y="1086" on="1"/>
+ <pt x="1012" y="1086" on="1"/>
+ <pt x="438" y="-395" on="1"/>
+ <pt x="233" y="-395" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 31 values pushed */
+ 1 3 1 2 2 0 1 0 2 6 2 0 7 6 1 0 5 4 2 1 1 3 14 7 6
+ 5 4 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="yacute" xMin="19" yMin="-395" xMax="1012" yMax="1604">
+ <component glyphName="y" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="259" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="ycircumflex" xMin="19" yMin="-395" xMax="1012" yMax="1604">
+ <contour>
+ <pt x="404" y="0" on="1"/>
+ <pt x="19" y="1086" on="1"/>
+ <pt x="219" y="1086" on="1"/>
+ <pt x="514" y="253" on="1"/>
+ <pt x="838" y="1086" on="1"/>
+ <pt x="1012" y="1086" on="1"/>
+ <pt x="438" y="-395" on="1"/>
+ <pt x="233" y="-395" on="1"/>
+ </contour>
+ <contour>
+ <pt x="178" y="1283" on="1"/>
+ <pt x="419" y="1604" on="1"/>
+ <pt x="637" y="1604" on="1"/>
+ <pt x="878" y="1283" on="1"/>
+ <pt x="730" y="1283" on="1"/>
+ <pt x="529" y="1485" on="1"/>
+ <pt x="527" y="1485" on="1"/>
+ <pt x="326" y="1283" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 54 values pushed */
+ 14 13 2 9 8 3 1 3 1 2 2 0 1 0 2 6 2 0 10 9 1 15 12 11 8
+ 3 7 6 1 3 0 5 4 2 1 1 3 14 15 14 13 12 11 10 9 8 7 6 5 4
+ 3 2 1 0
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ MDAP[0]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SZP1[ ]
+ CALL[ ]
+ SZP1[ ]
+ SZP0[ ]
+ CALL[ ]
+ SZP0[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="ydieresis" xMin="19" yMin="-395" xMax="1012" yMax="1456">
+ <component glyphName="y" x="0" y="0" flags="0x4"/>
+ <component glyphName="dieresis" x="188" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="yen" xMin="25" yMin="0" xMax="1077" yMax="1480">
+ <contour>
+ <pt x="453" y="0" on="1"/>
+ <pt x="453" y="345" on="1"/>
+ <pt x="157" y="345" on="1"/>
+ <pt x="157" y="469" on="1"/>
+ <pt x="453" y="469" on="1"/>
+ <pt x="453" y="617" on="1"/>
+ <pt x="157" y="617" on="1"/>
+ <pt x="157" y="740" on="1"/>
+ <pt x="453" y="740" on="1"/>
+ <pt x="25" y="1480" on="1"/>
+ <pt x="253" y="1480" on="1"/>
+ <pt x="575" y="922" on="1"/>
+ <pt x="577" y="922" on="1"/>
+ <pt x="900" y="1480" on="1"/>
+ <pt x="1077" y="1480" on="1"/>
+ <pt x="650" y="740" on="1"/>
+ <pt x="946" y="740" on="1"/>
+ <pt x="946" y="617" on="1"/>
+ <pt x="650" y="617" on="1"/>
+ <pt x="650" y="469" on="1"/>
+ <pt x="946" y="469" on="1"/>
+ <pt x="946" y="345" on="1"/>
+ <pt x="650" y="345" on="1"/>
+ <pt x="650" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 93 values pushed */
+ 12 11 2 9 7 3 0 0 18 17 6 5 6 3 7 20 19 4 3 6 3 1 2 4 48
+ 196 16 15 8 7 3 22 21 2 1 3 23 0 1 3 0 14 13 10 9 0 3 14 12 11
+ 2 15 0 3 21 20 17 16 14 13 6 13 15 10 9 7 6 3 2 6 13 0 0 0 23
+ 22 19 18 15 4 4 0 1 4 48 196 8 5 4 1 0 4 0
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ SRP0[ ]
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ SLOOP[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="z" xMin="74" yMin="0" xMax="950" yMax="1086">
+ <contour>
+ <pt x="74" y="0" on="1"/>
+ <pt x="74" y="148" on="1"/>
+ <pt x="695" y="938" on="1"/>
+ <pt x="105" y="938" on="1"/>
+ <pt x="105" y="1086" on="1"/>
+ <pt x="938" y="1086" on="1"/>
+ <pt x="938" y="938" on="1"/>
+ <pt x="317" y="148" on="1"/>
+ <pt x="950" y="148" on="1"/>
+ <pt x="950" y="0" on="1"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 46 values pushed */
+ 0 0 6 3 2 7 2 4 8 7 1 7 2 0 2 4 48 196 9 0 1 0 5 4 1
+ 14 7 2 2 5 3 3 9 8 1 6 5 1 4 3 1 1 0 1 4 0
+ LOOPCALL[ ]
+ CALL[ ]
+ CALL[ ]
+ MIAP[1]
+ ALIGNRP[ ]
+ CALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ LOOPCALL[ ]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ <TTGlyph name="zacute" xMin="74" yMin="0" xMax="950" yMax="1604">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="acute" x="257" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zcaron" xMin="74" yMin="0" xMax="950" yMax="1604">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="caron" x="174" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zdotaccent" xMin="74" yMin="0" xMax="950" yMax="1480">
+ <component glyphName="z" x="0" y="0" flags="0x4"/>
+ <component glyphName="dotaccent" x="168" y="0" flags="0x4"/>
+ </TTGlyph>
+
+ <TTGlyph name="zero" xMin="80" yMin="-37" xMax="1058" yMax="1517">
+ <contour>
+ <pt x="569" y="1517" on="1"/>
+ <pt x="794" y="1517" on="0"/>
+ <pt x="926" y="1309" on="1"/>
+ <pt x="1058" y="1101" on="0"/>
+ <pt x="1058" y="744" on="1"/>
+ <pt x="1058" y="378" on="0"/>
+ <pt x="926" y="171" on="1"/>
+ <pt x="794" y="-37" on="0"/>
+ <pt x="563" y="-37" on="1"/>
+ <pt x="365" y="-37" on="0"/>
+ <pt x="240" y="132" on="1"/>
+ <pt x="80" y="346" on="0"/>
+ <pt x="80" y="742" on="1"/>
+ <pt x="80" y="1101" on="0"/>
+ <pt x="212" y="1308" on="1"/>
+ <pt x="344" y="1517" on="0"/>
+ </contour>
+ <contour>
+ <pt x="569" y="1369" on="1"/>
+ <pt x="435" y="1369" on="0"/>
+ <pt x="363" y="1205" on="1"/>
+ <pt x="290" y="1040" on="0"/>
+ <pt x="290" y="741" on="1"/>
+ <pt x="290" y="444" on="0"/>
+ <pt x="363" y="277" on="1"/>
+ <pt x="435" y="111" on="0"/>
+ <pt x="570" y="111" on="1"/>
+ <pt x="692" y="111" on="0"/>
+ <pt x="759" y="233" on="1"/>
+ <pt x="849" y="395" on="0"/>
+ <pt x="849" y="743" on="1"/>
+ <pt x="849" y="1045" on="0"/>
+ <pt x="776" y="1206" on="1"/>
+ <pt x="701" y="1369" on="0"/>
+ </contour>
+ <instructions><assembly>
+ NPUSHB[ ] /* 27 values pushed */
+ 0 0 24 40 8 16 40 0 48 196 8 2 0 0 14 0 0 28 43 4 20 9 12 48 196
+ 12 4
+ MDAP[1]
+ MDAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ CALL[ ]
+ MIAP[1]
+ MIAP[1]
+ SSW[ ]
+ SSWCI[ ]
+ SRP0[ ]
+ MIRP[01101]
+ SRP0[ ]
+ MIRP[01101]
+ SSW[ ]
+ SSWCI[ ]
+ IUP[1]
+ IUP[0]
+ </assembly></instructions>
+ </TTGlyph>
+
+ </glyf>
+
+ <kern>
+ <version value="0"/>
+ <kernsubtable coverage="1" format="0">
+ <pair l="A" r="C" v="-76"/>
+ <pair l="A" r="Ccedilla" v="-80"/>
+ <pair l="A" r="G" v="-63"/>
+ <pair l="A" r="O" v="-67"/>
+ <pair l="A" r="Odieresis" v="-67"/>
+ <pair l="A" r="Q" v="-70"/>
+ <pair l="A" r="T" v="-178"/>
+ <pair l="A" r="U" v="-71"/>
+ <pair l="A" r="Uacute" v="-71"/>
+ <pair l="A" r="Ucircumflex" v="-71"/>
+ <pair l="A" r="Udieresis" v="-71"/>
+ <pair l="A" r="Ugrave" v="-71"/>
+ <pair l="A" r="V" v="-144"/>
+ <pair l="A" r="W" v="-90"/>
+ <pair l="A" r="Y" v="-185"/>
+ <pair l="A" r="a" v="-9"/>
+ <pair l="A" r="b" v="-4"/>
+ <pair l="A" r="c" v="-40"/>
+ <pair l="A" r="ccedilla" v="-41"/>
+ <pair l="A" r="comma" v="28"/>
+ <pair l="A" r="d" v="-32"/>
+ <pair l="A" r="e" v="-41"/>
+ <pair l="A" r="g" v="-46"/>
+ <pair l="A" r="guillemotleft" v="-76"/>
+ <pair l="A" r="guilsinglleft" v="-56"/>
+ <pair l="A" r="hyphen" v="-4"/>
+ <pair l="A" r="o" v="-36"/>
+ <pair l="A" r="period" v="27"/>
+ <pair l="A" r="q" v="-32"/>
+ <pair l="A" r="quotedblright" v="-117"/>
+ <pair l="A" r="quoteright" v="-130"/>
+ <pair l="A" r="t" v="-30"/>
+ <pair l="A" r="u" v="-29"/>
+ <pair l="A" r="v" v="-65"/>
+ <pair l="A" r="w" v="-29"/>
+ <pair l="A" r="y" v="-65"/>
+ <pair l="Aacute" r="C" v="-76"/>
+ <pair l="Aacute" r="G" v="-63"/>
+ <pair l="Aacute" r="O" v="-67"/>
+ <pair l="Aacute" r="Q" v="-70"/>
+ <pair l="Aacute" r="T" v="-178"/>
+ <pair l="Aacute" r="U" v="-71"/>
+ <pair l="Aacute" r="V" v="-144"/>
+ <pair l="Aacute" r="W" v="-90"/>
+ <pair l="Aacute" r="Y" v="-185"/>
+ <pair l="Aacute" r="a" v="-9"/>
+ <pair l="Aacute" r="b" v="-4"/>
+ <pair l="Aacute" r="c" v="-40"/>
+ <pair l="Aacute" r="comma" v="28"/>
+ <pair l="Aacute" r="d" v="-32"/>
+ <pair l="Aacute" r="e" v="-41"/>
+ <pair l="Aacute" r="g" v="-46"/>
+ <pair l="Aacute" r="guillemotleft" v="-76"/>
+ <pair l="Aacute" r="guilsinglleft" v="-56"/>
+ <pair l="Aacute" r="hyphen" v="-4"/>
+ <pair l="Aacute" r="o" v="-36"/>
+ <pair l="Aacute" r="period" v="27"/>
+ <pair l="Aacute" r="q" v="-32"/>
+ <pair l="Aacute" r="quoteright" v="-130"/>
+ <pair l="Aacute" r="t" v="-30"/>
+ <pair l="Aacute" r="u" v="-29"/>
+ <pair l="Aacute" r="v" v="-65"/>
+ <pair l="Aacute" r="w" v="-29"/>
+ <pair l="Aacute" r="y" v="-65"/>
+ <pair l="Acircumflex" r="C" v="-76"/>
+ <pair l="Acircumflex" r="G" v="-63"/>
+ <pair l="Acircumflex" r="O" v="-67"/>
+ <pair l="Acircumflex" r="Q" v="-70"/>
+ <pair l="Acircumflex" r="T" v="-178"/>
+ <pair l="Acircumflex" r="U" v="-71"/>
+ <pair l="Acircumflex" r="V" v="-144"/>
+ <pair l="Acircumflex" r="W" v="-90"/>
+ <pair l="Acircumflex" r="Y" v="-185"/>
+ <pair l="Acircumflex" r="comma" v="28"/>
+ <pair l="Acircumflex" r="period" v="27"/>
+ <pair l="Adieresis" r="C" v="-76"/>
+ <pair l="Adieresis" r="G" v="-63"/>
+ <pair l="Adieresis" r="O" v="-67"/>
+ <pair l="Adieresis" r="Q" v="-70"/>
+ <pair l="Adieresis" r="T" v="-178"/>
+ <pair l="Adieresis" r="U" v="-71"/>
+ <pair l="Adieresis" r="V" v="-144"/>
+ <pair l="Adieresis" r="W" v="-90"/>
+ <pair l="Adieresis" r="Y" v="-185"/>
+ <pair l="Adieresis" r="a" v="-9"/>
+ <pair l="Adieresis" r="b" v="-4"/>
+ <pair l="Adieresis" r="c" v="-40"/>
+ <pair l="Adieresis" r="comma" v="28"/>
+ <pair l="Adieresis" r="d" v="-32"/>
+ <pair l="Adieresis" r="g" v="-46"/>
+ <pair l="Adieresis" r="guillemotleft" v="-76"/>
+ <pair l="Adieresis" r="guilsinglleft" v="-56"/>
+ <pair l="Adieresis" r="hyphen" v="-4"/>
+ <pair l="Adieresis" r="o" v="-36"/>
+ <pair l="Adieresis" r="period" v="27"/>
+ <pair l="Adieresis" r="q" v="-32"/>
+ <pair l="Adieresis" r="quotedblright" v="-117"/>
+ <pair l="Adieresis" r="quoteright" v="-130"/>
+ <pair l="Adieresis" r="t" v="-30"/>
+ <pair l="Adieresis" r="u" v="-29"/>
+ <pair l="Adieresis" r="v" v="-65"/>
+ <pair l="Adieresis" r="w" v="-29"/>
+ <pair l="Adieresis" r="y" v="-65"/>
+ <pair l="Agrave" r="C" v="-76"/>
+ <pair l="Agrave" r="G" v="-63"/>
+ <pair l="Agrave" r="O" v="-67"/>
+ <pair l="Agrave" r="Q" v="-70"/>
+ <pair l="Agrave" r="T" v="-178"/>
+ <pair l="Agrave" r="U" v="-71"/>
+ <pair l="Agrave" r="V" v="-144"/>
+ <pair l="Agrave" r="W" v="-90"/>
+ <pair l="Agrave" r="Y" v="-185"/>
+ <pair l="Agrave" r="comma" v="28"/>
+ <pair l="Agrave" r="period" v="27"/>
+ <pair l="Aring" r="C" v="-76"/>
+ <pair l="Aring" r="G" v="-63"/>
+ <pair l="Aring" r="O" v="-67"/>
+ <pair l="Aring" r="Q" v="-70"/>
+ <pair l="Aring" r="T" v="-178"/>
+ <pair l="Aring" r="U" v="-71"/>
+ <pair l="Aring" r="V" v="-144"/>
+ <pair l="Aring" r="W" v="-90"/>
+ <pair l="Aring" r="Y" v="-185"/>
+ <pair l="Aring" r="a" v="-9"/>
+ <pair l="Aring" r="b" v="-4"/>
+ <pair l="Aring" r="c" v="-40"/>
+ <pair l="Aring" r="comma" v="28"/>
+ <pair l="Aring" r="d" v="-32"/>
+ <pair l="Aring" r="e" v="-41"/>
+ <pair l="Aring" r="g" v="-46"/>
+ <pair l="Aring" r="guillemotleft" v="-76"/>
+ <pair l="Aring" r="guilsinglleft" v="-56"/>
+ <pair l="Aring" r="hyphen" v="-4"/>
+ <pair l="Aring" r="o" v="-36"/>
+ <pair l="Aring" r="period" v="27"/>
+ <pair l="Aring" r="q" v="-32"/>
+ <pair l="Aring" r="quotedblright" v="-117"/>
+ <pair l="Aring" r="quoteright" v="-130"/>
+ <pair l="Aring" r="t" v="-30"/>
+ <pair l="Aring" r="u" v="-29"/>
+ <pair l="Aring" r="v" v="-65"/>
+ <pair l="Aring" r="w" v="-29"/>
+ <pair l="Aring" r="y" v="-65"/>
+ <pair l="Atilde" r="C" v="-76"/>
+ <pair l="Atilde" r="G" v="-63"/>
+ <pair l="Atilde" r="O" v="-67"/>
+ <pair l="Atilde" r="Q" v="-70"/>
+ <pair l="Atilde" r="T" v="-178"/>
+ <pair l="Atilde" r="U" v="-71"/>
+ <pair l="Atilde" r="V" v="-144"/>
+ <pair l="Atilde" r="W" v="-90"/>
+ <pair l="Atilde" r="Y" v="-185"/>
+ <pair l="Atilde" r="comma" v="28"/>
+ <pair l="Atilde" r="period" v="27"/>
+ <pair l="B" r="A" v="-39"/>
+ <pair l="B" r="AE" v="-61"/>
+ <pair l="B" r="Aacute" v="-39"/>
+ <pair l="B" r="Acircumflex" v="-39"/>
+ <pair l="B" r="Adieresis" v="-39"/>
+ <pair l="B" r="Aring" v="-39"/>
+ <pair l="B" r="Atilde" v="-39"/>
+ <pair l="B" r="O" v="-37"/>
+ <pair l="B" r="OE" v="-37"/>
+ <pair l="B" r="Oacute" v="-37"/>
+ <pair l="B" r="Ocircumflex" v="-37"/>
+ <pair l="B" r="Odieresis" v="-37"/>
+ <pair l="B" r="Ograve" v="-37"/>
+ <pair l="B" r="Oslash" v="-30"/>
+ <pair l="B" r="V" v="-69"/>
+ <pair l="B" r="W" v="-50"/>
+ <pair l="B" r="Y" v="-82"/>
+ <pair l="C" r="A" v="3"/>
+ <pair l="C" r="AE" v="-5"/>
+ <pair l="C" r="Aacute" v="3"/>
+ <pair l="C" r="Adieresis" v="3"/>
+ <pair l="C" r="Aring" v="3"/>
+ <pair l="C" r="H" v="-56"/>
+ <pair l="C" r="K" v="-69"/>
+ <pair l="C" r="O" v="-84"/>
+ <pair l="C" r="Oacute" v="-84"/>
+ <pair l="C" r="Odieresis" v="-84"/>
+ <pair l="Ccedilla" r="A" v="0"/>
+ <pair l="D" r="A" v="-72"/>
+ <pair l="D" r="Aacute" v="-72"/>
+ <pair l="D" r="Acircumflex" v="-72"/>
+ <pair l="D" r="Adieresis" v="-72"/>
+ <pair l="D" r="Agrave" v="-72"/>
+ <pair l="D" r="Aring" v="-72"/>
+ <pair l="D" r="Atilde" v="-72"/>
+ <pair l="D" r="J" v="-247"/>
+ <pair l="D" r="T" v="-63"/>
+ <pair l="D" r="V" v="-69"/>
+ <pair l="D" r="W" v="-33"/>
+ <pair l="D" r="X" v="-87"/>
+ <pair l="D" r="Y" v="-100"/>
+ <pair l="F" r="A" v="-122"/>
+ <pair l="F" r="Aacute" v="-122"/>
+ <pair l="F" r="Acircumflex" v="-122"/>
+ <pair l="F" r="Adieresis" v="-122"/>
+ <pair l="F" r="Agrave" v="-122"/>
+ <pair l="F" r="Aring" v="-122"/>
+ <pair l="F" r="Atilde" v="-122"/>
+ <pair l="F" r="J" v="-251"/>
+ <pair l="F" r="O" v="-33"/>
+ <pair l="F" r="Odieresis" v="-32"/>
+ <pair l="F" r="a" v="-102"/>
+ <pair l="F" r="aacute" v="-102"/>
+ <pair l="F" r="adieresis" v="-77"/>
+ <pair l="F" r="ae" v="-102"/>
+ <pair l="F" r="aring" v="-102"/>
+ <pair l="F" r="comma" v="-189"/>
+ <pair l="F" r="e" v="-35"/>
+ <pair l="F" r="eacute" v="-35"/>
+ <pair l="F" r="hyphen" v="4"/>
+ <pair l="F" r="i" v="-4"/>
+ <pair l="F" r="j" v="-6"/>
+ <pair l="F" r="o" v="-35"/>
+ <pair l="F" r="oacute" v="-35"/>
+ <pair l="F" r="odieresis" v="-35"/>
+ <pair l="F" r="oe" v="-36"/>
+ <pair l="F" r="oslash" v="-64"/>
+ <pair l="F" r="period" v="-190"/>
+ <pair l="F" r="r" v="-66"/>
+ <pair l="F" r="u" v="-60"/>
+ <pair l="G" r="A" v="-20"/>
+ <pair l="G" r="AE" v="-24"/>
+ <pair l="G" r="Aacute" v="-20"/>
+ <pair l="G" r="Acircumflex" v="-20"/>
+ <pair l="G" r="Adieresis" v="-20"/>
+ <pair l="G" r="Agrave" v="-20"/>
+ <pair l="G" r="Aring" v="-20"/>
+ <pair l="G" r="Atilde" v="-20"/>
+ <pair l="G" r="T" v="-14"/>
+ <pair l="G" r="V" v="-29"/>
+ <pair l="G" r="W" v="-22"/>
+ <pair l="G" r="Y" v="-30"/>
+ <pair l="J" r="A" v="-23"/>
+ <pair l="J" r="AE" v="-24"/>
+ <pair l="J" r="Adieresis" v="-23"/>
+ <pair l="J" r="Aring" v="-23"/>
+ <pair l="K" r="C" v="-148"/>
+ <pair l="K" r="G" v="-138"/>
+ <pair l="K" r="O" v="-140"/>
+ <pair l="K" r="OE" v="-139"/>
+ <pair l="K" r="Oacute" v="-139"/>
+ <pair l="K" r="Odieresis" v="-139"/>
+ <pair l="K" r="S" v="-8"/>
+ <pair l="K" r="T" v="3"/>
+ <pair l="K" r="a" v="-46"/>
+ <pair l="K" r="adieresis" v="-46"/>
+ <pair l="K" r="ae" v="-46"/>
+ <pair l="K" r="aring" v="-46"/>
+ <pair l="K" r="e" v="-105"/>
+ <pair l="K" r="hyphen" v="-173"/>
+ <pair l="K" r="o" v="-94"/>
+ <pair l="K" r="oacute" v="-94"/>
+ <pair l="K" r="odieresis" v="-94"/>
+ <pair l="K" r="u" v="-63"/>
+ <pair l="K" r="udieresis" v="-63"/>
+ <pair l="K" r="y" v="-138"/>
+ <pair l="L" r="A" v="60"/>
+ <pair l="L" r="AE" v="59"/>
+ <pair l="L" r="Aacute" v="60"/>
+ <pair l="L" r="Adieresis" v="60"/>
+ <pair l="L" r="Aring" v="60"/>
+ <pair l="L" r="C" v="-76"/>
+ <pair l="L" r="Ccedilla" v="-84"/>
+ <pair l="L" r="G" v="-65"/>
+ <pair l="L" r="O" v="-71"/>
+ <pair l="L" r="Oacute" v="-70"/>
+ <pair l="L" r="Ocircumflex" v="-70"/>
+ <pair l="L" r="Odieresis" v="-70"/>
+ <pair l="L" r="Ograve" v="-70"/>
+ <pair l="L" r="Otilde" v="-70"/>
+ <pair l="L" r="S" v="11"/>
+ <pair l="L" r="T" v="-188"/>
+ <pair l="L" r="U" v="-54"/>
+ <pair l="L" r="Udieresis" v="-54"/>
+ <pair l="L" r="V" v="-198"/>
+ <pair l="L" r="W" v="-108"/>
+ <pair l="L" r="Y" v="-208"/>
+ <pair l="L" r="hyphen" v="-259"/>
+ <pair l="L" r="quotedblright" v="-260"/>
+ <pair l="L" r="quoteright" v="-277"/>
+ <pair l="L" r="u" v="-9"/>
+ <pair l="L" r="udieresis" v="-9"/>
+ <pair l="L" r="y" v="-102"/>
+ <pair l="N" r="A" v="-4"/>
+ <pair l="N" r="AE" v="-5"/>
+ <pair l="N" r="Aacute" v="-4"/>
+ <pair l="N" r="Adieresis" v="-4"/>
+ <pair l="N" r="Aring" v="-4"/>
+ <pair l="N" r="C" v="-11"/>
+ <pair l="N" r="Ccedilla" v="-11"/>
+ <pair l="N" r="G" v="0"/>
+ <pair l="N" r="O" v="-2"/>
+ <pair l="N" r="Oacute" v="-1"/>
+ <pair l="N" r="Odieresis" v="-1"/>
+ <pair l="N" r="a" v="-24"/>
+ <pair l="N" r="aacute" v="-24"/>
+ <pair l="N" r="adieresis" v="-24"/>
+ <pair l="N" r="ae" v="-25"/>
+ <pair l="N" r="aring" v="-24"/>
+ <pair l="N" r="comma" v="-1"/>
+ <pair l="N" r="e" v="-5"/>
+ <pair l="N" r="eacute" v="-5"/>
+ <pair l="N" r="o" v="-2"/>
+ <pair l="N" r="oacute" v="-2"/>
+ <pair l="N" r="odieresis" v="-2"/>
+ <pair l="N" r="oslash" v="-25"/>
+ <pair l="N" r="period" v="-2"/>
+ <pair l="N" r="u" v="-3"/>
+ <pair l="N" r="udieresis" v="-3"/>
+ <pair l="O" r="A" v="-66"/>
+ <pair l="O" r="AE" v="-106"/>
+ <pair l="O" r="Aacute" v="-66"/>
+ <pair l="O" r="Adieresis" v="-66"/>
+ <pair l="O" r="Aring" v="-66"/>
+ <pair l="O" r="T" v="-66"/>
+ <pair l="O" r="V" v="-72"/>
+ <pair l="O" r="W" v="-31"/>
+ <pair l="O" r="X" v="-84"/>
+ <pair l="O" r="Y" v="-106"/>
+ <pair l="Oacute" r="A" v="-66"/>
+ <pair l="Oacute" r="T" v="-67"/>
+ <pair l="Oacute" r="V" v="-73"/>
+ <pair l="Oacute" r="W" v="-32"/>
+ <pair l="Oacute" r="Y" v="-107"/>
+ <pair l="Ocircumflex" r="T" v="-67"/>
+ <pair l="Ocircumflex" r="V" v="-73"/>
+ <pair l="Ocircumflex" r="Y" v="-107"/>
+ <pair l="Odieresis" r="A" v="-66"/>
+ <pair l="Odieresis" r="T" v="-67"/>
+ <pair l="Odieresis" r="V" v="-73"/>
+ <pair l="Odieresis" r="W" v="-32"/>
+ <pair l="Odieresis" r="X" v="-84"/>
+ <pair l="Odieresis" r="Y" v="-107"/>
+ <pair l="Ograve" r="T" v="-67"/>
+ <pair l="Ograve" r="V" v="-73"/>
+ <pair l="Ograve" r="Y" v="-107"/>
+ <pair l="Oslash" r="A" v="-65"/>
+ <pair l="Otilde" r="T" v="-67"/>
+ <pair l="Otilde" r="V" v="-73"/>
+ <pair l="Otilde" r="Y" v="-107"/>
+ <pair l="P" r="A" v="-125"/>
+ <pair l="P" r="AE" v="-226"/>
+ <pair l="P" r="Aacute" v="-125"/>
+ <pair l="P" r="Adieresis" v="-125"/>
+ <pair l="P" r="Aring" v="-125"/>
+ <pair l="P" r="J" v="-249"/>
+ <pair l="P" r="a" v="-32"/>
+ <pair l="P" r="aacute" v="-32"/>
+ <pair l="P" r="adieresis" v="-32"/>
+ <pair l="P" r="ae" v="-32"/>
+ <pair l="P" r="aring" v="-32"/>
+ <pair l="P" r="comma" v="-226"/>
+ <pair l="P" r="e" v="-29"/>
+ <pair l="P" r="eacute" v="-29"/>
+ <pair l="P" r="hyphen" v="-27"/>
+ <pair l="P" r="o" v="-30"/>
+ <pair l="P" r="oacute" v="-30"/>
+ <pair l="P" r="odieresis" v="-30"/>
+ <pair l="P" r="oe" v="-32"/>
+ <pair l="P" r="oslash" v="-58"/>
+ <pair l="P" r="period" v="-227"/>
+ <pair l="R" r="C" v="-87"/>
+ <pair l="R" r="Ccedilla" v="-87"/>
+ <pair l="R" r="G" v="-76"/>
+ <pair l="R" r="O" v="-78"/>
+ <pair l="R" r="OE" v="-77"/>
+ <pair l="R" r="Oacute" v="-78"/>
+ <pair l="R" r="Odieresis" v="-78"/>
+ <pair l="R" r="T" v="-64"/>
+ <pair l="R" r="U" v="-75"/>
+ <pair l="R" r="Udieresis" v="-75"/>
+ <pair l="R" r="V" v="-97"/>
+ <pair l="R" r="W" v="-78"/>
+ <pair l="R" r="Y" v="-112"/>
+ <pair l="R" r="a" v="-39"/>
+ <pair l="R" r="aacute" v="-39"/>
+ <pair l="R" r="adieresis" v="-39"/>
+ <pair l="R" r="ae" v="-37"/>
+ <pair l="R" r="aring" v="-39"/>
+ <pair l="R" r="e" v="-82"/>
+ <pair l="R" r="eacute" v="-82"/>
+ <pair l="R" r="hyphen" v="-98"/>
+ <pair l="R" r="o" v="-77"/>
+ <pair l="R" r="oacute" v="-77"/>
+ <pair l="R" r="odieresis" v="-77"/>
+ <pair l="R" r="oe" v="-81"/>
+ <pair l="R" r="u" v="-56"/>
+ <pair l="R" r="uacute" v="-56"/>
+ <pair l="R" r="udieresis" v="-56"/>
+ <pair l="R" r="y" v="-44"/>
+ <pair l="S" r="A" v="-36"/>
+ <pair l="S" r="AE" v="-60"/>
+ <pair l="S" r="Aacute" v="-36"/>
+ <pair l="S" r="Adieresis" v="-36"/>
+ <pair l="S" r="Aring" v="-36"/>
+ <pair l="S" r="T" v="-27"/>
+ <pair l="S" r="V" v="-42"/>
+ <pair l="S" r="W" v="-35"/>
+ <pair l="S" r="Y" v="-43"/>
+ <pair l="S" r="t" v="-48"/>
+ <pair l="T" r="A" v="-180"/>
+ <pair l="T" r="AE" v="-182"/>
+ <pair l="T" r="Aacute" v="-180"/>
+ <pair l="T" r="Acircumflex" v="-180"/>
+ <pair l="T" r="Adieresis" v="-180"/>
+ <pair l="T" r="Agrave" v="-180"/>
+ <pair l="T" r="Aring" v="-180"/>
+ <pair l="T" r="Atilde" v="-180"/>
+ <pair l="T" r="C" v="-75"/>
+ <pair l="T" r="G" v="-66"/>
+ <pair l="T" r="J" v="-235"/>
+ <pair l="T" r="O" v="-66"/>
+ <pair l="T" r="OE" v="-65"/>
+ <pair l="T" r="Oacute" v="-66"/>
+ <pair l="T" r="Ocircumflex" v="-66"/>
+ <pair l="T" r="Odieresis" v="-66"/>
+ <pair l="T" r="Ograve" v="-66"/>
+ <pair l="T" r="Oslash" v="-66"/>
+ <pair l="T" r="Otilde" v="-66"/>
+ <pair l="T" r="S" v="-5"/>
+ <pair l="T" r="V" v="58"/>
+ <pair l="T" r="W" v="65"/>
+ <pair l="T" r="Y" v="59"/>
+ <pair l="T" r="a" v="-211"/>
+ <pair l="T" r="ae" v="-211"/>
+ <pair l="T" r="c" v="-191"/>
+ <pair l="T" r="colon" v="-238"/>
+ <pair l="T" r="comma" v="-179"/>
+ <pair l="T" r="e" v="-192"/>
+ <pair l="T" r="g" v="-196"/>
+ <pair l="T" r="guillemotleft" v="-227"/>
+ <pair l="T" r="guilsinglleft" v="-206"/>
+ <pair l="T" r="hyphen" v="-140"/>
+ <pair l="T" r="i" v="12"/>
+ <pair l="T" r="j" v="9"/>
+ <pair l="T" r="o" v="-188"/>
+ <pair l="T" r="oslash" v="-208"/>
+ <pair l="T" r="period" v="-180"/>
+ <pair l="T" r="r" v="-183"/>
+ <pair l="T" r="s" v="-216"/>
+ <pair l="T" r="semicolon" v="-229"/>
+ <pair l="T" r="u" v="-182"/>
+ <pair l="T" r="v" v="-184"/>
+ <pair l="T" r="w" v="-175"/>
+ <pair l="T" r="y" v="-184"/>
+ <pair l="U" r="A" v="-64"/>
+ <pair l="U" r="AE" v="-89"/>
+ <pair l="U" r="Aacute" v="-64"/>
+ <pair l="U" r="Acircumflex" v="-64"/>
+ <pair l="U" r="Adieresis" v="-64"/>
+ <pair l="U" r="Aring" v="-64"/>
+ <pair l="U" r="Atilde" v="-64"/>
+ <pair l="U" r="comma" v="-37"/>
+ <pair l="U" r="m" v="-15"/>
+ <pair l="U" r="n" v="-15"/>
+ <pair l="U" r="p" v="-15"/>
+ <pair l="U" r="period" v="-33"/>
+ <pair l="U" r="r" v="-15"/>
+ <pair l="Uacute" r="A" v="-64"/>
+ <pair l="Uacute" r="comma" v="-37"/>
+ <pair l="Uacute" r="m" v="-15"/>
+ <pair l="Uacute" r="n" v="-15"/>
+ <pair l="Uacute" r="p" v="-15"/>
+ <pair l="Uacute" r="period" v="-33"/>
+ <pair l="Uacute" r="r" v="-15"/>
+ <pair l="Ucircumflex" r="A" v="-64"/>
+ <pair l="Udieresis" r="A" v="-64"/>
+ <pair l="Udieresis" r="b" v="-14"/>
+ <pair l="Udieresis" r="comma" v="-37"/>
+ <pair l="Udieresis" r="m" v="-15"/>
+ <pair l="Udieresis" r="n" v="-15"/>
+ <pair l="Udieresis" r="p" v="-15"/>
+ <pair l="Udieresis" r="period" v="-33"/>
+ <pair l="Udieresis" r="r" v="-15"/>
+ <pair l="Ugrave" r="A" v="-64"/>
+ <pair l="V" r="A" v="-125"/>
+ <pair l="V" r="AE" v="-200"/>
+ <pair l="V" r="Aacute" v="-125"/>
+ <pair l="V" r="Acircumflex" v="-125"/>
+ <pair l="V" r="Adieresis" v="-125"/>
+ <pair l="V" r="Agrave" v="-125"/>
+ <pair l="V" r="Aring" v="-125"/>
+ <pair l="V" r="Atilde" v="-125"/>
+ <pair l="V" r="C" v="-67"/>
+ <pair l="V" r="G" v="-58"/>
+ <pair l="V" r="O" v="-58"/>
+ <pair l="V" r="Oacute" v="-57"/>
+ <pair l="V" r="Ocircumflex" v="-57"/>
+ <pair l="V" r="Odieresis" v="-57"/>
+ <pair l="V" r="Ograve" v="-57"/>
+ <pair l="V" r="Oslash" v="-58"/>
+ <pair l="V" r="Otilde" v="-57"/>
+ <pair l="V" r="S" v="-23"/>
+ <pair l="V" r="T" v="74"/>
+ <pair l="V" r="a" v="-96"/>
+ <pair l="V" r="ae" v="-96"/>
+ <pair l="V" r="colon" v="-83"/>
+ <pair l="V" r="comma" v="-153"/>
+ <pair l="V" r="e" v="-101"/>
+ <pair l="V" r="g" v="-100"/>
+ <pair l="V" r="guillemotleft" v="-142"/>
+ <pair l="V" r="guilsinglleft" v="-122"/>
+ <pair l="V" r="hyphen" v="-48"/>
+ <pair l="V" r="i" v="16"/>
+ <pair l="V" r="o" v="-101"/>
+ <pair l="V" r="oslash" v="-124"/>
+ <pair l="V" r="period" v="-154"/>
+ <pair l="V" r="r" v="-66"/>
+ <pair l="V" r="semicolon" v="-79"/>
+ <pair l="V" r="u" v="-64"/>
+ <pair l="V" r="y" v="-4"/>
+ <pair l="W" r="A" v="-100"/>
+ <pair l="W" r="AE" v="-142"/>
+ <pair l="W" r="Aacute" v="-100"/>
+ <pair l="W" r="Acircumflex" v="-100"/>
+ <pair l="W" r="Adieresis" v="-100"/>
+ <pair l="W" r="Agrave" v="-100"/>
+ <pair l="W" r="Aring" v="-100"/>
+ <pair l="W" r="Atilde" v="-100"/>
+ <pair l="W" r="C" v="-50"/>
+ <pair l="W" r="G" v="-39"/>
+ <pair l="W" r="O" v="-41"/>
+ <pair l="W" r="Oacute" v="-40"/>
+ <pair l="W" r="Ocircumflex" v="-40"/>
+ <pair l="W" r="Odieresis" v="-40"/>
+ <pair l="W" r="Ograve" v="-40"/>
+ <pair l="W" r="Oslash" v="-34"/>
+ <pair l="W" r="Otilde" v="-40"/>
+ <pair l="W" r="S" v="-23"/>
+ <pair l="W" r="T" v="65"/>
+ <pair l="W" r="a" v="-84"/>
+ <pair l="W" r="ae" v="-84"/>
+ <pair l="W" r="colon" v="-73"/>
+ <pair l="W" r="comma" v="-106"/>
+ <pair l="W" r="e" v="-72"/>
+ <pair l="W" r="g" v="-75"/>
+ <pair l="W" r="guillemotleft" v="-109"/>
+ <pair l="W" r="guilsinglleft" v="-89"/>
+ <pair l="W" r="hyphen" v="-17"/>
+ <pair l="W" r="i" v="8"/>
+ <pair l="W" r="o" v="-69"/>
+ <pair l="W" r="oslash" v="-91"/>
+ <pair l="W" r="period" v="-107"/>
+ <pair l="W" r="r" v="-57"/>
+ <pair l="W" r="semicolon" v="-70"/>
+ <pair l="W" r="u" v="-54"/>
+ <pair l="W" r="y" v="4"/>
+ <pair l="X" r="C" v="-89"/>
+ <pair l="X" r="O" v="-81"/>
+ <pair l="X" r="Odieresis" v="-80"/>
+ <pair l="X" r="Q" v="-81"/>
+ <pair l="X" r="a" v="-30"/>
+ <pair l="X" r="e" v="-83"/>
+ <pair l="X" r="hyphen" v="-105"/>
+ <pair l="X" r="o" v="-73"/>
+ <pair l="X" r="u" v="-47"/>
+ <pair l="X" r="y" v="-94"/>
+ <pair l="Y" r="A" v="-197"/>
+ <pair l="Y" r="AE" v="-219"/>
+ <pair l="Y" r="Aacute" v="-197"/>
+ <pair l="Y" r="Acircumflex" v="-197"/>
+ <pair l="Y" r="Adieresis" v="-197"/>
+ <pair l="Y" r="Agrave" v="-197"/>
+ <pair l="Y" r="Aring" v="-197"/>
+ <pair l="Y" r="Atilde" v="-197"/>
+ <pair l="Y" r="C" v="-118"/>
+ <pair l="Y" r="G" v="-111"/>
+ <pair l="Y" r="O" v="-110"/>
+ <pair l="Y" r="Oacute" v="-109"/>
+ <pair l="Y" r="Ocircumflex" v="-109"/>
+ <pair l="Y" r="Odieresis" v="-109"/>
+ <pair l="Y" r="Ograve" v="-109"/>
+ <pair l="Y" r="Oslash" v="-110"/>
+ <pair l="Y" r="Otilde" v="-109"/>
+ <pair l="Y" r="S" v="-55"/>
+ <pair l="Y" r="T" v="65"/>
+ <pair l="Y" r="a" v="-167"/>
+ <pair l="Y" r="ae" v="-167"/>
+ <pair l="Y" r="colon" v="-150"/>
+ <pair l="Y" r="comma" v="-216"/>
+ <pair l="Y" r="e" v="-193"/>
+ <pair l="Y" r="g" v="-191"/>
+ <pair l="Y" r="guillemotleft" v="-258"/>
+ <pair l="Y" r="guilsinglleft" v="-238"/>
+ <pair l="Y" r="hyphen" v="-166"/>
+ <pair l="Y" r="i" v="7"/>
+ <pair l="Y" r="o" v="-189"/>
+ <pair l="Y" r="oslash" v="-211"/>
+ <pair l="Y" r="p" v="-130"/>
+ <pair l="Y" r="period" v="-217"/>
+ <pair l="Y" r="semicolon" v="-143"/>
+ <pair l="Y" r="u" v="-131"/>
+ <pair l="Y" r="v" v="-72"/>
+ <pair l="Z" r="v" v="-60"/>
+ <pair l="Z" r="y" v="-60"/>
+ <pair l="a" r="j" v="-2"/>
+ <pair l="a" r="quoteright" v="-45"/>
+ <pair l="a" r="v" v="-55"/>
+ <pair l="a" r="w" v="-22"/>
+ <pair l="a" r="y" v="-55"/>
+ <pair l="aacute" r="v" v="-55"/>
+ <pair l="aacute" r="w" v="-22"/>
+ <pair l="aacute" r="y" v="-55"/>
+ <pair l="adieresis" r="v" v="-55"/>
+ <pair l="adieresis" r="w" v="-22"/>
+ <pair l="adieresis" r="y" v="-55"/>
+ <pair l="ae" r="v" v="-42"/>
+ <pair l="ae" r="w" v="-26"/>
+ <pair l="ae" r="y" v="-42"/>
+ <pair l="agrave" r="v" v="-55"/>
+ <pair l="agrave" r="w" v="-22"/>
+ <pair l="agrave" r="y" v="-55"/>
+ <pair l="aring" r="v" v="-55"/>
+ <pair l="aring" r="w" v="-22"/>
+ <pair l="aring" r="y" v="-55"/>
+ <pair l="b" r="v" v="-28"/>
+ <pair l="b" r="w" v="0"/>
+ <pair l="b" r="y" v="-28"/>
+ <pair l="c" r="h" v="-41"/>
+ <pair l="c" r="k" v="-41"/>
+ <pair l="comma" r="one" v="-104"/>
+ <pair l="comma" r="quotedblright" v="-54"/>
+ <pair l="comma" r="quoteright" v="-67"/>
+ <pair l="e" r="quoteright" v="-27"/>
+ <pair l="e" r="t" v="-29"/>
+ <pair l="e" r="v" v="-41"/>
+ <pair l="e" r="w" v="-24"/>
+ <pair l="e" r="x" v="-2"/>
+ <pair l="e" r="y" v="-41"/>
+ <pair l="eacute" r="v" v="-41"/>
+ <pair l="eacute" r="w" v="-24"/>
+ <pair l="eacute" r="y" v="-41"/>
+ <pair l="ecircumflex" r="v" v="-41"/>
+ <pair l="ecircumflex" r="w" v="-24"/>
+ <pair l="ecircumflex" r="y" v="-41"/>
+ <pair l="eight" r="four" v="48"/>
+ <pair l="eight" r="one" v="-80"/>
+ <pair l="eight" r="seven" v="-36"/>
+ <pair l="f" r="a" v="-10"/>
+ <pair l="f" r="aacute" v="-10"/>
+ <pair l="f" r="adieresis" v="-10"/>
+ <pair l="f" r="ae" v="-10"/>
+ <pair l="f" r="aring" v="-10"/>
+ <pair l="f" r="e" v="-12"/>
+ <pair l="f" r="eacute" v="-12"/>
+ <pair l="f" r="f" v="68"/>
+ <pair l="f" r="i" v="50"/>
+ <pair l="f" r="j" v="48"/>
+ <pair l="f" r="l" v="50"/>
+ <pair l="f" r="o" v="-11"/>
+ <pair l="f" r="oacute" v="-11"/>
+ <pair l="f" r="odieresis" v="-11"/>
+ <pair l="f" r="oe" v="-16"/>
+ <pair l="f" r="oslash" v="-40"/>
+ <pair l="f" r="quoteright" v="60"/>
+ <pair l="f" r="s" v="14"/>
+ <pair l="f" r="t" v="69"/>
+ <pair l="five" r="four" v="-11"/>
+ <pair l="five" r="one" v="-125"/>
+ <pair l="five" r="seven" v="-79"/>
+ <pair l="four" r="four" v="41"/>
+ <pair l="four" r="one" v="-157"/>
+ <pair l="four" r="seven" v="-110"/>
+ <pair l="g" r="a" v="-27"/>
+ <pair l="g" r="adieresis" v="-27"/>
+ <pair l="g" r="ae" v="-27"/>
+ <pair l="g" r="aring" v="-27"/>
+ <pair l="g" r="e" v="-7"/>
+ <pair l="g" r="eacute" v="-7"/>
+ <pair l="g" r="l" v="3"/>
+ <pair l="g" r="oacute" v="-4"/>
+ <pair l="g" r="odieresis" v="-4"/>
+ <pair l="g" r="r" v="-9"/>
+ <pair l="guillemotright" r="A" v="-75"/>
+ <pair l="guillemotright" r="AE" v="-142"/>
+ <pair l="guillemotright" r="Aacute" v="-75"/>
+ <pair l="guillemotright" r="Adieresis" v="-75"/>
+ <pair l="guillemotright" r="Aring" v="-75"/>
+ <pair l="guillemotright" r="T" v="-226"/>
+ <pair l="guillemotright" r="V" v="-162"/>
+ <pair l="guillemotright" r="W" v="-97"/>
+ <pair l="guillemotright" r="Y" v="-242"/>
+ <pair l="guilsinglright" r="A" v="-54"/>
+ <pair l="guilsinglright" r="AE" v="-120"/>
+ <pair l="guilsinglright" r="Aacute" v="-54"/>
+ <pair l="guilsinglright" r="Adieresis" v="-54"/>
+ <pair l="guilsinglright" r="Aring" v="-54"/>
+ <pair l="guilsinglright" r="T" v="-205"/>
+ <pair l="guilsinglright" r="V" v="-140"/>
+ <pair l="guilsinglright" r="W" v="-75"/>
+ <pair l="guilsinglright" r="Y" v="-221"/>
+ <pair l="h" r="quoteright" v="-11"/>
+ <pair l="h" r="y" v="-29"/>
+ <pair l="hyphen" r="A" v="-2"/>
+ <pair l="hyphen" r="AE" v="-79"/>
+ <pair l="hyphen" r="Aacute" v="-2"/>
+ <pair l="hyphen" r="Adieresis" v="-2"/>
+ <pair l="hyphen" r="Aring" v="-2"/>
+ <pair l="hyphen" r="T" v="-139"/>
+ <pair l="hyphen" r="V" v="-65"/>
+ <pair l="hyphen" r="W" v="-4"/>
+ <pair l="hyphen" r="Y" v="-148"/>
+ <pair l="i" r="T" v="14"/>
+ <pair l="i" r="j" v="12"/>
+ <pair l="k" r="a" v="-31"/>
+ <pair l="k" r="aacute" v="-31"/>
+ <pair l="k" r="adieresis" v="-31"/>
+ <pair l="k" r="ae" v="-29"/>
+ <pair l="k" r="aring" v="-31"/>
+ <pair l="k" r="comma" v="-5"/>
+ <pair l="k" r="e" v="-76"/>
+ <pair l="k" r="eacute" v="-76"/>
+ <pair l="k" r="g" v="-81"/>
+ <pair l="k" r="hyphen" v="-102"/>
+ <pair l="k" r="o" v="-71"/>
+ <pair l="k" r="oacute" v="-71"/>
+ <pair l="k" r="odieresis" v="-71"/>
+ <pair l="k" r="period" v="-5"/>
+ <pair l="k" r="s" v="5"/>
+ <pair l="k" r="u" v="-46"/>
+ <pair l="k" r="udieresis" v="-46"/>
+ <pair l="l" r="v" v="9"/>
+ <pair l="l" r="y" v="9"/>
+ <pair l="m" r="p" v="-9"/>
+ <pair l="m" r="v" v="-29"/>
+ <pair l="m" r="w" v="-1"/>
+ <pair l="m" r="y" v="-29"/>
+ <pair l="n" r="T" v="-182"/>
+ <pair l="n" r="p" v="-8"/>
+ <pair l="n" r="quoteright" v="-11"/>
+ <pair l="n" r="v" v="-29"/>
+ <pair l="n" r="w" v="0"/>
+ <pair l="n" r="y" v="-29"/>
+ <pair l="nine" r="four" v="12"/>
+ <pair l="nine" r="one" v="-121"/>
+ <pair l="nine" r="seven" v="-84"/>
+ <pair l="o" r="T" v="-188"/>
+ <pair l="o" r="quoteright" v="-23"/>
+ <pair l="o" r="t" v="-9"/>
+ <pair l="o" r="v" v="-33"/>
+ <pair l="o" r="w" v="-3"/>
+ <pair l="o" r="x" v="-41"/>
+ <pair l="o" r="y" v="-33"/>
+ <pair l="oacute" r="v" v="-33"/>
+ <pair l="oacute" r="w" v="-3"/>
+ <pair l="oacute" r="y" v="-33"/>
+ <pair l="ocircumflex" r="t" v="-9"/>
+ <pair l="odieresis" r="t" v="-9"/>
+ <pair l="odieresis" r="v" v="-33"/>
+ <pair l="odieresis" r="w" v="-3"/>
+ <pair l="odieresis" r="x" v="-41"/>
+ <pair l="odieresis" r="y" v="-33"/>
+ <pair l="ograve" r="v" v="-33"/>
+ <pair l="ograve" r="w" v="-3"/>
+ <pair l="ograve" r="y" v="-33"/>
+ <pair l="one" r="comma" v="-48"/>
+ <pair l="one" r="eight" v="-50"/>
+ <pair l="one" r="five" v="-49"/>
+ <pair l="one" r="four" v="-111"/>
+ <pair l="one" r="nine" v="-50"/>
+ <pair l="one" r="one" v="-83"/>
+ <pair l="one" r="period" v="-48"/>
+ <pair l="one" r="seven" v="-80"/>
+ <pair l="one" r="six" v="-76"/>
+ <pair l="one" r="three" v="-44"/>
+ <pair l="one" r="two" v="-19"/>
+ <pair l="one" r="zero" v="-81"/>
+ <pair l="p" r="t" v="-5"/>
+ <pair l="p" r="y" v="-28"/>
+ <pair l="period" r="one" v="-104"/>
+ <pair l="period" r="quotedblright" v="-56"/>
+ <pair l="period" r="quoteright" v="-69"/>
+ <pair l="q" r="c" v="-10"/>
+ <pair l="q" r="u" v="-8"/>
+ <pair l="quotedblbase" r="A" v="75"/>
+ <pair l="quotedblbase" r="AE" v="47"/>
+ <pair l="quotedblbase" r="T" v="-134"/>
+ <pair l="quotedblbase" r="V" v="-130"/>
+ <pair l="quotedblbase" r="W" v="-46"/>
+ <pair l="quotedblbase" r="Y" v="-155"/>
+ <pair l="quotedblleft" r="A" v="-118"/>
+ <pair l="quotedblleft" r="AE" v="-274"/>
+ <pair l="quotedblleft" r="Aacute" v="-118"/>
+ <pair l="quotedblleft" r="Adieresis" v="-118"/>
+ <pair l="quotedblleft" r="Aring" v="-118"/>
+ <pair l="quotedblleft" r="T" v="32"/>
+ <pair l="quotedblleft" r="V" v="54"/>
+ <pair l="quotedblleft" r="W" v="75"/>
+ <pair l="quotedblleft" r="Y" v="29"/>
+ <pair l="quotedblright" r="A" v="-115"/>
+ <pair l="quotedblright" r="AE" v="-270"/>
+ <pair l="quotedblright" r="Aacute" v="-115"/>
+ <pair l="quotedblright" r="Adieresis" v="-115"/>
+ <pair l="quotedblright" r="Aring" v="-115"/>
+ <pair l="quotedblright" r="T" v="52"/>
+ <pair l="quotedblright" r="V" v="64"/>
+ <pair l="quotedblright" r="W" v="84"/>
+ <pair l="quotedblright" r="Y" v="42"/>
+ <pair l="quoteleft" r="A" v="-131"/>
+ <pair l="quoteleft" r="AE" v="-282"/>
+ <pair l="quoteleft" r="Aacute" v="-131"/>
+ <pair l="quoteleft" r="Adieresis" v="-131"/>
+ <pair l="quoteleft" r="Aring" v="-131"/>
+ <pair l="quoteleft" r="T" v="15"/>
+ <pair l="quoteleft" r="V" v="34"/>
+ <pair l="quoteleft" r="W" v="56"/>
+ <pair l="quoteleft" r="Y" v="7"/>
+ <pair l="quoteright" r="A" v="-127"/>
+ <pair l="quoteright" r="AE" v="-279"/>
+ <pair l="quoteright" r="Aacute" v="-127"/>
+ <pair l="quoteright" r="Adieresis" v="-127"/>
+ <pair l="quoteright" r="Aring" v="-127"/>
+ <pair l="quoteright" r="comma" v="-81"/>
+ <pair l="quoteright" r="d" v="-41"/>
+ <pair l="quoteright" r="o" v="-37"/>
+ <pair l="quoteright" r="period" v="-83"/>
+ <pair l="quoteright" r="r" v="-16"/>
+ <pair l="quoteright" r="s" v="-19"/>
+ <pair l="quoteright" r="t" v="15"/>
+ <pair l="quoteright" r="v" v="22"/>
+ <pair l="quoteright" r="w" v="35"/>
+ <pair l="quoteright" r="y" v="22"/>
+ <pair l="r" r="a" v="-16"/>
+ <pair l="r" r="aacute" v="-16"/>
+ <pair l="r" r="acircumflex" v="-16"/>
+ <pair l="r" r="adieresis" v="-16"/>
+ <pair l="r" r="ae" v="-16"/>
+ <pair l="r" r="agrave" v="-16"/>
+ <pair l="r" r="aring" v="-16"/>
+ <pair l="r" r="c" v="-13"/>
+ <pair l="r" r="ccedilla" v="-7"/>
+ <pair l="r" r="colon" v="-11"/>
+ <pair l="r" r="comma" v="-100"/>
+ <pair l="r" r="d" v="-13"/>
+ <pair l="r" r="e" v="-11"/>
+ <pair l="r" r="eacute" v="-11"/>
+ <pair l="r" r="ecircumflex" v="-11"/>
+ <pair l="r" r="egrave" v="-11"/>
+ <pair l="r" r="f" v="62"/>
+ <pair l="r" r="g" v="-5"/>
+ <pair l="r" r="h" v="1"/>
+ <pair l="r" r="hyphen" v="-64"/>
+ <pair l="r" r="i" v="13"/>
+ <pair l="r" r="j" v="11"/>
+ <pair l="r" r="k" v="1"/>
+ <pair l="r" r="l" v="13"/>
+ <pair l="r" r="m" v="1"/>
+ <pair l="r" r="n" v="1"/>
+ <pair l="r" r="o" v="-10"/>
+ <pair l="r" r="oacute" v="-10"/>
+ <pair l="r" r="ocircumflex" v="-10"/>
+ <pair l="r" r="odieresis" v="-10"/>
+ <pair l="r" r="oe" v="-14"/>
+ <pair l="r" r="ograve" v="-10"/>
+ <pair l="r" r="oslash" v="-39"/>
+ <pair l="r" r="p" v="1"/>
+ <pair l="r" r="period" v="-101"/>
+ <pair l="r" r="q" v="-13"/>
+ <pair l="r" r="quoteright" v="31"/>
+ <pair l="r" r="r" v="1"/>
+ <pair l="r" r="s" v="11"/>
+ <pair l="r" r="semicolon" v="-11"/>
+ <pair l="r" r="t" v="63"/>
+ <pair l="r" r="u" v="7"/>
+ <pair l="r" r="v" v="66"/>
+ <pair l="r" r="w" v="71"/>
+ <pair l="r" r="x" v="55"/>
+ <pair l="r" r="y" v="66"/>
+ <pair l="r" r="z" v="26"/>
+ <pair l="s" r="quoteright" v="-69"/>
+ <pair l="s" r="t" v="-29"/>
+ <pair l="seven" r="colon" v="-103"/>
+ <pair l="seven" r="comma" v="-230"/>
+ <pair l="seven" r="eight" v="-34"/>
+ <pair l="seven" r="five" v="-29"/>
+ <pair l="seven" r="four" v="-164"/>
+ <pair l="seven" r="one" v="-50"/>
+ <pair l="seven" r="period" v="-231"/>
+ <pair l="seven" r="seven" v="-3"/>
+ <pair l="seven" r="six" v="-46"/>
+ <pair l="seven" r="three" v="-22"/>
+ <pair l="seven" r="two" v="-5"/>
+ <pair l="six" r="four" v="18"/>
+ <pair l="six" r="one" v="-120"/>
+ <pair l="six" r="seven" v="-73"/>
+ <pair l="t" r="S" v="19"/>
+ <pair l="t" r="a" v="-1"/>
+ <pair l="t" r="aacute" v="-1"/>
+ <pair l="t" r="adieresis" v="-1"/>
+ <pair l="t" r="ae" v="0"/>
+ <pair l="t" r="aring" v="-1"/>
+ <pair l="t" r="colon" v="-9"/>
+ <pair l="t" r="e" v="-16"/>
+ <pair l="t" r="eacute" v="-16"/>
+ <pair l="t" r="h" v="3"/>
+ <pair l="t" r="o" v="-15"/>
+ <pair l="t" r="oacute" v="-15"/>
+ <pair l="t" r="odieresis" v="-15"/>
+ <pair l="t" r="quoteright" v="30"/>
+ <pair l="t" r="semicolon" v="-9"/>
+ <pair l="three" r="four" v="-11"/>
+ <pair l="three" r="one" v="-137"/>
+ <pair l="three" r="seven" v="-94"/>
+ <pair l="two" r="four" v="-145"/>
+ <pair l="two" r="one" v="-126"/>
+ <pair l="two" r="seven" v="-91"/>
+ <pair l="u" r="quoteright" v="0"/>
+ <pair l="v" r="a" v="-26"/>
+ <pair l="v" r="aacute" v="-26"/>
+ <pair l="v" r="acircumflex" v="-26"/>
+ <pair l="v" r="adieresis" v="-26"/>
+ <pair l="v" r="ae" v="-26"/>
+ <pair l="v" r="agrave" v="-26"/>
+ <pair l="v" r="aring" v="-26"/>
+ <pair l="v" r="atilde" v="-26"/>
+ <pair l="v" r="c" v="-35"/>
+ <pair l="v" r="colon" v="-11"/>
+ <pair l="v" r="comma" v="-112"/>
+ <pair l="v" r="e" v="-32"/>
+ <pair l="v" r="eacute" v="-32"/>
+ <pair l="v" r="ecircumflex" v="-32"/>
+ <pair l="v" r="egrave" v="-32"/>
+ <pair l="v" r="g" v="-31"/>
+ <pair l="v" r="hyphen" v="2"/>
+ <pair l="v" r="l" v="14"/>
+ <pair l="v" r="o" v="-33"/>
+ <pair l="v" r="oacute" v="-33"/>
+ <pair l="v" r="odieresis" v="-33"/>
+ <pair l="v" r="ograve" v="-33"/>
+ <pair l="v" r="oslash" v="-61"/>
+ <pair l="v" r="period" v="-113"/>
+ <pair l="v" r="s" v="-17"/>
+ <pair l="v" r="semicolon" v="-11"/>
+ <pair l="w" r="a" v="-25"/>
+ <pair l="w" r="aacute" v="-25"/>
+ <pair l="w" r="acircumflex" v="-25"/>
+ <pair l="w" r="adieresis" v="-25"/>
+ <pair l="w" r="ae" v="-25"/>
+ <pair l="w" r="agrave" v="-25"/>
+ <pair l="w" r="aring" v="-25"/>
+ <pair l="w" r="atilde" v="-25"/>
+ <pair l="w" r="c" v="-18"/>
+ <pair l="w" r="colon" v="-13"/>
+ <pair l="w" r="comma" v="-70"/>
+ <pair l="w" r="e" v="-19"/>
+ <pair l="w" r="eacute" v="-19"/>
+ <pair l="w" r="ecircumflex" v="-19"/>
+ <pair l="w" r="egrave" v="-19"/>
+ <pair l="w" r="g" v="-21"/>
+ <pair l="w" r="hyphen" v="23"/>
+ <pair l="w" r="l" v="12"/>
+ <pair l="w" r="o" v="-15"/>
+ <pair l="w" r="oacute" v="-15"/>
+ <pair l="w" r="odieresis" v="-15"/>
+ <pair l="w" r="ograve" v="-15"/>
+ <pair l="w" r="oslash" v="-38"/>
+ <pair l="w" r="period" v="-71"/>
+ <pair l="w" r="s" v="-12"/>
+ <pair l="w" r="semicolon" v="-13"/>
+ <pair l="x" r="a" v="-32"/>
+ <pair l="x" r="c" v="-49"/>
+ <pair l="x" r="e" v="-50"/>
+ <pair l="x" r="eacute" v="-50"/>
+ <pair l="x" r="o" v="-45"/>
+ <pair l="x" r="q" v="-43"/>
+ <pair l="y" r="a" v="-26"/>
+ <pair l="y" r="aacute" v="-26"/>
+ <pair l="y" r="acircumflex" v="-26"/>
+ <pair l="y" r="adieresis" v="-26"/>
+ <pair l="y" r="ae" v="-26"/>
+ <pair l="y" r="agrave" v="-26"/>
+ <pair l="y" r="aring" v="-26"/>
+ <pair l="y" r="atilde" v="-26"/>
+ <pair l="y" r="c" v="-36"/>
+ <pair l="y" r="colon" v="-11"/>
+ <pair l="y" r="comma" v="-116"/>
+ <pair l="y" r="e" v="-33"/>
+ <pair l="y" r="eacute" v="-33"/>
+ <pair l="y" r="ecircumflex" v="-33"/>
+ <pair l="y" r="egrave" v="-33"/>
+ <pair l="y" r="g" v="-32"/>
+ <pair l="y" r="hyphen" v="0"/>
+ <pair l="y" r="l" v="14"/>
+ <pair l="y" r="o" v="-35"/>
+ <pair l="y" r="oacute" v="-35"/>
+ <pair l="y" r="odieresis" v="-35"/>
+ <pair l="y" r="ograve" v="-35"/>
+ <pair l="y" r="oslash" v="-62"/>
+ <pair l="y" r="period" v="-117"/>
+ <pair l="y" r="s" v="-17"/>
+ <pair l="y" r="semicolon" v="-11"/>
+ <pair l="zero" r="four" v="30"/>
+ <pair l="zero" r="one" v="-111"/>
+ <pair l="zero" r="seven" v="-73"/>
+ </kernsubtable>
+ </kern>
+
+ <name>
+ <namerecord nameID="0" platformID="1" platEncID="0" langID="0x0">
+ Copyright (c) 2001 by Bigelow &amp; Holmes Inc. Instructions copyright (c) 2001 by URW++.
+ </namerecord>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0">
+ Luxi Sans
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0">
+ Regular
+ </namerecord>
+ <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0">
+ Luxi Sans Regular: B&amp;H
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0">
+ Luxi Sans Regular
+ </namerecord>
+ <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0">
+ 1.2 : October 12, 2001
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0">
+ LuxiSans
+ </namerecord>
+ <namerecord nameID="7" platformID="1" platEncID="0" langID="0x0">
+ Luxi is a registered trademark of Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="8" platformID="1" platEncID="0" langID="0x0">
+ Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="9" platformID="1" platEncID="0" langID="0x0">
+ Kris Holmes and Charles Bigelow
+ </namerecord>
+ <namerecord nameID="11" platformID="1" platEncID="0" langID="0x0">
+ http://www.urwpp.de
+ </namerecord>
+ <namerecord nameID="12" platformID="1" platEncID="0" langID="0x0">
+ design@bigelowandholmes.com
+ </namerecord>
+ <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409">
+ Copyright (c) 2001 by Bigelow &amp; Holmes Inc. Instructions copyright (c) 2001 by URW++.
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Luxi Sans
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409">
+ Luxi Sans Regular: B&amp;H
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Luxi Sans Regular
+ </namerecord>
+ <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
+ 1.2 : October 12, 2001
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ LuxiSans
+ </namerecord>
+ <namerecord nameID="7" platformID="3" platEncID="1" langID="0x409">
+ Luxi is a registered trademark of Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="8" platformID="3" platEncID="1" langID="0x409">
+ Bigelow &amp; Holmes Inc.
+ </namerecord>
+ <namerecord nameID="9" platformID="3" platEncID="1" langID="0x409">
+ Kris Holmes and Charles Bigelow
+ </namerecord>
+ <namerecord nameID="11" platformID="3" platEncID="1" langID="0x409">
+ http://www.urwpp.de
+ </namerecord>
+ <namerecord nameID="12" platformID="3" platEncID="1" langID="0x409">
+ design@bigelowandholmes.com
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="2.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="0"/>
+ <underlineThickness value="0"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ <psNames>
+ <!-- This file uses unique glyph names based on the information
+ found in the 'post' table. Since these names might not be unique,
+ we have to invent artificial names in case of clashes. In order to
+ be able to retain the original information, we need a name to
+ ps name mapping for those cases where they differ. That's what
+ you see below.
+ -->
+ <psName name=".notdef#1" psName=".notdef"/>
+ <psName name=".notdef#10" psName=".notdef"/>
+ <psName name=".notdef#11" psName=".notdef"/>
+ <psName name=".notdef#12" psName=".notdef"/>
+ <psName name=".notdef#13" psName=".notdef"/>
+ <psName name=".notdef#14" psName=".notdef"/>
+ <psName name=".notdef#15" psName=".notdef"/>
+ <psName name=".notdef#16" psName=".notdef"/>
+ <psName name=".notdef#17" psName=".notdef"/>
+ <psName name=".notdef#18" psName=".notdef"/>
+ <psName name=".notdef#2" psName=".notdef"/>
+ <psName name=".notdef#3" psName=".notdef"/>
+ <psName name=".notdef#4" psName=".notdef"/>
+ <psName name=".notdef#5" psName=".notdef"/>
+ <psName name=".notdef#6" psName=".notdef"/>
+ <psName name=".notdef#7" psName=".notdef"/>
+ <psName name=".notdef#8" psName=".notdef"/>
+ <psName name=".notdef#9" psName=".notdef"/>
+ <psName name="Euro#1" psName="Euro"/>
+ <psName name="fi#1" psName="fi"/>
+ <psName name="fl#1" psName="fl"/>
+ <psName name="fraction#1" psName="fraction"/>
+ <psName name="hyphen#1" psName="hyphen"/>
+ <psName name="macron#1" psName="macron"/>
+ <psName name="periodcentered#1" psName="periodcentered"/>
+ <psName name="semicolon#1" psName="semicolon"/>
+ </psNames>
+ <extraNames>
+ <!-- following are the name that are not taken from the standard Mac glyph order -->
+ <psName name="fraction"/>
+ <psName name="fi"/>
+ <psName name="Euro"/>
+ <psName name="tilde"/>
+ <psName name="macron"/>
+ <psName name="Euro"/>
+ <psName name="sfthyphen"/>
+ <psName name="periodcentered"/>
+ <psName name="Amacron"/>
+ <psName name="amacron"/>
+ <psName name="Abreve"/>
+ <psName name="abreve"/>
+ <psName name="Aogonek"/>
+ <psName name="aogonek"/>
+ <psName name="Ccircumflex"/>
+ <psName name="ccircumflex"/>
+ <psName name="Cdotaccent"/>
+ <psName name="cdotaccent"/>
+ <psName name="Dcaron"/>
+ <psName name="dcaron"/>
+ <psName name="Dcroat"/>
+ <psName name="dcroat"/>
+ <psName name="Emacron"/>
+ <psName name="emacron"/>
+ <psName name="Ebreve"/>
+ <psName name="ebreve"/>
+ <psName name="Edotaccent"/>
+ <psName name="edotaccent"/>
+ <psName name="Eogonek"/>
+ <psName name="eogonek"/>
+ <psName name="Ecaron"/>
+ <psName name="ecaron"/>
+ <psName name="Gcircumflex"/>
+ <psName name="gcircumflex"/>
+ <psName name="Gdotaccent"/>
+ <psName name="gdotaccent"/>
+ <psName name="Gcommaaccent"/>
+ <psName name="gcommaaccent"/>
+ <psName name="Hcircumflex"/>
+ <psName name="hcircumflex"/>
+ <psName name="Hbar"/>
+ <psName name="hbar"/>
+ <psName name="Itilde"/>
+ <psName name="itilde"/>
+ <psName name="Imacron"/>
+ <psName name="imacron"/>
+ <psName name="Ibreve"/>
+ <psName name="ibreve"/>
+ <psName name="Iogonek"/>
+ <psName name="iogonek"/>
+ <psName name="IJ"/>
+ <psName name="ij"/>
+ <psName name="Jcircumflex"/>
+ <psName name="jcircumflex"/>
+ <psName name="Kcommaaccent"/>
+ <psName name="kcommaaccent"/>
+ <psName name="kgreenlandic"/>
+ <psName name="Lacute"/>
+ <psName name="lacute"/>
+ <psName name="Lcommaaccent"/>
+ <psName name="lcommaaccent"/>
+ <psName name="Lcaron"/>
+ <psName name="lcaron"/>
+ <psName name="Ldot"/>
+ <psName name="ldot"/>
+ <psName name="Nacute"/>
+ <psName name="nacute"/>
+ <psName name="Ncommaaccent"/>
+ <psName name="ncommaaccent"/>
+ <psName name="Ncaron"/>
+ <psName name="ncaron"/>
+ <psName name="napostrophe"/>
+ <psName name="Eng"/>
+ <psName name="eng"/>
+ <psName name="Omacron"/>
+ <psName name="omacron"/>
+ <psName name="Obreve"/>
+ <psName name="obreve"/>
+ <psName name="Ohungarumlaut"/>
+ <psName name="ohungarumlaut"/>
+ <psName name="Racute"/>
+ <psName name="racute"/>
+ <psName name="Rcommaaccent"/>
+ <psName name="rcommaaccent"/>
+ <psName name="Rcaron"/>
+ <psName name="rcaron"/>
+ <psName name="Sacute"/>
+ <psName name="sacute"/>
+ <psName name="Scircumflex"/>
+ <psName name="scircumflex"/>
+ <psName name="Tcommaaccent"/>
+ <psName name="tcommaaccent"/>
+ <psName name="Tcaron"/>
+ <psName name="tcaron"/>
+ <psName name="Tbar"/>
+ <psName name="tbar"/>
+ <psName name="Utilde"/>
+ <psName name="utilde"/>
+ <psName name="Umacron"/>
+ <psName name="umacron"/>
+ <psName name="Ubreve"/>
+ <psName name="ubreve"/>
+ <psName name="Uring"/>
+ <psName name="uring"/>
+ <psName name="Uhungarumlaut"/>
+ <psName name="uhungarumlaut"/>
+ <psName name="Uogonek"/>
+ <psName name="uogonek"/>
+ <psName name="Wcircumflex"/>
+ <psName name="wcircumflex"/>
+ <psName name="Ycircumflex"/>
+ <psName name="ycircumflex"/>
+ <psName name="Zacute"/>
+ <psName name="zacute"/>
+ <psName name="Zdotaccent"/>
+ <psName name="zdotaccent"/>
+ <psName name="longs"/>
+ <psName name="Scommaaccent"/>
+ <psName name="scommaaccent"/>
+ <psName name="Tcommabelow"/>
+ <psName name="tcommabelow"/>
+ <psName name="Unterkomma"/>
+ <psName name="semicolon"/>
+ <psName name="anoteleia"/>
+ <psName name="hyphen"/>
+ <psName name="nbhyphen"/>
+ <psName name="figuredash"/>
+ <psName name="afii00208"/>
+ <psName name="quotereversed"/>
+ <psName name="radicalex"/>
+ <psName name="estimated"/>
+ <psName name="dotmath"/>
+ <psName name="fi"/>
+ <psName name="fl"/>
+ <psName name="foursuperiour"/>
+ <psName name="dotlessj"/>
+ </extraNames>
+ </post>
+
+ <gasp>
+ <gaspRange rangeMaxPPEM="8" rangeGaspBehavior="2"/>
+ <gaspRange rangeMaxPPEM="16" rangeGaspBehavior="1"/>
+ <gaspRange rangeMaxPPEM="65535" rangeGaspBehavior="3"/>
+ </gasp>
+
+ <vhea>
+ <tableVersion value="1.0"/>
+ <ascent value="2033"/>
+ <descent value="432"/>
+ <lineGap value="0"/>
+ <advanceHeightMax value="2465"/>
+ <minTopSideBearing value="0"/>
+ <minBottomSideBearing value="0"/>
+ <yMaxExtent value="2465"/>
+ <caretSlopeRise value="0"/>
+ <caretSlopeRun value="1"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <reserved4 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfVMetrics value="391"/>
+ </vhea>
+
+ <vmtx>
+ <mtx name=".notdef" height="2465" tsb="553"/>
+ <mtx name=".notdef#1" height="0" tsb="0"/>
+ <mtx name=".notdef#10" height="2465" tsb="0"/>
+ <mtx name=".notdef#11" height="2465" tsb="0"/>
+ <mtx name=".notdef#12" height="2465" tsb="0"/>
+ <mtx name=".notdef#13" height="2465" tsb="0"/>
+ <mtx name=".notdef#14" height="2465" tsb="0"/>
+ <mtx name=".notdef#15" height="2465" tsb="0"/>
+ <mtx name=".notdef#16" height="1139" tsb="0"/>
+ <mtx name=".notdef#17" height="2465" tsb="0"/>
+ <mtx name=".notdef#18" height="2465" tsb="0"/>
+ <mtx name=".notdef#2" height="2465" tsb="0"/>
+ <mtx name=".notdef#3" height="2465" tsb="0"/>
+ <mtx name=".notdef#4" height="2465" tsb="0"/>
+ <mtx name=".notdef#5" height="2465" tsb="0"/>
+ <mtx name=".notdef#6" height="2465" tsb="0"/>
+ <mtx name=".notdef#7" height="2465" tsb="0"/>
+ <mtx name=".notdef#8" height="2465" tsb="0"/>
+ <mtx name=".notdef#9" height="2465" tsb="0"/>
+ <mtx name="A" height="2465" tsb="553"/>
+ <mtx name="AE" height="2465" tsb="553"/>
+ <mtx name="Aacute" height="2465" tsb="108"/>
+ <mtx name="Abreve" height="2465" tsb="108"/>
+ <mtx name="Acircumflex" height="2465" tsb="108"/>
+ <mtx name="Adieresis" height="2465" tsb="256"/>
+ <mtx name="Agrave" height="2465" tsb="108"/>
+ <mtx name="Amacron" height="2465" tsb="281"/>
+ <mtx name="Aogonek" height="2465" tsb="553"/>
+ <mtx name="Aring" height="2465" tsb="98"/>
+ <mtx name="Atilde" height="2465" tsb="195"/>
+ <mtx name="B" height="2465" tsb="553"/>
+ <mtx name="C" height="2465" tsb="516"/>
+ <mtx name="Cacute" height="2465" tsb="108"/>
+ <mtx name="Ccaron" height="2465" tsb="108"/>
+ <mtx name="Ccedilla" height="2465" tsb="516"/>
+ <mtx name="Ccircumflex" height="2465" tsb="108"/>
+ <mtx name="Cdotaccent" height="2465" tsb="232"/>
+ <mtx name="D" height="2465" tsb="553"/>
+ <mtx name="Dcaron" height="2465" tsb="108"/>
+ <mtx name="Dcroat" height="2465" tsb="553"/>
+ <mtx name="E" height="2465" tsb="553"/>
+ <mtx name="Eacute" height="2465" tsb="108"/>
+ <mtx name="Ebreve" height="2465" tsb="108"/>
+ <mtx name="Ecaron" height="2465" tsb="108"/>
+ <mtx name="Ecircumflex" height="2465" tsb="108"/>
+ <mtx name="Edieresis" height="2465" tsb="256"/>
+ <mtx name="Edotaccent" height="2465" tsb="232"/>
+ <mtx name="Egrave" height="2465" tsb="108"/>
+ <mtx name="Emacron" height="2465" tsb="281"/>
+ <mtx name="Eng" height="2465" tsb="553"/>
+ <mtx name="Eogonek" height="2465" tsb="553"/>
+ <mtx name="Eth" height="2465" tsb="553"/>
+ <mtx name="Euro" height="2465" tsb="518"/>
+ <mtx name="Euro#1" height="2465" tsb="518"/>
+ <mtx name="F" height="2465" tsb="553"/>
+ <mtx name="G" height="2465" tsb="516"/>
+ <mtx name="Gbreve" height="2465" tsb="108"/>
+ <mtx name="Gcircumflex" height="2465" tsb="108"/>
+ <mtx name="Gcommaaccent" height="2465" tsb="516"/>
+ <mtx name="Gdotaccent" height="2465" tsb="232"/>
+ <mtx name="H" height="2465" tsb="553"/>
+ <mtx name="Hbar" height="2465" tsb="553"/>
+ <mtx name="Hcircumflex" height="2465" tsb="108"/>
+ <mtx name="I" height="2465" tsb="553"/>
+ <mtx name="IJ" height="2465" tsb="553"/>
+ <mtx name="Iacute" height="2465" tsb="108"/>
+ <mtx name="Ibreve" height="2465" tsb="108"/>
+ <mtx name="Icircumflex" height="2465" tsb="108"/>
+ <mtx name="Idieresis" height="2465" tsb="256"/>
+ <mtx name="Idotaccent" height="2465" tsb="232"/>
+ <mtx name="Igrave" height="2465" tsb="108"/>
+ <mtx name="Imacron" height="2465" tsb="281"/>
+ <mtx name="Iogonek" height="2465" tsb="553"/>
+ <mtx name="Itilde" height="2465" tsb="195"/>
+ <mtx name="J" height="2465" tsb="553"/>
+ <mtx name="Jcircumflex" height="2465" tsb="108"/>
+ <mtx name="K" height="2465" tsb="553"/>
+ <mtx name="Kcommaaccent" height="2465" tsb="553"/>
+ <mtx name="L" height="2465" tsb="553"/>
+ <mtx name="Lacute" height="2465" tsb="108"/>
+ <mtx name="Lcaron" height="2465" tsb="553"/>
+ <mtx name="Lcommaaccent" height="2465" tsb="553"/>
+ <mtx name="Ldot" height="2465" tsb="553"/>
+ <mtx name="Lslash" height="2465" tsb="553"/>
+ <mtx name="M" height="2465" tsb="553"/>
+ <mtx name="N" height="2465" tsb="553"/>
+ <mtx name="Nacute" height="2465" tsb="108"/>
+ <mtx name="Ncaron" height="2465" tsb="108"/>
+ <mtx name="Ncommaaccent" height="2465" tsb="553"/>
+ <mtx name="Ntilde" height="2465" tsb="195"/>
+ <mtx name="O" height="2465" tsb="516"/>
+ <mtx name="OE" height="2465" tsb="516"/>
+ <mtx name="Oacute" height="2465" tsb="108"/>
+ <mtx name="Obreve" height="2465" tsb="108"/>
+ <mtx name="Ocircumflex" height="2465" tsb="108"/>
+ <mtx name="Odieresis" height="2465" tsb="256"/>
+ <mtx name="Ograve" height="2465" tsb="108"/>
+ <mtx name="Ohungarumlaut" height="2465" tsb="108"/>
+ <mtx name="Omacron" height="2465" tsb="281"/>
+ <mtx name="Oslash" height="2465" tsb="516"/>
+ <mtx name="Otilde" height="2465" tsb="195"/>
+ <mtx name="P" height="2465" tsb="553"/>
+ <mtx name="Q" height="2465" tsb="516"/>
+ <mtx name="R" height="2465" tsb="553"/>
+ <mtx name="Racute" height="2465" tsb="108"/>
+ <mtx name="Rcaron" height="2465" tsb="108"/>
+ <mtx name="Rcommaaccent" height="2465" tsb="553"/>
+ <mtx name="S" height="2465" tsb="516"/>
+ <mtx name="Sacute" height="2465" tsb="108"/>
+ <mtx name="Scaron" height="2465" tsb="108"/>
+ <mtx name="Scedilla" height="2465" tsb="516"/>
+ <mtx name="Scircumflex" height="2465" tsb="108"/>
+ <mtx name="Scommaaccent" height="2465" tsb="516"/>
+ <mtx name="T" height="2465" tsb="553"/>
+ <mtx name="Tbar" height="2465" tsb="553"/>
+ <mtx name="Tcaron" height="2465" tsb="108"/>
+ <mtx name="Tcommaaccent" height="2465" tsb="553"/>
+ <mtx name="Tcommabelow" height="2465" tsb="553"/>
+ <mtx name="Thorn" height="2465" tsb="553"/>
+ <mtx name="U" height="2465" tsb="553"/>
+ <mtx name="Uacute" height="2465" tsb="108"/>
+ <mtx name="Ubreve" height="2465" tsb="108"/>
+ <mtx name="Ucircumflex" height="2465" tsb="108"/>
+ <mtx name="Udieresis" height="2465" tsb="256"/>
+ <mtx name="Ugrave" height="2465" tsb="108"/>
+ <mtx name="Uhungarumlaut" height="2465" tsb="108"/>
+ <mtx name="Umacron" height="2465" tsb="281"/>
+ <mtx name="Unterkomma" height="2465" tsb="2144"/>
+ <mtx name="Uogonek" height="2465" tsb="553"/>
+ <mtx name="Uring" height="2465" tsb="0"/>
+ <mtx name="Utilde" height="2465" tsb="195"/>
+ <mtx name="V" height="2465" tsb="553"/>
+ <mtx name="W" height="2465" tsb="553"/>
+ <mtx name="Wcircumflex" height="2465" tsb="108"/>
+ <mtx name="X" height="2465" tsb="553"/>
+ <mtx name="Y" height="2465" tsb="553"/>
+ <mtx name="Yacute" height="2465" tsb="108"/>
+ <mtx name="Ycircumflex" height="2465" tsb="108"/>
+ <mtx name="Ydieresis" height="2465" tsb="256"/>
+ <mtx name="Z" height="2465" tsb="553"/>
+ <mtx name="Zacute" height="2465" tsb="108"/>
+ <mtx name="Zcaron" height="2465" tsb="108"/>
+ <mtx name="Zdotaccent" height="2465" tsb="232"/>
+ <mtx name="a" height="2465" tsb="923"/>
+ <mtx name="aacute" height="2465" tsb="429"/>
+ <mtx name="abreve" height="2465" tsb="429"/>
+ <mtx name="acircumflex" height="2465" tsb="429"/>
+ <mtx name="acute" height="2465" tsb="429"/>
+ <mtx name="adieresis" height="2465" tsb="577"/>
+ <mtx name="ae" height="2465" tsb="923"/>
+ <mtx name="afii00208" height="2465" tsb="1391"/>
+ <mtx name="agrave" height="2465" tsb="429"/>
+ <mtx name="amacron" height="2465" tsb="602"/>
+ <mtx name="ampersand" height="2465" tsb="516"/>
+ <mtx name="anoteleia" height="2465" tsb="1295"/>
+ <mtx name="aogonek" height="2465" tsb="923"/>
+ <mtx name="aring" height="2465" tsb="296"/>
+ <mtx name="asciicircum" height="2465" tsb="553"/>
+ <mtx name="asciitilde" height="2465" tsb="1261"/>
+ <mtx name="asterisk" height="2465" tsb="553"/>
+ <mtx name="at" height="2465" tsb="516"/>
+ <mtx name="atilde" height="2465" tsb="516"/>
+ <mtx name="b" height="2465" tsb="454"/>
+ <mtx name="backslash" height="2465" tsb="553"/>
+ <mtx name="bar" height="2465" tsb="454"/>
+ <mtx name="braceleft" height="2465" tsb="454"/>
+ <mtx name="braceright" height="2465" tsb="454"/>
+ <mtx name="bracketleft" height="2465" tsb="454"/>
+ <mtx name="bracketright" height="2465" tsb="454"/>
+ <mtx name="breve" height="2465" tsb="429"/>
+ <mtx name="brokenbar" height="2465" tsb="454"/>
+ <mtx name="bullet" height="2465" tsb="923"/>
+ <mtx name="c" height="2465" tsb="923"/>
+ <mtx name="cacute" height="2465" tsb="429"/>
+ <mtx name="caron" height="2465" tsb="429"/>
+ <mtx name="ccaron" height="2465" tsb="429"/>
+ <mtx name="ccedilla" height="2465" tsb="923"/>
+ <mtx name="ccircumflex" height="2465" tsb="429"/>
+ <mtx name="cdotaccent" height="2465" tsb="553"/>
+ <mtx name="cedilla" height="2465" tsb="2033"/>
+ <mtx name="cent" height="2465" tsb="553"/>
+ <mtx name="circumflex" height="2465" tsb="429"/>
+ <mtx name="colon" height="2465" tsb="947"/>
+ <mtx name="comma" height="2465" tsb="1786"/>
+ <mtx name="copyright" height="2465" tsb="553"/>
+ <mtx name="currency" height="2465" tsb="845"/>
+ <mtx name="d" height="2465" tsb="454"/>
+ <mtx name="dagger" height="2465" tsb="553"/>
+ <mtx name="daggerdbl" height="2465" tsb="553"/>
+ <mtx name="dcaron" height="2465" tsb="454"/>
+ <mtx name="dcroat" height="2465" tsb="454"/>
+ <mtx name="degree" height="2465" tsb="516"/>
+ <mtx name="dieresis" height="2465" tsb="577"/>
+ <mtx name="divide" height="2465" tsb="849"/>
+ <mtx name="dollar" height="2465" tsb="429"/>
+ <mtx name="dotaccent" height="2465" tsb="553"/>
+ <mtx name="dotlessi" height="2465" tsb="947"/>
+ <mtx name="dotlessj" height="2465" tsb="947"/>
+ <mtx name="dotmath" height="2465" tsb="1295"/>
+ <mtx name="e" height="2465" tsb="923"/>
+ <mtx name="eacute" height="2465" tsb="429"/>
+ <mtx name="ebreve" height="2465" tsb="429"/>
+ <mtx name="ecaron" height="2465" tsb="429"/>
+ <mtx name="ecircumflex" height="2465" tsb="429"/>
+ <mtx name="edieresis" height="2465" tsb="577"/>
+ <mtx name="edotaccent" height="2465" tsb="553"/>
+ <mtx name="egrave" height="2465" tsb="429"/>
+ <mtx name="eight" height="2465" tsb="516"/>
+ <mtx name="ellipsis" height="2465" tsb="1836"/>
+ <mtx name="emacron" height="2465" tsb="602"/>
+ <mtx name="emdash" height="2465" tsb="1391"/>
+ <mtx name="endash" height="2465" tsb="1367"/>
+ <mtx name="eng" height="2465" tsb="923"/>
+ <mtx name="eogonek" height="2465" tsb="923"/>
+ <mtx name="equal" height="2465" tsb="1182"/>
+ <mtx name="estimated" height="2465" tsb="923"/>
+ <mtx name="eth" height="2465" tsb="357"/>
+ <mtx name="exclam" height="2465" tsb="553"/>
+ <mtx name="exclamdown" height="2465" tsb="947"/>
+ <mtx name="f" height="2465" tsb="429"/>
+ <mtx name="fi" height="2465" tsb="429"/>
+ <mtx name="fi#1" height="2465" tsb="429"/>
+ <mtx name="figuredash" height="2465" tsb="1367"/>
+ <mtx name="five" height="2465" tsb="553"/>
+ <mtx name="fl" height="2465" tsb="429"/>
+ <mtx name="fl#1" height="2465" tsb="429"/>
+ <mtx name="florin" height="2465" tsb="516"/>
+ <mtx name="four" height="2465" tsb="553"/>
+ <mtx name="foursuperiour" height="2465" tsb="553"/>
+ <mtx name="fraction" height="2465" tsb="516"/>
+ <mtx name="fraction#1" height="2465" tsb="516"/>
+ <mtx name="g" height="2465" tsb="923"/>
+ <mtx name="gbreve" height="2465" tsb="429"/>
+ <mtx name="gcircumflex" height="2465" tsb="429"/>
+ <mtx name="gcommaaccent" height="2465" tsb="296"/>
+ <mtx name="gdotaccent" height="2465" tsb="553"/>
+ <mtx name="germandbls" height="2465" tsb="429"/>
+ <mtx name="grave" height="2465" tsb="429"/>
+ <mtx name="greater" height="2465" tsb="947"/>
+ <mtx name="guillemotleft" height="2465" tsb="1046"/>
+ <mtx name="guillemotright" height="2465" tsb="1046"/>
+ <mtx name="guilsinglleft" height="2465" tsb="1046"/>
+ <mtx name="guilsinglright" height="2465" tsb="1046"/>
+ <mtx name="h" height="2465" tsb="454"/>
+ <mtx name="hbar" height="2465" tsb="454"/>
+ <mtx name="hcircumflex" height="2465" tsb="34"/>
+ <mtx name="hungarumlaut" height="2465" tsb="429"/>
+ <mtx name="hyphen" height="2465" tsb="1367"/>
+ <mtx name="hyphen#1" height="2465" tsb="1367"/>
+ <mtx name="i" height="2465" tsb="553"/>
+ <mtx name="iacute" height="2465" tsb="429"/>
+ <mtx name="ibreve" height="2465" tsb="429"/>
+ <mtx name="icircumflex" height="2465" tsb="429"/>
+ <mtx name="idieresis" height="2465" tsb="577"/>
+ <mtx name="igrave" height="2465" tsb="429"/>
+ <mtx name="ij" height="2465" tsb="553"/>
+ <mtx name="imacron" height="2465" tsb="602"/>
+ <mtx name="iogonek" height="2465" tsb="553"/>
+ <mtx name="itilde" height="2465" tsb="516"/>
+ <mtx name="j" height="2465" tsb="553"/>
+ <mtx name="jcircumflex" height="2465" tsb="429"/>
+ <mtx name="k" height="2465" tsb="454"/>
+ <mtx name="kcommaaccent" height="2465" tsb="454"/>
+ <mtx name="kgreenlandic" height="2465" tsb="947"/>
+ <mtx name="l" height="2465" tsb="454"/>
+ <mtx name="lacute" height="2465" tsb="34"/>
+ <mtx name="lcaron" height="2465" tsb="454"/>
+ <mtx name="lcommaaccent" height="2465" tsb="454"/>
+ <mtx name="ldot" height="2465" tsb="454"/>
+ <mtx name="less" height="2465" tsb="947"/>
+ <mtx name="logicalnot" height="2465" tsb="1145"/>
+ <mtx name="longs" height="2465" tsb="429"/>
+ <mtx name="lslash" height="2465" tsb="454"/>
+ <mtx name="m" height="2465" tsb="923"/>
+ <mtx name="macron" height="2465" tsb="602"/>
+ <mtx name="macron#1" height="2465" tsb="429"/>
+ <mtx name="minus" height="2465" tsb="1367"/>
+ <mtx name="mu" height="2465" tsb="947"/>
+ <mtx name="multiply" height="2465" tsb="961"/>
+ <mtx name="n" height="2465" tsb="923"/>
+ <mtx name="nacute" height="2465" tsb="429"/>
+ <mtx name="napostrophe" height="2465" tsb="454"/>
+ <mtx name="nbhyphen" height="2465" tsb="1367"/>
+ <mtx name="ncaron" height="2465" tsb="429"/>
+ <mtx name="ncommaaccent" height="2465" tsb="923"/>
+ <mtx name="nine" height="2465" tsb="515"/>
+ <mtx name="nonbreakingspace" height="2465" tsb="2033"/>
+ <mtx name="ntilde" height="2465" tsb="516"/>
+ <mtx name="numbersign" height="2465" tsb="553"/>
+ <mtx name="o" height="2465" tsb="923"/>
+ <mtx name="oacute" height="2465" tsb="429"/>
+ <mtx name="obreve" height="2465" tsb="429"/>
+ <mtx name="ocircumflex" height="2465" tsb="429"/>
+ <mtx name="odieresis" height="2465" tsb="577"/>
+ <mtx name="oe" height="2465" tsb="923"/>
+ <mtx name="ogonek" height="2465" tsb="2033"/>
+ <mtx name="ograve" height="2465" tsb="429"/>
+ <mtx name="ohungarumlaut" height="2465" tsb="429"/>
+ <mtx name="omacron" height="2465" tsb="602"/>
+ <mtx name="one" height="2465" tsb="516"/>
+ <mtx name="onehalf" height="2465" tsb="516"/>
+ <mtx name="onequarter" height="2465" tsb="516"/>
+ <mtx name="onesuperior" height="2465" tsb="530"/>
+ <mtx name="ordfeminine" height="2465" tsb="515"/>
+ <mtx name="ordmasculine" height="2465" tsb="516"/>
+ <mtx name="oslash" height="2465" tsb="923"/>
+ <mtx name="otilde" height="2465" tsb="516"/>
+ <mtx name="p" height="2465" tsb="923"/>
+ <mtx name="paragraph" height="2465" tsb="553"/>
+ <mtx name="parenleft" height="2465" tsb="454"/>
+ <mtx name="parenright" height="2465" tsb="454"/>
+ <mtx name="percent" height="2465" tsb="516"/>
+ <mtx name="period" height="2465" tsb="1786"/>
+ <mtx name="periodcentered" height="2465" tsb="1295"/>
+ <mtx name="periodcentered#1" height="2465" tsb="1295"/>
+ <mtx name="perthousand" height="2465" tsb="516"/>
+ <mtx name="plus" height="2465" tsb="947"/>
+ <mtx name="plusminus" height="2465" tsb="849"/>
+ <mtx name="q" height="2465" tsb="923"/>
+ <mtx name="question" height="2465" tsb="516"/>
+ <mtx name="questiondown" height="2465" tsb="947"/>
+ <mtx name="quotedbl" height="2465" tsb="454"/>
+ <mtx name="quotedblbase" height="2465" tsb="1836"/>
+ <mtx name="quotedblleft" height="2465" tsb="454"/>
+ <mtx name="quotedblright" height="2465" tsb="454"/>
+ <mtx name="quoteleft" height="2465" tsb="454"/>
+ <mtx name="quotereversed" height="2465" tsb="2033"/>
+ <mtx name="quoteright" height="2465" tsb="454"/>
+ <mtx name="quotesinglbase" height="2465" tsb="1786"/>
+ <mtx name="quotesingle" height="2465" tsb="454"/>
+ <mtx name="r" height="2465" tsb="923"/>
+ <mtx name="racute" height="2465" tsb="429"/>
+ <mtx name="radicalex" height="2465" tsb="429"/>
+ <mtx name="rcaron" height="2465" tsb="429"/>
+ <mtx name="rcommaaccent" height="2465" tsb="923"/>
+ <mtx name="registered" height="2465" tsb="553"/>
+ <mtx name="ring" height="2465" tsb="296"/>
+ <mtx name="s" height="2465" tsb="923"/>
+ <mtx name="sacute" height="2465" tsb="429"/>
+ <mtx name="scaron" height="2465" tsb="429"/>
+ <mtx name="scedilla" height="2465" tsb="923"/>
+ <mtx name="scircumflex" height="2465" tsb="429"/>
+ <mtx name="scommaaccent" height="2465" tsb="923"/>
+ <mtx name="section" height="2465" tsb="516"/>
+ <mtx name="semicolon" height="2465" tsb="947"/>
+ <mtx name="semicolon#1" height="2465" tsb="947"/>
+ <mtx name="seven" height="2465" tsb="553"/>
+ <mtx name="sfthyphen" height="2465" tsb="1367"/>
+ <mtx name="six" height="2465" tsb="515"/>
+ <mtx name="slash" height="2465" tsb="553"/>
+ <mtx name="space" height="2465" tsb="2033"/>
+ <mtx name="sterling" height="2465" tsb="516"/>
+ <mtx name="t" height="2465" tsb="731"/>
+ <mtx name="tbar" height="2465" tsb="731"/>
+ <mtx name="tcaron" height="2465" tsb="345"/>
+ <mtx name="tcommaaccent" height="2465" tsb="731"/>
+ <mtx name="tcommabelow" height="2465" tsb="731"/>
+ <mtx name="thorn" height="2465" tsb="454"/>
+ <mtx name="three" height="2465" tsb="516"/>
+ <mtx name="threequarters" height="2465" tsb="516"/>
+ <mtx name="threesuperior" height="2465" tsb="530"/>
+ <mtx name="tilde" height="2465" tsb="516"/>
+ <mtx name="trademark" height="2465" tsb="553"/>
+ <mtx name="two" height="2465" tsb="516"/>
+ <mtx name="twosuperior" height="2465" tsb="530"/>
+ <mtx name="u" height="2465" tsb="947"/>
+ <mtx name="uacute" height="2465" tsb="429"/>
+ <mtx name="ubreve" height="2465" tsb="429"/>
+ <mtx name="ucircumflex" height="2465" tsb="429"/>
+ <mtx name="udieresis" height="2465" tsb="577"/>
+ <mtx name="ugrave" height="2465" tsb="429"/>
+ <mtx name="uhungarumlaut" height="2465" tsb="429"/>
+ <mtx name="umacron" height="2465" tsb="602"/>
+ <mtx name="underscore" height="2465" tsb="2033"/>
+ <mtx name="uogonek" height="2465" tsb="947"/>
+ <mtx name="uring" height="2465" tsb="296"/>
+ <mtx name="utilde" height="2465" tsb="516"/>
+ <mtx name="v" height="2465" tsb="947"/>
+ <mtx name="w" height="2465" tsb="947"/>
+ <mtx name="wcircumflex" height="2465" tsb="429"/>
+ <mtx name="x" height="2465" tsb="947"/>
+ <mtx name="y" height="2465" tsb="947"/>
+ <mtx name="yacute" height="2465" tsb="429"/>
+ <mtx name="ycircumflex" height="2465" tsb="429"/>
+ <mtx name="ydieresis" height="2465" tsb="577"/>
+ <mtx name="yen" height="2465" tsb="553"/>
+ <mtx name="z" height="2465" tsb="947"/>
+ <mtx name="zacute" height="2465" tsb="429"/>
+ <mtx name="zcaron" height="2465" tsb="429"/>
+ <mtx name="zdotaccent" height="2465" tsb="553"/>
+ <mtx name="zero" height="2465" tsb="516"/>
+ </vmtx>
+
+</ttFont>
diff --git a/vendor/github.com/golang/freetype/testdata/make-other-hinting-txts.sh b/vendor/github.com/golang/freetype/testdata/make-other-hinting-txts.sh
new file mode 100755
index 000000000..afee131e8
--- /dev/null
+++ b/vendor/github.com/golang/freetype/testdata/make-other-hinting-txts.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+#
+# This script creates the optional x-*-hinting.txt files from fonts that are
+# not checked in for copyright or file size reasons.
+#
+# Run it from this directory (testdata).
+#
+# It has only been tested on an Ubuntu 14.04 system.
+
+set -e
+
+: ${FONTDIR:=/usr/share/fonts/truetype}
+
+ln -sf $FONTDIR/droid/DroidSansJapanese.ttf x-droid-sans-japanese.ttf
+ln -sf $FONTDIR/msttcorefonts/Arial_Bold.ttf x-arial-bold.ttf
+ln -sf $FONTDIR/msttcorefonts/Times_New_Roman.ttf x-times-new-roman.ttf
+ln -sf $FONTDIR/ttf-dejavu/DejaVuSans-Oblique.ttf x-deja-vu-sans-oblique.ttf
+
+${CC:=gcc} ../cmd/print-glyph-points/main.c $(pkg-config --cflags --libs freetype2) -o print-glyph-points
+
+# Uncomment these lines to also recreate the luxisr-*-hinting.txt files.
+# ./print-glyph-points 12 luxisr.ttf sans_hinting > luxisr-12pt-sans-hinting.txt
+# ./print-glyph-points 12 luxisr.ttf with_hinting > luxisr-12pt-with-hinting.txt
+
+./print-glyph-points 9 x-droid-sans-japanese.ttf sans_hinting > x-droid-sans-japanese-9pt-sans-hinting.txt
+./print-glyph-points 9 x-droid-sans-japanese.ttf with_hinting > x-droid-sans-japanese-9pt-with-hinting.txt
+./print-glyph-points 11 x-arial-bold.ttf sans_hinting > x-arial-bold-11pt-sans-hinting.txt
+./print-glyph-points 11 x-arial-bold.ttf with_hinting > x-arial-bold-11pt-with-hinting.txt
+./print-glyph-points 13 x-times-new-roman.ttf sans_hinting > x-times-new-roman-13pt-sans-hinting.txt
+./print-glyph-points 13 x-times-new-roman.ttf with_hinting > x-times-new-roman-13pt-with-hinting.txt
+./print-glyph-points 17 x-deja-vu-sans-oblique.ttf sans_hinting > x-deja-vu-sans-oblique-17pt-sans-hinting.txt
+./print-glyph-points 17 x-deja-vu-sans-oblique.ttf with_hinting > x-deja-vu-sans-oblique-17pt-with-hinting.txt
+
+rm print-glyph-points
diff --git a/vendor/github.com/golang/freetype/truetype/face_test.go b/vendor/github.com/golang/freetype/truetype/face_test.go
new file mode 100644
index 000000000..856581dff
--- /dev/null
+++ b/vendor/github.com/golang/freetype/truetype/face_test.go
@@ -0,0 +1,48 @@
+// Copyright 2015 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+package truetype
+
+import (
+ "image"
+ "image/draw"
+ "io/ioutil"
+ "strings"
+ "testing"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/math/fixed"
+)
+
+func BenchmarkDrawString(b *testing.B) {
+ data, err := ioutil.ReadFile("../licenses/gpl.txt")
+ if err != nil {
+ b.Fatal(err)
+ }
+ lines := strings.Split(string(data), "\n")
+ data, err = ioutil.ReadFile("../testdata/luxisr.ttf")
+ if err != nil {
+ b.Fatal(err)
+ }
+ f, err := Parse(data)
+ if err != nil {
+ b.Fatal(err)
+ }
+ dst := image.NewRGBA(image.Rect(0, 0, 800, 600))
+ draw.Draw(dst, dst.Bounds(), image.White, image.ZP, draw.Src)
+ d := &font.Drawer{
+ Dst: dst,
+ Src: image.Black,
+ Face: NewFace(f, nil),
+ }
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ for j, line := range lines {
+ d.Dot = fixed.P(0, (j*16)%600)
+ d.DrawString(line)
+ }
+ }
+}
diff --git a/vendor/github.com/golang/freetype/truetype/hint_test.go b/vendor/github.com/golang/freetype/truetype/hint_test.go
new file mode 100644
index 000000000..7eb43dde0
--- /dev/null
+++ b/vendor/github.com/golang/freetype/truetype/hint_test.go
@@ -0,0 +1,675 @@
+// Copyright 2012 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+package truetype
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+
+ "golang.org/x/image/math/fixed"
+)
+
+func TestBytecode(t *testing.T) {
+ testCases := []struct {
+ desc string
+ prog []byte
+ want []int32
+ errStr string
+ }{
+ {
+ "underflow",
+ []byte{
+ opDUP,
+ },
+ nil,
+ "underflow",
+ },
+ {
+ "infinite loop",
+ []byte{
+ opPUSHW000, // [-1]
+ 0xff,
+ 0xff,
+ opDUP, // [-1, -1]
+ opJMPR, // [-1]
+ },
+ nil,
+ "too many steps",
+ },
+ {
+ "unbalanced if/else",
+ []byte{
+ opPUSHB000, // [0]
+ 0,
+ opIF,
+ },
+ nil,
+ "unbalanced",
+ },
+ {
+ "vector set/gets",
+ []byte{
+ opSVTCA1, // []
+ opGPV, // [0x4000, 0]
+ opSVTCA0, // [0x4000, 0]
+ opGFV, // [0x4000, 0, 0, 0x4000]
+ opNEG, // [0x4000, 0, 0, -0x4000]
+ opSPVFS, // [0x4000, 0]
+ opSFVTPV, // [0x4000, 0]
+ opPUSHB000, // [0x4000, 0, 1]
+ 1,
+ opGFV, // [0x4000, 0, 1, 0, -0x4000]
+ opPUSHB000, // [0x4000, 0, 1, 0, -0x4000, 2]
+ 2,
+ },
+ []int32{0x4000, 0, 1, 0, -0x4000, 2},
+ "",
+ },
+ {
+ "jumps",
+ []byte{
+ opPUSHB001, // [10, 2]
+ 10,
+ 2,
+ opJMPR, // [10]
+ opDUP, // not executed
+ opDUP, // [10, 10]
+ opPUSHB010, // [10, 10, 20, 2, 1]
+ 20,
+ 2,
+ 1,
+ opJROT, // [10, 10, 20]
+ opDUP, // not executed
+ opDUP, // [10, 10, 20, 20]
+ opPUSHB010, // [10, 10, 20, 20, 30, 2, 1]
+ 30,
+ 2,
+ 1,
+ opJROF, // [10, 10, 20, 20, 30]
+ opDUP, // [10, 10, 20, 20, 30, 30]
+ opDUP, // [10, 10, 20, 20, 30, 30, 30]
+ },
+ []int32{10, 10, 20, 20, 30, 30, 30},
+ "",
+ },
+ {
+ "stack ops",
+ []byte{
+ opPUSHB010, // [10, 20, 30]
+ 10,
+ 20,
+ 30,
+ opCLEAR, // []
+ opPUSHB010, // [40, 50, 60]
+ 40,
+ 50,
+ 60,
+ opSWAP, // [40, 60, 50]
+ opDUP, // [40, 60, 50, 50]
+ opDUP, // [40, 60, 50, 50, 50]
+ opPOP, // [40, 60, 50, 50]
+ opDEPTH, // [40, 60, 50, 50, 4]
+ opCINDEX, // [40, 60, 50, 50, 40]
+ opPUSHB000, // [40, 60, 50, 50, 40, 4]
+ 4,
+ opMINDEX, // [40, 50, 50, 40, 60]
+ },
+ []int32{40, 50, 50, 40, 60},
+ "",
+ },
+ {
+ "push ops",
+ []byte{
+ opPUSHB000, // [255]
+ 255,
+ opPUSHW001, // [255, -2, 253]
+ 255,
+ 254,
+ 0,
+ 253,
+ opNPUSHB, // [1, -2, 253, 1, 2]
+ 2,
+ 1,
+ 2,
+ opNPUSHW, // [1, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809]
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ },
+ []int32{255, -2, 253, 1, 2, 0x0405, 0x0607, 0x0809},
+ "",
+ },
+ {
+ "store ops",
+ []byte{
+ opPUSHB011, // [1, 22, 3, 44]
+ 1,
+ 22,
+ 3,
+ 44,
+ opWS, // [1, 22]
+ opWS, // []
+ opPUSHB000, // [3]
+ 3,
+ opRS, // [44]
+ },
+ []int32{44},
+ "",
+ },
+ {
+ "comparison ops",
+ []byte{
+ opPUSHB001, // [10, 20]
+ 10,
+ 20,
+ opLT, // [1]
+ opPUSHB001, // [1, 10, 20]
+ 10,
+ 20,
+ opLTEQ, // [1, 1]
+ opPUSHB001, // [1, 1, 10, 20]
+ 10,
+ 20,
+ opGT, // [1, 1, 0]
+ opPUSHB001, // [1, 1, 0, 10, 20]
+ 10,
+ 20,
+ opGTEQ, // [1, 1, 0, 0]
+ opEQ, // [1, 1, 1]
+ opNEQ, // [1, 0]
+ },
+ []int32{1, 0},
+ "",
+ },
+ {
+ "odd/even",
+ // Calculate odd(2+31/64), odd(2+32/64), even(2), even(1).
+ []byte{
+ opPUSHB000, // [159]
+ 159,
+ opODD, // [0]
+ opPUSHB000, // [0, 160]
+ 160,
+ opODD, // [0, 1]
+ opPUSHB000, // [0, 1, 128]
+ 128,
+ opEVEN, // [0, 1, 1]
+ opPUSHB000, // [0, 1, 1, 64]
+ 64,
+ opEVEN, // [0, 1, 1, 0]
+ },
+ []int32{0, 1, 1, 0},
+ "",
+ },
+ {
+ "if true",
+ []byte{
+ opPUSHB001, // [255, 1]
+ 255,
+ 1,
+ opIF,
+ opPUSHB000, // [255, 2]
+ 2,
+ opEIF,
+ opPUSHB000, // [255, 2, 254]
+ 254,
+ },
+ []int32{255, 2, 254},
+ "",
+ },
+ {
+ "if false",
+ []byte{
+ opPUSHB001, // [255, 0]
+ 255,
+ 0,
+ opIF,
+ opPUSHB000, // [255]
+ 2,
+ opEIF,
+ opPUSHB000, // [255, 254]
+ 254,
+ },
+ []int32{255, 254},
+ "",
+ },
+ {
+ "if/else true",
+ []byte{
+ opPUSHB000, // [1]
+ 1,
+ opIF,
+ opPUSHB000, // [2]
+ 2,
+ opELSE,
+ opPUSHB000, // not executed
+ 3,
+ opEIF,
+ },
+ []int32{2},
+ "",
+ },
+ {
+ "if/else false",
+ []byte{
+ opPUSHB000, // [0]
+ 0,
+ opIF,
+ opPUSHB000, // not executed
+ 2,
+ opELSE,
+ opPUSHB000, // [3]
+ 3,
+ opEIF,
+ },
+ []int32{3},
+ "",
+ },
+ {
+ "if/else true if/else false",
+ // 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
+ []byte{
+ opPUSHB010, // [255, 0, 1]
+ 255,
+ 0,
+ 1,
+ opIF,
+ opIF,
+ opPUSHB001, // not executed
+ 0x58,
+ 0x58,
+ opELSE,
+ opPUSHW000, // [255, 0x5858]
+ 0x58,
+ 0x58,
+ opEIF,
+ opELSE,
+ opIF,
+ opNPUSHB, // not executed
+ 3,
+ 0x58,
+ 0x58,
+ 0x58,
+ opELSE,
+ opNPUSHW, // not executed
+ 2,
+ 0x58,
+ 0x58,
+ 0x58,
+ 0x58,
+ opEIF,
+ opEIF,
+ opPUSHB000, // [255, 0x5858, 254]
+ 254,
+ },
+ []int32{255, 0x5858, 254},
+ "",
+ },
+ {
+ "if/else false if/else true",
+ // 0x58 is the opcode for opIF. The literal 0x58s below are pushed data.
+ []byte{
+ opPUSHB010, // [255, 1, 0]
+ 255,
+ 1,
+ 0,
+ opIF,
+ opIF,
+ opPUSHB001, // not executed
+ 0x58,
+ 0x58,
+ opELSE,
+ opPUSHW000, // not executed
+ 0x58,
+ 0x58,
+ opEIF,
+ opELSE,
+ opIF,
+ opNPUSHB, // [255, 0x58, 0x58, 0x58]
+ 3,
+ 0x58,
+ 0x58,
+ 0x58,
+ opELSE,
+ opNPUSHW, // not executed
+ 2,
+ 0x58,
+ 0x58,
+ 0x58,
+ 0x58,
+ opEIF,
+ opEIF,
+ opPUSHB000, // [255, 0x58, 0x58, 0x58, 254]
+ 254,
+ },
+ []int32{255, 0x58, 0x58, 0x58, 254},
+ "",
+ },
+ {
+ "logical ops",
+ []byte{
+ opPUSHB010, // [0, 10, 20]
+ 0,
+ 10,
+ 20,
+ opAND, // [0, 1]
+ opOR, // [1]
+ opNOT, // [0]
+ },
+ []int32{0},
+ "",
+ },
+ {
+ "arithmetic ops",
+ // Calculate abs((-(1 - (2*3)))/2 + 1/64).
+ // The answer is 5/2 + 1/64 in ideal numbers, or 161 in 26.6 fixed point math.
+ []byte{
+ opPUSHB010, // [64, 128, 192]
+ 1 << 6,
+ 2 << 6,
+ 3 << 6,
+ opMUL, // [64, 384]
+ opSUB, // [-320]
+ opNEG, // [320]
+ opPUSHB000, // [320, 128]
+ 2 << 6,
+ opDIV, // [160]
+ opPUSHB000, // [160, 1]
+ 1,
+ opADD, // [161]
+ opABS, // [161]
+ },
+ []int32{161},
+ "",
+ },
+ {
+ "floor, ceiling",
+ []byte{
+ opPUSHB000, // [96]
+ 96,
+ opFLOOR, // [64]
+ opPUSHB000, // [64, 96]
+ 96,
+ opCEILING, // [64, 128]
+ },
+ []int32{64, 128},
+ "",
+ },
+ {
+ "rounding",
+ // Round 1.40625 (which is 90/64) under various rounding policies.
+ // See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
+ []byte{
+ opROFF, // []
+ opPUSHB000, // [90]
+ 90,
+ opROUND00, // [90]
+ opRTG, // [90]
+ opPUSHB000, // [90, 90]
+ 90,
+ opROUND00, // [90, 64]
+ opRTHG, // [90, 64]
+ opPUSHB000, // [90, 64, 90]
+ 90,
+ opROUND00, // [90, 64, 96]
+ opRDTG, // [90, 64, 96]
+ opPUSHB000, // [90, 64, 96, 90]
+ 90,
+ opROUND00, // [90, 64, 96, 64]
+ opRUTG, // [90, 64, 96, 64]
+ opPUSHB000, // [90, 64, 96, 64, 90]
+ 90,
+ opROUND00, // [90, 64, 96, 64, 128]
+ opRTDG, // [90, 64, 96, 64, 128]
+ opPUSHB000, // [90, 64, 96, 64, 128, 90]
+ 90,
+ opROUND00, // [90, 64, 96, 64, 128, 96]
+ },
+ []int32{90, 64, 96, 64, 128, 96},
+ "",
+ },
+ {
+ "super-rounding",
+ // See figure 20 of https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
+ // and the sign preservation steps of the "Order of rounding operations" section.
+ []byte{
+ opPUSHB000, // [0x58]
+ 0x58,
+ opSROUND, // []
+ opPUSHW000, // [-81]
+ 0xff,
+ 0xaf,
+ opROUND00, // [-80]
+ opPUSHW000, // [-80, -80]
+ 0xff,
+ 0xb0,
+ opROUND00, // [-80, -80]
+ opPUSHW000, // [-80, -80, -17]
+ 0xff,
+ 0xef,
+ opROUND00, // [-80, -80, -16]
+ opPUSHW000, // [-80, -80, -16, -16]
+ 0xff,
+ 0xf0,
+ opROUND00, // [-80, -80, -16, -16]
+ opPUSHB000, // [-80, -80, -16, -16, 0]
+ 0,
+ opROUND00, // [-80, -80, -16, -16, 16]
+ opPUSHB000, // [-80, -80, -16, -16, 16, 16]
+ 16,
+ opROUND00, // [-80, -80, -16, -16, 16, 16]
+ opPUSHB000, // [-80, -80, -16, -16, 16, 16, 47]
+ 47,
+ opROUND00, // [-80, -80, -16, -16, 16, 16, 16]
+ opPUSHB000, // [-80, -80, -16, -16, 16, 16, 16, 48]
+ 48,
+ opROUND00, // [-80, -80, -16, -16, 16, 16, 16, 80]
+ },
+ []int32{-80, -80, -16, -16, 16, 16, 16, 80},
+ "",
+ },
+ {
+ "roll",
+ []byte{
+ opPUSHB010, // [1, 2, 3]
+ 1,
+ 2,
+ 3,
+ opROLL, // [2, 3, 1]
+ },
+ []int32{2, 3, 1},
+ "",
+ },
+ {
+ "max/min",
+ []byte{
+ opPUSHW001, // [-2, -3]
+ 0xff,
+ 0xfe,
+ 0xff,
+ 0xfd,
+ opMAX, // [-2]
+ opPUSHW001, // [-2, -4, -5]
+ 0xff,
+ 0xfc,
+ 0xff,
+ 0xfb,
+ opMIN, // [-2, -5]
+ },
+ []int32{-2, -5},
+ "",
+ },
+ {
+ "functions",
+ []byte{
+ opPUSHB011, // [3, 7, 0, 3]
+ 3,
+ 7,
+ 0,
+ 3,
+
+ opFDEF, // Function #3 (not called)
+ opPUSHB000,
+ 98,
+ opENDF,
+
+ opFDEF, // Function #0
+ opDUP,
+ opADD,
+ opENDF,
+
+ opFDEF, // Function #7
+ opPUSHB001,
+ 10,
+ 0,
+ opCALL,
+ opDUP,
+ opENDF,
+
+ opFDEF, // Function #3 (again)
+ opPUSHB000,
+ 99,
+ opENDF,
+
+ opPUSHB001, // [2, 0]
+ 2,
+ 0,
+ opCALL, // [4]
+ opPUSHB000, // [4, 3]
+ 3,
+ opLOOPCALL, // [99, 99, 99, 99]
+ opPUSHB000, // [99, 99, 99, 99, 7]
+ 7,
+ opCALL, // [99, 99, 99, 99, 20, 20]
+ },
+ []int32{99, 99, 99, 99, 20, 20},
+ "",
+ },
+ }
+
+ for _, tc := range testCases {
+ h := &hinter{}
+ h.init(&Font{
+ maxStorage: 32,
+ maxStackElements: 100,
+ }, 768)
+ err, errStr := h.run(tc.prog, nil, nil, nil, nil), ""
+ if err != nil {
+ errStr = err.Error()
+ }
+ if tc.errStr != "" {
+ if errStr == "" {
+ t.Errorf("%s: got no error, want %q", tc.desc, tc.errStr)
+ } else if !strings.Contains(errStr, tc.errStr) {
+ t.Errorf("%s: got error %q, want one containing %q", tc.desc, errStr, tc.errStr)
+ }
+ continue
+ }
+ if errStr != "" {
+ t.Errorf("%s: got error %q, want none", tc.desc, errStr)
+ continue
+ }
+ got := h.stack[:len(tc.want)]
+ if !reflect.DeepEqual(got, tc.want) {
+ t.Errorf("%s: got %v, want %v", tc.desc, got, tc.want)
+ continue
+ }
+ }
+}
+
+// TestMove tests that the hinter.move method matches the output of the C
+// Freetype implementation.
+func TestMove(t *testing.T) {
+ h, p := hinter{}, Point{}
+ testCases := []struct {
+ pvX, pvY, fvX, fvY f2dot14
+ wantX, wantY fixed.Int26_6
+ }{
+ {+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0},
+ {+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0},
+ {-0x4000, +0x0000, +0x4000, +0x0000, -1000, +0},
+ {-0x4000, +0x0000, -0x4000, +0x0000, -1000, +0},
+ {+0x0000, +0x4000, +0x0000, +0x4000, +0, +1000},
+ {+0x0000, +0x4000, +0x0000, -0x4000, +0, +1000},
+ {+0x4000, +0x0000, +0x2d41, +0x2d41, +1000, +1000},
+ {+0x4000, +0x0000, -0x2d41, +0x2d41, +1000, -1000},
+ {+0x4000, +0x0000, +0x2d41, -0x2d41, +1000, -1000},
+ {+0x4000, +0x0000, -0x2d41, -0x2d41, +1000, +1000},
+ {-0x4000, +0x0000, +0x2d41, +0x2d41, -1000, -1000},
+ {-0x4000, +0x0000, -0x2d41, +0x2d41, -1000, +1000},
+ {-0x4000, +0x0000, +0x2d41, -0x2d41, -1000, +1000},
+ {-0x4000, +0x0000, -0x2d41, -0x2d41, -1000, -1000},
+ {+0x376d, +0x2000, +0x2d41, +0x2d41, +732, +732},
+ {-0x376d, +0x2000, +0x2d41, +0x2d41, -2732, -2732},
+ {+0x376d, +0x2000, +0x2d41, -0x2d41, +2732, -2732},
+ {-0x376d, +0x2000, +0x2d41, -0x2d41, -732, +732},
+ {-0x376d, -0x2000, +0x2d41, +0x2d41, -732, -732},
+ {+0x376d, +0x2000, +0x4000, +0x0000, +1155, +0},
+ {+0x376d, +0x2000, +0x0000, +0x4000, +0, +2000},
+ }
+ for _, tc := range testCases {
+ p = Point{}
+ h.gs.pv = [2]f2dot14{tc.pvX, tc.pvY}
+ h.gs.fv = [2]f2dot14{tc.fvX, tc.fvY}
+ h.move(&p, 1000, true)
+ tx := p.Flags&flagTouchedX != 0
+ ty := p.Flags&flagTouchedY != 0
+ wantTX := tc.fvX != 0
+ wantTY := tc.fvY != 0
+ if p.X != tc.wantX || p.Y != tc.wantY || tx != wantTX || ty != wantTY {
+ t.Errorf("pv=%v, fv=%v\ngot %d, %d, %t, %t\nwant %d, %d, %t, %t",
+ h.gs.pv, h.gs.fv, p.X, p.Y, tx, ty, tc.wantX, tc.wantY, wantTX, wantTY)
+ continue
+ }
+
+ // Check that p is aligned with the freedom vector.
+ a := int64(p.X) * int64(tc.fvY)
+ b := int64(p.Y) * int64(tc.fvX)
+ if a != b {
+ t.Errorf("pv=%v, fv=%v, p=%v not aligned with fv", h.gs.pv, h.gs.fv, p)
+ continue
+ }
+
+ // Check that the projected p is 1000 away from the origin.
+ dotProd := (int64(p.X)*int64(tc.pvX) + int64(p.Y)*int64(tc.pvY) + 1<<13) >> 14
+ if dotProd != 1000 {
+ t.Errorf("pv=%v, fv=%v, p=%v not 1000 from origin", h.gs.pv, h.gs.fv, p)
+ continue
+ }
+ }
+}
+
+// TestNormalize tests that the normalize function matches the output of the C
+// Freetype implementation.
+func TestNormalize(t *testing.T) {
+ testCases := [][2]f2dot14{
+ {-15895, 3974},
+ {-15543, 5181},
+ {-14654, 7327},
+ {-11585, 11585},
+ {0, 16384},
+ {11585, 11585},
+ {14654, 7327},
+ {15543, 5181},
+ {15895, 3974},
+ {16066, 3213},
+ {16161, 2694},
+ {16219, 2317},
+ {16257, 2032},
+ {16284, 1809},
+ }
+ for i, want := range testCases {
+ got := normalize(f2dot14(i)-4, 1)
+ if got != want {
+ t.Errorf("i=%d: got %v, want %v", i, got, want)
+ }
+ }
+}
diff --git a/vendor/github.com/golang/freetype/truetype/truetype.go b/vendor/github.com/golang/freetype/truetype/truetype.go
index 9e943d3ec..613fc17e2 100644
--- a/vendor/github.com/golang/freetype/truetype/truetype.go
+++ b/vendor/github.com/golang/freetype/truetype/truetype.go
@@ -15,7 +15,7 @@
//
// To measure a TrueType font in ideal FUnit space, use scale equal to
// font.FUnitsPerEm().
-package truetype
+package truetype // import "github.com/golang/freetype/truetype"
import (
"fmt"
diff --git a/vendor/github.com/golang/freetype/truetype/truetype_test.go b/vendor/github.com/golang/freetype/truetype/truetype_test.go
new file mode 100644
index 000000000..bd62d1da1
--- /dev/null
+++ b/vendor/github.com/golang/freetype/truetype/truetype_test.go
@@ -0,0 +1,400 @@
+// Copyright 2012 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+package truetype
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/math/fixed"
+)
+
+func parseTestdataFont(name string) (f *Font, testdataIsOptional bool, err error) {
+ b, err := ioutil.ReadFile(fmt.Sprintf("../testdata/%s.ttf", name))
+ if err != nil {
+ // The "x-foo" fonts are optional tests, as they are not checked
+ // in for copyright or file size reasons.
+ return nil, strings.HasPrefix(name, "x-"), fmt.Errorf("%s: ReadFile: %v", name, err)
+ }
+ f, err = Parse(b)
+ if err != nil {
+ return nil, true, fmt.Errorf("%s: Parse: %v", name, err)
+ }
+ return f, false, nil
+}
+
+func mkBounds(minX, minY, maxX, maxY fixed.Int26_6) fixed.Rectangle26_6 {
+ return fixed.Rectangle26_6{
+ Min: fixed.Point26_6{
+ X: minX,
+ Y: minY,
+ },
+ Max: fixed.Point26_6{
+ X: maxX,
+ Y: maxY,
+ },
+ }
+}
+
+// TestParse tests that the luxisr.ttf metrics and glyphs are parsed correctly.
+// The numerical values can be manually verified by examining luxisr.ttx.
+func TestParse(t *testing.T) {
+ f, _, err := parseTestdataFont("luxisr")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got, want := f.FUnitsPerEm(), int32(2048); got != want {
+ t.Errorf("FUnitsPerEm: got %v, want %v", got, want)
+ }
+ fupe := fixed.Int26_6(f.FUnitsPerEm())
+ if got, want := f.Bounds(fupe), mkBounds(-441, -432, 2024, 2033); got != want {
+ t.Errorf("Bounds: got %v, want %v", got, want)
+ }
+
+ i0 := f.Index('A')
+ i1 := f.Index('V')
+ if i0 != 36 || i1 != 57 {
+ t.Fatalf("Index: i0, i1 = %d, %d, want 36, 57", i0, i1)
+ }
+ if got, want := f.HMetric(fupe, i0), (HMetric{1366, 19}); got != want {
+ t.Errorf("HMetric: got %v, want %v", got, want)
+ }
+ if got, want := f.VMetric(fupe, i0), (VMetric{2465, 553}); got != want {
+ t.Errorf("VMetric: got %v, want %v", got, want)
+ }
+ if got, want := f.Kern(fupe, i0, i1), fixed.Int26_6(-144); got != want {
+ t.Errorf("Kern: got %v, want %v", got, want)
+ }
+
+ g := &GlyphBuf{}
+ err = g.Load(f, fupe, i0, font.HintingNone)
+ if err != nil {
+ t.Fatalf("Load: %v", err)
+ }
+ g0 := &GlyphBuf{
+ Bounds: g.Bounds,
+ Points: g.Points,
+ Ends: g.Ends,
+ }
+ g1 := &GlyphBuf{
+ Bounds: mkBounds(19, 0, 1342, 1480),
+ Points: []Point{
+ {19, 0, 51},
+ {581, 1480, 1},
+ {789, 1480, 51},
+ {1342, 0, 1},
+ {1116, 0, 35},
+ {962, 410, 3},
+ {368, 410, 33},
+ {214, 0, 3},
+ {428, 566, 19},
+ {904, 566, 33},
+ {667, 1200, 3},
+ },
+ Ends: []int{8, 11},
+ }
+ if got, want := fmt.Sprint(g0), fmt.Sprint(g1); got != want {
+ t.Errorf("GlyphBuf:\ngot %v\nwant %v", got, want)
+ }
+}
+
+func TestIndex(t *testing.T) {
+ testCases := map[string]map[rune]Index{
+ "luxisr": {
+ ' ': 3,
+ '!': 4,
+ 'A': 36,
+ 'V': 57,
+ 'É': 101,
+ 'fl': 193,
+ '\u22c5': 385,
+ '中': 0,
+ },
+
+ // The x-etc test cases use those versions of the .ttf files provided
+ // by Ubuntu 14.04. See testdata/make-other-hinting-txts.sh for details.
+
+ "x-arial-bold": {
+ ' ': 3,
+ '+': 14,
+ '0': 19,
+ '_': 66,
+ 'w': 90,
+ '~': 97,
+ 'Ä': 98,
+ 'fl': 192,
+ '½': 242,
+ 'σ': 305,
+ 'λ': 540,
+ 'ỹ': 1275,
+ '\u04e9': 1319,
+ '中': 0,
+ },
+ "x-deja-vu-sans-oblique": {
+ ' ': 3,
+ '*': 13,
+ 'Œ': 276,
+ 'ω': 861,
+ '‡': 2571,
+ '⊕': 3110,
+ 'fl': 4728,
+ '\ufb03': 4729,
+ '\ufffd': 4813,
+ // TODO: '\U0001f640': ???,
+ '中': 0,
+ },
+ "x-droid-sans-japanese": {
+ ' ': 0,
+ '\u3000': 3,
+ '\u3041': 25,
+ '\u30fe': 201,
+ '\uff61': 202,
+ '\uff67': 208,
+ '\uff9e': 263,
+ '\uff9f': 264,
+ '\u4e00': 265,
+ '\u557e': 1000,
+ '\u61b6': 2024,
+ '\u6ede': 3177,
+ '\u7505': 3555,
+ '\u81e3': 4602,
+ '\u81e5': 4603,
+ '\u81e7': 4604,
+ '\u81e8': 4605,
+ '\u81ea': 4606,
+ '\u81ed': 4607,
+ '\u81f3': 4608,
+ '\u81f4': 4609,
+ '\u91c7': 5796,
+ '\u9fa0': 6620,
+ '\u203e': 12584,
+ },
+ "x-times-new-roman": {
+ ' ': 3,
+ ':': 29,
+ 'fl': 192,
+ 'Ŀ': 273,
+ '♠': 388,
+ 'Ŗ': 451,
+ 'Σ': 520,
+ '\u200D': 745,
+ 'Ẽ': 1216,
+ '\u04e9': 1319,
+ '中': 0,
+ },
+ }
+ for name, wants := range testCases {
+ f, testdataIsOptional, err := parseTestdataFont(name)
+ if err != nil {
+ if testdataIsOptional {
+ t.Log(err)
+ } else {
+ t.Fatal(err)
+ }
+ continue
+ }
+ for r, want := range wants {
+ if got := f.Index(r); got != want {
+ t.Errorf("%s: Index of %q, aka %U: got %d, want %d", name, r, r, got, want)
+ }
+ }
+ }
+}
+
+func TestName(t *testing.T) {
+ testCases := map[string]string{
+ "luximr": "Luxi Mono",
+ "luxirr": "Luxi Serif",
+ "luxisr": "Luxi Sans",
+ }
+
+ for name, want := range testCases {
+ f, testdataIsOptional, err := parseTestdataFont(name)
+ if err != nil {
+ if testdataIsOptional {
+ t.Log(err)
+ } else {
+ t.Fatal(err)
+ }
+ continue
+ }
+ if got := f.Name(NameIDFontFamily); got != want {
+ t.Errorf("%s: got %q, want %q", name, got, want)
+ }
+ }
+}
+
+type scalingTestData struct {
+ advanceWidth fixed.Int26_6
+ bounds fixed.Rectangle26_6
+ points []Point
+}
+
+// scalingTestParse parses a line of points like
+// 213 -22 -111 236 555;-22 -111 1, 178 555 1, 236 555 1, 36 -111 1
+// The line will not have a trailing "\n".
+func scalingTestParse(line string) (ret scalingTestData) {
+ next := func(s string) (string, fixed.Int26_6) {
+ t, i := "", strings.Index(s, " ")
+ if i != -1 {
+ s, t = s[:i], s[i+1:]
+ }
+ x, _ := strconv.Atoi(s)
+ return t, fixed.Int26_6(x)
+ }
+
+ i := strings.Index(line, ";")
+ prefix, line := line[:i], line[i+1:]
+
+ prefix, ret.advanceWidth = next(prefix)
+ prefix, ret.bounds.Min.X = next(prefix)
+ prefix, ret.bounds.Min.Y = next(prefix)
+ prefix, ret.bounds.Max.X = next(prefix)
+ prefix, ret.bounds.Max.Y = next(prefix)
+
+ ret.points = make([]Point, 0, 1+strings.Count(line, ","))
+ for len(line) > 0 {
+ s := line
+ if i := strings.Index(line, ","); i != -1 {
+ s, line = line[:i], line[i+1:]
+ for len(line) > 0 && line[0] == ' ' {
+ line = line[1:]
+ }
+ } else {
+ line = ""
+ }
+ s, x := next(s)
+ s, y := next(s)
+ s, f := next(s)
+ ret.points = append(ret.points, Point{X: x, Y: y, Flags: uint32(f)})
+ }
+ return ret
+}
+
+// scalingTestEquals is equivalent to, but faster than, calling
+// reflect.DeepEquals(a, b), and also returns the index of the first non-equal
+// element. It also treats a nil []Point and an empty non-nil []Point as equal.
+// a and b must have equal length.
+func scalingTestEquals(a, b []Point) (index int, equals bool) {
+ for i, p := range a {
+ if p != b[i] {
+ return i, false
+ }
+ }
+ return 0, true
+}
+
+var scalingTestCases = []struct {
+ name string
+ size int
+}{
+ {"luxisr", 12},
+ {"x-arial-bold", 11},
+ {"x-deja-vu-sans-oblique", 17},
+ {"x-droid-sans-japanese", 9},
+ {"x-times-new-roman", 13},
+}
+
+func testScaling(t *testing.T, h font.Hinting) {
+ for _, tc := range scalingTestCases {
+ f, testdataIsOptional, err := parseTestdataFont(tc.name)
+ if err != nil {
+ if testdataIsOptional {
+ t.Log(err)
+ } else {
+ t.Error(err)
+ }
+ continue
+ }
+ hintingStr := "sans"
+ if h != font.HintingNone {
+ hintingStr = "with"
+ }
+ testFile, err := os.Open(fmt.Sprintf(
+ "../testdata/%s-%dpt-%s-hinting.txt", tc.name, tc.size, hintingStr))
+ if err != nil {
+ t.Errorf("%s: Open: %v", tc.name, err)
+ continue
+ }
+ defer testFile.Close()
+
+ wants := []scalingTestData{}
+ scanner := bufio.NewScanner(testFile)
+ if scanner.Scan() {
+ major, minor, patch := 0, 0, 0
+ _, err := fmt.Sscanf(scanner.Text(), "freetype version %d.%d.%d", &major, &minor, &patch)
+ if err != nil {
+ t.Errorf("%s: version information: %v", tc.name, err)
+ }
+ if (major < 2) || (major == 2 && minor < 5) || (major == 2 && minor == 5 && patch < 1) {
+ t.Errorf("%s: need freetype version >= 2.5.1.\n"+
+ "Try setting LD_LIBRARY_PATH=/path/to/freetype_built_from_src/objs/.libs/\n"+
+ "and re-running testdata/make-other-hinting-txts.sh",
+ tc.name)
+ continue
+ }
+ } else {
+ t.Errorf("%s: no version information", tc.name)
+ continue
+ }
+ for scanner.Scan() {
+ wants = append(wants, scalingTestParse(scanner.Text()))
+ }
+ if err := scanner.Err(); err != nil && err != io.EOF {
+ t.Errorf("%s: Scanner: %v", tc.name, err)
+ continue
+ }
+
+ glyphBuf := &GlyphBuf{}
+ for i, want := range wants {
+ if err = glyphBuf.Load(f, fixed.I(tc.size), Index(i), h); err != nil {
+ t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err)
+ continue
+ }
+ got := scalingTestData{
+ advanceWidth: glyphBuf.AdvanceWidth,
+ bounds: glyphBuf.Bounds,
+ points: glyphBuf.Points,
+ }
+
+ if got.advanceWidth != want.advanceWidth {
+ t.Errorf("%s: glyph #%d advance width:\ngot %v\nwant %v",
+ tc.name, i, got.advanceWidth, want.advanceWidth)
+ continue
+ }
+
+ if got.bounds != want.bounds {
+ t.Errorf("%s: glyph #%d bounds:\ngot %v\nwant %v",
+ tc.name, i, got.bounds, want.bounds)
+ continue
+ }
+
+ for i := range got.points {
+ got.points[i].Flags &= 0x01
+ }
+ if len(got.points) != len(want.points) {
+ t.Errorf("%s: glyph #%d:\ngot %v\nwant %v\ndifferent slice lengths: %d versus %d",
+ tc.name, i, got.points, want.points, len(got.points), len(want.points))
+ continue
+ }
+ if j, equals := scalingTestEquals(got.points, want.points); !equals {
+ t.Errorf("%s: glyph #%d:\ngot %v\nwant %v\nat index %d: %v versus %v",
+ tc.name, i, got.points, want.points, j, got.points[j], want.points[j])
+ continue
+ }
+ }
+ }
+}
+
+func TestScalingHintingNone(t *testing.T) { testScaling(t, font.HintingNone) }
+func TestScalingHintingFull(t *testing.T) { testScaling(t, font.HintingFull) }
diff --git a/vendor/github.com/golang/groupcache/.gitignore b/vendor/github.com/golang/groupcache/.gitignore
new file mode 100644
index 000000000..b25c15b81
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/vendor/github.com/golang/groupcache/README.md b/vendor/github.com/golang/groupcache/README.md
new file mode 100644
index 000000000..70c29da16
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/README.md
@@ -0,0 +1,73 @@
+# groupcache
+
+## Summary
+
+groupcache is a caching and cache-filling library, intended as a
+replacement for memcached in many cases.
+
+For API docs and examples, see http://godoc.org/github.com/golang/groupcache
+
+## Comparison to memcached
+
+### **Like memcached**, groupcache:
+
+ * shards by key to select which peer is responsible for that key
+
+### **Unlike memcached**, groupcache:
+
+ * does not require running a separate set of servers, thus massively
+ reducing deployment/configuration pain. groupcache is a client
+ library as well as a server. It connects to its own peers.
+
+ * comes with a cache filling mechanism. Whereas memcached just says
+ "Sorry, cache miss", often resulting in a thundering herd of
+ database (or whatever) loads from an unbounded number of clients
+ (which has resulted in several fun outages), groupcache coordinates
+ cache fills such that only one load in one process of an entire
+ replicated set of processes populates the cache, then multiplexes
+ the loaded value to all callers.
+
+ * does not support versioned values. If key "foo" is value "bar",
+ key "foo" must always be "bar". There are neither cache expiration
+ times, nor explicit cache evictions. Thus there is also no CAS,
+ nor Increment/Decrement. This also means that groupcache....
+
+ * ... supports automatic mirroring of super-hot items to multiple
+ processes. This prevents memcached hot spotting where a machine's
+ CPU and/or NIC are overloaded by very popular keys/values.
+
+ * is currently only available for Go. It's very unlikely that I
+ (bradfitz@) will port the code to any other language.
+
+## Loading process
+
+In a nutshell, a groupcache lookup of **Get("foo")** looks like:
+
+(On machine #5 of a set of N machines running the same code)
+
+ 1. Is the value of "foo" in local memory because it's super hot? If so, use it.
+
+ 2. Is the value of "foo" in local memory because peer #5 (the current
+ peer) is the owner of it? If so, use it.
+
+ 3. Amongst all the peers in my set of N, am I the owner of the key
+ "foo"? (e.g. does it consistent hash to 5?) If so, load it. If
+ other callers come in, via the same process or via RPC requests
+ from peers, they block waiting for the load to finish and get the
+ same answer. If not, RPC to the peer that's the owner and get
+ the answer. If the RPC fails, just load it locally (still with
+ local dup suppression).
+
+## Users
+
+groupcache is in production use by dl.google.com (its original user),
+parts of Blogger, parts of Google Code, parts of Google Fiber, parts
+of Google production monitoring systems, etc.
+
+## Presentations
+
+See http://talks.golang.org/2013/oscon-dl.slide
+
+## Help
+
+Use the golang-nuts mailing list for any discussion or questions.
diff --git a/vendor/github.com/golang/groupcache/byteview.go b/vendor/github.com/golang/groupcache/byteview.go
new file mode 100644
index 000000000..035a9ee44
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/byteview.go
@@ -0,0 +1,160 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package groupcache
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "strings"
+)
+
+// A ByteView holds an immutable view of bytes.
+// Internally it wraps either a []byte or a string,
+// but that detail is invisible to callers.
+//
+// A ByteView is meant to be used as a value type, not
+// a pointer (like a time.Time).
+type ByteView struct {
+ // If b is non-nil, b is used, else s is used.
+ b []byte
+ s string
+}
+
+// Len returns the view's length.
+func (v ByteView) Len() int {
+ if v.b != nil {
+ return len(v.b)
+ }
+ return len(v.s)
+}
+
+// ByteSlice returns a copy of the data as a byte slice.
+func (v ByteView) ByteSlice() []byte {
+ if v.b != nil {
+ return cloneBytes(v.b)
+ }
+ return []byte(v.s)
+}
+
+// String returns the data as a string, making a copy if necessary.
+func (v ByteView) String() string {
+ if v.b != nil {
+ return string(v.b)
+ }
+ return v.s
+}
+
+// At returns the byte at index i.
+func (v ByteView) At(i int) byte {
+ if v.b != nil {
+ return v.b[i]
+ }
+ return v.s[i]
+}
+
+// Slice slices the view between the provided from and to indices.
+func (v ByteView) Slice(from, to int) ByteView {
+ if v.b != nil {
+ return ByteView{b: v.b[from:to]}
+ }
+ return ByteView{s: v.s[from:to]}
+}
+
+// SliceFrom slices the view from the provided index until the end.
+func (v ByteView) SliceFrom(from int) ByteView {
+ if v.b != nil {
+ return ByteView{b: v.b[from:]}
+ }
+ return ByteView{s: v.s[from:]}
+}
+
+// Copy copies b into dest and returns the number of bytes copied.
+func (v ByteView) Copy(dest []byte) int {
+ if v.b != nil {
+ return copy(dest, v.b)
+ }
+ return copy(dest, v.s)
+}
+
+// Equal returns whether the bytes in b are the same as the bytes in
+// b2.
+func (v ByteView) Equal(b2 ByteView) bool {
+ if b2.b == nil {
+ return v.EqualString(b2.s)
+ }
+ return v.EqualBytes(b2.b)
+}
+
+// EqualString returns whether the bytes in b are the same as the bytes
+// in s.
+func (v ByteView) EqualString(s string) bool {
+ if v.b == nil {
+ return v.s == s
+ }
+ l := v.Len()
+ if len(s) != l {
+ return false
+ }
+ for i, bi := range v.b {
+ if bi != s[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// EqualBytes returns whether the bytes in b are the same as the bytes
+// in b2.
+func (v ByteView) EqualBytes(b2 []byte) bool {
+ if v.b != nil {
+ return bytes.Equal(v.b, b2)
+ }
+ l := v.Len()
+ if len(b2) != l {
+ return false
+ }
+ for i, bi := range b2 {
+ if bi != v.s[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// Reader returns an io.ReadSeeker for the bytes in v.
+func (v ByteView) Reader() io.ReadSeeker {
+ if v.b != nil {
+ return bytes.NewReader(v.b)
+ }
+ return strings.NewReader(v.s)
+}
+
+// ReadAt implements io.ReaderAt on the bytes in v.
+func (v ByteView) ReadAt(p []byte, off int64) (n int, err error) {
+ if off < 0 {
+ return 0, errors.New("view: invalid offset")
+ }
+ if off >= int64(v.Len()) {
+ return 0, io.EOF
+ }
+ n = v.SliceFrom(int(off)).Copy(p)
+ if n < len(p) {
+ err = io.EOF
+ }
+ return
+}
diff --git a/vendor/github.com/golang/groupcache/byteview_test.go b/vendor/github.com/golang/groupcache/byteview_test.go
new file mode 100644
index 000000000..9ece00f45
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/byteview_test.go
@@ -0,0 +1,142 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package groupcache
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+func TestByteView(t *testing.T) {
+ for _, s := range []string{"", "x", "yy"} {
+ for _, v := range []ByteView{of([]byte(s)), of(s)} {
+ name := fmt.Sprintf("string %q, view %+v", s, v)
+ if v.Len() != len(s) {
+ t.Errorf("%s: Len = %d; want %d", name, v.Len(), len(s))
+ }
+ if v.String() != s {
+ t.Errorf("%s: String = %q; want %q", name, v.String(), s)
+ }
+ var longDest [3]byte
+ if n := v.Copy(longDest[:]); n != len(s) {
+ t.Errorf("%s: long Copy = %d; want %d", name, n, len(s))
+ }
+ var shortDest [1]byte
+ if n := v.Copy(shortDest[:]); n != min(len(s), 1) {
+ t.Errorf("%s: short Copy = %d; want %d", name, n, min(len(s), 1))
+ }
+ if got, err := ioutil.ReadAll(v.Reader()); err != nil || string(got) != s {
+ t.Errorf("%s: Reader = %q, %v; want %q", name, got, err, s)
+ }
+ if got, err := ioutil.ReadAll(io.NewSectionReader(v, 0, int64(len(s)))); err != nil || string(got) != s {
+ t.Errorf("%s: SectionReader of ReaderAt = %q, %v; want %q", name, got, err, s)
+ }
+ }
+ }
+}
+
+// of returns a byte view of the []byte or string in x.
+func of(x interface{}) ByteView {
+ if bytes, ok := x.([]byte); ok {
+ return ByteView{b: bytes}
+ }
+ return ByteView{s: x.(string)}
+}
+
+func TestByteViewEqual(t *testing.T) {
+ tests := []struct {
+ a interface{} // string or []byte
+ b interface{} // string or []byte
+ want bool
+ }{
+ {"x", "x", true},
+ {"x", "y", false},
+ {"x", "yy", false},
+ {[]byte("x"), []byte("x"), true},
+ {[]byte("x"), []byte("y"), false},
+ {[]byte("x"), []byte("yy"), false},
+ {[]byte("x"), "x", true},
+ {[]byte("x"), "y", false},
+ {[]byte("x"), "yy", false},
+ {"x", []byte("x"), true},
+ {"x", []byte("y"), false},
+ {"x", []byte("yy"), false},
+ }
+ for i, tt := range tests {
+ va := of(tt.a)
+ if bytes, ok := tt.b.([]byte); ok {
+ if got := va.EqualBytes(bytes); got != tt.want {
+ t.Errorf("%d. EqualBytes = %v; want %v", i, got, tt.want)
+ }
+ } else {
+ if got := va.EqualString(tt.b.(string)); got != tt.want {
+ t.Errorf("%d. EqualString = %v; want %v", i, got, tt.want)
+ }
+ }
+ if got := va.Equal(of(tt.b)); got != tt.want {
+ t.Errorf("%d. Equal = %v; want %v", i, got, tt.want)
+ }
+ }
+}
+
+func TestByteViewSlice(t *testing.T) {
+ tests := []struct {
+ in string
+ from int
+ to interface{} // nil to mean the end (SliceFrom); else int
+ want string
+ }{
+ {
+ in: "abc",
+ from: 1,
+ to: 2,
+ want: "b",
+ },
+ {
+ in: "abc",
+ from: 1,
+ want: "bc",
+ },
+ {
+ in: "abc",
+ to: 2,
+ want: "ab",
+ },
+ }
+ for i, tt := range tests {
+ for _, v := range []ByteView{of([]byte(tt.in)), of(tt.in)} {
+ name := fmt.Sprintf("test %d, view %+v", i, v)
+ if tt.to != nil {
+ v = v.Slice(tt.from, tt.to.(int))
+ } else {
+ v = v.SliceFrom(tt.from)
+ }
+ if v.String() != tt.want {
+ t.Errorf("%s: got %q; want %q", name, v.String(), tt.want)
+ }
+ }
+ }
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
diff --git a/vendor/github.com/golang/groupcache/consistenthash/consistenthash.go b/vendor/github.com/golang/groupcache/consistenthash/consistenthash.go
new file mode 100644
index 000000000..a9c56f076
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/consistenthash/consistenthash.go
@@ -0,0 +1,81 @@
+/*
+Copyright 2013 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package consistenthash provides an implementation of a ring hash.
+package consistenthash
+
+import (
+ "hash/crc32"
+ "sort"
+ "strconv"
+)
+
+type Hash func(data []byte) uint32
+
+type Map struct {
+ hash Hash
+ replicas int
+ keys []int // Sorted
+ hashMap map[int]string
+}
+
+func New(replicas int, fn Hash) *Map {
+ m := &Map{
+ replicas: replicas,
+ hash: fn,
+ hashMap: make(map[int]string),
+ }
+ if m.hash == nil {
+ m.hash = crc32.ChecksumIEEE
+ }
+ return m
+}
+
+// Returns true if there are no items available.
+func (m *Map) IsEmpty() bool {
+ return len(m.keys) == 0
+}
+
+// Adds some keys to the hash.
+func (m *Map) Add(keys ...string) {
+ for _, key := range keys {
+ for i := 0; i < m.replicas; i++ {
+ hash := int(m.hash([]byte(strconv.Itoa(i) + key)))
+ m.keys = append(m.keys, hash)
+ m.hashMap[hash] = key
+ }
+ }
+ sort.Ints(m.keys)
+}
+
+// Gets the closest item in the hash to the provided key.
+func (m *Map) Get(key string) string {
+ if m.IsEmpty() {
+ return ""
+ }
+
+ hash := int(m.hash([]byte(key)))
+
+ // Binary search for appropriate replica.
+ idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash })
+
+ // Means we have cycled back to the first replica.
+ if idx == len(m.keys) {
+ idx = 0
+ }
+
+ return m.hashMap[m.keys[idx]]
+}
diff --git a/vendor/github.com/golang/groupcache/consistenthash/consistenthash_test.go b/vendor/github.com/golang/groupcache/consistenthash/consistenthash_test.go
new file mode 100644
index 000000000..1a37fd7ff
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/consistenthash/consistenthash_test.go
@@ -0,0 +1,110 @@
+/*
+Copyright 2013 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package consistenthash
+
+import (
+ "fmt"
+ "strconv"
+ "testing"
+)
+
+func TestHashing(t *testing.T) {
+
+ // Override the hash function to return easier to reason about values. Assumes
+ // the keys can be converted to an integer.
+ hash := New(3, func(key []byte) uint32 {
+ i, err := strconv.Atoi(string(key))
+ if err != nil {
+ panic(err)
+ }
+ return uint32(i)
+ })
+
+ // Given the above hash function, this will give replicas with "hashes":
+ // 2, 4, 6, 12, 14, 16, 22, 24, 26
+ hash.Add("6", "4", "2")
+
+ testCases := map[string]string{
+ "2": "2",
+ "11": "2",
+ "23": "4",
+ "27": "2",
+ }
+
+ for k, v := range testCases {
+ if hash.Get(k) != v {
+ t.Errorf("Asking for %s, should have yielded %s", k, v)
+ }
+ }
+
+ // Adds 8, 18, 28
+ hash.Add("8")
+
+ // 27 should now map to 8.
+ testCases["27"] = "8"
+
+ for k, v := range testCases {
+ if hash.Get(k) != v {
+ t.Errorf("Asking for %s, should have yielded %s", k, v)
+ }
+ }
+
+}
+
+func TestConsistency(t *testing.T) {
+ hash1 := New(1, nil)
+ hash2 := New(1, nil)
+
+ hash1.Add("Bill", "Bob", "Bonny")
+ hash2.Add("Bob", "Bonny", "Bill")
+
+ if hash1.Get("Ben") != hash2.Get("Ben") {
+ t.Errorf("Fetching 'Ben' from both hashes should be the same")
+ }
+
+ hash2.Add("Becky", "Ben", "Bobby")
+
+ if hash1.Get("Ben") != hash2.Get("Ben") ||
+ hash1.Get("Bob") != hash2.Get("Bob") ||
+ hash1.Get("Bonny") != hash2.Get("Bonny") {
+ t.Errorf("Direct matches should always return the same entry")
+ }
+
+}
+
+func BenchmarkGet8(b *testing.B) { benchmarkGet(b, 8) }
+func BenchmarkGet32(b *testing.B) { benchmarkGet(b, 32) }
+func BenchmarkGet128(b *testing.B) { benchmarkGet(b, 128) }
+func BenchmarkGet512(b *testing.B) { benchmarkGet(b, 512) }
+
+func benchmarkGet(b *testing.B, shards int) {
+
+ hash := New(50, nil)
+
+ var buckets []string
+ for i := 0; i < shards; i++ {
+ buckets = append(buckets, fmt.Sprintf("shard-%d", i))
+ }
+
+ hash.Add(buckets...)
+
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ hash.Get(buckets[i&(shards-1)])
+ }
+}
diff --git a/vendor/github.com/golang/groupcache/groupcache.go b/vendor/github.com/golang/groupcache/groupcache.go
new file mode 100644
index 000000000..40410a0cc
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/groupcache.go
@@ -0,0 +1,489 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package groupcache provides a data loading mechanism with caching
+// and de-duplication that works across a set of peer processes.
+//
+// Each data Get first consults its local cache, otherwise delegates
+// to the requested key's canonical owner, which then checks its cache
+// or finally gets the data. In the common case, many concurrent
+// cache misses across a set of peers for the same key result in just
+// one cache fill.
+package groupcache
+
+import (
+ "errors"
+ "math/rand"
+ "strconv"
+ "sync"
+ "sync/atomic"
+
+ pb "github.com/golang/groupcache/groupcachepb"
+ "github.com/golang/groupcache/lru"
+ "github.com/golang/groupcache/singleflight"
+)
+
+// A Getter loads data for a key.
+type Getter interface {
+ // Get returns the value identified by key, populating dest.
+ //
+ // The returned data must be unversioned. That is, key must
+ // uniquely describe the loaded data, without an implicit
+ // current time, and without relying on cache expiration
+ // mechanisms.
+ Get(ctx Context, key string, dest Sink) error
+}
+
+// A GetterFunc implements Getter with a function.
+type GetterFunc func(ctx Context, key string, dest Sink) error
+
+func (f GetterFunc) Get(ctx Context, key string, dest Sink) error {
+ return f(ctx, key, dest)
+}
+
+var (
+ mu sync.RWMutex
+ groups = make(map[string]*Group)
+
+ initPeerServerOnce sync.Once
+ initPeerServer func()
+)
+
+// GetGroup returns the named group previously created with NewGroup, or
+// nil if there's no such group.
+func GetGroup(name string) *Group {
+ mu.RLock()
+ g := groups[name]
+ mu.RUnlock()
+ return g
+}
+
+// NewGroup creates a coordinated group-aware Getter from a Getter.
+//
+// The returned Getter tries (but does not guarantee) to run only one
+// Get call at once for a given key across an entire set of peer
+// processes. Concurrent callers both in the local process and in
+// other processes receive copies of the answer once the original Get
+// completes.
+//
+// The group name must be unique for each getter.
+func NewGroup(name string, cacheBytes int64, getter Getter) *Group {
+ return newGroup(name, cacheBytes, getter, nil)
+}
+
+// If peers is nil, the peerPicker is called via a sync.Once to initialize it.
+func newGroup(name string, cacheBytes int64, getter Getter, peers PeerPicker) *Group {
+ if getter == nil {
+ panic("nil Getter")
+ }
+ mu.Lock()
+ defer mu.Unlock()
+ initPeerServerOnce.Do(callInitPeerServer)
+ if _, dup := groups[name]; dup {
+ panic("duplicate registration of group " + name)
+ }
+ g := &Group{
+ name: name,
+ getter: getter,
+ peers: peers,
+ cacheBytes: cacheBytes,
+ loadGroup: &singleflight.Group{},
+ }
+ if fn := newGroupHook; fn != nil {
+ fn(g)
+ }
+ groups[name] = g
+ return g
+}
+
+// newGroupHook, if non-nil, is called right after a new group is created.
+var newGroupHook func(*Group)
+
+// RegisterNewGroupHook registers a hook that is run each time
+// a group is created.
+func RegisterNewGroupHook(fn func(*Group)) {
+ if newGroupHook != nil {
+ panic("RegisterNewGroupHook called more than once")
+ }
+ newGroupHook = fn
+}
+
+// RegisterServerStart registers a hook that is run when the first
+// group is created.
+func RegisterServerStart(fn func()) {
+ if initPeerServer != nil {
+ panic("RegisterServerStart called more than once")
+ }
+ initPeerServer = fn
+}
+
+func callInitPeerServer() {
+ if initPeerServer != nil {
+ initPeerServer()
+ }
+}
+
+// A Group is a cache namespace and associated data loaded spread over
+// a group of 1 or more machines.
+type Group struct {
+ name string
+ getter Getter
+ peersOnce sync.Once
+ peers PeerPicker
+ cacheBytes int64 // limit for sum of mainCache and hotCache size
+
+ // mainCache is a cache of the keys for which this process
+ // (amongst its peers) is authorative. That is, this cache
+ // contains keys which consistent hash on to this process's
+ // peer number.
+ mainCache cache
+
+ // hotCache contains keys/values for which this peer is not
+ // authorative (otherwise they would be in mainCache), but
+ // are popular enough to warrant mirroring in this process to
+ // avoid going over the network to fetch from a peer. Having
+ // a hotCache avoids network hotspotting, where a peer's
+ // network card could become the bottleneck on a popular key.
+ // This cache is used sparingly to maximize the total number
+ // of key/value pairs that can be stored globally.
+ hotCache cache
+
+ // loadGroup ensures that each key is only fetched once
+ // (either locally or remotely), regardless of the number of
+ // concurrent callers.
+ loadGroup flightGroup
+
+ // Stats are statistics on the group.
+ Stats Stats
+}
+
+// flightGroup is defined as an interface which flightgroup.Group
+// satisfies. We define this so that we may test with an alternate
+// implementation.
+type flightGroup interface {
+ // Done is called when Do is done.
+ Do(key string, fn func() (interface{}, error)) (interface{}, error)
+}
+
+// Stats are per-group statistics.
+type Stats struct {
+ Gets AtomicInt // any Get request, including from peers
+ CacheHits AtomicInt // either cache was good
+ PeerLoads AtomicInt // either remote load or remote cache hit (not an error)
+ PeerErrors AtomicInt
+ Loads AtomicInt // (gets - cacheHits)
+ LoadsDeduped AtomicInt // after singleflight
+ LocalLoads AtomicInt // total good local loads
+ LocalLoadErrs AtomicInt // total bad local loads
+ ServerRequests AtomicInt // gets that came over the network from peers
+}
+
+// Name returns the name of the group.
+func (g *Group) Name() string {
+ return g.name
+}
+
+func (g *Group) initPeers() {
+ if g.peers == nil {
+ g.peers = getPeers()
+ }
+}
+
+func (g *Group) Get(ctx Context, key string, dest Sink) error {
+ g.peersOnce.Do(g.initPeers)
+ g.Stats.Gets.Add(1)
+ if dest == nil {
+ return errors.New("groupcache: nil dest Sink")
+ }
+ value, cacheHit := g.lookupCache(key)
+
+ if cacheHit {
+ g.Stats.CacheHits.Add(1)
+ return setSinkView(dest, value)
+ }
+
+ // Optimization to avoid double unmarshalling or copying: keep
+ // track of whether the dest was already populated. One caller
+ // (if local) will set this; the losers will not. The common
+ // case will likely be one caller.
+ destPopulated := false
+ value, destPopulated, err := g.load(ctx, key, dest)
+ if err != nil {
+ return err
+ }
+ if destPopulated {
+ return nil
+ }
+ return setSinkView(dest, value)
+}
+
+// load loads key either by invoking the getter locally or by sending it to another machine.
+func (g *Group) load(ctx Context, key string, dest Sink) (value ByteView, destPopulated bool, err error) {
+ g.Stats.Loads.Add(1)
+ viewi, err := g.loadGroup.Do(key, func() (interface{}, error) {
+ // Check the cache again because singleflight can only dedup calls
+ // that overlap concurrently. It's possible for 2 concurrent
+ // requests to miss the cache, resulting in 2 load() calls. An
+ // unfortunate goroutine scheduling would result in this callback
+ // being run twice, serially. If we don't check the cache again,
+ // cache.nbytes would be incremented below even though there will
+ // be only one entry for this key.
+ //
+ // Consider the following serialized event ordering for two
+ // goroutines in which this callback gets called twice for hte
+ // same key:
+ // 1: Get("key")
+ // 2: Get("key")
+ // 1: lookupCache("key")
+ // 2: lookupCache("key")
+ // 1: load("key")
+ // 2: load("key")
+ // 1: loadGroup.Do("key", fn)
+ // 1: fn()
+ // 2: loadGroup.Do("key", fn)
+ // 2: fn()
+ if value, cacheHit := g.lookupCache(key); cacheHit {
+ g.Stats.CacheHits.Add(1)
+ return value, nil
+ }
+ g.Stats.LoadsDeduped.Add(1)
+ var value ByteView
+ var err error
+ if peer, ok := g.peers.PickPeer(key); ok {
+ value, err = g.getFromPeer(ctx, peer, key)
+ if err == nil {
+ g.Stats.PeerLoads.Add(1)
+ return value, nil
+ }
+ g.Stats.PeerErrors.Add(1)
+ // TODO(bradfitz): log the peer's error? keep
+ // log of the past few for /groupcachez? It's
+ // probably boring (normal task movement), so not
+ // worth logging I imagine.
+ }
+ value, err = g.getLocally(ctx, key, dest)
+ if err != nil {
+ g.Stats.LocalLoadErrs.Add(1)
+ return nil, err
+ }
+ g.Stats.LocalLoads.Add(1)
+ destPopulated = true // only one caller of load gets this return value
+ g.populateCache(key, value, &g.mainCache)
+ return value, nil
+ })
+ if err == nil {
+ value = viewi.(ByteView)
+ }
+ return
+}
+
+func (g *Group) getLocally(ctx Context, key string, dest Sink) (ByteView, error) {
+ err := g.getter.Get(ctx, key, dest)
+ if err != nil {
+ return ByteView{}, err
+ }
+ return dest.view()
+}
+
+func (g *Group) getFromPeer(ctx Context, peer ProtoGetter, key string) (ByteView, error) {
+ req := &pb.GetRequest{
+ Group: &g.name,
+ Key: &key,
+ }
+ res := &pb.GetResponse{}
+ err := peer.Get(ctx, req, res)
+ if err != nil {
+ return ByteView{}, err
+ }
+ value := ByteView{b: res.Value}
+ // TODO(bradfitz): use res.MinuteQps or something smart to
+ // conditionally populate hotCache. For now just do it some
+ // percentage of the time.
+ if rand.Intn(10) == 0 {
+ g.populateCache(key, value, &g.hotCache)
+ }
+ return value, nil
+}
+
+func (g *Group) lookupCache(key string) (value ByteView, ok bool) {
+ if g.cacheBytes <= 0 {
+ return
+ }
+ value, ok = g.mainCache.get(key)
+ if ok {
+ return
+ }
+ value, ok = g.hotCache.get(key)
+ return
+}
+
+func (g *Group) populateCache(key string, value ByteView, cache *cache) {
+ if g.cacheBytes <= 0 {
+ return
+ }
+ cache.add(key, value)
+
+ // Evict items from cache(s) if necessary.
+ for {
+ mainBytes := g.mainCache.bytes()
+ hotBytes := g.hotCache.bytes()
+ if mainBytes+hotBytes <= g.cacheBytes {
+ return
+ }
+
+ // TODO(bradfitz): this is good-enough-for-now logic.
+ // It should be something based on measurements and/or
+ // respecting the costs of different resources.
+ victim := &g.mainCache
+ if hotBytes > mainBytes/8 {
+ victim = &g.hotCache
+ }
+ victim.removeOldest()
+ }
+}
+
+// CacheType represents a type of cache.
+type CacheType int
+
+const (
+ // The MainCache is the cache for items that this peer is the
+ // owner for.
+ MainCache CacheType = iota + 1
+
+ // The HotCache is the cache for items that seem popular
+ // enough to replicate to this node, even though it's not the
+ // owner.
+ HotCache
+)
+
+// CacheStats returns stats about the provided cache within the group.
+func (g *Group) CacheStats(which CacheType) CacheStats {
+ switch which {
+ case MainCache:
+ return g.mainCache.stats()
+ case HotCache:
+ return g.hotCache.stats()
+ default:
+ return CacheStats{}
+ }
+}
+
+// cache is a wrapper around an *lru.Cache that adds synchronization,
+// makes values always be ByteView, and counts the size of all keys and
+// values.
+type cache struct {
+ mu sync.RWMutex
+ nbytes int64 // of all keys and values
+ lru *lru.Cache
+ nhit, nget int64
+ nevict int64 // number of evictions
+}
+
+func (c *cache) stats() CacheStats {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return CacheStats{
+ Bytes: c.nbytes,
+ Items: c.itemsLocked(),
+ Gets: c.nget,
+ Hits: c.nhit,
+ Evictions: c.nevict,
+ }
+}
+
+func (c *cache) add(key string, value ByteView) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if c.lru == nil {
+ c.lru = &lru.Cache{
+ OnEvicted: func(key lru.Key, value interface{}) {
+ val := value.(ByteView)
+ c.nbytes -= int64(len(key.(string))) + int64(val.Len())
+ c.nevict++
+ },
+ }
+ }
+ c.lru.Add(key, value)
+ c.nbytes += int64(len(key)) + int64(value.Len())
+}
+
+func (c *cache) get(key string) (value ByteView, ok bool) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.nget++
+ if c.lru == nil {
+ return
+ }
+ vi, ok := c.lru.Get(key)
+ if !ok {
+ return
+ }
+ c.nhit++
+ return vi.(ByteView), true
+}
+
+func (c *cache) removeOldest() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if c.lru != nil {
+ c.lru.RemoveOldest()
+ }
+}
+
+func (c *cache) bytes() int64 {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return c.nbytes
+}
+
+func (c *cache) items() int64 {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return c.itemsLocked()
+}
+
+func (c *cache) itemsLocked() int64 {
+ if c.lru == nil {
+ return 0
+ }
+ return int64(c.lru.Len())
+}
+
+// An AtomicInt is an int64 to be accessed atomically.
+type AtomicInt int64
+
+// Add atomically adds n to i.
+func (i *AtomicInt) Add(n int64) {
+ atomic.AddInt64((*int64)(i), n)
+}
+
+// Get atomically gets the value of i.
+func (i *AtomicInt) Get() int64 {
+ return atomic.LoadInt64((*int64)(i))
+}
+
+func (i *AtomicInt) String() string {
+ return strconv.FormatInt(i.Get(), 10)
+}
+
+// CacheStats are returned by stats accessors on Group.
+type CacheStats struct {
+ Bytes int64
+ Items int64
+ Gets int64
+ Hits int64
+ Evictions int64
+}
diff --git a/vendor/github.com/golang/groupcache/groupcache_test.go b/vendor/github.com/golang/groupcache/groupcache_test.go
new file mode 100644
index 000000000..3a4ecc2cc
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/groupcache_test.go
@@ -0,0 +1,447 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Tests for groupcache.
+
+package groupcache
+
+import (
+ "errors"
+ "fmt"
+ "hash/crc32"
+ "math/rand"
+ "reflect"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/golang/protobuf/proto"
+
+ pb "github.com/golang/groupcache/groupcachepb"
+ testpb "github.com/golang/groupcache/testpb"
+)
+
+var (
+ once sync.Once
+ stringGroup, protoGroup Getter
+
+ stringc = make(chan string)
+
+ dummyCtx Context
+
+ // cacheFills is the number of times stringGroup or
+ // protoGroup's Getter have been called. Read using the
+ // cacheFills function.
+ cacheFills AtomicInt
+)
+
+const (
+ stringGroupName = "string-group"
+ protoGroupName = "proto-group"
+ testMessageType = "google3/net/groupcache/go/test_proto.TestMessage"
+ fromChan = "from-chan"
+ cacheSize = 1 << 20
+)
+
+func testSetup() {
+ stringGroup = NewGroup(stringGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error {
+ if key == fromChan {
+ key = <-stringc
+ }
+ cacheFills.Add(1)
+ return dest.SetString("ECHO:" + key)
+ }))
+
+ protoGroup = NewGroup(protoGroupName, cacheSize, GetterFunc(func(_ Context, key string, dest Sink) error {
+ if key == fromChan {
+ key = <-stringc
+ }
+ cacheFills.Add(1)
+ return dest.SetProto(&testpb.TestMessage{
+ Name: proto.String("ECHO:" + key),
+ City: proto.String("SOME-CITY"),
+ })
+ }))
+}
+
+// tests that a Getter's Get method is only called once with two
+// outstanding callers. This is the string variant.
+func TestGetDupSuppressString(t *testing.T) {
+ once.Do(testSetup)
+ // Start two getters. The first should block (waiting reading
+ // from stringc) and the second should latch on to the first
+ // one.
+ resc := make(chan string, 2)
+ for i := 0; i < 2; i++ {
+ go func() {
+ var s string
+ if err := stringGroup.Get(dummyCtx, fromChan, StringSink(&s)); err != nil {
+ resc <- "ERROR:" + err.Error()
+ return
+ }
+ resc <- s
+ }()
+ }
+
+ // Wait a bit so both goroutines get merged together via
+ // singleflight.
+ // TODO(bradfitz): decide whether there are any non-offensive
+ // debug/test hooks that could be added to singleflight to
+ // make a sleep here unnecessary.
+ time.Sleep(250 * time.Millisecond)
+
+ // Unblock the first getter, which should unblock the second
+ // as well.
+ stringc <- "foo"
+
+ for i := 0; i < 2; i++ {
+ select {
+ case v := <-resc:
+ if v != "ECHO:foo" {
+ t.Errorf("got %q; want %q", v, "ECHO:foo")
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting on getter #%d of 2", i+1)
+ }
+ }
+}
+
+// tests that a Getter's Get method is only called once with two
+// outstanding callers. This is the proto variant.
+func TestGetDupSuppressProto(t *testing.T) {
+ once.Do(testSetup)
+ // Start two getters. The first should block (waiting reading
+ // from stringc) and the second should latch on to the first
+ // one.
+ resc := make(chan *testpb.TestMessage, 2)
+ for i := 0; i < 2; i++ {
+ go func() {
+ tm := new(testpb.TestMessage)
+ if err := protoGroup.Get(dummyCtx, fromChan, ProtoSink(tm)); err != nil {
+ tm.Name = proto.String("ERROR:" + err.Error())
+ }
+ resc <- tm
+ }()
+ }
+
+ // Wait a bit so both goroutines get merged together via
+ // singleflight.
+ // TODO(bradfitz): decide whether there are any non-offensive
+ // debug/test hooks that could be added to singleflight to
+ // make a sleep here unnecessary.
+ time.Sleep(250 * time.Millisecond)
+
+ // Unblock the first getter, which should unblock the second
+ // as well.
+ stringc <- "Fluffy"
+ want := &testpb.TestMessage{
+ Name: proto.String("ECHO:Fluffy"),
+ City: proto.String("SOME-CITY"),
+ }
+ for i := 0; i < 2; i++ {
+ select {
+ case v := <-resc:
+ if !reflect.DeepEqual(v, want) {
+ t.Errorf(" Got: %v\nWant: %v", proto.CompactTextString(v), proto.CompactTextString(want))
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("timeout waiting on getter #%d of 2", i+1)
+ }
+ }
+}
+
+func countFills(f func()) int64 {
+ fills0 := cacheFills.Get()
+ f()
+ return cacheFills.Get() - fills0
+}
+
+func TestCaching(t *testing.T) {
+ once.Do(testSetup)
+ fills := countFills(func() {
+ for i := 0; i < 10; i++ {
+ var s string
+ if err := stringGroup.Get(dummyCtx, "TestCaching-key", StringSink(&s)); err != nil {
+ t.Fatal(err)
+ }
+ }
+ })
+ if fills != 1 {
+ t.Errorf("expected 1 cache fill; got %d", fills)
+ }
+}
+
+func TestCacheEviction(t *testing.T) {
+ once.Do(testSetup)
+ testKey := "TestCacheEviction-key"
+ getTestKey := func() {
+ var res string
+ for i := 0; i < 10; i++ {
+ if err := stringGroup.Get(dummyCtx, testKey, StringSink(&res)); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+ fills := countFills(getTestKey)
+ if fills != 1 {
+ t.Fatalf("expected 1 cache fill; got %d", fills)
+ }
+
+ g := stringGroup.(*Group)
+ evict0 := g.mainCache.nevict
+
+ // Trash the cache with other keys.
+ var bytesFlooded int64
+ // cacheSize/len(testKey) is approximate
+ for bytesFlooded < cacheSize+1024 {
+ var res string
+ key := fmt.Sprintf("dummy-key-%d", bytesFlooded)
+ stringGroup.Get(dummyCtx, key, StringSink(&res))
+ bytesFlooded += int64(len(key) + len(res))
+ }
+ evicts := g.mainCache.nevict - evict0
+ if evicts <= 0 {
+ t.Errorf("evicts = %v; want more than 0", evicts)
+ }
+
+ // Test that the key is gone.
+ fills = countFills(getTestKey)
+ if fills != 1 {
+ t.Fatalf("expected 1 cache fill after cache trashing; got %d", fills)
+ }
+}
+
+type fakePeer struct {
+ hits int
+ fail bool
+}
+
+func (p *fakePeer) Get(_ Context, in *pb.GetRequest, out *pb.GetResponse) error {
+ p.hits++
+ if p.fail {
+ return errors.New("simulated error from peer")
+ }
+ out.Value = []byte("got:" + in.GetKey())
+ return nil
+}
+
+type fakePeers []ProtoGetter
+
+func (p fakePeers) PickPeer(key string) (peer ProtoGetter, ok bool) {
+ if len(p) == 0 {
+ return
+ }
+ n := crc32.Checksum([]byte(key), crc32.IEEETable) % uint32(len(p))
+ return p[n], p[n] != nil
+}
+
+// tests that peers (virtual, in-process) are hit, and how much.
+func TestPeers(t *testing.T) {
+ once.Do(testSetup)
+ rand.Seed(123)
+ peer0 := &fakePeer{}
+ peer1 := &fakePeer{}
+ peer2 := &fakePeer{}
+ peerList := fakePeers([]ProtoGetter{peer0, peer1, peer2, nil})
+ const cacheSize = 0 // disabled
+ localHits := 0
+ getter := func(_ Context, key string, dest Sink) error {
+ localHits++
+ return dest.SetString("got:" + key)
+ }
+ testGroup := newGroup("TestPeers-group", cacheSize, GetterFunc(getter), peerList)
+ run := func(name string, n int, wantSummary string) {
+ // Reset counters
+ localHits = 0
+ for _, p := range []*fakePeer{peer0, peer1, peer2} {
+ p.hits = 0
+ }
+
+ for i := 0; i < n; i++ {
+ key := fmt.Sprintf("key-%d", i)
+ want := "got:" + key
+ var got string
+ err := testGroup.Get(dummyCtx, key, StringSink(&got))
+ if err != nil {
+ t.Errorf("%s: error on key %q: %v", name, key, err)
+ continue
+ }
+ if got != want {
+ t.Errorf("%s: for key %q, got %q; want %q", name, key, got, want)
+ }
+ }
+ summary := func() string {
+ return fmt.Sprintf("localHits = %d, peers = %d %d %d", localHits, peer0.hits, peer1.hits, peer2.hits)
+ }
+ if got := summary(); got != wantSummary {
+ t.Errorf("%s: got %q; want %q", name, got, wantSummary)
+ }
+ }
+ resetCacheSize := func(maxBytes int64) {
+ g := testGroup
+ g.cacheBytes = maxBytes
+ g.mainCache = cache{}
+ g.hotCache = cache{}
+ }
+
+ // Base case; peers all up, with no problems.
+ resetCacheSize(1 << 20)
+ run("base", 200, "localHits = 49, peers = 51 49 51")
+
+ // Verify cache was hit. All localHits are gone, and some of
+ // the peer hits (the ones randomly selected to be maybe hot)
+ run("cached_base", 200, "localHits = 0, peers = 49 47 48")
+ resetCacheSize(0)
+
+ // With one of the peers being down.
+ // TODO(bradfitz): on a peer number being unavailable, the
+ // consistent hashing should maybe keep trying others to
+ // spread the load out. Currently it fails back to local
+ // execution if the first consistent-hash slot is unavailable.
+ peerList[0] = nil
+ run("one_peer_down", 200, "localHits = 100, peers = 0 49 51")
+
+ // Failing peer
+ peerList[0] = peer0
+ peer0.fail = true
+ run("peer0_failing", 200, "localHits = 100, peers = 51 49 51")
+}
+
+func TestTruncatingByteSliceTarget(t *testing.T) {
+ var buf [100]byte
+ s := buf[:]
+ if err := stringGroup.Get(dummyCtx, "short", TruncatingByteSliceSink(&s)); err != nil {
+ t.Fatal(err)
+ }
+ if want := "ECHO:short"; string(s) != want {
+ t.Errorf("short key got %q; want %q", s, want)
+ }
+
+ s = buf[:6]
+ if err := stringGroup.Get(dummyCtx, "truncated", TruncatingByteSliceSink(&s)); err != nil {
+ t.Fatal(err)
+ }
+ if want := "ECHO:t"; string(s) != want {
+ t.Errorf("truncated key got %q; want %q", s, want)
+ }
+}
+
+func TestAllocatingByteSliceTarget(t *testing.T) {
+ var dst []byte
+ sink := AllocatingByteSliceSink(&dst)
+
+ inBytes := []byte("some bytes")
+ sink.SetBytes(inBytes)
+ if want := "some bytes"; string(dst) != want {
+ t.Errorf("SetBytes resulted in %q; want %q", dst, want)
+ }
+ v, err := sink.view()
+ if err != nil {
+ t.Fatalf("view after SetBytes failed: %v", err)
+ }
+ if &inBytes[0] == &dst[0] {
+ t.Error("inBytes and dst share memory")
+ }
+ if &inBytes[0] == &v.b[0] {
+ t.Error("inBytes and view share memory")
+ }
+ if &dst[0] == &v.b[0] {
+ t.Error("dst and view share memory")
+ }
+}
+
+// orderedFlightGroup allows the caller to force the schedule of when
+// orig.Do will be called. This is useful to serialize calls such
+// that singleflight cannot dedup them.
+type orderedFlightGroup struct {
+ mu sync.Mutex
+ stage1 chan bool
+ stage2 chan bool
+ orig flightGroup
+}
+
+func (g *orderedFlightGroup) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
+ <-g.stage1
+ <-g.stage2
+ g.mu.Lock()
+ defer g.mu.Unlock()
+ return g.orig.Do(key, fn)
+}
+
+// TestNoDedup tests invariants on the cache size when singleflight is
+// unable to dedup calls.
+func TestNoDedup(t *testing.T) {
+ const testkey = "testkey"
+ const testval = "testval"
+ g := newGroup("testgroup", 1024, GetterFunc(func(_ Context, key string, dest Sink) error {
+ return dest.SetString(testval)
+ }), nil)
+
+ orderedGroup := &orderedFlightGroup{
+ stage1: make(chan bool),
+ stage2: make(chan bool),
+ orig: g.loadGroup,
+ }
+ // Replace loadGroup with our wrapper so we can control when
+ // loadGroup.Do is entered for each concurrent request.
+ g.loadGroup = orderedGroup
+
+ // Issue two idential requests concurrently. Since the cache is
+ // empty, it will miss. Both will enter load(), but we will only
+ // allow one at a time to enter singleflight.Do, so the callback
+ // function will be called twice.
+ resc := make(chan string, 2)
+ for i := 0; i < 2; i++ {
+ go func() {
+ var s string
+ if err := g.Get(dummyCtx, testkey, StringSink(&s)); err != nil {
+ resc <- "ERROR:" + err.Error()
+ return
+ }
+ resc <- s
+ }()
+ }
+
+ // Ensure both goroutines have entered the Do routine. This implies
+ // both concurrent requests have checked the cache, found it empty,
+ // and called load().
+ orderedGroup.stage1 <- true
+ orderedGroup.stage1 <- true
+ orderedGroup.stage2 <- true
+ orderedGroup.stage2 <- true
+
+ for i := 0; i < 2; i++ {
+ if s := <-resc; s != testval {
+ t.Errorf("result is %s want %s", s, testval)
+ }
+ }
+
+ const wantItems = 1
+ if g.mainCache.items() != wantItems {
+ t.Errorf("mainCache has %d items, want %d", g.mainCache.items(), wantItems)
+ }
+
+ // If the singleflight callback doesn't double-check the cache again
+ // upon entry, we would increment nbytes twice but the entry would
+ // only be in the cache once.
+ const wantBytes = int64(len(testkey) + len(testval))
+ if g.mainCache.nbytes != wantBytes {
+ t.Errorf("cache has %d bytes, want %d", g.mainCache.nbytes, wantBytes)
+ }
+}
+
+// TODO(bradfitz): port the Google-internal full integration test into here,
+// using HTTP requests instead of our RPC system.
diff --git a/vendor/github.com/golang/groupcache/groupcachepb/groupcache.pb.go b/vendor/github.com/golang/groupcache/groupcachepb/groupcache.pb.go
new file mode 100644
index 000000000..520d1ee9a
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/groupcachepb/groupcache.pb.go
@@ -0,0 +1,65 @@
+// Code generated by protoc-gen-go.
+// source: groupcache.proto
+// DO NOT EDIT!
+
+package groupcachepb
+
+import proto "github.com/golang/protobuf/proto"
+import json "encoding/json"
+import math "math"
+
+// Reference proto, json, and math imports to suppress error if they are not otherwise used.
+var _ = proto.Marshal
+var _ = &json.SyntaxError{}
+var _ = math.Inf
+
+type GetRequest struct {
+ Group *string `protobuf:"bytes,1,req,name=group" json:"group,omitempty"`
+ Key *string `protobuf:"bytes,2,req,name=key" json:"key,omitempty"`
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *GetRequest) Reset() { *m = GetRequest{} }
+func (m *GetRequest) String() string { return proto.CompactTextString(m) }
+func (*GetRequest) ProtoMessage() {}
+
+func (m *GetRequest) GetGroup() string {
+ if m != nil && m.Group != nil {
+ return *m.Group
+ }
+ return ""
+}
+
+func (m *GetRequest) GetKey() string {
+ if m != nil && m.Key != nil {
+ return *m.Key
+ }
+ return ""
+}
+
+type GetResponse struct {
+ Value []byte `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"`
+ MinuteQps *float64 `protobuf:"fixed64,2,opt,name=minute_qps" json:"minute_qps,omitempty"`
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *GetResponse) Reset() { *m = GetResponse{} }
+func (m *GetResponse) String() string { return proto.CompactTextString(m) }
+func (*GetResponse) ProtoMessage() {}
+
+func (m *GetResponse) GetValue() []byte {
+ if m != nil {
+ return m.Value
+ }
+ return nil
+}
+
+func (m *GetResponse) GetMinuteQps() float64 {
+ if m != nil && m.MinuteQps != nil {
+ return *m.MinuteQps
+ }
+ return 0
+}
+
+func init() {
+}
diff --git a/vendor/github.com/golang/groupcache/groupcachepb/groupcache.proto b/vendor/github.com/golang/groupcache/groupcachepb/groupcache.proto
new file mode 100644
index 000000000..b5bdff94f
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/groupcachepb/groupcache.proto
@@ -0,0 +1,34 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+syntax = "proto2";
+
+package groupcachepb;
+
+message GetRequest {
+ required string group = 1;
+ required string key = 2; // not actually required/guaranteed to be UTF-8
+}
+
+message GetResponse {
+ optional bytes value = 1;
+ optional double minute_qps = 2;
+}
+
+service GroupCache {
+ rpc Get(GetRequest) returns (GetResponse) {
+ };
+}
diff --git a/vendor/github.com/golang/groupcache/http.go b/vendor/github.com/golang/groupcache/http.go
new file mode 100644
index 000000000..14eb345a8
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/http.go
@@ -0,0 +1,227 @@
+/*
+Copyright 2013 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package groupcache
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+ "sync"
+
+ "github.com/golang/groupcache/consistenthash"
+ pb "github.com/golang/groupcache/groupcachepb"
+ "github.com/golang/protobuf/proto"
+)
+
+const defaultBasePath = "/_groupcache/"
+
+const defaultReplicas = 50
+
+// HTTPPool implements PeerPicker for a pool of HTTP peers.
+type HTTPPool struct {
+ // Context optionally specifies a context for the server to use when it
+ // receives a request.
+ // If nil, the server uses a nil Context.
+ Context func(*http.Request) Context
+
+ // Transport optionally specifies an http.RoundTripper for the client
+ // to use when it makes a request.
+ // If nil, the client uses http.DefaultTransport.
+ Transport func(Context) http.RoundTripper
+
+ // this peer's base URL, e.g. "https://example.net:8000"
+ self string
+
+ // opts specifies the options.
+ opts HTTPPoolOptions
+
+ mu sync.Mutex // guards peers and httpGetters
+ peers *consistenthash.Map
+ httpGetters map[string]*httpGetter // keyed by e.g. "http://10.0.0.2:8008"
+}
+
+// HTTPPoolOptions are the configurations of a HTTPPool.
+type HTTPPoolOptions struct {
+ // BasePath specifies the HTTP path that will serve groupcache requests.
+ // If blank, it defaults to "/_groupcache/".
+ BasePath string
+
+ // Replicas specifies the number of key replicas on the consistent hash.
+ // If blank, it defaults to 50.
+ Replicas int
+
+ // HashFn specifies the hash function of the consistent hash.
+ // If blank, it defaults to crc32.ChecksumIEEE.
+ HashFn consistenthash.Hash
+}
+
+// NewHTTPPool initializes an HTTP pool of peers, and registers itself as a PeerPicker.
+// For convenience, it also registers itself as an http.Handler with http.DefaultServeMux.
+// The self argument be a valid base URL that points to the current server,
+// for example "http://example.net:8000".
+func NewHTTPPool(self string) *HTTPPool {
+ p := NewHTTPPoolOpts(self, nil)
+ http.Handle(p.opts.BasePath, p)
+ return p
+}
+
+var httpPoolMade bool
+
+// NewHTTPPoolOpts initializes an HTTP pool of peers with the given options.
+// Unlike NewHTTPPool, this function does not register the created pool as an HTTP handler.
+// The returned *HTTPPool implements http.Handler and must be registered using http.Handle.
+func NewHTTPPoolOpts(self string, o *HTTPPoolOptions) *HTTPPool {
+ if httpPoolMade {
+ panic("groupcache: NewHTTPPool must be called only once")
+ }
+ httpPoolMade = true
+
+ p := &HTTPPool{
+ self: self,
+ httpGetters: make(map[string]*httpGetter),
+ }
+ if o != nil {
+ p.opts = *o
+ }
+ if p.opts.BasePath == "" {
+ p.opts.BasePath = defaultBasePath
+ }
+ if p.opts.Replicas == 0 {
+ p.opts.Replicas = defaultReplicas
+ }
+ p.peers = consistenthash.New(p.opts.Replicas, p.opts.HashFn)
+
+ RegisterPeerPicker(func() PeerPicker { return p })
+ return p
+}
+
+// Set updates the pool's list of peers.
+// Each peer value should be a valid base URL,
+// for example "http://example.net:8000".
+func (p *HTTPPool) Set(peers ...string) {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ p.peers = consistenthash.New(p.opts.Replicas, p.opts.HashFn)
+ p.peers.Add(peers...)
+ p.httpGetters = make(map[string]*httpGetter, len(peers))
+ for _, peer := range peers {
+ p.httpGetters[peer] = &httpGetter{transport: p.Transport, baseURL: peer + p.opts.BasePath}
+ }
+}
+
+func (p *HTTPPool) PickPeer(key string) (ProtoGetter, bool) {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.peers.IsEmpty() {
+ return nil, false
+ }
+ if peer := p.peers.Get(key); peer != p.self {
+ return p.httpGetters[peer], true
+ }
+ return nil, false
+}
+
+func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ // Parse request.
+ if !strings.HasPrefix(r.URL.Path, p.opts.BasePath) {
+ panic("HTTPPool serving unexpected path: " + r.URL.Path)
+ }
+ parts := strings.SplitN(r.URL.Path[len(p.opts.BasePath):], "/", 2)
+ if len(parts) != 2 {
+ http.Error(w, "bad request", http.StatusBadRequest)
+ return
+ }
+ groupName := parts[0]
+ key := parts[1]
+
+ // Fetch the value for this group/key.
+ group := GetGroup(groupName)
+ if group == nil {
+ http.Error(w, "no such group: "+groupName, http.StatusNotFound)
+ return
+ }
+ var ctx Context
+ if p.Context != nil {
+ ctx = p.Context(r)
+ }
+
+ group.Stats.ServerRequests.Add(1)
+ var value []byte
+ err := group.Get(ctx, key, AllocatingByteSliceSink(&value))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ // Write the value to the response body as a proto message.
+ body, err := proto.Marshal(&pb.GetResponse{Value: value})
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ w.Header().Set("Content-Type", "application/x-protobuf")
+ w.Write(body)
+}
+
+type httpGetter struct {
+ transport func(Context) http.RoundTripper
+ baseURL string
+}
+
+var bufferPool = sync.Pool{
+ New: func() interface{} { return new(bytes.Buffer) },
+}
+
+func (h *httpGetter) Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error {
+ u := fmt.Sprintf(
+ "%v%v/%v",
+ h.baseURL,
+ url.QueryEscape(in.GetGroup()),
+ url.QueryEscape(in.GetKey()),
+ )
+ req, err := http.NewRequest("GET", u, nil)
+ if err != nil {
+ return err
+ }
+ tr := http.DefaultTransport
+ if h.transport != nil {
+ tr = h.transport(context)
+ }
+ res, err := tr.RoundTrip(req)
+ if err != nil {
+ return err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return fmt.Errorf("server returned: %v", res.Status)
+ }
+ b := bufferPool.Get().(*bytes.Buffer)
+ b.Reset()
+ defer bufferPool.Put(b)
+ _, err = io.Copy(b, res.Body)
+ if err != nil {
+ return fmt.Errorf("reading response body: %v", err)
+ }
+ err = proto.Unmarshal(b.Bytes(), out)
+ if err != nil {
+ return fmt.Errorf("decoding response body: %v", err)
+ }
+ return nil
+}
diff --git a/vendor/github.com/golang/groupcache/http_test.go b/vendor/github.com/golang/groupcache/http_test.go
new file mode 100644
index 000000000..b42edd7f0
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/http_test.go
@@ -0,0 +1,166 @@
+/*
+Copyright 2013 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package groupcache
+
+import (
+ "errors"
+ "flag"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+var (
+ peerAddrs = flag.String("test_peer_addrs", "", "Comma-separated list of peer addresses; used by TestHTTPPool")
+ peerIndex = flag.Int("test_peer_index", -1, "Index of which peer this child is; used by TestHTTPPool")
+ peerChild = flag.Bool("test_peer_child", false, "True if running as a child process; used by TestHTTPPool")
+)
+
+func TestHTTPPool(t *testing.T) {
+ if *peerChild {
+ beChildForTestHTTPPool()
+ os.Exit(0)
+ }
+
+ const (
+ nChild = 4
+ nGets = 100
+ )
+
+ var childAddr []string
+ for i := 0; i < nChild; i++ {
+ childAddr = append(childAddr, pickFreeAddr(t))
+ }
+
+ var cmds []*exec.Cmd
+ var wg sync.WaitGroup
+ for i := 0; i < nChild; i++ {
+ cmd := exec.Command(os.Args[0],
+ "--test.run=TestHTTPPool",
+ "--test_peer_child",
+ "--test_peer_addrs="+strings.Join(childAddr, ","),
+ "--test_peer_index="+strconv.Itoa(i),
+ )
+ cmds = append(cmds, cmd)
+ wg.Add(1)
+ if err := cmd.Start(); err != nil {
+ t.Fatal("failed to start child process: ", err)
+ }
+ go awaitAddrReady(t, childAddr[i], &wg)
+ }
+ defer func() {
+ for i := 0; i < nChild; i++ {
+ if cmds[i].Process != nil {
+ cmds[i].Process.Kill()
+ }
+ }
+ }()
+ wg.Wait()
+
+ // Use a dummy self address so that we don't handle gets in-process.
+ p := NewHTTPPool("should-be-ignored")
+ p.Set(addrToURL(childAddr)...)
+
+ // Dummy getter function. Gets should go to children only.
+ // The only time this process will handle a get is when the
+ // children can't be contacted for some reason.
+ getter := GetterFunc(func(ctx Context, key string, dest Sink) error {
+ return errors.New("parent getter called; something's wrong")
+ })
+ g := NewGroup("httpPoolTest", 1<<20, getter)
+
+ for _, key := range testKeys(nGets) {
+ var value string
+ if err := g.Get(nil, key, StringSink(&value)); err != nil {
+ t.Fatal(err)
+ }
+ if suffix := ":" + key; !strings.HasSuffix(value, suffix) {
+ t.Errorf("Get(%q) = %q, want value ending in %q", key, value, suffix)
+ }
+ t.Logf("Get key=%q, value=%q (peer:key)", key, value)
+ }
+}
+
+func testKeys(n int) (keys []string) {
+ keys = make([]string, n)
+ for i := range keys {
+ keys[i] = strconv.Itoa(i)
+ }
+ return
+}
+
+func beChildForTestHTTPPool() {
+ addrs := strings.Split(*peerAddrs, ",")
+
+ p := NewHTTPPool("http://" + addrs[*peerIndex])
+ p.Set(addrToURL(addrs)...)
+
+ getter := GetterFunc(func(ctx Context, key string, dest Sink) error {
+ dest.SetString(strconv.Itoa(*peerIndex) + ":" + key)
+ return nil
+ })
+ NewGroup("httpPoolTest", 1<<20, getter)
+
+ log.Fatal(http.ListenAndServe(addrs[*peerIndex], p))
+}
+
+// This is racy. Another process could swoop in and steal the port between the
+// call to this function and the next listen call. Should be okay though.
+// The proper way would be to pass the l.File() as ExtraFiles to the child
+// process, and then close your copy once the child starts.
+func pickFreeAddr(t *testing.T) string {
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer l.Close()
+ return l.Addr().String()
+}
+
+func addrToURL(addr []string) []string {
+ url := make([]string, len(addr))
+ for i := range addr {
+ url[i] = "http://" + addr[i]
+ }
+ return url
+}
+
+func awaitAddrReady(t *testing.T, addr string, wg *sync.WaitGroup) {
+ defer wg.Done()
+ const max = 1 * time.Second
+ tries := 0
+ for {
+ tries++
+ c, err := net.Dial("tcp", addr)
+ if err == nil {
+ c.Close()
+ return
+ }
+ delay := time.Duration(tries) * 25 * time.Millisecond
+ if delay > max {
+ delay = max
+ }
+ time.Sleep(delay)
+ }
+}
diff --git a/vendor/github.com/golang/groupcache/lru/lru_test.go b/vendor/github.com/golang/groupcache/lru/lru_test.go
new file mode 100644
index 000000000..98a2656e8
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/lru/lru_test.go
@@ -0,0 +1,73 @@
+/*
+Copyright 2013 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package lru
+
+import (
+ "testing"
+)
+
+type simpleStruct struct {
+ int
+ string
+}
+
+type complexStruct struct {
+ int
+ simpleStruct
+}
+
+var getTests = []struct {
+ name string
+ keyToAdd interface{}
+ keyToGet interface{}
+ expectedOk bool
+}{
+ {"string_hit", "myKey", "myKey", true},
+ {"string_miss", "myKey", "nonsense", false},
+ {"simple_struct_hit", simpleStruct{1, "two"}, simpleStruct{1, "two"}, true},
+ {"simeple_struct_miss", simpleStruct{1, "two"}, simpleStruct{0, "noway"}, false},
+ {"complex_struct_hit", complexStruct{1, simpleStruct{2, "three"}},
+ complexStruct{1, simpleStruct{2, "three"}}, true},
+}
+
+func TestGet(t *testing.T) {
+ for _, tt := range getTests {
+ lru := New(0)
+ lru.Add(tt.keyToAdd, 1234)
+ val, ok := lru.Get(tt.keyToGet)
+ if ok != tt.expectedOk {
+ t.Fatalf("%s: cache hit = %v; want %v", tt.name, ok, !ok)
+ } else if ok && val != 1234 {
+ t.Fatalf("%s expected get to return 1234 but got %v", tt.name, val)
+ }
+ }
+}
+
+func TestRemove(t *testing.T) {
+ lru := New(0)
+ lru.Add("myKey", 1234)
+ if val, ok := lru.Get("myKey"); !ok {
+ t.Fatal("TestRemove returned no match")
+ } else if val != 1234 {
+ t.Fatalf("TestRemove failed. Expected %d, got %v", 1234, val)
+ }
+
+ lru.Remove("myKey")
+ if _, ok := lru.Get("myKey"); ok {
+ t.Fatal("TestRemove returned a removed entry")
+ }
+}
diff --git a/vendor/github.com/golang/groupcache/peers.go b/vendor/github.com/golang/groupcache/peers.go
new file mode 100644
index 000000000..a74a79b8f
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/peers.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// peers.go defines how processes find and communicate with their peers.
+
+package groupcache
+
+import (
+ pb "github.com/golang/groupcache/groupcachepb"
+)
+
+// Context is an opaque value passed through calls to the
+// ProtoGetter. It may be nil if your ProtoGetter implementation does
+// not require a context.
+type Context interface{}
+
+// ProtoGetter is the interface that must be implemented by a peer.
+type ProtoGetter interface {
+ Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error
+}
+
+// PeerPicker is the interface that must be implemented to locate
+// the peer that owns a specific key.
+type PeerPicker interface {
+ // PickPeer returns the peer that owns the specific key
+ // and true to indicate that a remote peer was nominated.
+ // It returns nil, false if the key owner is the current peer.
+ PickPeer(key string) (peer ProtoGetter, ok bool)
+}
+
+// NoPeers is an implementation of PeerPicker that never finds a peer.
+type NoPeers struct{}
+
+func (NoPeers) PickPeer(key string) (peer ProtoGetter, ok bool) { return }
+
+var (
+ portPicker func() PeerPicker
+)
+
+// RegisterPeerPicker registers the peer initialization function.
+// It is called once, when the first group is created.
+func RegisterPeerPicker(fn func() PeerPicker) {
+ if portPicker != nil {
+ panic("RegisterPeerPicker called more than once")
+ }
+ portPicker = fn
+}
+
+func getPeers() PeerPicker {
+ if portPicker == nil {
+ return NoPeers{}
+ }
+ pk := portPicker()
+ if pk == nil {
+ pk = NoPeers{}
+ }
+ return pk
+}
diff --git a/vendor/github.com/golang/groupcache/singleflight/singleflight.go b/vendor/github.com/golang/groupcache/singleflight/singleflight.go
new file mode 100644
index 000000000..ff2c2ee4f
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/singleflight/singleflight.go
@@ -0,0 +1,64 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package singleflight provides a duplicate function call suppression
+// mechanism.
+package singleflight
+
+import "sync"
+
+// call is an in-flight or completed Do call
+type call struct {
+ wg sync.WaitGroup
+ val interface{}
+ err error
+}
+
+// Group represents a class of work and forms a namespace in which
+// units of work can be executed with duplicate suppression.
+type Group struct {
+ mu sync.Mutex // protects m
+ m map[string]*call // lazily initialized
+}
+
+// Do executes and returns the results of the given function, making
+// sure that only one execution is in-flight for a given key at a
+// time. If a duplicate comes in, the duplicate caller waits for the
+// original to complete and receives the same results.
+func (g *Group) Do(key string, fn func() (interface{}, error)) (interface{}, error) {
+ g.mu.Lock()
+ if g.m == nil {
+ g.m = make(map[string]*call)
+ }
+ if c, ok := g.m[key]; ok {
+ g.mu.Unlock()
+ c.wg.Wait()
+ return c.val, c.err
+ }
+ c := new(call)
+ c.wg.Add(1)
+ g.m[key] = c
+ g.mu.Unlock()
+
+ c.val, c.err = fn()
+ c.wg.Done()
+
+ g.mu.Lock()
+ delete(g.m, key)
+ g.mu.Unlock()
+
+ return c.val, c.err
+}
diff --git a/vendor/github.com/golang/groupcache/singleflight/singleflight_test.go b/vendor/github.com/golang/groupcache/singleflight/singleflight_test.go
new file mode 100644
index 000000000..47b4d3dc0
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/singleflight/singleflight_test.go
@@ -0,0 +1,85 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package singleflight
+
+import (
+ "errors"
+ "fmt"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+func TestDo(t *testing.T) {
+ var g Group
+ v, err := g.Do("key", func() (interface{}, error) {
+ return "bar", nil
+ })
+ if got, want := fmt.Sprintf("%v (%T)", v, v), "bar (string)"; got != want {
+ t.Errorf("Do = %v; want %v", got, want)
+ }
+ if err != nil {
+ t.Errorf("Do error = %v", err)
+ }
+}
+
+func TestDoErr(t *testing.T) {
+ var g Group
+ someErr := errors.New("Some error")
+ v, err := g.Do("key", func() (interface{}, error) {
+ return nil, someErr
+ })
+ if err != someErr {
+ t.Errorf("Do error = %v; want someErr", err)
+ }
+ if v != nil {
+ t.Errorf("unexpected non-nil value %#v", v)
+ }
+}
+
+func TestDoDupSuppress(t *testing.T) {
+ var g Group
+ c := make(chan string)
+ var calls int32
+ fn := func() (interface{}, error) {
+ atomic.AddInt32(&calls, 1)
+ return <-c, nil
+ }
+
+ const n = 10
+ var wg sync.WaitGroup
+ for i := 0; i < n; i++ {
+ wg.Add(1)
+ go func() {
+ v, err := g.Do("key", fn)
+ if err != nil {
+ t.Errorf("Do error: %v", err)
+ }
+ if v.(string) != "bar" {
+ t.Errorf("got %q; want %q", v, "bar")
+ }
+ wg.Done()
+ }()
+ }
+ time.Sleep(100 * time.Millisecond) // let goroutines above block
+ c <- "bar"
+ wg.Wait()
+ if got := atomic.LoadInt32(&calls); got != 1 {
+ t.Errorf("number of calls = %d; want 1", got)
+ }
+}
diff --git a/vendor/github.com/golang/groupcache/sinks.go b/vendor/github.com/golang/groupcache/sinks.go
new file mode 100644
index 000000000..cb42b41b4
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/sinks.go
@@ -0,0 +1,322 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package groupcache
+
+import (
+ "errors"
+
+ "github.com/golang/protobuf/proto"
+)
+
+// A Sink receives data from a Get call.
+//
+// Implementation of Getter must call exactly one of the Set methods
+// on success.
+type Sink interface {
+ // SetString sets the value to s.
+ SetString(s string) error
+
+ // SetBytes sets the value to the contents of v.
+ // The caller retains ownership of v.
+ SetBytes(v []byte) error
+
+ // SetProto sets the value to the encoded version of m.
+ // The caller retains ownership of m.
+ SetProto(m proto.Message) error
+
+ // view returns a frozen view of the bytes for caching.
+ view() (ByteView, error)
+}
+
+func cloneBytes(b []byte) []byte {
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+}
+
+func setSinkView(s Sink, v ByteView) error {
+ // A viewSetter is a Sink that can also receive its value from
+ // a ByteView. This is a fast path to minimize copies when the
+ // item was already cached locally in memory (where it's
+ // cached as a ByteView)
+ type viewSetter interface {
+ setView(v ByteView) error
+ }
+ if vs, ok := s.(viewSetter); ok {
+ return vs.setView(v)
+ }
+ if v.b != nil {
+ return s.SetBytes(v.b)
+ }
+ return s.SetString(v.s)
+}
+
+// StringSink returns a Sink that populates the provided string pointer.
+func StringSink(sp *string) Sink {
+ return &stringSink{sp: sp}
+}
+
+type stringSink struct {
+ sp *string
+ v ByteView
+ // TODO(bradfitz): track whether any Sets were called.
+}
+
+func (s *stringSink) view() (ByteView, error) {
+ // TODO(bradfitz): return an error if no Set was called
+ return s.v, nil
+}
+
+func (s *stringSink) SetString(v string) error {
+ s.v.b = nil
+ s.v.s = v
+ *s.sp = v
+ return nil
+}
+
+func (s *stringSink) SetBytes(v []byte) error {
+ return s.SetString(string(v))
+}
+
+func (s *stringSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ s.v.b = b
+ *s.sp = string(b)
+ return nil
+}
+
+// ByteViewSink returns a Sink that populates a ByteView.
+func ByteViewSink(dst *ByteView) Sink {
+ if dst == nil {
+ panic("nil dst")
+ }
+ return &byteViewSink{dst: dst}
+}
+
+type byteViewSink struct {
+ dst *ByteView
+
+ // if this code ever ends up tracking that at least one set*
+ // method was called, don't make it an error to call set
+ // methods multiple times. Lorry's payload.go does that, and
+ // it makes sense. The comment at the top of this file about
+ // "exactly one of the Set methods" is overly strict. We
+ // really care about at least once (in a handler), but if
+ // multiple handlers fail (or multiple functions in a program
+ // using a Sink), it's okay to re-use the same one.
+}
+
+func (s *byteViewSink) setView(v ByteView) error {
+ *s.dst = v
+ return nil
+}
+
+func (s *byteViewSink) view() (ByteView, error) {
+ return *s.dst, nil
+}
+
+func (s *byteViewSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ *s.dst = ByteView{b: b}
+ return nil
+}
+
+func (s *byteViewSink) SetBytes(b []byte) error {
+ *s.dst = ByteView{b: cloneBytes(b)}
+ return nil
+}
+
+func (s *byteViewSink) SetString(v string) error {
+ *s.dst = ByteView{s: v}
+ return nil
+}
+
+// ProtoSink returns a sink that unmarshals binary proto values into m.
+func ProtoSink(m proto.Message) Sink {
+ return &protoSink{
+ dst: m,
+ }
+}
+
+type protoSink struct {
+ dst proto.Message // authorative value
+ typ string
+
+ v ByteView // encoded
+}
+
+func (s *protoSink) view() (ByteView, error) {
+ return s.v, nil
+}
+
+func (s *protoSink) SetBytes(b []byte) error {
+ err := proto.Unmarshal(b, s.dst)
+ if err != nil {
+ return err
+ }
+ s.v.b = cloneBytes(b)
+ s.v.s = ""
+ return nil
+}
+
+func (s *protoSink) SetString(v string) error {
+ b := []byte(v)
+ err := proto.Unmarshal(b, s.dst)
+ if err != nil {
+ return err
+ }
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+func (s *protoSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ // TODO(bradfitz): optimize for same-task case more and write
+ // right through? would need to document ownership rules at
+ // the same time. but then we could just assign *dst = *m
+ // here. This works for now:
+ err = proto.Unmarshal(b, s.dst)
+ if err != nil {
+ return err
+ }
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+// AllocatingByteSliceSink returns a Sink that allocates
+// a byte slice to hold the received value and assigns
+// it to *dst. The memory is not retained by groupcache.
+func AllocatingByteSliceSink(dst *[]byte) Sink {
+ return &allocBytesSink{dst: dst}
+}
+
+type allocBytesSink struct {
+ dst *[]byte
+ v ByteView
+}
+
+func (s *allocBytesSink) view() (ByteView, error) {
+ return s.v, nil
+}
+
+func (s *allocBytesSink) setView(v ByteView) error {
+ if v.b != nil {
+ *s.dst = cloneBytes(v.b)
+ } else {
+ *s.dst = []byte(v.s)
+ }
+ s.v = v
+ return nil
+}
+
+func (s *allocBytesSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ return s.setBytesOwned(b)
+}
+
+func (s *allocBytesSink) SetBytes(b []byte) error {
+ return s.setBytesOwned(cloneBytes(b))
+}
+
+func (s *allocBytesSink) setBytesOwned(b []byte) error {
+ if s.dst == nil {
+ return errors.New("nil AllocatingByteSliceSink *[]byte dst")
+ }
+ *s.dst = cloneBytes(b) // another copy, protecting the read-only s.v.b view
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+func (s *allocBytesSink) SetString(v string) error {
+ if s.dst == nil {
+ return errors.New("nil AllocatingByteSliceSink *[]byte dst")
+ }
+ *s.dst = []byte(v)
+ s.v.b = nil
+ s.v.s = v
+ return nil
+}
+
+// TruncatingByteSliceSink returns a Sink that writes up to len(*dst)
+// bytes to *dst. If more bytes are available, they're silently
+// truncated. If fewer bytes are available than len(*dst), *dst
+// is shrunk to fit the number of bytes available.
+func TruncatingByteSliceSink(dst *[]byte) Sink {
+ return &truncBytesSink{dst: dst}
+}
+
+type truncBytesSink struct {
+ dst *[]byte
+ v ByteView
+}
+
+func (s *truncBytesSink) view() (ByteView, error) {
+ return s.v, nil
+}
+
+func (s *truncBytesSink) SetProto(m proto.Message) error {
+ b, err := proto.Marshal(m)
+ if err != nil {
+ return err
+ }
+ return s.setBytesOwned(b)
+}
+
+func (s *truncBytesSink) SetBytes(b []byte) error {
+ return s.setBytesOwned(cloneBytes(b))
+}
+
+func (s *truncBytesSink) setBytesOwned(b []byte) error {
+ if s.dst == nil {
+ return errors.New("nil TruncatingByteSliceSink *[]byte dst")
+ }
+ n := copy(*s.dst, b)
+ if n < len(*s.dst) {
+ *s.dst = (*s.dst)[:n]
+ }
+ s.v.b = b
+ s.v.s = ""
+ return nil
+}
+
+func (s *truncBytesSink) SetString(v string) error {
+ if s.dst == nil {
+ return errors.New("nil TruncatingByteSliceSink *[]byte dst")
+ }
+ n := copy(*s.dst, v)
+ if n < len(*s.dst) {
+ *s.dst = (*s.dst)[:n]
+ }
+ s.v.b = nil
+ s.v.s = v
+ return nil
+}
diff --git a/vendor/github.com/golang/groupcache/testpb/test.pb.go b/vendor/github.com/golang/groupcache/testpb/test.pb.go
new file mode 100644
index 000000000..038040d15
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/testpb/test.pb.go
@@ -0,0 +1,235 @@
+// Code generated by protoc-gen-go.
+// source: test.proto
+// DO NOT EDIT!
+
+package testpb
+
+import proto "github.com/golang/protobuf/proto"
+import json "encoding/json"
+import math "math"
+
+// Reference proto, json, and math imports to suppress error if they are not otherwise used.
+var _ = proto.Marshal
+var _ = &json.SyntaxError{}
+var _ = math.Inf
+
+type TestMessage struct {
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ City *string `protobuf:"bytes,2,opt,name=city" json:"city,omitempty"`
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *TestMessage) Reset() { *m = TestMessage{} }
+func (m *TestMessage) String() string { return proto.CompactTextString(m) }
+func (*TestMessage) ProtoMessage() {}
+
+func (m *TestMessage) GetName() string {
+ if m != nil && m.Name != nil {
+ return *m.Name
+ }
+ return ""
+}
+
+func (m *TestMessage) GetCity() string {
+ if m != nil && m.City != nil {
+ return *m.City
+ }
+ return ""
+}
+
+type TestRequest struct {
+ Lower *string `protobuf:"bytes,1,req,name=lower" json:"lower,omitempty"`
+ RepeatCount *int32 `protobuf:"varint,2,opt,name=repeat_count,def=1" json:"repeat_count,omitempty"`
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *TestRequest) Reset() { *m = TestRequest{} }
+func (m *TestRequest) String() string { return proto.CompactTextString(m) }
+func (*TestRequest) ProtoMessage() {}
+
+const Default_TestRequest_RepeatCount int32 = 1
+
+func (m *TestRequest) GetLower() string {
+ if m != nil && m.Lower != nil {
+ return *m.Lower
+ }
+ return ""
+}
+
+func (m *TestRequest) GetRepeatCount() int32 {
+ if m != nil && m.RepeatCount != nil {
+ return *m.RepeatCount
+ }
+ return Default_TestRequest_RepeatCount
+}
+
+type TestResponse struct {
+ Value *string `protobuf:"bytes,1,opt,name=value" json:"value,omitempty"`
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *TestResponse) Reset() { *m = TestResponse{} }
+func (m *TestResponse) String() string { return proto.CompactTextString(m) }
+func (*TestResponse) ProtoMessage() {}
+
+func (m *TestResponse) GetValue() string {
+ if m != nil && m.Value != nil {
+ return *m.Value
+ }
+ return ""
+}
+
+type CacheStats struct {
+ Items *int64 `protobuf:"varint,1,opt,name=items" json:"items,omitempty"`
+ Bytes *int64 `protobuf:"varint,2,opt,name=bytes" json:"bytes,omitempty"`
+ Gets *int64 `protobuf:"varint,3,opt,name=gets" json:"gets,omitempty"`
+ Hits *int64 `protobuf:"varint,4,opt,name=hits" json:"hits,omitempty"`
+ Evicts *int64 `protobuf:"varint,5,opt,name=evicts" json:"evicts,omitempty"`
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *CacheStats) Reset() { *m = CacheStats{} }
+func (m *CacheStats) String() string { return proto.CompactTextString(m) }
+func (*CacheStats) ProtoMessage() {}
+
+func (m *CacheStats) GetItems() int64 {
+ if m != nil && m.Items != nil {
+ return *m.Items
+ }
+ return 0
+}
+
+func (m *CacheStats) GetBytes() int64 {
+ if m != nil && m.Bytes != nil {
+ return *m.Bytes
+ }
+ return 0
+}
+
+func (m *CacheStats) GetGets() int64 {
+ if m != nil && m.Gets != nil {
+ return *m.Gets
+ }
+ return 0
+}
+
+func (m *CacheStats) GetHits() int64 {
+ if m != nil && m.Hits != nil {
+ return *m.Hits
+ }
+ return 0
+}
+
+func (m *CacheStats) GetEvicts() int64 {
+ if m != nil && m.Evicts != nil {
+ return *m.Evicts
+ }
+ return 0
+}
+
+type StatsResponse struct {
+ Gets *int64 `protobuf:"varint,1,opt,name=gets" json:"gets,omitempty"`
+ CacheHits *int64 `protobuf:"varint,12,opt,name=cache_hits" json:"cache_hits,omitempty"`
+ Fills *int64 `protobuf:"varint,2,opt,name=fills" json:"fills,omitempty"`
+ TotalAlloc *uint64 `protobuf:"varint,3,opt,name=total_alloc" json:"total_alloc,omitempty"`
+ MainCache *CacheStats `protobuf:"bytes,4,opt,name=main_cache" json:"main_cache,omitempty"`
+ HotCache *CacheStats `protobuf:"bytes,5,opt,name=hot_cache" json:"hot_cache,omitempty"`
+ ServerIn *int64 `protobuf:"varint,6,opt,name=server_in" json:"server_in,omitempty"`
+ Loads *int64 `protobuf:"varint,8,opt,name=loads" json:"loads,omitempty"`
+ PeerLoads *int64 `protobuf:"varint,9,opt,name=peer_loads" json:"peer_loads,omitempty"`
+ PeerErrors *int64 `protobuf:"varint,10,opt,name=peer_errors" json:"peer_errors,omitempty"`
+ LocalLoads *int64 `protobuf:"varint,11,opt,name=local_loads" json:"local_loads,omitempty"`
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *StatsResponse) Reset() { *m = StatsResponse{} }
+func (m *StatsResponse) String() string { return proto.CompactTextString(m) }
+func (*StatsResponse) ProtoMessage() {}
+
+func (m *StatsResponse) GetGets() int64 {
+ if m != nil && m.Gets != nil {
+ return *m.Gets
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetCacheHits() int64 {
+ if m != nil && m.CacheHits != nil {
+ return *m.CacheHits
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetFills() int64 {
+ if m != nil && m.Fills != nil {
+ return *m.Fills
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetTotalAlloc() uint64 {
+ if m != nil && m.TotalAlloc != nil {
+ return *m.TotalAlloc
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetMainCache() *CacheStats {
+ if m != nil {
+ return m.MainCache
+ }
+ return nil
+}
+
+func (m *StatsResponse) GetHotCache() *CacheStats {
+ if m != nil {
+ return m.HotCache
+ }
+ return nil
+}
+
+func (m *StatsResponse) GetServerIn() int64 {
+ if m != nil && m.ServerIn != nil {
+ return *m.ServerIn
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetLoads() int64 {
+ if m != nil && m.Loads != nil {
+ return *m.Loads
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetPeerLoads() int64 {
+ if m != nil && m.PeerLoads != nil {
+ return *m.PeerLoads
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetPeerErrors() int64 {
+ if m != nil && m.PeerErrors != nil {
+ return *m.PeerErrors
+ }
+ return 0
+}
+
+func (m *StatsResponse) GetLocalLoads() int64 {
+ if m != nil && m.LocalLoads != nil {
+ return *m.LocalLoads
+ }
+ return 0
+}
+
+type Empty struct {
+ XXX_unrecognized []byte `json:"-"`
+}
+
+func (m *Empty) Reset() { *m = Empty{} }
+func (m *Empty) String() string { return proto.CompactTextString(m) }
+func (*Empty) ProtoMessage() {}
+
+func init() {
+}
diff --git a/vendor/github.com/golang/groupcache/testpb/test.proto b/vendor/github.com/golang/groupcache/testpb/test.proto
new file mode 100644
index 000000000..b9dc6c9a0
--- /dev/null
+++ b/vendor/github.com/golang/groupcache/testpb/test.proto
@@ -0,0 +1,63 @@
+/*
+Copyright 2012 Google Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+syntax = "proto2";
+
+package testpb;
+
+message TestMessage {
+ optional string name = 1;
+ optional string city = 2;
+}
+
+message TestRequest {
+ required string lower = 1; // to be returned upper case
+ optional int32 repeat_count = 2 [default = 1]; // .. this many times
+}
+
+message TestResponse {
+ optional string value = 1;
+}
+
+message CacheStats {
+ optional int64 items = 1;
+ optional int64 bytes = 2;
+ optional int64 gets = 3;
+ optional int64 hits = 4;
+ optional int64 evicts = 5;
+}
+
+message StatsResponse {
+ optional int64 gets = 1;
+ optional int64 cache_hits = 12;
+ optional int64 fills = 2;
+ optional uint64 total_alloc = 3;
+ optional CacheStats main_cache = 4;
+ optional CacheStats hot_cache = 5;
+ optional int64 server_in = 6;
+ optional int64 loads = 8;
+ optional int64 peer_loads = 9;
+ optional int64 peer_errors = 10;
+ optional int64 local_loads = 11;
+}
+
+message Empty {}
+
+service GroupCacheTest {
+ rpc InitPeers(Empty) returns (Empty) {};
+ rpc Get(TestRequest) returns (TestResponse) {};
+ rpc GetStats(Empty) returns (StatsResponse) {};
+}
diff --git a/vendor/github.com/gorilla/context/context_test.go b/vendor/github.com/gorilla/context/context_test.go
new file mode 100644
index 000000000..9814c501e
--- /dev/null
+++ b/vendor/github.com/gorilla/context/context_test.go
@@ -0,0 +1,161 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package context
+
+import (
+ "net/http"
+ "testing"
+)
+
+type keyType int
+
+const (
+ key1 keyType = iota
+ key2
+)
+
+func TestContext(t *testing.T) {
+ assertEqual := func(val interface{}, exp interface{}) {
+ if val != exp {
+ t.Errorf("Expected %v, got %v.", exp, val)
+ }
+ }
+
+ r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
+ emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
+
+ // Get()
+ assertEqual(Get(r, key1), nil)
+
+ // Set()
+ Set(r, key1, "1")
+ assertEqual(Get(r, key1), "1")
+ assertEqual(len(data[r]), 1)
+
+ Set(r, key2, "2")
+ assertEqual(Get(r, key2), "2")
+ assertEqual(len(data[r]), 2)
+
+ //GetOk
+ value, ok := GetOk(r, key1)
+ assertEqual(value, "1")
+ assertEqual(ok, true)
+
+ value, ok = GetOk(r, "not exists")
+ assertEqual(value, nil)
+ assertEqual(ok, false)
+
+ Set(r, "nil value", nil)
+ value, ok = GetOk(r, "nil value")
+ assertEqual(value, nil)
+ assertEqual(ok, true)
+
+ // GetAll()
+ values := GetAll(r)
+ assertEqual(len(values), 3)
+
+ // GetAll() for empty request
+ values = GetAll(emptyR)
+ if values != nil {
+ t.Error("GetAll didn't return nil value for invalid request")
+ }
+
+ // GetAllOk()
+ values, ok = GetAllOk(r)
+ assertEqual(len(values), 3)
+ assertEqual(ok, true)
+
+ // GetAllOk() for empty request
+ values, ok = GetAllOk(emptyR)
+ assertEqual(value, nil)
+ assertEqual(ok, false)
+
+ // Delete()
+ Delete(r, key1)
+ assertEqual(Get(r, key1), nil)
+ assertEqual(len(data[r]), 2)
+
+ Delete(r, key2)
+ assertEqual(Get(r, key2), nil)
+ assertEqual(len(data[r]), 1)
+
+ // Clear()
+ Clear(r)
+ assertEqual(len(data), 0)
+}
+
+func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) {
+ <-wait
+ for i := 0; i < iterations; i++ {
+ Get(r, key)
+ }
+ done <- struct{}{}
+
+}
+
+func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) {
+ <-wait
+ for i := 0; i < iterations; i++ {
+ Set(r, key, value)
+ }
+ done <- struct{}{}
+
+}
+
+func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) {
+
+ b.StopTimer()
+ r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
+ done := make(chan struct{})
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ wait := make(chan struct{})
+
+ for i := 0; i < numReaders; i++ {
+ go parallelReader(r, "test", iterations, wait, done)
+ }
+
+ for i := 0; i < numWriters; i++ {
+ go parallelWriter(r, "test", "123", iterations, wait, done)
+ }
+
+ close(wait)
+
+ for i := 0; i < numReaders+numWriters; i++ {
+ <-done
+ }
+
+ }
+
+}
+
+func BenchmarkMutexSameReadWrite1(b *testing.B) {
+ benchmarkMutex(b, 1, 1, 32)
+}
+func BenchmarkMutexSameReadWrite2(b *testing.B) {
+ benchmarkMutex(b, 2, 2, 32)
+}
+func BenchmarkMutexSameReadWrite4(b *testing.B) {
+ benchmarkMutex(b, 4, 4, 32)
+}
+func BenchmarkMutex1(b *testing.B) {
+ benchmarkMutex(b, 2, 8, 32)
+}
+func BenchmarkMutex2(b *testing.B) {
+ benchmarkMutex(b, 16, 4, 64)
+}
+func BenchmarkMutex3(b *testing.B) {
+ benchmarkMutex(b, 1, 2, 128)
+}
+func BenchmarkMutex4(b *testing.B) {
+ benchmarkMutex(b, 128, 32, 256)
+}
+func BenchmarkMutex5(b *testing.B) {
+ benchmarkMutex(b, 1024, 2048, 64)
+}
+func BenchmarkMutex6(b *testing.B) {
+ benchmarkMutex(b, 2048, 1024, 512)
+}
diff --git a/vendor/github.com/gorilla/handlers/canonical_test.go b/vendor/github.com/gorilla/handlers/canonical_test.go
new file mode 100644
index 000000000..615e4b056
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/canonical_test.go
@@ -0,0 +1,127 @@
+package handlers
+
+import (
+ "bufio"
+ "bytes"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+ "testing"
+)
+
+func TestCleanHost(t *testing.T) {
+ tests := []struct {
+ in, want string
+ }{
+ {"www.google.com", "www.google.com"},
+ {"www.google.com foo", "www.google.com"},
+ {"www.google.com/foo", "www.google.com"},
+ {" first character is a space", ""},
+ }
+ for _, tt := range tests {
+ got := cleanHost(tt.in)
+ if tt.want != got {
+ t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want)
+ }
+ }
+}
+
+func TestCanonicalHost(t *testing.T) {
+ gorilla := "http://www.gorillatoolkit.org"
+
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "http://www.example.com/")
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ // Test a re-direct: should return a 302 Found.
+ CanonicalHost(gorilla, http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusFound {
+ t.Fatalf("bad status: got %v want %v", rr.Code, http.StatusFound)
+ }
+
+ if rr.Header().Get("Location") != gorilla+r.URL.Path {
+ t.Fatalf("bad re-direct: got %q want %q", rr.Header().Get("Location"), gorilla+r.URL.Path)
+ }
+
+}
+
+func TestKeepsQueryString(t *testing.T) {
+ google := "https://www.google.com"
+
+ rr := httptest.NewRecorder()
+ querystring := url.Values{"q": {"golang"}, "format": {"json"}}.Encode()
+ r := newRequest("GET", "http://www.example.com/search?"+querystring)
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+ CanonicalHost(google, http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ want := google + r.URL.Path + "?" + querystring
+ if rr.Header().Get("Location") != want {
+ t.Fatalf("bad re-direct: got %q want %q", rr.Header().Get("Location"), want)
+ }
+}
+
+func TestBadDomain(t *testing.T) {
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "http://www.example.com/")
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ // Test a bad domain - should return 200 OK.
+ CanonicalHost("%", http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", rr.Code, http.StatusOK)
+ }
+}
+
+func TestEmptyHost(t *testing.T) {
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "http://www.example.com/")
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ // Test a domain that returns an empty url.Host from url.Parse.
+ CanonicalHost("hello.com", http.StatusFound)(testHandler).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", rr.Code, http.StatusOK)
+ }
+}
+
+func TestHeaderWrites(t *testing.T) {
+ gorilla := "http://www.gorillatoolkit.org"
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(200)
+ })
+
+ // Catch the log output to ensure we don't write multiple headers.
+ var b bytes.Buffer
+ buf := bufio.NewWriter(&b)
+ tl := log.New(buf, "test: ", log.Lshortfile)
+
+ srv := httptest.NewServer(
+ CanonicalHost(gorilla, http.StatusFound)(testHandler))
+ defer srv.Close()
+ srv.Config.ErrorLog = tl
+
+ _, err := http.Get(srv.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = buf.Flush()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // We rely on the error not changing: net/http does not export it.
+ if strings.Contains(b.String(), "multiple response.WriteHeader calls") {
+ t.Fatalf("re-direct did not return early: multiple header writes")
+ }
+}
diff --git a/vendor/github.com/gorilla/handlers/compress_test.go b/vendor/github.com/gorilla/handlers/compress_test.go
new file mode 100644
index 000000000..6f07f440d
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/compress_test.go
@@ -0,0 +1,154 @@
+// Copyright 2013 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package handlers
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "strconv"
+ "testing"
+)
+
+var contentType = "text/plain; charset=utf-8"
+
+func compressedRequest(w *httptest.ResponseRecorder, compression string) {
+ CompressHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Length", strconv.Itoa(9*1024))
+ w.Header().Set("Content-Type", contentType)
+ for i := 0; i < 1024; i++ {
+ io.WriteString(w, "Gorilla!\n")
+ }
+ })).ServeHTTP(w, &http.Request{
+ Method: "GET",
+ Header: http.Header{
+ "Accept-Encoding": []string{compression},
+ },
+ })
+
+}
+
+func TestCompressHandlerNoCompression(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "")
+ if enc := w.HeaderMap.Get("Content-Encoding"); enc != "" {
+ t.Errorf("wrong content encoding, got %q want %q", enc, "")
+ }
+ if ct := w.HeaderMap.Get("Content-Type"); ct != contentType {
+ t.Errorf("wrong content type, got %q want %q", ct, contentType)
+ }
+ if w.Body.Len() != 1024*9 {
+ t.Errorf("wrong len, got %d want %d", w.Body.Len(), 1024*9)
+ }
+ if l := w.HeaderMap.Get("Content-Length"); l != "9216" {
+ t.Errorf("wrong content-length. got %q expected %d", l, 1024*9)
+ }
+}
+
+func TestCompressHandlerGzip(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "gzip")
+ if w.HeaderMap.Get("Content-Encoding") != "gzip" {
+ t.Errorf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "gzip")
+ }
+ if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
+ t.Errorf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
+ }
+ if w.Body.Len() != 72 {
+ t.Errorf("wrong len, got %d want %d", w.Body.Len(), 72)
+ }
+ if l := w.HeaderMap.Get("Content-Length"); l != "" {
+ t.Errorf("wrong content-length. got %q expected %q", l, "")
+ }
+}
+
+func TestCompressHandlerDeflate(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "deflate")
+ if w.HeaderMap.Get("Content-Encoding") != "deflate" {
+ t.Fatalf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "deflate")
+ }
+ if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
+ t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
+ }
+ if w.Body.Len() != 54 {
+ t.Fatalf("wrong len, got %d want %d", w.Body.Len(), 54)
+ }
+}
+
+func TestCompressHandlerGzipDeflate(t *testing.T) {
+ w := httptest.NewRecorder()
+ compressedRequest(w, "gzip, deflate ")
+ if w.HeaderMap.Get("Content-Encoding") != "gzip" {
+ t.Fatalf("wrong content encoding, got %q want %q", w.HeaderMap.Get("Content-Encoding"), "gzip")
+ }
+ if w.HeaderMap.Get("Content-Type") != "text/plain; charset=utf-8" {
+ t.Fatalf("wrong content type, got %s want %s", w.HeaderMap.Get("Content-Type"), "text/plain; charset=utf-8")
+ }
+}
+
+type fullyFeaturedResponseWriter struct{}
+
+// Header/Write/WriteHeader implement the http.ResponseWriter interface.
+func (fullyFeaturedResponseWriter) Header() http.Header {
+ return http.Header{}
+}
+func (fullyFeaturedResponseWriter) Write([]byte) (int, error) {
+ return 0, nil
+}
+func (fullyFeaturedResponseWriter) WriteHeader(int) {}
+
+// Flush implements the http.Flusher interface.
+func (fullyFeaturedResponseWriter) Flush() {}
+
+// Hijack implements the http.Hijacker interface.
+func (fullyFeaturedResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ return nil, nil, nil
+}
+
+// CloseNotify implements the http.CloseNotifier interface.
+func (fullyFeaturedResponseWriter) CloseNotify() <-chan bool {
+ return nil
+}
+
+func TestCompressHandlerPreserveInterfaces(t *testing.T) {
+ // Compile time validation fullyFeaturedResponseWriter implements all the
+ // interfaces we're asserting in the test case below.
+ var (
+ _ http.Flusher = fullyFeaturedResponseWriter{}
+ _ http.CloseNotifier = fullyFeaturedResponseWriter{}
+ _ http.Hijacker = fullyFeaturedResponseWriter{}
+ )
+ var h http.Handler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ comp := r.Header.Get("Accept-Encoding")
+ if _, ok := rw.(*compressResponseWriter); !ok {
+ t.Fatalf("ResponseWriter wasn't wrapped by compressResponseWriter, got %T type", rw)
+ }
+ if _, ok := rw.(http.Flusher); !ok {
+ t.Errorf("ResponseWriter lost http.Flusher interface for %q", comp)
+ }
+ if _, ok := rw.(http.CloseNotifier); !ok {
+ t.Errorf("ResponseWriter lost http.CloseNotifier interface for %q", comp)
+ }
+ if _, ok := rw.(http.Hijacker); !ok {
+ t.Errorf("ResponseWriter lost http.Hijacker interface for %q", comp)
+ }
+ })
+ h = CompressHandler(h)
+ var (
+ rw fullyFeaturedResponseWriter
+ )
+ r, err := http.NewRequest("GET", "/", nil)
+ if err != nil {
+ t.Fatalf("Failed to create test request: %v", err)
+ }
+ r.Header.Set("Accept-Encoding", "gzip")
+ h.ServeHTTP(rw, r)
+
+ r.Header.Set("Accept-Encoding", "deflate")
+ h.ServeHTTP(rw, r)
+}
diff --git a/vendor/github.com/gorilla/handlers/cors_test.go b/vendor/github.com/gorilla/handlers/cors_test.go
new file mode 100644
index 000000000..c63913eee
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/cors_test.go
@@ -0,0 +1,336 @@
+package handlers
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func TestDefaultCORSHandlerReturnsOk(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusFound)
+ }
+}
+
+func TestDefaultCORSHandlerReturnsOkWithOrigin(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusFound)
+ }
+}
+
+func TestCORSHandlerIgnoreOptionsFallsThrough(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusTeapot)
+ })
+
+ CORS(IgnoreOptions())(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusTeapot {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusTeapot)
+ }
+}
+
+func TestCORSHandlerSetsExposedHeaders(t *testing.T) {
+ // Test default configuration.
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(ExposedHeaders([]string{"X-CORS-TEST"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsExposeHeadersHeader)
+ if header != "X-Cors-Test" {
+ t.Fatal("bad header: expected X-Cors-Test header, got empty header for method.")
+ }
+}
+
+func TestCORSHandlerUnsetRequestMethodForPreflightBadRequest(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedMethods([]string{"DELETE"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusBadRequest {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusBadRequest)
+ }
+}
+
+func TestCORSHandlerInvalidRequestMethodForPreflightMethodNotAllowed(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "DELETE")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusMethodNotAllowed {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusMethodNotAllowed)
+ }
+}
+
+func TestCORSHandlerOptionsRequestMustNotBePassedToNextHandler(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "GET")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ t.Fatal("Options request must not be passed to next handler")
+ })
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+}
+
+func TestCORSHandlerAllowedMethodForPreflight(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "DELETE")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedMethods([]string{"DELETE"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowMethodsHeader)
+ if header != "DELETE" {
+ t.Fatalf("bad header: expected DELETE method header, got empty header.")
+ }
+}
+
+func TestCORSHandlerAllowMethodsNotSetForSimpleRequestPreflight(t *testing.T) {
+ for _, method := range defaultCorsMethods {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, method)
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowMethodsHeader)
+ if header != "" {
+ t.Fatalf("bad header: expected empty method header, got %s.", header)
+ }
+ }
+}
+
+func TestCORSHandlerAllowedHeaderNotSetForSimpleRequestPreflight(t *testing.T) {
+ for _, simpleHeader := range defaultCorsHeaders {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "GET")
+ r.Header.Set(corsRequestHeadersHeader, simpleHeader)
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowHeadersHeader)
+ if header != "" {
+ t.Fatalf("bad header: expected empty header, got %s.", header)
+ }
+ }
+}
+
+func TestCORSHandlerAllowedHeaderForPreflight(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "POST")
+ r.Header.Set(corsRequestHeadersHeader, "Content-Type")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedHeaders([]string{"Content-Type"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowHeadersHeader)
+ if header != "Content-Type" {
+ t.Fatalf("bad header: expected Content-Type header, got empty header.")
+ }
+}
+
+func TestCORSHandlerInvalidHeaderForPreflightForbidden(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "POST")
+ r.Header.Set(corsRequestHeadersHeader, "Content-Type")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS()(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusForbidden {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusForbidden)
+ }
+}
+
+func TestCORSHandlerMaxAgeForPreflight(t *testing.T) {
+ r := newRequest("OPTIONS", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+ r.Header.Set(corsRequestMethodHeader, "POST")
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(MaxAge(3500))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsMaxAgeHeader)
+ if header != "600" {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsMaxAgeHeader, "600", header)
+ }
+}
+
+func TestCORSHandlerAllowedCredentials(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowCredentials())(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsAllowCredentialsHeader)
+ if header != "true" {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowCredentialsHeader, "true", header)
+ }
+}
+
+func TestCORSHandlerMultipleAllowOriginsSetsVaryHeader(t *testing.T) {
+ r := newRequest("GET", "http://www.example.com/")
+ r.Header.Set("Origin", r.URL.String())
+
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ CORS(AllowedOrigins([]string{r.URL.String(), "http://google.com"}))(testHandler).ServeHTTP(rr, r)
+
+ if status := rr.Code; status != http.StatusOK {
+ t.Fatalf("bad status: got %v want %v", status, http.StatusOK)
+ }
+
+ header := rr.HeaderMap.Get(corsVaryHeader)
+ if header != corsOriginHeader {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsVaryHeader, corsOriginHeader, header)
+ }
+}
+
+func TestCORSWithMultipleHandlers(t *testing.T) {
+ var lastHandledBy string
+ corsMiddleware := CORS()
+
+ testHandler1 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ lastHandledBy = "testHandler1"
+ })
+ testHandler2 := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ lastHandledBy = "testHandler2"
+ })
+
+ r1 := newRequest("GET", "http://www.example.com/")
+ rr1 := httptest.NewRecorder()
+ handler1 := corsMiddleware(testHandler1)
+
+ corsMiddleware(testHandler2)
+
+ handler1.ServeHTTP(rr1, r1)
+ if lastHandledBy != "testHandler1" {
+ t.Fatalf("bad CORS() registration: Handler served should be Handler registered")
+ }
+}
+
+func TestCORSHandlerWithCustomValidator(t *testing.T) {
+ r := newRequest("GET", "http://a.example.com")
+ r.Header.Set("Origin", r.URL.String())
+ rr := httptest.NewRecorder()
+
+ testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
+
+ originValidator := func(origin string) bool {
+ if strings.HasSuffix(origin, ".example.com") {
+ return true
+ }
+ return false
+ }
+
+ CORS(AllowedOriginValidator(originValidator))(testHandler).ServeHTTP(rr, r)
+ header := rr.HeaderMap.Get(corsAllowOriginHeader)
+ if header != r.URL.String() {
+ t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowOriginHeader, r.URL.String(), header)
+ }
+
+}
diff --git a/vendor/github.com/gorilla/handlers/handlers_test.go b/vendor/github.com/gorilla/handlers/handlers_test.go
new file mode 100644
index 000000000..6ea7c7fa6
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/handlers_test.go
@@ -0,0 +1,354 @@
+// Copyright 2013 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package handlers
+
+import (
+ "bytes"
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "strings"
+ "testing"
+ "time"
+)
+
+const (
+ ok = "ok\n"
+ notAllowed = "Method not allowed\n"
+)
+
+var okHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ w.Write([]byte(ok))
+})
+
+func newRequest(method, url string) *http.Request {
+ req, err := http.NewRequest(method, url, nil)
+ if err != nil {
+ panic(err)
+ }
+ return req
+}
+
+func TestMethodHandler(t *testing.T) {
+ tests := []struct {
+ req *http.Request
+ handler http.Handler
+ code int
+ allow string // Contents of the Allow header
+ body string
+ }{
+ // No handlers
+ {newRequest("GET", "/foo"), MethodHandler{}, http.StatusMethodNotAllowed, "", notAllowed},
+ {newRequest("OPTIONS", "/foo"), MethodHandler{}, http.StatusOK, "", ""},
+
+ // A single handler
+ {newRequest("GET", "/foo"), MethodHandler{"GET": okHandler}, http.StatusOK, "", ok},
+ {newRequest("POST", "/foo"), MethodHandler{"GET": okHandler}, http.StatusMethodNotAllowed, "GET", notAllowed},
+
+ // Multiple handlers
+ {newRequest("GET", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusOK, "", ok},
+ {newRequest("POST", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusOK, "", ok},
+ {newRequest("DELETE", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusMethodNotAllowed, "GET, POST", notAllowed},
+ {newRequest("OPTIONS", "/foo"), MethodHandler{"GET": okHandler, "POST": okHandler}, http.StatusOK, "GET, POST", ""},
+
+ // Override OPTIONS
+ {newRequest("OPTIONS", "/foo"), MethodHandler{"OPTIONS": okHandler}, http.StatusOK, "", ok},
+ }
+
+ for i, test := range tests {
+ rec := httptest.NewRecorder()
+ test.handler.ServeHTTP(rec, test.req)
+ if rec.Code != test.code {
+ t.Fatalf("%d: wrong code, got %d want %d", i, rec.Code, test.code)
+ }
+ if allow := rec.HeaderMap.Get("Allow"); allow != test.allow {
+ t.Fatalf("%d: wrong Allow, got %s want %s", i, allow, test.allow)
+ }
+ if body := rec.Body.String(); body != test.body {
+ t.Fatalf("%d: wrong body, got %q want %q", i, body, test.body)
+ }
+ }
+}
+
+func TestWriteLog(t *testing.T) {
+ loc, err := time.LoadLocation("Europe/Warsaw")
+ if err != nil {
+ panic(err)
+ }
+ ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
+
+ // A typical request with an OK response
+ req := newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+
+ buf := new(bytes.Buffer)
+ writeLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log := buf.String()
+
+ expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // CONNECT request over http/2.0
+ req = &http.Request{
+ Method: "CONNECT",
+ Proto: "HTTP/2.0",
+ ProtoMajor: 2,
+ ProtoMinor: 0,
+ URL: &url.URL{Host: "www.example.com:443"},
+ Host: "www.example.com:443",
+ RemoteAddr: "192.168.100.5",
+ }
+
+ buf = new(bytes.Buffer)
+ writeLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"CONNECT www.example.com:443 HTTP/2.0\" 200 100\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Request with an unauthorized user
+ req = newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+ req.URL.User = url.User("kamil")
+
+ buf.Reset()
+ writeLog(buf, req, *req.URL, ts, http.StatusUnauthorized, 500)
+ log = buf.String()
+
+ expected = "192.168.100.5 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 401 500\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Request with url encoded parameters
+ req = newRequest("GET", "http://example.com/test?abc=hello%20world&a=b%3F")
+ req.RemoteAddr = "192.168.100.5"
+
+ buf.Reset()
+ writeLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET /test?abc=hello%20world&a=b%3F HTTP/1.1\" 200 100\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+}
+
+func TestWriteCombinedLog(t *testing.T) {
+ loc, err := time.LoadLocation("Europe/Warsaw")
+ if err != nil {
+ panic(err)
+ }
+ ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
+
+ // A typical request with an OK response
+ req := newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+ req.Header.Set("Referer", "http://example.com")
+ req.Header.Set(
+ "User-Agent",
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.33 "+
+ "(KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33",
+ )
+
+ buf := new(bytes.Buffer)
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log := buf.String()
+
+ expected := "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // CONNECT request over http/2.0
+ req1 := &http.Request{
+ Method: "CONNECT",
+ Host: "www.example.com:443",
+ Proto: "HTTP/2.0",
+ ProtoMajor: 2,
+ ProtoMinor: 0,
+ RemoteAddr: "192.168.100.5",
+ Header: http.Header{},
+ URL: &url.URL{Host: "www.example.com:443"},
+ }
+ req1.Header.Set("Referer", "http://example.com")
+ req1.Header.Set(
+ "User-Agent",
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.33 "+
+ "(KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33",
+ )
+
+ buf = new(bytes.Buffer)
+ writeCombinedLog(buf, req1, *req1.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "192.168.100.5 - - [26/May/1983:03:30:45 +0200] \"CONNECT www.example.com:443 HTTP/2.0\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Request with an unauthorized user
+ req.URL.User = url.User("kamil")
+
+ buf.Reset()
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusUnauthorized, 500)
+ log = buf.String()
+
+ expected = "192.168.100.5 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 401 500 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Test with remote ipv6 address
+ req.RemoteAddr = "::1"
+
+ buf.Reset()
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "::1 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+
+ // Test remote ipv6 addr, with port
+ req.RemoteAddr = net.JoinHostPort("::1", "65000")
+
+ buf.Reset()
+ writeCombinedLog(buf, req, *req.URL, ts, http.StatusOK, 100)
+ log = buf.String()
+
+ expected = "::1 - kamil [26/May/1983:03:30:45 +0200] \"GET / HTTP/1.1\" 200 100 \"http://example.com\" " +
+ "\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) " +
+ "AppleWebKit/537.33 (KHTML, like Gecko) Chrome/27.0.1430.0 Safari/537.33\"\n"
+ if log != expected {
+ t.Fatalf("wrong log, got %q want %q", log, expected)
+ }
+}
+
+func TestLogPathRewrites(t *testing.T) {
+ var buf bytes.Buffer
+
+ handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ req.URL.Path = "/" // simulate http.StripPrefix and friends
+ w.WriteHeader(200)
+ })
+ logger := LoggingHandler(&buf, handler)
+
+ logger.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/subdir/asdf"))
+
+ if !strings.Contains(buf.String(), "GET /subdir/asdf HTTP") {
+ t.Fatalf("Got log %#v, wanted substring %#v", buf.String(), "GET /subdir/asdf HTTP")
+ }
+}
+
+func BenchmarkWriteLog(b *testing.B) {
+ loc, err := time.LoadLocation("Europe/Warsaw")
+ if err != nil {
+ b.Fatalf(err.Error())
+ }
+ ts := time.Date(1983, 05, 26, 3, 30, 45, 0, loc)
+
+ req := newRequest("GET", "http://example.com")
+ req.RemoteAddr = "192.168.100.5"
+
+ b.ResetTimer()
+
+ buf := &bytes.Buffer{}
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ writeLog(buf, req, *req.URL, ts, http.StatusUnauthorized, 500)
+ }
+}
+
+func TestContentTypeHandler(t *testing.T) {
+ tests := []struct {
+ Method string
+ AllowContentTypes []string
+ ContentType string
+ Code int
+ }{
+ {"POST", []string{"application/json"}, "application/json", http.StatusOK},
+ {"POST", []string{"application/json", "application/xml"}, "application/json", http.StatusOK},
+ {"POST", []string{"application/json"}, "application/json; charset=utf-8", http.StatusOK},
+ {"POST", []string{"application/json"}, "application/json+xxx", http.StatusUnsupportedMediaType},
+ {"POST", []string{"application/json"}, "text/plain", http.StatusUnsupportedMediaType},
+ {"GET", []string{"application/json"}, "", http.StatusOK},
+ {"GET", []string{}, "", http.StatusOK},
+ }
+ for _, test := range tests {
+ r, err := http.NewRequest(test.Method, "/", nil)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ h := ContentTypeHandler(okHandler, test.AllowContentTypes...)
+ r.Header.Set("Content-Type", test.ContentType)
+ w := httptest.NewRecorder()
+ h.ServeHTTP(w, r)
+ if w.Code != test.Code {
+ t.Errorf("expected %d, got %d", test.Code, w.Code)
+ }
+ }
+}
+
+func TestHTTPMethodOverride(t *testing.T) {
+ var tests = []struct {
+ Method string
+ OverrideMethod string
+ ExpectedMethod string
+ }{
+ {"POST", "PUT", "PUT"},
+ {"POST", "PATCH", "PATCH"},
+ {"POST", "DELETE", "DELETE"},
+ {"PUT", "DELETE", "PUT"},
+ {"GET", "GET", "GET"},
+ {"HEAD", "HEAD", "HEAD"},
+ {"GET", "PUT", "GET"},
+ {"HEAD", "DELETE", "HEAD"},
+ }
+
+ for _, test := range tests {
+ h := HTTPMethodOverrideHandler(okHandler)
+ reqs := make([]*http.Request, 0, 2)
+
+ rHeader, err := http.NewRequest(test.Method, "/", nil)
+ if err != nil {
+ t.Error(err)
+ }
+ rHeader.Header.Set(HTTPMethodOverrideHeader, test.OverrideMethod)
+ reqs = append(reqs, rHeader)
+
+ f := url.Values{HTTPMethodOverrideFormKey: []string{test.OverrideMethod}}
+ rForm, err := http.NewRequest(test.Method, "/", strings.NewReader(f.Encode()))
+ if err != nil {
+ t.Error(err)
+ }
+ rForm.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ reqs = append(reqs, rForm)
+
+ for _, r := range reqs {
+ w := httptest.NewRecorder()
+ h.ServeHTTP(w, r)
+ if r.Method != test.ExpectedMethod {
+ t.Errorf("Expected %s, got %s", test.ExpectedMethod, r.Method)
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/handlers/proxy_headers_test.go b/vendor/github.com/gorilla/handlers/proxy_headers_test.go
new file mode 100644
index 000000000..85282ef7d
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/proxy_headers_test.go
@@ -0,0 +1,100 @@
+package handlers
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+type headerTable struct {
+ key string // header key
+ val string // header val
+ expected string // expected result
+}
+
+func TestGetIP(t *testing.T) {
+ headers := []headerTable{
+ {xForwardedFor, "8.8.8.8", "8.8.8.8"}, // Single address
+ {xForwardedFor, "8.8.8.8, 8.8.4.4", "8.8.8.8"}, // Multiple
+ {xForwardedFor, "[2001:db8:cafe::17]:4711", "[2001:db8:cafe::17]:4711"}, // IPv6 address
+ {xForwardedFor, "", ""}, // None
+ {xRealIP, "8.8.8.8", "8.8.8.8"}, // Single address
+ {xRealIP, "8.8.8.8, 8.8.4.4", "8.8.8.8, 8.8.4.4"}, // Multiple
+ {xRealIP, "[2001:db8:cafe::17]:4711", "[2001:db8:cafe::17]:4711"}, // IPv6 address
+ {xRealIP, "", ""}, // None
+ {forwarded, `for="_gazonk"`, "_gazonk"}, // Hostname
+ {forwarded, `For="[2001:db8:cafe::17]:4711`, `[2001:db8:cafe::17]:4711`}, // IPv6 address
+ {forwarded, `for=192.0.2.60;proto=http;by=203.0.113.43`, `192.0.2.60`}, // Multiple params
+ {forwarded, `for=192.0.2.43, for=198.51.100.17`, "192.0.2.43"}, // Multiple params
+ {forwarded, `for="workstation.local",for=198.51.100.17`, "workstation.local"}, // Hostname
+ }
+
+ for _, v := range headers {
+ req := &http.Request{
+ Header: http.Header{
+ v.key: []string{v.val},
+ }}
+ res := getIP(req)
+ if res != v.expected {
+ t.Fatalf("wrong header for %s: got %s want %s", v.key, res,
+ v.expected)
+ }
+ }
+}
+
+func TestGetScheme(t *testing.T) {
+ headers := []headerTable{
+ {xForwardedProto, "https", "https"},
+ {xForwardedProto, "http", "http"},
+ {xForwardedProto, "HTTP", "http"},
+ {forwarded, `For="[2001:db8:cafe::17]:4711`, ""}, // No proto
+ {forwarded, `for=192.0.2.43, for=198.51.100.17;proto=https`, "https"}, // Multiple params before proto
+ {forwarded, `for=172.32.10.15; proto=https;by=127.0.0.1`, "https"}, // Space before proto
+ {forwarded, `for=192.0.2.60;proto=http;by=203.0.113.43`, "http"}, // Multiple params
+ }
+
+ for _, v := range headers {
+ req := &http.Request{
+ Header: http.Header{
+ v.key: []string{v.val},
+ },
+ }
+ res := getScheme(req)
+ if res != v.expected {
+ t.Fatalf("wrong header for %s: got %s want %s", v.key, res,
+ v.expected)
+ }
+ }
+}
+
+// Test the middleware end-to-end
+func TestProxyHeaders(t *testing.T) {
+ rr := httptest.NewRecorder()
+ r := newRequest("GET", "/")
+
+ r.Header.Set(xForwardedFor, "8.8.8.8")
+ r.Header.Set(xForwardedProto, "https")
+
+ var addr string
+ var proto string
+ ProxyHeaders(http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ addr = r.RemoteAddr
+ proto = r.URL.Scheme
+ })).ServeHTTP(rr, r)
+
+ if rr.Code != http.StatusOK {
+ t.Fatalf("bad status: got %d want %d", rr.Code, http.StatusOK)
+ }
+
+ if addr != r.Header.Get(xForwardedFor) {
+ t.Fatalf("wrong address: got %s want %s", addr,
+ r.Header.Get(xForwardedFor))
+ }
+
+ if proto != r.Header.Get(xForwardedProto) {
+ t.Fatalf("wrong address: got %s want %s", proto,
+ r.Header.Get(xForwardedProto))
+ }
+
+}
diff --git a/vendor/github.com/gorilla/handlers/recovery_test.go b/vendor/github.com/gorilla/handlers/recovery_test.go
new file mode 100644
index 000000000..1ae0e5805
--- /dev/null
+++ b/vendor/github.com/gorilla/handlers/recovery_test.go
@@ -0,0 +1,44 @@
+package handlers
+
+import (
+ "bytes"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+)
+
+func TestRecoveryLoggerWithDefaultOptions(t *testing.T) {
+ var buf bytes.Buffer
+ log.SetOutput(&buf)
+
+ handler := RecoveryHandler()
+ handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ panic("Unexpected error!")
+ })
+
+ recovery := handler(handlerFunc)
+ recovery.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/subdir/asdf"))
+
+ if !strings.Contains(buf.String(), "Unexpected error!") {
+ t.Fatalf("Got log %#v, wanted substring %#v", buf.String(), "Unexpected error!")
+ }
+}
+
+func TestRecoveryLoggerWithCustomLogger(t *testing.T) {
+ var buf bytes.Buffer
+ var logger = log.New(&buf, "", log.LstdFlags)
+
+ handler := RecoveryHandler(RecoveryLogger(logger), PrintRecoveryStack(false))
+ handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ panic("Unexpected error!")
+ })
+
+ recovery := handler(handlerFunc)
+ recovery.ServeHTTP(httptest.NewRecorder(), newRequest("GET", "/subdir/asdf"))
+
+ if !strings.Contains(buf.String(), "Unexpected error!") {
+ t.Fatalf("Got log %#v, wanted substring %#v", buf.String(), "Unexpected error!")
+ }
+}
diff --git a/vendor/github.com/gorilla/mux/bench_test.go b/vendor/github.com/gorilla/mux/bench_test.go
new file mode 100644
index 000000000..946289b92
--- /dev/null
+++ b/vendor/github.com/gorilla/mux/bench_test.go
@@ -0,0 +1,49 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mux
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func BenchmarkMux(b *testing.B) {
+ router := new(Router)
+ handler := func(w http.ResponseWriter, r *http.Request) {}
+ router.HandleFunc("/v1/{v1}", handler)
+
+ request, _ := http.NewRequest("GET", "/v1/anything", nil)
+ for i := 0; i < b.N; i++ {
+ router.ServeHTTP(nil, request)
+ }
+}
+
+func BenchmarkMuxAlternativeInRegexp(b *testing.B) {
+ router := new(Router)
+ handler := func(w http.ResponseWriter, r *http.Request) {}
+ router.HandleFunc("/v1/{v1:(a|b)}", handler)
+
+ requestA, _ := http.NewRequest("GET", "/v1/a", nil)
+ requestB, _ := http.NewRequest("GET", "/v1/b", nil)
+ for i := 0; i < b.N; i++ {
+ router.ServeHTTP(nil, requestA)
+ router.ServeHTTP(nil, requestB)
+ }
+}
+
+func BenchmarkManyPathVariables(b *testing.B) {
+ router := new(Router)
+ handler := func(w http.ResponseWriter, r *http.Request) {}
+ router.HandleFunc("/v1/{v1}/{v2}/{v3}/{v4}/{v5}", handler)
+
+ matchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4/5", nil)
+ notMatchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4", nil)
+ recorder := httptest.NewRecorder()
+ for i := 0; i < b.N; i++ {
+ router.ServeHTTP(nil, matchingRequest)
+ router.ServeHTTP(recorder, notMatchingRequest)
+ }
+}
diff --git a/vendor/github.com/gorilla/mux/mux_test.go b/vendor/github.com/gorilla/mux/mux_test.go
new file mode 100644
index 000000000..777d063c0
--- /dev/null
+++ b/vendor/github.com/gorilla/mux/mux_test.go
@@ -0,0 +1,1471 @@
+// Copyright 2012 The Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mux
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+ "testing"
+
+ "github.com/gorilla/context"
+)
+
+func (r *Route) GoString() string {
+ matchers := make([]string, len(r.matchers))
+ for i, m := range r.matchers {
+ matchers[i] = fmt.Sprintf("%#v", m)
+ }
+ return fmt.Sprintf("&Route{matchers:[]matcher{%s}}", strings.Join(matchers, ", "))
+}
+
+func (r *routeRegexp) GoString() string {
+ return fmt.Sprintf("&routeRegexp{template: %q, matchHost: %t, matchQuery: %t, strictSlash: %t, regexp: regexp.MustCompile(%q), reverse: %q, varsN: %v, varsR: %v", r.template, r.matchHost, r.matchQuery, r.strictSlash, r.regexp.String(), r.reverse, r.varsN, r.varsR)
+}
+
+type routeTest struct {
+ title string // title of the test
+ route *Route // the route being tested
+ request *http.Request // a request to test the route
+ vars map[string]string // the expected vars of the match
+ host string // the expected host of the match
+ path string // the expected path of the match
+ path_template string // the expected path template to match
+ host_template string // the expected host template to match
+ shouldMatch bool // whether the request is expected to match the route at all
+ shouldRedirect bool // whether the request should result in a redirect
+}
+
+func TestHost(t *testing.T) {
+ // newRequestHost a new request with a method, url, and host header
+ newRequestHost := func(method, url, host string) *http.Request {
+ req, err := http.NewRequest(method, url, nil)
+ if err != nil {
+ panic(err)
+ }
+ req.Host = host
+ return req
+ }
+
+ tests := []routeTest{
+ {
+ title: "Host route match",
+ route: new(Route).Host("aaa.bbb.ccc"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{},
+ host: "aaa.bbb.ccc",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Host route, wrong host in request URL",
+ route: new(Route).Host("aaa.bbb.ccc"),
+ request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
+ vars: map[string]string{},
+ host: "aaa.bbb.ccc",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Host route with port, match",
+ route: new(Route).Host("aaa.bbb.ccc:1234"),
+ request: newRequest("GET", "http://aaa.bbb.ccc:1234/111/222/333"),
+ vars: map[string]string{},
+ host: "aaa.bbb.ccc:1234",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Host route with port, wrong port in request URL",
+ route: new(Route).Host("aaa.bbb.ccc:1234"),
+ request: newRequest("GET", "http://aaa.bbb.ccc:9999/111/222/333"),
+ vars: map[string]string{},
+ host: "aaa.bbb.ccc:1234",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Host route, match with host in request header",
+ route: new(Route).Host("aaa.bbb.ccc"),
+ request: newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc"),
+ vars: map[string]string{},
+ host: "aaa.bbb.ccc",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Host route, wrong host in request header",
+ route: new(Route).Host("aaa.bbb.ccc"),
+ request: newRequestHost("GET", "/111/222/333", "aaa.222.ccc"),
+ vars: map[string]string{},
+ host: "aaa.bbb.ccc",
+ path: "",
+ shouldMatch: false,
+ },
+ // BUG {new(Route).Host("aaa.bbb.ccc:1234"), newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:1234"), map[string]string{}, "aaa.bbb.ccc:1234", "", true},
+ {
+ title: "Host route with port, wrong host in request header",
+ route: new(Route).Host("aaa.bbb.ccc:1234"),
+ request: newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:9999"),
+ vars: map[string]string{},
+ host: "aaa.bbb.ccc:1234",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Host route with pattern, match",
+ route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v1": "bbb"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `aaa.{v1:[a-z]{3}}.ccc`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host route with pattern, additional capturing group, match",
+ route: new(Route).Host("aaa.{v1:[a-z]{2}(b|c)}.ccc"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v1": "bbb"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `aaa.{v1:[a-z]{2}(b|c)}.ccc`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host route with pattern, wrong host in request URL",
+ route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
+ request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
+ vars: map[string]string{"v1": "bbb"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `aaa.{v1:[a-z]{3}}.ccc`,
+ shouldMatch: false,
+ },
+ {
+ title: "Host route with multiple patterns, match",
+ route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host route with multiple patterns, wrong host in request URL",
+ route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"),
+ request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
+ vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
+ shouldMatch: false,
+ },
+ {
+ title: "Host route with hyphenated name and pattern, match",
+ route: new(Route).Host("aaa.{v-1:[a-z]{3}}.ccc"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v-1": "bbb"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `aaa.{v-1:[a-z]{3}}.ccc`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host route with hyphenated name and pattern, additional capturing group, match",
+ route: new(Route).Host("aaa.{v-1:[a-z]{2}(b|c)}.ccc"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v-1": "bbb"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `aaa.{v-1:[a-z]{2}(b|c)}.ccc`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host route with multiple hyphenated names and patterns, match",
+ route: new(Route).Host("{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v-1": "aaa", "v-2": "bbb", "v-3": "ccc"},
+ host: "aaa.bbb.ccc",
+ path: "",
+ host_template: `{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with single pattern with pipe, match",
+ route: new(Route).Path("/{category:a|b/c}"),
+ request: newRequest("GET", "http://localhost/a"),
+ vars: map[string]string{"category": "a"},
+ host: "",
+ path: "/a",
+ path_template: `/{category:a|b/c}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with single pattern with pipe, match",
+ route: new(Route).Path("/{category:a|b/c}"),
+ request: newRequest("GET", "http://localhost/b/c"),
+ vars: map[string]string{"category": "b/c"},
+ host: "",
+ path: "/b/c",
+ path_template: `/{category:a|b/c}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with multiple patterns with pipe, match",
+ route: new(Route).Path("/{category:a|b/c}/{product}/{id:[0-9]+}"),
+ request: newRequest("GET", "http://localhost/a/product_name/1"),
+ vars: map[string]string{"category": "a", "product": "product_name", "id": "1"},
+ host: "",
+ path: "/a/product_name/1",
+ path_template: `/{category:a|b/c}/{product}/{id:[0-9]+}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with multiple patterns with pipe, match",
+ route: new(Route).Path("/{category:a|b/c}/{product}/{id:[0-9]+}"),
+ request: newRequest("GET", "http://localhost/b/c/product_name/1"),
+ vars: map[string]string{"category": "b/c", "product": "product_name", "id": "1"},
+ host: "",
+ path: "/b/c/product_name/1",
+ path_template: `/{category:a|b/c}/{product}/{id:[0-9]+}`,
+ shouldMatch: true,
+ },
+ }
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestPath(t *testing.T) {
+ tests := []routeTest{
+ {
+ title: "Path route, match",
+ route: new(Route).Path("/111/222/333"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111/222/333",
+ shouldMatch: true,
+ },
+ {
+ title: "Path route, match with trailing slash in request and path",
+ route: new(Route).Path("/111/"),
+ request: newRequest("GET", "http://localhost/111/"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111/",
+ shouldMatch: true,
+ },
+ {
+ title: "Path route, do not match with trailing slash in path",
+ route: new(Route).Path("/111/"),
+ request: newRequest("GET", "http://localhost/111"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111",
+ path_template: `/111/`,
+ shouldMatch: false,
+ },
+ {
+ title: "Path route, do not match with trailing slash in request",
+ route: new(Route).Path("/111"),
+ request: newRequest("GET", "http://localhost/111/"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111/",
+ path_template: `/111`,
+ shouldMatch: false,
+ },
+ {
+ title: "Path route, wrong path in request in request URL",
+ route: new(Route).Path("/111/222/333"),
+ request: newRequest("GET", "http://localhost/1/2/3"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111/222/333",
+ shouldMatch: false,
+ },
+ {
+ title: "Path route with pattern, match",
+ route: new(Route).Path("/111/{v1:[0-9]{3}}/333"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{"v1": "222"},
+ host: "",
+ path: "/111/222/333",
+ path_template: `/111/{v1:[0-9]{3}}/333`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with pattern, URL in request does not match",
+ route: new(Route).Path("/111/{v1:[0-9]{3}}/333"),
+ request: newRequest("GET", "http://localhost/111/aaa/333"),
+ vars: map[string]string{"v1": "222"},
+ host: "",
+ path: "/111/222/333",
+ path_template: `/111/{v1:[0-9]{3}}/333`,
+ shouldMatch: false,
+ },
+ {
+ title: "Path route with multiple patterns, match",
+ route: new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{"v1": "111", "v2": "222", "v3": "333"},
+ host: "",
+ path: "/111/222/333",
+ path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with multiple patterns, URL in request does not match",
+ route: new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"),
+ request: newRequest("GET", "http://localhost/111/aaa/333"),
+ vars: map[string]string{"v1": "111", "v2": "222", "v3": "333"},
+ host: "",
+ path: "/111/222/333",
+ path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}`,
+ shouldMatch: false,
+ },
+ {
+ title: "Path route with multiple patterns with pipe, match",
+ route: new(Route).Path("/{category:a|(b/c)}/{product}/{id:[0-9]+}"),
+ request: newRequest("GET", "http://localhost/a/product_name/1"),
+ vars: map[string]string{"category": "a", "product": "product_name", "id": "1"},
+ host: "",
+ path: "/a/product_name/1",
+ path_template: `/{category:a|(b/c)}/{product}/{id:[0-9]+}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with hyphenated name and pattern, match",
+ route: new(Route).Path("/111/{v-1:[0-9]{3}}/333"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{"v-1": "222"},
+ host: "",
+ path: "/111/222/333",
+ path_template: `/111/{v-1:[0-9]{3}}/333`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with multiple hyphenated names and patterns, match",
+ route: new(Route).Path("/{v-1:[0-9]{3}}/{v-2:[0-9]{3}}/{v-3:[0-9]{3}}"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{"v-1": "111", "v-2": "222", "v-3": "333"},
+ host: "",
+ path: "/111/222/333",
+ path_template: `/{v-1:[0-9]{3}}/{v-2:[0-9]{3}}/{v-3:[0-9]{3}}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with multiple hyphenated names and patterns with pipe, match",
+ route: new(Route).Path("/{product-category:a|(b/c)}/{product-name}/{product-id:[0-9]+}"),
+ request: newRequest("GET", "http://localhost/a/product_name/1"),
+ vars: map[string]string{"product-category": "a", "product-name": "product_name", "product-id": "1"},
+ host: "",
+ path: "/a/product_name/1",
+ path_template: `/{product-category:a|(b/c)}/{product-name}/{product-id:[0-9]+}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Path route with multiple hyphenated names and patterns with pipe and case insensitive, match",
+ route: new(Route).Path("/{type:(?i:daily|mini|variety)}-{date:\\d{4,4}-\\d{2,2}-\\d{2,2}}"),
+ request: newRequest("GET", "http://localhost/daily-2016-01-01"),
+ vars: map[string]string{"type": "daily", "date": "2016-01-01"},
+ host: "",
+ path: "/daily-2016-01-01",
+ path_template: `/{type:(?i:daily|mini|variety)}-{date:\d{4,4}-\d{2,2}-\d{2,2}}`,
+ shouldMatch: true,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestPathPrefix(t *testing.T) {
+ tests := []routeTest{
+ {
+ title: "PathPrefix route, match",
+ route: new(Route).PathPrefix("/111"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111",
+ shouldMatch: true,
+ },
+ {
+ title: "PathPrefix route, match substring",
+ route: new(Route).PathPrefix("/1"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{},
+ host: "",
+ path: "/1",
+ shouldMatch: true,
+ },
+ {
+ title: "PathPrefix route, URL prefix in request does not match",
+ route: new(Route).PathPrefix("/111"),
+ request: newRequest("GET", "http://localhost/1/2/3"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111",
+ shouldMatch: false,
+ },
+ {
+ title: "PathPrefix route with pattern, match",
+ route: new(Route).PathPrefix("/111/{v1:[0-9]{3}}"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{"v1": "222"},
+ host: "",
+ path: "/111/222",
+ path_template: `/111/{v1:[0-9]{3}}`,
+ shouldMatch: true,
+ },
+ {
+ title: "PathPrefix route with pattern, URL prefix in request does not match",
+ route: new(Route).PathPrefix("/111/{v1:[0-9]{3}}"),
+ request: newRequest("GET", "http://localhost/111/aaa/333"),
+ vars: map[string]string{"v1": "222"},
+ host: "",
+ path: "/111/222",
+ path_template: `/111/{v1:[0-9]{3}}`,
+ shouldMatch: false,
+ },
+ {
+ title: "PathPrefix route with multiple patterns, match",
+ route: new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"),
+ request: newRequest("GET", "http://localhost/111/222/333"),
+ vars: map[string]string{"v1": "111", "v2": "222"},
+ host: "",
+ path: "/111/222",
+ path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}`,
+ shouldMatch: true,
+ },
+ {
+ title: "PathPrefix route with multiple patterns, URL prefix in request does not match",
+ route: new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"),
+ request: newRequest("GET", "http://localhost/111/aaa/333"),
+ vars: map[string]string{"v1": "111", "v2": "222"},
+ host: "",
+ path: "/111/222",
+ path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}`,
+ shouldMatch: false,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestHostPath(t *testing.T) {
+ tests := []routeTest{
+ {
+ title: "Host and Path route, match",
+ route: new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ path_template: `/111/222/333`,
+ host_template: `aaa.bbb.ccc`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host and Path route, wrong host in request URL",
+ route: new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"),
+ request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ path_template: `/111/222/333`,
+ host_template: `aaa.bbb.ccc`,
+ shouldMatch: false,
+ },
+ {
+ title: "Host and Path route with pattern, match",
+ route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v1": "bbb", "v2": "222"},
+ host: "aaa.bbb.ccc",
+ path: "/111/222/333",
+ path_template: `/111/{v2:[0-9]{3}}/333`,
+ host_template: `aaa.{v1:[a-z]{3}}.ccc`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host and Path route with pattern, URL in request does not match",
+ route: new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"),
+ request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
+ vars: map[string]string{"v1": "bbb", "v2": "222"},
+ host: "aaa.bbb.ccc",
+ path: "/111/222/333",
+ path_template: `/111/{v2:[0-9]{3}}/333`,
+ host_template: `aaa.{v1:[a-z]{3}}.ccc`,
+ shouldMatch: false,
+ },
+ {
+ title: "Host and Path route with multiple patterns, match",
+ route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"),
+ request: newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
+ vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"},
+ host: "aaa.bbb.ccc",
+ path: "/111/222/333",
+ path_template: `/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}`,
+ host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
+ shouldMatch: true,
+ },
+ {
+ title: "Host and Path route with multiple patterns, URL in request does not match",
+ route: new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"),
+ request: newRequest("GET", "http://aaa.222.ccc/111/222/333"),
+ vars: map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"},
+ host: "aaa.bbb.ccc",
+ path: "/111/222/333",
+ path_template: `/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}`,
+ host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
+ shouldMatch: false,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestHeaders(t *testing.T) {
+ // newRequestHeaders creates a new request with a method, url, and headers
+ newRequestHeaders := func(method, url string, headers map[string]string) *http.Request {
+ req, err := http.NewRequest(method, url, nil)
+ if err != nil {
+ panic(err)
+ }
+ for k, v := range headers {
+ req.Header.Add(k, v)
+ }
+ return req
+ }
+
+ tests := []routeTest{
+ {
+ title: "Headers route, match",
+ route: new(Route).Headers("foo", "bar", "baz", "ding"),
+ request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "ding"}),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Headers route, bad header values",
+ route: new(Route).Headers("foo", "bar", "baz", "ding"),
+ request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "dong"}),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Headers route, regex header values to match",
+ route: new(Route).Headers("foo", "ba[zr]"),
+ request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar"}),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Headers route, regex header values to match",
+ route: new(Route).HeadersRegexp("foo", "ba[zr]"),
+ request: newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "baz"}),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+
+}
+
+func TestMethods(t *testing.T) {
+ tests := []routeTest{
+ {
+ title: "Methods route, match GET",
+ route: new(Route).Methods("GET", "POST"),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Methods route, match POST",
+ route: new(Route).Methods("GET", "POST"),
+ request: newRequest("POST", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Methods route, bad method",
+ route: new(Route).Methods("GET", "POST"),
+ request: newRequest("PUT", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestQueries(t *testing.T) {
+ tests := []routeTest{
+ {
+ title: "Queries route, match",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, match with a query string",
+ route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ path_template: `/api`,
+ host_template: `www.example.com`,
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, match with a query string out of order",
+ route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ path_template: `/api`,
+ host_template: `www.example.com`,
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, bad query",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with pattern, match",
+ route: new(Route).Queries("foo", "{v1}"),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{"v1": "bar"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with multiple patterns, match",
+ route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{"v1": "bar", "v2": "ding"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=10"),
+ vars: map[string]string{"v1": "10"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=a"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=1"),
+ vars: map[string]string{"v1": "1"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, additional variable in query string, match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?bar=2&foo=1"),
+ vars: map[string]string{"v1": "1"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=12"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, additional capturing group",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}(a|b)}"),
+ request: newRequest("GET", "http://localhost?foo=1a"),
+ vars: map[string]string{"v1": "1a"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
+ route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
+ request: newRequest("GET", "http://localhost?foo=12"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with hyphenated name, match",
+ route: new(Route).Queries("foo", "{v-1}"),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{"v-1": "bar"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with multiple hyphenated names, match",
+ route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
+ request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
+ vars: map[string]string{"v-1": "bar", "v-2": "ding"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with hyphenate name and pattern, match",
+ route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
+ request: newRequest("GET", "http://localhost?foo=10"),
+ vars: map[string]string{"v-1": "10"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
+ route: new(Route).Queries("foo", "{v-1:[0-9]{1}(a|b)}"),
+ request: newRequest("GET", "http://localhost?foo=1a"),
+ vars: map[string]string{"v-1": "1a"},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with empty value, should match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost?foo=bar"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with empty value and no parameter in request, should not match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with empty value and empty parameter in request, should match",
+ route: new(Route).Queries("foo", ""),
+ request: newRequest("GET", "http://localhost?foo="),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route with overlapping value, should not match",
+ route: new(Route).Queries("foo", "bar"),
+ request: newRequest("GET", "http://localhost?foo=barfoo"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with no parameter in request, should not match",
+ route: new(Route).Queries("foo", "{bar}"),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ {
+ title: "Queries route with empty parameter in request, should match",
+ route: new(Route).Queries("foo", "{bar}"),
+ request: newRequest("GET", "http://localhost?foo="),
+ vars: map[string]string{"foo": ""},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Queries route, bad submatch",
+ route: new(Route).Queries("foo", "bar", "baz", "ding"),
+ request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestSchemes(t *testing.T) {
+ tests := []routeTest{
+ // Schemes
+ {
+ title: "Schemes route, match https",
+ route: new(Route).Schemes("https", "ftp"),
+ request: newRequest("GET", "https://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Schemes route, match ftp",
+ route: new(Route).Schemes("https", "ftp"),
+ request: newRequest("GET", "ftp://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "Schemes route, bad scheme",
+ route: new(Route).Schemes("https", "ftp"),
+ request: newRequest("GET", "http://localhost"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ }
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestMatcherFunc(t *testing.T) {
+ m := func(r *http.Request, m *RouteMatch) bool {
+ if r.URL.Host == "aaa.bbb.ccc" {
+ return true
+ }
+ return false
+ }
+
+ tests := []routeTest{
+ {
+ title: "MatchFunc route, match",
+ route: new(Route).MatcherFunc(m),
+ request: newRequest("GET", "http://aaa.bbb.ccc"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: true,
+ },
+ {
+ title: "MatchFunc route, non-match",
+ route: new(Route).MatcherFunc(m),
+ request: newRequest("GET", "http://aaa.222.ccc"),
+ vars: map[string]string{},
+ host: "",
+ path: "",
+ shouldMatch: false,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestBuildVarsFunc(t *testing.T) {
+ tests := []routeTest{
+ {
+ title: "BuildVarsFunc set on route",
+ route: new(Route).Path(`/111/{v1:\d}{v2:.*}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
+ vars["v1"] = "3"
+ vars["v2"] = "a"
+ return vars
+ }),
+ request: newRequest("GET", "http://localhost/111/2"),
+ path: "/111/3a",
+ path_template: `/111/{v1:\d}{v2:.*}`,
+ shouldMatch: true,
+ },
+ {
+ title: "BuildVarsFunc set on route and parent route",
+ route: new(Route).PathPrefix(`/{v1:\d}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
+ vars["v1"] = "2"
+ return vars
+ }).Subrouter().Path(`/{v2:\w}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
+ vars["v2"] = "b"
+ return vars
+ }),
+ request: newRequest("GET", "http://localhost/1/a"),
+ path: "/2/b",
+ path_template: `/{v1:\d}/{v2:\w}`,
+ shouldMatch: true,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestSubRouter(t *testing.T) {
+ subrouter1 := new(Route).Host("{v1:[a-z]+}.google.com").Subrouter()
+ subrouter2 := new(Route).PathPrefix("/foo/{v1}").Subrouter()
+
+ tests := []routeTest{
+ {
+ route: subrouter1.Path("/{v2:[a-z]+}"),
+ request: newRequest("GET", "http://aaa.google.com/bbb"),
+ vars: map[string]string{"v1": "aaa", "v2": "bbb"},
+ host: "aaa.google.com",
+ path: "/bbb",
+ path_template: `/{v2:[a-z]+}`,
+ host_template: `{v1:[a-z]+}.google.com`,
+ shouldMatch: true,
+ },
+ {
+ route: subrouter1.Path("/{v2:[a-z]+}"),
+ request: newRequest("GET", "http://111.google.com/111"),
+ vars: map[string]string{"v1": "aaa", "v2": "bbb"},
+ host: "aaa.google.com",
+ path: "/bbb",
+ path_template: `/{v2:[a-z]+}`,
+ host_template: `{v1:[a-z]+}.google.com`,
+ shouldMatch: false,
+ },
+ {
+ route: subrouter2.Path("/baz/{v2}"),
+ request: newRequest("GET", "http://localhost/foo/bar/baz/ding"),
+ vars: map[string]string{"v1": "bar", "v2": "ding"},
+ host: "",
+ path: "/foo/bar/baz/ding",
+ path_template: `/foo/{v1}/baz/{v2}`,
+ shouldMatch: true,
+ },
+ {
+ route: subrouter2.Path("/baz/{v2}"),
+ request: newRequest("GET", "http://localhost/foo/bar"),
+ vars: map[string]string{"v1": "bar", "v2": "ding"},
+ host: "",
+ path: "/foo/bar/baz/ding",
+ path_template: `/foo/{v1}/baz/{v2}`,
+ shouldMatch: false,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestNamedRoutes(t *testing.T) {
+ r1 := NewRouter()
+ r1.NewRoute().Name("a")
+ r1.NewRoute().Name("b")
+ r1.NewRoute().Name("c")
+
+ r2 := r1.NewRoute().Subrouter()
+ r2.NewRoute().Name("d")
+ r2.NewRoute().Name("e")
+ r2.NewRoute().Name("f")
+
+ r3 := r2.NewRoute().Subrouter()
+ r3.NewRoute().Name("g")
+ r3.NewRoute().Name("h")
+ r3.NewRoute().Name("i")
+
+ if r1.namedRoutes == nil || len(r1.namedRoutes) != 9 {
+ t.Errorf("Expected 9 named routes, got %v", r1.namedRoutes)
+ } else if r1.Get("i") == nil {
+ t.Errorf("Subroute name not registered")
+ }
+}
+
+func TestStrictSlash(t *testing.T) {
+ r := NewRouter()
+ r.StrictSlash(true)
+
+ tests := []routeTest{
+ {
+ title: "Redirect path without slash",
+ route: r.NewRoute().Path("/111/"),
+ request: newRequest("GET", "http://localhost/111"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111/",
+ shouldMatch: true,
+ shouldRedirect: true,
+ },
+ {
+ title: "Do not redirect path with slash",
+ route: r.NewRoute().Path("/111/"),
+ request: newRequest("GET", "http://localhost/111/"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111/",
+ shouldMatch: true,
+ shouldRedirect: false,
+ },
+ {
+ title: "Redirect path with slash",
+ route: r.NewRoute().Path("/111"),
+ request: newRequest("GET", "http://localhost/111/"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111",
+ shouldMatch: true,
+ shouldRedirect: true,
+ },
+ {
+ title: "Do not redirect path without slash",
+ route: r.NewRoute().Path("/111"),
+ request: newRequest("GET", "http://localhost/111"),
+ vars: map[string]string{},
+ host: "",
+ path: "/111",
+ shouldMatch: true,
+ shouldRedirect: false,
+ },
+ {
+ title: "Propagate StrictSlash to subrouters",
+ route: r.NewRoute().PathPrefix("/static/").Subrouter().Path("/images/"),
+ request: newRequest("GET", "http://localhost/static/images"),
+ vars: map[string]string{},
+ host: "",
+ path: "/static/images/",
+ shouldMatch: true,
+ shouldRedirect: true,
+ },
+ {
+ title: "Ignore StrictSlash for path prefix",
+ route: r.NewRoute().PathPrefix("/static/"),
+ request: newRequest("GET", "http://localhost/static/logo.png"),
+ vars: map[string]string{},
+ host: "",
+ path: "/static/",
+ shouldMatch: true,
+ shouldRedirect: false,
+ },
+ }
+
+ for _, test := range tests {
+ testRoute(t, test)
+ testTemplate(t, test)
+ }
+}
+
+func TestWalkSingleDepth(t *testing.T) {
+ r0 := NewRouter()
+ r1 := NewRouter()
+ r2 := NewRouter()
+
+ r0.Path("/g")
+ r0.Path("/o")
+ r0.Path("/d").Handler(r1)
+ r0.Path("/r").Handler(r2)
+ r0.Path("/a")
+
+ r1.Path("/z")
+ r1.Path("/i")
+ r1.Path("/l")
+ r1.Path("/l")
+
+ r2.Path("/i")
+ r2.Path("/l")
+ r2.Path("/l")
+
+ paths := []string{"g", "o", "r", "i", "l", "l", "a"}
+ depths := []int{0, 0, 0, 1, 1, 1, 0}
+ i := 0
+ err := r0.Walk(func(route *Route, router *Router, ancestors []*Route) error {
+ matcher := route.matchers[0].(*routeRegexp)
+ if matcher.template == "/d" {
+ return SkipRouter
+ }
+ if len(ancestors) != depths[i] {
+ t.Errorf(`Expected depth of %d at i = %d; got "%d"`, depths[i], i, len(ancestors))
+ }
+ if matcher.template != "/"+paths[i] {
+ t.Errorf(`Expected "/%s" at i = %d; got "%s"`, paths[i], i, matcher.template)
+ }
+ i++
+ return nil
+ })
+ if err != nil {
+ panic(err)
+ }
+ if i != len(paths) {
+ t.Errorf("Expected %d routes, found %d", len(paths), i)
+ }
+}
+
+func TestWalkNested(t *testing.T) {
+ router := NewRouter()
+
+ g := router.Path("/g").Subrouter()
+ o := g.PathPrefix("/o").Subrouter()
+ r := o.PathPrefix("/r").Subrouter()
+ i := r.PathPrefix("/i").Subrouter()
+ l1 := i.PathPrefix("/l").Subrouter()
+ l2 := l1.PathPrefix("/l").Subrouter()
+ l2.Path("/a")
+
+ paths := []string{"/g", "/g/o", "/g/o/r", "/g/o/r/i", "/g/o/r/i/l", "/g/o/r/i/l/l", "/g/o/r/i/l/l/a"}
+ idx := 0
+ err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error {
+ path := paths[idx]
+ tpl := route.regexp.path.template
+ if tpl != path {
+ t.Errorf(`Expected %s got %s`, path, tpl)
+ }
+ idx++
+ return nil
+ })
+ if err != nil {
+ panic(err)
+ }
+ if idx != len(paths) {
+ t.Errorf("Expected %d routes, found %d", len(paths), idx)
+ }
+}
+
+func TestSubrouterErrorHandling(t *testing.T) {
+ superRouterCalled := false
+ subRouterCalled := false
+
+ router := NewRouter()
+ router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ superRouterCalled = true
+ })
+ subRouter := router.PathPrefix("/bign8").Subrouter()
+ subRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ subRouterCalled = true
+ })
+
+ req, _ := http.NewRequest("GET", "http://localhost/bign8/was/here", nil)
+ router.ServeHTTP(NewRecorder(), req)
+
+ if superRouterCalled {
+ t.Error("Super router 404 handler called when sub-router 404 handler is available.")
+ }
+ if !subRouterCalled {
+ t.Error("Sub-router 404 handler was not called.")
+ }
+}
+
+// ----------------------------------------------------------------------------
+// Helpers
+// ----------------------------------------------------------------------------
+
+func getRouteTemplate(route *Route) string {
+ host, err := route.GetHostTemplate()
+ if err != nil {
+ host = "none"
+ }
+ path, err := route.GetPathTemplate()
+ if err != nil {
+ path = "none"
+ }
+ return fmt.Sprintf("Host: %v, Path: %v", host, path)
+}
+
+func testRoute(t *testing.T, test routeTest) {
+ request := test.request
+ route := test.route
+ vars := test.vars
+ shouldMatch := test.shouldMatch
+ host := test.host
+ path := test.path
+ url := test.host + test.path
+ shouldRedirect := test.shouldRedirect
+
+ var match RouteMatch
+ ok := route.Match(request, &match)
+ if ok != shouldMatch {
+ msg := "Should match"
+ if !shouldMatch {
+ msg = "Should not match"
+ }
+ t.Errorf("(%v) %v:\nRoute: %#v\nRequest: %#v\nVars: %v\n", test.title, msg, route, request, vars)
+ return
+ }
+ if shouldMatch {
+ if test.vars != nil && !stringMapEqual(test.vars, match.Vars) {
+ t.Errorf("(%v) Vars not equal: expected %v, got %v", test.title, vars, match.Vars)
+ return
+ }
+ if host != "" {
+ u, _ := test.route.URLHost(mapToPairs(match.Vars)...)
+ if host != u.Host {
+ t.Errorf("(%v) URLHost not equal: expected %v, got %v -- %v", test.title, host, u.Host, getRouteTemplate(route))
+ return
+ }
+ }
+ if path != "" {
+ u, _ := route.URLPath(mapToPairs(match.Vars)...)
+ if path != u.Path {
+ t.Errorf("(%v) URLPath not equal: expected %v, got %v -- %v", test.title, path, u.Path, getRouteTemplate(route))
+ return
+ }
+ }
+ if url != "" {
+ u, _ := route.URL(mapToPairs(match.Vars)...)
+ if url != u.Host+u.Path {
+ t.Errorf("(%v) URL not equal: expected %v, got %v -- %v", test.title, url, u.Host+u.Path, getRouteTemplate(route))
+ return
+ }
+ }
+ if shouldRedirect && match.Handler == nil {
+ t.Errorf("(%v) Did not redirect", test.title)
+ return
+ }
+ if !shouldRedirect && match.Handler != nil {
+ t.Errorf("(%v) Unexpected redirect", test.title)
+ return
+ }
+ }
+}
+
+func testTemplate(t *testing.T, test routeTest) {
+ route := test.route
+ path_template := test.path_template
+ if len(path_template) == 0 {
+ path_template = test.path
+ }
+ host_template := test.host_template
+ if len(host_template) == 0 {
+ host_template = test.host
+ }
+
+ path_tmpl, path_err := route.GetPathTemplate()
+ if path_err == nil && path_tmpl != path_template {
+ t.Errorf("(%v) GetPathTemplate not equal: expected %v, got %v", test.title, path_template, path_tmpl)
+ }
+
+ host_tmpl, host_err := route.GetHostTemplate()
+ if host_err == nil && host_tmpl != host_template {
+ t.Errorf("(%v) GetHostTemplate not equal: expected %v, got %v", test.title, host_template, host_tmpl)
+ }
+}
+
+// Tests that the context is cleared or not cleared properly depending on
+// the configuration of the router
+func TestKeepContext(t *testing.T) {
+ func1 := func(w http.ResponseWriter, r *http.Request) {}
+
+ r := NewRouter()
+ r.HandleFunc("/", func1).Name("func1")
+
+ req, _ := http.NewRequest("GET", "http://localhost/", nil)
+ context.Set(req, "t", 1)
+
+ res := new(http.ResponseWriter)
+ r.ServeHTTP(*res, req)
+
+ if _, ok := context.GetOk(req, "t"); ok {
+ t.Error("Context should have been cleared at end of request")
+ }
+
+ r.KeepContext = true
+
+ req, _ = http.NewRequest("GET", "http://localhost/", nil)
+ context.Set(req, "t", 1)
+
+ r.ServeHTTP(*res, req)
+ if _, ok := context.GetOk(req, "t"); !ok {
+ t.Error("Context should NOT have been cleared at end of request")
+ }
+
+}
+
+type TestA301ResponseWriter struct {
+ hh http.Header
+ status int
+}
+
+func (ho TestA301ResponseWriter) Header() http.Header {
+ return http.Header(ho.hh)
+}
+
+func (ho TestA301ResponseWriter) Write(b []byte) (int, error) {
+ return 0, nil
+}
+
+func (ho TestA301ResponseWriter) WriteHeader(code int) {
+ ho.status = code
+}
+
+func Test301Redirect(t *testing.T) {
+ m := make(http.Header)
+
+ func1 := func(w http.ResponseWriter, r *http.Request) {}
+ func2 := func(w http.ResponseWriter, r *http.Request) {}
+
+ r := NewRouter()
+ r.HandleFunc("/api/", func2).Name("func2")
+ r.HandleFunc("/", func1).Name("func1")
+
+ req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil)
+
+ res := TestA301ResponseWriter{
+ hh: m,
+ status: 0,
+ }
+ r.ServeHTTP(&res, req)
+
+ if "http://localhost/api/?abc=def" != res.hh["Location"][0] {
+ t.Errorf("Should have complete URL with query string")
+ }
+}
+
+func TestSkipClean(t *testing.T) {
+ func1 := func(w http.ResponseWriter, r *http.Request) {}
+ func2 := func(w http.ResponseWriter, r *http.Request) {}
+
+ r := NewRouter()
+ r.SkipClean(true)
+ r.HandleFunc("/api/", func2).Name("func2")
+ r.HandleFunc("/", func1).Name("func1")
+
+ req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil)
+ res := NewRecorder()
+ r.ServeHTTP(res, req)
+
+ if len(res.HeaderMap["Location"]) != 0 {
+ t.Errorf("Shouldn't redirect since skip clean is disabled")
+ }
+}
+
+// https://plus.google.com/101022900381697718949/posts/eWy6DjFJ6uW
+func TestSubrouterHeader(t *testing.T) {
+ expected := "func1 response"
+ func1 := func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprint(w, expected)
+ }
+ func2 := func(http.ResponseWriter, *http.Request) {}
+
+ r := NewRouter()
+ s := r.Headers("SomeSpecialHeader", "").Subrouter()
+ s.HandleFunc("/", func1).Name("func1")
+ r.HandleFunc("/", func2).Name("func2")
+
+ req, _ := http.NewRequest("GET", "http://localhost/", nil)
+ req.Header.Add("SomeSpecialHeader", "foo")
+ match := new(RouteMatch)
+ matched := r.Match(req, match)
+ if !matched {
+ t.Errorf("Should match request")
+ }
+ if match.Route.GetName() != "func1" {
+ t.Errorf("Expecting func1 handler, got %s", match.Route.GetName())
+ }
+ resp := NewRecorder()
+ match.Handler.ServeHTTP(resp, req)
+ if resp.Body.String() != expected {
+ t.Errorf("Expecting %q", expected)
+ }
+}
+
+// mapToPairs converts a string map to a slice of string pairs
+func mapToPairs(m map[string]string) []string {
+ var i int
+ p := make([]string, len(m)*2)
+ for k, v := range m {
+ p[i] = k
+ p[i+1] = v
+ i += 2
+ }
+ return p
+}
+
+// stringMapEqual checks the equality of two string maps
+func stringMapEqual(m1, m2 map[string]string) bool {
+ nil1 := m1 == nil
+ nil2 := m2 == nil
+ if nil1 != nil2 || len(m1) != len(m2) {
+ return false
+ }
+ for k, v := range m1 {
+ if v != m2[k] {
+ return false
+ }
+ }
+ return true
+}
+
+// newRequest is a helper function to create a new request with a method and url
+func newRequest(method, url string) *http.Request {
+ req, err := http.NewRequest(method, url, nil)
+ if err != nil {
+ panic(err)
+ }
+ return req
+}
diff --git a/vendor/github.com/gorilla/mux/old_test.go b/vendor/github.com/gorilla/mux/old_test.go
new file mode 100644
index 000000000..c385a2519
--- /dev/null
+++ b/vendor/github.com/gorilla/mux/old_test.go
@@ -0,0 +1,710 @@
+// Old tests ported to Go1. This is a mess. Want to drop it one day.
+
+// Copyright 2011 Gorilla Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mux
+
+import (
+ "bytes"
+ "net/http"
+ "testing"
+)
+
+// ----------------------------------------------------------------------------
+// ResponseRecorder
+// ----------------------------------------------------------------------------
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// ResponseRecorder is an implementation of http.ResponseWriter that
+// records its mutations for later inspection in tests.
+type ResponseRecorder struct {
+ Code int // the HTTP response code from WriteHeader
+ HeaderMap http.Header // the HTTP response headers
+ Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
+ Flushed bool
+}
+
+// NewRecorder returns an initialized ResponseRecorder.
+func NewRecorder() *ResponseRecorder {
+ return &ResponseRecorder{
+ HeaderMap: make(http.Header),
+ Body: new(bytes.Buffer),
+ }
+}
+
+// Header returns the response headers.
+func (rw *ResponseRecorder) Header() http.Header {
+ return rw.HeaderMap
+}
+
+// Write always succeeds and writes to rw.Body, if not nil.
+func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
+ if rw.Body != nil {
+ rw.Body.Write(buf)
+ }
+ if rw.Code == 0 {
+ rw.Code = http.StatusOK
+ }
+ return len(buf), nil
+}
+
+// WriteHeader sets rw.Code.
+func (rw *ResponseRecorder) WriteHeader(code int) {
+ rw.Code = code
+}
+
+// Flush sets rw.Flushed to true.
+func (rw *ResponseRecorder) Flush() {
+ rw.Flushed = true
+}
+
+// ----------------------------------------------------------------------------
+
+func TestRouteMatchers(t *testing.T) {
+ var scheme, host, path, query, method string
+ var headers map[string]string
+ var resultVars map[bool]map[string]string
+
+ router := NewRouter()
+ router.NewRoute().Host("{var1}.google.com").
+ Path("/{var2:[a-z]+}/{var3:[0-9]+}").
+ Queries("foo", "bar").
+ Methods("GET").
+ Schemes("https").
+ Headers("x-requested-with", "XMLHttpRequest")
+ router.NewRoute().Host("www.{var4}.com").
+ PathPrefix("/foo/{var5:[a-z]+}/{var6:[0-9]+}").
+ Queries("baz", "ding").
+ Methods("POST").
+ Schemes("http").
+ Headers("Content-Type", "application/json")
+
+ reset := func() {
+ // Everything match.
+ scheme = "https"
+ host = "www.google.com"
+ path = "/product/42"
+ query = "?foo=bar"
+ method = "GET"
+ headers = map[string]string{"X-Requested-With": "XMLHttpRequest"}
+ resultVars = map[bool]map[string]string{
+ true: {"var1": "www", "var2": "product", "var3": "42"},
+ false: {},
+ }
+ }
+
+ reset2 := func() {
+ // Everything match.
+ scheme = "http"
+ host = "www.google.com"
+ path = "/foo/product/42/path/that/is/ignored"
+ query = "?baz=ding"
+ method = "POST"
+ headers = map[string]string{"Content-Type": "application/json"}
+ resultVars = map[bool]map[string]string{
+ true: {"var4": "google", "var5": "product", "var6": "42"},
+ false: {},
+ }
+ }
+
+ match := func(shouldMatch bool) {
+ url := scheme + "://" + host + path + query
+ request, _ := http.NewRequest(method, url, nil)
+ for key, value := range headers {
+ request.Header.Add(key, value)
+ }
+
+ var routeMatch RouteMatch
+ matched := router.Match(request, &routeMatch)
+ if matched != shouldMatch {
+ // Need better messages. :)
+ if matched {
+ t.Errorf("Should match.")
+ } else {
+ t.Errorf("Should not match.")
+ }
+ }
+
+ if matched {
+ currentRoute := routeMatch.Route
+ if currentRoute == nil {
+ t.Errorf("Expected a current route.")
+ }
+ vars := routeMatch.Vars
+ expectedVars := resultVars[shouldMatch]
+ if len(vars) != len(expectedVars) {
+ t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars)
+ }
+ for name, value := range vars {
+ if expectedVars[name] != value {
+ t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars)
+ }
+ }
+ }
+ }
+
+ // 1st route --------------------------------------------------------------
+
+ // Everything match.
+ reset()
+ match(true)
+
+ // Scheme doesn't match.
+ reset()
+ scheme = "http"
+ match(false)
+
+ // Host doesn't match.
+ reset()
+ host = "www.mygoogle.com"
+ match(false)
+
+ // Path doesn't match.
+ reset()
+ path = "/product/notdigits"
+ match(false)
+
+ // Query doesn't match.
+ reset()
+ query = "?foo=baz"
+ match(false)
+
+ // Method doesn't match.
+ reset()
+ method = "POST"
+ match(false)
+
+ // Header doesn't match.
+ reset()
+ headers = map[string]string{}
+ match(false)
+
+ // Everything match, again.
+ reset()
+ match(true)
+
+ // 2nd route --------------------------------------------------------------
+
+ // Everything match.
+ reset2()
+ match(true)
+
+ // Scheme doesn't match.
+ reset2()
+ scheme = "https"
+ match(false)
+
+ // Host doesn't match.
+ reset2()
+ host = "sub.google.com"
+ match(false)
+
+ // Path doesn't match.
+ reset2()
+ path = "/bar/product/42"
+ match(false)
+
+ // Query doesn't match.
+ reset2()
+ query = "?foo=baz"
+ match(false)
+
+ // Method doesn't match.
+ reset2()
+ method = "GET"
+ match(false)
+
+ // Header doesn't match.
+ reset2()
+ headers = map[string]string{}
+ match(false)
+
+ // Everything match, again.
+ reset2()
+ match(true)
+}
+
+type headerMatcherTest struct {
+ matcher headerMatcher
+ headers map[string]string
+ result bool
+}
+
+var headerMatcherTests = []headerMatcherTest{
+ {
+ matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}),
+ headers: map[string]string{"X-Requested-With": "XMLHttpRequest"},
+ result: true,
+ },
+ {
+ matcher: headerMatcher(map[string]string{"x-requested-with": ""}),
+ headers: map[string]string{"X-Requested-With": "anything"},
+ result: true,
+ },
+ {
+ matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}),
+ headers: map[string]string{},
+ result: false,
+ },
+}
+
+type hostMatcherTest struct {
+ matcher *Route
+ url string
+ vars map[string]string
+ result bool
+}
+
+var hostMatcherTests = []hostMatcherTest{
+ {
+ matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"),
+ url: "http://abc.def.ghi/",
+ vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"},
+ result: true,
+ },
+ {
+ matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"),
+ url: "http://a.b.c/",
+ vars: map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"},
+ result: false,
+ },
+}
+
+type methodMatcherTest struct {
+ matcher methodMatcher
+ method string
+ result bool
+}
+
+var methodMatcherTests = []methodMatcherTest{
+ {
+ matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
+ method: "GET",
+ result: true,
+ },
+ {
+ matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
+ method: "POST",
+ result: true,
+ },
+ {
+ matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
+ method: "PUT",
+ result: true,
+ },
+ {
+ matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
+ method: "DELETE",
+ result: false,
+ },
+}
+
+type pathMatcherTest struct {
+ matcher *Route
+ url string
+ vars map[string]string
+ result bool
+}
+
+var pathMatcherTests = []pathMatcherTest{
+ {
+ matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"),
+ url: "http://localhost:8080/123/456/789",
+ vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"},
+ result: true,
+ },
+ {
+ matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"),
+ url: "http://localhost:8080/1/2/3",
+ vars: map[string]string{"foo": "123", "bar": "456", "baz": "789"},
+ result: false,
+ },
+}
+
+type schemeMatcherTest struct {
+ matcher schemeMatcher
+ url string
+ result bool
+}
+
+var schemeMatcherTests = []schemeMatcherTest{
+ {
+ matcher: schemeMatcher([]string{"http", "https"}),
+ url: "http://localhost:8080/",
+ result: true,
+ },
+ {
+ matcher: schemeMatcher([]string{"http", "https"}),
+ url: "https://localhost:8080/",
+ result: true,
+ },
+ {
+ matcher: schemeMatcher([]string{"https"}),
+ url: "http://localhost:8080/",
+ result: false,
+ },
+ {
+ matcher: schemeMatcher([]string{"http"}),
+ url: "https://localhost:8080/",
+ result: false,
+ },
+}
+
+type urlBuildingTest struct {
+ route *Route
+ vars []string
+ url string
+}
+
+var urlBuildingTests = []urlBuildingTest{
+ {
+ route: new(Route).Host("foo.domain.com"),
+ vars: []string{},
+ url: "http://foo.domain.com",
+ },
+ {
+ route: new(Route).Host("{subdomain}.domain.com"),
+ vars: []string{"subdomain", "bar"},
+ url: "http://bar.domain.com",
+ },
+ {
+ route: new(Route).Host("foo.domain.com").Path("/articles"),
+ vars: []string{},
+ url: "http://foo.domain.com/articles",
+ },
+ {
+ route: new(Route).Path("/articles"),
+ vars: []string{},
+ url: "/articles",
+ },
+ {
+ route: new(Route).Path("/articles/{category}/{id:[0-9]+}"),
+ vars: []string{"category", "technology", "id", "42"},
+ url: "/articles/technology/42",
+ },
+ {
+ route: new(Route).Host("{subdomain}.domain.com").Path("/articles/{category}/{id:[0-9]+}"),
+ vars: []string{"subdomain", "foo", "category", "technology", "id", "42"},
+ url: "http://foo.domain.com/articles/technology/42",
+ },
+}
+
+func TestHeaderMatcher(t *testing.T) {
+ for _, v := range headerMatcherTests {
+ request, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
+ for key, value := range v.headers {
+ request.Header.Add(key, value)
+ }
+ var routeMatch RouteMatch
+ result := v.matcher.Match(request, &routeMatch)
+ if result != v.result {
+ if v.result {
+ t.Errorf("%#v: should match %v.", v.matcher, request.Header)
+ } else {
+ t.Errorf("%#v: should not match %v.", v.matcher, request.Header)
+ }
+ }
+ }
+}
+
+func TestHostMatcher(t *testing.T) {
+ for _, v := range hostMatcherTests {
+ request, _ := http.NewRequest("GET", v.url, nil)
+ var routeMatch RouteMatch
+ result := v.matcher.Match(request, &routeMatch)
+ vars := routeMatch.Vars
+ if result != v.result {
+ if v.result {
+ t.Errorf("%#v: should match %v.", v.matcher, v.url)
+ } else {
+ t.Errorf("%#v: should not match %v.", v.matcher, v.url)
+ }
+ }
+ if result {
+ if len(vars) != len(v.vars) {
+ t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars))
+ }
+ for name, value := range vars {
+ if v.vars[name] != value {
+ t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value)
+ }
+ }
+ } else {
+ if len(vars) != 0 {
+ t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars))
+ }
+ }
+ }
+}
+
+func TestMethodMatcher(t *testing.T) {
+ for _, v := range methodMatcherTests {
+ request, _ := http.NewRequest(v.method, "http://localhost:8080/", nil)
+ var routeMatch RouteMatch
+ result := v.matcher.Match(request, &routeMatch)
+ if result != v.result {
+ if v.result {
+ t.Errorf("%#v: should match %v.", v.matcher, v.method)
+ } else {
+ t.Errorf("%#v: should not match %v.", v.matcher, v.method)
+ }
+ }
+ }
+}
+
+func TestPathMatcher(t *testing.T) {
+ for _, v := range pathMatcherTests {
+ request, _ := http.NewRequest("GET", v.url, nil)
+ var routeMatch RouteMatch
+ result := v.matcher.Match(request, &routeMatch)
+ vars := routeMatch.Vars
+ if result != v.result {
+ if v.result {
+ t.Errorf("%#v: should match %v.", v.matcher, v.url)
+ } else {
+ t.Errorf("%#v: should not match %v.", v.matcher, v.url)
+ }
+ }
+ if result {
+ if len(vars) != len(v.vars) {
+ t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars))
+ }
+ for name, value := range vars {
+ if v.vars[name] != value {
+ t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value)
+ }
+ }
+ } else {
+ if len(vars) != 0 {
+ t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars))
+ }
+ }
+ }
+}
+
+func TestSchemeMatcher(t *testing.T) {
+ for _, v := range schemeMatcherTests {
+ request, _ := http.NewRequest("GET", v.url, nil)
+ var routeMatch RouteMatch
+ result := v.matcher.Match(request, &routeMatch)
+ if result != v.result {
+ if v.result {
+ t.Errorf("%#v: should match %v.", v.matcher, v.url)
+ } else {
+ t.Errorf("%#v: should not match %v.", v.matcher, v.url)
+ }
+ }
+ }
+}
+
+func TestUrlBuilding(t *testing.T) {
+
+ for _, v := range urlBuildingTests {
+ u, _ := v.route.URL(v.vars...)
+ url := u.String()
+ if url != v.url {
+ t.Errorf("expected %v, got %v", v.url, url)
+ /*
+ reversePath := ""
+ reverseHost := ""
+ if v.route.pathTemplate != nil {
+ reversePath = v.route.pathTemplate.Reverse
+ }
+ if v.route.hostTemplate != nil {
+ reverseHost = v.route.hostTemplate.Reverse
+ }
+
+ t.Errorf("%#v:\nexpected: %q\ngot: %q\nreverse path: %q\nreverse host: %q", v.route, v.url, url, reversePath, reverseHost)
+ */
+ }
+ }
+
+ ArticleHandler := func(w http.ResponseWriter, r *http.Request) {
+ }
+
+ router := NewRouter()
+ router.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).Name("article")
+
+ url, _ := router.Get("article").URL("category", "technology", "id", "42")
+ expected := "/articles/technology/42"
+ if url.String() != expected {
+ t.Errorf("Expected %v, got %v", expected, url.String())
+ }
+}
+
+func TestMatchedRouteName(t *testing.T) {
+ routeName := "stock"
+ router := NewRouter()
+ route := router.NewRoute().Path("/products/").Name(routeName)
+
+ url := "http://www.example.com/products/"
+ request, _ := http.NewRequest("GET", url, nil)
+ var rv RouteMatch
+ ok := router.Match(request, &rv)
+
+ if !ok || rv.Route != route {
+ t.Errorf("Expected same route, got %+v.", rv.Route)
+ }
+
+ retName := rv.Route.GetName()
+ if retName != routeName {
+ t.Errorf("Expected %q, got %q.", routeName, retName)
+ }
+}
+
+func TestSubRouting(t *testing.T) {
+ // Example from docs.
+ router := NewRouter()
+ subrouter := router.NewRoute().Host("www.example.com").Subrouter()
+ route := subrouter.NewRoute().Path("/products/").Name("products")
+
+ url := "http://www.example.com/products/"
+ request, _ := http.NewRequest("GET", url, nil)
+ var rv RouteMatch
+ ok := router.Match(request, &rv)
+
+ if !ok || rv.Route != route {
+ t.Errorf("Expected same route, got %+v.", rv.Route)
+ }
+
+ u, _ := router.Get("products").URL()
+ builtURL := u.String()
+ // Yay, subroute aware of the domain when building!
+ if builtURL != url {
+ t.Errorf("Expected %q, got %q.", url, builtURL)
+ }
+}
+
+func TestVariableNames(t *testing.T) {
+ route := new(Route).Host("{arg1}.domain.com").Path("/{arg1}/{arg2:[0-9]+}")
+ if route.err == nil {
+ t.Errorf("Expected error for duplicated variable names")
+ }
+}
+
+func TestRedirectSlash(t *testing.T) {
+ var route *Route
+ var routeMatch RouteMatch
+ r := NewRouter()
+
+ r.StrictSlash(false)
+ route = r.NewRoute()
+ if route.strictSlash != false {
+ t.Errorf("Expected false redirectSlash.")
+ }
+
+ r.StrictSlash(true)
+ route = r.NewRoute()
+ if route.strictSlash != true {
+ t.Errorf("Expected true redirectSlash.")
+ }
+
+ route = new(Route)
+ route.strictSlash = true
+ route.Path("/{arg1}/{arg2:[0-9]+}/")
+ request, _ := http.NewRequest("GET", "http://localhost/foo/123", nil)
+ routeMatch = RouteMatch{}
+ _ = route.Match(request, &routeMatch)
+ vars := routeMatch.Vars
+ if vars["arg1"] != "foo" {
+ t.Errorf("Expected foo.")
+ }
+ if vars["arg2"] != "123" {
+ t.Errorf("Expected 123.")
+ }
+ rsp := NewRecorder()
+ routeMatch.Handler.ServeHTTP(rsp, request)
+ if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123/" {
+ t.Errorf("Expected redirect header.")
+ }
+
+ route = new(Route)
+ route.strictSlash = true
+ route.Path("/{arg1}/{arg2:[0-9]+}")
+ request, _ = http.NewRequest("GET", "http://localhost/foo/123/", nil)
+ routeMatch = RouteMatch{}
+ _ = route.Match(request, &routeMatch)
+ vars = routeMatch.Vars
+ if vars["arg1"] != "foo" {
+ t.Errorf("Expected foo.")
+ }
+ if vars["arg2"] != "123" {
+ t.Errorf("Expected 123.")
+ }
+ rsp = NewRecorder()
+ routeMatch.Handler.ServeHTTP(rsp, request)
+ if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123" {
+ t.Errorf("Expected redirect header.")
+ }
+}
+
+// Test for the new regexp library, still not available in stable Go.
+func TestNewRegexp(t *testing.T) {
+ var p *routeRegexp
+ var matches []string
+
+ tests := map[string]map[string][]string{
+ "/{foo:a{2}}": {
+ "/a": nil,
+ "/aa": {"aa"},
+ "/aaa": nil,
+ "/aaaa": nil,
+ },
+ "/{foo:a{2,}}": {
+ "/a": nil,
+ "/aa": {"aa"},
+ "/aaa": {"aaa"},
+ "/aaaa": {"aaaa"},
+ },
+ "/{foo:a{2,3}}": {
+ "/a": nil,
+ "/aa": {"aa"},
+ "/aaa": {"aaa"},
+ "/aaaa": nil,
+ },
+ "/{foo:[a-z]{3}}/{bar:[a-z]{2}}": {
+ "/a": nil,
+ "/ab": nil,
+ "/abc": nil,
+ "/abcd": nil,
+ "/abc/ab": {"abc", "ab"},
+ "/abc/abc": nil,
+ "/abcd/ab": nil,
+ },
+ `/{foo:\w{3,}}/{bar:\d{2,}}`: {
+ "/a": nil,
+ "/ab": nil,
+ "/abc": nil,
+ "/abc/1": nil,
+ "/abc/12": {"abc", "12"},
+ "/abcd/12": {"abcd", "12"},
+ "/abcd/123": {"abcd", "123"},
+ },
+ }
+
+ for pattern, paths := range tests {
+ p, _ = newRouteRegexp(pattern, false, false, false, false)
+ for path, result := range paths {
+ matches = p.regexp.FindStringSubmatch(path)
+ if result == nil {
+ if matches != nil {
+ t.Errorf("%v should not match %v.", pattern, path)
+ }
+ } else {
+ if len(matches) != len(result)+1 {
+ t.Errorf("Expected %v matches, got %v.", len(result)+1, len(matches))
+ } else {
+ for k, v := range result {
+ if matches[k+1] != v {
+ t.Errorf("Expected %v, got %v.", v, matches[k+1])
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/bench_test.go b/vendor/github.com/gorilla/websocket/bench_test.go
new file mode 100644
index 000000000..f66fc36bc
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/bench_test.go
@@ -0,0 +1,19 @@
+// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "testing"
+)
+
+func BenchmarkMaskBytes(b *testing.B) {
+ var key [4]byte
+ data := make([]byte, 1024)
+ pos := 0
+ for i := 0; i < b.N; i++ {
+ pos = maskBytes(key, pos, data)
+ }
+ b.SetBytes(int64(len(data)))
+}
diff --git a/vendor/github.com/gorilla/websocket/client_server_test.go b/vendor/github.com/gorilla/websocket/client_server_test.go
new file mode 100644
index 000000000..3f7345dde
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/client_server_test.go
@@ -0,0 +1,451 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/base64"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/http/httptest"
+ "net/url"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+)
+
+var cstUpgrader = Upgrader{
+ Subprotocols: []string{"p0", "p1"},
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+ Error: func(w http.ResponseWriter, r *http.Request, status int, reason error) {
+ http.Error(w, reason.Error(), status)
+ },
+}
+
+var cstDialer = Dialer{
+ Subprotocols: []string{"p1", "p2"},
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+}
+
+type cstHandler struct{ *testing.T }
+
+type cstServer struct {
+ *httptest.Server
+ URL string
+}
+
+const (
+ cstPath = "/a/b"
+ cstRawQuery = "x=y"
+ cstRequestURI = cstPath + "?" + cstRawQuery
+)
+
+func newServer(t *testing.T) *cstServer {
+ var s cstServer
+ s.Server = httptest.NewServer(cstHandler{t})
+ s.Server.URL += cstRequestURI
+ s.URL = makeWsProto(s.Server.URL)
+ return &s
+}
+
+func newTLSServer(t *testing.T) *cstServer {
+ var s cstServer
+ s.Server = httptest.NewTLSServer(cstHandler{t})
+ s.Server.URL += cstRequestURI
+ s.URL = makeWsProto(s.Server.URL)
+ return &s
+}
+
+func (t cstHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != cstPath {
+ t.Logf("path=%v, want %v", r.URL.Path, cstPath)
+ http.Error(w, "bad path", 400)
+ return
+ }
+ if r.URL.RawQuery != cstRawQuery {
+ t.Logf("query=%v, want %v", r.URL.RawQuery, cstRawQuery)
+ http.Error(w, "bad path", 400)
+ return
+ }
+ subprotos := Subprotocols(r)
+ if !reflect.DeepEqual(subprotos, cstDialer.Subprotocols) {
+ t.Logf("subprotols=%v, want %v", subprotos, cstDialer.Subprotocols)
+ http.Error(w, "bad protocol", 400)
+ return
+ }
+ ws, err := cstUpgrader.Upgrade(w, r, http.Header{"Set-Cookie": {"sessionID=1234"}})
+ if err != nil {
+ t.Logf("Upgrade: %v", err)
+ return
+ }
+ defer ws.Close()
+
+ if ws.Subprotocol() != "p1" {
+ t.Logf("Subprotocol() = %s, want p1", ws.Subprotocol())
+ ws.Close()
+ return
+ }
+ op, rd, err := ws.NextReader()
+ if err != nil {
+ t.Logf("NextReader: %v", err)
+ return
+ }
+ wr, err := ws.NextWriter(op)
+ if err != nil {
+ t.Logf("NextWriter: %v", err)
+ return
+ }
+ if _, err = io.Copy(wr, rd); err != nil {
+ t.Logf("NextWriter: %v", err)
+ return
+ }
+ if err := wr.Close(); err != nil {
+ t.Logf("Close: %v", err)
+ return
+ }
+}
+
+func makeWsProto(s string) string {
+ return "ws" + strings.TrimPrefix(s, "http")
+}
+
+func sendRecv(t *testing.T, ws *Conn) {
+ const message = "Hello World!"
+ if err := ws.SetWriteDeadline(time.Now().Add(time.Second)); err != nil {
+ t.Fatalf("SetWriteDeadline: %v", err)
+ }
+ if err := ws.WriteMessage(TextMessage, []byte(message)); err != nil {
+ t.Fatalf("WriteMessage: %v", err)
+ }
+ if err := ws.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
+ t.Fatalf("SetReadDeadline: %v", err)
+ }
+ _, p, err := ws.ReadMessage()
+ if err != nil {
+ t.Fatalf("ReadMessage: %v", err)
+ }
+ if string(p) != message {
+ t.Fatalf("message=%s, want %s", p, message)
+ }
+}
+
+func TestProxyDial(t *testing.T) {
+
+ s := newServer(t)
+ defer s.Close()
+
+ surl, _ := url.Parse(s.URL)
+
+ cstDialer.Proxy = http.ProxyURL(surl)
+
+ connect := false
+ origHandler := s.Server.Config.Handler
+
+ // Capture the request Host header.
+ s.Server.Config.Handler = http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "CONNECT" {
+ connect = true
+ w.WriteHeader(200)
+ return
+ }
+
+ if !connect {
+ t.Log("connect not recieved")
+ http.Error(w, "connect not recieved", 405)
+ return
+ }
+ origHandler.ServeHTTP(w, r)
+ })
+
+ ws, _, err := cstDialer.Dial(s.URL, nil)
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer ws.Close()
+ sendRecv(t, ws)
+
+ cstDialer.Proxy = http.ProxyFromEnvironment
+}
+
+func TestProxyAuthorizationDial(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ surl, _ := url.Parse(s.URL)
+ surl.User = url.UserPassword("username", "password")
+ cstDialer.Proxy = http.ProxyURL(surl)
+
+ connect := false
+ origHandler := s.Server.Config.Handler
+
+ // Capture the request Host header.
+ s.Server.Config.Handler = http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ proxyAuth := r.Header.Get("Proxy-Authorization")
+ expectedProxyAuth := "Basic " + base64.StdEncoding.EncodeToString([]byte("username:password"))
+ if r.Method == "CONNECT" && proxyAuth == expectedProxyAuth {
+ connect = true
+ w.WriteHeader(200)
+ return
+ }
+
+ if !connect {
+ t.Log("connect with proxy authorization not recieved")
+ http.Error(w, "connect with proxy authorization not recieved", 405)
+ return
+ }
+ origHandler.ServeHTTP(w, r)
+ })
+
+ ws, _, err := cstDialer.Dial(s.URL, nil)
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer ws.Close()
+ sendRecv(t, ws)
+
+ cstDialer.Proxy = http.ProxyFromEnvironment
+}
+
+func TestDial(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ ws, _, err := cstDialer.Dial(s.URL, nil)
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer ws.Close()
+ sendRecv(t, ws)
+}
+
+func TestDialTLS(t *testing.T) {
+ s := newTLSServer(t)
+ defer s.Close()
+
+ certs := x509.NewCertPool()
+ for _, c := range s.TLS.Certificates {
+ roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])
+ if err != nil {
+ t.Fatalf("error parsing server's root cert: %v", err)
+ }
+ for _, root := range roots {
+ certs.AddCert(root)
+ }
+ }
+
+ u, _ := url.Parse(s.URL)
+ d := cstDialer
+ d.NetDial = func(network, addr string) (net.Conn, error) { return net.Dial(network, u.Host) }
+ d.TLSClientConfig = &tls.Config{RootCAs: certs}
+ ws, _, err := d.Dial("wss://example.com"+cstRequestURI, nil)
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer ws.Close()
+ sendRecv(t, ws)
+}
+
+func xTestDialTLSBadCert(t *testing.T) {
+ // This test is deactivated because of noisy logging from the net/http package.
+ s := newTLSServer(t)
+ defer s.Close()
+
+ ws, _, err := cstDialer.Dial(s.URL, nil)
+ if err == nil {
+ ws.Close()
+ t.Fatalf("Dial: nil")
+ }
+}
+
+func xTestDialTLSNoVerify(t *testing.T) {
+ s := newTLSServer(t)
+ defer s.Close()
+
+ d := cstDialer
+ d.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
+ ws, _, err := d.Dial(s.URL, nil)
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer ws.Close()
+ sendRecv(t, ws)
+}
+
+func TestDialTimeout(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ d := cstDialer
+ d.HandshakeTimeout = -1
+ ws, _, err := d.Dial(s.URL, nil)
+ if err == nil {
+ ws.Close()
+ t.Fatalf("Dial: nil")
+ }
+}
+
+func TestDialBadScheme(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ ws, _, err := cstDialer.Dial(s.Server.URL, nil)
+ if err == nil {
+ ws.Close()
+ t.Fatalf("Dial: nil")
+ }
+}
+
+func TestDialBadOrigin(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {"bad"}})
+ if err == nil {
+ ws.Close()
+ t.Fatalf("Dial: nil")
+ }
+ if resp == nil {
+ t.Fatalf("resp=nil, err=%v", err)
+ }
+ if resp.StatusCode != http.StatusForbidden {
+ t.Fatalf("status=%d, want %d", resp.StatusCode, http.StatusForbidden)
+ }
+}
+
+func TestDialBadHeader(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ for _, k := range []string{"Upgrade",
+ "Connection",
+ "Sec-Websocket-Key",
+ "Sec-Websocket-Version",
+ "Sec-Websocket-Protocol"} {
+ h := http.Header{}
+ h.Set(k, "bad")
+ ws, _, err := cstDialer.Dial(s.URL, http.Header{"Origin": {"bad"}})
+ if err == nil {
+ ws.Close()
+ t.Errorf("Dial with header %s returned nil", k)
+ }
+ }
+}
+
+func TestBadMethod(t *testing.T) {
+ s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ ws, err := cstUpgrader.Upgrade(w, r, nil)
+ if err == nil {
+ t.Errorf("handshake succeeded, expect fail")
+ ws.Close()
+ }
+ }))
+ defer s.Close()
+
+ resp, err := http.PostForm(s.URL, url.Values{})
+ if err != nil {
+ t.Fatalf("PostForm returned error %v", err)
+ }
+ resp.Body.Close()
+ if resp.StatusCode != http.StatusMethodNotAllowed {
+ t.Errorf("Status = %d, want %d", resp.StatusCode, http.StatusMethodNotAllowed)
+ }
+}
+
+func TestHandshake(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {s.URL}})
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer ws.Close()
+
+ var sessionID string
+ for _, c := range resp.Cookies() {
+ if c.Name == "sessionID" {
+ sessionID = c.Value
+ }
+ }
+ if sessionID != "1234" {
+ t.Error("Set-Cookie not received from the server.")
+ }
+
+ if ws.Subprotocol() != "p1" {
+ t.Errorf("ws.Subprotocol() = %s, want p1", ws.Subprotocol())
+ }
+ sendRecv(t, ws)
+}
+
+func TestRespOnBadHandshake(t *testing.T) {
+ const expectedStatus = http.StatusGone
+ const expectedBody = "This is the response body."
+
+ s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(expectedStatus)
+ io.WriteString(w, expectedBody)
+ }))
+ defer s.Close()
+
+ ws, resp, err := cstDialer.Dial(makeWsProto(s.URL), nil)
+ if err == nil {
+ ws.Close()
+ t.Fatalf("Dial: nil")
+ }
+
+ if resp == nil {
+ t.Fatalf("resp=nil, err=%v", err)
+ }
+
+ if resp.StatusCode != expectedStatus {
+ t.Errorf("resp.StatusCode=%d, want %d", resp.StatusCode, expectedStatus)
+ }
+
+ p, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ t.Fatalf("ReadFull(resp.Body) returned error %v", err)
+ }
+
+ if string(p) != expectedBody {
+ t.Errorf("resp.Body=%s, want %s", p, expectedBody)
+ }
+}
+
+// TestHostHeader confirms that the host header provided in the call to Dial is
+// sent to the server.
+func TestHostHeader(t *testing.T) {
+ s := newServer(t)
+ defer s.Close()
+
+ specifiedHost := make(chan string, 1)
+ origHandler := s.Server.Config.Handler
+
+ // Capture the request Host header.
+ s.Server.Config.Handler = http.HandlerFunc(
+ func(w http.ResponseWriter, r *http.Request) {
+ specifiedHost <- r.Host
+ origHandler.ServeHTTP(w, r)
+ })
+
+ ws, _, err := cstDialer.Dial(s.URL, http.Header{"Host": {"testhost"}})
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer ws.Close()
+
+ if gotHost := <-specifiedHost; gotHost != "testhost" {
+ t.Fatalf("gotHost = %q, want \"testhost\"", gotHost)
+ }
+
+ sendRecv(t, ws)
+}
diff --git a/vendor/github.com/gorilla/websocket/client_test.go b/vendor/github.com/gorilla/websocket/client_test.go
new file mode 100644
index 000000000..7d2b0844f
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/client_test.go
@@ -0,0 +1,72 @@
+// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "net/url"
+ "reflect"
+ "testing"
+)
+
+var parseURLTests = []struct {
+ s string
+ u *url.URL
+ rui string
+}{
+ {"ws://example.com/", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}, "/"},
+ {"ws://example.com", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}, "/"},
+ {"ws://example.com:7777/", &url.URL{Scheme: "ws", Host: "example.com:7777", Opaque: "/"}, "/"},
+ {"wss://example.com/", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/"}, "/"},
+ {"wss://example.com/a/b", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b"}, "/a/b"},
+ {"ss://example.com/a/b", nil, ""},
+ {"ws://webmaster@example.com/", nil, ""},
+ {"wss://example.com/a/b?x=y", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b", RawQuery: "x=y"}, "/a/b?x=y"},
+ {"wss://example.com?x=y", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/", RawQuery: "x=y"}, "/?x=y"},
+}
+
+func TestParseURL(t *testing.T) {
+ for _, tt := range parseURLTests {
+ u, err := parseURL(tt.s)
+ if tt.u != nil && err != nil {
+ t.Errorf("parseURL(%q) returned error %v", tt.s, err)
+ continue
+ }
+ if tt.u == nil {
+ if err == nil {
+ t.Errorf("parseURL(%q) did not return error", tt.s)
+ }
+ continue
+ }
+ if !reflect.DeepEqual(u, tt.u) {
+ t.Errorf("parseURL(%q) = %v, want %v", tt.s, u, tt.u)
+ continue
+ }
+ if u.RequestURI() != tt.rui {
+ t.Errorf("parseURL(%q).RequestURI() = %v, want %v", tt.s, u.RequestURI(), tt.rui)
+ }
+ }
+}
+
+var hostPortNoPortTests = []struct {
+ u *url.URL
+ hostPort, hostNoPort string
+}{
+ {&url.URL{Scheme: "ws", Host: "example.com"}, "example.com:80", "example.com"},
+ {&url.URL{Scheme: "wss", Host: "example.com"}, "example.com:443", "example.com"},
+ {&url.URL{Scheme: "ws", Host: "example.com:7777"}, "example.com:7777", "example.com"},
+ {&url.URL{Scheme: "wss", Host: "example.com:7777"}, "example.com:7777", "example.com"},
+}
+
+func TestHostPortNoPort(t *testing.T) {
+ for _, tt := range hostPortNoPortTests {
+ hostPort, hostNoPort := hostPortNoPort(tt.u)
+ if hostPort != tt.hostPort {
+ t.Errorf("hostPortNoPort(%v) returned hostPort %q, want %q", tt.u, hostPort, tt.hostPort)
+ }
+ if hostNoPort != tt.hostNoPort {
+ t.Errorf("hostPortNoPort(%v) returned hostNoPort %q, want %q", tt.u, hostNoPort, tt.hostNoPort)
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/conn_test.go b/vendor/github.com/gorilla/websocket/conn_test.go
new file mode 100644
index 000000000..0243c1154
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/conn_test.go
@@ -0,0 +1,402 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "reflect"
+ "testing"
+ "testing/iotest"
+ "time"
+)
+
+var _ net.Error = errWriteTimeout
+
+type fakeNetConn struct {
+ io.Reader
+ io.Writer
+}
+
+func (c fakeNetConn) Close() error { return nil }
+func (c fakeNetConn) LocalAddr() net.Addr { return nil }
+func (c fakeNetConn) RemoteAddr() net.Addr { return nil }
+func (c fakeNetConn) SetDeadline(t time.Time) error { return nil }
+func (c fakeNetConn) SetReadDeadline(t time.Time) error { return nil }
+func (c fakeNetConn) SetWriteDeadline(t time.Time) error { return nil }
+
+func TestFraming(t *testing.T) {
+ frameSizes := []int{0, 1, 2, 124, 125, 126, 127, 128, 129, 65534, 65535, 65536, 65537}
+ var readChunkers = []struct {
+ name string
+ f func(io.Reader) io.Reader
+ }{
+ {"half", iotest.HalfReader},
+ {"one", iotest.OneByteReader},
+ {"asis", func(r io.Reader) io.Reader { return r }},
+ }
+
+ writeBuf := make([]byte, 65537)
+ for i := range writeBuf {
+ writeBuf[i] = byte(i)
+ }
+
+ for _, isServer := range []bool{true, false} {
+ for _, chunker := range readChunkers {
+
+ var connBuf bytes.Buffer
+ wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024)
+ rc := newConn(fakeNetConn{Reader: chunker.f(&connBuf), Writer: nil}, !isServer, 1024, 1024)
+
+ for _, n := range frameSizes {
+ for _, iocopy := range []bool{true, false} {
+ name := fmt.Sprintf("s:%v, r:%s, n:%d c:%v", isServer, chunker.name, n, iocopy)
+
+ w, err := wc.NextWriter(TextMessage)
+ if err != nil {
+ t.Errorf("%s: wc.NextWriter() returned %v", name, err)
+ continue
+ }
+ var nn int
+ if iocopy {
+ var n64 int64
+ n64, err = io.Copy(w, bytes.NewReader(writeBuf[:n]))
+ nn = int(n64)
+ } else {
+ nn, err = w.Write(writeBuf[:n])
+ }
+ if err != nil || nn != n {
+ t.Errorf("%s: w.Write(writeBuf[:n]) returned %d, %v", name, nn, err)
+ continue
+ }
+ err = w.Close()
+ if err != nil {
+ t.Errorf("%s: w.Close() returned %v", name, err)
+ continue
+ }
+
+ opCode, r, err := rc.NextReader()
+ if err != nil || opCode != TextMessage {
+ t.Errorf("%s: NextReader() returned %d, r, %v", name, opCode, err)
+ continue
+ }
+ rbuf, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("%s: ReadFull() returned rbuf, %v", name, err)
+ continue
+ }
+
+ if len(rbuf) != n {
+ t.Errorf("%s: len(rbuf) is %d, want %d", name, len(rbuf), n)
+ continue
+ }
+
+ for i, b := range rbuf {
+ if byte(i) != b {
+ t.Errorf("%s: bad byte at offset %d", name, i)
+ break
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestControl(t *testing.T) {
+ const message = "this is a ping/pong messsage"
+ for _, isServer := range []bool{true, false} {
+ for _, isWriteControl := range []bool{true, false} {
+ name := fmt.Sprintf("s:%v, wc:%v", isServer, isWriteControl)
+ var connBuf bytes.Buffer
+ wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024)
+ rc := newConn(fakeNetConn{Reader: &connBuf, Writer: nil}, !isServer, 1024, 1024)
+ if isWriteControl {
+ wc.WriteControl(PongMessage, []byte(message), time.Now().Add(time.Second))
+ } else {
+ w, err := wc.NextWriter(PongMessage)
+ if err != nil {
+ t.Errorf("%s: wc.NextWriter() returned %v", name, err)
+ continue
+ }
+ if _, err := w.Write([]byte(message)); err != nil {
+ t.Errorf("%s: w.Write() returned %v", name, err)
+ continue
+ }
+ if err := w.Close(); err != nil {
+ t.Errorf("%s: w.Close() returned %v", name, err)
+ continue
+ }
+ var actualMessage string
+ rc.SetPongHandler(func(s string) error { actualMessage = s; return nil })
+ rc.NextReader()
+ if actualMessage != message {
+ t.Errorf("%s: pong=%q, want %q", name, actualMessage, message)
+ continue
+ }
+ }
+ }
+ }
+}
+
+func TestCloseBeforeFinalFrame(t *testing.T) {
+ const bufSize = 512
+
+ expectedErr := &CloseError{Code: CloseNormalClosure, Text: "hello"}
+
+ var b1, b2 bytes.Buffer
+ wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, bufSize)
+ rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024)
+
+ w, _ := wc.NextWriter(BinaryMessage)
+ w.Write(make([]byte, bufSize+bufSize/2))
+ wc.WriteControl(CloseMessage, FormatCloseMessage(expectedErr.Code, expectedErr.Text), time.Now().Add(10*time.Second))
+ w.Close()
+
+ op, r, err := rc.NextReader()
+ if op != BinaryMessage || err != nil {
+ t.Fatalf("NextReader() returned %d, %v", op, err)
+ }
+ _, err = io.Copy(ioutil.Discard, r)
+ if !reflect.DeepEqual(err, expectedErr) {
+ t.Fatalf("io.Copy() returned %v, want %v", err, expectedErr)
+ }
+ _, _, err = rc.NextReader()
+ if !reflect.DeepEqual(err, expectedErr) {
+ t.Fatalf("NextReader() returned %v, want %v", err, expectedErr)
+ }
+}
+
+func TestEOFWithinFrame(t *testing.T) {
+ const bufSize = 64
+
+ for n := 0; ; n++ {
+ var b bytes.Buffer
+ wc := newConn(fakeNetConn{Reader: nil, Writer: &b}, false, 1024, 1024)
+ rc := newConn(fakeNetConn{Reader: &b, Writer: nil}, true, 1024, 1024)
+
+ w, _ := wc.NextWriter(BinaryMessage)
+ w.Write(make([]byte, bufSize))
+ w.Close()
+
+ if n >= b.Len() {
+ break
+ }
+ b.Truncate(n)
+
+ op, r, err := rc.NextReader()
+ if err == errUnexpectedEOF {
+ continue
+ }
+ if op != BinaryMessage || err != nil {
+ t.Fatalf("%d: NextReader() returned %d, %v", n, op, err)
+ }
+ _, err = io.Copy(ioutil.Discard, r)
+ if err != errUnexpectedEOF {
+ t.Fatalf("%d: io.Copy() returned %v, want %v", n, err, errUnexpectedEOF)
+ }
+ _, _, err = rc.NextReader()
+ if err != errUnexpectedEOF {
+ t.Fatalf("%d: NextReader() returned %v, want %v", n, err, errUnexpectedEOF)
+ }
+ }
+}
+
+func TestEOFBeforeFinalFrame(t *testing.T) {
+ const bufSize = 512
+
+ var b1, b2 bytes.Buffer
+ wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, bufSize)
+ rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024)
+
+ w, _ := wc.NextWriter(BinaryMessage)
+ w.Write(make([]byte, bufSize+bufSize/2))
+
+ op, r, err := rc.NextReader()
+ if op != BinaryMessage || err != nil {
+ t.Fatalf("NextReader() returned %d, %v", op, err)
+ }
+ _, err = io.Copy(ioutil.Discard, r)
+ if err != errUnexpectedEOF {
+ t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF)
+ }
+ _, _, err = rc.NextReader()
+ if err != errUnexpectedEOF {
+ t.Fatalf("NextReader() returned %v, want %v", err, errUnexpectedEOF)
+ }
+}
+
+func TestReadLimit(t *testing.T) {
+
+ const readLimit = 512
+ message := make([]byte, readLimit+1)
+
+ var b1, b2 bytes.Buffer
+ wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, readLimit-2)
+ rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024)
+ rc.SetReadLimit(readLimit)
+
+ // Send message at the limit with interleaved pong.
+ w, _ := wc.NextWriter(BinaryMessage)
+ w.Write(message[:readLimit-1])
+ wc.WriteControl(PongMessage, []byte("this is a pong"), time.Now().Add(10*time.Second))
+ w.Write(message[:1])
+ w.Close()
+
+ // Send message larger than the limit.
+ wc.WriteMessage(BinaryMessage, message[:readLimit+1])
+
+ op, _, err := rc.NextReader()
+ if op != BinaryMessage || err != nil {
+ t.Fatalf("1: NextReader() returned %d, %v", op, err)
+ }
+ op, r, err := rc.NextReader()
+ if op != BinaryMessage || err != nil {
+ t.Fatalf("2: NextReader() returned %d, %v", op, err)
+ }
+ _, err = io.Copy(ioutil.Discard, r)
+ if err != ErrReadLimit {
+ t.Fatalf("io.Copy() returned %v", err)
+ }
+}
+
+func TestUnderlyingConn(t *testing.T) {
+ var b1, b2 bytes.Buffer
+ fc := fakeNetConn{Reader: &b1, Writer: &b2}
+ c := newConn(fc, true, 1024, 1024)
+ ul := c.UnderlyingConn()
+ if ul != fc {
+ t.Fatalf("Underlying conn is not what it should be.")
+ }
+}
+
+func TestBufioReadBytes(t *testing.T) {
+
+ // Test calling bufio.ReadBytes for value longer than read buffer size.
+
+ m := make([]byte, 512)
+ m[len(m)-1] = '\n'
+
+ var b1, b2 bytes.Buffer
+ wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, len(m)+64, len(m)+64)
+ rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, len(m)-64, len(m)-64)
+
+ w, _ := wc.NextWriter(BinaryMessage)
+ w.Write(m)
+ w.Close()
+
+ op, r, err := rc.NextReader()
+ if op != BinaryMessage || err != nil {
+ t.Fatalf("NextReader() returned %d, %v", op, err)
+ }
+
+ br := bufio.NewReader(r)
+ p, err := br.ReadBytes('\n')
+ if err != nil {
+ t.Fatalf("ReadBytes() returned %v", err)
+ }
+ if len(p) != len(m) {
+ t.Fatalf("read returnd %d bytes, want %d bytes", len(p), len(m))
+ }
+}
+
+var closeErrorTests = []struct {
+ err error
+ codes []int
+ ok bool
+}{
+ {&CloseError{Code: CloseNormalClosure}, []int{CloseNormalClosure}, true},
+ {&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived}, false},
+ {&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived, CloseNormalClosure}, true},
+ {errors.New("hello"), []int{CloseNormalClosure}, false},
+}
+
+func TestCloseError(t *testing.T) {
+ for _, tt := range closeErrorTests {
+ ok := IsCloseError(tt.err, tt.codes...)
+ if ok != tt.ok {
+ t.Errorf("IsCloseError(%#v, %#v) returned %v, want %v", tt.err, tt.codes, ok, tt.ok)
+ }
+ }
+}
+
+var unexpectedCloseErrorTests = []struct {
+ err error
+ codes []int
+ ok bool
+}{
+ {&CloseError{Code: CloseNormalClosure}, []int{CloseNormalClosure}, false},
+ {&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived}, true},
+ {&CloseError{Code: CloseNormalClosure}, []int{CloseNoStatusReceived, CloseNormalClosure}, false},
+ {errors.New("hello"), []int{CloseNormalClosure}, false},
+}
+
+func TestUnexpectedCloseErrors(t *testing.T) {
+ for _, tt := range unexpectedCloseErrorTests {
+ ok := IsUnexpectedCloseError(tt.err, tt.codes...)
+ if ok != tt.ok {
+ t.Errorf("IsUnexpectedCloseError(%#v, %#v) returned %v, want %v", tt.err, tt.codes, ok, tt.ok)
+ }
+ }
+}
+
+type blockingWriter struct {
+ c1, c2 chan struct{}
+}
+
+func (w blockingWriter) Write(p []byte) (int, error) {
+ // Allow main to continue
+ close(w.c1)
+ // Wait for panic in main
+ <-w.c2
+ return len(p), nil
+}
+
+func TestConcurrentWritePanic(t *testing.T) {
+ w := blockingWriter{make(chan struct{}), make(chan struct{})}
+ c := newConn(fakeNetConn{Reader: nil, Writer: w}, false, 1024, 1024)
+ go func() {
+ c.WriteMessage(TextMessage, []byte{})
+ }()
+
+ // wait for goroutine to block in write.
+ <-w.c1
+
+ defer func() {
+ close(w.c2)
+ if v := recover(); v != nil {
+ return
+ }
+ }()
+
+ c.WriteMessage(TextMessage, []byte{})
+ t.Fatal("should not get here")
+}
+
+type failingReader struct{}
+
+func (r failingReader) Read(p []byte) (int, error) {
+ return 0, io.EOF
+}
+
+func TestFailedConnectionReadPanic(t *testing.T) {
+ c := newConn(fakeNetConn{Reader: failingReader{}, Writer: nil}, false, 1024, 1024)
+
+ defer func() {
+ if v := recover(); v != nil {
+ return
+ }
+ }()
+
+ for i := 0; i < 20000; i++ {
+ c.ReadMessage()
+ }
+ t.Fatal("should not get here")
+}
diff --git a/vendor/github.com/gorilla/websocket/example_test.go b/vendor/github.com/gorilla/websocket/example_test.go
new file mode 100644
index 000000000..96449eac7
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/example_test.go
@@ -0,0 +1,46 @@
+// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket_test
+
+import (
+ "log"
+ "net/http"
+ "testing"
+
+ "github.com/gorilla/websocket"
+)
+
+var (
+ c *websocket.Conn
+ req *http.Request
+)
+
+// The websocket.IsUnexpectedCloseError function is useful for identifying
+// application and protocol errors.
+//
+// This server application works with a client application running in the
+// browser. The client application does not explicitly close the websocket. The
+// only expected close message from the client has the code
+// websocket.CloseGoingAway. All other other close messages are likely the
+// result of an application or protocol error and are logged to aid debugging.
+func ExampleIsUnexpectedCloseError() {
+
+ for {
+ messageType, p, err := c.ReadMessage()
+ if err != nil {
+ if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
+ log.Printf("error: %v, user-agent: %v", err, req.Header.Get("User-Agent"))
+ }
+ return
+ }
+ processMesage(messageType, p)
+ }
+}
+
+func processMesage(mt int, p []byte) {}
+
+// TestX prevents godoc from showing this entire file in the example. Remove
+// this function when a second example is added.
+func TestX(t *testing.T) {}
diff --git a/vendor/github.com/gorilla/websocket/examples/autobahn/README.md b/vendor/github.com/gorilla/websocket/examples/autobahn/README.md
new file mode 100644
index 000000000..075ac1530
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/autobahn/README.md
@@ -0,0 +1,13 @@
+# Test Server
+
+This package contains a server for the [Autobahn WebSockets Test Suite](http://autobahn.ws/testsuite).
+
+To test the server, run
+
+ go run server.go
+
+and start the client test driver
+
+ wstest -m fuzzingclient -s fuzzingclient.json
+
+When the client completes, it writes a report to reports/clients/index.html.
diff --git a/vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json b/vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json
new file mode 100644
index 000000000..27d5a5b14
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json
@@ -0,0 +1,14 @@
+
+{
+ "options": {"failByDrop": false},
+ "outdir": "./reports/clients",
+ "servers": [
+ {"agent": "ReadAllWriteMessage", "url": "ws://localhost:9000/m", "options": {"version": 18}},
+ {"agent": "ReadAllWrite", "url": "ws://localhost:9000/r", "options": {"version": 18}},
+ {"agent": "CopyFull", "url": "ws://localhost:9000/f", "options": {"version": 18}},
+ {"agent": "CopyWriterOnly", "url": "ws://localhost:9000/c", "options": {"version": 18}}
+ ],
+ "cases": ["*"],
+ "exclude-cases": [],
+ "exclude-agent-cases": {}
+}
diff --git a/vendor/github.com/gorilla/websocket/examples/autobahn/server.go b/vendor/github.com/gorilla/websocket/examples/autobahn/server.go
new file mode 100644
index 000000000..d96ac84db
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/autobahn/server.go
@@ -0,0 +1,246 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Command server is a test server for the Autobahn WebSockets Test Suite.
+package main
+
+import (
+ "errors"
+ "flag"
+ "github.com/gorilla/websocket"
+ "io"
+ "log"
+ "net/http"
+ "time"
+ "unicode/utf8"
+)
+
+var upgrader = websocket.Upgrader{
+ ReadBufferSize: 4096,
+ WriteBufferSize: 4096,
+ CheckOrigin: func(r *http.Request) bool {
+ return true
+ },
+}
+
+// echoCopy echoes messages from the client using io.Copy.
+func echoCopy(w http.ResponseWriter, r *http.Request, writerOnly bool) {
+ conn, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.Println("Upgrade:", err)
+ return
+ }
+ defer conn.Close()
+ for {
+ mt, r, err := conn.NextReader()
+ if err != nil {
+ if err != io.EOF {
+ log.Println("NextReader:", err)
+ }
+ return
+ }
+ if mt == websocket.TextMessage {
+ r = &validator{r: r}
+ }
+ w, err := conn.NextWriter(mt)
+ if err != nil {
+ log.Println("NextWriter:", err)
+ return
+ }
+ if mt == websocket.TextMessage {
+ r = &validator{r: r}
+ }
+ if writerOnly {
+ _, err = io.Copy(struct{ io.Writer }{w}, r)
+ } else {
+ _, err = io.Copy(w, r)
+ }
+ if err != nil {
+ if err == errInvalidUTF8 {
+ conn.WriteControl(websocket.CloseMessage,
+ websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
+ time.Time{})
+ }
+ log.Println("Copy:", err)
+ return
+ }
+ err = w.Close()
+ if err != nil {
+ log.Println("Close:", err)
+ return
+ }
+ }
+}
+
+func echoCopyWriterOnly(w http.ResponseWriter, r *http.Request) {
+ echoCopy(w, r, true)
+}
+
+func echoCopyFull(w http.ResponseWriter, r *http.Request) {
+ echoCopy(w, r, false)
+}
+
+// echoReadAll echoes messages from the client by reading the entire message
+// with ioutil.ReadAll.
+func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage bool) {
+ conn, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.Println("Upgrade:", err)
+ return
+ }
+ defer conn.Close()
+ for {
+ mt, b, err := conn.ReadMessage()
+ if err != nil {
+ if err != io.EOF {
+ log.Println("NextReader:", err)
+ }
+ return
+ }
+ if mt == websocket.TextMessage {
+ if !utf8.Valid(b) {
+ conn.WriteControl(websocket.CloseMessage,
+ websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""),
+ time.Time{})
+ log.Println("ReadAll: invalid utf8")
+ }
+ }
+ if writeMessage {
+ err = conn.WriteMessage(mt, b)
+ if err != nil {
+ log.Println("WriteMessage:", err)
+ }
+ } else {
+ w, err := conn.NextWriter(mt)
+ if err != nil {
+ log.Println("NextWriter:", err)
+ return
+ }
+ if _, err := w.Write(b); err != nil {
+ log.Println("Writer:", err)
+ return
+ }
+ if err := w.Close(); err != nil {
+ log.Println("Close:", err)
+ return
+ }
+ }
+ }
+}
+
+func echoReadAllWriter(w http.ResponseWriter, r *http.Request) {
+ echoReadAll(w, r, false)
+}
+
+func echoReadAllWriteMessage(w http.ResponseWriter, r *http.Request) {
+ echoReadAll(w, r, true)
+}
+
+func serveHome(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/" {
+ http.Error(w, "Not found.", 404)
+ return
+ }
+ if r.Method != "GET" {
+ http.Error(w, "Method not allowed", 405)
+ return
+ }
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ io.WriteString(w, "<html><body>Echo Server</body></html>")
+}
+
+var addr = flag.String("addr", ":9000", "http service address")
+
+func main() {
+ flag.Parse()
+ http.HandleFunc("/", serveHome)
+ http.HandleFunc("/c", echoCopyWriterOnly)
+ http.HandleFunc("/f", echoCopyFull)
+ http.HandleFunc("/r", echoReadAllWriter)
+ http.HandleFunc("/m", echoReadAllWriteMessage)
+ err := http.ListenAndServe(*addr, nil)
+ if err != nil {
+ log.Fatal("ListenAndServe: ", err)
+ }
+}
+
+type validator struct {
+ state int
+ x rune
+ r io.Reader
+}
+
+var errInvalidUTF8 = errors.New("invalid utf8")
+
+func (r *validator) Read(p []byte) (int, error) {
+ n, err := r.r.Read(p)
+ state := r.state
+ x := r.x
+ for _, b := range p[:n] {
+ state, x = decode(state, x, b)
+ if state == utf8Reject {
+ break
+ }
+ }
+ r.state = state
+ r.x = x
+ if state == utf8Reject || (err == io.EOF && state != utf8Accept) {
+ return n, errInvalidUTF8
+ }
+ return n, err
+}
+
+// UTF-8 decoder from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+//
+// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+var utf8d = [...]byte{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf
+ 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df
+ 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef
+ 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff
+ 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
+ 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
+ 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
+ 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8
+}
+
+const (
+ utf8Accept = 0
+ utf8Reject = 1
+)
+
+func decode(state int, x rune, b byte) (int, rune) {
+ t := utf8d[b]
+ if state != utf8Accept {
+ x = rune(b&0x3f) | (x << 6)
+ } else {
+ x = rune((0xff >> t) & b)
+ }
+ state = int(utf8d[256+state*16+int(t)])
+ return state, x
+}
diff --git a/vendor/github.com/gorilla/websocket/examples/chat/README.md b/vendor/github.com/gorilla/websocket/examples/chat/README.md
new file mode 100644
index 000000000..5df3cf1a3
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/chat/README.md
@@ -0,0 +1,20 @@
+# Chat Example
+
+This application shows how to use use the
+[websocket](https://github.com/gorilla/websocket) package and
+[jQuery](http://jquery.com) to implement a simple web chat application.
+
+## Running the example
+
+The example requires a working Go development environment. The [Getting
+Started](http://golang.org/doc/install) page describes how to install the
+development environment.
+
+Once you have Go up and running, you can download, build and run the example
+using the following commands.
+
+ $ go get github.com/gorilla/websocket
+ $ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/chat`
+ $ go run *.go
+
+To use the chat example, open http://localhost:8080/ in your browser.
diff --git a/vendor/github.com/gorilla/websocket/examples/chat/conn.go b/vendor/github.com/gorilla/websocket/examples/chat/conn.go
new file mode 100644
index 000000000..40fd38c2c
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/chat/conn.go
@@ -0,0 +1,105 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "github.com/gorilla/websocket"
+ "log"
+ "net/http"
+ "time"
+)
+
+const (
+ // Time allowed to write a message to the peer.
+ writeWait = 10 * time.Second
+
+ // Time allowed to read the next pong message from the peer.
+ pongWait = 60 * time.Second
+
+ // Send pings to peer with this period. Must be less than pongWait.
+ pingPeriod = (pongWait * 9) / 10
+
+ // Maximum message size allowed from peer.
+ maxMessageSize = 512
+)
+
+var upgrader = websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+}
+
+// connection is an middleman between the websocket connection and the hub.
+type connection struct {
+ // The websocket connection.
+ ws *websocket.Conn
+
+ // Buffered channel of outbound messages.
+ send chan []byte
+}
+
+// readPump pumps messages from the websocket connection to the hub.
+func (c *connection) readPump() {
+ defer func() {
+ h.unregister <- c
+ c.ws.Close()
+ }()
+ c.ws.SetReadLimit(maxMessageSize)
+ c.ws.SetReadDeadline(time.Now().Add(pongWait))
+ c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
+ for {
+ _, message, err := c.ws.ReadMessage()
+ if err != nil {
+ if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
+ log.Printf("error: %v", err)
+ }
+ break
+ }
+ h.broadcast <- message
+ }
+}
+
+// write writes a message with the given message type and payload.
+func (c *connection) write(mt int, payload []byte) error {
+ c.ws.SetWriteDeadline(time.Now().Add(writeWait))
+ return c.ws.WriteMessage(mt, payload)
+}
+
+// writePump pumps messages from the hub to the websocket connection.
+func (c *connection) writePump() {
+ ticker := time.NewTicker(pingPeriod)
+ defer func() {
+ ticker.Stop()
+ c.ws.Close()
+ }()
+ for {
+ select {
+ case message, ok := <-c.send:
+ if !ok {
+ c.write(websocket.CloseMessage, []byte{})
+ return
+ }
+ if err := c.write(websocket.TextMessage, message); err != nil {
+ return
+ }
+ case <-ticker.C:
+ if err := c.write(websocket.PingMessage, []byte{}); err != nil {
+ return
+ }
+ }
+ }
+}
+
+// serveWs handles websocket requests from the peer.
+func serveWs(w http.ResponseWriter, r *http.Request) {
+ ws, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ c := &connection{send: make(chan []byte, 256), ws: ws}
+ h.register <- c
+ go c.writePump()
+ c.readPump()
+}
diff --git a/vendor/github.com/gorilla/websocket/examples/chat/home.html b/vendor/github.com/gorilla/websocket/examples/chat/home.html
new file mode 100644
index 000000000..29599225c
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/chat/home.html
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Chat Example</title>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
+<script type="text/javascript">
+ $(function() {
+
+ var conn;
+ var msg = $("#msg");
+ var log = $("#log");
+
+ function appendLog(msg) {
+ var d = log[0]
+ var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
+ msg.appendTo(log)
+ if (doScroll) {
+ d.scrollTop = d.scrollHeight - d.clientHeight;
+ }
+ }
+
+ $("#form").submit(function() {
+ if (!conn) {
+ return false;
+ }
+ if (!msg.val()) {
+ return false;
+ }
+ conn.send(msg.val());
+ msg.val("");
+ return false
+ });
+
+ if (window["WebSocket"]) {
+ conn = new WebSocket("ws://{{$}}/ws");
+ conn.onclose = function(evt) {
+ appendLog($("<div><b>Connection closed.</b></div>"))
+ }
+ conn.onmessage = function(evt) {
+ appendLog($("<div/>").text(evt.data))
+ }
+ } else {
+ appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
+ }
+ });
+</script>
+<style type="text/css">
+html {
+ overflow: hidden;
+}
+
+body {
+ overflow: hidden;
+ padding: 0;
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ background: gray;
+}
+
+#log {
+ background: white;
+ margin: 0;
+ padding: 0.5em 0.5em 0.5em 0.5em;
+ position: absolute;
+ top: 0.5em;
+ left: 0.5em;
+ right: 0.5em;
+ bottom: 3em;
+ overflow: auto;
+}
+
+#form {
+ padding: 0 0.5em 0 0.5em;
+ margin: 0;
+ position: absolute;
+ bottom: 1em;
+ left: 0px;
+ width: 100%;
+ overflow: hidden;
+}
+
+</style>
+</head>
+<body>
+<div id="log"></div>
+<form id="form">
+ <input type="submit" value="Send" />
+ <input type="text" id="msg" size="64"/>
+</form>
+</body>
+</html>
diff --git a/vendor/github.com/gorilla/websocket/examples/chat/hub.go b/vendor/github.com/gorilla/websocket/examples/chat/hub.go
new file mode 100644
index 000000000..449ba753d
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/chat/hub.go
@@ -0,0 +1,51 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// hub maintains the set of active connections and broadcasts messages to the
+// connections.
+type hub struct {
+ // Registered connections.
+ connections map[*connection]bool
+
+ // Inbound messages from the connections.
+ broadcast chan []byte
+
+ // Register requests from the connections.
+ register chan *connection
+
+ // Unregister requests from connections.
+ unregister chan *connection
+}
+
+var h = hub{
+ broadcast: make(chan []byte),
+ register: make(chan *connection),
+ unregister: make(chan *connection),
+ connections: make(map[*connection]bool),
+}
+
+func (h *hub) run() {
+ for {
+ select {
+ case c := <-h.register:
+ h.connections[c] = true
+ case c := <-h.unregister:
+ if _, ok := h.connections[c]; ok {
+ delete(h.connections, c)
+ close(c.send)
+ }
+ case m := <-h.broadcast:
+ for c := range h.connections {
+ select {
+ case c.send <- m:
+ default:
+ close(c.send)
+ delete(h.connections, c)
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/examples/chat/main.go b/vendor/github.com/gorilla/websocket/examples/chat/main.go
new file mode 100644
index 000000000..3c4448d72
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/chat/main.go
@@ -0,0 +1,39 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "flag"
+ "log"
+ "net/http"
+ "text/template"
+)
+
+var addr = flag.String("addr", ":8080", "http service address")
+var homeTempl = template.Must(template.ParseFiles("home.html"))
+
+func serveHome(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/" {
+ http.Error(w, "Not found", 404)
+ return
+ }
+ if r.Method != "GET" {
+ http.Error(w, "Method not allowed", 405)
+ return
+ }
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ homeTempl.Execute(w, r.Host)
+}
+
+func main() {
+ flag.Parse()
+ go h.run()
+ http.HandleFunc("/", serveHome)
+ http.HandleFunc("/ws", serveWs)
+ err := http.ListenAndServe(*addr, nil)
+ if err != nil {
+ log.Fatal("ListenAndServe: ", err)
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/examples/command/README.md b/vendor/github.com/gorilla/websocket/examples/command/README.md
new file mode 100644
index 000000000..c30d3979a
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/command/README.md
@@ -0,0 +1,19 @@
+# Command example
+
+This example connects a websocket connection to stdin and stdout of a command.
+Received messages are written to stdin followed by a `\n`. Each line read from
+from standard out is sent as a message to the client.
+
+ $ go get github.com/gorilla/websocket
+ $ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/command`
+ $ go run main.go <command and arguments to run>
+ # Open http://localhost:8080/ .
+
+Try the following commands.
+
+ # Echo sent messages to the output area.
+ $ go run main.go cat
+
+ # Run a shell.Try sending "ls" and "cat main.go".
+ $ go run main.go sh
+
diff --git a/vendor/github.com/gorilla/websocket/examples/command/home.html b/vendor/github.com/gorilla/websocket/examples/command/home.html
new file mode 100644
index 000000000..72fd02b2a
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/command/home.html
@@ -0,0 +1,96 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>Command Example</title>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
+<script type="text/javascript">
+ $(function() {
+
+ var conn;
+ var msg = $("#msg");
+ var log = $("#log");
+
+ function appendLog(msg) {
+ var d = log[0]
+ var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
+ msg.appendTo(log)
+ if (doScroll) {
+ d.scrollTop = d.scrollHeight - d.clientHeight;
+ }
+ }
+
+ $("#form").submit(function() {
+ if (!conn) {
+ return false;
+ }
+ if (!msg.val()) {
+ return false;
+ }
+ conn.send(msg.val());
+ msg.val("");
+ return false
+ });
+
+ if (window["WebSocket"]) {
+ conn = new WebSocket("ws://{{$}}/ws");
+ conn.onclose = function(evt) {
+ appendLog($("<div><b>Connection closed.</b></div>"))
+ }
+ conn.onmessage = function(evt) {
+ appendLog($("<pre/>").text(evt.data))
+ }
+ } else {
+ appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
+ }
+ });
+</script>
+<style type="text/css">
+html {
+ overflow: hidden;
+}
+
+body {
+ overflow: hidden;
+ padding: 0;
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ background: gray;
+}
+
+#log {
+ background: white;
+ margin: 0;
+ padding: 0.5em 0.5em 0.5em 0.5em;
+ position: absolute;
+ top: 0.5em;
+ left: 0.5em;
+ right: 0.5em;
+ bottom: 3em;
+ overflow: auto;
+}
+
+#log pre {
+ margin: 0;
+}
+
+#form {
+ padding: 0 0.5em 0 0.5em;
+ margin: 0;
+ position: absolute;
+ bottom: 1em;
+ left: 0px;
+ width: 100%;
+ overflow: hidden;
+}
+
+</style>
+</head>
+<body>
+<div id="log"></div>
+<form id="form">
+ <input type="submit" value="Send" />
+ <input type="text" id="msg" size="64"/>
+</form>
+</body>
+</html>
diff --git a/vendor/github.com/gorilla/websocket/examples/command/main.go b/vendor/github.com/gorilla/websocket/examples/command/main.go
new file mode 100644
index 000000000..f3f022edb
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/command/main.go
@@ -0,0 +1,188 @@
+// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "os/exec"
+ "text/template"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+var (
+ addr = flag.String("addr", "127.0.0.1:8080", "http service address")
+ cmdPath string
+ homeTempl = template.Must(template.ParseFiles("home.html"))
+)
+
+const (
+ // Time allowed to write a message to the peer.
+ writeWait = 10 * time.Second
+
+ // Maximum message size allowed from peer.
+ maxMessageSize = 8192
+
+ // Time allowed to read the next pong message from the peer.
+ pongWait = 60 * time.Second
+
+ // Send pings to peer with this period. Must be less than pongWait.
+ pingPeriod = (pongWait * 9) / 10
+)
+
+func pumpStdin(ws *websocket.Conn, w io.Writer) {
+ defer ws.Close()
+ ws.SetReadLimit(maxMessageSize)
+ ws.SetReadDeadline(time.Now().Add(pongWait))
+ ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
+ for {
+ _, message, err := ws.ReadMessage()
+ if err != nil {
+ break
+ }
+ message = append(message, '\n')
+ if _, err := w.Write(message); err != nil {
+ break
+ }
+ }
+}
+
+func pumpStdout(ws *websocket.Conn, r io.Reader, done chan struct{}) {
+ defer func() {
+ ws.Close()
+ close(done)
+ }()
+ s := bufio.NewScanner(r)
+ for s.Scan() {
+ ws.SetWriteDeadline(time.Now().Add(writeWait))
+ if err := ws.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
+ break
+ }
+ }
+ if s.Err() != nil {
+ log.Println("scan:", s.Err())
+ }
+}
+
+func ping(ws *websocket.Conn, done chan struct{}) {
+ ticker := time.NewTicker(pingPeriod)
+ defer ticker.Stop()
+ for {
+ select {
+ case <-ticker.C:
+ if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
+ log.Println("ping:", err)
+ }
+ case <-done:
+ return
+ }
+ }
+}
+
+func internalError(ws *websocket.Conn, msg string, err error) {
+ log.Println(msg, err)
+ ws.WriteMessage(websocket.TextMessage, []byte("Internal server error."))
+}
+
+var upgrader = websocket.Upgrader{}
+
+func serveWs(w http.ResponseWriter, r *http.Request) {
+ ws, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.Println("upgrade:", err)
+ return
+ }
+
+ defer ws.Close()
+
+ outr, outw, err := os.Pipe()
+ if err != nil {
+ internalError(ws, "stdout:", err)
+ return
+ }
+ defer outr.Close()
+ defer outw.Close()
+
+ inr, inw, err := os.Pipe()
+ if err != nil {
+ internalError(ws, "stdin:", err)
+ return
+ }
+ defer inr.Close()
+ defer inw.Close()
+
+ proc, err := os.StartProcess(cmdPath, flag.Args(), &os.ProcAttr{
+ Files: []*os.File{inr, outw, outw},
+ })
+ if err != nil {
+ internalError(ws, "start:", err)
+ return
+ }
+
+ inr.Close()
+ outw.Close()
+
+ stdoutDone := make(chan struct{})
+ go pumpStdout(ws, outr, stdoutDone)
+ go ping(ws, stdoutDone)
+
+ pumpStdin(ws, inw)
+
+ // Some commands will exit when stdin is closed.
+ inw.Close()
+
+ // Other commands need a bonk on the head.
+ if err := proc.Signal(os.Interrupt); err != nil {
+ log.Println("inter:", err)
+ }
+
+ select {
+ case <-stdoutDone:
+ case <-time.After(time.Second):
+ // A bigger bonk on the head.
+ if err := proc.Signal(os.Kill); err != nil {
+ log.Println("term:", err)
+ }
+ <-stdoutDone
+ }
+
+ if _, err := proc.Wait(); err != nil {
+ log.Println("wait:", err)
+ }
+}
+
+func serveHome(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/" {
+ http.Error(w, "Not found", 404)
+ return
+ }
+ if r.Method != "GET" {
+ http.Error(w, "Method not allowed", 405)
+ return
+ }
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ homeTempl.Execute(w, r.Host)
+}
+
+func main() {
+ flag.Parse()
+ if len(flag.Args()) < 1 {
+ log.Fatal("must specify at least one argument")
+ }
+ var err error
+ cmdPath, err = exec.LookPath(flag.Args()[0])
+ if err != nil {
+ log.Fatal(err)
+ }
+ http.HandleFunc("/", serveHome)
+ http.HandleFunc("/ws", serveWs)
+ log.Fatal(http.ListenAndServe(*addr, nil))
+}
diff --git a/vendor/github.com/gorilla/websocket/examples/echo/README.md b/vendor/github.com/gorilla/websocket/examples/echo/README.md
new file mode 100644
index 000000000..6ad79ed76
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/echo/README.md
@@ -0,0 +1,17 @@
+# Client and server example
+
+This example shows a simple client and server.
+
+The server echoes messages sent to it. The client sends a message every second
+and prints all messages received.
+
+To run the example, start the server:
+
+ $ go run server.go
+
+Next, start the client:
+
+ $ go run client.go
+
+The server includes a simple web client. To use the client, open
+http://127.0.0.1:8080 in the browser and follow the instructions on the page.
diff --git a/vendor/github.com/gorilla/websocket/examples/echo/client.go b/vendor/github.com/gorilla/websocket/examples/echo/client.go
new file mode 100644
index 000000000..6578094e7
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/echo/client.go
@@ -0,0 +1,81 @@
+// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import (
+ "flag"
+ "log"
+ "net/url"
+ "os"
+ "os/signal"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+var addr = flag.String("addr", "localhost:8080", "http service address")
+
+func main() {
+ flag.Parse()
+ log.SetFlags(0)
+
+ interrupt := make(chan os.Signal, 1)
+ signal.Notify(interrupt, os.Interrupt)
+
+ u := url.URL{Scheme: "ws", Host: *addr, Path: "/echo"}
+ log.Printf("connecting to %s", u.String())
+
+ c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
+ if err != nil {
+ log.Fatal("dial:", err)
+ }
+ defer c.Close()
+
+ done := make(chan struct{})
+
+ go func() {
+ defer c.Close()
+ defer close(done)
+ for {
+ _, message, err := c.ReadMessage()
+ if err != nil {
+ log.Println("read:", err)
+ return
+ }
+ log.Printf("recv: %s", message)
+ }
+ }()
+
+ ticker := time.NewTicker(time.Second)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case t := <-ticker.C:
+ err := c.WriteMessage(websocket.TextMessage, []byte(t.String()))
+ if err != nil {
+ log.Println("write:", err)
+ return
+ }
+ case <-interrupt:
+ log.Println("interrupt")
+ // To cleanly close a connection, a client should send a close
+ // frame and wait for the server to close the connection.
+ err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
+ if err != nil {
+ log.Println("write close:", err)
+ return
+ }
+ select {
+ case <-done:
+ case <-time.After(time.Second):
+ }
+ c.Close()
+ return
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/examples/echo/server.go b/vendor/github.com/gorilla/websocket/examples/echo/server.go
new file mode 100644
index 000000000..a685b0974
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/echo/server.go
@@ -0,0 +1,132 @@
+// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import (
+ "flag"
+ "html/template"
+ "log"
+ "net/http"
+
+ "github.com/gorilla/websocket"
+)
+
+var addr = flag.String("addr", "localhost:8080", "http service address")
+
+var upgrader = websocket.Upgrader{} // use default options
+
+func echo(w http.ResponseWriter, r *http.Request) {
+ c, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ log.Print("upgrade:", err)
+ return
+ }
+ defer c.Close()
+ for {
+ mt, message, err := c.ReadMessage()
+ if err != nil {
+ log.Println("read:", err)
+ break
+ }
+ log.Printf("recv: %s", message)
+ err = c.WriteMessage(mt, message)
+ if err != nil {
+ log.Println("write:", err)
+ break
+ }
+ }
+}
+
+func home(w http.ResponseWriter, r *http.Request) {
+ homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
+}
+
+func main() {
+ flag.Parse()
+ log.SetFlags(0)
+ http.HandleFunc("/echo", echo)
+ http.HandleFunc("/", home)
+ log.Fatal(http.ListenAndServe(*addr, nil))
+}
+
+var homeTemplate = template.Must(template.New("").Parse(`
+<!DOCTYPE html>
+<head>
+<meta charset="utf-8">
+<script>
+window.addEventListener("load", function(evt) {
+
+ var output = document.getElementById("output");
+ var input = document.getElementById("input");
+ var ws;
+
+ var print = function(message) {
+ var d = document.createElement("div");
+ d.innerHTML = message;
+ output.appendChild(d);
+ };
+
+ document.getElementById("open").onclick = function(evt) {
+ if (ws) {
+ return false;
+ }
+ ws = new WebSocket("{{.}}");
+ ws.onopen = function(evt) {
+ print("OPEN");
+ }
+ ws.onclose = function(evt) {
+ print("CLOSE");
+ ws = null;
+ }
+ ws.onmessage = function(evt) {
+ print("RESPONSE: " + evt.data);
+ }
+ ws.onerror = function(evt) {
+ print("ERROR: " + evt.data);
+ }
+ return false;
+ };
+
+ document.getElementById("send").onclick = function(evt) {
+ if (!ws) {
+ return false;
+ }
+ print("SEND: " + input.value);
+ ws.send(input.value);
+ return false;
+ };
+
+ document.getElementById("close").onclick = function(evt) {
+ if (!ws) {
+ return false;
+ }
+ ws.close();
+ return false;
+ };
+
+});
+</script>
+</head>
+<body>
+<table>
+<tr><td valign="top" width="50%">
+<p>Click "Open" to create a connection to the server,
+"Send" to send a message to the server and "Close" to close the connection.
+You can change the message and send multiple times.
+<p>
+<form>
+<button id="open">Open</button>
+<button id="close">Close</button>
+<p><input id="input" type="text" value="Hello world!">
+<button id="send">Send</button>
+</form>
+</td><td valign="top" width="50%">
+<div id="output"></div>
+</td></tr></table>
+</body>
+</html>
+`))
diff --git a/vendor/github.com/gorilla/websocket/examples/filewatch/README.md b/vendor/github.com/gorilla/websocket/examples/filewatch/README.md
new file mode 100644
index 000000000..ca4931f3b
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/filewatch/README.md
@@ -0,0 +1,9 @@
+# File Watch example.
+
+This example sends a file to the browser client for display whenever the file is modified.
+
+ $ go get github.com/gorilla/websocket
+ $ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/filewatch`
+ $ go run main.go <name of file to watch>
+ # Open http://localhost:8080/ .
+ # Modify the file to see it update in the browser.
diff --git a/vendor/github.com/gorilla/websocket/examples/filewatch/main.go b/vendor/github.com/gorilla/websocket/examples/filewatch/main.go
new file mode 100644
index 000000000..2ac2b324f
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/examples/filewatch/main.go
@@ -0,0 +1,193 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "flag"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "strconv"
+ "text/template"
+ "time"
+
+ "github.com/gorilla/websocket"
+)
+
+const (
+ // Time allowed to write the file to the client.
+ writeWait = 10 * time.Second
+
+ // Time allowed to read the next pong message from the client.
+ pongWait = 60 * time.Second
+
+ // Send pings to client with this period. Must be less than pongWait.
+ pingPeriod = (pongWait * 9) / 10
+
+ // Poll file for changes with this period.
+ filePeriod = 10 * time.Second
+)
+
+var (
+ addr = flag.String("addr", ":8080", "http service address")
+ homeTempl = template.Must(template.New("").Parse(homeHTML))
+ filename string
+ upgrader = websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+ }
+)
+
+func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) {
+ fi, err := os.Stat(filename)
+ if err != nil {
+ return nil, lastMod, err
+ }
+ if !fi.ModTime().After(lastMod) {
+ return nil, lastMod, nil
+ }
+ p, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, fi.ModTime(), err
+ }
+ return p, fi.ModTime(), nil
+}
+
+func reader(ws *websocket.Conn) {
+ defer ws.Close()
+ ws.SetReadLimit(512)
+ ws.SetReadDeadline(time.Now().Add(pongWait))
+ ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
+ for {
+ _, _, err := ws.ReadMessage()
+ if err != nil {
+ break
+ }
+ }
+}
+
+func writer(ws *websocket.Conn, lastMod time.Time) {
+ lastError := ""
+ pingTicker := time.NewTicker(pingPeriod)
+ fileTicker := time.NewTicker(filePeriod)
+ defer func() {
+ pingTicker.Stop()
+ fileTicker.Stop()
+ ws.Close()
+ }()
+ for {
+ select {
+ case <-fileTicker.C:
+ var p []byte
+ var err error
+
+ p, lastMod, err = readFileIfModified(lastMod)
+
+ if err != nil {
+ if s := err.Error(); s != lastError {
+ lastError = s
+ p = []byte(lastError)
+ }
+ } else {
+ lastError = ""
+ }
+
+ if p != nil {
+ ws.SetWriteDeadline(time.Now().Add(writeWait))
+ if err := ws.WriteMessage(websocket.TextMessage, p); err != nil {
+ return
+ }
+ }
+ case <-pingTicker.C:
+ ws.SetWriteDeadline(time.Now().Add(writeWait))
+ if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
+ return
+ }
+ }
+ }
+}
+
+func serveWs(w http.ResponseWriter, r *http.Request) {
+ ws, err := upgrader.Upgrade(w, r, nil)
+ if err != nil {
+ if _, ok := err.(websocket.HandshakeError); !ok {
+ log.Println(err)
+ }
+ return
+ }
+
+ var lastMod time.Time
+ if n, err := strconv.ParseInt(r.FormValue("lastMod"), 16, 64); err == nil {
+ lastMod = time.Unix(0, n)
+ }
+
+ go writer(ws, lastMod)
+ reader(ws)
+}
+
+func serveHome(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/" {
+ http.Error(w, "Not found", 404)
+ return
+ }
+ if r.Method != "GET" {
+ http.Error(w, "Method not allowed", 405)
+ return
+ }
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ p, lastMod, err := readFileIfModified(time.Time{})
+ if err != nil {
+ p = []byte(err.Error())
+ lastMod = time.Unix(0, 0)
+ }
+ var v = struct {
+ Host string
+ Data string
+ LastMod string
+ }{
+ r.Host,
+ string(p),
+ strconv.FormatInt(lastMod.UnixNano(), 16),
+ }
+ homeTempl.Execute(w, &v)
+}
+
+func main() {
+ flag.Parse()
+ if flag.NArg() != 1 {
+ log.Fatal("filename not specified")
+ }
+ filename = flag.Args()[0]
+ http.HandleFunc("/", serveHome)
+ http.HandleFunc("/ws", serveWs)
+ if err := http.ListenAndServe(*addr, nil); err != nil {
+ log.Fatal(err)
+ }
+}
+
+const homeHTML = `<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>WebSocket Example</title>
+ </head>
+ <body>
+ <pre id="fileData">{{.Data}}</pre>
+ <script type="text/javascript">
+ (function() {
+ var data = document.getElementById("fileData");
+ var conn = new WebSocket("ws://{{.Host}}/ws?lastMod={{.LastMod}}");
+ conn.onclose = function(evt) {
+ data.textContent = 'Connection closed';
+ }
+ conn.onmessage = function(evt) {
+ console.log('file updated');
+ data.textContent = evt.data;
+ }
+ })();
+ </script>
+ </body>
+</html>
+`
diff --git a/vendor/github.com/gorilla/websocket/json_test.go b/vendor/github.com/gorilla/websocket/json_test.go
new file mode 100644
index 000000000..61100e481
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/json_test.go
@@ -0,0 +1,119 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "reflect"
+ "testing"
+)
+
+func TestJSON(t *testing.T) {
+ var buf bytes.Buffer
+ c := fakeNetConn{&buf, &buf}
+ wc := newConn(c, true, 1024, 1024)
+ rc := newConn(c, false, 1024, 1024)
+
+ var actual, expect struct {
+ A int
+ B string
+ }
+ expect.A = 1
+ expect.B = "hello"
+
+ if err := wc.WriteJSON(&expect); err != nil {
+ t.Fatal("write", err)
+ }
+
+ if err := rc.ReadJSON(&actual); err != nil {
+ t.Fatal("read", err)
+ }
+
+ if !reflect.DeepEqual(&actual, &expect) {
+ t.Fatal("equal", actual, expect)
+ }
+}
+
+func TestPartialJSONRead(t *testing.T) {
+ var buf bytes.Buffer
+ c := fakeNetConn{&buf, &buf}
+ wc := newConn(c, true, 1024, 1024)
+ rc := newConn(c, false, 1024, 1024)
+
+ var v struct {
+ A int
+ B string
+ }
+ v.A = 1
+ v.B = "hello"
+
+ messageCount := 0
+
+ // Partial JSON values.
+
+ data, err := json.Marshal(v)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for i := len(data) - 1; i >= 0; i-- {
+ if err := wc.WriteMessage(TextMessage, data[:i]); err != nil {
+ t.Fatal(err)
+ }
+ messageCount++
+ }
+
+ // Whitespace.
+
+ if err := wc.WriteMessage(TextMessage, []byte(" ")); err != nil {
+ t.Fatal(err)
+ }
+ messageCount++
+
+ // Close.
+
+ if err := wc.WriteMessage(CloseMessage, FormatCloseMessage(CloseNormalClosure, "")); err != nil {
+ t.Fatal(err)
+ }
+
+ for i := 0; i < messageCount; i++ {
+ err := rc.ReadJSON(&v)
+ if err != io.ErrUnexpectedEOF {
+ t.Error("read", i, err)
+ }
+ }
+
+ err = rc.ReadJSON(&v)
+ if _, ok := err.(*CloseError); !ok {
+ t.Error("final", err)
+ }
+}
+
+func TestDeprecatedJSON(t *testing.T) {
+ var buf bytes.Buffer
+ c := fakeNetConn{&buf, &buf}
+ wc := newConn(c, true, 1024, 1024)
+ rc := newConn(c, false, 1024, 1024)
+
+ var actual, expect struct {
+ A int
+ B string
+ }
+ expect.A = 1
+ expect.B = "hello"
+
+ if err := WriteJSON(wc, &expect); err != nil {
+ t.Fatal("write", err)
+ }
+
+ if err := ReadJSON(rc, &actual); err != nil {
+ t.Fatal("read", err)
+ }
+
+ if !reflect.DeepEqual(&actual, &expect) {
+ t.Fatal("equal", actual, expect)
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/server_test.go b/vendor/github.com/gorilla/websocket/server_test.go
new file mode 100644
index 000000000..0a28141d6
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/server_test.go
@@ -0,0 +1,51 @@
+// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "net/http"
+ "reflect"
+ "testing"
+)
+
+var subprotocolTests = []struct {
+ h string
+ protocols []string
+}{
+ {"", nil},
+ {"foo", []string{"foo"}},
+ {"foo,bar", []string{"foo", "bar"}},
+ {"foo, bar", []string{"foo", "bar"}},
+ {" foo, bar", []string{"foo", "bar"}},
+ {" foo, bar ", []string{"foo", "bar"}},
+}
+
+func TestSubprotocols(t *testing.T) {
+ for _, st := range subprotocolTests {
+ r := http.Request{Header: http.Header{"Sec-Websocket-Protocol": {st.h}}}
+ protocols := Subprotocols(&r)
+ if !reflect.DeepEqual(st.protocols, protocols) {
+ t.Errorf("SubProtocols(%q) returned %#v, want %#v", st.h, protocols, st.protocols)
+ }
+ }
+}
+
+var isWebSocketUpgradeTests = []struct {
+ ok bool
+ h http.Header
+}{
+ {false, http.Header{"Upgrade": {"websocket"}}},
+ {false, http.Header{"Connection": {"upgrade"}}},
+ {true, http.Header{"Connection": {"upgRade"}, "Upgrade": {"WebSocket"}}},
+}
+
+func TestIsWebSocketUpgrade(t *testing.T) {
+ for _, tt := range isWebSocketUpgradeTests {
+ ok := IsWebSocketUpgrade(&http.Request{Header: tt.h})
+ if tt.ok != ok {
+ t.Errorf("IsWebSocketUpgrade(%v) returned %v, want %v", tt.h, ok, tt.ok)
+ }
+ }
+}
diff --git a/vendor/github.com/gorilla/websocket/util_test.go b/vendor/github.com/gorilla/websocket/util_test.go
new file mode 100644
index 000000000..91f70ceb0
--- /dev/null
+++ b/vendor/github.com/gorilla/websocket/util_test.go
@@ -0,0 +1,34 @@
+// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package websocket
+
+import (
+ "net/http"
+ "testing"
+)
+
+var tokenListContainsValueTests = []struct {
+ value string
+ ok bool
+}{
+ {"WebSocket", true},
+ {"WEBSOCKET", true},
+ {"websocket", true},
+ {"websockets", false},
+ {"x websocket", false},
+ {"websocket x", false},
+ {"other,websocket,more", true},
+ {"other, websocket, more", true},
+}
+
+func TestTokenListContainsValue(t *testing.T) {
+ for _, tt := range tokenListContainsValueTests {
+ h := http.Header{"Upgrade": {tt.value}}
+ ok := tokenListContainsValue(h, "Upgrade", "websocket")
+ if ok != tt.ok {
+ t.Errorf("tokenListContainsValue(h, n, %q) = %v, want %v", tt.value, ok, tt.ok)
+ }
+ }
+}
diff --git a/vendor/github.com/lib/pq/.travis.yml b/vendor/github.com/lib/pq/.travis.yml
index 567c7c666..d63afcb9f 100644
--- a/vendor/github.com/lib/pq/.travis.yml
+++ b/vendor/github.com/lib/pq/.travis.yml
@@ -37,6 +37,7 @@ before_install:
- sudo cat /etc/postgresql/$PGVERSION/main/postgresql.conf
- sudo chmod 600 $PQSSLCERTTEST_PATH/postgresql.key
- sudo /etc/init.d/postgresql restart
+ - go get golang.org/x/tools/cmd/goimports
env:
global:
@@ -59,7 +60,7 @@ env:
- PGVERSION=9.0 PQTEST_BINARY_PARAMETERS=no
script:
- - go test -v ./...
+ - result=$(goimports -d -e $(find -name \*.go)); test -z "$result" || (echo "$result" && false) && go vet ./... && go test -v ./...
before_script:
- psql -c 'create database pqgotest' -U postgres
diff --git a/vendor/github.com/lib/pq/README.md b/vendor/github.com/lib/pq/README.md
index b4e3f45cb..148451e80 100644
--- a/vendor/github.com/lib/pq/README.md
+++ b/vendor/github.com/lib/pq/README.md
@@ -20,11 +20,11 @@ variables.
Example:
- PGHOST=/var/run/postgresql go test github.com/lib/pq
+ PGHOST=/run/postgresql go test github.com/lib/pq
Optionally, a benchmark suite can be run as part of the tests:
- PGHOST=/var/run/postgresql go test -bench .
+ PGHOST=/run/postgresql go test -bench .
## Features
diff --git a/vendor/github.com/lib/pq/bench_test.go b/vendor/github.com/lib/pq/bench_test.go
new file mode 100644
index 000000000..e71f41d06
--- /dev/null
+++ b/vendor/github.com/lib/pq/bench_test.go
@@ -0,0 +1,435 @@
+// +build go1.1
+
+package pq
+
+import (
+ "bufio"
+ "bytes"
+ "database/sql"
+ "database/sql/driver"
+ "io"
+ "math/rand"
+ "net"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/lib/pq/oid"
+)
+
+var (
+ selectStringQuery = "SELECT '" + strings.Repeat("0123456789", 10) + "'"
+ selectSeriesQuery = "SELECT generate_series(1, 100)"
+)
+
+func BenchmarkSelectString(b *testing.B) {
+ var result string
+ benchQuery(b, selectStringQuery, &result)
+}
+
+func BenchmarkSelectSeries(b *testing.B) {
+ var result int
+ benchQuery(b, selectSeriesQuery, &result)
+}
+
+func benchQuery(b *testing.B, query string, result interface{}) {
+ b.StopTimer()
+ db := openTestConn(b)
+ defer db.Close()
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ benchQueryLoop(b, db, query, result)
+ }
+}
+
+func benchQueryLoop(b *testing.B, db *sql.DB, query string, result interface{}) {
+ rows, err := db.Query(query)
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer rows.Close()
+ for rows.Next() {
+ err = rows.Scan(result)
+ if err != nil {
+ b.Fatal("failed to scan", err)
+ }
+ }
+}
+
+// reading from circularConn yields content[:prefixLen] once, followed by
+// content[prefixLen:] over and over again. It never returns EOF.
+type circularConn struct {
+ content string
+ prefixLen int
+ pos int
+ net.Conn // for all other net.Conn methods that will never be called
+}
+
+func (r *circularConn) Read(b []byte) (n int, err error) {
+ n = copy(b, r.content[r.pos:])
+ r.pos += n
+ if r.pos >= len(r.content) {
+ r.pos = r.prefixLen
+ }
+ return
+}
+
+func (r *circularConn) Write(b []byte) (n int, err error) { return len(b), nil }
+
+func (r *circularConn) Close() error { return nil }
+
+func fakeConn(content string, prefixLen int) *conn {
+ c := &circularConn{content: content, prefixLen: prefixLen}
+ return &conn{buf: bufio.NewReader(c), c: c}
+}
+
+// This benchmark is meant to be the same as BenchmarkSelectString, but takes
+// out some of the factors this package can't control. The numbers are less noisy,
+// but also the costs of network communication aren't accurately represented.
+func BenchmarkMockSelectString(b *testing.B) {
+ b.StopTimer()
+ // taken from a recorded run of BenchmarkSelectString
+ // See: http://www.postgresql.org/docs/current/static/protocol-message-formats.html
+ const response = "1\x00\x00\x00\x04" +
+ "t\x00\x00\x00\x06\x00\x00" +
+ "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
+ "Z\x00\x00\x00\x05I" +
+ "2\x00\x00\x00\x04" +
+ "D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
+ "C\x00\x00\x00\rSELECT 1\x00" +
+ "Z\x00\x00\x00\x05I" +
+ "3\x00\x00\x00\x04" +
+ "Z\x00\x00\x00\x05I"
+ c := fakeConn(response, 0)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ benchMockQuery(b, c, selectStringQuery)
+ }
+}
+
+var seriesRowData = func() string {
+ var buf bytes.Buffer
+ for i := 1; i <= 100; i++ {
+ digits := byte(2)
+ if i >= 100 {
+ digits = 3
+ } else if i < 10 {
+ digits = 1
+ }
+ buf.WriteString("D\x00\x00\x00")
+ buf.WriteByte(10 + digits)
+ buf.WriteString("\x00\x01\x00\x00\x00")
+ buf.WriteByte(digits)
+ buf.WriteString(strconv.Itoa(i))
+ }
+ return buf.String()
+}()
+
+func BenchmarkMockSelectSeries(b *testing.B) {
+ b.StopTimer()
+ var response = "1\x00\x00\x00\x04" +
+ "t\x00\x00\x00\x06\x00\x00" +
+ "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
+ "Z\x00\x00\x00\x05I" +
+ "2\x00\x00\x00\x04" +
+ seriesRowData +
+ "C\x00\x00\x00\x0fSELECT 100\x00" +
+ "Z\x00\x00\x00\x05I" +
+ "3\x00\x00\x00\x04" +
+ "Z\x00\x00\x00\x05I"
+ c := fakeConn(response, 0)
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ benchMockQuery(b, c, selectSeriesQuery)
+ }
+}
+
+func benchMockQuery(b *testing.B, c *conn, query string) {
+ stmt, err := c.Prepare(query)
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer stmt.Close()
+ rows, err := stmt.Query(nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer rows.Close()
+ var dest [1]driver.Value
+ for {
+ if err := rows.Next(dest[:]); err != nil {
+ if err == io.EOF {
+ break
+ }
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkPreparedSelectString(b *testing.B) {
+ var result string
+ benchPreparedQuery(b, selectStringQuery, &result)
+}
+
+func BenchmarkPreparedSelectSeries(b *testing.B) {
+ var result int
+ benchPreparedQuery(b, selectSeriesQuery, &result)
+}
+
+func benchPreparedQuery(b *testing.B, query string, result interface{}) {
+ b.StopTimer()
+ db := openTestConn(b)
+ defer db.Close()
+ stmt, err := db.Prepare(query)
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer stmt.Close()
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ benchPreparedQueryLoop(b, db, stmt, result)
+ }
+}
+
+func benchPreparedQueryLoop(b *testing.B, db *sql.DB, stmt *sql.Stmt, result interface{}) {
+ rows, err := stmt.Query()
+ if err != nil {
+ b.Fatal(err)
+ }
+ if !rows.Next() {
+ rows.Close()
+ b.Fatal("no rows")
+ }
+ defer rows.Close()
+ for rows.Next() {
+ err = rows.Scan(&result)
+ if err != nil {
+ b.Fatal("failed to scan")
+ }
+ }
+}
+
+// See the comment for BenchmarkMockSelectString.
+func BenchmarkMockPreparedSelectString(b *testing.B) {
+ b.StopTimer()
+ const parseResponse = "1\x00\x00\x00\x04" +
+ "t\x00\x00\x00\x06\x00\x00" +
+ "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
+ "Z\x00\x00\x00\x05I"
+ const responses = parseResponse +
+ "2\x00\x00\x00\x04" +
+ "D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" +
+ "C\x00\x00\x00\rSELECT 1\x00" +
+ "Z\x00\x00\x00\x05I"
+ c := fakeConn(responses, len(parseResponse))
+
+ stmt, err := c.Prepare(selectStringQuery)
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ benchPreparedMockQuery(b, c, stmt)
+ }
+}
+
+func BenchmarkMockPreparedSelectSeries(b *testing.B) {
+ b.StopTimer()
+ const parseResponse = "1\x00\x00\x00\x04" +
+ "t\x00\x00\x00\x06\x00\x00" +
+ "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" +
+ "Z\x00\x00\x00\x05I"
+ var responses = parseResponse +
+ "2\x00\x00\x00\x04" +
+ seriesRowData +
+ "C\x00\x00\x00\x0fSELECT 100\x00" +
+ "Z\x00\x00\x00\x05I"
+ c := fakeConn(responses, len(parseResponse))
+
+ stmt, err := c.Prepare(selectSeriesQuery)
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ benchPreparedMockQuery(b, c, stmt)
+ }
+}
+
+func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) {
+ rows, err := stmt.Query(nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer rows.Close()
+ var dest [1]driver.Value
+ for {
+ if err := rows.Next(dest[:]); err != nil {
+ if err == io.EOF {
+ break
+ }
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkEncodeInt64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ encode(&parameterStatus{}, int64(1234), oid.T_int8)
+ }
+}
+
+func BenchmarkEncodeFloat64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ encode(&parameterStatus{}, 3.14159, oid.T_float8)
+ }
+}
+
+var testByteString = []byte("abcdefghijklmnopqrstuvwxyz")
+
+func BenchmarkEncodeByteaHex(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ encode(&parameterStatus{serverVersion: 90000}, testByteString, oid.T_bytea)
+ }
+}
+func BenchmarkEncodeByteaEscape(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ encode(&parameterStatus{serverVersion: 84000}, testByteString, oid.T_bytea)
+ }
+}
+
+func BenchmarkEncodeBool(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ encode(&parameterStatus{}, true, oid.T_bool)
+ }
+}
+
+var testTimestamptz = time.Date(2001, time.January, 1, 0, 0, 0, 0, time.Local)
+
+func BenchmarkEncodeTimestamptz(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ encode(&parameterStatus{}, testTimestamptz, oid.T_timestamptz)
+ }
+}
+
+var testIntBytes = []byte("1234")
+
+func BenchmarkDecodeInt64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ decode(&parameterStatus{}, testIntBytes, oid.T_int8, formatText)
+ }
+}
+
+var testFloatBytes = []byte("3.14159")
+
+func BenchmarkDecodeFloat64(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ decode(&parameterStatus{}, testFloatBytes, oid.T_float8, formatText)
+ }
+}
+
+var testBoolBytes = []byte{'t'}
+
+func BenchmarkDecodeBool(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ decode(&parameterStatus{}, testBoolBytes, oid.T_bool, formatText)
+ }
+}
+
+func TestDecodeBool(t *testing.T) {
+ db := openTestConn(t)
+ rows, err := db.Query("select true")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows.Close()
+}
+
+var testTimestamptzBytes = []byte("2013-09-17 22:15:32.360754-07")
+
+func BenchmarkDecodeTimestamptz(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ decode(&parameterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText)
+ }
+}
+
+func BenchmarkDecodeTimestamptzMultiThread(b *testing.B) {
+ oldProcs := runtime.GOMAXPROCS(0)
+ defer runtime.GOMAXPROCS(oldProcs)
+ runtime.GOMAXPROCS(runtime.NumCPU())
+ globalLocationCache = newLocationCache()
+
+ f := func(wg *sync.WaitGroup, loops int) {
+ defer wg.Done()
+ for i := 0; i < loops; i++ {
+ decode(&parameterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText)
+ }
+ }
+
+ wg := &sync.WaitGroup{}
+ b.ResetTimer()
+ for j := 0; j < 10; j++ {
+ wg.Add(1)
+ go f(wg, b.N/10)
+ }
+ wg.Wait()
+}
+
+func BenchmarkLocationCache(b *testing.B) {
+ globalLocationCache = newLocationCache()
+ for i := 0; i < b.N; i++ {
+ globalLocationCache.getLocation(rand.Intn(10000))
+ }
+}
+
+func BenchmarkLocationCacheMultiThread(b *testing.B) {
+ oldProcs := runtime.GOMAXPROCS(0)
+ defer runtime.GOMAXPROCS(oldProcs)
+ runtime.GOMAXPROCS(runtime.NumCPU())
+ globalLocationCache = newLocationCache()
+
+ f := func(wg *sync.WaitGroup, loops int) {
+ defer wg.Done()
+ for i := 0; i < loops; i++ {
+ globalLocationCache.getLocation(rand.Intn(10000))
+ }
+ }
+
+ wg := &sync.WaitGroup{}
+ b.ResetTimer()
+ for j := 0; j < 10; j++ {
+ wg.Add(1)
+ go f(wg, b.N/10)
+ }
+ wg.Wait()
+}
+
+// Stress test the performance of parsing results from the wire.
+func BenchmarkResultParsing(b *testing.B) {
+ b.StopTimer()
+
+ db := openTestConn(b)
+ defer db.Close()
+ _, err := db.Exec("BEGIN")
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ res, err := db.Query("SELECT generate_series(1, 50000)")
+ if err != nil {
+ b.Fatal(err)
+ }
+ res.Close()
+ }
+}
diff --git a/vendor/github.com/lib/pq/certs/README b/vendor/github.com/lib/pq/certs/README
new file mode 100644
index 000000000..24ab7b256
--- /dev/null
+++ b/vendor/github.com/lib/pq/certs/README
@@ -0,0 +1,3 @@
+This directory contains certificates and private keys for testing some
+SSL-related functionality in Travis. Do NOT use these certificates for
+anything other than testing.
diff --git a/vendor/github.com/lib/pq/certs/postgresql.crt b/vendor/github.com/lib/pq/certs/postgresql.crt
new file mode 100644
index 000000000..6e6b4284a
--- /dev/null
+++ b/vendor/github.com/lib/pq/certs/postgresql.crt
@@ -0,0 +1,69 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 2 (0x2)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pq CA
+ Validity
+ Not Before: Oct 11 15:10:11 2014 GMT
+ Not After : Oct 8 15:10:11 2024 GMT
+ Subject: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pqgosslcert
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (1024 bit)
+ Modulus (1024 bit):
+ 00:e3:8c:06:9a:70:54:51:d1:34:34:83:39:cd:a2:
+ 59:0f:05:ed:8d:d8:0e:34:d0:92:f4:09:4d:ee:8c:
+ 78:55:49:24:f8:3c:e0:34:58:02:b2:e7:94:58:c1:
+ e8:e5:bb:d1:af:f6:54:c1:40:b1:90:70:79:0d:35:
+ 54:9c:8f:16:e9:c2:f0:92:e6:64:49:38:c1:76:f8:
+ 47:66:c4:5b:4a:b6:a9:43:ce:c8:be:6c:4d:2b:94:
+ 97:3c:55:bc:d1:d0:6e:b7:53:ae:89:5c:4b:6b:86:
+ 40:be:c1:ae:1e:64:ce:9c:ae:87:0a:69:e5:c8:21:
+ 12:be:ae:1d:f6:45:df:16:a7
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 9B:25:31:63:A2:D8:06:FF:CB:E3:E9:96:FF:0D:BA:DC:12:7D:04:CF
+ X509v3 Authority Key Identifier:
+ keyid:52:93:ED:1E:76:0A:9F:65:4F:DE:19:66:C1:D5:22:40:35:CB:A0:72
+
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Signature Algorithm: sha256WithRSAEncryption
+ 3e:f5:f8:0b:4e:11:bd:00:86:1f:ce:dc:97:02:98:91:11:f5:
+ 65:f6:f2:8a:b2:3e:47:92:05:69:28:c9:e9:b4:f7:cf:93:d1:
+ 2d:81:5d:00:3c:23:be:da:70:ea:59:e1:2c:d3:25:49:ae:a6:
+ 95:54:c1:10:df:23:e3:fe:d6:e4:76:c7:6b:73:ad:1b:34:7c:
+ e2:56:cc:c0:37:ae:c5:7a:11:20:6c:3d:05:0e:99:cd:22:6c:
+ cf:59:a1:da:28:d4:65:ba:7d:2f:2b:3d:69:6d:a6:c1:ae:57:
+ bf:56:64:13:79:f8:48:46:65:eb:81:67:28:0b:7b:de:47:10:
+ b3:80:3c:31:d1:58:94:01:51:4a:c7:c8:1a:01:a8:af:c4:cd:
+ bb:84:a5:d9:8b:b4:b9:a1:64:3e:95:d9:90:1d:d5:3f:67:cc:
+ 3b:ba:f5:b4:d1:33:77:ee:c2:d2:3e:7e:c5:66:6e:b7:35:4c:
+ 60:57:b0:b8:be:36:c8:f3:d3:95:8c:28:4a:c9:f7:27:a4:0d:
+ e5:96:99:eb:f5:c8:bd:f3:84:6d:ef:02:f9:8a:36:7d:6b:5f:
+ 36:68:37:41:d9:74:ae:c6:78:2e:44:86:a1:ad:43:ca:fb:b5:
+ 3e:ba:10:23:09:02:ac:62:d1:d0:83:c8:95:b9:e3:5e:30:ff:
+ 5b:2b:38:fa
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAfugAwIBAgIBAjANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEP
+MA0GA1UECBMGTmV2YWRhMRIwEAYDVQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdp
+dGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDEwVwcSBDQTAeFw0xNDEwMTExNTEwMTFa
+Fw0yNDEwMDgxNTEwMTFaMGQxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGEx
+EjAQBgNVBAcTCUxhcyBWZWdhczEaMBgGA1UEChMRZ2l0aHViLmNvbS9saWIvcHEx
+FDASBgNVBAMTC3BxZ29zc2xjZXJ0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0WAKy55RYwejl
+u9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+bE0rlJc8VbzR
+0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQABo1owWDAdBgNV
+HQ4EFgQUmyUxY6LYBv/L4+mW/w263BJ9BM8wHwYDVR0jBBgwFoAUUpPtHnYKn2VP
+3hlmwdUiQDXLoHIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQEL
+BQADggEBAD71+AtOEb0Ahh/O3JcCmJER9WX28oqyPkeSBWkoyem098+T0S2BXQA8
+I77acOpZ4SzTJUmuppVUwRDfI+P+1uR2x2tzrRs0fOJWzMA3rsV6ESBsPQUOmc0i
+bM9Zodoo1GW6fS8rPWltpsGuV79WZBN5+EhGZeuBZygLe95HELOAPDHRWJQBUUrH
+yBoBqK/EzbuEpdmLtLmhZD6V2ZAd1T9nzDu69bTRM3fuwtI+fsVmbrc1TGBXsLi+
+Nsjz05WMKErJ9yekDeWWmev1yL3zhG3vAvmKNn1rXzZoN0HZdK7GeC5EhqGtQ8r7
+tT66ECMJAqxi0dCDyJW5414w/1srOPo=
+-----END CERTIFICATE-----
diff --git a/vendor/github.com/lib/pq/certs/postgresql.key b/vendor/github.com/lib/pq/certs/postgresql.key
new file mode 100644
index 000000000..eb8b20be9
--- /dev/null
+++ b/vendor/github.com/lib/pq/certs/postgresql.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQDjjAaacFRR0TQ0gznNolkPBe2N2A400JL0CU3ujHhVSST4POA0
+WAKy55RYwejlu9Gv9lTBQLGQcHkNNVScjxbpwvCS5mRJOMF2+EdmxFtKtqlDzsi+
+bE0rlJc8VbzR0G63U66JXEtrhkC+wa4eZM6crocKaeXIIRK+rh32Rd8WpwIDAQAB
+AoGAM5dM6/kp9P700i8qjOgRPym96Zoh5nGfz/rIE5z/r36NBkdvIg8OVZfR96nH
+b0b9TOMR5lsPp0sI9yivTWvX6qyvLJRWy2vvx17hXK9NxXUNTAm0PYZUTvCtcPeX
+RnJpzQKNZQPkFzF0uXBc4CtPK2Vz0+FGvAelrhYAxnw1dIkCQQD+9qaW5QhXjsjb
+Nl85CmXgxPmGROcgLQCO+omfrjf9UXrituU9Dz6auym5lDGEdMFnkzfr+wpasEy9
+mf5ZZOhDAkEA5HjXfVGaCtpydOt6hDon/uZsyssCK2lQ7NSuE3vP+sUsYMzIpEoy
+t3VWXqKbo+g9KNDTP4WEliqp1aiSIylzzQJANPeqzihQnlgEdD4MdD4rwhFJwVIp
+Le8Lcais1KaN7StzOwxB/XhgSibd2TbnPpw+3bSg5n5lvUdo+e62/31OHwJAU1jS
+I+F09KikQIr28u3UUWT2IzTT4cpVv1AHAQyV3sG3YsjSGT0IK20eyP9BEBZU2WL0
+7aNjrvR5aHxKc5FXsQJABsFtyGpgI5X4xufkJZVZ+Mklz2n7iXa+XPatMAHFxAtb
+EEMt60rngwMjXAzBSC6OYuYogRRAY3UCacNC5VhLYQ==
+-----END RSA PRIVATE KEY-----
diff --git a/vendor/github.com/lib/pq/certs/root.crt b/vendor/github.com/lib/pq/certs/root.crt
new file mode 100644
index 000000000..aecf8f621
--- /dev/null
+++ b/vendor/github.com/lib/pq/certs/root.crt
@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIJANmheROCdW1NMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNV
+BAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGExEjAQBgNVBAcTCUxhcyBWZWdhczEaMBgG
+A1UEChMRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMTBXBxIENBMB4XDTE0MTAx
+MTE1MDQyOVoXDTI0MTAwODE1MDQyOVowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgT
+Bk5ldmFkYTESMBAGA1UEBxMJTGFzIFZlZ2FzMRowGAYDVQQKExFnaXRodWIuY29t
+L2xpYi9wcTEOMAwGA1UEAxMFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCV4PxP7ShzWBzUCThcKk3qZtOLtHmszQVtbqhvgTpm1kTRtKBdVMu0
+pLAHQ3JgJCnAYgH0iZxVGoMP16T3irdgsdC48+nNTFM2T0cCdkfDURGIhSFN47cb
+Pgy306BcDUD2q7ucW33+dlFSRuGVewocoh4BWM/vMtMvvWzdi4Ag/L/jhb+5wZxZ
+sWymsadOVSDePEMKOvlCa3EdVwVFV40TVyDb+iWBUivDAYsS2a3KajuJrO6MbZiE
+Sp2RCIkZS2zFmzWxVRi9ZhzIZhh7EVF9JAaNC3T52jhGUdlRq3YpBTMnd89iOh74
+6jWXG7wSuPj3haFzyNhmJ0ZUh+2Ynoh1AgMBAAGjgcMwgcAwHQYDVR0OBBYEFFKT
+7R52Cp9lT94ZZsHVIkA1y6ByMIGQBgNVHSMEgYgwgYWAFFKT7R52Cp9lT94ZZsHV
+IkA1y6ByoWKkYDBeMQswCQYDVQQGEwJVUzEPMA0GA1UECBMGTmV2YWRhMRIwEAYD
+VQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdpdGh1Yi5jb20vbGliL3BxMQ4wDAYD
+VQQDEwVwcSBDQYIJANmheROCdW1NMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF
+BQADggEBAAEhCLWkqJNMI8b4gkbmj5fqQ/4+oO83bZ3w2Oqf6eZ8I8BC4f2NOyE6
+tRUlq5+aU7eqC1cOAvGjO+YHN/bF/DFpwLlzvUSXt+JP/pYcUjL7v+pIvwqec9hD
+ndvM4iIbkD/H/OYQ3L+N3W+G1x7AcFIX+bGCb3PzYVQAjxreV6//wgKBosMGFbZo
+HPxT9RPMun61SViF04H5TNs0derVn1+5eiiYENeAhJzQNyZoOOUuX1X/Inx9bEPh
+C5vFBtSMgIytPgieRJVWAiMLYsfpIAStrHztRAbBs2DU01LmMgRvHdxgFEKinC/d
+UHZZQDP+6pT+zADrGhQGXe4eThaO6f0=
+-----END CERTIFICATE-----
diff --git a/vendor/github.com/lib/pq/certs/server.crt b/vendor/github.com/lib/pq/certs/server.crt
new file mode 100644
index 000000000..ddc995a6d
--- /dev/null
+++ b/vendor/github.com/lib/pq/certs/server.crt
@@ -0,0 +1,81 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number: 1 (0x1)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=pq CA
+ Validity
+ Not Before: Oct 11 15:05:15 2014 GMT
+ Not After : Oct 8 15:05:15 2024 GMT
+ Subject: C=US, ST=Nevada, L=Las Vegas, O=github.com/lib/pq, CN=postgres
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:d7:8a:4c:85:fb:17:a5:3c:8f:e0:72:11:29:ce:
+ 3f:b0:1f:3f:7d:c6:ee:7f:a7:fc:02:2b:35:47:08:
+ a6:3d:90:df:5c:56:14:94:00:c7:6d:d1:d2:e2:61:
+ 95:77:b8:e3:a6:66:31:f9:1f:21:7d:62:e1:27:da:
+ 94:37:61:4a:ea:63:53:a0:61:b8:9c:bb:a5:e2:e7:
+ b7:a6:d8:0f:05:04:c7:29:e2:ea:49:2b:7f:de:15:
+ 00:a6:18:70:50:c7:0c:de:9a:f9:5a:96:b0:e1:94:
+ 06:c6:6d:4a:21:3b:b4:0f:a5:6d:92:86:34:b2:4e:
+ d7:0e:a7:19:c0:77:0b:7b:87:c8:92:de:42:ff:86:
+ d2:b7:9a:a4:d4:15:23:ca:ad:a5:69:21:b8:ce:7e:
+ 66:cb:85:5d:b9:ed:8b:2d:09:8d:94:e4:04:1e:72:
+ ec:ef:d0:76:90:15:5a:a4:f7:91:4b:e9:ce:4e:9d:
+ 5d:9a:70:17:9c:d8:e9:73:83:ea:3d:61:99:a6:cd:
+ ac:91:40:5a:88:77:e5:4e:2a:8e:3d:13:f3:f9:38:
+ 6f:81:6b:8a:95:ca:0e:07:ab:6f:da:b4:8c:d9:ff:
+ aa:78:03:aa:c7:c2:cf:6f:64:92:d3:d8:83:d5:af:
+ f1:23:18:a7:2e:7b:17:0b:e7:7d:f1:fa:a8:41:a3:
+ 04:57
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ EE:F0:B3:46:DC:C7:09:EB:0E:B6:2F:E5:FE:62:60:45:44:9F:59:CC
+ X509v3 Authority Key Identifier:
+ keyid:52:93:ED:1E:76:0A:9F:65:4F:DE:19:66:C1:D5:22:40:35:CB:A0:72
+
+ X509v3 Basic Constraints:
+ CA:FALSE
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Key Encipherment
+ Signature Algorithm: sha256WithRSAEncryption
+ 7e:5a:6e:be:bf:d2:6c:c1:d6:fa:b6:fb:3f:06:53:36:08:87:
+ 9d:95:b1:39:af:9e:f6:47:38:17:39:da:25:7c:f2:ad:0c:e3:
+ ab:74:19:ca:fb:8c:a0:50:c0:1d:19:8a:9c:21:ed:0f:3a:d1:
+ 96:54:2e:10:09:4f:b8:70:f7:2b:99:43:d2:c6:15:bc:3f:24:
+ 7d:28:39:32:3f:8d:a4:4f:40:75:7f:3e:0d:1c:d1:69:f2:4e:
+ 98:83:47:97:d2:25:ac:c9:36:86:2f:04:a6:c4:86:c7:c4:00:
+ 5f:7f:b9:ad:fc:bf:e9:f5:78:d7:82:1a:51:0d:fc:ab:9e:92:
+ 1d:5f:0c:18:d1:82:e0:14:c9:ce:91:89:71:ff:49:49:ff:35:
+ bf:7b:44:78:42:c1:d0:66:65:bb:28:2e:60:ca:9b:20:12:a9:
+ 90:61:b1:96:ec:15:46:c9:37:f7:07:90:8a:89:45:2a:3f:37:
+ ec:dc:e3:e5:8f:c3:3a:57:80:a5:54:60:0c:e1:b2:26:99:2b:
+ 40:7e:36:d1:9a:70:02:ec:63:f4:3b:72:ae:81:fb:30:20:6d:
+ cb:48:46:c6:b5:8f:39:b1:84:05:25:55:8d:f5:62:f6:1b:46:
+ 2e:da:a3:4c:26:12:44:d7:56:b6:b8:a9:ca:d3:ab:71:45:7c:
+ 9f:48:6d:1e
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIBATANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJVUzEP
+MA0GA1UECBMGTmV2YWRhMRIwEAYDVQQHEwlMYXMgVmVnYXMxGjAYBgNVBAoTEWdp
+dGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDEwVwcSBDQTAeFw0xNDEwMTExNTA1MTVa
+Fw0yNDEwMDgxNTA1MTVaMGExCzAJBgNVBAYTAlVTMQ8wDQYDVQQIEwZOZXZhZGEx
+EjAQBgNVBAcTCUxhcyBWZWdhczEaMBgGA1UEChMRZ2l0aHViLmNvbS9saWIvcHEx
+ETAPBgNVBAMTCHBvc3RncmVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYUlADHbdHS4mGV
+d7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLqSSt/3hUAphhw
+UMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C/4bSt5qk1BUj
+yq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1dmnAXnNjpc4Pq
+PWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOqx8LPb2SS09iD
+1a/xIxinLnsXC+d98fqoQaMEVwIDAQABo1owWDAdBgNVHQ4EFgQU7vCzRtzHCesO
+ti/l/mJgRUSfWcwwHwYDVR0jBBgwFoAUUpPtHnYKn2VP3hlmwdUiQDXLoHIwCQYD
+VR0TBAIwADALBgNVHQ8EBAMCBeAwDQYJKoZIhvcNAQELBQADggEBAH5abr6/0mzB
+1vq2+z8GUzYIh52VsTmvnvZHOBc52iV88q0M46t0Gcr7jKBQwB0Zipwh7Q860ZZU
+LhAJT7hw9yuZQ9LGFbw/JH0oOTI/jaRPQHV/Pg0c0WnyTpiDR5fSJazJNoYvBKbE
+hsfEAF9/ua38v+n1eNeCGlEN/Kuekh1fDBjRguAUyc6RiXH/SUn/Nb97RHhCwdBm
+ZbsoLmDKmyASqZBhsZbsFUbJN/cHkIqJRSo/N+zc4+WPwzpXgKVUYAzhsiaZK0B+
+NtGacALsY/Q7cq6B+zAgbctIRsa1jzmxhAUlVY31YvYbRi7ao0wmEkTXVra4qcrT
+q3FFfJ9IbR4=
+-----END CERTIFICATE-----
diff --git a/vendor/github.com/lib/pq/certs/server.key b/vendor/github.com/lib/pq/certs/server.key
new file mode 100644
index 000000000..bd7b019b6
--- /dev/null
+++ b/vendor/github.com/lib/pq/certs/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA14pMhfsXpTyP4HIRKc4/sB8/fcbuf6f8Ais1RwimPZDfXFYU
+lADHbdHS4mGVd7jjpmYx+R8hfWLhJ9qUN2FK6mNToGG4nLul4ue3ptgPBQTHKeLq
+SSt/3hUAphhwUMcM3pr5Wpaw4ZQGxm1KITu0D6VtkoY0sk7XDqcZwHcLe4fIkt5C
+/4bSt5qk1BUjyq2laSG4zn5my4Vdue2LLQmNlOQEHnLs79B2kBVapPeRS+nOTp1d
+mnAXnNjpc4PqPWGZps2skUBaiHflTiqOPRPz+ThvgWuKlcoOB6tv2rSM2f+qeAOq
+x8LPb2SS09iD1a/xIxinLnsXC+d98fqoQaMEVwIDAQABAoIBAF3ZoihUhJ82F4+r
+Gz4QyDpv4L1reT2sb1aiabhcU8ZK5nbWJG+tRyjSS/i2dNaEcttpdCj9HR/zhgZM
+bm0OuAgG58rVwgS80CZUruq++Qs+YVojq8/gWPTiQD4SNhV2Fmx3HkwLgUk3oxuT
+SsvdqzGE3okGVrutCIcgy126eA147VPMoej1Bb3fO6npqK0pFPhZfAc0YoqJuM+k
+obRm5pAnGUipyLCFXjA9HYPKwYZw2RtfdA3CiImHeanSdqS+ctrC9y8BV40Th7gZ
+haXdKUNdjmIxV695QQ1mkGqpKLZFqhzKioGQ2/Ly2d1iaKN9fZltTusu8unepWJ2
+tlT9qMECgYEA9uHaF1t2CqE+AJvWTihHhPIIuLxoOQXYea1qvxfcH/UMtaLKzCNm
+lQ5pqCGsPvp+10f36yttO1ZehIvlVNXuJsjt0zJmPtIolNuJY76yeussfQ9jHheB
+5uPEzCFlHzxYbBUyqgWaF6W74okRGzEGJXjYSP0yHPPdU4ep2q3bGiUCgYEA34Af
+wBSuQSK7uLxArWHvQhyuvi43ZGXls6oRGl+Ysj54s8BP6XGkq9hEJ6G4yxgyV+BR
+DUOs5X8/TLT8POuIMYvKTQthQyCk0eLv2FLdESDuuKx0kBVY3s8lK3/z5HhrdOiN
+VMNZU+xDKgKc3hN9ypkk8vcZe6EtH7Y14e0rVcsCgYBTgxi8F/M5K0wG9rAqphNz
+VFBA9XKn/2M33cKjO5X5tXIEKzpAjaUQvNxexG04rJGljzG8+mar0M6ONahw5yD1
+O7i/XWgazgpuOEkkVYiYbd8RutfDgR4vFVMn3hAP3eDnRtBplRWH9Ec3HTiNIys6
+F8PKBOQjyRZQQC7jyzW3hQKBgACe5HeuFwXLSOYsb6mLmhR+6+VPT4wR1F95W27N
+USk9jyxAnngxfpmTkiziABdgS9N+pfr5cyN4BP77ia/Jn6kzkC5Cl9SN5KdIkA3z
+vPVtN/x/ThuQU5zaymmig1ThGLtMYggYOslG4LDfLPxY5YKIhle+Y+259twdr2yf
+Mf2dAoGAaGv3tWMgnIdGRk6EQL/yb9PKHo7ShN+tKNlGaK7WwzBdKs+Fe8jkgcr7
+pz4Ne887CmxejdISzOCcdT+Zm9Bx6I/uZwWOtDvWpIgIxVX9a9URj/+D1MxTE/y4
+d6H+c89yDY62I2+drMpdjCd3EtCaTlxpTbRS+s1eAHMH7aEkcCE=
+-----END RSA PRIVATE KEY-----
diff --git a/vendor/github.com/lib/pq/conn_test.go b/vendor/github.com/lib/pq/conn_test.go
new file mode 100644
index 000000000..274147c27
--- /dev/null
+++ b/vendor/github.com/lib/pq/conn_test.go
@@ -0,0 +1,1434 @@
+package pq
+
+import (
+ "database/sql"
+ "database/sql/driver"
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+)
+
+type Fatalistic interface {
+ Fatal(args ...interface{})
+}
+
+func forceBinaryParameters() bool {
+ bp := os.Getenv("PQTEST_BINARY_PARAMETERS")
+ if bp == "yes" {
+ return true
+ } else if bp == "" || bp == "no" {
+ return false
+ } else {
+ panic("unexpected value for PQTEST_BINARY_PARAMETERS")
+ }
+}
+
+func openTestConnConninfo(conninfo string) (*sql.DB, error) {
+ defaultTo := func(envvar string, value string) {
+ if os.Getenv(envvar) == "" {
+ os.Setenv(envvar, value)
+ }
+ }
+ defaultTo("PGDATABASE", "pqgotest")
+ defaultTo("PGSSLMODE", "disable")
+ defaultTo("PGCONNECT_TIMEOUT", "20")
+
+ if forceBinaryParameters() &&
+ !strings.HasPrefix(conninfo, "postgres://") &&
+ !strings.HasPrefix(conninfo, "postgresql://") {
+ conninfo = conninfo + " binary_parameters=yes"
+ }
+
+ return sql.Open("postgres", conninfo)
+}
+
+func openTestConn(t Fatalistic) *sql.DB {
+ conn, err := openTestConnConninfo("")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return conn
+}
+
+func getServerVersion(t *testing.T, db *sql.DB) int {
+ var version int
+ err := db.QueryRow("SHOW server_version_num").Scan(&version)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return version
+}
+
+func TestReconnect(t *testing.T) {
+ db1 := openTestConn(t)
+ defer db1.Close()
+ tx, err := db1.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ var pid1 int
+ err = tx.QueryRow("SELECT pg_backend_pid()").Scan(&pid1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ db2 := openTestConn(t)
+ defer db2.Close()
+ _, err = db2.Exec("SELECT pg_terminate_backend($1)", pid1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // The rollback will probably "fail" because we just killed
+ // its connection above
+ _ = tx.Rollback()
+
+ const expected int = 42
+ var result int
+ err = db1.QueryRow(fmt.Sprintf("SELECT %d", expected)).Scan(&result)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if result != expected {
+ t.Errorf("got %v; expected %v", result, expected)
+ }
+}
+
+func TestCommitInFailedTransaction(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err := txn.Query("SELECT error")
+ if err == nil {
+ rows.Close()
+ t.Fatal("expected failure")
+ }
+ err = txn.Commit()
+ if err != ErrInFailedTransaction {
+ t.Fatalf("expected ErrInFailedTransaction; got %#v", err)
+ }
+}
+
+func TestOpenURL(t *testing.T) {
+ testURL := func(url string) {
+ db, err := openTestConnConninfo(url)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db.Close()
+ // database/sql might not call our Open at all unless we do something with
+ // the connection
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ txn.Rollback()
+ }
+ testURL("postgres://")
+ testURL("postgresql://")
+}
+
+const pgpass_file = "/tmp/pqgotest_pgpass"
+
+func TestPgpass(t *testing.T) {
+ testAssert := func(conninfo string, expected string, reason string) {
+ conn, err := openTestConnConninfo(conninfo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+
+ txn, err := conn.Begin()
+ if err != nil {
+ if expected != "fail" {
+ t.Fatalf(reason, err)
+ }
+ return
+ }
+ rows, err := txn.Query("SELECT USER")
+ if err != nil {
+ txn.Rollback()
+ rows.Close()
+ if expected != "fail" {
+ t.Fatalf(reason, err)
+ }
+ } else {
+ if expected != "ok" {
+ t.Fatalf(reason, err)
+ }
+ }
+ txn.Rollback()
+ }
+ testAssert("", "ok", "missing .pgpass, unexpected error %#v")
+ os.Setenv("PGPASSFILE", pgpass_file)
+ testAssert("host=/tmp", "fail", ", unexpected error %#v")
+ os.Remove(pgpass_file)
+ pgpass, err := os.OpenFile(pgpass_file, os.O_RDWR|os.O_CREATE, 0644)
+ if err != nil {
+ t.Fatalf("Unexpected error writing pgpass file %#v", err)
+ }
+ _, err = pgpass.WriteString(`# comment
+server:5432:some_db:some_user:pass_A
+*:5432:some_db:some_user:pass_B
+localhost:*:*:*:pass_C
+*:*:*:*:pass_fallback
+`)
+ if err != nil {
+ t.Fatalf("Unexpected error writing pgpass file %#v", err)
+ }
+ pgpass.Close()
+
+ assertPassword := func(extra values, expected string) {
+ o := &values{"host": "localhost", "sslmode": "disable", "connect_timeout": "20", "user": "majid", "port": "5432", "extra_float_digits": "2", "dbname": "pqgotest", "client_encoding": "UTF8", "datestyle": "ISO, MDY"}
+ for k, v := range extra {
+ (*o)[k] = v
+ }
+ (&conn{}).handlePgpass(*o)
+ if o.Get("password") != expected {
+ t.Fatalf("For %v expected %s got %s", extra, expected, o.Get("password"))
+ }
+ }
+ // wrong permissions for the pgpass file means it should be ignored
+ assertPassword(values{"host": "example.com", "user": "foo"}, "")
+ // fix the permissions and check if it has taken effect
+ os.Chmod(pgpass_file, 0600)
+ assertPassword(values{"host": "server", "dbname": "some_db", "user": "some_user"}, "pass_A")
+ assertPassword(values{"host": "example.com", "user": "foo"}, "pass_fallback")
+ assertPassword(values{"host": "example.com", "dbname": "some_db", "user": "some_user"}, "pass_B")
+ // localhost also matches the default "" and UNIX sockets
+ assertPassword(values{"host": "", "user": "some_user"}, "pass_C")
+ assertPassword(values{"host": "/tmp", "user": "some_user"}, "pass_C")
+ // cleanup
+ os.Remove(pgpass_file)
+ os.Setenv("PGPASSFILE", "")
+}
+
+func TestExec(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ _, err := db.Exec("CREATE TEMP TABLE temp (a int)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ r, err := db.Exec("INSERT INTO temp VALUES (1)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if n, _ := r.RowsAffected(); n != 1 {
+ t.Fatalf("expected 1 row affected, not %d", n)
+ }
+
+ r, err = db.Exec("INSERT INTO temp VALUES ($1), ($2), ($3)", 1, 2, 3)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if n, _ := r.RowsAffected(); n != 3 {
+ t.Fatalf("expected 3 rows affected, not %d", n)
+ }
+
+ // SELECT doesn't send the number of returned rows in the command tag
+ // before 9.0
+ if getServerVersion(t, db) >= 90000 {
+ r, err = db.Exec("SELECT g FROM generate_series(1, 2) g")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n, _ := r.RowsAffected(); n != 2 {
+ t.Fatalf("expected 2 rows affected, not %d", n)
+ }
+
+ r, err = db.Exec("SELECT g FROM generate_series(1, $1) g", 3)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n, _ := r.RowsAffected(); n != 3 {
+ t.Fatalf("expected 3 rows affected, not %d", n)
+ }
+ }
+}
+
+func TestStatment(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ st, err := db.Prepare("SELECT 1")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ st1, err := db.Prepare("SELECT 2")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ r, err := st.Query()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+
+ if !r.Next() {
+ t.Fatal("expected row")
+ }
+
+ var i int
+ err = r.Scan(&i)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if i != 1 {
+ t.Fatalf("expected 1, got %d", i)
+ }
+
+ // st1
+
+ r1, err := st1.Query()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r1.Close()
+
+ if !r1.Next() {
+ if r.Err() != nil {
+ t.Fatal(r1.Err())
+ }
+ t.Fatal("expected row")
+ }
+
+ err = r1.Scan(&i)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if i != 2 {
+ t.Fatalf("expected 2, got %d", i)
+ }
+}
+
+func TestRowsCloseBeforeDone(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ r, err := db.Query("SELECT 1")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = r.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if r.Next() {
+ t.Fatal("unexpected row")
+ }
+
+ if r.Err() != nil {
+ t.Fatal(r.Err())
+ }
+}
+
+func TestParameterCountMismatch(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ var notused int
+ err := db.QueryRow("SELECT false", 1).Scan(&notused)
+ if err == nil {
+ t.Fatal("expected err")
+ }
+ // make sure we clean up correctly
+ err = db.QueryRow("SELECT 1").Scan(&notused)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = db.QueryRow("SELECT $1").Scan(&notused)
+ if err == nil {
+ t.Fatal("expected err")
+ }
+ // make sure we clean up correctly
+ err = db.QueryRow("SELECT 1").Scan(&notused)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Test that EmptyQueryResponses are handled correctly.
+func TestEmptyQuery(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ _, err := db.Exec("")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err := db.Query("")
+ if err != nil {
+ t.Fatal(err)
+ }
+ cols, err := rows.Columns()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(cols) != 0 {
+ t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
+ }
+ if rows.Next() {
+ t.Fatal("unexpected row")
+ }
+ if rows.Err() != nil {
+ t.Fatal(rows.Err())
+ }
+
+ stmt, err := db.Prepare("")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = stmt.Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err = stmt.Query()
+ if err != nil {
+ t.Fatal(err)
+ }
+ cols, err = rows.Columns()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(cols) != 0 {
+ t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
+ }
+ if rows.Next() {
+ t.Fatal("unexpected row")
+ }
+ if rows.Err() != nil {
+ t.Fatal(rows.Err())
+ }
+}
+
+// Test that rows.Columns() is correct even if there are no result rows.
+func TestEmptyResultSetColumns(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ rows, err := db.Query("SELECT 1 AS a, text 'bar' AS bar WHERE FALSE")
+ if err != nil {
+ t.Fatal(err)
+ }
+ cols, err := rows.Columns()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(cols) != 2 {
+ t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
+ }
+ if rows.Next() {
+ t.Fatal("unexpected row")
+ }
+ if rows.Err() != nil {
+ t.Fatal(rows.Err())
+ }
+ if cols[0] != "a" || cols[1] != "bar" {
+ t.Fatalf("unexpected Columns result %v", cols)
+ }
+
+ stmt, err := db.Prepare("SELECT $1::int AS a, text 'bar' AS bar WHERE FALSE")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err = stmt.Query(1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cols, err = rows.Columns()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(cols) != 2 {
+ t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols))
+ }
+ if rows.Next() {
+ t.Fatal("unexpected row")
+ }
+ if rows.Err() != nil {
+ t.Fatal(rows.Err())
+ }
+ if cols[0] != "a" || cols[1] != "bar" {
+ t.Fatalf("unexpected Columns result %v", cols)
+ }
+
+}
+
+func TestEncodeDecode(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ q := `
+ SELECT
+ E'\\000\\001\\002'::bytea,
+ 'foobar'::text,
+ NULL::integer,
+ '2000-1-1 01:02:03.04-7'::timestamptz,
+ 0::boolean,
+ 123,
+ -321,
+ 3.14::float8
+ WHERE
+ E'\\000\\001\\002'::bytea = $1
+ AND 'foobar'::text = $2
+ AND $3::integer is NULL
+ `
+ // AND '2000-1-1 12:00:00.000000-7'::timestamp = $3
+
+ exp1 := []byte{0, 1, 2}
+ exp2 := "foobar"
+
+ r, err := db.Query(q, exp1, exp2, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+
+ if !r.Next() {
+ if r.Err() != nil {
+ t.Fatal(r.Err())
+ }
+ t.Fatal("expected row")
+ }
+
+ var got1 []byte
+ var got2 string
+ var got3 = sql.NullInt64{Valid: true}
+ var got4 time.Time
+ var got5, got6, got7, got8 interface{}
+
+ err = r.Scan(&got1, &got2, &got3, &got4, &got5, &got6, &got7, &got8)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(exp1, got1) {
+ t.Errorf("expected %q byte: %q", exp1, got1)
+ }
+
+ if !reflect.DeepEqual(exp2, got2) {
+ t.Errorf("expected %q byte: %q", exp2, got2)
+ }
+
+ if got3.Valid {
+ t.Fatal("expected invalid")
+ }
+
+ if got4.Year() != 2000 {
+ t.Fatal("wrong year")
+ }
+
+ if got5 != false {
+ t.Fatalf("expected false, got %q", got5)
+ }
+
+ if got6 != int64(123) {
+ t.Fatalf("expected 123, got %d", got6)
+ }
+
+ if got7 != int64(-321) {
+ t.Fatalf("expected -321, got %d", got7)
+ }
+
+ if got8 != float64(3.14) {
+ t.Fatalf("expected 3.14, got %f", got8)
+ }
+}
+
+func TestNoData(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ st, err := db.Prepare("SELECT 1 WHERE true = false")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer st.Close()
+
+ r, err := st.Query()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+
+ if r.Next() {
+ if r.Err() != nil {
+ t.Fatal(r.Err())
+ }
+ t.Fatal("unexpected row")
+ }
+
+ _, err = db.Query("SELECT * FROM nonexistenttable WHERE age=$1", 20)
+ if err == nil {
+ t.Fatal("Should have raised an error on non existent table")
+ }
+
+ _, err = db.Query("SELECT * FROM nonexistenttable")
+ if err == nil {
+ t.Fatal("Should have raised an error on non existent table")
+ }
+}
+
+func TestErrorDuringStartup(t *testing.T) {
+ // Don't use the normal connection setup, this is intended to
+ // blow up in the startup packet from a non-existent user.
+ db, err := openTestConnConninfo("user=thisuserreallydoesntexist")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db.Close()
+
+ _, err = db.Begin()
+ if err == nil {
+ t.Fatal("expected error")
+ }
+
+ e, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("expected Error, got %#v", err)
+ } else if e.Code.Name() != "invalid_authorization_specification" && e.Code.Name() != "invalid_password" {
+ t.Fatalf("expected invalid_authorization_specification or invalid_password, got %s (%+v)", e.Code.Name(), err)
+ }
+}
+
+func TestBadConn(t *testing.T) {
+ var err error
+
+ cn := conn{}
+ func() {
+ defer cn.errRecover(&err)
+ panic(io.EOF)
+ }()
+ if err != driver.ErrBadConn {
+ t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
+ }
+ if !cn.bad {
+ t.Fatalf("expected cn.bad")
+ }
+
+ cn = conn{}
+ func() {
+ defer cn.errRecover(&err)
+ e := &Error{Severity: Efatal}
+ panic(e)
+ }()
+ if err != driver.ErrBadConn {
+ t.Fatalf("expected driver.ErrBadConn, got: %#v", err)
+ }
+ if !cn.bad {
+ t.Fatalf("expected cn.bad")
+ }
+}
+
+func TestErrorOnExec(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = txn.Exec("INSERT INTO foo VALUES (0), (0)")
+ if err == nil {
+ t.Fatal("Should have raised error")
+ }
+
+ e, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("expected Error, got %#v", err)
+ } else if e.Code.Name() != "unique_violation" {
+ t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
+ }
+}
+
+func TestErrorOnQuery(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = txn.Query("INSERT INTO foo VALUES (0), (0)")
+ if err == nil {
+ t.Fatal("Should have raised error")
+ }
+
+ e, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("expected Error, got %#v", err)
+ } else if e.Code.Name() != "unique_violation" {
+ t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
+ }
+}
+
+func TestErrorOnQueryRowSimpleQuery(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var v int
+ err = txn.QueryRow("INSERT INTO foo VALUES (0), (0)").Scan(&v)
+ if err == nil {
+ t.Fatal("Should have raised error")
+ }
+
+ e, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("expected Error, got %#v", err)
+ } else if e.Code.Name() != "unique_violation" {
+ t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err)
+ }
+}
+
+// Test the QueryRow bug workarounds in stmt.exec() and simpleQuery()
+func TestQueryRowBugWorkaround(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ // stmt.exec()
+ _, err := db.Exec("CREATE TEMP TABLE notnulltemp (a varchar(10) not null)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var a string
+ err = db.QueryRow("INSERT INTO notnulltemp(a) values($1) RETURNING a", nil).Scan(&a)
+ if err == sql.ErrNoRows {
+ t.Fatalf("expected constraint violation error; got: %v", err)
+ }
+ pge, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("expected *Error; got: %#v", err)
+ }
+ if pge.Code.Name() != "not_null_violation" {
+ t.Fatalf("expected not_null_violation; got: %s (%+v)", pge.Code.Name(), err)
+ }
+
+ // Test workaround in simpleQuery()
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatalf("unexpected error %s in Begin", err)
+ }
+ defer tx.Rollback()
+
+ _, err = tx.Exec("SET LOCAL check_function_bodies TO FALSE")
+ if err != nil {
+ t.Fatalf("could not disable check_function_bodies: %s", err)
+ }
+ _, err = tx.Exec(`
+CREATE OR REPLACE FUNCTION bad_function()
+RETURNS integer
+-- hack to prevent the function from being inlined
+SET check_function_bodies TO TRUE
+AS $$
+ SELECT text 'bad'
+$$ LANGUAGE sql`)
+ if err != nil {
+ t.Fatalf("could not create function: %s", err)
+ }
+
+ err = tx.QueryRow("SELECT * FROM bad_function()").Scan(&a)
+ if err == nil {
+ t.Fatalf("expected error")
+ }
+ pge, ok = err.(*Error)
+ if !ok {
+ t.Fatalf("expected *Error; got: %#v", err)
+ }
+ if pge.Code.Name() != "invalid_function_definition" {
+ t.Fatalf("expected invalid_function_definition; got: %s (%+v)", pge.Code.Name(), err)
+ }
+
+ err = tx.Rollback()
+ if err != nil {
+ t.Fatalf("unexpected error %s in Rollback", err)
+ }
+
+ // Also test that simpleQuery()'s workaround works when the query fails
+ // after a row has been received.
+ rows, err := db.Query(`
+select
+ (select generate_series(1, ss.i))
+from (select gs.i
+ from generate_series(1, 2) gs(i)
+ order by gs.i limit 2) ss`)
+ if err != nil {
+ t.Fatalf("query failed: %s", err)
+ }
+ if !rows.Next() {
+ t.Fatalf("expected at least one result row; got %s", rows.Err())
+ }
+ var i int
+ err = rows.Scan(&i)
+ if err != nil {
+ t.Fatalf("rows.Scan() failed: %s", err)
+ }
+ if i != 1 {
+ t.Fatalf("unexpected value for i: %d", i)
+ }
+ if rows.Next() {
+ t.Fatalf("unexpected row")
+ }
+ pge, ok = rows.Err().(*Error)
+ if !ok {
+ t.Fatalf("expected *Error; got: %#v", err)
+ }
+ if pge.Code.Name() != "cardinality_violation" {
+ t.Fatalf("expected cardinality_violation; got: %s (%+v)", pge.Code.Name(), rows.Err())
+ }
+}
+
+func TestSimpleQuery(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ r, err := db.Query("select 1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+
+ if !r.Next() {
+ t.Fatal("expected row")
+ }
+}
+
+func TestBindError(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ _, err := db.Exec("create temp table test (i integer)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Query("select * from test where i=$1", "hhh")
+ if err == nil {
+ t.Fatal("expected an error")
+ }
+
+ // Should not get error here
+ r, err := db.Query("select * from test where i=$1", 1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+}
+
+func TestParseErrorInExtendedQuery(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ rows, err := db.Query("PARSE_ERROR $1", 1)
+ if err == nil {
+ t.Fatal("expected error")
+ }
+
+ rows, err = db.Query("SELECT 1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows.Close()
+}
+
+// TestReturning tests that an INSERT query using the RETURNING clause returns a row.
+func TestReturning(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ _, err := db.Exec("CREATE TEMP TABLE distributors (did integer default 0, dname text)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rows, err := db.Query("INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets') " +
+ "RETURNING did;")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !rows.Next() {
+ t.Fatal("no rows")
+ }
+ var did int
+ err = rows.Scan(&did)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if did != 0 {
+ t.Fatalf("bad value for did: got %d, want %d", did, 0)
+ }
+
+ if rows.Next() {
+ t.Fatal("unexpected next row")
+ }
+ err = rows.Err()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestIssue186(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ // Exec() a query which returns results
+ _, err := db.Exec("VALUES (1), (2), (3)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("VALUES ($1), ($2), ($3)", 1, 2, 3)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Query() a query which doesn't return any results
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ rows, err := txn.Query("CREATE TEMP TABLE foo(f1 int)")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err = rows.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ // small trick to get NoData from a parameterized query
+ _, err = txn.Exec("CREATE RULE nodata AS ON INSERT TO foo DO INSTEAD NOTHING")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err = txn.Query("INSERT INTO foo VALUES ($1)", 1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err = rows.Close(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestIssue196(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ row := db.QueryRow("SELECT float4 '0.10000122' = $1, float8 '35.03554004971999' = $2",
+ float32(0.10000122), float64(35.03554004971999))
+
+ var float4match, float8match bool
+ err := row.Scan(&float4match, &float8match)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !float4match {
+ t.Errorf("Expected float4 fidelity to be maintained; got no match")
+ }
+ if !float8match {
+ t.Errorf("Expected float8 fidelity to be maintained; got no match")
+ }
+}
+
+// Test that any CommandComplete messages sent before the query results are
+// ignored.
+func TestIssue282(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ var search_path string
+ err := db.QueryRow(`
+ SET LOCAL search_path TO pg_catalog;
+ SET LOCAL search_path TO pg_catalog;
+ SHOW search_path`).Scan(&search_path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if search_path != "pg_catalog" {
+ t.Fatalf("unexpected search_path %s", search_path)
+ }
+}
+
+func TestReadFloatPrecision(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ row := db.QueryRow("SELECT float4 '0.10000122', float8 '35.03554004971999'")
+ var float4val float32
+ var float8val float64
+ err := row.Scan(&float4val, &float8val)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if float4val != float32(0.10000122) {
+ t.Errorf("Expected float4 fidelity to be maintained; got no match")
+ }
+ if float8val != float64(35.03554004971999) {
+ t.Errorf("Expected float8 fidelity to be maintained; got no match")
+ }
+}
+
+func TestXactMultiStmt(t *testing.T) {
+ // minified test case based on bug reports from
+ // pico303@gmail.com and rangelspam@gmail.com
+ t.Skip("Skipping failing test")
+ db := openTestConn(t)
+ defer db.Close()
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer tx.Commit()
+
+ rows, err := tx.Query("select 1")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if rows.Next() {
+ var val int32
+ if err = rows.Scan(&val); err != nil {
+ t.Fatal(err)
+ }
+ } else {
+ t.Fatal("Expected at least one row in first query in xact")
+ }
+
+ rows2, err := tx.Query("select 2")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if rows2.Next() {
+ var val2 int32
+ if err := rows2.Scan(&val2); err != nil {
+ t.Fatal(err)
+ }
+ } else {
+ t.Fatal("Expected at least one row in second query in xact")
+ }
+
+ if err = rows.Err(); err != nil {
+ t.Fatal(err)
+ }
+
+ if err = rows2.Err(); err != nil {
+ t.Fatal(err)
+ }
+
+ if err = tx.Commit(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+var envParseTests = []struct {
+ Expected map[string]string
+ Env []string
+}{
+ {
+ Env: []string{"PGDATABASE=hello", "PGUSER=goodbye"},
+ Expected: map[string]string{"dbname": "hello", "user": "goodbye"},
+ },
+ {
+ Env: []string{"PGDATESTYLE=ISO, MDY"},
+ Expected: map[string]string{"datestyle": "ISO, MDY"},
+ },
+ {
+ Env: []string{"PGCONNECT_TIMEOUT=30"},
+ Expected: map[string]string{"connect_timeout": "30"},
+ },
+}
+
+func TestParseEnviron(t *testing.T) {
+ for i, tt := range envParseTests {
+ results := parseEnviron(tt.Env)
+ if !reflect.DeepEqual(tt.Expected, results) {
+ t.Errorf("%d: Expected: %#v Got: %#v", i, tt.Expected, results)
+ }
+ }
+}
+
+func TestParseComplete(t *testing.T) {
+ tpc := func(commandTag string, command string, affectedRows int64, shouldFail bool) {
+ defer func() {
+ if p := recover(); p != nil {
+ if !shouldFail {
+ t.Error(p)
+ }
+ }
+ }()
+ cn := &conn{}
+ res, c := cn.parseComplete(commandTag)
+ if c != command {
+ t.Errorf("Expected %v, got %v", command, c)
+ }
+ n, err := res.RowsAffected()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != affectedRows {
+ t.Errorf("Expected %d, got %d", affectedRows, n)
+ }
+ }
+
+ tpc("ALTER TABLE", "ALTER TABLE", 0, false)
+ tpc("INSERT 0 1", "INSERT", 1, false)
+ tpc("UPDATE 100", "UPDATE", 100, false)
+ tpc("SELECT 100", "SELECT", 100, false)
+ tpc("FETCH 100", "FETCH", 100, false)
+ // allow COPY (and others) without row count
+ tpc("COPY", "COPY", 0, false)
+ // don't fail on command tags we don't recognize
+ tpc("UNKNOWNCOMMANDTAG", "UNKNOWNCOMMANDTAG", 0, false)
+
+ // failure cases
+ tpc("INSERT 1", "", 0, true) // missing oid
+ tpc("UPDATE 0 1", "", 0, true) // too many numbers
+ tpc("SELECT foo", "", 0, true) // invalid row count
+}
+
+func TestExecerInterface(t *testing.T) {
+ // Gin up a straw man private struct just for the type check
+ cn := &conn{c: nil}
+ var cni interface{} = cn
+
+ _, ok := cni.(driver.Execer)
+ if !ok {
+ t.Fatal("Driver doesn't implement Execer")
+ }
+}
+
+func TestNullAfterNonNull(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ r, err := db.Query("SELECT 9::integer UNION SELECT NULL::integer")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var n sql.NullInt64
+
+ if !r.Next() {
+ if r.Err() != nil {
+ t.Fatal(err)
+ }
+ t.Fatal("expected row")
+ }
+
+ if err := r.Scan(&n); err != nil {
+ t.Fatal(err)
+ }
+
+ if n.Int64 != 9 {
+ t.Fatalf("expected 2, not %d", n.Int64)
+ }
+
+ if !r.Next() {
+ if r.Err() != nil {
+ t.Fatal(err)
+ }
+ t.Fatal("expected row")
+ }
+
+ if err := r.Scan(&n); err != nil {
+ t.Fatal(err)
+ }
+
+ if n.Valid {
+ t.Fatal("expected n to be invalid")
+ }
+
+ if n.Int64 != 0 {
+ t.Fatalf("expected n to 2, not %d", n.Int64)
+ }
+}
+
+func Test64BitErrorChecking(t *testing.T) {
+ defer func() {
+ if err := recover(); err != nil {
+ t.Fatal("panic due to 0xFFFFFFFF != -1 " +
+ "when int is 64 bits")
+ }
+ }()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ r, err := db.Query(`SELECT *
+FROM (VALUES (0::integer, NULL::text), (1, 'test string')) AS t;`)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ defer r.Close()
+
+ for r.Next() {
+ }
+}
+
+func TestCommit(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ _, err := db.Exec("CREATE TEMP TABLE temp (a int)")
+ if err != nil {
+ t.Fatal(err)
+ }
+ sqlInsert := "INSERT INTO temp VALUES (1)"
+ sqlSelect := "SELECT * FROM temp"
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = tx.Exec(sqlInsert)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = tx.Commit()
+ if err != nil {
+ t.Fatal(err)
+ }
+ var i int
+ err = db.QueryRow(sqlSelect).Scan(&i)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if i != 1 {
+ t.Fatalf("expected 1, got %d", i)
+ }
+}
+
+func TestErrorClass(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ _, err := db.Query("SELECT int 'notint'")
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ pge, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("expected *pq.Error, got %#+v", err)
+ }
+ if pge.Code.Class() != "22" {
+ t.Fatalf("expected class 28, got %v", pge.Code.Class())
+ }
+ if pge.Code.Class().Name() != "data_exception" {
+ t.Fatalf("expected data_exception, got %v", pge.Code.Class().Name())
+ }
+}
+
+func TestParseOpts(t *testing.T) {
+ tests := []struct {
+ in string
+ expected values
+ valid bool
+ }{
+ {"dbname=hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
+ {"dbname=hello user=goodbye ", values{"dbname": "hello", "user": "goodbye"}, true},
+ {"dbname = hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
+ {"dbname=hello user =goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
+ {"dbname=hello user= goodbye", values{"dbname": "hello", "user": "goodbye"}, true},
+ {"host=localhost password='correct horse battery staple'", values{"host": "localhost", "password": "correct horse battery staple"}, true},
+ {"dbname=データベース password=パスワード", values{"dbname": "データベース", "password": "パスワード"}, true},
+ {"dbname=hello user=''", values{"dbname": "hello", "user": ""}, true},
+ {"user='' dbname=hello", values{"dbname": "hello", "user": ""}, true},
+ // The last option value is an empty string if there's no non-whitespace after its =
+ {"dbname=hello user= ", values{"dbname": "hello", "user": ""}, true},
+
+ // The parser ignores spaces after = and interprets the next set of non-whitespace characters as the value.
+ {"user= password=foo", values{"user": "password=foo"}, true},
+
+ // Backslash escapes next char
+ {`user=a\ \'\\b`, values{"user": `a '\b`}, true},
+ {`user='a \'b'`, values{"user": `a 'b`}, true},
+
+ // Incomplete escape
+ {`user=x\`, values{}, false},
+
+ // No '=' after the key
+ {"postgre://marko@internet", values{}, false},
+ {"dbname user=goodbye", values{}, false},
+ {"user=foo blah", values{}, false},
+ {"user=foo blah ", values{}, false},
+
+ // Unterminated quoted value
+ {"dbname=hello user='unterminated", values{}, false},
+ }
+
+ for _, test := range tests {
+ o := make(values)
+ err := parseOpts(test.in, o)
+
+ switch {
+ case err != nil && test.valid:
+ t.Errorf("%q got unexpected error: %s", test.in, err)
+ case err == nil && test.valid && !reflect.DeepEqual(test.expected, o):
+ t.Errorf("%q got: %#v want: %#v", test.in, o, test.expected)
+ case err == nil && !test.valid:
+ t.Errorf("%q expected an error", test.in)
+ }
+ }
+}
+
+func TestRuntimeParameters(t *testing.T) {
+ type RuntimeTestResult int
+ const (
+ ResultUnknown RuntimeTestResult = iota
+ ResultSuccess
+ ResultError // other error
+ )
+
+ tests := []struct {
+ conninfo string
+ param string
+ expected string
+ expectedOutcome RuntimeTestResult
+ }{
+ // invalid parameter
+ {"DOESNOTEXIST=foo", "", "", ResultError},
+ // we can only work with a specific value for these two
+ {"client_encoding=SQL_ASCII", "", "", ResultError},
+ {"datestyle='ISO, YDM'", "", "", ResultError},
+ // "options" should work exactly as it does in libpq
+ {"options='-c search_path=pqgotest'", "search_path", "pqgotest", ResultSuccess},
+ // pq should override client_encoding in this case
+ {"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", ResultSuccess},
+ // allow client_encoding to be set explicitly
+ {"client_encoding=UTF8", "client_encoding", "UTF8", ResultSuccess},
+ // test a runtime parameter not supported by libpq
+ {"work_mem='139kB'", "work_mem", "139kB", ResultSuccess},
+ // test fallback_application_name
+ {"application_name=foo fallback_application_name=bar", "application_name", "foo", ResultSuccess},
+ {"application_name='' fallback_application_name=bar", "application_name", "", ResultSuccess},
+ {"fallback_application_name=bar", "application_name", "bar", ResultSuccess},
+ }
+
+ for _, test := range tests {
+ db, err := openTestConnConninfo(test.conninfo)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // application_name didn't exist before 9.0
+ if test.param == "application_name" && getServerVersion(t, db) < 90000 {
+ db.Close()
+ continue
+ }
+
+ tryGetParameterValue := func() (value string, outcome RuntimeTestResult) {
+ defer db.Close()
+ row := db.QueryRow("SELECT current_setting($1)", test.param)
+ err = row.Scan(&value)
+ if err != nil {
+ return "", ResultError
+ }
+ return value, ResultSuccess
+ }
+
+ value, outcome := tryGetParameterValue()
+ if outcome != test.expectedOutcome && outcome == ResultError {
+ t.Fatalf("%v: unexpected error: %v", test.conninfo, err)
+ }
+ if outcome != test.expectedOutcome {
+ t.Fatalf("unexpected outcome %v (was expecting %v) for conninfo \"%s\"",
+ outcome, test.expectedOutcome, test.conninfo)
+ }
+ if value != test.expected {
+ t.Fatalf("bad value for %s: got %s, want %s with conninfo \"%s\"",
+ test.param, value, test.expected, test.conninfo)
+ }
+ }
+}
+
+func TestIsUTF8(t *testing.T) {
+ var cases = []struct {
+ name string
+ want bool
+ }{
+ {"unicode", true},
+ {"utf-8", true},
+ {"utf_8", true},
+ {"UTF-8", true},
+ {"UTF8", true},
+ {"utf8", true},
+ {"u n ic_ode", true},
+ {"ut_f%8", true},
+ {"ubf8", false},
+ {"punycode", false},
+ }
+
+ for _, test := range cases {
+ if g := isUTF8(test.name); g != test.want {
+ t.Errorf("isUTF8(%q) = %v want %v", test.name, g, test.want)
+ }
+ }
+}
+
+func TestQuoteIdentifier(t *testing.T) {
+ var cases = []struct {
+ input string
+ want string
+ }{
+ {`foo`, `"foo"`},
+ {`foo bar baz`, `"foo bar baz"`},
+ {`foo"bar`, `"foo""bar"`},
+ {"foo\x00bar", `"foo"`},
+ {"\x00foo", `""`},
+ }
+
+ for _, test := range cases {
+ got := QuoteIdentifier(test.input)
+ if got != test.want {
+ t.Errorf("QuoteIdentifier(%q) = %v want %v", test.input, got, test.want)
+ }
+ }
+}
diff --git a/vendor/github.com/lib/pq/copy_test.go b/vendor/github.com/lib/pq/copy_test.go
new file mode 100644
index 000000000..86745b38f
--- /dev/null
+++ b/vendor/github.com/lib/pq/copy_test.go
@@ -0,0 +1,465 @@
+package pq
+
+import (
+ "bytes"
+ "database/sql"
+ "database/sql/driver"
+ "strings"
+ "testing"
+)
+
+func TestCopyInStmt(t *testing.T) {
+ var stmt string
+ stmt = CopyIn("table name")
+ if stmt != `COPY "table name" () FROM STDIN` {
+ t.Fatal(stmt)
+ }
+
+ stmt = CopyIn("table name", "column 1", "column 2")
+ if stmt != `COPY "table name" ("column 1", "column 2") FROM STDIN` {
+ t.Fatal(stmt)
+ }
+
+ stmt = CopyIn(`table " name """`, `co"lumn""`)
+ if stmt != `COPY "table "" name """"""" ("co""lumn""""") FROM STDIN` {
+ t.Fatal(stmt)
+ }
+}
+
+func TestCopyInSchemaStmt(t *testing.T) {
+ var stmt string
+ stmt = CopyInSchema("schema name", "table name")
+ if stmt != `COPY "schema name"."table name" () FROM STDIN` {
+ t.Fatal(stmt)
+ }
+
+ stmt = CopyInSchema("schema name", "table name", "column 1", "column 2")
+ if stmt != `COPY "schema name"."table name" ("column 1", "column 2") FROM STDIN` {
+ t.Fatal(stmt)
+ }
+
+ stmt = CopyInSchema(`schema " name """`, `table " name """`, `co"lumn""`)
+ if stmt != `COPY "schema "" name """"""".`+
+ `"table "" name """"""" ("co""lumn""""") FROM STDIN` {
+ t.Fatal(stmt)
+ }
+}
+
+func TestCopyInMultipleValues(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ stmt, err := txn.Prepare(CopyIn("temp", "a", "b"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ longString := strings.Repeat("#", 500)
+
+ for i := 0; i < 500; i++ {
+ _, err = stmt.Exec(int64(i), longString)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ _, err = stmt.Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = stmt.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var num int
+ err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if num != 500 {
+ t.Fatalf("expected 500 items, not %d", num)
+ }
+}
+
+func TestCopyInRaiseStmtTrigger(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ if getServerVersion(t, db) < 90000 {
+ var exists int
+ err := db.QueryRow("SELECT 1 FROM pg_language WHERE lanname = 'plpgsql'").Scan(&exists)
+ if err == sql.ErrNoRows {
+ t.Skip("language PL/PgSQL does not exist; skipping TestCopyInRaiseStmtTrigger")
+ } else if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = txn.Exec(`
+ CREATE OR REPLACE FUNCTION pg_temp.temptest()
+ RETURNS trigger AS
+ $BODY$ begin
+ raise notice 'Hello world';
+ return new;
+ end $BODY$
+ LANGUAGE plpgsql`)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = txn.Exec(`
+ CREATE TRIGGER temptest_trigger
+ BEFORE INSERT
+ ON temp
+ FOR EACH ROW
+ EXECUTE PROCEDURE pg_temp.temptest()`)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ stmt, err := txn.Prepare(CopyIn("temp", "a", "b"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ longString := strings.Repeat("#", 500)
+
+ _, err = stmt.Exec(int64(1), longString)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = stmt.Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = stmt.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var num int
+ err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if num != 1 {
+ t.Fatalf("expected 1 items, not %d", num)
+ }
+}
+
+func TestCopyInTypes(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER, text VARCHAR, blob BYTEA, nothing VARCHAR)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ stmt, err := txn.Prepare(CopyIn("temp", "num", "text", "blob", "nothing"))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = stmt.Exec(int64(1234567890), "Héllö\n ☃!\r\t\\", []byte{0, 255, 9, 10, 13}, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = stmt.Exec()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = stmt.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var num int
+ var text string
+ var blob []byte
+ var nothing sql.NullString
+
+ err = txn.QueryRow("SELECT * FROM temp").Scan(&num, &text, &blob, &nothing)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if num != 1234567890 {
+ t.Fatal("unexpected result", num)
+ }
+ if text != "Héllö\n ☃!\r\t\\" {
+ t.Fatal("unexpected result", text)
+ }
+ if bytes.Compare(blob, []byte{0, 255, 9, 10, 13}) != 0 {
+ t.Fatal("unexpected result", blob)
+ }
+ if nothing.Valid {
+ t.Fatal("unexpected result", nothing.String)
+ }
+}
+
+func TestCopyInWrongType(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ stmt, err := txn.Prepare(CopyIn("temp", "num"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer stmt.Close()
+
+ _, err = stmt.Exec("Héllö\n ☃!\r\t\\")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = stmt.Exec()
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if pge := err.(*Error); pge.Code.Name() != "invalid_text_representation" {
+ t.Fatalf("expected 'invalid input syntax for integer' error, got %s (%+v)", pge.Code.Name(), pge)
+ }
+}
+
+func TestCopyOutsideOfTxnError(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ _, err := db.Prepare(CopyIn("temp", "num"))
+ if err == nil {
+ t.Fatal("COPY outside of transaction did not return an error")
+ }
+ if err != errCopyNotSupportedOutsideTxn {
+ t.Fatalf("expected %s, got %s", err, err.Error())
+ }
+}
+
+func TestCopyInBinaryError(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = txn.Prepare("COPY temp (num) FROM STDIN WITH binary")
+ if err != errBinaryCopyNotSupported {
+ t.Fatalf("expected %s, got %+v", errBinaryCopyNotSupported, err)
+ }
+ // check that the protocol is in a valid state
+ err = txn.Rollback()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestCopyFromError(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = txn.Prepare("COPY temp (num) TO STDOUT")
+ if err != errCopyToNotSupported {
+ t.Fatalf("expected %s, got %+v", errCopyToNotSupported, err)
+ }
+ // check that the protocol is in a valid state
+ err = txn.Rollback()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestCopySyntaxError(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Prepare("COPY ")
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if pge := err.(*Error); pge.Code.Name() != "syntax_error" {
+ t.Fatalf("expected syntax error, got %s (%+v)", pge.Code.Name(), pge)
+ }
+ // check that the protocol is in a valid state
+ err = txn.Rollback()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Tests for connection errors in copyin.resploop()
+func TestCopyRespLoopConnectionError(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ var pid int
+ err = txn.QueryRow("SELECT pg_backend_pid()").Scan(&pid)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (a int)")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ stmt, err := txn.Prepare(CopyIn("temp", "a"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer stmt.Close()
+
+ _, err = db.Exec("SELECT pg_terminate_backend($1)", pid)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if getServerVersion(t, db) < 90500 {
+ // We have to try and send something over, since postgres before
+ // version 9.5 won't process SIGTERMs while it's waiting for
+ // CopyData/CopyEnd messages; see tcop/postgres.c.
+ _, err = stmt.Exec(1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ _, err = stmt.Exec()
+ if err == nil {
+ t.Fatalf("expected error")
+ }
+ pge, ok := err.(*Error)
+ if !ok {
+ if err == driver.ErrBadConn {
+ // likely an EPIPE
+ } else {
+ t.Fatalf("expected *pq.Error or driver.ErrBadConn, got %+#v", err)
+ }
+ } else if pge.Code.Name() != "admin_shutdown" {
+ t.Fatalf("expected admin_shutdown, got %s", pge.Code.Name())
+ }
+
+ _ = stmt.Close()
+}
+
+func BenchmarkCopyIn(b *testing.B) {
+ db := openTestConn(b)
+ defer db.Close()
+
+ txn, err := db.Begin()
+ if err != nil {
+ b.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)")
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ stmt, err := txn.Prepare(CopyIn("temp", "a", "b"))
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ for i := 0; i < b.N; i++ {
+ _, err = stmt.Exec(int64(i), "hello world!")
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+
+ _, err = stmt.Exec()
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ err = stmt.Close()
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ var num int
+ err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ if num != b.N {
+ b.Fatalf("expected %d items, not %d", b.N, num)
+ }
+}
diff --git a/vendor/github.com/lib/pq/encode.go b/vendor/github.com/lib/pq/encode.go
index e52d39b26..6681bd3e7 100644
--- a/vendor/github.com/lib/pq/encode.go
+++ b/vendor/github.com/lib/pq/encode.go
@@ -23,7 +23,6 @@ func binaryEncode(parameterStatus *parameterStatus, x interface{}) []byte {
default:
return encode(parameterStatus, x, oid.T_unknown)
}
- panic("not reached")
}
func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte {
@@ -76,7 +75,7 @@ func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) inter
return int64(int16(binary.BigEndian.Uint16(s)))
default:
- errorf("don't know how to decode binary parameter of type %u", uint32(typ))
+ errorf("don't know how to decode binary parameter of type %d", uint32(typ))
}
panic("not reached")
diff --git a/vendor/github.com/lib/pq/encode_test.go b/vendor/github.com/lib/pq/encode_test.go
new file mode 100644
index 000000000..984abbc94
--- /dev/null
+++ b/vendor/github.com/lib/pq/encode_test.go
@@ -0,0 +1,727 @@
+package pq
+
+import (
+ "bytes"
+ "database/sql"
+ "fmt"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/lib/pq/oid"
+)
+
+func TestScanTimestamp(t *testing.T) {
+ var nt NullTime
+ tn := time.Now()
+ nt.Scan(tn)
+ if !nt.Valid {
+ t.Errorf("Expected Valid=false")
+ }
+ if nt.Time != tn {
+ t.Errorf("Time value mismatch")
+ }
+}
+
+func TestScanNilTimestamp(t *testing.T) {
+ var nt NullTime
+ nt.Scan(nil)
+ if nt.Valid {
+ t.Errorf("Expected Valid=false")
+ }
+}
+
+var timeTests = []struct {
+ str string
+ timeval time.Time
+}{
+ {"22001-02-03", time.Date(22001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
+ {"2001-02-03", time.Date(2001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06", time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.000001", time.Date(2001, time.February, 3, 4, 5, 6, 1000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.00001", time.Date(2001, time.February, 3, 4, 5, 6, 10000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.0001", time.Date(2001, time.February, 3, 4, 5, 6, 100000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.001", time.Date(2001, time.February, 3, 4, 5, 6, 1000000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.01", time.Date(2001, time.February, 3, 4, 5, 6, 10000000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.1", time.Date(2001, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.12", time.Date(2001, time.February, 3, 4, 5, 6, 120000000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.123", time.Date(2001, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.1234", time.Date(2001, time.February, 3, 4, 5, 6, 123400000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.12345", time.Date(2001, time.February, 3, 4, 5, 6, 123450000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.123456", time.Date(2001, time.February, 3, 4, 5, 6, 123456000, time.FixedZone("", 0))},
+ {"2001-02-03 04:05:06.123-07", time.Date(2001, time.February, 3, 4, 5, 6, 123000000,
+ time.FixedZone("", -7*60*60))},
+ {"2001-02-03 04:05:06-07", time.Date(2001, time.February, 3, 4, 5, 6, 0,
+ time.FixedZone("", -7*60*60))},
+ {"2001-02-03 04:05:06-07:42", time.Date(2001, time.February, 3, 4, 5, 6, 0,
+ time.FixedZone("", -(7*60*60+42*60)))},
+ {"2001-02-03 04:05:06-07:30:09", time.Date(2001, time.February, 3, 4, 5, 6, 0,
+ time.FixedZone("", -(7*60*60+30*60+9)))},
+ {"2001-02-03 04:05:06+07", time.Date(2001, time.February, 3, 4, 5, 6, 0,
+ time.FixedZone("", 7*60*60))},
+ {"0011-02-03 04:05:06 BC", time.Date(-10, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))},
+ {"0011-02-03 04:05:06.123 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
+ {"0011-02-03 04:05:06.123-07 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000,
+ time.FixedZone("", -7*60*60))},
+ {"0001-02-03 04:05:06.123", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
+ {"0001-02-03 04:05:06.123 BC", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)},
+ {"0001-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
+ {"0002-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)},
+ {"0002-02-03 04:05:06.123 BC", time.Date(-1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))},
+ {"12345-02-03 04:05:06.1", time.Date(12345, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))},
+ {"123456-02-03 04:05:06.1", time.Date(123456, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))},
+}
+
+// Test that parsing the string results in the expected value.
+func TestParseTs(t *testing.T) {
+ for i, tt := range timeTests {
+ val, err := ParseTimestamp(nil, tt.str)
+ if err != nil {
+ t.Errorf("%d: got error: %v", i, err)
+ } else if val.String() != tt.timeval.String() {
+ t.Errorf("%d: expected to parse %q into %q; got %q",
+ i, tt.str, tt.timeval, val)
+ }
+ }
+}
+
+var timeErrorTests = []string{
+ "2001",
+ "2001-2-03",
+ "2001-02-3",
+ "2001-02-03 ",
+ "2001-02-03 04",
+ "2001-02-03 04:",
+ "2001-02-03 04:05",
+ "2001-02-03 04:05:",
+ "2001-02-03 04:05:6",
+ "2001-02-03 04:05:06.123 B",
+}
+
+// Test that parsing the string results in an error.
+func TestParseTsErrors(t *testing.T) {
+ for i, tt := range timeErrorTests {
+ _, err := ParseTimestamp(nil, tt)
+ if err == nil {
+ t.Errorf("%d: expected an error from parsing: %v", i, tt)
+ }
+ }
+}
+
+// Now test that sending the value into the database and parsing it back
+// returns the same time.Time value.
+func TestEncodeAndParseTs(t *testing.T) {
+ db, err := openTestConnConninfo("timezone='Etc/UTC'")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db.Close()
+
+ for i, tt := range timeTests {
+ var dbstr string
+ err = db.QueryRow("SELECT ($1::timestamptz)::text", tt.timeval).Scan(&dbstr)
+ if err != nil {
+ t.Errorf("%d: could not send value %q to the database: %s", i, tt.timeval, err)
+ continue
+ }
+
+ val, err := ParseTimestamp(nil, dbstr)
+ if err != nil {
+ t.Errorf("%d: could not parse value %q: %s", i, dbstr, err)
+ continue
+ }
+ val = val.In(tt.timeval.Location())
+ if val.String() != tt.timeval.String() {
+ t.Errorf("%d: expected to parse %q into %q; got %q", i, dbstr, tt.timeval, val)
+ }
+ }
+}
+
+var formatTimeTests = []struct {
+ time time.Time
+ expected string
+}{
+ {time.Time{}, "0001-01-01T00:00:00Z"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03T04:05:06.123456789Z"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03T04:05:06.123456789+02:00"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03T04:05:06.123456789-06:00"},
+ {time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03T04:05:06-07:30:09"},
+
+ {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z"},
+ {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00"},
+ {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00"},
+
+ {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03T04:05:06.123456789Z BC"},
+ {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03T04:05:06.123456789+02:00 BC"},
+ {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03T04:05:06.123456789-06:00 BC"},
+
+ {time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09"},
+ {time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03T04:05:06-07:30:09 BC"},
+}
+
+func TestFormatTs(t *testing.T) {
+ for i, tt := range formatTimeTests {
+ val := string(formatTs(tt.time))
+ if val != tt.expected {
+ t.Errorf("%d: incorrect time format %q, want %q", i, val, tt.expected)
+ }
+ }
+}
+
+func TestTimestampWithTimeZone(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer tx.Rollback()
+
+ // try several different locations, all included in Go's zoneinfo.zip
+ for _, locName := range []string{
+ "UTC",
+ "America/Chicago",
+ "America/New_York",
+ "Australia/Darwin",
+ "Australia/Perth",
+ } {
+ loc, err := time.LoadLocation(locName)
+ if err != nil {
+ t.Logf("Could not load time zone %s - skipping", locName)
+ continue
+ }
+
+ // Postgres timestamps have a resolution of 1 microsecond, so don't
+ // use the full range of the Nanosecond argument
+ refTime := time.Date(2012, 11, 6, 10, 23, 42, 123456000, loc)
+
+ for _, pgTimeZone := range []string{"US/Eastern", "Australia/Darwin"} {
+ // Switch Postgres's timezone to test different output timestamp formats
+ _, err = tx.Exec(fmt.Sprintf("set time zone '%s'", pgTimeZone))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var gotTime time.Time
+ row := tx.QueryRow("select $1::timestamp with time zone", refTime)
+ err = row.Scan(&gotTime)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !refTime.Equal(gotTime) {
+ t.Errorf("timestamps not equal: %s != %s", refTime, gotTime)
+ }
+
+ // check that the time zone is set correctly based on TimeZone
+ pgLoc, err := time.LoadLocation(pgTimeZone)
+ if err != nil {
+ t.Logf("Could not load time zone %s - skipping", pgLoc)
+ continue
+ }
+ translated := refTime.In(pgLoc)
+ if translated.String() != gotTime.String() {
+ t.Errorf("timestamps not equal: %s != %s", translated, gotTime)
+ }
+ }
+ }
+}
+
+func TestTimestampWithOutTimezone(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ test := func(ts, pgts string) {
+ r, err := db.Query("SELECT $1::timestamp", pgts)
+ if err != nil {
+ t.Fatalf("Could not run query: %v", err)
+ }
+
+ n := r.Next()
+
+ if n != true {
+ t.Fatal("Expected at least one row")
+ }
+
+ var result time.Time
+ err = r.Scan(&result)
+ if err != nil {
+ t.Fatalf("Did not expect error scanning row: %v", err)
+ }
+
+ expected, err := time.Parse(time.RFC3339, ts)
+ if err != nil {
+ t.Fatalf("Could not parse test time literal: %v", err)
+ }
+
+ if !result.Equal(expected) {
+ t.Fatalf("Expected time to match %v: got mismatch %v",
+ expected, result)
+ }
+
+ n = r.Next()
+ if n != false {
+ t.Fatal("Expected only one row")
+ }
+ }
+
+ test("2000-01-01T00:00:00Z", "2000-01-01T00:00:00")
+
+ // Test higher precision time
+ test("2013-01-04T20:14:58.80033Z", "2013-01-04 20:14:58.80033")
+}
+
+func TestInfinityTimestamp(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+ var err error
+ var resultT time.Time
+
+ expectedErrorStrPrefix := `sql: Scan error on column index 0: unsupported`
+ type testCases []struct {
+ Query string
+ Param string
+ ExpectedErrStrPrefix string
+ ExpectedVal interface{}
+ }
+ tc := testCases{
+ {"SELECT $1::timestamp", "-infinity", expectedErrorStrPrefix, "-infinity"},
+ {"SELECT $1::timestamptz", "-infinity", expectedErrorStrPrefix, "-infinity"},
+ {"SELECT $1::timestamp", "infinity", expectedErrorStrPrefix, "infinity"},
+ {"SELECT $1::timestamptz", "infinity", expectedErrorStrPrefix, "infinity"},
+ }
+ // try to assert []byte to time.Time
+ for _, q := range tc {
+ err = db.QueryRow(q.Query, q.Param).Scan(&resultT)
+ if !strings.HasPrefix(err.Error(), q.ExpectedErrStrPrefix) {
+ t.Errorf("Scanning -/+infinity, expected error to have prefix %q, got %q", q.ExpectedErrStrPrefix, err)
+ }
+ }
+ // yield []byte
+ for _, q := range tc {
+ var resultI interface{}
+ err = db.QueryRow(q.Query, q.Param).Scan(&resultI)
+ if err != nil {
+ t.Errorf("Scanning -/+infinity, expected no error, got %q", err)
+ }
+ result, ok := resultI.([]byte)
+ if !ok {
+ t.Errorf("Scanning -/+infinity, expected []byte, got %#v", resultI)
+ }
+ if string(result) != q.ExpectedVal {
+ t.Errorf("Scanning -/+infinity, expected %q, got %q", q.ExpectedVal, result)
+ }
+ }
+
+ y1500 := time.Date(1500, time.January, 1, 0, 0, 0, 0, time.UTC)
+ y2500 := time.Date(2500, time.January, 1, 0, 0, 0, 0, time.UTC)
+ EnableInfinityTs(y1500, y2500)
+
+ err = db.QueryRow("SELECT $1::timestamp", "infinity").Scan(&resultT)
+ if err != nil {
+ t.Errorf("Scanning infinity, expected no error, got %q", err)
+ }
+ if !resultT.Equal(y2500) {
+ t.Errorf("Scanning infinity, expected %q, got %q", y2500, resultT)
+ }
+
+ err = db.QueryRow("SELECT $1::timestamptz", "infinity").Scan(&resultT)
+ if err != nil {
+ t.Errorf("Scanning infinity, expected no error, got %q", err)
+ }
+ if !resultT.Equal(y2500) {
+ t.Errorf("Scanning Infinity, expected time %q, got %q", y2500, resultT.String())
+ }
+
+ err = db.QueryRow("SELECT $1::timestamp", "-infinity").Scan(&resultT)
+ if err != nil {
+ t.Errorf("Scanning -infinity, expected no error, got %q", err)
+ }
+ if !resultT.Equal(y1500) {
+ t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String())
+ }
+
+ err = db.QueryRow("SELECT $1::timestamptz", "-infinity").Scan(&resultT)
+ if err != nil {
+ t.Errorf("Scanning -infinity, expected no error, got %q", err)
+ }
+ if !resultT.Equal(y1500) {
+ t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String())
+ }
+
+ y_1500 := time.Date(-1500, time.January, 1, 0, 0, 0, 0, time.UTC)
+ y11500 := time.Date(11500, time.January, 1, 0, 0, 0, 0, time.UTC)
+ var s string
+ err = db.QueryRow("SELECT $1::timestamp::text", y_1500).Scan(&s)
+ if err != nil {
+ t.Errorf("Encoding -infinity, expected no error, got %q", err)
+ }
+ if s != "-infinity" {
+ t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s)
+ }
+ err = db.QueryRow("SELECT $1::timestamptz::text", y_1500).Scan(&s)
+ if err != nil {
+ t.Errorf("Encoding -infinity, expected no error, got %q", err)
+ }
+ if s != "-infinity" {
+ t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s)
+ }
+
+ err = db.QueryRow("SELECT $1::timestamp::text", y11500).Scan(&s)
+ if err != nil {
+ t.Errorf("Encoding infinity, expected no error, got %q", err)
+ }
+ if s != "infinity" {
+ t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s)
+ }
+ err = db.QueryRow("SELECT $1::timestamptz::text", y11500).Scan(&s)
+ if err != nil {
+ t.Errorf("Encoding infinity, expected no error, got %q", err)
+ }
+ if s != "infinity" {
+ t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s)
+ }
+
+ disableInfinityTs()
+
+ var panicErrorString string
+ func() {
+ defer func() {
+ panicErrorString, _ = recover().(string)
+ }()
+ EnableInfinityTs(y2500, y1500)
+ }()
+ if panicErrorString != infinityTsNegativeMustBeSmaller {
+ t.Errorf("Expected error, %q, got %q", infinityTsNegativeMustBeSmaller, panicErrorString)
+ }
+}
+
+func TestStringWithNul(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ hello0world := string("hello\x00world")
+ _, err := db.Query("SELECT $1::text", &hello0world)
+ if err == nil {
+ t.Fatal("Postgres accepts a string with nul in it; " +
+ "injection attacks may be plausible")
+ }
+}
+
+func TestByteSliceToText(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ b := []byte("hello world")
+ row := db.QueryRow("SELECT $1::text", b)
+
+ var result []byte
+ err := row.Scan(&result)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if string(result) != string(b) {
+ t.Fatalf("expected %v but got %v", b, result)
+ }
+}
+
+func TestStringToBytea(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ b := "hello world"
+ row := db.QueryRow("SELECT $1::bytea", b)
+
+ var result []byte
+ err := row.Scan(&result)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(result, []byte(b)) {
+ t.Fatalf("expected %v but got %v", b, result)
+ }
+}
+
+func TestTextByteSliceToUUID(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ b := []byte("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
+ row := db.QueryRow("SELECT $1::uuid", b)
+
+ var result string
+ err := row.Scan(&result)
+ if forceBinaryParameters() {
+ pqErr := err.(*Error)
+ if pqErr == nil {
+ t.Errorf("Expected to get error")
+ } else if pqErr.Code != "22P03" {
+ t.Fatalf("Expected to get invalid binary encoding error (22P03), got %s", pqErr.Code)
+ }
+ } else {
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if result != string(b) {
+ t.Fatalf("expected %v but got %v", b, result)
+ }
+ }
+}
+
+func TestBinaryByteSlicetoUUID(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ b := []byte{'\xa0', '\xee', '\xbc', '\x99',
+ '\x9c', '\x0b',
+ '\x4e', '\xf8',
+ '\xbb', '\x00', '\x6b',
+ '\xb9', '\xbd', '\x38', '\x0a', '\x11'}
+ row := db.QueryRow("SELECT $1::uuid", b)
+
+ var result string
+ err := row.Scan(&result)
+ if forceBinaryParameters() {
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if result != string("a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11") {
+ t.Fatalf("expected %v but got %v", b, result)
+ }
+ } else {
+ pqErr := err.(*Error)
+ if pqErr == nil {
+ t.Errorf("Expected to get error")
+ } else if pqErr.Code != "22021" {
+ t.Fatalf("Expected to get invalid byte sequence for encoding error (22021), got %s", pqErr.Code)
+ }
+ }
+}
+
+func TestStringToUUID(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ s := "a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11"
+ row := db.QueryRow("SELECT $1::uuid", s)
+
+ var result string
+ err := row.Scan(&result)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if result != s {
+ t.Fatalf("expected %v but got %v", s, result)
+ }
+}
+
+func TestTextByteSliceToInt(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ expected := 12345678
+ b := []byte(fmt.Sprintf("%d", expected))
+ row := db.QueryRow("SELECT $1::int", b)
+
+ var result int
+ err := row.Scan(&result)
+ if forceBinaryParameters() {
+ pqErr := err.(*Error)
+ if pqErr == nil {
+ t.Errorf("Expected to get error")
+ } else if pqErr.Code != "22P03" {
+ t.Fatalf("Expected to get invalid binary encoding error (22P03), got %s", pqErr.Code)
+ }
+ } else {
+ if err != nil {
+ t.Fatal(err)
+ }
+ if result != expected {
+ t.Fatalf("expected %v but got %v", expected, result)
+ }
+ }
+}
+
+func TestBinaryByteSliceToInt(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ expected := 12345678
+ b := []byte{'\x00', '\xbc', '\x61', '\x4e'}
+ row := db.QueryRow("SELECT $1::int", b)
+
+ var result int
+ err := row.Scan(&result)
+ if forceBinaryParameters() {
+ if err != nil {
+ t.Fatal(err)
+ }
+ if result != expected {
+ t.Fatalf("expected %v but got %v", expected, result)
+ }
+ } else {
+ pqErr := err.(*Error)
+ if pqErr == nil {
+ t.Errorf("Expected to get error")
+ } else if pqErr.Code != "22021" {
+ t.Fatalf("Expected to get invalid byte sequence for encoding error (22021), got %s", pqErr.Code)
+ }
+ }
+}
+
+func TestByteaOutputFormatEncoding(t *testing.T) {
+ input := []byte("\\x\x00\x01\x02\xFF\xFEabcdefg0123")
+ want := []byte("\\x5c78000102fffe6162636465666730313233")
+ got := encode(&parameterStatus{serverVersion: 90000}, input, oid.T_bytea)
+ if !bytes.Equal(want, got) {
+ t.Errorf("invalid hex bytea output, got %v but expected %v", got, want)
+ }
+
+ want = []byte("\\\\x\\000\\001\\002\\377\\376abcdefg0123")
+ got = encode(&parameterStatus{serverVersion: 84000}, input, oid.T_bytea)
+ if !bytes.Equal(want, got) {
+ t.Errorf("invalid escape bytea output, got %v but expected %v", got, want)
+ }
+}
+
+func TestByteaOutputFormats(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ if getServerVersion(t, db) < 90000 {
+ // skip
+ return
+ }
+
+ testByteaOutputFormat := func(f string, usePrepared bool) {
+ expectedData := []byte("\x5c\x78\x00\xff\x61\x62\x63\x01\x08")
+ sqlQuery := "SELECT decode('5c7800ff6162630108', 'hex')"
+
+ var data []byte
+
+ // use a txn to avoid relying on getting the same connection
+ txn, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer txn.Rollback()
+
+ _, err = txn.Exec("SET LOCAL bytea_output TO " + f)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var rows *sql.Rows
+ var stmt *sql.Stmt
+ if usePrepared {
+ stmt, err = txn.Prepare(sqlQuery)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err = stmt.Query()
+ } else {
+ // use Query; QueryRow would hide the actual error
+ rows, err = txn.Query(sqlQuery)
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !rows.Next() {
+ if rows.Err() != nil {
+ t.Fatal(rows.Err())
+ }
+ t.Fatal("shouldn't happen")
+ }
+ err = rows.Scan(&data)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = rows.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if stmt != nil {
+ err = stmt.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ if !bytes.Equal(data, expectedData) {
+ t.Errorf("unexpected bytea value %v for format %s; expected %v", data, f, expectedData)
+ }
+ }
+
+ testByteaOutputFormat("hex", false)
+ testByteaOutputFormat("escape", false)
+ testByteaOutputFormat("hex", true)
+ testByteaOutputFormat("escape", true)
+}
+
+func TestAppendEncodedText(t *testing.T) {
+ var buf []byte
+
+ buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, int64(10))
+ buf = append(buf, '\t')
+ buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, 42.0000000001)
+ buf = append(buf, '\t')
+ buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, "hello\tworld")
+ buf = append(buf, '\t')
+ buf = appendEncodedText(&parameterStatus{serverVersion: 90000}, buf, []byte{0, 128, 255})
+
+ if string(buf) != "10\t42.0000000001\thello\\tworld\t\\\\x0080ff" {
+ t.Fatal(string(buf))
+ }
+}
+
+func TestAppendEscapedText(t *testing.T) {
+ if esc := appendEscapedText(nil, "hallo\tescape"); string(esc) != "hallo\\tescape" {
+ t.Fatal(string(esc))
+ }
+ if esc := appendEscapedText(nil, "hallo\\tescape\n"); string(esc) != "hallo\\\\tescape\\n" {
+ t.Fatal(string(esc))
+ }
+ if esc := appendEscapedText(nil, "\n\r\t\f"); string(esc) != "\\n\\r\\t\f" {
+ t.Fatal(string(esc))
+ }
+}
+
+func TestAppendEscapedTextExistingBuffer(t *testing.T) {
+ var buf []byte
+ buf = []byte("123\t")
+ if esc := appendEscapedText(buf, "hallo\tescape"); string(esc) != "123\thallo\\tescape" {
+ t.Fatal(string(esc))
+ }
+ buf = []byte("123\t")
+ if esc := appendEscapedText(buf, "hallo\\tescape\n"); string(esc) != "123\thallo\\\\tescape\\n" {
+ t.Fatal(string(esc))
+ }
+ buf = []byte("123\t")
+ if esc := appendEscapedText(buf, "\n\r\t\f"); string(esc) != "123\t\\n\\r\\t\f" {
+ t.Fatal(string(esc))
+ }
+}
+
+func BenchmarkAppendEscapedText(b *testing.B) {
+ longString := ""
+ for i := 0; i < 100; i++ {
+ longString += "123456789\n"
+ }
+ for i := 0; i < b.N; i++ {
+ appendEscapedText(nil, longString)
+ }
+}
+
+func BenchmarkAppendEscapedTextNoEscape(b *testing.B) {
+ longString := ""
+ for i := 0; i < 100; i++ {
+ longString += "1234567890"
+ }
+ for i := 0; i < b.N; i++ {
+ appendEscapedText(nil, longString)
+ }
+}
diff --git a/vendor/github.com/lib/pq/hstore/hstore.go b/vendor/github.com/lib/pq/hstore/hstore.go
new file mode 100644
index 000000000..72d5abf51
--- /dev/null
+++ b/vendor/github.com/lib/pq/hstore/hstore.go
@@ -0,0 +1,118 @@
+package hstore
+
+import (
+ "database/sql"
+ "database/sql/driver"
+ "strings"
+)
+
+// A wrapper for transferring Hstore values back and forth easily.
+type Hstore struct {
+ Map map[string]sql.NullString
+}
+
+// escapes and quotes hstore keys/values
+// s should be a sql.NullString or string
+func hQuote(s interface{}) string {
+ var str string
+ switch v := s.(type) {
+ case sql.NullString:
+ if !v.Valid {
+ return "NULL"
+ }
+ str = v.String
+ case string:
+ str = v
+ default:
+ panic("not a string or sql.NullString")
+ }
+
+ str = strings.Replace(str, "\\", "\\\\", -1)
+ return `"` + strings.Replace(str, "\"", "\\\"", -1) + `"`
+}
+
+// Scan implements the Scanner interface.
+//
+// Note h.Map is reallocated before the scan to clear existing values. If the
+// hstore column's database value is NULL, then h.Map is set to nil instead.
+func (h *Hstore) Scan(value interface{}) error {
+ if value == nil {
+ h.Map = nil
+ return nil
+ }
+ h.Map = make(map[string]sql.NullString)
+ var b byte
+ pair := [][]byte{{}, {}}
+ pi := 0
+ inQuote := false
+ didQuote := false
+ sawSlash := false
+ bindex := 0
+ for bindex, b = range value.([]byte) {
+ if sawSlash {
+ pair[pi] = append(pair[pi], b)
+ sawSlash = false
+ continue
+ }
+
+ switch b {
+ case '\\':
+ sawSlash = true
+ continue
+ case '"':
+ inQuote = !inQuote
+ if !didQuote {
+ didQuote = true
+ }
+ continue
+ default:
+ if !inQuote {
+ switch b {
+ case ' ', '\t', '\n', '\r':
+ continue
+ case '=':
+ continue
+ case '>':
+ pi = 1
+ didQuote = false
+ continue
+ case ',':
+ s := string(pair[1])
+ if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" {
+ h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false}
+ } else {
+ h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true}
+ }
+ pair[0] = []byte{}
+ pair[1] = []byte{}
+ pi = 0
+ continue
+ }
+ }
+ }
+ pair[pi] = append(pair[pi], b)
+ }
+ if bindex > 0 {
+ s := string(pair[1])
+ if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" {
+ h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false}
+ } else {
+ h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true}
+ }
+ }
+ return nil
+}
+
+// Value implements the driver Valuer interface. Note if h.Map is nil, the
+// database column value will be set to NULL.
+func (h Hstore) Value() (driver.Value, error) {
+ if h.Map == nil {
+ return nil, nil
+ }
+ parts := []string{}
+ for key, val := range h.Map {
+ thispart := hQuote(key) + "=>" + hQuote(val)
+ parts = append(parts, thispart)
+ }
+ return []byte(strings.Join(parts, ",")), nil
+}
diff --git a/vendor/github.com/lib/pq/hstore/hstore_test.go b/vendor/github.com/lib/pq/hstore/hstore_test.go
new file mode 100644
index 000000000..1c9f2bd49
--- /dev/null
+++ b/vendor/github.com/lib/pq/hstore/hstore_test.go
@@ -0,0 +1,148 @@
+package hstore
+
+import (
+ "database/sql"
+ "os"
+ "testing"
+
+ _ "github.com/lib/pq"
+)
+
+type Fatalistic interface {
+ Fatal(args ...interface{})
+}
+
+func openTestConn(t Fatalistic) *sql.DB {
+ datname := os.Getenv("PGDATABASE")
+ sslmode := os.Getenv("PGSSLMODE")
+
+ if datname == "" {
+ os.Setenv("PGDATABASE", "pqgotest")
+ }
+
+ if sslmode == "" {
+ os.Setenv("PGSSLMODE", "disable")
+ }
+
+ conn, err := sql.Open("postgres", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return conn
+}
+
+func TestHstore(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ // quitely create hstore if it doesn't exist
+ _, err := db.Exec("CREATE EXTENSION IF NOT EXISTS hstore")
+ if err != nil {
+ t.Skipf("Skipping hstore tests - hstore extension create failed: %s", err.Error())
+ }
+
+ hs := Hstore{}
+
+ // test for null-valued hstores
+ err = db.QueryRow("SELECT NULL::hstore").Scan(&hs)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if hs.Map != nil {
+ t.Fatalf("expected null map")
+ }
+
+ err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs)
+ if err != nil {
+ t.Fatalf("re-query null map failed: %s", err.Error())
+ }
+ if hs.Map != nil {
+ t.Fatalf("expected null map")
+ }
+
+ // test for empty hstores
+ err = db.QueryRow("SELECT ''::hstore").Scan(&hs)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if hs.Map == nil {
+ t.Fatalf("expected empty map, got null map")
+ }
+ if len(hs.Map) != 0 {
+ t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map))
+ }
+
+ err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs)
+ if err != nil {
+ t.Fatalf("re-query empty map failed: %s", err.Error())
+ }
+ if hs.Map == nil {
+ t.Fatalf("expected empty map, got null map")
+ }
+ if len(hs.Map) != 0 {
+ t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map))
+ }
+
+ // a few example maps to test out
+ hsOnePair := Hstore{
+ Map: map[string]sql.NullString{
+ "key1": {String: "value1", Valid: true},
+ },
+ }
+
+ hsThreePairs := Hstore{
+ Map: map[string]sql.NullString{
+ "key1": {String: "value1", Valid: true},
+ "key2": {String: "value2", Valid: true},
+ "key3": {String: "value3", Valid: true},
+ },
+ }
+
+ hsSmorgasbord := Hstore{
+ Map: map[string]sql.NullString{
+ "nullstring": {String: "NULL", Valid: true},
+ "actuallynull": {String: "", Valid: false},
+ "NULL": {String: "NULL string key", Valid: true},
+ "withbracket": {String: "value>42", Valid: true},
+ "withequal": {String: "value=42", Valid: true},
+ `"withquotes1"`: {String: `this "should" be fine`, Valid: true},
+ `"withquotes"2"`: {String: `this "should\" also be fine`, Valid: true},
+ "embedded1": {String: "value1=>x1", Valid: true},
+ "embedded2": {String: `"value2"=>x2`, Valid: true},
+ "withnewlines": {String: "\n\nvalue\t=>2", Valid: true},
+ "<<all sorts of crazy>>": {String: `this, "should,\" also, => be fine`, Valid: true},
+ },
+ }
+
+ // test encoding in query params, then decoding during Scan
+ testBidirectional := func(h Hstore) {
+ err = db.QueryRow("SELECT $1::hstore", h).Scan(&hs)
+ if err != nil {
+ t.Fatalf("re-query %d-pair map failed: %s", len(h.Map), err.Error())
+ }
+ if hs.Map == nil {
+ t.Fatalf("expected %d-pair map, got null map", len(h.Map))
+ }
+ if len(hs.Map) != len(h.Map) {
+ t.Fatalf("expected %d-pair map, got len(map)=%d", len(h.Map), len(hs.Map))
+ }
+
+ for key, val := range hs.Map {
+ otherval, found := h.Map[key]
+ if !found {
+ t.Fatalf(" key '%v' not found in %d-pair map", key, len(h.Map))
+ }
+ if otherval.Valid != val.Valid {
+ t.Fatalf(" value %v <> %v in %d-pair map", otherval, val, len(h.Map))
+ }
+ if otherval.String != val.String {
+ t.Fatalf(" value '%v' <> '%v' in %d-pair map", otherval.String, val.String, len(h.Map))
+ }
+ }
+ }
+
+ testBidirectional(hsOnePair)
+ testBidirectional(hsThreePairs)
+ testBidirectional(hsSmorgasbord)
+}
diff --git a/vendor/github.com/lib/pq/listen_example/doc.go b/vendor/github.com/lib/pq/listen_example/doc.go
new file mode 100644
index 000000000..5bc99f5c1
--- /dev/null
+++ b/vendor/github.com/lib/pq/listen_example/doc.go
@@ -0,0 +1,102 @@
+/*
+
+Below you will find a self-contained Go program which uses the LISTEN / NOTIFY
+mechanism to avoid polling the database while waiting for more work to arrive.
+
+ //
+ // You can see the program in action by defining a function similar to
+ // the following:
+ //
+ // CREATE OR REPLACE FUNCTION public.get_work()
+ // RETURNS bigint
+ // LANGUAGE sql
+ // AS $$
+ // SELECT CASE WHEN random() >= 0.2 THEN int8 '1' END
+ // $$
+ // ;
+
+ package main
+
+ import (
+ "database/sql"
+ "fmt"
+ "time"
+
+ "github.com/lib/pq"
+ )
+
+ func doWork(db *sql.DB, work int64) {
+ // work here
+ }
+
+ func getWork(db *sql.DB) {
+ for {
+ // get work from the database here
+ var work sql.NullInt64
+ err := db.QueryRow("SELECT get_work()").Scan(&work)
+ if err != nil {
+ fmt.Println("call to get_work() failed: ", err)
+ time.Sleep(10 * time.Second)
+ continue
+ }
+ if !work.Valid {
+ // no more work to do
+ fmt.Println("ran out of work")
+ return
+ }
+
+ fmt.Println("starting work on ", work.Int64)
+ go doWork(db, work.Int64)
+ }
+ }
+
+ func waitForNotification(l *pq.Listener) {
+ for {
+ select {
+ case <-l.Notify:
+ fmt.Println("received notification, new work available")
+ return
+ case <-time.After(90 * time.Second):
+ go func() {
+ l.Ping()
+ }()
+ // Check if there's more work available, just in case it takes
+ // a while for the Listener to notice connection loss and
+ // reconnect.
+ fmt.Println("received no work for 90 seconds, checking for new work")
+ return
+ }
+ }
+ }
+
+ func main() {
+ var conninfo string = ""
+
+ db, err := sql.Open("postgres", conninfo)
+ if err != nil {
+ panic(err)
+ }
+
+ reportProblem := func(ev pq.ListenerEventType, err error) {
+ if err != nil {
+ fmt.Println(err.Error())
+ }
+ }
+
+ listener := pq.NewListener(conninfo, 10 * time.Second, time.Minute, reportProblem)
+ err = listener.Listen("getwork")
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Println("entering main loop")
+ for {
+ // process all available work before waiting for notifications
+ getWork(db)
+ waitForNotification(listener)
+ }
+ }
+
+
+*/
+package listen_example
diff --git a/vendor/github.com/lib/pq/notify.go b/vendor/github.com/lib/pq/notify.go
index 8cad57815..09f94244b 100644
--- a/vendor/github.com/lib/pq/notify.go
+++ b/vendor/github.com/lib/pq/notify.go
@@ -62,14 +62,18 @@ type ListenerConn struct {
// Creates a new ListenerConn. Use NewListener instead.
func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) {
- cn, err := Open(name)
+ return newDialListenerConn(defaultDialer{}, name, notificationChan)
+}
+
+func newDialListenerConn(d Dialer, name string, c chan<- *Notification) (*ListenerConn, error) {
+ cn, err := DialOpen(d, name)
if err != nil {
return nil, err
}
l := &ListenerConn{
cn: cn.(*conn),
- notificationChan: notificationChan,
+ notificationChan: c,
connState: connStateIdle,
replyChan: make(chan message, 2),
}
@@ -391,6 +395,7 @@ type Listener struct {
name string
minReconnectInterval time.Duration
maxReconnectInterval time.Duration
+ dialer Dialer
eventCallback EventCallbackType
lock sync.Mutex
@@ -421,10 +426,21 @@ func NewListener(name string,
minReconnectInterval time.Duration,
maxReconnectInterval time.Duration,
eventCallback EventCallbackType) *Listener {
+ return NewDialListener(defaultDialer{}, name, minReconnectInterval, maxReconnectInterval, eventCallback)
+}
+
+// NewDialListener is like NewListener but it takes a Dialer.
+func NewDialListener(d Dialer,
+ name string,
+ minReconnectInterval time.Duration,
+ maxReconnectInterval time.Duration,
+ eventCallback EventCallbackType) *Listener {
+
l := &Listener{
name: name,
minReconnectInterval: minReconnectInterval,
maxReconnectInterval: maxReconnectInterval,
+ dialer: d,
eventCallback: eventCallback,
channels: make(map[string]struct{}),
@@ -660,7 +676,7 @@ func (l *Listener) closed() bool {
func (l *Listener) connect() error {
notificationChan := make(chan *Notification, 32)
- cn, err := NewListenerConn(l.name, notificationChan)
+ cn, err := newDialListenerConn(l.dialer, l.name, notificationChan)
if err != nil {
return err
}
diff --git a/vendor/github.com/lib/pq/notify_test.go b/vendor/github.com/lib/pq/notify_test.go
new file mode 100644
index 000000000..fe8941a4e
--- /dev/null
+++ b/vendor/github.com/lib/pq/notify_test.go
@@ -0,0 +1,574 @@
+package pq
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+var errNilNotification = errors.New("nil notification")
+
+func expectNotification(t *testing.T, ch <-chan *Notification, relname string, extra string) error {
+ select {
+ case n := <-ch:
+ if n == nil {
+ return errNilNotification
+ }
+ if n.Channel != relname || n.Extra != extra {
+ return fmt.Errorf("unexpected notification %v", n)
+ }
+ return nil
+ case <-time.After(1500 * time.Millisecond):
+ return fmt.Errorf("timeout")
+ }
+}
+
+func expectNoNotification(t *testing.T, ch <-chan *Notification) error {
+ select {
+ case n := <-ch:
+ return fmt.Errorf("unexpected notification %v", n)
+ case <-time.After(100 * time.Millisecond):
+ return nil
+ }
+}
+
+func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEventType) error {
+ select {
+ case e := <-eventch:
+ if e != et {
+ return fmt.Errorf("unexpected event %v", e)
+ }
+ return nil
+ case <-time.After(1500 * time.Millisecond):
+ panic("expectEvent timeout")
+ }
+}
+
+func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error {
+ select {
+ case e := <-eventch:
+ return fmt.Errorf("unexpected event %v", e)
+ case <-time.After(100 * time.Millisecond):
+ return nil
+ }
+}
+
+func newTestListenerConn(t *testing.T) (*ListenerConn, <-chan *Notification) {
+ datname := os.Getenv("PGDATABASE")
+ sslmode := os.Getenv("PGSSLMODE")
+
+ if datname == "" {
+ os.Setenv("PGDATABASE", "pqgotest")
+ }
+
+ if sslmode == "" {
+ os.Setenv("PGSSLMODE", "disable")
+ }
+
+ notificationChan := make(chan *Notification)
+ l, err := NewListenerConn("", notificationChan)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return l, notificationChan
+}
+
+func TestNewListenerConn(t *testing.T) {
+ l, _ := newTestListenerConn(t)
+
+ defer l.Close()
+}
+
+func TestConnListen(t *testing.T) {
+ l, channel := newTestListenerConn(t)
+
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ ok, err := l.Listen("notify_test")
+ if !ok || err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, channel, "notify_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestConnUnlisten(t *testing.T) {
+ l, channel := newTestListenerConn(t)
+
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ ok, err := l.Listen("notify_test")
+ if !ok || err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_test")
+
+ err = expectNotification(t, channel, "notify_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ok, err = l.Unlisten("notify_test")
+ if !ok || err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNoNotification(t, channel)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestConnUnlistenAll(t *testing.T) {
+ l, channel := newTestListenerConn(t)
+
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ ok, err := l.Listen("notify_test")
+ if !ok || err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_test")
+
+ err = expectNotification(t, channel, "notify_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ok, err = l.UnlistenAll()
+ if !ok || err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNoNotification(t, channel)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestConnClose(t *testing.T) {
+ l, _ := newTestListenerConn(t)
+ defer l.Close()
+
+ err := l.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = l.Close()
+ if err != errListenerConnClosed {
+ t.Fatalf("expected errListenerConnClosed; got %v", err)
+ }
+}
+
+func TestConnPing(t *testing.T) {
+ l, _ := newTestListenerConn(t)
+ defer l.Close()
+ err := l.Ping()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = l.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = l.Ping()
+ if err != errListenerConnClosed {
+ t.Fatalf("expected errListenerConnClosed; got %v", err)
+ }
+}
+
+// Test for deadlock where a query fails while another one is queued
+func TestConnExecDeadlock(t *testing.T) {
+ l, _ := newTestListenerConn(t)
+ defer l.Close()
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+
+ go func() {
+ l.ExecSimpleQuery("SELECT pg_sleep(60)")
+ wg.Done()
+ }()
+ runtime.Gosched()
+ go func() {
+ l.ExecSimpleQuery("SELECT 1")
+ wg.Done()
+ }()
+ // give the two goroutines some time to get into position
+ runtime.Gosched()
+ // calls Close on the net.Conn; equivalent to a network failure
+ l.Close()
+
+ var done int32 = 0
+ go func() {
+ time.Sleep(10 * time.Second)
+ if atomic.LoadInt32(&done) != 1 {
+ panic("timed out")
+ }
+ }()
+ wg.Wait()
+ atomic.StoreInt32(&done, 1)
+}
+
+// Test for ListenerConn being closed while a slow query is executing
+func TestListenerConnCloseWhileQueryIsExecuting(t *testing.T) {
+ l, _ := newTestListenerConn(t)
+ defer l.Close()
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ go func() {
+ sent, err := l.ExecSimpleQuery("SELECT pg_sleep(60)")
+ if sent {
+ panic("expected sent=false")
+ }
+ // could be any of a number of errors
+ if err == nil {
+ panic("expected error")
+ }
+ wg.Done()
+ }()
+ // give the above goroutine some time to get into position
+ runtime.Gosched()
+ err := l.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ var done int32 = 0
+ go func() {
+ time.Sleep(10 * time.Second)
+ if atomic.LoadInt32(&done) != 1 {
+ panic("timed out")
+ }
+ }()
+ wg.Wait()
+ atomic.StoreInt32(&done, 1)
+}
+
+func TestNotifyExtra(t *testing.T) {
+ db := openTestConn(t)
+ defer db.Close()
+
+ if getServerVersion(t, db) < 90000 {
+ t.Skip("skipping NOTIFY payload test since the server does not appear to support it")
+ }
+
+ l, channel := newTestListenerConn(t)
+ defer l.Close()
+
+ ok, err := l.Listen("notify_test")
+ if !ok || err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_test, 'something'")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, channel, "notify_test", "something")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// create a new test listener and also set the timeouts
+func newTestListenerTimeout(t *testing.T, min time.Duration, max time.Duration) (*Listener, <-chan ListenerEventType) {
+ datname := os.Getenv("PGDATABASE")
+ sslmode := os.Getenv("PGSSLMODE")
+
+ if datname == "" {
+ os.Setenv("PGDATABASE", "pqgotest")
+ }
+
+ if sslmode == "" {
+ os.Setenv("PGSSLMODE", "disable")
+ }
+
+ eventch := make(chan ListenerEventType, 16)
+ l := NewListener("", min, max, func(t ListenerEventType, err error) { eventch <- t })
+ err := expectEvent(t, eventch, ListenerEventConnected)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return l, eventch
+}
+
+func newTestListener(t *testing.T) (*Listener, <-chan ListenerEventType) {
+ return newTestListenerTimeout(t, time.Hour, time.Hour)
+}
+
+func TestListenerListen(t *testing.T) {
+ l, _ := newTestListener(t)
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ err := l.Listen("notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, l.Notify, "notify_listen_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestListenerUnlisten(t *testing.T) {
+ l, _ := newTestListener(t)
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ err := l.Listen("notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = l.Unlisten("notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, l.Notify, "notify_listen_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNoNotification(t, l.Notify)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestListenerUnlistenAll(t *testing.T) {
+ l, _ := newTestListener(t)
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ err := l.Listen("notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = l.UnlistenAll()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, l.Notify, "notify_listen_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNoNotification(t, l.Notify)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestListenerFailedQuery(t *testing.T) {
+ l, eventch := newTestListener(t)
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ err := l.Listen("notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, l.Notify, "notify_listen_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // shouldn't cause a disconnect
+ ok, err := l.cn.ExecSimpleQuery("SELECT error")
+ if !ok {
+ t.Fatalf("could not send query to server: %v", err)
+ }
+ _, ok = err.(PGError)
+ if !ok {
+ t.Fatalf("unexpected error %v", err)
+ }
+ err = expectNoEvent(t, eventch)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // should still work
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, l.Notify, "notify_listen_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestListenerReconnect(t *testing.T) {
+ l, eventch := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour)
+ defer l.Close()
+
+ db := openTestConn(t)
+ defer db.Close()
+
+ err := l.Listen("notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, l.Notify, "notify_listen_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // kill the connection and make sure it comes back up
+ ok, err := l.cn.ExecSimpleQuery("SELECT pg_terminate_backend(pg_backend_pid())")
+ if ok {
+ t.Fatalf("could not kill the connection: %v", err)
+ }
+ if err != io.EOF {
+ t.Fatalf("unexpected error %v", err)
+ }
+ err = expectEvent(t, eventch, ListenerEventDisconnected)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = expectEvent(t, eventch, ListenerEventReconnected)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // should still work
+ _, err = db.Exec("NOTIFY notify_listen_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // should get nil after Reconnected
+ err = expectNotification(t, l.Notify, "", "")
+ if err != errNilNotification {
+ t.Fatal(err)
+ }
+
+ err = expectNotification(t, l.Notify, "notify_listen_test", "")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestListenerClose(t *testing.T) {
+ l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour)
+ defer l.Close()
+
+ err := l.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = l.Close()
+ if err != errListenerClosed {
+ t.Fatalf("expected errListenerClosed; got %v", err)
+ }
+}
+
+func TestListenerPing(t *testing.T) {
+ l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour)
+ defer l.Close()
+
+ err := l.Ping()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = l.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = l.Ping()
+ if err != errListenerClosed {
+ t.Fatalf("expected errListenerClosed; got %v", err)
+ }
+}
diff --git a/vendor/github.com/lib/pq/ssl_test.go b/vendor/github.com/lib/pq/ssl_test.go
new file mode 100644
index 000000000..932b336f5
--- /dev/null
+++ b/vendor/github.com/lib/pq/ssl_test.go
@@ -0,0 +1,226 @@
+package pq
+
+// This file contains SSL tests
+
+import (
+ _ "crypto/sha256"
+ "crypto/x509"
+ "database/sql"
+ "fmt"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func maybeSkipSSLTests(t *testing.T) {
+ // Require some special variables for testing certificates
+ if os.Getenv("PQSSLCERTTEST_PATH") == "" {
+ t.Skip("PQSSLCERTTEST_PATH not set, skipping SSL tests")
+ }
+
+ value := os.Getenv("PQGOSSLTESTS")
+ if value == "" || value == "0" {
+ t.Skip("PQGOSSLTESTS not enabled, skipping SSL tests")
+ } else if value != "1" {
+ t.Fatalf("unexpected value %q for PQGOSSLTESTS", value)
+ }
+}
+
+func openSSLConn(t *testing.T, conninfo string) (*sql.DB, error) {
+ db, err := openTestConnConninfo(conninfo)
+ if err != nil {
+ // should never fail
+ t.Fatal(err)
+ }
+ // Do something with the connection to see whether it's working or not.
+ tx, err := db.Begin()
+ if err == nil {
+ return db, tx.Rollback()
+ }
+ _ = db.Close()
+ return nil, err
+}
+
+func checkSSLSetup(t *testing.T, conninfo string) {
+ db, err := openSSLConn(t, conninfo)
+ if err == nil {
+ db.Close()
+ t.Fatalf("expected error with conninfo=%q", conninfo)
+ }
+}
+
+// Connect over SSL and run a simple query to test the basics
+func TestSSLConnection(t *testing.T) {
+ maybeSkipSSLTests(t)
+ // Environment sanity check: should fail without SSL
+ checkSSLSetup(t, "sslmode=disable user=pqgossltest")
+
+ db, err := openSSLConn(t, "sslmode=require user=pqgossltest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err := db.Query("SELECT 1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows.Close()
+}
+
+// Test sslmode=verify-full
+func TestSSLVerifyFull(t *testing.T) {
+ maybeSkipSSLTests(t)
+ // Environment sanity check: should fail without SSL
+ checkSSLSetup(t, "sslmode=disable user=pqgossltest")
+
+ // Not OK according to the system CA
+ _, err := openSSLConn(t, "host=postgres sslmode=verify-full user=pqgossltest")
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ _, ok := err.(x509.UnknownAuthorityError)
+ if !ok {
+ t.Fatalf("expected x509.UnknownAuthorityError, got %#+v", err)
+ }
+
+ rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt")
+ rootCert := "sslrootcert=" + rootCertPath + " "
+ // No match on Common Name
+ _, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-full user=pqgossltest")
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ _, ok = err.(x509.HostnameError)
+ if !ok {
+ t.Fatalf("expected x509.HostnameError, got %#+v", err)
+ }
+ // OK
+ _, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-full user=pqgossltest")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Test sslmode=verify-ca
+func TestSSLVerifyCA(t *testing.T) {
+ maybeSkipSSLTests(t)
+ // Environment sanity check: should fail without SSL
+ checkSSLSetup(t, "sslmode=disable user=pqgossltest")
+
+ // Not OK according to the system CA
+ _, err := openSSLConn(t, "host=postgres sslmode=verify-ca user=pqgossltest")
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ _, ok := err.(x509.UnknownAuthorityError)
+ if !ok {
+ t.Fatalf("expected x509.UnknownAuthorityError, got %#+v", err)
+ }
+
+ rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt")
+ rootCert := "sslrootcert=" + rootCertPath + " "
+ // No match on Common Name, but that's OK
+ _, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-ca user=pqgossltest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Everything OK
+ _, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-ca user=pqgossltest")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func getCertConninfo(t *testing.T, source string) string {
+ var sslkey string
+ var sslcert string
+
+ certpath := os.Getenv("PQSSLCERTTEST_PATH")
+
+ switch source {
+ case "missingkey":
+ sslkey = "/tmp/filedoesnotexist"
+ sslcert = filepath.Join(certpath, "postgresql.crt")
+ case "missingcert":
+ sslkey = filepath.Join(certpath, "postgresql.key")
+ sslcert = "/tmp/filedoesnotexist"
+ case "certtwice":
+ sslkey = filepath.Join(certpath, "postgresql.crt")
+ sslcert = filepath.Join(certpath, "postgresql.crt")
+ case "valid":
+ sslkey = filepath.Join(certpath, "postgresql.key")
+ sslcert = filepath.Join(certpath, "postgresql.crt")
+ default:
+ t.Fatalf("invalid source %q", source)
+ }
+ return fmt.Sprintf("sslmode=require user=pqgosslcert sslkey=%s sslcert=%s", sslkey, sslcert)
+}
+
+// Authenticate over SSL using client certificates
+func TestSSLClientCertificates(t *testing.T) {
+ maybeSkipSSLTests(t)
+ // Environment sanity check: should fail without SSL
+ checkSSLSetup(t, "sslmode=disable user=pqgossltest")
+
+ // Should also fail without a valid certificate
+ db, err := openSSLConn(t, "sslmode=require user=pqgosslcert")
+ if err == nil {
+ db.Close()
+ t.Fatal("expected error")
+ }
+ pge, ok := err.(*Error)
+ if !ok {
+ t.Fatal("expected pq.Error")
+ }
+ if pge.Code.Name() != "invalid_authorization_specification" {
+ t.Fatalf("unexpected error code %q", pge.Code.Name())
+ }
+
+ // Should work
+ db, err = openSSLConn(t, getCertConninfo(t, "valid"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows, err := db.Query("SELECT 1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ rows.Close()
+}
+
+// Test errors with ssl certificates
+func TestSSLClientCertificatesMissingFiles(t *testing.T) {
+ maybeSkipSSLTests(t)
+ // Environment sanity check: should fail without SSL
+ checkSSLSetup(t, "sslmode=disable user=pqgossltest")
+
+ // Key missing, should fail
+ _, err := openSSLConn(t, getCertConninfo(t, "missingkey"))
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ // should be a PathError
+ _, ok := err.(*os.PathError)
+ if !ok {
+ t.Fatalf("expected PathError, got %#+v", err)
+ }
+
+ // Cert missing, should fail
+ _, err = openSSLConn(t, getCertConninfo(t, "missingcert"))
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ // should be a PathError
+ _, ok = err.(*os.PathError)
+ if !ok {
+ t.Fatalf("expected PathError, got %#+v", err)
+ }
+
+ // Key has wrong permissions, should fail
+ _, err = openSSLConn(t, getCertConninfo(t, "certtwice"))
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if err != ErrSSLKeyHasWorldPermissions {
+ t.Fatalf("expected ErrSSLKeyHasWorldPermissions, got %#+v", err)
+ }
+}
diff --git a/vendor/github.com/lib/pq/url_test.go b/vendor/github.com/lib/pq/url_test.go
new file mode 100644
index 000000000..4ff0ce034
--- /dev/null
+++ b/vendor/github.com/lib/pq/url_test.go
@@ -0,0 +1,66 @@
+package pq
+
+import (
+ "testing"
+)
+
+func TestSimpleParseURL(t *testing.T) {
+ expected := "host=hostname.remote"
+ str, err := ParseURL("postgres://hostname.remote")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if str != expected {
+ t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected)
+ }
+}
+
+func TestIPv6LoopbackParseURL(t *testing.T) {
+ expected := "host=::1 port=1234"
+ str, err := ParseURL("postgres://[::1]:1234")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if str != expected {
+ t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected)
+ }
+}
+
+func TestFullParseURL(t *testing.T) {
+ expected := `dbname=database host=hostname.remote password=top\ secret port=1234 user=username`
+ str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if str != expected {
+ t.Fatalf("unexpected result from ParseURL:\n+ %s\n- %s", str, expected)
+ }
+}
+
+func TestInvalidProtocolParseURL(t *testing.T) {
+ _, err := ParseURL("http://hostname.remote")
+ switch err {
+ case nil:
+ t.Fatal("Expected an error from parsing invalid protocol")
+ default:
+ msg := "invalid connection protocol: http"
+ if err.Error() != msg {
+ t.Fatalf("Unexpected error message:\n+ %s\n- %s",
+ err.Error(), msg)
+ }
+ }
+}
+
+func TestMinimalURL(t *testing.T) {
+ cs, err := ParseURL("postgres://")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if cs != "" {
+ t.Fatalf("expected blank connection string, got: %q", cs)
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/.gitignore b/vendor/github.com/mattermost/rsc/.gitignore
new file mode 100644
index 000000000..00268614f
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/.gitignore
@@ -0,0 +1,22 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
diff --git a/vendor/github.com/mattermost/rsc/README.md b/vendor/github.com/mattermost/rsc/README.md
new file mode 100644
index 000000000..d110adfb2
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/README.md
@@ -0,0 +1,4 @@
+rsc
+===
+
+fork of Russ Cox's code.google.com/p/rsc \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/app/app.go b/vendor/github.com/mattermost/rsc/app/app.go
new file mode 100644
index 000000000..d6db65dd4
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/app/app.go
@@ -0,0 +1,39 @@
+package app
+
+import (
+ "fmt"
+ "net/http"
+
+ "appengine"
+ "appengine/memcache"
+
+ _ "github.com/mattermost/rsc/appfs/server"
+ _ "github.com/mattermost/rsc/blog/post"
+)
+
+func init() {
+ http.HandleFunc("/admin/", Admin)
+}
+
+func Admin(w http.ResponseWriter, req *http.Request) {
+ c := appengine.NewContext(req)
+ switch req.FormValue("op") {
+ default:
+ fmt.Fprintf(w, "unknown op %s\n", req.FormValue("op"))
+ case "memcache-get":
+ key := req.FormValue("key")
+ item, err := memcache.Get(c, key)
+ if err != nil {
+ fmt.Fprintf(w, "ERROR: %s\n", err)
+ return
+ }
+ w.Write(item.Value)
+ case "memcache-delete":
+ key := req.FormValue("key")
+ if err := memcache.Delete(c, key); err != nil {
+ fmt.Fprintf(w, "ERROR: %s\n", err)
+ return
+ }
+ fmt.Fprintf(w, "deleted %s\n", key)
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/app/app.yaml b/vendor/github.com/mattermost/rsc/app/app.yaml
new file mode 100644
index 000000000..d45119345
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/app/app.yaml
@@ -0,0 +1,23 @@
+# mkapp
+# ~/pub/go_appengine/dev_appserver.py --high_replication tmp
+# ~/pub/go_appengine/appcfg.py update tmp
+
+application: rsc-swtch-app
+runtime: go
+version: test
+api_version: go1
+
+handlers:
+- url: /\.appfs.*
+ script: _go_app
+ secure: always
+- url: /draft(/.*)?
+ script: _go_app
+ login: required
+- url: /admin(/.*)?
+ script: _go_app
+ login: admin
+
+# MUST BE LAST
+- url: /.*
+ script: _go_app
diff --git a/vendor/github.com/mattermost/rsc/app/index.yaml b/vendor/github.com/mattermost/rsc/app/index.yaml
new file mode 100644
index 000000000..c94524657
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/app/index.yaml
@@ -0,0 +1,16 @@
+indexes:
+
+# AUTOGENERATED
+
+# This index.yaml is automatically updated whenever the dev_appserver
+# detects that a new type of query is run. If you want to manage the
+# index.yaml file manually, remove the above marker line (the line
+# saying "# AUTOGENERATED"). If you want to manage some indexes
+# manually, move them above the marker line. The index.yaml file is
+# automatically uploaded to the admin console when you next deploy
+# your application using appcfg.py.
+
+- kind: FileInfo
+ ancestor: yes
+ properties:
+ - name: Path
diff --git a/vendor/github.com/mattermost/rsc/appfs/appfile/main.go b/vendor/github.com/mattermost/rsc/appfs/appfile/main.go
new file mode 100644
index 000000000..6d77df9aa
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/appfile/main.go
@@ -0,0 +1,156 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// appfile is a command-line interface to an appfs file system.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+
+ "github.com/mattermost/rsc/appfs/client"
+ "github.com/mattermost/rsc/keychain"
+)
+
+var c client.Client
+
+func init() {
+ flag.StringVar(&c.Host, "h", "localhost:8080", "app serving host")
+ flag.StringVar(&c.User, "u", "", "user name")
+ flag.StringVar(&c.Password, "p", "", "password")
+}
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: appfile [-h host] cmd args...\n")
+ fmt.Fprintf(os.Stderr, "\n")
+ fmt.Fprintf(os.Stderr, "Commands are:\n")
+ for _, c := range cmd {
+ fmt.Fprintf(os.Stderr, "\t%s\n", c.name)
+ }
+ os.Exit(2)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ args := flag.Args()
+ if len(args) == 0 {
+ usage()
+ }
+
+ if c.Password == "" {
+ var err error
+ c.User, c.Password, err = keychain.UserPasswd(c.Host, "")
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "unable to obtain user and password: %s\n", err)
+ os.Exit(2)
+ }
+ }
+
+ name, args := args[0], args[1:]
+ for _, c := range cmd {
+ if name == c.name {
+ switch c.arg {
+ case 0, 1:
+ if len(args) != c.arg {
+ if c.arg == 0 {
+ fmt.Fprintf(os.Stderr, "%s takes no arguments\n", name)
+ os.Exit(2)
+ }
+ fmt.Fprintf(os.Stderr, "%s requires 1 argument\n", name)
+ os.Exit(2)
+ }
+ case 2:
+ if len(args) == 0 {
+ fmt.Fprintf(os.Stderr, "%s requires at least 1 argument\n", name)
+ os.Exit(2)
+ }
+ }
+ c.fn(args)
+ return
+ }
+ }
+ fmt.Fprintf(os.Stderr, "unknown command %s\n", name)
+ os.Exit(2)
+}
+
+var cmd = []struct {
+ name string
+ fn func([]string)
+ arg int
+}{
+ {"mkdir", mkdir, 2},
+ {"write", write, 1},
+ {"read", read, 2},
+ {"mkfs", mkfs, 0},
+ {"stat", stat, 2},
+}
+
+func mkdir(args []string) {
+ for _, name := range args {
+ if err := c.Create(name, true); err != nil {
+ log.Printf("mkdir %s: %v", name, err)
+ }
+ }
+}
+
+func write(args []string) {
+ name := args[0]
+ data, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ log.Printf("reading stdin: %v", err)
+ return
+ }
+ c.Create(name, false)
+ if err := c.Write(name, data); err != nil {
+ log.Printf("write %s: %v", name, err)
+ }
+}
+
+func read(args []string) {
+ for _, name := range args {
+ fi, err := c.Stat(name)
+ if err != nil {
+ log.Printf("stat %s: %v", name, err)
+ continue
+ }
+ if fi.IsDir {
+ dirs, err := c.ReadDir(name)
+ if err != nil {
+ log.Printf("read %s: %v", name, err)
+ continue
+ }
+ for _, fi := range dirs {
+ fmt.Printf("%+v\n", *fi)
+ }
+ } else {
+ data, err := c.Read(name)
+ if err != nil {
+ log.Printf("read %s: %v", name, err)
+ continue
+ }
+ os.Stdout.Write(data)
+ }
+ }
+}
+
+func mkfs([]string) {
+ if err := c.Mkfs(); err != nil {
+ log.Printf("mkfs: %v", err)
+ }
+}
+
+func stat(args []string) {
+ for _, name := range args {
+ fi, err := c.Stat(name)
+ if err != nil {
+ log.Printf("stat %s: %v", name, err)
+ continue
+ }
+ fmt.Printf("%+v\n", *fi)
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/appfs/appmount/main.go b/vendor/github.com/mattermost/rsc/appfs/appmount/main.go
new file mode 100644
index 000000000..2c9f867d3
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/appmount/main.go
@@ -0,0 +1,287 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// appmount mounts an appfs file system.
+package main
+
+import (
+ "bytes"
+ "encoding/gob"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path"
+ "strings"
+ "syscall"
+ "time"
+ "sync"
+ "runtime"
+
+ "github.com/mattermost/rsc/appfs/client"
+ "github.com/mattermost/rsc/appfs/proto"
+ "github.com/mattermost/rsc/fuse"
+ "github.com/mattermost/rsc/keychain"
+)
+
+var usageMessage = `usage: appmount [-h host] [-u user] [-p password] /mnt
+
+Appmount mounts the appfs file system on the named mount point.
+
+The default host is localhost:8080.
+`
+
+// Shared between master and slave.
+var z struct {
+ Client client.Client
+ Debug *bool
+ Mtpt string
+}
+
+var fc *fuse.Conn
+var cl = &z.Client
+
+func init() {
+ flag.StringVar(&cl.Host, "h", "localhost:8080", "app serving host")
+ flag.StringVar(&cl.User, "u", "", "user name")
+ flag.StringVar(&cl.Password, "p", "", "password")
+ z.Debug = flag.Bool("debug", false, "")
+}
+
+func usage() {
+ fmt.Fprint(os.Stderr, usageMessage)
+ os.Exit(2)
+}
+
+func main() {
+ log.SetFlags(0)
+
+ if len(os.Args) == 2 && os.Args[1] == "MOUNTSLAVE" {
+ mountslave()
+ return
+ }
+
+ flag.Usage = usage
+ flag.Parse()
+ args := flag.Args()
+ if len(args) == 0 {
+ usage()
+ }
+ z.Mtpt = args[0]
+
+ if cl.Password == "" {
+ var err error
+ cl.User, cl.Password, err = keychain.UserPasswd(cl.Host, "")
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "unable to obtain user and password: %s\n", err)
+ os.Exit(2)
+ }
+ }
+
+ if _, err := cl.Stat("/"); err != nil {
+ log.Fatal(err)
+ }
+
+ // Run in child so that we can exit once child is running.
+ r, w, err := os.Pipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var buf bytes.Buffer
+ enc := gob.NewEncoder(&buf)
+ enc.Encode(&z)
+
+ cmd := exec.Command(os.Args[0], "MOUNTSLAVE")
+ cmd.Stdin = &buf
+ cmd.Stdout = w
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ log.Fatalf("mount process: %v", err)
+ }
+ w.Close()
+
+ ok := make([]byte, 10)
+ n, _ := r.Read(ok)
+ if n != 2 || string(ok[0:2]) != "OK" {
+ os.Exit(1)
+ }
+
+ fmt.Fprintf(os.Stderr, "mounted on %s\n", z.Mtpt)
+}
+
+func mountslave() {
+ stdout, _ := syscall.Dup(1)
+ syscall.Dup2(2, 1)
+
+ r := gob.NewDecoder(os.Stdin)
+ if err := r.Decode(&z); err != nil {
+ log.Fatalf("gob decode: %v", err)
+ }
+
+ fc, err := fuse.Mount(z.Mtpt)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer exec.Command("umount", z.Mtpt).Run()
+
+ if *z.Debug {
+ fuse.Debugf = log.Printf
+ }
+
+ syscall.Write(stdout, []byte("OK"))
+ syscall.Close(stdout)
+ fc.Serve(FS{})
+}
+
+type FS struct{}
+
+func (FS) Root() (fuse.Node, fuse.Error) {
+ return file("/")
+}
+
+type File struct {
+ Name string
+ FileInfo *proto.FileInfo
+ Data []byte
+}
+
+type statEntry struct {
+ fi *proto.FileInfo
+ err error
+ t time.Time
+}
+
+var statCache struct {
+ mu sync.Mutex
+ m map[string] statEntry
+}
+
+func stat(name string) (*proto.FileInfo, error) {
+ if runtime.GOOS == "darwin" && strings.Contains(name, "/._") {
+ // Mac resource forks
+ return nil, fmt.Errorf("file not found")
+ }
+ statCache.mu.Lock()
+ e, ok := statCache.m[name]
+ statCache.mu.Unlock()
+ if ok && time.Since(e.t) < 2*time.Minute {
+ return e.fi, e.err
+ }
+ fi, err := cl.Stat(name)
+ saveStat(name, fi, err)
+ return fi, err
+}
+
+func saveStat(name string, fi *proto.FileInfo, err error) {
+ if *z.Debug {
+if fi != nil {
+ fmt.Fprintf(os.Stderr, "savestat %s %+v\n", name, *fi)
+} else {
+ fmt.Fprintf(os.Stderr, "savestat %s %v\n", name, err)
+}
+ }
+ statCache.mu.Lock()
+ if statCache.m == nil {
+ statCache.m = make(map[string]statEntry)
+ }
+ statCache.m[name] = statEntry{fi, err, time.Now()}
+ statCache.mu.Unlock()
+}
+
+func delStat(name string) {
+ statCache.mu.Lock()
+ if statCache.m != nil {
+ delete(statCache.m, name)
+ }
+ statCache.mu.Unlock()
+}
+
+func file(name string) (fuse.Node, fuse.Error) {
+ fi, err := stat(name)
+ if err != nil {
+ if strings.Contains(err.Error(), "no such entity") {
+ return nil, fuse.ENOENT
+ }
+ if *z.Debug {
+ log.Printf("stat %s: %v", name, err)
+ }
+ return nil, fuse.EIO
+ }
+ return &File{name, fi, nil}, nil
+}
+
+func (f *File) Attr() (attr fuse.Attr) {
+ fi := f.FileInfo
+ attr.Mode = 0666
+ if fi.IsDir {
+ attr.Mode |= 0111 | os.ModeDir
+ }
+ attr.Mtime = fi.ModTime
+ attr.Size = uint64(fi.Size)
+ return
+}
+
+func (f *File) Lookup(name string, intr fuse.Intr) (fuse.Node, fuse.Error) {
+ return file(path.Join(f.Name, name))
+}
+
+func (f *File) ReadAll(intr fuse.Intr) ([]byte, fuse.Error) {
+ data, err := cl.Read(f.Name)
+ if err != nil {
+ log.Printf("read %s: %v", f.Name, err)
+ return nil, fuse.EIO
+ }
+ return data, nil
+}
+
+func (f *File) ReadDir(intr fuse.Intr) ([]fuse.Dirent, fuse.Error) {
+ fis, err := cl.ReadDir(f.Name)
+ if err != nil {
+ log.Printf("read %s: %v", f.Name, err)
+ return nil, fuse.EIO
+ }
+ var dirs []fuse.Dirent
+ for _, fi := range fis {
+ saveStat(path.Join(f.Name, fi.Name), fi, nil)
+ dirs = append(dirs, fuse.Dirent{Name: fi.Name})
+ }
+ return dirs, nil
+}
+
+func (f *File) WriteAll(data []byte, intr fuse.Intr) fuse.Error {
+ defer delStat(f.Name)
+ if err := cl.Write(f.Name[1:], data); err != nil {
+ log.Printf("write %s: %v", f.Name, err)
+ return fuse.EIO
+ }
+ return nil
+}
+
+func (f *File) Mkdir(req *fuse.MkdirRequest, intr fuse.Intr) (fuse.Node, fuse.Error) {
+ defer delStat(f.Name)
+ p := path.Join(f.Name, req.Name)
+ if err := cl.Create(p[1:], true); err != nil {
+ log.Printf("mkdir %s: %v", p, err)
+ return nil, fuse.EIO
+ }
+ delStat(p)
+ return file(p)
+}
+
+func (f *File) Create(req *fuse.CreateRequest, resp *fuse.CreateResponse, intr fuse.Intr) (fuse.Node, fuse.Handle, fuse.Error) {
+ defer delStat(f.Name)
+ p := path.Join(f.Name, req.Name)
+ if err := cl.Create(p[1:], false); err != nil {
+ log.Printf("create %s: %v", p, err)
+ return nil, nil, fuse.EIO
+ }
+ delStat(p)
+ n, err := file(p)
+ if err != nil {
+ return nil, nil, err
+ }
+ return n, n, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/appfs/client/client.go b/vendor/github.com/mattermost/rsc/appfs/client/client.go
new file mode 100644
index 000000000..a1deb291d
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/client/client.go
@@ -0,0 +1,150 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package client implements a basic appfs client.
+package client
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/mattermost/rsc/appfs/proto"
+)
+
+type Client struct {
+ Host string
+ User string
+ Password string
+}
+
+func (c *Client) url(op, path string) string {
+ scheme := "https"
+ if strings.HasPrefix(c.Host, "localhost:") {
+ scheme = "http"
+ }
+ if strings.HasSuffix(op, "/") && strings.HasPrefix(path, "/") {
+ path = path[1:]
+ }
+ return scheme + "://"+ c.User + ":" + c.Password + "@" + c.Host + op + path
+}
+
+func (c *Client) do(u string) error {
+ _, err := c.get(u)
+ return err
+}
+
+func (c *Client) get(u string) ([]byte, error) {
+ tries := 0
+ for {
+ r, err := http.Get(u)
+ if err != nil {
+ return nil, err
+ }
+ defer r.Body.Close()
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, err
+ }
+ if r.StatusCode != 200 {
+ if r.StatusCode == 500 {
+ if tries++; tries < 3 {
+ fmt.Printf("%s %s; sleeping\n", r.Status, data)
+ time.Sleep(5*time.Second)
+ continue
+ }
+ }
+ return nil, fmt.Errorf("%s %s", r.Status, data)
+ }
+ return data, nil
+ }
+ panic("unreachable")
+}
+
+func (c *Client) post(u string, data []byte) ([]byte, error) {
+ tries := 0
+ for {
+ r, err := http.Post(u, proto.PostContentType, bytes.NewBuffer(data))
+ if err != nil {
+ return nil, err
+ }
+ defer r.Body.Close()
+ rdata, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return nil, err
+ }
+ if r.StatusCode != 200 {
+ if r.StatusCode == 500 {
+ if tries++; tries < 3 {
+ fmt.Printf("%s %s; sleeping\n", r.Status, rdata)
+ time.Sleep(5*time.Second)
+ continue
+ }
+ }
+ return nil, fmt.Errorf("%s %s", r.Status, rdata)
+ }
+ return rdata, nil
+ }
+ panic("unreachable")
+}
+
+func (c *Client) Create(path string, isdir bool) error {
+ u := c.url(proto.CreateURL, path)
+ if isdir {
+ u += "?dir=1"
+ }
+ return c.do(u)
+}
+
+func (c *Client) Read(path string) ([]byte, error) {
+ return c.get(c.url(proto.ReadURL, path))
+}
+
+func (c *Client) Write(path string, data []byte) error {
+ u := c.url(proto.WriteURL, path)
+ _, err := c.post(u, data)
+ return err
+}
+
+func (c *Client) Mkfs() error {
+ return c.do(c.url(proto.MkfsURL, ""))
+}
+
+func (c *Client) Stat(path string) (*proto.FileInfo, error) {
+ data, err := c.get(c.url(proto.StatURL, path))
+ if err != nil {
+ return nil, err
+ }
+ var fi proto.FileInfo
+ if err := json.Unmarshal(data, &fi); err != nil {
+ return nil, err
+ }
+ return &fi, nil
+}
+
+func (c *Client) ReadDir(path string) ([]*proto.FileInfo, error) {
+ data, err := c.Read(path)
+ if err != nil {
+ return nil, err
+ }
+ dec := json.NewDecoder(bytes.NewBuffer(data))
+ var out []*proto.FileInfo
+ for {
+ var fi proto.FileInfo
+ err := dec.Decode(&fi)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return out, err
+ }
+ out = append(out, &fi)
+ }
+ return out, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/appfs/fs/fs.go b/vendor/github.com/mattermost/rsc/appfs/fs/fs.go
new file mode 100644
index 000000000..ac6657393
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/fs/fs.go
@@ -0,0 +1,273 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package fs is an indirection layer, allowing code to use a
+// file system without knowing whether it is the host file system
+// (running without App Engine) or the datastore-based app
+// file system (running on App Engine).
+//
+// When compiled locally, fs refers to files in the local file system,
+// and the cache saves nothing.
+//
+// When compiled for App Engine, fs uses the appfs file system
+// and the memcache-based cache.
+package fs
+
+import (
+ "bytes"
+ "encoding/gob"
+ "fmt"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "time"
+
+ "github.com/mattermost/rsc/appfs/proto"
+)
+
+type AppEngine interface {
+ NewContext(req *http.Request) interface{}
+ CacheRead(ctxt interface{}, name, path string) (key interface{}, data []byte, found bool)
+ CacheWrite(ctxt, key interface{}, data []byte)
+ Read(ctxt interface{}, path string) ([]byte, *proto.FileInfo, error)
+ Write(ctxt interface{}, path string, data []byte) error
+ Remove(ctxt interface{}, path string) error
+ Mkdir(ctxt interface{}, path string) error
+ ReadDir(ctxt interface{}, path string) ([]proto.FileInfo, error)
+ Criticalf(ctxt interface{}, format string, args ...interface{})
+ User(ctxt interface{}) string
+}
+
+var ae AppEngine
+
+func Register(impl AppEngine) {
+ ae = impl
+}
+
+// Root is the root of the local file system. It has no effect on App Engine.
+var Root = "."
+
+// A Context is an opaque context that is needed to perform file system
+// operations. Each context is associated with a single HTTP request.
+type Context struct {
+ context
+ ae interface{}
+}
+
+// NewContext returns a context associated with the given HTTP request.
+func NewContext(req *http.Request) *Context {
+ if ae != nil {
+ ctxt := ae.NewContext(req)
+ return &Context{ae: ctxt}
+ }
+ return newContext(req)
+}
+
+// A CacheKey is an opaque cache key that can be used to store new entries
+// in the cache. To ensure that the cache remains consistent with the underlying
+// file system, the correct procedure is:
+//
+// 1. Use CacheRead (or CacheLoad) to attempt to load the entry. If it succeeds, use it.
+// If not, continue, saving the CacheKey.
+//
+// 2. Read from the file system and construct the entry that would have
+// been in the cache. In order to be consistent, all the file system reads
+// should only refer to parts of the file system in the tree rooted at the path
+// passed to CacheRead.
+//
+// 3. Save the entry using CacheWrite (or CacheStore), using the key that was
+// created by the CacheRead (or CacheLoad) executed before reading from the
+// file system.
+//
+type CacheKey struct {
+ cacheKey
+ ae interface{}
+}
+
+// CacheRead reads from cache the entry with the given name and path.
+// The path specifies the scope of information stored in the cache entry.
+// An entry is invalidated by a write to any location in the file tree rooted at path.
+// The name is an uninterpreted identifier to distinguish the cache entry
+// from other entries using the same path.
+//
+// If it finds a cache entry, CacheRead returns the data and found=true.
+// If it does not find a cache entry, CacheRead returns data=nil and found=false.
+// Either way, CacheRead returns an appropriate cache key for storing to the
+// cache entry using CacheWrite.
+func (c *Context) CacheRead(name, path string) (ckey CacheKey, data []byte, found bool) {
+ if ae != nil {
+ key, data, found := ae.CacheRead(c.ae, name, path)
+ return CacheKey{ae: key}, data, found
+ }
+ return c.cacheRead(ckey, path)
+}
+
+// CacheLoad uses CacheRead to load gob-encoded data and decodes it into value.
+func (c *Context) CacheLoad(name, path string, value interface{}) (ckey CacheKey, found bool) {
+ ckey, data, found := c.CacheRead(name, path)
+ if found {
+ if err := gob.NewDecoder(bytes.NewBuffer(data)).Decode(value); err != nil {
+ c.Criticalf("gob Decode: %v", err)
+ found = false
+ }
+ }
+ return
+}
+
+// CacheWrite writes an entry to the cache with the given key, path, and data.
+// The cache entry will be invalidated the next time the file tree rooted at path is
+// modified in anyway.
+func (c *Context) CacheWrite(ckey CacheKey, data []byte) {
+ if ae != nil {
+ ae.CacheWrite(c.ae, ckey.ae, data)
+ return
+ }
+ c.cacheWrite(ckey, data)
+}
+
+// CacheStore uses CacheWrite to save the gob-encoded form of value.
+func (c *Context) CacheStore(ckey CacheKey, value interface{}) {
+ var buf bytes.Buffer
+ if err := gob.NewEncoder(&buf).Encode(value); err != nil {
+ c.Criticalf("gob Encode: %v", err)
+ return
+ }
+ c.CacheWrite(ckey, buf.Bytes())
+}
+
+// Read returns the data associated with the file named by path.
+// It is a copy and can be modified without affecting the file.
+func (c *Context) Read(path string) ([]byte, *proto.FileInfo, error) {
+ if ae != nil {
+ return ae.Read(c.ae, path)
+ }
+ return c.read(path)
+}
+
+// Write replaces the data associated with the file named by path.
+func (c *Context) Write(path string, data []byte) error {
+ if ae != nil {
+ return ae.Write(c.ae, path, data)
+ }
+ return c.write(path, data)
+}
+
+// Remove removes the file named by path.
+func (c *Context) Remove(path string) error {
+ if ae != nil {
+ return ae.Remove(c.ae, path)
+ }
+ return c.remove(path)
+}
+
+// Mkdir creates a directory with the given path.
+// If the path already exists and is a directory, Mkdir returns no error.
+func (c *Context) Mkdir(path string) error {
+ if ae != nil {
+ return ae.Mkdir(c.ae, path)
+ }
+ return c.mkdir(path)
+}
+
+// ReadDir returns the contents of the directory named by the path.
+func (c *Context) ReadDir(path string) ([]proto.FileInfo, error) {
+ if ae != nil {
+ return ae.ReadDir(c.ae, path)
+ }
+ return c.readdir(path)
+}
+
+// ServeFile serves the named file as the response to the HTTP request.
+func (c *Context) ServeFile(w http.ResponseWriter, req *http.Request, name string) {
+ root := &httpFS{c, name}
+ http.FileServer(root).ServeHTTP(w, req)
+}
+
+// Criticalf logs the message at critical priority.
+func (c *Context) Criticalf(format string, args ...interface{}) {
+ if ae != nil {
+ ae.Criticalf(c.ae, format, args...)
+ }
+ log.Printf(format, args...)
+}
+
+// User returns the name of the user running the request.
+func (c *Context) User() string {
+ if ae != nil {
+ return ae.User(c.ae)
+ }
+ return os.Getenv("USER")
+}
+
+type httpFS struct {
+ c *Context
+ name string
+}
+
+type httpFile struct {
+ data []byte
+ fi *proto.FileInfo
+ off int
+}
+
+func (h *httpFS) Open(_ string) (http.File, error) {
+ data, fi, err := h.c.Read(h.name)
+ if err != nil {
+ return nil, err
+ }
+ return &httpFile{data, fi, 0}, nil
+}
+
+func (f *httpFile) Close() error {
+ return nil
+}
+
+type fileInfo struct {
+ p *proto.FileInfo
+}
+
+func (f *fileInfo) IsDir() bool { return f.p.IsDir }
+func (f *fileInfo) Name() string { return f.p.Name }
+func (f *fileInfo) ModTime() time.Time { return f.p.ModTime }
+func (f *fileInfo) Size() int64 { return f.p.Size }
+func (f *fileInfo) Sys() interface{} { return f.p }
+func (f *fileInfo) Mode() os.FileMode {
+ if f.p.IsDir {
+ return os.ModeDir | 0777
+ }
+ return 0666
+}
+
+func (f *httpFile) Stat() (os.FileInfo, error) {
+ return &fileInfo{f.fi}, nil
+}
+
+func (f *httpFile) Readdir(count int) ([]os.FileInfo, error) {
+ return nil, fmt.Errorf("no directory")
+}
+
+func (f *httpFile) Read(data []byte) (int, error) {
+ if f.off >= len(f.data) {
+ return 0, io.EOF
+ }
+ n := copy(data, f.data[f.off:])
+ f.off += n
+ return n, nil
+}
+
+func (f *httpFile) Seek(offset int64, whence int) (int64, error) {
+ off := int(offset)
+ if int64(off) != offset {
+ return 0, fmt.Errorf("invalid offset")
+ }
+ switch whence {
+ case 1:
+ off += f.off
+ case 2:
+ off += len(f.data)
+ }
+ f.off = off
+ return int64(off), nil
+}
diff --git a/vendor/github.com/mattermost/rsc/appfs/fs/local.go b/vendor/github.com/mattermost/rsc/appfs/fs/local.go
new file mode 100644
index 000000000..c78b35b64
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/fs/local.go
@@ -0,0 +1,82 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fs
+
+import (
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "github.com/mattermost/rsc/appfs/proto"
+)
+
+type context struct{}
+
+type cacheKey struct{}
+
+func newContext(req *http.Request) *Context {
+ return &Context{}
+}
+
+func (*context) cacheRead(ckey CacheKey, path string) (CacheKey, []byte, bool) {
+ return ckey, nil, false
+}
+
+func (*context) cacheWrite(ckey CacheKey, data []byte) {
+}
+
+func (*context) read(path string) ([]byte, *proto.FileInfo, error) {
+ p := filepath.Join(Root, path)
+ dir, err := os.Stat(p)
+ if err != nil {
+ return nil, nil, err
+ }
+ fi := &proto.FileInfo{
+ Name: dir.Name(),
+ ModTime: dir.ModTime(),
+ Size: dir.Size(),
+ IsDir: dir.IsDir(),
+ }
+ data, err := ioutil.ReadFile(p)
+ return data, fi, err
+}
+
+func (*context) write(path string, data []byte) error {
+ p := filepath.Join(Root, path)
+ return ioutil.WriteFile(p, data, 0666)
+}
+
+func (*context) remove(path string) error {
+ p := filepath.Join(Root, path)
+ return os.Remove(p)
+}
+
+func (*context) mkdir(path string) error {
+ p := filepath.Join(Root, path)
+ fi, err := os.Stat(p)
+ if err == nil && fi.IsDir() {
+ return nil
+ }
+ return os.Mkdir(p, 0777)
+}
+
+func (*context) readdir(path string) ([]proto.FileInfo, error) {
+ p := filepath.Join(Root, path)
+ dirs, err := ioutil.ReadDir(p)
+ if err != nil {
+ return nil, err
+ }
+ var out []proto.FileInfo
+ for _, dir := range dirs {
+ out = append(out, proto.FileInfo{
+ Name: dir.Name(),
+ ModTime: dir.ModTime(),
+ Size: dir.Size(),
+ IsDir: dir.IsDir(),
+ })
+ }
+ return out, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/appfs/proto/data.go b/vendor/github.com/mattermost/rsc/appfs/proto/data.go
new file mode 100644
index 000000000..ac15411a8
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/proto/data.go
@@ -0,0 +1,55 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package proto defines the protocol between appfs client and server.
+package proto
+
+import "time"
+
+// An Auth appears, JSON-encoded, as the X-Appfs-Auth header line,
+// to authenticate a request made to the file server.
+// The authentication scheme could be made more sophisticated, but since
+// we are already forcing the use of TLS, a plain password is fine for now.
+type Auth struct {
+ Password string
+}
+
+// GET /.appfs/stat/path returns the metadata for a file or directory,
+// a JSON-encoded FileInfo.
+const StatURL = "/.appfs/stat/"
+
+// GET /.appfs/read/path returns the content of the file or directory.
+// The body of the response is the raw file or directory content.
+// The content of a directory is a sequence of JSON-encoded FileInfo.
+const ReadURL = "/.appfs/read/"
+
+// POST to /.appfs/write/path writes new data to a file.
+// The X-Appfs-SHA1 header is the SHA1 hash of the data.
+// The body of the request is the raw file content.
+const WriteURL = "/.appfs/write/"
+
+// POST to /.appfs/mount initializes the file system if it does not
+// yet exist in the datastore.
+const MkfsURL = "/.appfs/mkfs"
+
+// POST to /.appfs/create/path creates a new file or directory.
+// The named path must not already exist; its parent must exist.
+// The query parameter dir=1 indicates that a directory should be created.
+const CreateURL = "/.appfs/create/"
+
+// POST to /.appfs/remove/path removes the file or directory.
+// A directory must be empty to be removed.
+const RemoveURL = "/.appfs/remove/"
+
+// A FileInfo is a directory entry.
+type FileInfo struct {
+ Name string // final path element
+ ModTime time.Time
+ Size int64
+ IsDir bool
+}
+
+// PostContentType is the Content-Type for POSTed data.
+// There is no encoding or framing: it is just raw data bytes.
+const PostContentType = "x-appfs/raw"
diff --git a/vendor/github.com/mattermost/rsc/appfs/server/app.go b/vendor/github.com/mattermost/rsc/appfs/server/app.go
new file mode 100644
index 000000000..9486eac41
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/appfs/server/app.go
@@ -0,0 +1,982 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package server implements an appfs server backed by the
+// App Engine datastore.
+package server
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "path"
+ "strconv"
+ "strings"
+ "time"
+
+ "appengine"
+ "appengine/datastore"
+ "appengine/memcache"
+ "appengine/user"
+
+ "github.com/mattermost/rsc/appfs/fs"
+ "github.com/mattermost/rsc/appfs/proto"
+)
+
+const pwFile = "/.password"
+var chatty = false
+
+func init() {
+ handle(proto.ReadURL, (*request).read)
+ handle(proto.WriteURL, (*request).write)
+ handle(proto.StatURL, (*request).stat)
+ handle(proto.MkfsURL, (*request).mkfs)
+ handle(proto.CreateURL, (*request).create)
+ handle(proto.RemoveURL, (*request).remove)
+}
+
+type request struct {
+ w http.ResponseWriter
+ req *http.Request
+ c appengine.Context
+ name string
+ mname string
+ key *datastore.Key
+}
+
+func auth(r *request) bool {
+ hdr := r.req.Header.Get("Authorization")
+ if !strings.HasPrefix(hdr, "Basic ") {
+ return false
+ }
+ data, err := base64.StdEncoding.DecodeString(hdr[6:])
+ if err != nil {
+ return false
+ }
+ i := bytes.IndexByte(data, ':')
+ if i < 0 {
+ return false
+ }
+ user, passwd := string(data[:i]), string(data[i+1:])
+
+ _, data, err = read(r.c, pwFile)
+ if err != nil {
+ r.c.Errorf("reading %s: %v", pwFile, err)
+ if _, err := mkfs(r.c); err != nil {
+ r.c.Errorf("creating fs: %v", err)
+ }
+ _, data, err = read(r.c, pwFile)
+ if err != nil {
+ r.c.Errorf("reading %s again: %v", pwFile, err)
+ return false
+ }
+ }
+
+ lines := strings.Split(string(data), "\n")
+ for _, line := range lines {
+ if strings.HasPrefix(line, "#") {
+ continue
+ }
+ f := strings.Fields(line)
+ if len(f) < 3 {
+ continue
+ }
+ if f[0] == user {
+ return hash(f[1]+passwd) == f[2]
+ }
+ }
+ return false
+}
+
+func hash(s string) string {
+ h := sha1.New()
+ h.Write([]byte(s))
+ return fmt.Sprintf("%x", h.Sum(nil))
+}
+
+func handle(prefix string, f func(*request)) {
+ http.HandleFunc(prefix, func(w http.ResponseWriter, req *http.Request) {
+ c := appengine.NewContext(req)
+ r := &request{
+ w: w,
+ req: req,
+ c: c,
+ }
+
+ if strings.HasSuffix(prefix, "/") {
+ r.name, r.mname, r.key = mangle(c, req.URL.Path[len(prefix)-1:])
+ } else {
+ req.URL.Path = "/"
+ }
+ defer func() {
+ if err := recover(); err != nil {
+ w.WriteHeader(http.StatusConflict)
+ fmt.Fprintf(w, "%s\n", err)
+ }
+ }()
+
+ if !auth(r) {
+ w.Header().Set("WWW-Authenticate", "Basic realm=\"appfs\"")
+ http.Error(w, "Need auth", http.StatusUnauthorized)
+ return
+ }
+
+ f(r)
+ })
+}
+
+func mangle(c appengine.Context, name string) (string, string, *datastore.Key) {
+ name = path.Clean("/" + name)
+ n := strings.Count(name, "/")
+ if name == "/" {
+ n = 0
+ }
+ mname := fmt.Sprintf("%d%s", n, name)
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ key := datastore.NewKey(c, "FileInfo", mname, 0, root)
+ return name, mname, key
+}
+
+type FileInfo struct {
+ Path string // mangled path
+ Name string
+ Qid int64 // assigned unique id number
+ Seq int64 // modification sequence number in file tree
+ ModTime time.Time
+ Size int64
+ IsDir bool
+}
+
+type FileData struct {
+ Data []byte
+}
+
+func stat(c appengine.Context, name string) (*FileInfo, error) {
+ var fi FileInfo
+ name, _, key := mangle(c, name)
+ c.Infof("DATASTORE Stat %q", name)
+ err := datastore.Get(c, key, &fi)
+ if err != nil {
+ return nil, err
+ }
+ return &fi, nil
+}
+
+func (r *request) saveStat(fi *FileInfo) {
+ jfi, err := json.Marshal(&fi)
+ if err != nil {
+ panic(err)
+ }
+ r.w.Header().Set("X-Appfs-Stat", string(jfi))
+}
+
+func (r *request) tx(f func(c appengine.Context) error) {
+ err := datastore.RunInTransaction(r.c, f, &datastore.TransactionOptions{XG: true})
+ if err != nil {
+ panic(err)
+ }
+}
+
+func (r *request) stat() {
+ var fi *FileInfo
+ r.tx(func(c appengine.Context) error {
+ fi1, err := stat(c, r.name)
+ if err != nil {
+ return err
+ }
+ fi = fi1
+ return nil
+ })
+
+ jfi, err := json.Marshal(&fi)
+ if err != nil {
+ panic(err)
+ }
+ r.w.Write(jfi)
+}
+
+func read(c appengine.Context, name string) (fi *FileInfo, data []byte, err error) {
+ name, _, _ = mangle(c, name)
+ fi1, err := stat(c, name)
+ if err != nil {
+ return nil, nil, err
+ }
+ if fi1.IsDir {
+ dt, err := readdir(c, name)
+ if err != nil {
+ return nil, nil, err
+ }
+ fi = fi1
+ data = dt
+ return fi, data, nil
+ }
+
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ dkey := datastore.NewKey(c, "FileData", "", fi1.Qid, root)
+ var fd FileData
+ c.Infof("DATASTORE Read %q", name)
+ if err := datastore.Get(c, dkey, &fd); err != nil {
+ return nil, nil, err
+ }
+ fi = fi1
+ data = fd.Data
+ return fi, data, nil
+}
+
+func (r *request) read() {
+ var (
+ fi *FileInfo
+ data []byte
+ )
+ r.tx(func(c appengine.Context) error {
+ var err error
+ fi, data, err = read(r.c, r.name)
+ return err
+ })
+ r.saveStat(fi)
+ r.w.Write(data)
+}
+
+func readdir(c appengine.Context, name string) ([]byte, error) {
+ name, _, _ = mangle(c, name)
+ var buf bytes.Buffer
+
+ n := strings.Count(name, "/")
+ if name == "/" {
+ name = ""
+ n = 0
+ }
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ first := fmt.Sprintf("%d%s/", n+1, name)
+ limit := fmt.Sprintf("%d%s0", n+1, name)
+ c.Infof("DATASTORE ReadDir %q", name)
+ q := datastore.NewQuery("FileInfo").
+ Filter("Path >=", first).
+ Filter("Path <", limit).
+ Ancestor(root)
+ enc := json.NewEncoder(&buf)
+ it := q.Run(c)
+ var fi FileInfo
+ var pfi proto.FileInfo
+ for {
+ fi = FileInfo{}
+ _, err := it.Next(&fi)
+ if err != nil {
+ if err == datastore.Done {
+ break
+ }
+ return nil, err
+ }
+ pfi = proto.FileInfo{
+ Name: fi.Name,
+ ModTime: fi.ModTime,
+ Size: fi.Size,
+ IsDir: fi.IsDir,
+ }
+ if err := enc.Encode(&pfi); err != nil {
+ return nil, err
+ }
+ }
+
+ return buf.Bytes(), nil
+}
+
+func readdirRaw(c appengine.Context, name string) ([]proto.FileInfo, error) {
+ name, _, _ = mangle(c, name)
+ n := strings.Count(name, "/")
+ if name == "/" {
+ name = ""
+ n = 0
+ }
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ first := fmt.Sprintf("%d%s/", n+1, name)
+ limit := fmt.Sprintf("%d%s0", n+1, name)
+ c.Infof("DATASTORE ReadDir %q", name)
+ q := datastore.NewQuery("FileInfo").
+ Filter("Path >=", first).
+ Filter("Path <", limit).
+ Ancestor(root)
+ it := q.Run(c)
+ var fi FileInfo
+ var pfi proto.FileInfo
+ var out []proto.FileInfo
+ for {
+ fi = FileInfo{}
+ _, err := it.Next(&fi)
+ if err != nil {
+ if err == datastore.Done {
+ break
+ }
+ return nil, err
+ }
+ pfi = proto.FileInfo{
+ Name: fi.Name,
+ ModTime: fi.ModTime,
+ Size: fi.Size,
+ IsDir: fi.IsDir,
+ }
+ out = append(out, pfi)
+ }
+println("READDIR", name, len(out))
+ return out, nil
+}
+
+
+var initPasswd = `# Password file
+# This file controls access to the server.
+# The format is lines of space-separated fields:
+# user salt pwhash
+# The pwhash is the SHA1 of the salt string concatenated with the password.
+
+# user=dummy password=dummy (replace with your own entries)
+dummy 12345 faa863c7d3d41893f80165c704b714d5e31bdd3b
+`
+
+func (r *request) mkfs() {
+ var fi *FileInfo
+ r.tx(func(c appengine.Context) error {
+ var err error
+ fi, err = mkfs(c)
+ return err
+ })
+ r.saveStat(fi)
+}
+
+func mkfs(c appengine.Context) (fi *FileInfo, err error) {
+ fi1, err := stat(c, "/")
+ if err == nil {
+ return fi1, nil
+ }
+
+ // Root needs to be created.
+ // Probably root key does too.
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ _, err = datastore.Put(c, root, &struct{}{})
+ if err != nil {
+ return nil, fmt.Errorf("mkfs put root: %s", err)
+ }
+
+ // Entry for /.
+ _, mpath, key := mangle(c, "/")
+ fi3 := FileInfo{
+ Path: mpath,
+ Name: "/",
+ Seq: 2, // 2, not 1, because we're going to write password file with #2
+ Qid: 1,
+ ModTime: time.Now(),
+ Size: 0,
+ IsDir: true,
+ }
+ _, err = datastore.Put(c, key, &fi3)
+ if err != nil {
+ return nil, fmt.Errorf("mkfs put /: %s", err)
+ }
+
+ /*
+ * Would like to use this code but App Engine apparently
+ * does not let Get observe the effect of a Put in the same
+ * transaction. What planet does that make sense on?
+ * Instead, we have to execute just the datastore writes that this
+ * sequence would.
+ *
+ _, err = create(c, pwFile, false)
+ if err != nil {
+ return nil, fmt.Errorf("mkfs create .password: %s", err)
+ }
+ _, err = write(c, pwFile, []byte(initPasswd))
+ if err != nil {
+ return nil, fmt.Errorf("mkfs write .password: %s", err)
+ }
+ *
+ */
+
+ {
+ name, mname, key := mangle(c, pwFile)
+
+ // Create data object.
+ dataKey := int64(2)
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ dkey := datastore.NewKey(c, "FileData", "", dataKey, root)
+ _, err := datastore.Put(c, dkey, &FileData{[]byte(initPasswd)})
+ if err != nil {
+ return nil, err
+ }
+
+ // Create new directory entry.
+ _, elem := path.Split(name)
+ fi1 = &FileInfo{
+ Path: mname,
+ Name: elem,
+ Qid: 2,
+ Seq: 2,
+ ModTime: time.Now(),
+ Size: int64(len(initPasswd)),
+ IsDir: false,
+ }
+ if _, err := datastore.Put(c, key, fi1); err != nil {
+ return nil, err
+ }
+ }
+
+ return &fi3, nil
+}
+
+func (r *request) write() {
+ data, err := ioutil.ReadAll(r.req.Body)
+ if err != nil {
+ panic(err)
+ }
+
+ var fi *FileInfo
+ var seq int64
+ r.tx(func(c appengine.Context) error {
+ var err error
+ fi, seq, err = write(r.c, r.name, data)
+ return err
+ })
+ updateCacheTime(r.c, seq)
+ r.saveStat(fi)
+}
+
+func write(c appengine.Context, name string, data []byte) (*FileInfo, int64, error) {
+ name, _, key := mangle(c, name)
+
+ // Check that file exists and is not a directory.
+ fi1, err := stat(c, name)
+ if err != nil {
+ return nil, 0, err
+ }
+ if fi1.IsDir {
+ return nil, 0, fmt.Errorf("cannot write to directory")
+ }
+
+ // Fetch and increment root sequence number.
+ rfi, err := stat(c, "/")
+ if err != nil {
+ return nil, 0, err
+ }
+ rfi.Seq++
+
+ // Write data.
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ dkey := datastore.NewKey(c, "FileData", "", fi1.Qid, root)
+ fd := &FileData{data}
+ if _, err := datastore.Put(c, dkey, fd); err != nil {
+ return nil, 0, err
+ }
+
+ // Update directory entry.
+ fi1.Seq = rfi.Seq
+ fi1.Size = int64(len(data))
+ fi1.ModTime = time.Now()
+ if _, err := datastore.Put(c, key, fi1); err != nil {
+ return nil, 0, err
+ }
+
+ // Update sequence numbers all the way to the root.
+ if err := updateSeq(c, name, rfi.Seq, 1); err != nil {
+ return nil, 0, err
+ }
+
+ return fi1, rfi.Seq, nil
+}
+
+func updateSeq(c appengine.Context, name string, seq int64, skip int) error {
+ p := path.Clean(name)
+ for i := 0; ; i++ {
+ if i >= skip {
+ _, _, key := mangle(c, p)
+ var fi FileInfo
+ if err := datastore.Get(c, key, &fi); err != nil {
+ return err
+ }
+ fi.Seq = seq
+ if _, err := datastore.Put(c, key, &fi); err != nil {
+ return err
+ }
+ }
+ if p == "/" {
+ break
+ }
+ p, _ = path.Split(p)
+ p = path.Clean(p)
+ }
+ return nil
+}
+
+func (r *request) remove() {
+ panic("remove not implemented")
+}
+
+func (r *request) create() {
+ var fi *FileInfo
+ var seq int64
+ isDir := r.req.FormValue("dir") == "1"
+ r.tx(func(c appengine.Context) error {
+ var err error
+ fi, seq, err = create(r.c, r.name, isDir, nil)
+ return err
+ })
+ updateCacheTime(r.c, seq)
+ r.saveStat(fi)
+}
+
+func create(c appengine.Context, name string, isDir bool, data []byte) (*FileInfo, int64, error) {
+ name, mname, key := mangle(c, name)
+
+ // File must not exist.
+ fi1, err := stat(c, name)
+ if err == nil {
+ return nil, 0, fmt.Errorf("file already exists")
+ }
+ if err != datastore.ErrNoSuchEntity {
+ return nil, 0, err
+ }
+
+ // Parent must exist and be a directory.
+ p, _ := path.Split(name)
+ fi2, err := stat(c, p)
+ if err != nil {
+ if err == datastore.ErrNoSuchEntity {
+ return nil, 0, fmt.Errorf("parent directory %q does not exist", p)
+ }
+ return nil, 0, err
+ }
+ if !fi2.IsDir {
+ return nil, 0, fmt.Errorf("parent %q is not a directory", p)
+ }
+
+ // Fetch and increment root sequence number.
+ rfi, err := stat(c, "/")
+ if err != nil {
+ return nil, 0, err
+ }
+ rfi.Seq++
+
+ var dataKey int64
+ // Create data object.
+ if !isDir {
+ dataKey = rfi.Seq
+ root := datastore.NewKey(c, "RootKey", "v2:", 0, nil)
+ dkey := datastore.NewKey(c, "FileData", "", dataKey, root)
+ _, err := datastore.Put(c, dkey, &FileData{data})
+ if err != nil {
+ return nil, 0, err
+ }
+ }
+
+ // Create new directory entry.
+ _, elem := path.Split(name)
+ fi1 = &FileInfo{
+ Path: mname,
+ Name: elem,
+ Qid: rfi.Seq,
+ Seq: rfi.Seq,
+ ModTime: time.Now(),
+ Size: int64(len(data)),
+ IsDir: isDir,
+ }
+ if _, err := datastore.Put(c, key, fi1); err != nil {
+ return nil, 0, err
+ }
+
+ // Update sequence numbers all the way to root,
+ // but skip entry we just wrote.
+ if err := updateSeq(c, name, rfi.Seq, 1); err != nil {
+ return nil, 0, err
+ }
+
+ return fi1, rfi.Seq, nil
+}
+
+// Implementation of fs.AppEngine.
+
+func init() {
+ fs.Register(ae{})
+}
+
+type ae struct{}
+
+func tx(c interface{}, f func(c appengine.Context) error) error {
+ return datastore.RunInTransaction(c.(appengine.Context), f, &datastore.TransactionOptions{XG: true})
+}
+
+func (ae) NewContext(req *http.Request) interface{} {
+ return appengine.NewContext(req)
+}
+
+func (ae) User(ctxt interface{}) string {
+ c := ctxt.(appengine.Context)
+ u := user.Current(c)
+ if u == nil {
+ return "?"
+ }
+ return u.String()
+}
+
+type cacheKey struct {
+ t int64
+ name string
+}
+
+func (ae) CacheRead(ctxt interface{}, name, path string) (key interface{}, data []byte, found bool) {
+ c := ctxt.(appengine.Context)
+ t, data, _, err := cacheRead(c, "cache", name, path)
+ return &cacheKey{t, name}, data, err == nil
+}
+
+func (ae) CacheWrite(ctxt, key interface{}, data []byte) {
+ c := ctxt.(appengine.Context)
+ k := key.(*cacheKey)
+ cacheWrite(c, k.t, "cache", k.name, data)
+}
+
+func (ae ae) Read(ctxt interface{}, name string) (data []byte, pfi *proto.FileInfo, err error) {
+ c := ctxt.(appengine.Context)
+ name = path.Clean("/"+name)
+ if chatty {
+ c.Infof("AE Read %s", name)
+ }
+ _, data, pfi, err = cacheRead(c, "data", name, name)
+ if err != nil {
+ err = fmt.Errorf("Read %q: %v", name, err)
+ }
+ return
+}
+
+func (ae) Write(ctxt interface{}, path string, data []byte) error {
+ var seq int64
+ err := tx(ctxt, func(c appengine.Context) error {
+ _, err := stat(c, path)
+ if err != nil {
+ _, seq, err = create(c, path, false, data)
+ } else {
+ _, seq, err = write(c, path, data)
+ }
+ return err
+ })
+ if seq != 0 {
+ updateCacheTime(ctxt.(appengine.Context), seq)
+ }
+ if err != nil {
+ err = fmt.Errorf("Write %q: %v", path, err)
+ }
+ return err
+}
+
+func (ae) Remove(ctxt interface{}, path string) error {
+ return fmt.Errorf("remove not implemented")
+}
+
+func (ae) Mkdir(ctxt interface{}, path string) error {
+ var seq int64
+ err := tx(ctxt, func(c appengine.Context) error {
+ var err error
+ _, seq, err = create(c, path, true, nil)
+ return err
+ })
+ if seq != 0 {
+ updateCacheTime(ctxt.(appengine.Context), seq)
+ }
+ if err != nil {
+ err = fmt.Errorf("Mkdir %q: %v", path, err)
+ }
+ return err
+}
+
+func (ae) Criticalf(ctxt interface{}, format string, args ...interface{}) {
+ ctxt.(appengine.Context).Criticalf(format, args...)
+}
+
+type readDirCacheEntry struct {
+ Dir []proto.FileInfo
+ Error string
+}
+
+func (ae) ReadDir(ctxt interface{}, name string) (dir []proto.FileInfo, err error) {
+ c := ctxt.(appengine.Context)
+ name = path.Clean("/"+name)
+ t, data, _, err := cacheRead(c, "dir", name, name)
+ if err == nil {
+ var e readDirCacheEntry
+ if err := json.Unmarshal(data, &e); err == nil {
+ if chatty {
+ c.Infof("cached ReadDir %q", name)
+ }
+ if e.Error != "" {
+ return nil, errors.New(e.Error)
+ }
+ return e.Dir, nil
+ }
+ c.Criticalf("unmarshal cached dir %q: %v", name)
+ }
+ err = tx(ctxt, func(c appengine.Context) error {
+ var err error
+ dir, err = readdirRaw(c, name)
+ return err
+ })
+ var e readDirCacheEntry
+ e.Dir = dir
+ if err != nil {
+ err = fmt.Errorf("ReadDir %q: %v", name, err)
+ e.Error = err.Error()
+ }
+ if data, err := json.Marshal(&e); err != nil {
+ c.Criticalf("json marshal cached dir: %v", err)
+ } else {
+ c.Criticalf("caching dir %q@%d %d bytes", name, t, len(data))
+ cacheWrite(c, t, "dir", name, data)
+ }
+ return
+}
+
+// Caching of file system data.
+//
+// The cache stores entries under keys of the form time,space,name,
+// where time is the time at which the entry is valid for, space is a name
+// space identifier, and name is an arbitrary name.
+//
+// A key of the form t,mtime,path maps to an integer value giving the
+// modification time of the named path at root time t.
+// The special key 0,mtime,/ is an integer giving the current time at the root.
+//
+// A key of the form t,data,path maps to the content of path at time t.
+//
+// Thus, a read from path should first obtain the root time,
+// then obtain the modification time for the path at that root time
+// then obtain the data for that path.
+// t1 = get(0,mtime,/)
+// t2 = get(t1,mtime,path)
+// data = get(t2,data,path)
+//
+// The API allows clients to cache their own data too, with expiry tied to
+// the modification time of a particular path (file or directory). To look
+// up one of those, we use:
+// t1 = get(0,mtime,/)
+// t2 = get(t1,mtime,path)
+// data = get(t2,clientdata,name)
+//
+// To store data in the cache, the t1, t2 should be determined before reading
+// from datastore. Then the data should be saved under t2. This ensures
+// that if a datastore update happens after the read but before the cache write,
+// we'll be writing to an entry that will no longer be used (t2).
+
+const rootMemcacheKey = "0,mtime,/"
+
+func updateCacheTime(c appengine.Context, seq int64) {
+ const key = rootMemcacheKey
+ bseq := []byte(strconv.FormatInt(seq, 10))
+ for tries := 0; tries < 10; tries++ {
+ item, err := memcache.Get(c, key)
+ if err != nil {
+ c.Infof("memcache.Get %q: %v", key, err)
+ err = memcache.Add(c, &memcache.Item{Key: key, Value: bseq})
+ if err == nil {
+ c.Infof("memcache.Add %q %q ok", key, bseq)
+ return
+ }
+ c.Infof("memcache.Add %q %q: %v", key, bseq, err)
+ }
+ v, err := strconv.ParseInt(string(item.Value), 10, 64)
+ if err != nil {
+ c.Criticalf("memcache.Get %q = %q (%v)", key, item.Value, err)
+ return
+ }
+ if v >= seq {
+ return
+ }
+ item.Value = bseq
+ err = memcache.CompareAndSwap(c, item)
+ if err == nil {
+ c.Infof("memcache.CAS %q %d->%d ok", key, v, seq)
+ return
+ }
+ c.Infof("memcache.CAS %q %d->%d: %v", key, v, seq, err)
+ }
+ c.Criticalf("repeatedly failed to update root key")
+}
+
+func cacheTime(c appengine.Context) (t int64, err error) {
+ const key = rootMemcacheKey
+ item, err := memcache.Get(c, key)
+ if err == nil {
+ v, err := strconv.ParseInt(string(item.Value), 10, 64)
+ if err == nil {
+ if chatty {
+ c.Infof("cacheTime %q = %v", key, v)
+ }
+ return v, nil
+ }
+ c.Criticalf("memcache.Get %q = %q (%v) - deleting", key, item.Value, err)
+ memcache.Delete(c, key)
+ }
+ fi, err := stat(c, "/")
+ if err != nil {
+ c.Criticalf("stat /: %v", err)
+ return 0, err
+ }
+ updateCacheTime(c, fi.Seq)
+ return fi.Seq, nil
+}
+
+func cachePathTime(c appengine.Context, path string) (t int64, err error) {
+ t, err = cacheTime(c)
+ if err != nil {
+ return 0, err
+ }
+
+ key := fmt.Sprintf("%d,mtime,%s", t, path)
+ item, err := memcache.Get(c, key)
+ if err == nil {
+ v, err := strconv.ParseInt(string(item.Value), 10, 64)
+ if err == nil {
+ if chatty {
+ c.Infof("cachePathTime %q = %v", key, v)
+ }
+ return v, nil
+ }
+ c.Criticalf("memcache.Get %q = %q (%v) - deleting", key, item.Value, err)
+ memcache.Delete(c, key)
+ }
+
+ var seq int64
+ if fi, err := stat(c, path); err == nil {
+ seq = fi.Seq
+ }
+
+ c.Infof("cachePathTime save %q = %v", key, seq)
+ item = &memcache.Item{Key: key, Value: []byte(strconv.FormatInt(seq, 10))}
+ if err := memcache.Set(c, item); err != nil {
+ c.Criticalf("memcache.Set %q %q: %v", key, item.Value, err)
+ }
+ return seq, nil
+}
+
+type statCacheEntry struct {
+ FileInfo *proto.FileInfo
+ Error string
+}
+
+func cacheRead(c appengine.Context, kind, name, path string) (mtime int64, data []byte, pfi *proto.FileInfo, err error) {
+ for tries := 0; tries < 10; tries++ {
+ t, err := cachePathTime(c, path)
+ if err != nil {
+ return 0, nil, nil, err
+ }
+
+ key := fmt.Sprintf("%d,%s,%s", t, kind, name)
+ item, err := memcache.Get(c, key)
+ var data []byte
+ if item != nil {
+ data = item.Value
+ }
+ if err != nil {
+ c.Infof("memcache miss %q %v", key, err)
+ } else if chatty {
+ c.Infof("memcache hit %q (%d bytes)", key, len(data))
+ }
+ if kind != "data" {
+ // Not a file; whatever memcache says is all we have.
+ return t, data, nil, err
+ }
+
+ // Load stat from cache (includes negative entry).
+ statkey := fmt.Sprintf("%d,stat,%s", t, name)
+ var st statCacheEntry
+ _, err = memcache.JSON.Get(c, statkey, &st)
+ if err == nil {
+ if st.Error != "" {
+ if chatty {
+ c.Infof("memcache hit stat error %q %q", statkey, st.Error)
+ }
+ err = errors.New(st.Error)
+ } else {
+ if chatty {
+ c.Infof("memcache hit stat %q", statkey)
+ }
+ }
+ if err != nil || data != nil {
+ return t, data, st.FileInfo, err
+ }
+ }
+
+ // Need stat, or maybe stat+data.
+ var fi *FileInfo
+ if data != nil {
+ c.Infof("stat %q", name)
+ fi, err = stat(c, name)
+ if err == nil && fi.Seq != t {
+ c.Criticalf("loaded %s but found stat %d", key, fi.Seq)
+ continue
+ }
+ } else {
+ c.Infof("read %q", name)
+ fi, data, err = read(c, name)
+ if err == nil && fi.Seq != t {
+ c.Infof("loaded %s but found read %d", key, fi.Seq)
+ t = fi.Seq
+ key = fmt.Sprintf("%d,data,%s", t, name)
+ statkey = fmt.Sprintf("%d,stat,%s", t, name)
+ }
+
+ // Save data to memcache.
+ if err == nil {
+ if true || chatty {
+ c.Infof("save data in memcache %q", key)
+ }
+ item := &memcache.Item{Key: key, Value: data}
+ if err := memcache.Set(c, item); err != nil {
+ c.Criticalf("failed to cache %s: %v", key, err)
+ }
+ }
+ }
+
+ // Cache stat, including error.
+ st = statCacheEntry{}
+ if fi != nil {
+ st.FileInfo = &proto.FileInfo{
+ Name: fi.Name,
+ ModTime: fi.ModTime,
+ Size: fi.Size,
+ IsDir: fi.IsDir,
+ }
+ }
+ if err != nil {
+ st.Error = err.Error()
+ // If this is a deadline exceeded, do not cache.
+ if strings.Contains(st.Error, "Canceled") || strings.Contains(st.Error, "Deadline") {
+ return t, data, st.FileInfo, err
+ }
+ }
+ if chatty {
+ c.Infof("save stat in memcache %q", statkey)
+ }
+ if err := memcache.JSON.Set(c, &memcache.Item{Key: statkey, Object: &st}); err != nil {
+ c.Criticalf("failed to cache %s: %v", statkey, err)
+ }
+
+ // Done!
+ return t, data, st.FileInfo, err
+ }
+
+ c.Criticalf("failed repeatedly in cacheRead")
+ return 0, nil, nil, errors.New("cacheRead loop failed")
+}
+
+func cacheWrite(c appengine.Context, t int64, kind, name string, data []byte) error {
+ mkey := fmt.Sprintf("%d,%s,%s", t, kind, name)
+ if true || chatty {
+ c.Infof("cacheWrite %s %d bytes", mkey, len(data))
+ }
+ err := memcache.Set(c, &memcache.Item{Key: mkey, Value: data})
+ if err != nil {
+ c.Criticalf("cacheWrite memcache.Set %q: %v", mkey, err)
+ }
+ return err
+}
diff --git a/vendor/github.com/mattermost/rsc/arq/arq.go b/vendor/github.com/mattermost/rsc/arq/arq.go
new file mode 100644
index 000000000..85a5138e9
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/arq/arq.go
@@ -0,0 +1,663 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package arq implements read-only access to Arq backups stored on S3.
+// Arq is a Mac backup tool (http://www.haystacksoftware.com/arq/)
+// but the package can read the backups regardless of operating system.
+package arq
+
+import (
+ "bytes"
+ "compress/gzip"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/mattermost/rsc/plist"
+ "launchpad.net/goamz/aws"
+ "launchpad.net/goamz/s3"
+)
+
+// A Conn represents a connection to an S3 server holding Arq backups.
+type Conn struct {
+ b *s3.Bucket
+ cache string
+ altCache string
+}
+
+// cachedir returns the canonical directory in which to cache data.
+func cachedir() string {
+ if runtime.GOOS == "darwin" {
+ return filepath.Join(os.Getenv("HOME"), "Library/Caches/arq-cache")
+ }
+ return filepath.Join(os.Getenv("HOME"), ".cache/arq-cache")
+}
+
+// Dial establishes a connection to an S3 server holding Arq backups.
+func Dial(auth aws.Auth) (*Conn, error) {
+ buck := fmt.Sprintf("%s-com-haystacksoftware-arq", strings.ToLower(auth.AccessKey))
+ b := s3.New(auth, aws.USEast).Bucket(buck)
+ c := &Conn{
+ b: b,
+ cache: filepath.Join(cachedir(), buck),
+ }
+ if runtime.GOOS == "darwin" {
+ c.altCache = filepath.Join(os.Getenv("HOME"), "Library/Arq/Cache.noindex/"+buck)
+ }
+
+ // Check that the bucket works by listing computers (relatively cheap).
+ if _, err := c.list("", "/", 10); err != nil {
+ return nil, err
+ }
+
+ // Create S3 lookaside cache directory.
+
+ return c, nil
+}
+
+func (c *Conn) list(prefix, delim string, max int) (*s3.ListResp, error) {
+ resp, err := c.b.List(prefix, delim, "", max)
+ if err != nil {
+ return nil, err
+ }
+ ret := resp
+ for max == 0 && resp.IsTruncated {
+ last := resp.Contents[len(resp.Contents)-1].Key
+ resp, err = c.b.List(prefix, delim, last, max)
+ if err != nil {
+ return ret, err
+ }
+ ret.Contents = append(ret.Contents, resp.Contents...)
+ ret.CommonPrefixes = append(ret.CommonPrefixes, resp.CommonPrefixes...)
+ }
+ return ret, nil
+}
+
+func (c *Conn) altCachePath(name string) string {
+ if c.altCache == "" || !strings.Contains(name, "/packsets/") {
+ return ""
+ }
+ i := strings.Index(name, "-trees/")
+ if i < 0 {
+ i = strings.Index(name, "-blobs/")
+ if i < 0 {
+ return ""
+ }
+ }
+ i += len("-trees/") + 2
+ if i >= len(name) {
+ return ""
+ }
+ return filepath.Join(c.altCache, name[:i]+"/"+name[i:])
+}
+
+func (c *Conn) cget(name string) (data []byte, err error) {
+ cache := filepath.Join(c.cache, name)
+ f, err := os.Open(cache)
+ if err == nil {
+ defer f.Close()
+ return ioutil.ReadAll(f)
+ }
+ if altCache := c.altCachePath(name); altCache != "" {
+ f, err := os.Open(altCache)
+ if err == nil {
+ defer f.Close()
+ return ioutil.ReadAll(f)
+ }
+ }
+
+ data, err = c.bget(name)
+ if err != nil {
+ return nil, err
+ }
+
+ dir, _ := filepath.Split(cache)
+ os.MkdirAll(dir, 0700)
+ ioutil.WriteFile(cache, data, 0600)
+ return data, nil
+}
+
+func (c *Conn) bget(name string) (data []byte, err error) {
+ for i := 0; ; {
+ data, err = c.b.Get(name)
+ if err == nil {
+ break
+ }
+ if i++; i >= 5 {
+ return nil, err
+ }
+ log.Print(err)
+ }
+ return data, nil
+}
+
+func (c *Conn) DeleteCache() {
+ os.RemoveAll(c.cache)
+}
+
+// Computers returns a list of the computers with backups available on the S3 server.
+func (c *Conn) Computers() ([]*Computer, error) {
+ // Each backup is a top-level directory with a computerinfo file in it.
+ list, err := c.list("", "/", 0)
+ if err != nil {
+ return nil, err
+ }
+ var out []*Computer
+ for _, p := range list.CommonPrefixes {
+ data, err := c.bget(p + "computerinfo")
+ if err != nil {
+ continue
+ }
+ var info computerInfo
+ if err := plist.Unmarshal(data, &info); err != nil {
+ return nil, err
+ }
+
+ comp := &Computer{
+ Name: info.ComputerName,
+ User: info.UserName,
+ UUID: p[:len(p)-1],
+ conn: c,
+ index: map[score]ientry{},
+ }
+
+ salt, err := c.cget(p + "salt")
+ if err != nil {
+ return nil, err
+ }
+ comp.crypto.salt = salt
+
+ out = append(out, comp)
+ }
+ return out, nil
+}
+
+// A Computer represents a computer with backups (Folders).
+type Computer struct {
+ Name string // name of computer
+ User string // name of user
+ UUID string
+ conn *Conn
+ crypto cryptoState
+ index map[score]ientry
+}
+
+// Folders returns a list of the folders that have been backed up on the computer.
+func (c *Computer) Folders() ([]*Folder, error) {
+ // Each folder is a file under computer/buckets/.
+ list, err := c.conn.list(c.UUID+"/buckets/", "", 0)
+ if err != nil {
+ return nil, err
+ }
+ var out []*Folder
+ for _, obj := range list.Contents {
+ data, err := c.conn.bget(obj.Key)
+ if err != nil {
+ return nil, err
+ }
+ var info folderInfo
+ if err := plist.Unmarshal(data, &info); err != nil {
+ return nil, err
+ }
+ out = append(out, &Folder{
+ Path: info.LocalPath,
+ uuid: info.BucketUUID,
+ comp: c,
+ conn: c.conn,
+ })
+ }
+ return out, nil
+}
+
+// Unlock records the password to use when decrypting
+// backups from this computer. It must be called before calling Trees
+// in any folder obtained for this computer.
+func (c *Computer) Unlock(pw string) {
+ c.crypto.unlock(pw)
+}
+
+func (c *Computer) scget(sc score) ([]byte, error) {
+ if c.crypto.c == nil {
+ return nil, fmt.Errorf("computer not yet unlocked")
+ }
+
+ var data []byte
+ var err error
+ ie, ok := c.index[sc]
+ if ok {
+ data, err = c.conn.cget(ie.File)
+ if err != nil {
+ return nil, err
+ }
+
+ //fmt.Printf("offset size %d %d\n", ie.Offset, ie.Size)
+ if len(data) < int(ie.Offset+ie.Size) {
+ return nil, fmt.Errorf("short pack block")
+ }
+
+ data = data[ie.Offset:]
+ if ie.Size < 1+8+1+8+8 {
+ return nil, fmt.Errorf("short pack block")
+ }
+
+ bo := binary.BigEndian
+
+ if data[0] != 1 {
+ return nil, fmt.Errorf("missing mime type")
+ }
+ n := bo.Uint64(data[1:])
+ if 1+8+n > uint64(len(data)) {
+ return nil, fmt.Errorf("malformed mime type")
+ }
+ mimeType := data[1+8 : 1+8+n]
+ data = data[1+8+n:]
+
+ n = bo.Uint64(data[1:])
+ if 1+8+n > uint64(len(data)) {
+ return nil, fmt.Errorf("malformed name")
+ }
+ name := data[1+8 : 1+8+n]
+ data = data[1+8+n:]
+
+ _, _ = mimeType, name
+ // fmt.Printf("%s %s\n", mimeType, name)
+
+ n = bo.Uint64(data[0:])
+ if int64(n) != ie.Size {
+ return nil, fmt.Errorf("unexpected data length %d %d", n, ie.Size)
+ }
+ if 8+n > uint64(len(data)) {
+ return nil, fmt.Errorf("short data %d %d", 8+n, len(data))
+ }
+
+ data = data[8 : 8+n]
+ } else {
+ data, err = c.conn.cget(c.UUID + "/objects/" + sc.String())
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ data = c.crypto.decrypt(data)
+ return data, nil
+}
+
+// A Folder represents a backed-up tree on a computer.
+type Folder struct {
+ Path string // root of tree of last backup
+ uuid string
+ comp *Computer
+ conn *Conn
+}
+
+// Load loads xxx
+func (f *Folder) Load() error {
+ if err := f.comp.loadPack(f.uuid, "-trees"); err != nil {
+ return err
+ }
+ if err := f.comp.loadPack(f.uuid, "-blobs"); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (c *Computer) loadPack(fold, suf string) error {
+ list, err := c.conn.list(c.UUID+"/packsets/"+fold+suf+"/", "", 0)
+ if err != nil {
+ return err
+ }
+
+ for _, obj := range list.Contents {
+ if !strings.HasSuffix(obj.Key, ".index") {
+ continue
+ }
+ data, err := c.conn.cget(obj.Key)
+ if err != nil {
+ return err
+ }
+ // fmt.Printf("pack %s\n", obj.Key)
+ c.saveIndex(obj.Key[:len(obj.Key)-len(".index")]+".pack", data)
+ }
+ return nil
+}
+
+func (c *Computer) saveIndex(file string, data []byte) error {
+ const (
+ headerSize = 4 + 4 + 4*256
+ entrySize = 8 + 8 + 20 + 4
+ trailerSize = 20
+ )
+ bo := binary.BigEndian
+ if len(data) < headerSize+trailerSize {
+ return fmt.Errorf("short index")
+ }
+ i := len(data) - trailerSize
+ sum1 := sha(data[:i])
+ sum2 := binaryScore(data[i:])
+ if !sum1.Equal(sum2) {
+ return fmt.Errorf("invalid sha index")
+ }
+
+ obj := data[headerSize : len(data)-trailerSize]
+ n := len(obj) / entrySize
+ if n*entrySize != len(obj) {
+ return fmt.Errorf("misaligned index %d %d", n*entrySize, len(obj))
+ }
+ nn := bo.Uint32(data[headerSize-4:])
+ if int(nn) != n {
+ return fmt.Errorf("inconsistent index %d %d\n", nn, n)
+ }
+
+ for i := 0; i < n; i++ {
+ e := obj[i*entrySize:]
+ var ie ientry
+ ie.File = file
+ ie.Offset = int64(bo.Uint64(e[0:]))
+ ie.Size = int64(bo.Uint64(e[8:]))
+ ie.Score = binaryScore(e[16:])
+ c.index[ie.Score] = ie
+ }
+ return nil
+}
+
+// Trees returns a list of the individual backup snapshots for the folder.
+// Note that different trees from the same Folder might have different Paths
+// if the folder was "relocated" using the Arq interface.
+func (f *Folder) Trees() ([]*Tree, error) {
+ data, err := f.conn.bget(f.comp.UUID + "/bucketdata/" + f.uuid + "/refs/heads/master")
+ if err != nil {
+ return nil, err
+ }
+ sc := hexScore(string(data))
+ if err != nil {
+ return nil, err
+ }
+
+ var out []*Tree
+ for {
+ data, err = f.comp.scget(sc)
+ if err != nil {
+ return nil, err
+ }
+
+ var com commit
+ if err := unpack(data, &com); err != nil {
+ return nil, err
+ }
+
+ var info folderInfo
+ if err := plist.Unmarshal(com.BucketXML, &info); err != nil {
+ return nil, err
+ }
+
+ t := &Tree{
+ Time: com.CreateTime,
+ Path: info.LocalPath,
+ Score: com.Tree.Score,
+
+ commit: com,
+ comp: f.comp,
+ folder: f,
+ info: info,
+ }
+ out = append(out, t)
+
+ if len(com.ParentCommits) == 0 {
+ break
+ }
+
+ sc = com.ParentCommits[0].Score
+ }
+
+ for i, n := 0, len(out)-1; i < n-i; i++ {
+ out[i], out[n-i] = out[n-i], out[i]
+ }
+ return out, nil
+}
+
+func (f *Folder) Trees2() ([]*Tree, error) {
+ list, err := f.conn.list(f.comp.UUID+"/bucketdata/"+f.uuid+"/refs/logs/master/", "", 0)
+ if err != nil {
+ return nil, err
+ }
+
+ var out []*Tree
+ for _, obj := range list.Contents {
+ data, err := f.conn.cget(obj.Key)
+ if err != nil {
+ return nil, err
+ }
+ var l reflog
+ if err := plist.Unmarshal(data, &l); err != nil {
+ return nil, err
+ }
+
+ sc := hexScore(l.NewHeadSHA1)
+ if err != nil {
+ return nil, err
+ }
+
+ data, err = f.comp.scget(sc)
+ if err != nil {
+ return nil, err
+ }
+
+ var com commit
+ if err := unpack(data, &com); err != nil {
+ return nil, err
+ }
+
+ var info folderInfo
+ if err := plist.Unmarshal(com.BucketXML, &info); err != nil {
+ return nil, err
+ }
+
+ t := &Tree{
+ Time: com.CreateTime,
+ Path: info.LocalPath,
+ Score: com.Tree.Score,
+
+ commit: com,
+ comp: f.comp,
+ folder: f,
+ info: info,
+ }
+ out = append(out, t)
+ }
+ return out, nil
+}
+
+// A Tree represents a single backed-up file tree snapshot.
+type Tree struct {
+ Time time.Time // time back-up completed
+ Path string // root of backed-up tree
+ Score [20]byte
+
+ comp *Computer
+ folder *Folder
+ commit commit
+ info folderInfo
+
+ raw tree
+ haveRaw bool
+}
+
+// Root returns the File for the tree's root directory.
+func (t *Tree) Root() (*File, error) {
+ if !t.haveRaw {
+ data, err := t.comp.scget(t.Score)
+ if err != nil {
+ return nil, err
+ }
+ if err := unpack(data, &t.raw); err != nil {
+ return nil, err
+ }
+ t.haveRaw = true
+ }
+
+ dir := &File{
+ t: t,
+ dir: &t.raw,
+ n: &nameNode{"/", node{IsTree: true}},
+ }
+ return dir, nil
+}
+
+// A File represents a file or directory in a tree.
+type File struct {
+ t *Tree
+ n *nameNode
+ dir *tree
+ byName map[string]*nameNode
+}
+
+func (f *File) loadDir() error {
+ if f.dir == nil {
+ data, err := f.t.comp.scget(f.n.Node.Blob[0].Score)
+ if err != nil {
+ return err
+ }
+ var dir tree
+ if err := unpack(data, &dir); err != nil {
+ return err
+ }
+ f.dir = &dir
+ }
+ return nil
+}
+
+func (f *File) Lookup(name string) (*File, error) {
+ if !f.n.Node.IsTree {
+ return nil, fmt.Errorf("lookup in non-directory")
+ }
+ if f.byName == nil {
+ if err := f.loadDir(); err != nil {
+ return nil, err
+ }
+ f.byName = map[string]*nameNode{}
+ for _, n := range f.dir.Nodes {
+ f.byName[n.Name] = n
+ }
+ }
+ n := f.byName[name]
+ if n == nil {
+ return nil, fmt.Errorf("no entry %q", name)
+ }
+ return &File{t: f.t, n: n}, nil
+}
+
+func (f *File) Stat() *Dirent {
+ if f.n.Node.IsTree {
+ if err := f.loadDir(); err == nil {
+ return &Dirent{
+ Name: f.n.Name,
+ ModTime: f.dir.Mtime.Time(),
+ Mode: fileMode(f.dir.Mode),
+ Size: 0,
+ }
+ }
+ }
+ return &Dirent{
+ Name: f.n.Name,
+ ModTime: f.n.Node.Mtime.Time(),
+ Mode: fileMode(f.n.Node.Mode),
+ Size: int64(f.n.Node.UncompressedSize),
+ }
+}
+
+type Dirent struct {
+ Name string
+ ModTime time.Time
+ Mode os.FileMode
+ Size int64
+}
+
+func (f *File) ReadDir() ([]Dirent, error) {
+ if !f.n.Node.IsTree {
+ return nil, fmt.Errorf("ReadDir in non-directory")
+ }
+ if err := f.loadDir(); err != nil {
+ return nil, err
+ }
+ var out []Dirent
+ for _, n := range f.dir.Nodes {
+ out = append(out, Dirent{
+ Name: n.Name,
+ ModTime: n.Node.Mtime.Time(),
+ Mode: fileMode(n.Node.Mode),
+ })
+ }
+ return out, nil
+}
+
+func (f *File) Open() (io.ReadCloser, error) {
+ return &fileReader{t: f.t, blob: f.n.Node.Blob, n: &f.n.Node}, nil
+}
+
+type fileReader struct {
+ t *Tree
+ n *node
+ blob []sscore
+ cur io.Reader
+ close []io.Closer
+}
+
+func (f *fileReader) Read(b []byte) (int, error) {
+ for {
+ if f.cur != nil {
+ n, err := f.cur.Read(b)
+ if n > 0 || err != nil && err != io.EOF {
+ return n, err
+ }
+ for _, cl := range f.close {
+ cl.Close()
+ }
+ f.close = f.close[:0]
+ f.cur = nil
+ }
+
+ if len(f.blob) == 0 {
+ break
+ }
+
+ // TODO: Get a direct reader, not a []byte.
+ data, err := f.t.comp.scget(f.blob[0].Score)
+ if err != nil {
+ return 0, err
+ }
+ rc := ioutil.NopCloser(bytes.NewBuffer(data))
+
+ if f.n.CompressData {
+ gz, err := gzip.NewReader(rc)
+ if err != nil {
+ rc.Close()
+ return 0, err
+ }
+ f.close = append(f.close, gz)
+ f.cur = gz
+ } else {
+ f.cur = rc
+ }
+ f.close = append(f.close, rc)
+ f.blob = f.blob[1:]
+ }
+
+ return 0, io.EOF
+}
+
+func (f *fileReader) Close() error {
+ for _, cl := range f.close {
+ cl.Close()
+ }
+ f.close = f.close[:0]
+ f.cur = nil
+ return nil
+}
diff --git a/vendor/github.com/mattermost/rsc/arq/arqfs/main.go b/vendor/github.com/mattermost/rsc/arq/arqfs/main.go
new file mode 100644
index 000000000..9e9001133
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/arq/arqfs/main.go
@@ -0,0 +1,247 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Arqfs implements a file system interface to a collection of Arq backups.
+
+ usage: arqfs [-m mtpt]
+
+Arqfs mounts the Arq backups on the file system directory mtpt,
+(default /mnt/arq). The directory must exist and be writable by
+the current user.
+
+Arq
+
+Arq is an Amazon S3-based backup system for OS X and sold by
+Haystack Software (http://www.haystacksoftware.com/arq/).
+This software reads backups written by Arq.
+It is not affiliated with or connected to Haystack Software.
+
+Passwords
+
+Arqfs reads necessary passwords from the OS X keychain.
+It expects at least two entries:
+
+The keychain entry for s3.amazonaws.com should list the Amazon S3 access ID
+as user name and the S3 secret key as password.
+
+Each backup being accessed must have its own keychain entry for
+host arq.swtch.com, listing the backup UUID as user name and the encryption
+password as the password.
+
+Arqfs will not prompt for passwords or create these entries itself: they must
+be created using the Keychain Access application.
+
+FUSE
+
+Arqfs creates a virtual file system using the FUSE file system layer.
+On OS X, it requires OSXFUSE (http://osxfuse.github.com/).
+
+Cache
+
+Reading the Arq backups efficiently requires caching directory tree information
+on local disk instead of reading the same data from S3 repeatedly. Arqfs caches
+data downloaded from S3 in $HOME/Library/Caches/arq-cache/.
+If an Arq installation is present on the same machine, arqfs will look in
+its cache ($HOME/Library/Arq/Cache.noindex) first, but arqfs will not
+write to Arq's cache directory.
+
+Bugs
+
+Arqfs only runs on OS X for now, because both FUSE and the keychain access
+packages have not been ported to other systems yet.
+
+Both Arqfs and the FUSE package on which it is based have seen only light
+use. There are likely to be bugs. Mail rsc@swtch.com with reports.
+
+*/
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "syscall"
+
+ "github.com/mattermost/rsc/arq"
+ "github.com/mattermost/rsc/fuse"
+ "github.com/mattermost/rsc/keychain"
+ "launchpad.net/goamz/aws"
+)
+
+var mtpt = flag.String("m", "/mnt/arq", "")
+
+func main() {
+ log.SetFlags(0)
+
+ if len(os.Args) == 3 && os.Args[1] == "MOUNTSLAVE" {
+ *mtpt = os.Args[2]
+ mountslave()
+ return
+ }
+
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, "usage: arqfs [-m /mnt/arq]\n")
+ os.Exit(2)
+ }
+ flag.Parse()
+ if len(flag.Args()) != 0 {
+ flag.Usage()
+ }
+
+ // Run in child so that we can exit once child is running.
+ r, w, err := os.Pipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ cmd := exec.Command(os.Args[0], "MOUNTSLAVE", *mtpt)
+ cmd.Stdout = w
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ log.Fatalf("mount process: %v", err)
+ }
+ w.Close()
+
+ buf := make([]byte, 10)
+ n, _ := r.Read(buf)
+ if n != 2 || string(buf[0:2]) != "OK" {
+ os.Exit(1)
+ }
+
+ fmt.Fprintf(os.Stderr, "mounted on %s\n", *mtpt)
+}
+
+func mountslave() {
+ stdout, _ := syscall.Dup(1)
+ syscall.Dup2(2, 1)
+
+ access, secret, err := keychain.UserPasswd("s3.amazonaws.com", "")
+ if err != nil {
+ log.Fatal(err)
+ }
+ auth := aws.Auth{AccessKey: access, SecretKey: secret}
+
+ conn, err := arq.Dial(auth)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ comps, err := conn.Computers()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fs := &fuse.Tree{}
+ for _, c := range comps {
+ fmt.Fprintf(os.Stderr, "scanning %s...\n", c.Name)
+
+ // TODO: Better password protocol.
+ _, pw, err := keychain.UserPasswd("arq.swtch.com", c.UUID)
+ if err != nil {
+ log.Fatal(err)
+ }
+ c.Unlock(pw)
+
+ folders, err := c.Folders()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ lastDate := ""
+ n := 0
+ for _, f := range folders {
+ if err := f.Load(); err != nil {
+ log.Fatal(err)
+ }
+ trees, err := f.Trees()
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, t := range trees {
+ y, m, d := t.Time.Date()
+ date := fmt.Sprintf("%04d/%02d%02d", y, m, d)
+ suffix := ""
+ if date == lastDate {
+ n++
+ suffix = fmt.Sprintf(".%d", n)
+ } else {
+ n = 0
+ }
+ lastDate = date
+ f, err := t.Root()
+ if err != nil {
+ log.Print(err)
+ }
+ // TODO: Pass times to fs.Add.
+ // fmt.Fprintf(os.Stderr, "%v %s %x\n", t.Time, c.Name+"/"+date+suffix+"/"+t.Path, t.Score)
+ fs.Add(c.Name+"/"+date+suffix+"/"+t.Path, &fuseNode{f})
+ }
+ }
+ }
+
+ fmt.Fprintf(os.Stderr, "mounting...\n")
+
+ c, err := fuse.Mount(*mtpt)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer exec.Command("umount", *mtpt).Run()
+
+ syscall.Write(stdout, []byte("OK"))
+ syscall.Close(stdout)
+ c.Serve(fs)
+}
+
+type fuseNode struct {
+ arq *arq.File
+}
+
+func (f *fuseNode) Attr() fuse.Attr {
+ de := f.arq.Stat()
+ return fuse.Attr{
+ Mode: de.Mode,
+ Mtime: de.ModTime,
+ Size: uint64(de.Size),
+ }
+}
+
+func (f *fuseNode) Lookup(name string, intr fuse.Intr) (fuse.Node, fuse.Error) {
+ ff, err := f.arq.Lookup(name)
+ if err != nil {
+ return nil, fuse.ENOENT
+ }
+ return &fuseNode{ff}, nil
+}
+
+func (f *fuseNode) ReadDir(intr fuse.Intr) ([]fuse.Dirent, fuse.Error) {
+ adir, err := f.arq.ReadDir()
+ if err != nil {
+ return nil, fuse.EIO
+ }
+ var dir []fuse.Dirent
+ for _, ade := range adir {
+ dir = append(dir, fuse.Dirent{
+ Name: ade.Name,
+ })
+ }
+ return dir, nil
+}
+
+// TODO: Implement Read+Release, not ReadAll, to avoid giant buffer.
+func (f *fuseNode) ReadAll(intr fuse.Intr) ([]byte, fuse.Error) {
+ rc, err := f.arq.Open()
+ if err != nil {
+ return nil, fuse.EIO
+ }
+ defer rc.Close()
+ data, err := ioutil.ReadAll(rc)
+ if err != nil {
+ return data, fuse.EIO
+ }
+ return data, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/arq/crypto.go b/vendor/github.com/mattermost/rsc/arq/crypto.go
new file mode 100644
index 000000000..e567ec36d
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/arq/crypto.go
@@ -0,0 +1,93 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package arq
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/sha1"
+ "hash"
+ "log"
+
+ "bitbucket.org/taruti/pbkdf2.go" // TODO: Pull in copy
+)
+
+type cryptoState struct {
+ c cipher.Block
+ iv []byte
+ salt []byte
+}
+
+func (c *cryptoState) unlock(pw string) {
+ const (
+ iter = 1000
+ keyLen = 48
+ aesKeyLen = 32
+ aesIVLen = 16
+ )
+ key1 := pbkdf2.Pbkdf2([]byte(pw), c.salt, iter, sha1.New, keyLen)
+ var key2 []byte
+ key2, c.iv = bytesToKey(sha1.New, c.salt, key1, iter, aesKeyLen, aesIVLen)
+ c.c, _ = aes.NewCipher(key2)
+}
+
+func (c *cryptoState) decrypt(data []byte) []byte {
+ dec := cipher.NewCBCDecrypter(c.c, c.iv)
+ if len(data)%aes.BlockSize != 0 {
+ log.Fatal("bad block")
+ }
+ dec.CryptBlocks(data, data)
+ // fmt.Printf("% x\n", data)
+ // fmt.Printf("%s\n", data)
+
+ // unpad
+ {
+ n := len(data)
+ p := int(data[n-1])
+ if p == 0 || p > aes.BlockSize {
+ log.Fatal("impossible padding")
+ }
+ for i := 0; i < p; i++ {
+ if data[n-1-i] != byte(p) {
+ log.Fatal("bad padding")
+ }
+ }
+ data = data[:n-p]
+ }
+ return data
+}
+
+func sha(data []byte) score {
+ h := sha1.New()
+ h.Write(data)
+ var sc score
+ copy(sc[:], h.Sum(nil))
+ return sc
+}
+
+func bytesToKey(hf func() hash.Hash, salt, data []byte, iter int, keySize, ivSize int) (key, iv []byte) {
+ h := hf()
+ var d, dcat []byte
+ sum := make([]byte, 0, h.Size())
+ for len(dcat) < keySize+ivSize {
+ // D_i = HASH^count(D_(i-1) || data || salt)
+ h.Reset()
+ h.Write(d)
+ h.Write(data)
+ h.Write(salt)
+ sum = h.Sum(sum[:0])
+
+ for j := 1; j < iter; j++ {
+ h.Reset()
+ h.Write(sum)
+ sum = h.Sum(sum[:0])
+ }
+
+ d = append(d[:0], sum...)
+ dcat = append(dcat, d...)
+ }
+
+ return dcat[:keySize], dcat[keySize : keySize+ivSize]
+}
diff --git a/vendor/github.com/mattermost/rsc/arq/data.go b/vendor/github.com/mattermost/rsc/arq/data.go
new file mode 100644
index 000000000..74eaba450
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/arq/data.go
@@ -0,0 +1,240 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// On-cloud data structures
+
+package arq
+
+import (
+ "fmt"
+ "os"
+ "time"
+)
+
+// plist data structures
+
+type computerInfo struct {
+ UserName string `plist:"userName"`
+ ComputerName string `plist:"computerName"`
+}
+
+type folderInfo struct {
+ BucketUUID string
+ BucketName string
+ ComputerUUID string
+ LocalPath string
+ LocalMountPoint string
+ // don't care about IgnoredRelativePaths or Excludes
+}
+
+type reflog struct {
+ OldHeadSHA1 string `plist:"oldHeadSHA1"`
+ NewHeadSHA1 string `plist:"newHeadSHA1"`
+}
+
+// binary data structures
+
+type score [20]byte
+
+type sscore struct {
+ Score score `arq:"HexScore"`
+ StretchKey bool // v4+
+}
+
+type tag string
+
+type commit struct {
+ Tag tag `arq:"CommitV005"`
+ Author string
+ Comment string
+ ParentCommits []sscore
+ Tree sscore
+ Location string
+ MergeCommonAncestor sscore
+ CreateTime time.Time
+ Failed []failed // v3+
+ BucketXML []byte // v5+
+}
+
+type tree struct {
+ Tag tag `arq:"TreeV015"`
+ CompressXattr bool
+ CompressACL bool
+ Xattr sscore
+ XattrSize uint64
+ ACL sscore
+ Uid int32
+ Gid int32
+ Mode int32
+ Mtime unixTime
+ Flags int64
+ FinderFlags int32
+ XFinderFlags int32
+ StDev int32
+ StIno int32
+ StNlink uint32
+ StRdev int32
+ Ctime unixTime
+ StBlocks int64
+ StBlksize uint32
+ AggrSize uint64
+ Crtime unixTime
+ Nodes []*nameNode `arq:"count32"`
+}
+
+type nameNode struct {
+ Name string
+ Node node
+}
+
+type node struct {
+ IsTree bool
+ CompressData bool
+ CompressXattr bool
+ CompressACL bool
+ Blob []sscore `arq:"count32"`
+ UncompressedSize uint64
+ Thumbnail sscore
+ Preview sscore
+ Xattr sscore
+ XattrSize uint64
+ ACL sscore
+ Uid int32
+ Gid int32
+ Mode int32
+ Mtime unixTime
+ Flags int64
+ FinderFlags int32
+ XFinderFlags int32
+ FinderFileType string
+ FinderFileCreator string
+ IsExtHidden bool
+ StDev int32
+ StIno int32
+ StNlink uint32
+ StRdev int32
+ Ctime unixTime
+ CreateTime unixTime
+ StBlocks int64
+ StBlksize uint32
+}
+
+func fileMode(m int32) os.FileMode {
+ const (
+ // Darwin file mode.
+ S_IFBLK = 0x6000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFIFO = 0x1000
+ S_IFLNK = 0xa000
+ S_IFMT = 0xf000
+ S_IFREG = 0x8000
+ S_IFSOCK = 0xc000
+ S_IFWHT = 0xe000
+ S_ISGID = 0x400
+ S_ISTXT = 0x200
+ S_ISUID = 0x800
+ S_ISVTX = 0x200
+ )
+ mode := os.FileMode(m & 0777)
+ switch m & S_IFMT {
+ case S_IFBLK, S_IFWHT:
+ mode |= os.ModeDevice
+ case S_IFCHR:
+ mode |= os.ModeDevice | os.ModeCharDevice
+ case S_IFDIR:
+ mode |= os.ModeDir
+ case S_IFIFO:
+ mode |= os.ModeNamedPipe
+ case S_IFLNK:
+ mode |= os.ModeSymlink
+ case S_IFREG:
+ // nothing to do
+ case S_IFSOCK:
+ mode |= os.ModeSocket
+ }
+ if m&S_ISGID != 0 {
+ mode |= os.ModeSetgid
+ }
+ if m&S_ISUID != 0 {
+ mode |= os.ModeSetuid
+ }
+ if m&S_ISVTX != 0 {
+ mode |= os.ModeSticky
+ }
+ return mode
+}
+
+type unixTime struct {
+ Sec int64
+ Nsec int64
+}
+
+func (t *unixTime) Time() time.Time {
+ return time.Unix(t.Sec, t.Nsec)
+}
+
+type failed struct {
+ Path string
+ Error string
+}
+
+type ientry struct {
+ File string
+ Offset int64
+ Size int64
+ Score score
+}
+
+func (s score) Equal(t score) bool {
+ for i := range s {
+ if s[i] != t[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func (s score) String() string {
+ return fmt.Sprintf("%x", s[:])
+}
+
+func binaryScore(b []byte) score {
+ if len(b) < 20 {
+ panic("BinaryScore: not enough data")
+ }
+ var sc score
+ copy(sc[:], b)
+ return sc
+}
+
+func hexScore(b string) score {
+ if len(b) < 40 {
+ panic("HexScore: not enough data")
+ }
+ var sc score
+ for i := 0; i < 40; i++ {
+ ch := b[i]
+ if '0' <= ch && ch <= '9' {
+ ch -= '0'
+ } else if 'a' <= ch && ch <= 'f' {
+ ch -= 'a' - 10
+ } else {
+ panic("HexScore: invalid lower hex digit")
+ }
+ if i%2 == 0 {
+ ch <<= 4
+ }
+ sc[i/2] |= ch
+ }
+ return sc
+}
+
+func (ss sscore) String() string {
+ str := ss.Score.String()
+ if ss.StretchKey {
+ str += "Y"
+ }
+ return str
+}
diff --git a/vendor/github.com/mattermost/rsc/arq/hist/hist.go b/vendor/github.com/mattermost/rsc/arq/hist/hist.go
new file mode 100644
index 000000000..02fb5fbf0
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/arq/hist/hist.go
@@ -0,0 +1,160 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Hist shows the history of a given file, using Arq backups.
+
+ usage: hist [-d] [-h host] [-m mtpt] [-s yyyy/mmdd] file ...
+
+The -d flag causes it to show diffs between successive versions.
+
+By default, hist assumes backups are mounted at mtpt/host, where
+mtpt defaults to /mnt/arq and host is the first element of the local host name.
+Hist starts the file list with the present copy of the file.
+
+The -h and -s flags override these assumptions.
+
+*/
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+var usageString = `usage: hist [-d] [-h host] [-m mtpt] [-s yyyy/mmdd] file ...
+
+Hist lists the known versions of the given file.
+The -d flag causes it to show diffs between successive versions.
+
+By default, hist assumes backups are mounted at mtpt/host, where
+mtpt defaults to /mnt/arq and host is the first element of the local host name.
+Hist starts the file list with the present copy of the file.
+
+The -h and -s flags override these assumptions.
+`
+
+var (
+ diff = flag.Bool("d", false, "diff")
+ host = flag.String("h", defaultHost(), "host name")
+ mtpt = flag.String("m", "/mnt/arq", "mount point")
+ vers = flag.String("s", "", "version")
+)
+
+func defaultHost() string {
+ name, _ := os.Hostname()
+ if name == "" {
+ name = "gnot"
+ }
+ if i := strings.Index(name, "."); i >= 0 {
+ name = name[:i]
+ }
+ return name
+}
+
+func main() {
+ flag.Usage = func() {
+ fmt.Fprint(os.Stderr, usageString)
+ os.Exit(2)
+ }
+
+ flag.Parse()
+ args := flag.Args()
+ if len(args) == 0 {
+ flag.Usage()
+ }
+
+ dates := loadDates()
+ for _, file := range args {
+ list(dates, file)
+ }
+}
+
+var (
+ yyyy = regexp.MustCompile(`^\d{4}$`)
+ mmdd = regexp.MustCompile(`^\d{4}(\.\d+)?$`)
+)
+
+func loadDates() []string {
+ var all []string
+ ydir, err := ioutil.ReadDir(filepath.Join(*mtpt, *host))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ os.Exit(3)
+ }
+ for _, y := range ydir {
+ if !y.IsDir() || !yyyy.MatchString(y.Name()) {
+ continue
+ }
+ ddir, err := ioutil.ReadDir(filepath.Join(*mtpt, *host, y.Name()))
+ if err != nil {
+ continue
+ }
+ for _, d := range ddir {
+ if !d.IsDir() || !mmdd.MatchString(d.Name()) {
+ continue
+ }
+ date := y.Name() + "/" + d.Name()
+ if *vers > date {
+ continue
+ }
+ all = append(all, filepath.Join(*mtpt, *host, date))
+ }
+ }
+ return all
+}
+
+const timeFormat = "Jan 02 15:04:05 MST 2006"
+
+func list(dates []string, file string) {
+ var (
+ last os.FileInfo
+ lastPath string
+ )
+
+ fi, err := os.Stat(file)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "hist: warning: %s: %v\n", file, err)
+ } else {
+ fmt.Printf("%s %s %d\n", fi.ModTime().Format(timeFormat), file, fi.Size())
+ last = fi
+ lastPath = file
+ }
+
+ file, err = filepath.Abs(file)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "hist: abs: %v\n", err)
+ return
+ }
+
+ for i := len(dates)-1; i >= 0; i-- {
+ p := filepath.Join(dates[i], file)
+ fi, err := os.Stat(p)
+ if err != nil {
+ continue
+ }
+ if last != nil && fi.ModTime() == last.ModTime() && fi.Size() == last.Size() {
+ continue
+ }
+ if *diff {
+ cmd := exec.Command("diff", lastPath, p)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ }
+ cmd.Wait()
+ }
+ fmt.Printf("%s %s %d\n", fi.ModTime().Format(timeFormat), p, fi.Size())
+ last = fi
+ lastPath = p
+ }
+}
+
diff --git a/vendor/github.com/mattermost/rsc/arq/unpack.go b/vendor/github.com/mattermost/rsc/arq/unpack.go
new file mode 100644
index 000000000..ec4296a7c
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/arq/unpack.go
@@ -0,0 +1,227 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Parsing of Arq's binary data structures.
+
+package arq
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "reflect"
+ "time"
+)
+
+var errMalformed = fmt.Errorf("malformed data")
+var tagType = reflect.TypeOf(tag(""))
+var timeType = reflect.TypeOf(time.Time{})
+var scoreType = reflect.TypeOf(score{})
+
+func unpack(data []byte, v interface{}) error {
+ data, err := unpackValue(data, reflect.ValueOf(v).Elem(), "")
+ if err != nil {
+ return err
+ }
+ if len(data) != 0 {
+ if len(data) > 100 {
+ return fmt.Errorf("more data than expected: %x...", data[:100])
+ }
+ return fmt.Errorf("more data than expected: %x", data)
+ }
+ return nil
+}
+
+func unpackValue(data []byte, v reflect.Value, tag string) ([]byte, error) {
+ //println("unpackvalue", v.Type().String(), len(data))
+ switch v.Kind() {
+ case reflect.String:
+ if v.Type() == tagType {
+ if tag == "" {
+ panic("arqfs: missing reflect tag on Tag field")
+ }
+ if len(data) < len(tag) || !bytes.Equal(data[:len(tag)], []byte(tag)) {
+ return nil, errMalformed
+ }
+ data = data[len(tag):]
+ return data, nil
+ }
+ if len(data) < 1 {
+ return nil, errMalformed
+ }
+ if data[0] == 0 {
+ data = data[1:]
+ v.SetString("")
+ return data, nil
+ }
+ if data[0] != 1 || len(data) < 1+8 {
+ return nil, errMalformed
+ }
+ n := binary.BigEndian.Uint64(data[1:])
+ data = data[1+8:]
+ if n >= uint64(len(data)) {
+ return nil, errMalformed
+ }
+ str := data[:n]
+ data = data[n:]
+ v.SetString(string(str))
+ return data, nil
+
+ case reflect.Uint32:
+ if len(data) < 4 {
+ return nil, errMalformed
+ }
+ v.SetUint(uint64(binary.BigEndian.Uint32(data)))
+ data = data[4:]
+ return data, nil
+
+ case reflect.Int32:
+ if len(data) < 4 {
+ return nil, errMalformed
+ }
+ v.SetInt(int64(binary.BigEndian.Uint32(data)))
+ data = data[4:]
+ return data, nil
+
+ case reflect.Uint8:
+ if len(data) < 1 {
+ return nil, errMalformed
+ }
+ v.SetUint(uint64(data[0]))
+ data = data[1:]
+ return data, nil
+
+ case reflect.Uint64:
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ v.SetUint(binary.BigEndian.Uint64(data))
+ data = data[8:]
+ return data, nil
+
+ case reflect.Int64:
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ v.SetInt(int64(binary.BigEndian.Uint64(data)))
+ data = data[8:]
+ return data, nil
+
+ case reflect.Ptr:
+ v.Set(reflect.New(v.Type().Elem()))
+ return unpackValue(data, v.Elem(), tag)
+
+ case reflect.Slice:
+ var n int
+ if tag == "count32" {
+ n32 := binary.BigEndian.Uint32(data)
+ n = int(n32)
+ if uint32(n) != n32 {
+ return nil, errMalformed
+ }
+ data = data[4:]
+ } else {
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ n64 := binary.BigEndian.Uint64(data)
+ n = int(n64)
+ if uint64(n) != n64 {
+ return nil, errMalformed
+ }
+ data = data[8:]
+ }
+ v.Set(v.Slice(0, 0))
+ if v.Type().Elem().Kind() == reflect.Uint8 {
+ // Fast case for []byte
+ if len(data) < n {
+ return nil, errMalformed
+ }
+ v.Set(reflect.AppendSlice(v, reflect.ValueOf(data[:n])))
+ return data[n:], nil
+ }
+ for i := 0; i < n; i++ {
+ elem := reflect.New(v.Type().Elem()).Elem()
+ var err error
+ data, err = unpackValue(data, elem, "")
+ if err != nil {
+ return nil, err
+ }
+ v.Set(reflect.Append(v, elem))
+ }
+ return data, nil
+
+ case reflect.Array:
+ if v.Type() == scoreType && tag == "HexScore" {
+ var s string
+ data, err := unpackValue(data, reflect.ValueOf(&s).Elem(), "")
+ if err != nil {
+ return nil, err
+ }
+ if len(s) != 0 {
+ v.Set(reflect.ValueOf(hexScore(s)))
+ }
+ return data, nil
+ }
+ n := v.Len()
+ if v.Type().Elem().Kind() == reflect.Uint8 {
+ // Fast case for [n]byte
+ if len(data) < n {
+ return nil, errMalformed
+ }
+ reflect.Copy(v, reflect.ValueOf(data))
+ data = data[n:]
+ return data, nil
+ }
+ for i := 0; i < n; i++ {
+ var err error
+ data, err = unpackValue(data, v.Index(i), "")
+ if err != nil {
+ return nil, err
+ }
+ }
+ return data, nil
+
+ case reflect.Bool:
+ if len(data) < 1 || data[0] > 1 {
+ if len(data) >= 1 {
+ println("badbool", data[0])
+ }
+ return nil, errMalformed
+ }
+ v.SetBool(data[0] == 1)
+ data = data[1:]
+ return data, nil
+
+ case reflect.Struct:
+ if v.Type() == timeType {
+ if len(data) < 1 || data[0] > 1 {
+ return nil, errMalformed
+ }
+ if data[0] == 0 {
+ v.Set(reflect.ValueOf(time.Time{}))
+ return data[1:], nil
+ }
+ data = data[1:]
+ if len(data) < 8 {
+ return nil, errMalformed
+ }
+ ms := binary.BigEndian.Uint64(data)
+ v.Set(reflect.ValueOf(time.Unix(int64(ms/1e3), int64(ms%1e3)*1e6)))
+ return data[8:], nil
+ }
+ for i := 0; i < v.NumField(); i++ {
+ f := v.Type().Field(i)
+ fv := v.Field(i)
+ var err error
+ data, err = unpackValue(data, fv, f.Tag.Get("arq"))
+ if err != nil {
+ return nil, err
+ }
+ }
+ return data, nil
+ }
+
+ panic("arqfs: unexpected type in unpackValue: " + v.Type().String())
+}
diff --git a/vendor/github.com/mattermost/rsc/blog/atom/atom.go b/vendor/github.com/mattermost/rsc/blog/atom/atom.go
new file mode 100644
index 000000000..4038e4fcd
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/blog/atom/atom.go
@@ -0,0 +1,58 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Adapted from encoding/xml/read_test.go.
+
+// Package atom defines XML data structures for an Atom feed.
+package atom
+
+import (
+ "encoding/xml"
+ "time"
+)
+
+type Feed struct {
+ XMLName xml.Name `xml:"http://www.w3.org/2005/Atom feed"`
+ Title string `xml:"title"`
+ ID string `xml:"id"`
+ Link []Link `xml:"link"`
+ Updated TimeStr `xml:"updated"`
+ Author *Person `xml:"author"`
+ Entry []*Entry `xml:"entry"`
+}
+
+type Entry struct {
+ Title string `xml:"title"`
+ ID string `xml:"id"`
+ Link []Link `xml:"link"`
+ Published TimeStr `xml:"published"`
+ Updated TimeStr `xml:"updated"`
+ Author *Person `xml:"author"`
+ Summary *Text `xml:"summary"`
+ Content *Text `xml:"content"`
+}
+
+type Link struct {
+ Rel string `xml:"rel,attr"`
+ Href string `xml:"href,attr"`
+}
+
+type Person struct {
+ Name string `xml:"name"`
+ URI string `xml:"uri"`
+ Email string `xml:"email"`
+ InnerXML string `xml:",innerxml"`
+}
+
+type Text struct {
+ Type string `xml:"type,attr"`
+ Body string `xml:",chardata"`
+}
+
+type TimeStr string
+
+func Time(t time.Time) TimeStr {
+ return TimeStr(t.Format("2006-01-02T15:04:05-07:00"))
+}
+
diff --git a/vendor/github.com/mattermost/rsc/blog/main.go b/vendor/github.com/mattermost/rsc/blog/main.go
new file mode 100644
index 000000000..182dc88f1
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/blog/main.go
@@ -0,0 +1,15 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "github.com/mattermost/rsc/devweb/slave"
+
+ _ "github.com/mattermost/rsc/blog/post"
+)
+
+func main() {
+ slave.Main()
+}
diff --git a/vendor/github.com/mattermost/rsc/blog/post/post.go b/vendor/github.com/mattermost/rsc/blog/post/post.go
new file mode 100644
index 000000000..beae651f8
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/blog/post/post.go
@@ -0,0 +1,534 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package post
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "fmt"
+ "html/template"
+ "net/http"
+ "os"
+ "path"
+ "runtime/debug"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/mattermost/rsc/appfs/fs"
+ "github.com/mattermost/rsc/appfs/proto"
+ "github.com/mattermost/rsc/blog/atom"
+)
+
+func init() {
+ fs.Root = os.Getenv("HOME") + "/app/"
+ http.HandleFunc("/", serve)
+ http.Handle("/feeds/posts/default", http.RedirectHandler("/feed.atom", http.StatusFound))
+}
+
+var funcMap = template.FuncMap{
+ "now": time.Now,
+ "date": timeFormat,
+}
+
+func timeFormat(fmt string, t time.Time) string {
+ return t.Format(fmt)
+}
+
+type blogTime struct {
+ time.Time
+}
+
+var timeFormats = []string{
+ time.RFC3339,
+ "Monday, January 2, 2006",
+ "January 2, 2006 15:00 -0700",
+}
+
+func (t *blogTime) UnmarshalJSON(data []byte) (err error) {
+ str := string(data)
+ for _, f := range timeFormats {
+ tt, err := time.Parse(`"`+f+`"`, str)
+ if err == nil {
+ t.Time = tt
+ return nil
+ }
+ }
+ return fmt.Errorf("did not recognize time: %s", str)
+}
+
+type PostData struct {
+ FileModTime time.Time
+ FileSize int64
+
+ Title string
+ Date blogTime
+ Name string
+ OldURL string
+ Summary string
+ Favorite bool
+
+ Reader []string
+
+ PlusAuthor string // Google+ ID of author
+ PlusPage string // Google+ Post ID for comment post
+ PlusAPIKey string // Google+ API key
+ PlusURL string
+ HostURL string // host URL
+ Comments bool
+
+ article string
+}
+
+func (d *PostData) canRead(user string) bool {
+ for _, r := range d.Reader {
+ if r == user {
+ return true
+ }
+ }
+ return false
+}
+
+func (d *PostData) IsDraft() bool {
+ return d.Date.IsZero() || d.Date.After(time.Now())
+}
+
+// To find PlusPage value:
+// https://www.googleapis.com/plus/v1/people/116810148281701144465/activities/public?key=AIzaSyB_JO6hyAJAL659z0Dmu0RUVVvTx02ZPMM
+//
+
+const owner = "rsc@swtch.com"
+const plusRsc = "116810148281701144465"
+const plusKey = "AIzaSyB_JO6hyAJAL659z0Dmu0RUVVvTx02ZPMM"
+const feedID = "tag:research.swtch.com,2012:research.swtch.com"
+
+var replacer = strings.NewReplacer(
+ "⁰", "<sup>0</sup>",
+ "¹", "<sup>1</sup>",
+ "²", "<sup>2</sup>",
+ "³", "<sup>3</sup>",
+ "⁴", "<sup>4</sup>",
+ "⁵", "<sup>5</sup>",
+ "⁶", "<sup>6</sup>",
+ "⁷", "<sup>7</sup>",
+ "⁸", "<sup>8</sup>",
+ "⁹", "<sup>9</sup>",
+ "ⁿ", "<sup>n</sup>",
+ "₀", "<sub>0</sub>",
+ "₁", "<sub>1</sub>",
+ "₂", "<sub>2</sub>",
+ "₃", "<sub>3</sub>",
+ "₄", "<sub>4</sub>",
+ "₅", "<sub>5</sub>",
+ "₆", "<sub>6</sub>",
+ "₇", "<sub>7</sub>",
+ "₈", "<sub>8</sub>",
+ "₉", "<sub>9</sub>",
+ "``", "&ldquo;",
+ "''", "&rdquo;",
+)
+
+func serve(w http.ResponseWriter, req *http.Request) {
+ ctxt := fs.NewContext(req)
+
+ defer func() {
+ if err := recover(); err != nil {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "panic: %s\n\n", err)
+ buf.Write(debug.Stack())
+ ctxt.Criticalf("%s", buf.String())
+
+ http.Error(w, buf.String(), 500)
+ }
+ }()
+
+ p := path.Clean("/" + req.URL.Path)
+/*
+ if strings.Contains(req.Host, "appspot.com") {
+ http.Redirect(w, req, "http://research.swtch.com" + p, http.StatusFound)
+ }
+*/
+ if p != req.URL.Path {
+ http.Redirect(w, req, p, http.StatusFound)
+ return
+ }
+
+ if p == "/feed.atom" {
+ atomfeed(w, req)
+ return
+ }
+
+ if strings.HasPrefix(p, "/20") && strings.Contains(p[1:], "/") {
+ // Assume this is an old-style URL.
+ oldRedirect(ctxt, w, req, p)
+ }
+
+ user := ctxt.User()
+ isOwner := ctxt.User() == owner || len(os.Args) >= 2 && os.Args[1] == "LISTEN_STDIN"
+ if p == "" || p == "/" || p == "/draft" {
+ if p == "/draft" && user == "?" {
+ ctxt.Criticalf("/draft loaded by %s", user)
+ notfound(ctxt, w, req)
+ return
+ }
+ toc(w, req, p == "/draft", isOwner, user)
+ return
+ }
+
+ draft := false
+ if strings.HasPrefix(p, "/draft/") {
+ if user == "?" {
+ ctxt.Criticalf("/draft loaded by %s", user)
+ notfound(ctxt, w, req)
+ return
+ }
+ draft = true
+ p = p[len("/draft"):]
+ }
+
+ if strings.Contains(p[1:], "/") {
+ notfound(ctxt, w, req)
+ return
+ }
+
+ if strings.Contains(p, ".") {
+ // Let Google's front end servers cache static
+ // content for a short amount of time.
+ httpCache(w, 5*time.Minute)
+ ctxt.ServeFile(w, req, "blog/static/"+p)
+ return
+ }
+
+ // Use just 'blog' as the cache path so that if we change
+ // templates, all the cached HTML gets invalidated.
+ var data []byte
+ pp := "bloghtml:"+p
+ if draft && !isOwner {
+ pp += ",user="+user
+ }
+ if key, ok := ctxt.CacheLoad(pp, "blog", &data); !ok {
+ meta, article, err := loadPost(ctxt, p, req)
+ if err != nil || meta.IsDraft() != draft || (draft && !isOwner && !meta.canRead(user)) {
+ ctxt.Criticalf("no %s for %s", p, user)
+ notfound(ctxt, w, req)
+ return
+ }
+ t := mainTemplate(ctxt)
+ template.Must(t.New("article").Parse(article))
+
+ var buf bytes.Buffer
+ meta.Comments = true
+ if err := t.Execute(&buf, meta); err != nil {
+ panic(err)
+ }
+ data = buf.Bytes()
+ ctxt.CacheStore(key, data)
+ }
+ w.Write(data)
+}
+
+func notfound(ctxt *fs.Context, w http.ResponseWriter, req *http.Request) {
+ var buf bytes.Buffer
+ var data struct {
+ HostURL string
+ }
+ data.HostURL = hostURL(req)
+ t := mainTemplate(ctxt)
+ if err := t.Lookup("404").Execute(&buf, &data); err != nil {
+ panic(err)
+ }
+ w.WriteHeader(404)
+ w.Write(buf.Bytes())
+}
+
+func mainTemplate(c *fs.Context) *template.Template {
+ t := template.New("main")
+ t.Funcs(funcMap)
+
+ main, _, err := c.Read("blog/main.html")
+ if err != nil {
+ panic(err)
+ }
+ style, _, _ := c.Read("blog/style.html")
+ main = append(main, style...)
+ _, err = t.Parse(string(main))
+ if err != nil {
+ panic(err)
+ }
+ return t
+}
+
+func loadPost(c *fs.Context, name string, req *http.Request) (meta *PostData, article string, err error) {
+ meta = &PostData{
+ Name: name,
+ Title: "TITLE HERE",
+ PlusAuthor: plusRsc,
+ PlusAPIKey: plusKey,
+ HostURL: hostURL(req),
+ }
+
+ art, fi, err := c.Read("blog/post/" + name)
+ if err != nil {
+ return nil, "", err
+ }
+ if bytes.HasPrefix(art, []byte("{\n")) {
+ i := bytes.Index(art, []byte("\n}\n"))
+ if i < 0 {
+ panic("cannot find end of json metadata")
+ }
+ hdr, rest := art[:i+3], art[i+3:]
+ if err := json.Unmarshal(hdr, meta); err != nil {
+ panic(fmt.Sprintf("loading %s: %s", name, err))
+ }
+ art = rest
+ }
+ meta.FileModTime = fi.ModTime
+ meta.FileSize = fi.Size
+
+ return meta, replacer.Replace(string(art)), nil
+}
+
+type byTime []*PostData
+
+func (x byTime) Len() int { return len(x) }
+func (x byTime) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byTime) Less(i, j int) bool { return x[i].Date.Time.After(x[j].Date.Time) }
+
+type TocData struct {
+ Draft bool
+ HostURL string
+ Posts []*PostData
+}
+
+func toc(w http.ResponseWriter, req *http.Request, draft bool, isOwner bool, user string) {
+ c := fs.NewContext(req)
+
+ var data []byte
+ keystr := fmt.Sprintf("blog:toc:%v", draft)
+ if req.FormValue("readdir") != "" {
+ keystr += ",readdir=" + req.FormValue("readdir")
+ }
+ if draft {
+ keystr += ",user="+user
+ }
+
+ if key, ok := c.CacheLoad(keystr, "blog", &data); !ok {
+ c := fs.NewContext(req)
+ dir, err := c.ReadDir("blog/post")
+ if err != nil {
+ panic(err)
+ }
+
+ if req.FormValue("readdir") == "1" {
+ fmt.Fprintf(w, "%d dir entries\n", len(dir))
+ return
+ }
+
+ postCache := map[string]*PostData{}
+ if data, _, err := c.Read("blogcache"); err == nil {
+ if err := json.Unmarshal(data, &postCache); err != nil {
+ c.Criticalf("unmarshal blogcache: %v", err)
+ }
+ }
+
+ ch := make(chan *PostData, len(dir))
+ const par = 20
+ var limit = make(chan bool, par)
+ for i := 0; i < par; i++ {
+ limit <- true
+ }
+ for _, d := range dir {
+ if meta := postCache[d.Name]; meta != nil && meta.FileModTime.Equal(d.ModTime) && meta.FileSize == d.Size {
+ ch <- meta
+ continue
+ }
+
+ <-limit
+ go func(d proto.FileInfo) {
+ defer func() { limit <- true }()
+ meta, _, err := loadPost(c, d.Name, req)
+ if err != nil {
+ // Should not happen: we just listed the directory.
+ c.Criticalf("loadPost %s: %v", d.Name, err)
+ return
+ }
+ ch <- meta
+ }(d)
+ }
+ for i := 0; i < par; i++ {
+ <-limit
+ }
+ close(ch)
+ postCache = map[string]*PostData{}
+ var all []*PostData
+ for meta := range ch {
+ postCache[meta.Name] = meta
+ if meta.IsDraft() == draft && (!draft || isOwner || meta.canRead(user)) {
+ all = append(all, meta)
+ }
+ }
+ sort.Sort(byTime(all))
+
+ if data, err := json.Marshal(postCache); err != nil {
+ c.Criticalf("marshal blogcache: %v", err)
+ } else if err := c.Write("blogcache", data); err != nil {
+ c.Criticalf("write blogcache: %v", err)
+ }
+
+ var buf bytes.Buffer
+ t := mainTemplate(c)
+ if err := t.Lookup("toc").Execute(&buf, &TocData{draft, hostURL(req), all}); err != nil {
+ panic(err)
+ }
+ data = buf.Bytes()
+ c.CacheStore(key, data)
+ }
+ w.Write(data)
+}
+
+func oldRedirect(ctxt *fs.Context, w http.ResponseWriter, req *http.Request, p string) {
+ m := map[string]string{}
+ if key, ok := ctxt.CacheLoad("blog:oldRedirectMap", "blog/post", &m); !ok {
+ dir, err := ctxt.ReadDir("blog/post")
+ if err != nil {
+ panic(err)
+ }
+
+ for _, d := range dir {
+ meta, _, err := loadPost(ctxt, d.Name, req)
+ if err != nil {
+ // Should not happen: we just listed the directory.
+ panic(err)
+ }
+ m[meta.OldURL] = "/" + d.Name
+ }
+
+ ctxt.CacheStore(key, m)
+ }
+
+ if url, ok := m[p]; ok {
+ http.Redirect(w, req, url, http.StatusFound)
+ return
+ }
+
+ notfound(ctxt, w, req)
+}
+
+func hostURL(req *http.Request) string {
+ if strings.HasPrefix(req.Host, "localhost") {
+ return "http://localhost:8080"
+ }
+ return "http://research.swtch.com"
+}
+
+func atomfeed(w http.ResponseWriter, req *http.Request) {
+ c := fs.NewContext(req)
+
+ c.Criticalf("Header: %v", req.Header)
+
+ var data []byte
+ if key, ok := c.CacheLoad("blog:atomfeed", "blog/post", &data); !ok {
+ dir, err := c.ReadDir("blog/post")
+ if err != nil {
+ panic(err)
+ }
+
+ var all []*PostData
+ for _, d := range dir {
+ meta, article, err := loadPost(c, d.Name, req)
+ if err != nil {
+ // Should not happen: we just loaded the directory.
+ panic(err)
+ }
+ if meta.IsDraft() {
+ continue
+ }
+ meta.article = article
+ all = append(all, meta)
+ }
+ sort.Sort(byTime(all))
+
+ show := all
+ if len(show) > 10 {
+ show = show[:10]
+ for _, meta := range all[10:] {
+ if meta.Favorite {
+ show = append(show, meta)
+ }
+ }
+ }
+
+ feed := &atom.Feed{
+ Title: "research!rsc",
+ ID: feedID,
+ Updated: atom.Time(show[0].Date.Time),
+ Author: &atom.Person{
+ Name: "Russ Cox",
+ URI: "https://plus.google.com/" + plusRsc,
+ Email: "rsc@swtch.com",
+ },
+ Link: []atom.Link{
+ {Rel: "self", Href: hostURL(req) + "/feed.atom"},
+ },
+ }
+
+ for _, meta := range show {
+ t := template.New("main")
+ t.Funcs(funcMap)
+ main, _, err := c.Read("blog/atom.html")
+ if err != nil {
+ panic(err)
+ }
+ _, err = t.Parse(string(main))
+ if err != nil {
+ panic(err)
+ }
+ template.Must(t.New("article").Parse(meta.article))
+ var buf bytes.Buffer
+ if err := t.Execute(&buf, meta); err != nil {
+ panic(err)
+ }
+
+ e := &atom.Entry{
+ Title: meta.Title,
+ ID: feed.ID + "/" + meta.Name,
+ Link: []atom.Link{
+ {Rel: "alternate", Href: meta.HostURL + "/" + meta.Name},
+ },
+ Published: atom.Time(meta.Date.Time),
+ Updated: atom.Time(meta.Date.Time),
+ Summary: &atom.Text{
+ Type: "text",
+ Body: meta.Summary,
+ },
+ Content: &atom.Text{
+ Type: "html",
+ Body: buf.String(),
+ },
+ }
+
+ feed.Entry = append(feed.Entry, e)
+ }
+
+ data, err = xml.Marshal(&feed)
+ if err != nil {
+ panic(err)
+ }
+
+ c.CacheStore(key, data)
+ }
+
+ // Feed readers like to hammer us; let Google cache the
+ // response to reduce the traffic we have to serve.
+ httpCache(w, 15*time.Minute)
+
+ w.Header().Set("Content-Type", "application/atom+xml")
+ w.Write(data)
+}
+
+func httpCache(w http.ResponseWriter, dt time.Duration) {
+ w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d", int(dt.Seconds())))
+}
diff --git a/vendor/github.com/mattermost/rsc/blog/post/qr.go b/vendor/github.com/mattermost/rsc/blog/post/qr.go
new file mode 100644
index 000000000..a1a03fdbf
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/blog/post/qr.go
@@ -0,0 +1,34 @@
+package post
+
+import (
+ "fmt"
+ "net/http"
+ "runtime/debug"
+
+ qrweb "github.com/mattermost/rsc/qr/web"
+)
+
+func carp(f http.HandlerFunc) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ defer func() {
+ if err := recover(); err != nil {
+ w.Header().Set("Content-Type", "text/plain")
+ fmt.Fprintf(w, "<pre>\npanic: %s\n\n%s\n", err, debug.Stack())
+ }
+ }()
+ f.ServeHTTP(w, req)
+ })
+}
+
+func init() {
+ // http.Handle("/qr/bits", carp(qrweb.Bits))
+ http.Handle("/qr/frame", carp(qrweb.Frame))
+ http.Handle("/qr/frames", carp(qrweb.Frames))
+ http.Handle("/qr/mask", carp(qrweb.Mask))
+ http.Handle("/qr/masks", carp(qrweb.Masks))
+ http.Handle("/qr/arrow", carp(qrweb.Arrow))
+ http.Handle("/qr/draw", carp(qrweb.Draw))
+ http.Handle("/qr/bitstable", carp(qrweb.BitsTable))
+ http.Handle("/qr/encode", carp(qrweb.Encode))
+ http.Handle("/qr/show/", carp(qrweb.Show))
+}
diff --git a/vendor/github.com/mattermost/rsc/cmd/crypt/crypt.go b/vendor/github.com/mattermost/rsc/cmd/crypt/crypt.go
new file mode 100644
index 000000000..4a2150540
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/cmd/crypt/crypt.go
@@ -0,0 +1,79 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Crypt is a simple password-based encryption program,
+// demonstrating how to use github.com/mattermost/rsc/crypt.
+//
+// Encrypt input to output using password:
+// crypt password <input >output
+//
+// Decrypt input to output using password:
+// crypt -d password <input >output
+//
+// Yes, the password is a command-line argument. This is a demo of the
+// github.com/mattermost/rsc/crypt package. It's not intended for real use.
+//
+package main
+
+import (
+ "encoding/base64"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+
+ "github.com/mattermost/rsc/crypt"
+)
+
+func main() {
+ args := os.Args[1:]
+ encrypt := true
+ if len(args) >= 1 && args[0] == "-d" {
+ encrypt = false
+ args = args[1:]
+ }
+ if len(args) != 1 || strings.HasPrefix(args[0], "-") {
+ fmt.Fprintf(os.Stderr, "usage: crypt [-d] password < input > output\n")
+ os.Exit(2)
+ }
+ password := args[0]
+
+ data, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "reading stdin: %v\n", err)
+ os.Exit(1)
+ }
+ if encrypt {
+ pkt, err := crypt.Encrypt(password, data)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ os.Exit(1)
+ }
+ str := base64.StdEncoding.EncodeToString(pkt)
+ for len(str) > 60 {
+ fmt.Printf("%s\n", str[:60])
+ str = str[60:]
+ }
+ fmt.Printf("%s\n", str)
+ } else {
+ pkt, err := base64.StdEncoding.DecodeString(strings.Map(noSpace, string(data)))
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "decoding input: %v\n", err)
+ os.Exit(1)
+ }
+ dec, err := crypt.Decrypt(password, pkt)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", err)
+ os.Exit(1)
+ }
+ os.Stdout.Write(dec)
+ }
+}
+
+func noSpace(r rune) rune {
+ if r == ' ' || r == '\t' || r == '\n' {
+ return -1
+ }
+ return r
+}
diff --git a/vendor/github.com/mattermost/rsc/cmd/issue/issue.go b/vendor/github.com/mattermost/rsc/cmd/issue/issue.go
new file mode 100644
index 000000000..651a65d96
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/cmd/issue/issue.go
@@ -0,0 +1,185 @@
+package main
+
+import (
+ "encoding/xml"
+ "flag"
+ "fmt"
+ "html"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, `usage: issue [-p project] query
+
+If query is a single number, prints the full history for the issue.
+Otherwise, prints a table of matching results.
+The special query 'go1' is shorthand for 'Priority-Go1'.
+`)
+ os.Exit(2)
+}
+
+type Feed struct {
+ Entry Entries `xml:"entry"`
+}
+
+type Entry struct {
+ ID string `xml:"id"`
+ Title string `xml:"title"`
+ Published time.Time `xml:"published"`
+ Content string `xml:"content"`
+ Updates []Update `xml:"updates"`
+ Author struct {
+ Name string `xml:"name"`
+ } `xml:"author"`
+ Owner string `xml:"owner"`
+ Status string `xml:"status"`
+ Label []string `xml:"label"`
+}
+
+type Update struct {
+ Summary string `xml:"summary"`
+ Owner string `xml:"ownerUpdate"`
+ Label string `xml:"label"`
+ Status string `xml:"status"`
+}
+
+type Entries []Entry
+
+func (e Entries) Len() int { return len(e) }
+func (e Entries) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
+func (e Entries) Less(i, j int) bool { return e[i].Title < e[j].Title }
+
+var project = flag.String("p", "go", "code.google.com project identifier")
+var v = flag.Bool("v", false, "verbose")
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ if flag.NArg() != 1 {
+ usage()
+ }
+
+ full := false
+ q := flag.Arg(0)
+ n, _ := strconv.Atoi(q)
+ if n != 0 {
+ q = "id:" + q
+ full = true
+ }
+ if q == "go1" {
+ q = "label:Priority-Go1"
+ }
+
+ log.SetFlags(0)
+
+ query := url.Values{
+ "q": {q},
+ "max-results": {"400"},
+ }
+ if !full {
+ query["can"] = []string{"open"}
+ }
+ u := "https://code.google.com/feeds/issues/p/" + *project + "/issues/full?" + query.Encode()
+ if *v {
+ log.Print(u)
+ }
+ r, err := http.Get(u)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var feed Feed
+ if err := xml.NewDecoder(r.Body).Decode(&feed); err != nil {
+ log.Fatal(err)
+ }
+ r.Body.Close()
+
+ sort.Sort(feed.Entry)
+ for _, e := range feed.Entry {
+ id := e.ID
+ if i := strings.Index(id, "id="); i >= 0 {
+ id = id[:i+len("id=")]
+ }
+ fmt.Printf("%s\t%s\n", id, e.Title)
+ if full {
+ fmt.Printf("Reported by %s (%s)\n", e.Author.Name, e.Published.Format("2006-01-02 15:04:05"))
+ if e.Owner != "" {
+ fmt.Printf("\tOwner: %s\n", e.Owner)
+ }
+ if e.Status != "" {
+ fmt.Printf("\tStatus: %s\n", e.Status)
+ }
+ for _, l := range e.Label {
+ fmt.Printf("\tLabel: %s\n", l)
+ }
+ if e.Content != "" {
+ fmt.Printf("\n\t%s\n", wrap(html.UnescapeString(e.Content), "\t"))
+ }
+ u := "https://code.google.com/feeds/issues/p/" + *project + "/issues/" + id + "/comments/full"
+ if *v {
+ log.Print(u)
+ }
+ r, err := http.Get(u)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var feed Feed
+ if err := xml.NewDecoder(r.Body).Decode(&feed); err != nil {
+ log.Fatal(err)
+ }
+ r.Body.Close()
+
+ for _, e := range feed.Entry {
+ fmt.Printf("\n%s (%s)\n", e.Title, e.Published.Format("2006-01-02 15:04:05"))
+ for _, up := range e.Updates {
+ if up.Summary != "" {
+ fmt.Printf("\tSummary: %s\n", up.Summary)
+ }
+ if up.Owner != "" {
+ fmt.Printf("\tOwner: %s\n", up.Owner)
+ }
+ if up.Status != "" {
+ fmt.Printf("\tStatus: %s\n", up.Status)
+ }
+ if up.Label != "" {
+ fmt.Printf("\tLabel: %s\n", up.Label)
+ }
+ }
+ if e.Content != "" {
+ fmt.Printf("\n\t%s\n", wrap(html.UnescapeString(e.Content), "\t"))
+ }
+ }
+ }
+ }
+}
+
+func wrap(t string, prefix string) string {
+ out := ""
+ t = strings.Replace(t, "\r\n", "\n", -1)
+ lines := strings.Split(t, "\n")
+ for i, line := range lines {
+ if i > 0 {
+ out += "\n" + prefix
+ }
+ s := line
+ for len(s) > 70 {
+ i := strings.LastIndex(s[:70], " ")
+ if i < 0 {
+ i = 69
+ }
+ i++
+ out += s[:i] + "\n" + prefix
+ s = s[i:]
+ }
+ out += s
+ }
+ return out
+}
diff --git a/vendor/github.com/mattermost/rsc/cmd/jfmt/main.go b/vendor/github.com/mattermost/rsc/cmd/jfmt/main.go
new file mode 100644
index 000000000..31c5eddfc
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/cmd/jfmt/main.go
@@ -0,0 +1,37 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// jfmt reads JSON from standard input, formats it, and writes it to standard output.
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+)
+
+func main() {
+ log.SetFlags(0)
+
+ if len(os.Args) > 1 {
+ fmt.Fprintf(os.Stderr, "usage: json < input > output\n")
+ os.Exit(2)
+ }
+
+ // TODO: Can do on the fly.
+
+ data, err := ioutil.ReadAll(os.Stdin)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var buf bytes.Buffer
+ json.Indent(&buf, data, "", " ")
+ buf.WriteByte('\n')
+
+ os.Stdout.Write(buf.Bytes())
+}
diff --git a/vendor/github.com/mattermost/rsc/crypt/crypt.go b/vendor/github.com/mattermost/rsc/crypt/crypt.go
new file mode 100644
index 000000000..c65129be4
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/crypt/crypt.go
@@ -0,0 +1,150 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crypt provides simple, password-based encryption and decryption of data blobs.
+package crypt
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha1"
+ "fmt"
+ "io"
+
+ "code.google.com/p/go.crypto/pbkdf2"
+)
+
+// This program manipulates encrypted, signed packets with the following format:
+// 1 byte version
+// 8 byte salt
+// 4 byte key hash
+// aes.BlockSize-byte IV
+// aes.BlockSize-byte encryption (maybe longer)
+// sha1.Size-byte HMAC signature
+
+const version = 0
+
+// deriveKey returns the AES key, HMAC-SHA1 key, and key hash for
+// the given password, salt combination.
+func deriveKey(password string, salt []byte) (aesKey, hmacKey, keyHash []byte) {
+ const keySize = 16
+ key := pbkdf2.Key([]byte(password), salt, 4096, 2*keySize, sha1.New)
+ aesKey = key[:keySize]
+ hmacKey = key[keySize:]
+ h := sha1.New()
+ h.Write(key)
+ keyHash = h.Sum(nil)[:4]
+ return
+}
+
+// Encrypt encrypts the plaintext into an encrypted packet
+// using the given password. The password is required for
+// decryption.
+func Encrypt(password string, plaintext []byte) (encrypted []byte, err error) {
+ // Derive key material from password and salt.
+ salt := make([]byte, 8)
+ _, err = io.ReadFull(rand.Reader, salt)
+ if err != nil {
+ return nil, err
+ }
+ aesKey, hmacKey, keyHash := deriveKey(password, salt)
+
+ // Pad.
+ n := aes.BlockSize - len(plaintext)%aes.BlockSize
+ dec := make([]byte, len(plaintext)+n)
+ copy(dec, plaintext)
+ for i := len(plaintext); i < len(dec); i++ {
+ dec[i] = byte(n)
+ }
+
+ // Encrypt.
+ iv := make([]byte, aes.BlockSize)
+ _, err = io.ReadFull(rand.Reader, iv)
+ if err != nil {
+ return nil, err
+ }
+ aesBlock, err := aes.NewCipher(aesKey)
+ if err != nil {
+ // Cannot happen - key is right size.
+ panic("aes: " + err.Error())
+ }
+ m := cipher.NewCBCEncrypter(aesBlock, iv)
+ enc := make([]byte, len(dec))
+ m.CryptBlocks(enc, dec)
+
+ // Construct packet.
+ var pkt []byte
+ pkt = append(pkt, version)
+ pkt = append(pkt, salt...)
+ pkt = append(pkt, keyHash...)
+ pkt = append(pkt, iv...)
+ pkt = append(pkt, enc...)
+
+ // Sign.
+ h := hmac.New(sha1.New, hmacKey)
+ h.Write(pkt)
+ pkt = append(pkt, h.Sum(nil)...)
+
+ return pkt, nil
+}
+
+// Decrypt decrypts the encrypted packet using the given password.
+// It returns the decrypted data.
+func Decrypt(password string, encrypted []byte) (plaintext []byte, err error) {
+ // Pull apart packet.
+ pkt := encrypted
+ if len(pkt) < 1+8+4+2*aes.BlockSize+sha1.Size {
+ return nil, fmt.Errorf("encrypted packet too short")
+ }
+ vers, pkt := pkt[:1], pkt[1:]
+ salt, pkt := pkt[:8], pkt[8:]
+ hash, pkt := pkt[:4], pkt[4:]
+ iv, pkt := pkt[:aes.BlockSize], pkt[aes.BlockSize:]
+ enc, sig := pkt[:len(pkt)-sha1.Size], pkt[len(pkt)-sha1.Size:]
+
+ if vers[0] != version || len(enc)%aes.BlockSize != 0 {
+ return nil, fmt.Errorf("malformed encrypted packet")
+ }
+
+ // Derive key and check against hash.
+ aesKey, hmacKey, keyHash := deriveKey(password, salt)
+ if !bytes.Equal(hash, keyHash) {
+ return nil, fmt.Errorf("incorrect password - %x vs %x", hash, keyHash)
+ }
+
+ // Verify signature.
+ h := hmac.New(sha1.New, hmacKey)
+ h.Write(encrypted[:len(encrypted)-len(sig)])
+ if !bytes.Equal(sig, h.Sum(nil)) {
+ return nil, fmt.Errorf("cannot authenticate encrypted packet")
+ }
+
+ // Decrypt.
+ aesBlock, err := aes.NewCipher(aesKey)
+ if err != nil {
+ // Cannot happen - key is right size.
+ panic("aes: " + err.Error())
+ }
+ m := cipher.NewCBCDecrypter(aesBlock, iv)
+ dec := make([]byte, len(enc))
+ m.CryptBlocks(dec, enc)
+
+ // Unpad.
+ pad := dec[len(dec)-1]
+ if pad <= 0 || pad > aes.BlockSize {
+ return nil, fmt.Errorf("malformed packet padding")
+ }
+ for _, b := range dec[len(dec)-int(pad):] {
+ if b != pad {
+ return nil, fmt.Errorf("malformed packet padding")
+ }
+ }
+ dec = dec[:len(dec)-int(pad)]
+
+ // Success!
+ return dec, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/devweb/main.go b/vendor/github.com/mattermost/rsc/devweb/main.go
new file mode 100644
index 000000000..7a09f032b
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/devweb/main.go
@@ -0,0 +1,317 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Devweb is a simple environment for developing a web server.
+// It runs its own web server on the given address and proxies
+// all requests to the http server program named by importpath.
+// It takes care of recompiling and restarting the program as needed.
+//
+// The server program should be a trivial main program like:
+//
+// package main
+//
+// import (
+// "github.com/mattermost/rsc/devweb/slave"
+//
+// _ "this/package"
+// _ "that/package"
+// )
+//
+// func main() {
+// slave.Main()
+// }
+//
+// The import _ lines import packages that register HTTP handlers,
+// like in an App Engine program.
+//
+// As you make changes to this/package or that/package (or their
+// dependencies), devweb recompiles and relaunches the servers as
+// needed to serve requests.
+//
+package main
+
+// BUG(rsc): Devweb should probably
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sync"
+ "time"
+)
+
+func usage() {
+ fmt.Fprint(os.Stderr, `usage: devweb [-addr :8000] importpath
+
+Devweb runs a web server on the given address and proxies all requests
+to the http server program named by importpath. It takes care of
+recompiling and restarting the program as needed.
+
+The http server program must itself have a -addr argument that
+says which TCP port to listen on.
+`,
+ )
+}
+
+var addr = flag.String("addr", ":8000", "web service address")
+var rootPackage string
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ args := flag.Args()
+ if len(args) != 1 {
+ usage()
+ }
+ rootPackage = args[0]
+
+ log.Fatal(http.ListenAndServe(*addr, http.HandlerFunc(relay)))
+}
+
+func relay(w http.ResponseWriter, req *http.Request) {
+ defer func() {
+ if err := recover(); err != nil {
+ http.Error(w, fmt.Sprint(err), 200)
+ }
+ }()
+
+ c, proxy, err := buildProxy()
+ if err != nil {
+ panic(err)
+ }
+ defer c.Close()
+ _ = proxy
+
+ outreq := new(http.Request)
+ *outreq = *req // includes shallow copies of maps, but okay
+
+ outreq.Proto = "HTTP/1.1"
+ outreq.ProtoMajor = 1
+ outreq.ProtoMinor = 1
+ outreq.Close = false
+
+ // Remove the connection header to the backend. We want a
+ // persistent connection, regardless of what the client sent
+ // to us. This is modifying the same underlying map from req
+ // (shallow copied above) so we only copy it if necessary.
+ if outreq.Header.Get("Connection") != "" {
+ outreq.Header = make(http.Header)
+ copyHeader(outreq.Header, req.Header)
+ outreq.Header.Del("Connection")
+ }
+
+ outreq.Write(c)
+
+ br := bufio.NewReader(c)
+ resp, err := http.ReadResponse(br, outreq)
+ if err != nil {
+ panic(err)
+ }
+
+ copyHeader(w.Header(), resp.Header)
+ w.WriteHeader(resp.StatusCode)
+
+ if resp.Body != nil {
+ io.Copy(w, resp.Body)
+ }
+}
+
+func copyHeader(dst, src http.Header) {
+ for k, vv := range src {
+ for _, v := range vv {
+ dst.Add(k, v)
+ }
+ }
+}
+
+type cmdProxy struct {
+ cmd *exec.Cmd
+ addr string
+}
+
+func (p *cmdProxy) kill() {
+ if p == nil {
+ return
+ }
+ p.cmd.Process.Kill()
+ p.cmd.Wait()
+}
+
+var proxyInfo struct {
+ sync.Mutex
+ build time.Time
+ check time.Time
+ active *cmdProxy
+ err error
+}
+
+func buildProxy() (c net.Conn, proxy *cmdProxy, err error) {
+ p := &proxyInfo
+
+ t := time.Now()
+ p.Lock()
+ defer p.Unlock()
+ if t.Before(p.check) {
+ // We waited for the lock while someone else dialed.
+ // If we can connect, done.
+ if p.active != nil {
+ if c, err := net.DialTimeout("tcp", p.active.addr, 5*time.Second); err == nil {
+ return c, p.active, nil
+ }
+ }
+ }
+
+ defer func() {
+ p.err = err
+ p.check = time.Now()
+ }()
+
+ pkgs, err := loadPackage(rootPackage)
+ if err != nil {
+ return nil, nil, fmt.Errorf("load %s: %s", rootPackage, err)
+ }
+
+ deps := pkgs[0].Deps
+ if len(deps) > 0 && deps[0] == "C" {
+ deps = deps[1:]
+ }
+ pkgs1, err := loadPackage(deps...)
+ if err != nil {
+ return nil, nil, fmt.Errorf("load %v: %s", deps, err)
+ }
+ pkgs = append(pkgs, pkgs1...)
+
+ var latest time.Time
+
+ for _, pkg := range pkgs {
+ var files []string
+ files = append(files, pkg.GoFiles...)
+ files = append(files, pkg.CFiles...)
+ files = append(files, pkg.HFiles...)
+ files = append(files, pkg.SFiles...)
+ files = append(files, pkg.CgoFiles...)
+
+ for _, file := range files {
+ if fi, err := os.Stat(filepath.Join(pkg.Dir, file)); err == nil && fi.ModTime().After(latest) {
+ latest = fi.ModTime()
+ }
+ }
+ }
+
+ if latest.After(p.build) {
+ p.active.kill()
+ p.active = nil
+
+ out, err := exec.Command("go", "build", "-o", "prox.exe", rootPackage).CombinedOutput()
+ if len(out) > 0 {
+ return nil, nil, fmt.Errorf("%s", out)
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+
+ p.build = latest
+ }
+
+ // If we can connect, done.
+ if p.active != nil {
+ if c, err := net.DialTimeout("tcp", p.active.addr, 5*time.Second); err == nil {
+ return c, p.active, nil
+ }
+ }
+
+ // Otherwise, start a new server.
+ p.active.kill()
+ p.active = nil
+
+ l, err := net.Listen("tcp", "localhost:0")
+ if err != nil {
+ return nil, nil, err
+ }
+ addr := l.Addr().String()
+
+ cmd := exec.Command("prox.exe", "LISTEN_STDIN")
+ cmd.Stdin, err = l.(*net.TCPListener).File()
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err != nil {
+ l.Close()
+ return nil, nil, err
+ }
+ err = cmd.Start()
+ l.Close()
+
+ if err != nil {
+ return nil, nil, err
+ }
+
+ c, err = net.DialTimeout("tcp", addr, 5*time.Second)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ p.active = &cmdProxy{cmd, addr}
+ return c, p.active, nil
+}
+
+type Pkg struct {
+ ImportPath string
+ Dir string
+ GoFiles []string
+ CFiles []string
+ HFiles []string
+ SFiles []string
+ CgoFiles []string
+ Deps []string
+}
+
+func loadPackage(name ...string) ([]*Pkg, error) {
+ args := []string{"list", "-json"}
+ args = append(args, name...)
+ var stderr bytes.Buffer
+ cmd := exec.Command("go", args...)
+ r, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, err
+ }
+ cmd.Stderr = &stderr
+ if err := cmd.Start(); err != nil {
+ return nil, err
+ }
+
+ dec := json.NewDecoder(r)
+ var pkgs []*Pkg
+ for {
+ p := new(Pkg)
+ if err := dec.Decode(p); err != nil {
+ if err == io.EOF {
+ break
+ }
+ cmd.Process.Kill()
+ return nil, err
+ }
+ pkgs = append(pkgs, p)
+ }
+
+ err = cmd.Wait()
+ if b := stderr.Bytes(); len(b) > 0 {
+ return nil, fmt.Errorf("%s", b)
+ }
+ if err != nil {
+ return nil, err
+ }
+ if len(pkgs) != len(name) {
+ return nil, fmt.Errorf("found fewer packages than expected")
+ }
+ return pkgs, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/devweb/slave/slave.go b/vendor/github.com/mattermost/rsc/devweb/slave/slave.go
new file mode 100644
index 000000000..a6983c23c
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/devweb/slave/slave.go
@@ -0,0 +1,26 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slave
+
+import (
+ "fmt"
+ "log"
+ "net"
+ "net/http"
+ "os"
+)
+
+func Main() {
+ if len(os.Args) != 2 || os.Args[1] != "LISTEN_STDIN" {
+ fmt.Fprintf(os.Stderr, "devweb slave must be invoked by devweb\n")
+ os.Exit(2)
+ }
+ l, err := net.FileListener(os.Stdin)
+ if err != nil {
+ log.Fatal(err)
+ }
+ os.Stdin.Close()
+ log.Fatal(http.Serve(l, nil))
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/debug.go b/vendor/github.com/mattermost/rsc/fuse/debug.go
new file mode 100644
index 000000000..2dc5d4312
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/debug.go
@@ -0,0 +1,20 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// FUSE service loop, for servers that wish to use it.
+
+package fuse
+
+import (
+ "runtime"
+)
+
+func stack() string {
+ buf := make([]byte, 1024)
+ return string(buf[:runtime.Stack(buf, false)])
+}
+
+var Debugf = nop
+
+func nop(string, ...interface{}) {}
diff --git a/vendor/github.com/mattermost/rsc/fuse/fuse.go b/vendor/github.com/mattermost/rsc/fuse/fuse.go
new file mode 100644
index 000000000..2ad10c93e
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/fuse.go
@@ -0,0 +1,1650 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+// Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+// Package fuse enables writing FUSE file systems on FreeBSD, Linux, and OS X.
+//
+// On OS X, it requires OSXFUSE (http://osxfuse.github.com/).
+//
+// There are two approaches to writing a FUSE file system. The first is to speak
+// the low-level message protocol, reading from a Conn using ReadRequest and
+// writing using the various Respond methods. This approach is closest to
+// the actual interaction with the kernel and can be the simplest one in contexts
+// such as protocol translators.
+//
+// Servers of synthesized file systems tend to share common bookkeeping
+// abstracted away by the second approach, which is to call the Conn's
+// Serve method to serve the FUSE protocol using
+// an implementation of the service methods in the interfaces
+// FS (file system), Node (file or directory), and Handle (opened file or directory).
+// There are a daunting number of such methods that can be written,
+// but few are required.
+// The specific methods are described in the documentation for those interfaces.
+//
+// The hellofs subdirectory contains a simple illustration of the ServeFS approach.
+//
+// Service Methods
+//
+// The required and optional methods for the FS, Node, and Handle interfaces
+// have the general form
+//
+// Op(req *OpRequest, resp *OpResponse, intr Intr) Error
+//
+// where Op is the name of a FUSE operation. Op reads request parameters
+// from req and writes results to resp. An operation whose only result is
+// the error result omits the resp parameter. Multiple goroutines may call
+// service methods simultaneously; the methods being called are responsible
+// for appropriate synchronization.
+//
+// Interrupted Operations
+//
+// In some file systems, some operations
+// may take an undetermined amount of time. For example, a Read waiting for
+// a network message or a matching Write might wait indefinitely. If the request
+// is cancelled and no longer needed, the package will close intr, a chan struct{}.
+// Blocking operations should select on a receive from intr and attempt to
+// abort the operation early if the receive succeeds (meaning the channel is closed).
+// To indicate that the operation failed because it was aborted, return fuse.EINTR.
+//
+// If an operation does not block for an indefinite amount of time, the intr parameter
+// can be ignored.
+//
+// Authentication
+//
+// All requests types embed a Header, meaning that the method can inspect
+// req.Pid, req.Uid, and req.Gid as necessary to implement permission checking.
+// Alternately, XXX.
+//
+// Mount Options
+//
+// XXX
+//
+package fuse
+
+// BUG(rsc): The mount code for FreeBSD has not been written yet.
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "runtime"
+ "sync"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+// A Conn represents a connection to a mounted FUSE file system.
+type Conn struct {
+ fd int
+ buf []byte
+ wio sync.Mutex
+
+ serveConn
+}
+
+// Mount mounts a new FUSE connection on the named directory
+// and returns a connection for reading and writing FUSE messages.
+func Mount(dir string) (*Conn, error) {
+ // TODO(rsc): mount options (...string?)
+ fd, errstr := mount(dir)
+ if errstr != "" {
+ return nil, errors.New(errstr)
+ }
+
+ return &Conn{fd: fd}, nil
+}
+
+// A Request represents a single FUSE request received from the kernel.
+// Use a type switch to determine the specific kind.
+// A request of unrecognized type will have concrete type *Header.
+type Request interface {
+ // Hdr returns the Header associated with this request.
+ Hdr() *Header
+
+ // RespondError responds to the request with the given error.
+ RespondError(Error)
+
+ String() string
+
+ // handle returns the HandleID for the request, or 0.
+ handle() HandleID
+}
+
+// A RequestID identifies an active FUSE request.
+type RequestID uint64
+
+// A NodeID is a number identifying a directory or file.
+// It must be unique among IDs returned in LookupResponses
+// that have not yet been forgotten by ForgetRequests.
+type NodeID uint64
+
+// A HandleID is a number identifying an open directory or file.
+// It only needs to be unique while the directory or file is open.
+type HandleID uint64
+
+// The RootID identifies the root directory of a FUSE file system.
+const RootID NodeID = rootID
+
+// A Header describes the basic information sent in every request.
+type Header struct {
+ Conn *Conn // connection this request was received on
+ ID RequestID // unique ID for request
+ Node NodeID // file or directory the request is about
+ Uid uint32 // user ID of process making request
+ Gid uint32 // group ID of process making request
+ Pid uint32 // process ID of process making request
+}
+
+func (h *Header) String() string {
+ return fmt.Sprintf("ID=%#x Node=%#x Uid=%d Gid=%d Pid=%d", h.ID, h.Node, h.Uid, h.Gid, h.Pid)
+}
+
+func (h *Header) Hdr() *Header {
+ return h
+}
+
+func (h *Header) handle() HandleID {
+ return 0
+}
+
+// An Error is a FUSE error.
+type Error interface {
+ errno() int32
+}
+
+const (
+ // ENOSYS indicates that the call is not supported.
+ ENOSYS = Errno(syscall.ENOSYS)
+
+ // ESTALE is used by Serve to respond to violations of the FUSE protocol.
+ ESTALE = Errno(syscall.ESTALE)
+
+ ENOENT = Errno(syscall.ENOENT)
+ EIO = Errno(syscall.EIO)
+ EPERM = Errno(syscall.EPERM)
+)
+
+type errno int
+
+func (e errno) errno() int32 {
+ return int32(e)
+}
+
+// Errno implements Error using a syscall.Errno.
+type Errno syscall.Errno
+
+func (e Errno) errno() int32 {
+ return int32(e)
+}
+
+func (e Errno) String() string {
+ return syscall.Errno(e).Error()
+}
+
+func (h *Header) RespondError(err Error) {
+ // FUSE uses negative errors!
+ // TODO: File bug report against OSXFUSE: positive error causes kernel panic.
+ out := &outHeader{Error: -err.errno(), Unique: uint64(h.ID)}
+ h.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+var maxWrite = syscall.Getpagesize()
+var bufSize = 4096 + maxWrite
+
+// a message represents the bytes of a single FUSE message
+type message struct {
+ conn *Conn
+ buf []byte // all bytes
+ hdr *inHeader // header
+ off int // offset for reading additional fields
+}
+
+func newMessage(c *Conn) *message {
+ m := &message{conn: c, buf: make([]byte, bufSize)}
+ m.hdr = (*inHeader)(unsafe.Pointer(&m.buf[0]))
+ return m
+}
+
+func (m *message) len() uintptr {
+ return uintptr(len(m.buf) - m.off)
+}
+
+func (m *message) data() unsafe.Pointer {
+ var p unsafe.Pointer
+ if m.off < len(m.buf) {
+ p = unsafe.Pointer(&m.buf[m.off])
+ }
+ return p
+}
+
+func (m *message) bytes() []byte {
+ return m.buf[m.off:]
+}
+
+func (m *message) Header() Header {
+ h := m.hdr
+ return Header{Conn: m.conn, ID: RequestID(h.Unique), Node: NodeID(h.Nodeid), Uid: h.Uid, Gid: h.Gid, Pid: h.Pid}
+}
+
+// fileMode returns a Go os.FileMode from a Unix mode.
+func fileMode(unixMode uint32) os.FileMode {
+ mode := os.FileMode(unixMode & 0777)
+ switch unixMode & syscall.S_IFMT {
+ case syscall.S_IFREG:
+ // nothing
+ case syscall.S_IFDIR:
+ mode |= os.ModeDir
+ case syscall.S_IFCHR:
+ mode |= os.ModeCharDevice | os.ModeDevice
+ case syscall.S_IFBLK:
+ mode |= os.ModeDevice
+ case syscall.S_IFIFO:
+ mode |= os.ModeNamedPipe
+ case syscall.S_IFLNK:
+ mode |= os.ModeSymlink
+ case syscall.S_IFSOCK:
+ mode |= os.ModeSocket
+ default:
+ // no idea
+ mode |= os.ModeDevice
+ }
+ if unixMode&syscall.S_ISUID != 0 {
+ mode |= os.ModeSetuid
+ }
+ if unixMode&syscall.S_ISGID != 0 {
+ mode |= os.ModeSetgid
+ }
+ return mode
+}
+
+func (c *Conn) ReadRequest() (Request, error) {
+ // TODO: Some kind of buffer reuse.
+ m := newMessage(c)
+ n, err := syscall.Read(c.fd, m.buf)
+ if err != nil && err != syscall.ENODEV {
+ return nil, err
+ }
+ if n <= 0 {
+ return nil, io.EOF
+ }
+ m.buf = m.buf[:n]
+
+ if n < inHeaderSize {
+ return nil, errors.New("fuse: message too short")
+ }
+
+ // FreeBSD FUSE sends a short length in the header
+ // for FUSE_INIT even though the actual read length is correct.
+ if n == inHeaderSize+initInSize && m.hdr.Opcode == opInit && m.hdr.Len < uint32(n) {
+ m.hdr.Len = uint32(n)
+ }
+
+ // OSXFUSE sometimes sends the wrong m.hdr.Len in a FUSE_WRITE message.
+ if m.hdr.Len < uint32(n) && m.hdr.Len >= uint32(unsafe.Sizeof(writeIn{})) && m.hdr.Opcode == opWrite {
+ m.hdr.Len = uint32(n)
+ }
+
+ if m.hdr.Len != uint32(n) {
+ return nil, fmt.Errorf("fuse: read %d opcode %d but expected %d", n, m.hdr.Opcode, m.hdr.Len)
+ }
+
+ m.off = inHeaderSize
+
+ // Convert to data structures.
+ // Do not trust kernel to hand us well-formed data.
+ var req Request
+ switch m.hdr.Opcode {
+ default:
+ println("No opcode", m.hdr.Opcode)
+ goto unrecognized
+
+ case opLookup:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &LookupRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ }
+
+ case opForget:
+ in := (*forgetIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ForgetRequest{
+ Header: m.Header(),
+ N: in.Nlookup,
+ }
+
+ case opGetattr:
+ req = &GetattrRequest{
+ Header: m.Header(),
+ }
+
+ case opSetattr:
+ in := (*setattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &SetattrRequest{
+ Header: m.Header(),
+ Valid: SetattrValid(in.Valid),
+ Handle: HandleID(in.Fh),
+ Size: in.Size,
+ Atime: time.Unix(int64(in.Atime), int64(in.AtimeNsec)),
+ Mtime: time.Unix(int64(in.Mtime), int64(in.MtimeNsec)),
+ Mode: fileMode(in.Mode),
+ Uid: in.Uid,
+ Gid: in.Gid,
+ Bkuptime: in.BkupTime(),
+ Chgtime: in.Chgtime(),
+ Flags: in.Flags(),
+ }
+
+ case opReadlink:
+ if len(m.bytes()) > 0 {
+ goto corrupt
+ }
+ req = &ReadlinkRequest{
+ Header: m.Header(),
+ }
+
+ case opSymlink:
+ // m.bytes() is "newName\0target\0"
+ names := m.bytes()
+ if len(names) == 0 || names[len(names)-1] != 0 {
+ goto corrupt
+ }
+ i := bytes.IndexByte(names, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ newName, target := names[0:i], names[i+1:len(names)-1]
+ req = &SymlinkRequest{
+ Header: m.Header(),
+ NewName: string(newName),
+ Target: string(target),
+ }
+
+ case opLink:
+ in := (*linkIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ newName := m.bytes()[unsafe.Sizeof(*in):]
+ if len(newName) < 2 || newName[len(newName)-1] != 0 {
+ goto corrupt
+ }
+ newName = newName[:len(newName)-1]
+ req = &LinkRequest{
+ Header: m.Header(),
+ OldNode: NodeID(in.Oldnodeid),
+ NewName: string(newName),
+ }
+
+ case opMknod:
+ in := (*mknodIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ name := m.bytes()[unsafe.Sizeof(*in):]
+ if len(name) < 2 || name[len(name)-1] != '\x00' {
+ goto corrupt
+ }
+ name = name[:len(name)-1]
+ req = &MknodRequest{
+ Header: m.Header(),
+ Mode: fileMode(in.Mode),
+ Rdev: in.Rdev,
+ Name: string(name),
+ }
+
+ case opMkdir:
+ in := (*mkdirIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ name := m.bytes()[unsafe.Sizeof(*in):]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ req = &MkdirRequest{
+ Header: m.Header(),
+ Name: string(name[:i]),
+ Mode: fileMode(in.Mode) | os.ModeDir,
+ }
+
+ case opUnlink, opRmdir:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &RemoveRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ Dir: m.hdr.Opcode == opRmdir,
+ }
+
+ case opRename:
+ in := (*renameIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ newDirNodeID := NodeID(in.Newdir)
+ oldNew := m.bytes()[unsafe.Sizeof(*in):]
+ // oldNew should be "old\x00new\x00"
+ if len(oldNew) < 4 {
+ goto corrupt
+ }
+ if oldNew[len(oldNew)-1] != '\x00' {
+ goto corrupt
+ }
+ i := bytes.IndexByte(oldNew, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ oldName, newName := string(oldNew[:i]), string(oldNew[i+1:len(oldNew)-1])
+ // log.Printf("RENAME: newDirNode = %d; old = %q, new = %q", newDirNodeID, oldName, newName)
+ req = &RenameRequest{
+ Header: m.Header(),
+ NewDir: newDirNodeID,
+ OldName: oldName,
+ NewName: newName,
+ }
+
+ case opOpendir, opOpen:
+ in := (*openIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &OpenRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opOpendir,
+ Flags: in.Flags,
+ Mode: fileMode(in.Mode),
+ }
+
+ case opRead, opReaddir:
+ in := (*readIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ReadRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opReaddir,
+ Handle: HandleID(in.Fh),
+ Offset: int64(in.Offset),
+ Size: int(in.Size),
+ }
+
+ case opWrite:
+ in := (*writeIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ r := &WriteRequest{
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Offset: int64(in.Offset),
+ Flags: WriteFlags(in.WriteFlags),
+ }
+ buf := m.bytes()[unsafe.Sizeof(*in):]
+ if uint32(len(buf)) < in.Size {
+ goto corrupt
+ }
+ r.Data = buf
+ req = r
+
+ case opStatfs:
+ req = &StatfsRequest{
+ Header: m.Header(),
+ }
+
+ case opRelease, opReleasedir:
+ in := (*releaseIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ReleaseRequest{
+ Header: m.Header(),
+ Dir: m.hdr.Opcode == opReleasedir,
+ Handle: HandleID(in.Fh),
+ Flags: in.Flags,
+ ReleaseFlags: ReleaseFlags(in.ReleaseFlags),
+ LockOwner: in.LockOwner,
+ }
+
+ case opFsync:
+ in := (*fsyncIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &FsyncRequest{
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Flags: in.FsyncFlags,
+ }
+
+ case opSetxattr:
+ var size uint32
+ var r *SetxattrRequest
+ if runtime.GOOS == "darwin" {
+ in := (*setxattrInOSX)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ r = &SetxattrRequest{
+ Flags: in.Flags,
+ Position: in.Position,
+ }
+ size = in.Size
+ m.off += int(unsafe.Sizeof(*in))
+ } else {
+ in := (*setxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ r = &SetxattrRequest{}
+ size = in.Size
+ m.off += int(unsafe.Sizeof(*in))
+ }
+ r.Header = m.Header()
+ name := m.bytes()
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ r.Name = string(name[:i])
+ r.Xattr = name[i+1:]
+ if uint32(len(r.Xattr)) < size {
+ goto corrupt
+ }
+ r.Xattr = r.Xattr[:size]
+ req = r
+
+ case opGetxattr:
+ if runtime.GOOS == "darwin" {
+ in := (*getxattrInOSX)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &GetxattrRequest{
+ Header: m.Header(),
+ Size: in.Size,
+ Position: in.Position,
+ }
+ } else {
+ in := (*getxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &GetxattrRequest{
+ Header: m.Header(),
+ Size: in.Size,
+ }
+ }
+
+ case opListxattr:
+ if runtime.GOOS == "darwin" {
+ in := (*getxattrInOSX)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ListxattrRequest{
+ Header: m.Header(),
+ Size: in.Size,
+ Position: in.Position,
+ }
+ } else {
+ in := (*getxattrIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &ListxattrRequest{
+ Header: m.Header(),
+ Size: in.Size,
+ }
+ }
+
+ case opRemovexattr:
+ buf := m.bytes()
+ n := len(buf)
+ if n == 0 || buf[n-1] != '\x00' {
+ goto corrupt
+ }
+ req = &RemovexattrRequest{
+ Header: m.Header(),
+ Name: string(buf[:n-1]),
+ }
+
+ case opFlush:
+ in := (*flushIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &FlushRequest{
+ Header: m.Header(),
+ Handle: HandleID(in.Fh),
+ Flags: in.FlushFlags,
+ LockOwner: in.LockOwner,
+ }
+
+ case opInit:
+ in := (*initIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &InitRequest{
+ Header: m.Header(),
+ Major: in.Major,
+ Minor: in.Minor,
+ MaxReadahead: in.MaxReadahead,
+ Flags: InitFlags(in.Flags),
+ }
+
+ case opFsyncdir:
+ panic("opFsyncdir")
+ case opGetlk:
+ panic("opGetlk")
+ case opSetlk:
+ panic("opSetlk")
+ case opSetlkw:
+ panic("opSetlkw")
+
+ case opAccess:
+ in := (*accessIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ req = &AccessRequest{
+ Header: m.Header(),
+ Mask: in.Mask,
+ }
+
+ case opCreate:
+ in := (*openIn)(m.data())
+ if m.len() < unsafe.Sizeof(*in) {
+ goto corrupt
+ }
+ name := m.bytes()[unsafe.Sizeof(*in):]
+ i := bytes.IndexByte(name, '\x00')
+ if i < 0 {
+ goto corrupt
+ }
+ req = &CreateRequest{
+ Header: m.Header(),
+ Flags: in.Flags,
+ Mode: fileMode(in.Mode),
+ Name: string(name[:i]),
+ }
+
+ case opInterrupt:
+ panic("opInterrupt")
+ case opBmap:
+ panic("opBmap")
+
+ case opDestroy:
+ req = &DestroyRequest{
+ Header: m.Header(),
+ }
+
+ // OS X
+ case opSetvolname:
+ panic("opSetvolname")
+ case opGetxtimes:
+ panic("opGetxtimes")
+ case opExchange:
+ panic("opExchange")
+ }
+
+ return req, nil
+
+corrupt:
+ println("malformed message")
+ return nil, fmt.Errorf("fuse: malformed message")
+
+unrecognized:
+ // Unrecognized message.
+ // Assume higher-level code will send a "no idea what you mean" error.
+ h := m.Header()
+ return &h, nil
+}
+
+func (c *Conn) respond(out *outHeader, n uintptr) {
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ out.Len = uint32(n)
+ msg := (*[1 << 30]byte)(unsafe.Pointer(out))[:n]
+ nn, err := syscall.Write(c.fd, msg)
+ if nn != len(msg) || err != nil {
+ log.Printf("RESPOND WRITE: %d %v", nn, err)
+ log.Printf("with stack: %s", stack())
+ }
+}
+
+func (c *Conn) respondData(out *outHeader, n uintptr, data []byte) {
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ // TODO: use writev
+ out.Len = uint32(n + uintptr(len(data)))
+ msg := make([]byte, out.Len)
+ copy(msg, (*[1 << 30]byte)(unsafe.Pointer(out))[:n])
+ copy(msg[n:], data)
+ syscall.Write(c.fd, msg)
+}
+
+// An InitRequest is the first request sent on a FUSE file system.
+type InitRequest struct {
+ Header
+ Major uint32
+ Minor uint32
+ MaxReadahead uint32
+ Flags InitFlags
+}
+
+func (r *InitRequest) String() string {
+ return fmt.Sprintf("Init [%s] %d.%d ra=%d fl=%v", &r.Header, r.Major, r.Minor, r.MaxReadahead, r.Flags)
+}
+
+// An InitResponse is the response to an InitRequest.
+type InitResponse struct {
+ MaxReadahead uint32
+ Flags InitFlags
+ MaxWrite uint32
+}
+
+func (r *InitResponse) String() string {
+ return fmt.Sprintf("Init %+v", *r)
+}
+
+// Respond replies to the request with the given response.
+func (r *InitRequest) Respond(resp *InitResponse) {
+ out := &initOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Major: kernelVersion,
+ Minor: kernelMinorVersion,
+ MaxReadahead: resp.MaxReadahead,
+ Flags: uint32(resp.Flags),
+ MaxWrite: resp.MaxWrite,
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A StatfsRequest requests information about the mounted file system.
+type StatfsRequest struct {
+ Header
+}
+
+func (r *StatfsRequest) String() string {
+ return fmt.Sprintf("Statfs [%s]\n", &r.Header)
+}
+
+// Respond replies to the request with the given response.
+func (r *StatfsRequest) Respond(resp *StatfsResponse) {
+ out := &statfsOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ St: kstatfs{
+ Blocks: resp.Blocks,
+ Bfree: resp.Bfree,
+ Bavail: resp.Bavail,
+ Files: resp.Files,
+ Bsize: resp.Bsize,
+ Namelen: resp.Namelen,
+ Frsize: resp.Frsize,
+ },
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A StatfsResponse is the response to a StatfsRequest.
+type StatfsResponse struct {
+ Blocks uint64 // Total data blocks in file system.
+ Bfree uint64 // Free blocks in file system.
+ Bavail uint64 // Free blocks in file system if you're not root.
+ Files uint64 // Total files in file system.
+ Ffree uint64 // Free files in file system.
+ Bsize uint32 // Block size
+ Namelen uint32 // Maximum file name length?
+ Frsize uint32 // ?
+}
+
+func (r *StatfsResponse) String() string {
+ return fmt.Sprintf("Statfs %+v", *r)
+}
+
+// An AccessRequest asks whether the file can be accessed
+// for the purpose specified by the mask.
+type AccessRequest struct {
+ Header
+ Mask uint32
+}
+
+func (r *AccessRequest) String() string {
+ return fmt.Sprintf("Access [%s] mask=%#x", &r.Header, r.Mask)
+}
+
+// Respond replies to the request indicating that access is allowed.
+// To deny access, use RespondError.
+func (r *AccessRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+// An Attr is the metadata for a single file or directory.
+type Attr struct {
+ Inode uint64 // inode number
+ Size uint64 // size in bytes
+ Blocks uint64 // size in blocks
+ Atime time.Time // time of last access
+ Mtime time.Time // time of last modification
+ Ctime time.Time // time of last inode change
+ Crtime time.Time // time of creation (OS X only)
+ Mode os.FileMode // file mode
+ Nlink uint32 // number of links
+ Uid uint32 // owner uid
+ Gid uint32 // group gid
+ Rdev uint32 // device numbers
+ Flags uint32 // chflags(2) flags (OS X only)
+}
+
+func unix(t time.Time) (sec uint64, nsec uint32) {
+ nano := t.UnixNano()
+ sec = uint64(nano / 1e9)
+ nsec = uint32(nano % 1e9)
+ return
+}
+
+func (a *Attr) attr() (out attr) {
+ out.Ino = a.Inode
+ out.Size = a.Size
+ out.Blocks = a.Blocks
+ out.Atime, out.AtimeNsec = unix(a.Atime)
+ out.Mtime, out.MtimeNsec = unix(a.Mtime)
+ out.Ctime, out.CtimeNsec = unix(a.Ctime)
+ out.SetCrtime(unix(a.Crtime))
+ out.Mode = uint32(a.Mode) & 0777
+ switch {
+ default:
+ out.Mode |= syscall.S_IFREG
+ case a.Mode&os.ModeDir != 0:
+ out.Mode |= syscall.S_IFDIR
+ case a.Mode&os.ModeDevice != 0:
+ if a.Mode&os.ModeCharDevice != 0 {
+ out.Mode |= syscall.S_IFCHR
+ } else {
+ out.Mode |= syscall.S_IFBLK
+ }
+ case a.Mode&os.ModeNamedPipe != 0:
+ out.Mode |= syscall.S_IFIFO
+ case a.Mode&os.ModeSymlink != 0:
+ out.Mode |= syscall.S_IFLNK
+ case a.Mode&os.ModeSocket != 0:
+ out.Mode |= syscall.S_IFSOCK
+ }
+ if a.Mode&os.ModeSetuid != 0 {
+ out.Mode |= syscall.S_ISUID
+ }
+ if a.Mode&os.ModeSetgid != 0 {
+ out.Mode |= syscall.S_ISGID
+ }
+ out.Nlink = a.Nlink
+ if out.Nlink < 1 {
+ out.Nlink = 1
+ }
+ out.Uid = a.Uid
+ out.Gid = a.Gid
+ out.Rdev = a.Rdev
+ out.SetFlags(a.Flags)
+
+ return
+}
+
+// A GetattrRequest asks for the metadata for the file denoted by r.Node.
+type GetattrRequest struct {
+ Header
+}
+
+func (r *GetattrRequest) String() string {
+ return fmt.Sprintf("Getattr [%s]", &r.Header)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetattrRequest) Respond(resp *GetattrResponse) {
+ out := &attrOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A GetattrResponse is the response to a GetattrRequest.
+type GetattrResponse struct {
+ AttrValid time.Duration // how long Attr can be cached
+ Attr Attr // file attributes
+}
+
+func (r *GetattrResponse) String() string {
+ return fmt.Sprintf("Getattr %+v", *r)
+}
+
+// A GetxattrRequest asks for the extended attributes associated with r.Node.
+type GetxattrRequest struct {
+ Header
+ Size uint32 // maximum size to return
+ Position uint32 // offset within extended attributes
+}
+
+func (r *GetxattrRequest) String() string {
+ return fmt.Sprintf("Getxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *GetxattrRequest) Respond(resp *GetxattrResponse) {
+ out := &getxattrOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Size: uint32(len(resp.Xattr)),
+ }
+ r.Conn.respondData(&out.outHeader, unsafe.Sizeof(*out), resp.Xattr)
+}
+
+// A GetxattrResponse is the response to a GetxattrRequest.
+type GetxattrResponse struct {
+ Xattr []byte
+}
+
+func (r *GetxattrResponse) String() string {
+ return fmt.Sprintf("Getxattr %x", r.Xattr)
+}
+
+// A ListxattrRequest asks to list the extended attributes associated with r.Node.
+type ListxattrRequest struct {
+ Header
+ Size uint32 // maximum size to return
+ Position uint32 // offset within attribute list
+}
+
+func (r *ListxattrRequest) String() string {
+ return fmt.Sprintf("Listxattr [%s] %d @%d", &r.Header, r.Size, r.Position)
+}
+
+// Respond replies to the request with the given response.
+func (r *ListxattrRequest) Respond(resp *ListxattrResponse) {
+ out := &getxattrOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Size: uint32(len(resp.Xattr)),
+ }
+ r.Conn.respondData(&out.outHeader, unsafe.Sizeof(*out), resp.Xattr)
+}
+
+// A ListxattrResponse is the response to a ListxattrRequest.
+type ListxattrResponse struct {
+ Xattr []byte
+}
+
+func (r *ListxattrResponse) String() string {
+ return fmt.Sprintf("Listxattr %x", r.Xattr)
+}
+
+// A RemovexattrRequest asks to remove an extended attribute associated with r.Node.
+type RemovexattrRequest struct {
+ Header
+ Name string // name of extended attribute
+}
+
+func (r *RemovexattrRequest) String() string {
+ return fmt.Sprintf("Removexattr [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request, indicating that the attribute was removed.
+func (r *RemovexattrRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+// A SetxattrRequest asks to set an extended attribute associated with a file.
+type SetxattrRequest struct {
+ Header
+ Flags uint32
+ Position uint32 // OS X only
+ Name string
+ Xattr []byte
+}
+
+func (r *SetxattrRequest) String() string {
+ return fmt.Sprintf("Setxattr [%s] %q %x fl=%v @%#x", &r.Header, r.Name, r.Xattr, r.Flags, r.Position)
+}
+
+// Respond replies to the request, indicating that the extended attribute was set.
+func (r *SetxattrRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+// A LookupRequest asks to look up the given name in the directory named by r.Node.
+type LookupRequest struct {
+ Header
+ Name string
+}
+
+func (r *LookupRequest) String() string {
+ return fmt.Sprintf("Lookup [%s] %q", &r.Header, r.Name)
+}
+
+// Respond replies to the request with the given response.
+func (r *LookupRequest) Respond(resp *LookupResponse) {
+ out := &entryOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Nodeid: uint64(resp.Node),
+ Generation: resp.Generation,
+ EntryValid: uint64(resp.EntryValid / time.Second),
+ EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A LookupResponse is the response to a LookupRequest.
+type LookupResponse struct {
+ Node NodeID
+ Generation uint64
+ EntryValid time.Duration
+ AttrValid time.Duration
+ Attr Attr
+}
+
+func (r *LookupResponse) String() string {
+ return fmt.Sprintf("Lookup %+v", *r)
+}
+
+// An OpenRequest asks to open a file or directory
+type OpenRequest struct {
+ Header
+ Dir bool // is this Opendir?
+ Flags uint32
+ Mode os.FileMode
+}
+
+func (r *OpenRequest) String() string {
+ return fmt.Sprintf("Open [%s] dir=%v fl=%v mode=%v", &r.Header, r.Dir, r.Flags, r.Mode)
+}
+
+// Respond replies to the request with the given response.
+func (r *OpenRequest) Respond(resp *OpenResponse) {
+ out := &openOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Fh: uint64(resp.Handle),
+ OpenFlags: uint32(resp.Flags),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A OpenResponse is the response to a OpenRequest.
+type OpenResponse struct {
+ Handle HandleID
+ Flags OpenFlags
+}
+
+func (r *OpenResponse) String() string {
+ return fmt.Sprintf("Open %+v", *r)
+}
+
+// A CreateRequest asks to create and open a file (not a directory).
+type CreateRequest struct {
+ Header
+ Name string
+ Flags uint32
+ Mode os.FileMode
+}
+
+func (r *CreateRequest) String() string {
+ return fmt.Sprintf("Create [%s] %q fl=%v mode=%v", &r.Header, r.Name, r.Flags, r.Mode)
+}
+
+// Respond replies to the request with the given response.
+func (r *CreateRequest) Respond(resp *CreateResponse) {
+ out := &createOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+
+ Nodeid: uint64(resp.Node),
+ Generation: resp.Generation,
+ EntryValid: uint64(resp.EntryValid / time.Second),
+ EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+
+ Fh: uint64(resp.Handle),
+ OpenFlags: uint32(resp.Flags),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A CreateResponse is the response to a CreateRequest.
+// It describes the created node and opened handle.
+type CreateResponse struct {
+ LookupResponse
+ OpenResponse
+}
+
+func (r *CreateResponse) String() string {
+ return fmt.Sprintf("Create %+v", *r)
+}
+
+// A MkdirRequest asks to create (but not open) a directory.
+type MkdirRequest struct {
+ Header
+ Name string
+ Mode os.FileMode
+}
+
+func (r *MkdirRequest) String() string {
+ return fmt.Sprintf("Mkdir [%s] %q mode=%v", &r.Header, r.Name, r.Mode)
+}
+
+// Respond replies to the request with the given response.
+func (r *MkdirRequest) Respond(resp *MkdirResponse) {
+ out := &entryOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Nodeid: uint64(resp.Node),
+ Generation: resp.Generation,
+ EntryValid: uint64(resp.EntryValid / time.Second),
+ EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A MkdirResponse is the response to a MkdirRequest.
+type MkdirResponse struct {
+ LookupResponse
+}
+
+func (r *MkdirResponse) String() string {
+ return fmt.Sprintf("Mkdir %+v", *r)
+}
+
+// A ReadRequest asks to read from an open file.
+type ReadRequest struct {
+ Header
+ Dir bool // is this Readdir?
+ Handle HandleID
+ Offset int64
+ Size int
+}
+
+func (r *ReadRequest) handle() HandleID {
+ return r.Handle
+}
+
+func (r *ReadRequest) String() string {
+ return fmt.Sprintf("Read [%s] %#x %d @%#x dir=%v", &r.Header, r.Handle, r.Size, r.Offset, r.Dir)
+}
+
+// Respond replies to the request with the given response.
+func (r *ReadRequest) Respond(resp *ReadResponse) {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respondData(out, unsafe.Sizeof(*out), resp.Data)
+}
+
+// A ReadResponse is the response to a ReadRequest.
+type ReadResponse struct {
+ Data []byte
+}
+
+func (r *ReadResponse) String() string {
+ return fmt.Sprintf("Read %x", r.Data)
+}
+
+// A ReleaseRequest asks to release (close) an open file handle.
+type ReleaseRequest struct {
+ Header
+ Dir bool // is this Releasedir?
+ Handle HandleID
+ Flags uint32 // flags from OpenRequest
+ ReleaseFlags ReleaseFlags
+ LockOwner uint32
+}
+
+func (r *ReleaseRequest) handle() HandleID {
+ return r.Handle
+}
+
+func (r *ReleaseRequest) String() string {
+ return fmt.Sprintf("Release [%s] %#x fl=%v rfl=%v owner=%#x", &r.Header, r.Handle, r.Flags, r.ReleaseFlags, r.LockOwner)
+}
+
+// Respond replies to the request, indicating that the handle has been released.
+func (r *ReleaseRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+// A DestroyRequest is sent by the kernel when unmounting the file system.
+// No more requests will be received after this one, but it should still be
+// responded to.
+type DestroyRequest struct {
+ Header
+}
+
+func (r *DestroyRequest) String() string {
+ return fmt.Sprintf("Destroy [%s]", &r.Header)
+}
+
+// Respond replies to the request.
+func (r *DestroyRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+// A ForgetRequest is sent by the kernel when forgetting about r.Node
+// as returned by r.N lookup requests.
+type ForgetRequest struct {
+ Header
+ N uint64
+}
+
+func (r *ForgetRequest) String() string {
+ return fmt.Sprintf("Forget [%s] %d", &r.Header, r.N)
+}
+
+// Respond replies to the request, indicating that the forgetfulness has been recorded.
+func (r *ForgetRequest) Respond() {
+ // Don't reply to forget messages.
+}
+
+// A Dirent represents a single directory entry.
+type Dirent struct {
+ Inode uint64 // inode this entry names
+ Type uint32 // ?
+ Name string // name of entry
+}
+
+// AppendDirent appends the encoded form of a directory entry to data
+// and returns the resulting slice.
+func AppendDirent(data []byte, dir Dirent) []byte {
+ de := dirent{
+ Ino: dir.Inode,
+ Namelen: uint32(len(dir.Name)),
+ Type: dir.Type,
+ }
+ de.Off = uint64(len(data) + direntSize + (len(dir.Name)+7)&^7)
+ data = append(data, (*[direntSize]byte)(unsafe.Pointer(&de))[:]...)
+ data = append(data, dir.Name...)
+ n := direntSize + uintptr(len(dir.Name))
+ if n%8 != 0 {
+ var pad [8]byte
+ data = append(data, pad[:8-n%8]...)
+ }
+ return data
+}
+
+// A WriteRequest asks to write to an open file.
+type WriteRequest struct {
+ Header
+ Handle HandleID
+ Offset int64
+ Data []byte
+ Flags WriteFlags
+}
+
+func (r *WriteRequest) String() string {
+ return fmt.Sprintf("Write [%s] %#x %d @%d fl=%v", &r.Header, r.Handle, len(r.Data), r.Offset, r.Flags)
+}
+
+// Respond replies to the request with the given response.
+func (r *WriteRequest) Respond(resp *WriteResponse) {
+ out := &writeOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Size: uint32(resp.Size),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+func (r *WriteRequest) handle() HandleID {
+ return r.Handle
+}
+
+// A WriteResponse replies to a write indicating how many bytes were written.
+type WriteResponse struct {
+ Size int
+}
+
+func (r *WriteResponse) String() string {
+ return fmt.Sprintf("Write %+v", *r)
+}
+
+// A SetattrRequest asks to change one or more attributes associated with a file,
+// as indicated by Valid.
+type SetattrRequest struct {
+ Header
+ Valid SetattrValid
+ Handle HandleID
+ Size uint64
+ Atime time.Time
+ Mtime time.Time
+ Mode os.FileMode
+ Uid uint32
+ Gid uint32
+
+ // OS X only
+ Bkuptime time.Time
+ Chgtime time.Time
+ Crtime time.Time
+ Flags uint32 // see chflags(2)
+}
+
+func (r *SetattrRequest) String() string {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "Setattr [%s]", &r.Header)
+ if r.Valid.Mode() {
+ fmt.Fprintf(&buf, " mode=%v", r.Mode)
+ }
+ if r.Valid.Uid() {
+ fmt.Fprintf(&buf, " uid=%d", r.Uid)
+ }
+ if r.Valid.Gid() {
+ fmt.Fprintf(&buf, " gid=%d", r.Gid)
+ }
+ if r.Valid.Size() {
+ fmt.Fprintf(&buf, " size=%d", r.Size)
+ }
+ if r.Valid.Atime() {
+ fmt.Fprintf(&buf, " atime=%v", r.Atime)
+ }
+ if r.Valid.Mtime() {
+ fmt.Fprintf(&buf, " mtime=%v", r.Mtime)
+ }
+ if r.Valid.Handle() {
+ fmt.Fprintf(&buf, " handle=%#x", r.Handle)
+ } else {
+ fmt.Fprintf(&buf, " handle=INVALID-%#x", r.Handle)
+ }
+ if r.Valid.Crtime() {
+ fmt.Fprintf(&buf, " crtime=%v", r.Crtime)
+ }
+ if r.Valid.Chgtime() {
+ fmt.Fprintf(&buf, " chgtime=%v", r.Chgtime)
+ }
+ if r.Valid.Bkuptime() {
+ fmt.Fprintf(&buf, " bkuptime=%v", r.Bkuptime)
+ }
+ if r.Valid.Flags() {
+ fmt.Fprintf(&buf, " flags=%#x", r.Flags)
+ }
+ return buf.String()
+}
+
+func (r *SetattrRequest) handle() HandleID {
+ if r.Valid.Handle() {
+ return r.Handle
+ }
+ return 0
+}
+
+// Respond replies to the request with the given response,
+// giving the updated attributes.
+func (r *SetattrRequest) Respond(resp *SetattrResponse) {
+ out := &attrOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A SetattrResponse is the response to a SetattrRequest.
+type SetattrResponse struct {
+ AttrValid time.Duration // how long Attr can be cached
+ Attr Attr // file attributes
+}
+
+func (r *SetattrResponse) String() string {
+ return fmt.Sprintf("Setattr %+v", *r)
+}
+
+// A FlushRequest asks for the current state of an open file to be flushed
+// to storage, as when a file descriptor is being closed. A single opened Handle
+// may receive multiple FlushRequests over its lifetime.
+type FlushRequest struct {
+ Header
+ Handle HandleID
+ Flags uint32
+ LockOwner uint64
+}
+
+func (r *FlushRequest) String() string {
+ return fmt.Sprintf("Flush [%s] %#x fl=%#x lk=%#x", &r.Header, r.Handle, r.Flags, r.LockOwner)
+}
+
+func (r *FlushRequest) handle() HandleID {
+ return r.Handle
+}
+
+// Respond replies to the request, indicating that the flush succeeded.
+func (r *FlushRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+// A RemoveRequest asks to remove a file or directory.
+type RemoveRequest struct {
+ Header
+ Name string // name of extended attribute
+ Dir bool // is this rmdir?
+}
+
+func (r *RemoveRequest) String() string {
+ return fmt.Sprintf("Remove [%s] %q dir=%v", &r.Header, r.Name, r.Dir)
+}
+
+// Respond replies to the request, indicating that the file was removed.
+func (r *RemoveRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+// A SymlinkRequest is a request to create a symlink making NewName point to Target.
+type SymlinkRequest struct {
+ Header
+ NewName, Target string
+}
+
+func (r *SymlinkRequest) String() string {
+ return fmt.Sprintf("Symlink [%s] from %q to target %q", &r.Header, r.NewName, r.Target)
+}
+
+func (r *SymlinkRequest) handle() HandleID {
+ return 0
+}
+
+// Respond replies to the request, indicating that the symlink was created.
+func (r *SymlinkRequest) Respond(resp *SymlinkResponse) {
+ out := &entryOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Nodeid: uint64(resp.Node),
+ Generation: resp.Generation,
+ EntryValid: uint64(resp.EntryValid / time.Second),
+ EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A SymlinkResponse is the response to a SymlinkRequest.
+type SymlinkResponse struct {
+ LookupResponse
+}
+
+// A ReadlinkRequest is a request to read a symlink's target.
+type ReadlinkRequest struct {
+ Header
+}
+
+func (r *ReadlinkRequest) String() string {
+ return fmt.Sprintf("Readlink [%s]", &r.Header)
+}
+
+func (r *ReadlinkRequest) handle() HandleID {
+ return 0
+}
+
+func (r *ReadlinkRequest) Respond(target string) {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respondData(out, unsafe.Sizeof(*out), []byte(target))
+}
+
+// A LinkRequest is a request to create a hard link.
+type LinkRequest struct {
+ Header
+ OldNode NodeID
+ NewName string
+}
+
+func (r *LinkRequest) Respond(resp *LookupResponse) {
+ out := &entryOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Nodeid: uint64(resp.Node),
+ Generation: resp.Generation,
+ EntryValid: uint64(resp.EntryValid / time.Second),
+ EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A RenameRequest is a request to rename a file.
+type RenameRequest struct {
+ Header
+ NewDir NodeID
+ OldName, NewName string
+}
+
+func (r *RenameRequest) handle() HandleID {
+ return 0
+}
+
+func (r *RenameRequest) String() string {
+ return fmt.Sprintf("Rename [%s] from %q to dirnode %d %q", &r.Header, r.OldName, r.NewDir, r.NewName)
+}
+
+func (r *RenameRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+type MknodRequest struct {
+ Header
+ Name string
+ Mode os.FileMode
+ Rdev uint32
+}
+
+func (r *MknodRequest) String() string {
+ return fmt.Sprintf("Mknod [%s] Name %q mode %v rdev %d", &r.Header, r.Name, r.Mode, r.Rdev)
+}
+
+func (r *MknodRequest) Respond(resp *LookupResponse) {
+ out := &entryOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ Nodeid: uint64(resp.Node),
+ Generation: resp.Generation,
+ EntryValid: uint64(resp.EntryValid / time.Second),
+ EntryValidNsec: uint32(resp.EntryValid % time.Second / time.Nanosecond),
+ AttrValid: uint64(resp.AttrValid / time.Second),
+ AttrValidNsec: uint32(resp.AttrValid % time.Second / time.Nanosecond),
+ Attr: resp.Attr.attr(),
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+type FsyncRequest struct {
+ Header
+ Handle HandleID
+ Flags uint32
+}
+
+func (r *FsyncRequest) String() string {
+ return fmt.Sprintf("Fsync [%s] Handle %v Flags %v", &r.Header, r.Handle, r.Flags)
+}
+
+func (r *FsyncRequest) Respond() {
+ out := &outHeader{Unique: uint64(r.ID)}
+ r.Conn.respond(out, unsafe.Sizeof(*out))
+}
+
+/*{
+
+// A XXXRequest xxx.
+type XXXRequest struct {
+ Header
+ xxx
+}
+
+func (r *XXXRequest) String() string {
+ return fmt.Sprintf("XXX [%s] xxx", &r.Header)
+}
+
+func (r *XXXRequest) handle() HandleID {
+ return r.Handle
+}
+
+// Respond replies to the request with the given response.
+func (r *XXXRequest) Respond(resp *XXXResponse) {
+ out := &xxxOut{
+ outHeader: outHeader{Unique: uint64(r.ID)},
+ xxx,
+ }
+ r.Conn.respond(&out.outHeader, unsafe.Sizeof(*out))
+}
+
+// A XXXResponse is the response to a XXXRequest.
+type XXXResponse struct {
+ xxx
+}
+
+func (r *XXXResponse) String() string {
+ return fmt.Sprintf("XXX %+v", *r)
+}
+
+ }
+*/
diff --git a/vendor/github.com/mattermost/rsc/fuse/fuse_kernel.go b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel.go
new file mode 100644
index 000000000..a57360e63
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel.go
@@ -0,0 +1,539 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Derived from FUSE's fuse_kernel.h
+/*
+ This file defines the kernel interface of FUSE
+ Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
+
+
+ This -- and only this -- header file may also be distributed under
+ the terms of the BSD Licence as follows:
+
+ Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+
+package fuse
+
+import (
+ "fmt"
+ "unsafe"
+)
+
+// Version is the FUSE version implemented by the package.
+const Version = "7.8"
+
+const (
+ kernelVersion = 7
+ kernelMinorVersion = 8
+ rootID = 1
+)
+
+type kstatfs struct {
+ Blocks uint64
+ Bfree uint64
+ Bavail uint64
+ Files uint64
+ Ffree uint64
+ Bsize uint32
+ Namelen uint32
+ Frsize uint32
+ Padding uint32
+ Spare [6]uint32
+}
+
+type fileLock struct {
+ Start uint64
+ End uint64
+ Type uint32
+ Pid uint32
+}
+
+// The SetattrValid are bit flags describing which fields in the SetattrRequest
+// are included in the change.
+type SetattrValid uint32
+
+const (
+ SetattrMode SetattrValid = 1 << 0
+ SetattrUid SetattrValid = 1 << 1
+ SetattrGid SetattrValid = 1 << 2
+ SetattrSize SetattrValid = 1 << 3
+ SetattrAtime SetattrValid = 1 << 4
+ SetattrMtime SetattrValid = 1 << 5
+ SetattrHandle SetattrValid = 1 << 6 // TODO: What does this mean?
+
+ // Linux only(?)
+ SetattrAtimeNow SetattrValid = 1 << 7
+ SetattrMtimeNow SetattrValid = 1 << 8
+ SetattrLockOwner SetattrValid = 1 << 9 // http://www.mail-archive.com/git-commits-head@vger.kernel.org/msg27852.html
+
+ // OS X only
+ SetattrCrtime SetattrValid = 1 << 28
+ SetattrChgtime SetattrValid = 1 << 29
+ SetattrBkuptime SetattrValid = 1 << 30
+ SetattrFlags SetattrValid = 1 << 31
+)
+
+func (fl SetattrValid) Mode() bool { return fl&SetattrMode != 0 }
+func (fl SetattrValid) Uid() bool { return fl&SetattrUid != 0 }
+func (fl SetattrValid) Gid() bool { return fl&SetattrGid != 0 }
+func (fl SetattrValid) Size() bool { return fl&SetattrSize != 0 }
+func (fl SetattrValid) Atime() bool { return fl&SetattrAtime != 0 }
+func (fl SetattrValid) Mtime() bool { return fl&SetattrMtime != 0 }
+func (fl SetattrValid) Handle() bool { return fl&SetattrHandle != 0 }
+func (fl SetattrValid) Crtime() bool { return fl&SetattrCrtime != 0 }
+func (fl SetattrValid) Chgtime() bool { return fl&SetattrChgtime != 0 }
+func (fl SetattrValid) Bkuptime() bool { return fl&SetattrBkuptime != 0 }
+func (fl SetattrValid) Flags() bool { return fl&SetattrFlags != 0 }
+
+func (fl SetattrValid) String() string {
+ return flagString(uint32(fl), setattrValidNames)
+}
+
+var setattrValidNames = []flagName{
+ {uint32(SetattrMode), "SetattrMode"},
+ {uint32(SetattrUid), "SetattrUid"},
+ {uint32(SetattrGid), "SetattrGid"},
+ {uint32(SetattrSize), "SetattrSize"},
+ {uint32(SetattrAtime), "SetattrAtime"},
+ {uint32(SetattrMtime), "SetattrMtime"},
+ {uint32(SetattrHandle), "SetattrHandle"},
+ {uint32(SetattrCrtime), "SetattrCrtime"},
+ {uint32(SetattrChgtime), "SetattrChgtime"},
+ {uint32(SetattrBkuptime), "SetattrBkuptime"},
+ {uint32(SetattrFlags), "SetattrFlags"},
+}
+
+// The OpenFlags are returned in the OpenResponse.
+type OpenFlags uint32
+
+const (
+ OpenDirectIO OpenFlags = 1 << 0 // bypass page cache for this open file
+ OpenKeepCache OpenFlags = 1 << 1 // don't invalidate the data cache on open
+ OpenNonSeekable OpenFlags = 1 << 2 // (Linux?)
+
+ OpenPurgeAttr OpenFlags = 1 << 30 // OS X
+ OpenPurgeUBC OpenFlags = 1 << 31 // OS X
+)
+
+func (fl OpenFlags) String() string {
+ return flagString(uint32(fl), openFlagNames)
+}
+
+var openFlagNames = []flagName{
+ {uint32(OpenDirectIO), "OpenDirectIO"},
+ {uint32(OpenKeepCache), "OpenKeepCache"},
+ {uint32(OpenPurgeAttr), "OpenPurgeAttr"},
+ {uint32(OpenPurgeUBC), "OpenPurgeUBC"},
+}
+
+// The InitFlags are used in the Init exchange.
+type InitFlags uint32
+
+const (
+ InitAsyncRead InitFlags = 1 << 0
+ InitPosixLocks InitFlags = 1 << 1
+
+ InitCaseSensitive InitFlags = 1 << 29 // OS X only
+ InitVolRename InitFlags = 1 << 30 // OS X only
+ InitXtimes InitFlags = 1 << 31 // OS X only
+)
+
+type flagName struct {
+ bit uint32
+ name string
+}
+
+var initFlagNames = []flagName{
+ {uint32(InitAsyncRead), "InitAsyncRead"},
+ {uint32(InitPosixLocks), "InitPosixLocks"},
+ {uint32(InitCaseSensitive), "InitCaseSensitive"},
+ {uint32(InitVolRename), "InitVolRename"},
+ {uint32(InitXtimes), "InitXtimes"},
+}
+
+func (fl InitFlags) String() string {
+ return flagString(uint32(fl), initFlagNames)
+}
+
+func flagString(f uint32, names []flagName) string {
+ var s string
+
+ if f == 0 {
+ return "0"
+ }
+
+ for _, n := range names {
+ if f&n.bit != 0 {
+ s += "+" + n.name
+ f &^= n.bit
+ }
+ }
+ if f != 0 {
+ s += fmt.Sprintf("%+#x", f)
+ }
+ return s[1:]
+}
+
+// The ReleaseFlags are used in the Release exchange.
+type ReleaseFlags uint32
+
+const (
+ ReleaseFlush ReleaseFlags = 1 << 0
+)
+
+func (fl ReleaseFlags) String() string {
+ return flagString(uint32(fl), releaseFlagNames)
+}
+
+var releaseFlagNames = []flagName{
+ {uint32(ReleaseFlush), "ReleaseFlush"},
+}
+
+// Opcodes
+const (
+ opLookup = 1
+ opForget = 2 // no reply
+ opGetattr = 3
+ opSetattr = 4
+ opReadlink = 5
+ opSymlink = 6
+ opMknod = 8
+ opMkdir = 9
+ opUnlink = 10
+ opRmdir = 11
+ opRename = 12
+ opLink = 13
+ opOpen = 14
+ opRead = 15
+ opWrite = 16
+ opStatfs = 17
+ opRelease = 18
+ opFsync = 20
+ opSetxattr = 21
+ opGetxattr = 22
+ opListxattr = 23
+ opRemovexattr = 24
+ opFlush = 25
+ opInit = 26
+ opOpendir = 27
+ opReaddir = 28
+ opReleasedir = 29
+ opFsyncdir = 30
+ opGetlk = 31
+ opSetlk = 32
+ opSetlkw = 33
+ opAccess = 34
+ opCreate = 35
+ opInterrupt = 36
+ opBmap = 37
+ opDestroy = 38
+ opIoctl = 39 // Linux?
+ opPoll = 40 // Linux?
+
+ // OS X
+ opSetvolname = 61
+ opGetxtimes = 62
+ opExchange = 63
+)
+
+// The read buffer is required to be at least 8k but may be much larger
+const minReadBuffer = 8192
+
+type entryOut struct {
+ outHeader
+ Nodeid uint64 // Inode ID
+ Generation uint64 // Inode generation
+ EntryValid uint64 // Cache timeout for the name
+ AttrValid uint64 // Cache timeout for the attributes
+ EntryValidNsec uint32
+ AttrValidNsec uint32
+ Attr attr
+}
+
+type forgetIn struct {
+ Nlookup uint64
+}
+
+type attrOut struct {
+ outHeader
+ AttrValid uint64 // Cache timeout for the attributes
+ AttrValidNsec uint32
+ Dummy uint32
+ Attr attr
+}
+
+// OS X
+type getxtimesOut struct {
+ outHeader
+ Bkuptime uint64
+ Crtime uint64
+ BkuptimeNsec uint32
+ CrtimeNsec uint32
+}
+
+type mknodIn struct {
+ Mode uint32
+ Rdev uint32
+ // "filename\x00" follows.
+}
+
+type mkdirIn struct {
+ Mode uint32
+ Padding uint32
+ // filename follows
+}
+
+type renameIn struct {
+ Newdir uint64
+ // "oldname\x00newname\x00" follows
+}
+
+// OS X
+type exchangeIn struct {
+ Olddir uint64
+ Newdir uint64
+ Options uint64
+}
+
+type linkIn struct {
+ Oldnodeid uint64
+}
+
+type setattrInCommon struct {
+ Valid uint32
+ Padding uint32
+ Fh uint64
+ Size uint64
+ LockOwner uint64 // unused on OS X?
+ Atime uint64
+ Mtime uint64
+ Unused2 uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ Unused3 uint32
+ Mode uint32
+ Unused4 uint32
+ Uid uint32
+ Gid uint32
+ Unused5 uint32
+}
+
+type openIn struct {
+ Flags uint32
+ Mode uint32
+}
+
+type openOut struct {
+ outHeader
+ Fh uint64
+ OpenFlags uint32
+ Padding uint32
+}
+
+type createOut struct {
+ outHeader
+
+ Nodeid uint64 // Inode ID
+ Generation uint64 // Inode generation
+ EntryValid uint64 // Cache timeout for the name
+ AttrValid uint64 // Cache timeout for the attributes
+ EntryValidNsec uint32
+ AttrValidNsec uint32
+ Attr attr
+
+ Fh uint64
+ OpenFlags uint32
+ Padding uint32
+}
+
+type releaseIn struct {
+ Fh uint64
+ Flags uint32
+ ReleaseFlags uint32
+ LockOwner uint32
+}
+
+type flushIn struct {
+ Fh uint64
+ FlushFlags uint32
+ Padding uint32
+ LockOwner uint64
+}
+
+type readIn struct {
+ Fh uint64
+ Offset uint64
+ Size uint32
+ Padding uint32
+}
+
+type writeIn struct {
+ Fh uint64
+ Offset uint64
+ Size uint32
+ WriteFlags uint32
+}
+
+type writeOut struct {
+ outHeader
+ Size uint32
+ Padding uint32
+}
+
+// The WriteFlags are returned in the WriteResponse.
+type WriteFlags uint32
+
+func (fl WriteFlags) String() string {
+ return flagString(uint32(fl), writeFlagNames)
+}
+
+var writeFlagNames = []flagName{}
+
+const compatStatfsSize = 48
+
+type statfsOut struct {
+ outHeader
+ St kstatfs
+}
+
+type fsyncIn struct {
+ Fh uint64
+ FsyncFlags uint32
+ Padding uint32
+}
+
+type setxattrIn struct {
+ Size uint32
+ Flags uint32
+}
+
+type setxattrInOSX struct {
+ Size uint32
+ Flags uint32
+
+ // OS X only
+ Position uint32
+ Padding uint32
+}
+
+type getxattrIn struct {
+ Size uint32
+ Padding uint32
+}
+
+type getxattrInOSX struct {
+ Size uint32
+ Padding uint32
+
+ // OS X only
+ Position uint32
+ Padding2 uint32
+}
+
+type getxattrOut struct {
+ outHeader
+ Size uint32
+ Padding uint32
+}
+
+type lkIn struct {
+ Fh uint64
+ Owner uint64
+ Lk fileLock
+}
+
+type lkOut struct {
+ outHeader
+ Lk fileLock
+}
+
+type accessIn struct {
+ Mask uint32
+ Padding uint32
+}
+
+type initIn struct {
+ Major uint32
+ Minor uint32
+ MaxReadahead uint32
+ Flags uint32
+}
+
+const initInSize = int(unsafe.Sizeof(initIn{}))
+
+type initOut struct {
+ outHeader
+ Major uint32
+ Minor uint32
+ MaxReadahead uint32
+ Flags uint32
+ Unused uint32
+ MaxWrite uint32
+}
+
+type interruptIn struct {
+ Unique uint64
+}
+
+type bmapIn struct {
+ Block uint64
+ BlockSize uint32
+ Padding uint32
+}
+
+type bmapOut struct {
+ outHeader
+ Block uint64
+}
+
+type inHeader struct {
+ Len uint32
+ Opcode uint32
+ Unique uint64
+ Nodeid uint64
+ Uid uint32
+ Gid uint32
+ Pid uint32
+ Padding uint32
+}
+
+const inHeaderSize = int(unsafe.Sizeof(inHeader{}))
+
+type outHeader struct {
+ Len uint32
+ Error int32
+ Unique uint64
+}
+
+type dirent struct {
+ Ino uint64
+ Off uint64
+ Namelen uint32
+ Type uint32
+ Name [0]byte
+}
+
+const direntSize = 8 + 8 + 4 + 4
diff --git a/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_darwin.go b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_darwin.go
new file mode 100644
index 000000000..f7bc37766
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_darwin.go
@@ -0,0 +1,58 @@
+package fuse
+
+import (
+ "time"
+)
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ Crtime_ uint64 // OS X only
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ CrtimeNsec uint32 // OS X only
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ Flags_ uint32 // OS X only; see chflags(2)
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ a.Crtime_, a.CrtimeNsec = s, ns
+}
+
+func (a *attr) SetFlags(f uint32) {
+ a.Flags_ = f
+}
+
+type setattrIn struct {
+ setattrInCommon
+
+ // OS X only
+ Bkuptime_ uint64
+ Chgtime_ uint64
+ Crtime uint64
+ BkuptimeNsec uint32
+ ChgtimeNsec uint32
+ CrtimeNsec uint32
+ Flags_ uint32 // see chflags(2)
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Unix(int64(in.Bkuptime_), int64(in.BkuptimeNsec))
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Unix(int64(in.Chgtime_), int64(in.ChgtimeNsec))
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return in.Flags_
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_linux.go b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_linux.go
new file mode 100644
index 000000000..914bc3063
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_linux.go
@@ -0,0 +1,50 @@
+package fuse
+
+import "time"
+
+type attr struct {
+ Ino uint64
+ Size uint64
+ Blocks uint64
+ Atime uint64
+ Mtime uint64
+ Ctime uint64
+ AtimeNsec uint32
+ MtimeNsec uint32
+ CtimeNsec uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint32
+ // Blksize uint32 // Only in protocol 7.9
+ // padding_ uint32 // Only in protocol 7.9
+}
+
+func (a *attr) Crtime() time.Time {
+ return time.Time{}
+}
+
+func (a *attr) SetCrtime(s uint64, ns uint32) {
+ // Ignored on Linux.
+}
+
+func (a *attr) SetFlags(f uint32) {
+ // Ignored on Linux.
+}
+
+type setattrIn struct {
+ setattrInCommon
+}
+
+func (in *setattrIn) BkupTime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Chgtime() time.Time {
+ return time.Time{}
+}
+
+func (in *setattrIn) Flags() uint32 {
+ return 0
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_std.go b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_std.go
new file mode 100644
index 000000000..074cfd322
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/fuse_kernel_std.go
@@ -0,0 +1 @@
+package fuse
diff --git a/vendor/github.com/mattermost/rsc/fuse/fuse_test.go b/vendor/github.com/mattermost/rsc/fuse/fuse_test.go
new file mode 100644
index 000000000..61533b8c5
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/fuse_test.go
@@ -0,0 +1,594 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fuse
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "runtime"
+ "syscall"
+ "testing"
+ "time"
+)
+
+var fuseRun = flag.String("fuserun", "", "which fuse test to run. runs all if empty.")
+
+// umount tries its best to unmount dir.
+func umount(dir string) {
+ err := exec.Command("umount", dir).Run()
+ if err != nil && runtime.GOOS == "linux" {
+ exec.Command("/bin/fusermount", "-u", dir).Run()
+ }
+}
+
+func TestFuse(t *testing.T) {
+ Debugf = log.Printf
+ dir, err := ioutil.TempDir("", "fusetest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ os.MkdirAll(dir, 0777)
+
+ c, err := Mount(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer umount(dir)
+
+ go func() {
+ err := c.Serve(testFS{})
+ if err != nil {
+ fmt.Printf("SERVE ERROR: %v\n", err)
+ }
+ }()
+
+ waitForMount(t, dir)
+
+ for _, tt := range fuseTests {
+ if *fuseRun == "" || *fuseRun == tt.name {
+ t.Logf("running %T", tt.node)
+ tt.node.test(dir+"/"+tt.name, t)
+ }
+ }
+}
+
+func waitForMount(t *testing.T, dir string) {
+ // Filename to wait for in dir:
+ probeEntry := *fuseRun
+ if probeEntry == "" {
+ probeEntry = fuseTests[0].name
+ }
+ for tries := 0; tries < 100; tries++ {
+ _, err := os.Stat(dir + "/" + probeEntry)
+ if err == nil {
+ return
+ }
+ time.Sleep(10 * time.Millisecond)
+ }
+ t.Fatalf("mount did not work")
+}
+
+var fuseTests = []struct {
+ name string
+ node interface {
+ Node
+ test(string, *testing.T)
+ }
+}{
+ {"readAll", readAll{}},
+ {"readAll1", &readAll1{}},
+ {"write", &write{}},
+ {"writeAll", &writeAll{}},
+ {"writeAll2", &writeAll2{}},
+ {"release", &release{}},
+ {"mkdir1", &mkdir1{}},
+ {"create1", &create1{}},
+ {"create2", &create2{}},
+ {"symlink1", &symlink1{}},
+ {"link1", &link1{}},
+ {"rename1", &rename1{}},
+ {"mknod1", &mknod1{}},
+}
+
+// TO TEST:
+// Statfs
+// Lookup(*LookupRequest, *LookupResponse)
+// Getattr(*GetattrRequest, *GetattrResponse)
+// Attr with explicit inode
+// Setattr(*SetattrRequest, *SetattrResponse)
+// Access(*AccessRequest)
+// Open(*OpenRequest, *OpenResponse)
+// Getxattr, Setxattr, Listxattr, Removexattr
+// Write(*WriteRequest, *WriteResponse)
+// Flush(*FlushRequest, *FlushResponse)
+
+// Test Read calling ReadAll.
+
+type readAll struct{ file }
+
+const hi = "hello, world"
+
+func (readAll) ReadAll(intr Intr) ([]byte, Error) {
+ return []byte(hi), nil
+}
+
+func (readAll) test(path string, t *testing.T) {
+ data, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Errorf("readAll: %v", err)
+ return
+ }
+ if string(data) != hi {
+ t.Errorf("readAll = %q, want %q", data, hi)
+ }
+}
+
+// Test Read.
+
+type readAll1 struct{ file }
+
+func (readAll1) Read(req *ReadRequest, resp *ReadResponse, intr Intr) Error {
+ HandleRead(req, resp, []byte(hi))
+ return nil
+}
+
+func (readAll1) test(path string, t *testing.T) {
+ readAll{}.test(path, t)
+}
+
+// Test Write calling basic Write, with an fsync thrown in too.
+
+type write struct {
+ file
+ data []byte
+ gotfsync bool
+}
+
+func (w *write) Write(req *WriteRequest, resp *WriteResponse, intr Intr) Error {
+ w.data = append(w.data, req.Data...)
+ resp.Size = len(req.Data)
+ return nil
+}
+
+func (w *write) Fsync(r *FsyncRequest, intr Intr) Error {
+ w.gotfsync = true
+ return nil
+}
+
+func (w *write) test(path string, t *testing.T) {
+ log.Printf("pre-write Create")
+ f, err := os.Create(path)
+ if err != nil {
+ t.Fatalf("Create: %v", err)
+ }
+ log.Printf("pre-write Write")
+ n, err := f.Write([]byte(hi))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ if n != len(hi) {
+ t.Fatalf("short write; n=%d; hi=%d", n, len(hi))
+ }
+
+ err = syscall.Fsync(int(f.Fd()))
+ if err != nil {
+ t.Fatalf("Fsync = %v", err)
+ }
+ if !w.gotfsync {
+ t.Errorf("never received expected fsync call")
+ }
+
+ log.Printf("pre-write Close")
+ err = f.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ log.Printf("post-write Close")
+ if string(w.data) != hi {
+ t.Errorf("writeAll = %q, want %q", w.data, hi)
+ }
+}
+
+// Test Write calling WriteAll.
+
+type writeAll struct {
+ file
+ data []byte
+ gotfsync bool
+}
+
+func (w *writeAll) Fsync(r *FsyncRequest, intr Intr) Error {
+ w.gotfsync = true
+ return nil
+}
+
+func (w *writeAll) WriteAll(data []byte, intr Intr) Error {
+ w.data = data
+ return nil
+}
+
+func (w *writeAll) test(path string, t *testing.T) {
+ err := ioutil.WriteFile(path, []byte(hi), 0666)
+ if err != nil {
+ t.Fatalf("WriteFile: %v", err)
+ return
+ }
+ if string(w.data) != hi {
+ t.Errorf("writeAll = %q, want %q", w.data, hi)
+ }
+}
+
+// Test Write calling Setattr+Write+Flush.
+
+type writeAll2 struct {
+ file
+ data []byte
+ setattr bool
+ flush bool
+}
+
+func (w *writeAll2) Setattr(req *SetattrRequest, resp *SetattrResponse, intr Intr) Error {
+ w.setattr = true
+ return nil
+}
+
+func (w *writeAll2) Flush(req *FlushRequest, intr Intr) Error {
+ w.flush = true
+ return nil
+}
+
+func (w *writeAll2) Write(req *WriteRequest, resp *WriteResponse, intr Intr) Error {
+ w.data = append(w.data, req.Data...)
+ resp.Size = len(req.Data)
+ return nil
+}
+
+func (w *writeAll2) test(path string, t *testing.T) {
+ err := ioutil.WriteFile(path, []byte(hi), 0666)
+ if err != nil {
+ t.Errorf("WriteFile: %v", err)
+ return
+ }
+ if !w.setattr || string(w.data) != hi || !w.flush {
+ t.Errorf("writeAll = %v, %q, %v, want %v, %q, %v", w.setattr, string(w.data), w.flush, true, hi, true)
+ }
+}
+
+// Test Mkdir.
+
+type mkdir1 struct {
+ dir
+ name string
+}
+
+func (f *mkdir1) Mkdir(req *MkdirRequest, intr Intr) (Node, Error) {
+ f.name = req.Name
+ return &mkdir1{}, nil
+}
+
+func (f *mkdir1) test(path string, t *testing.T) {
+ f.name = ""
+ err := os.Mkdir(path+"/foo", 0777)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if f.name != "foo" {
+ t.Error(err)
+ return
+ }
+}
+
+// Test Create (and fsync)
+
+type create1 struct {
+ dir
+ name string
+ f *writeAll
+}
+
+func (f *create1) Create(req *CreateRequest, resp *CreateResponse, intr Intr) (Node, Handle, Error) {
+ f.name = req.Name
+ f.f = &writeAll{}
+ return f.f, f.f, nil
+}
+
+func (f *create1) test(path string, t *testing.T) {
+ f.name = ""
+ ff, err := os.Create(path + "/foo")
+ if err != nil {
+ t.Errorf("create1 WriteFile: %v", err)
+ return
+ }
+
+ err = syscall.Fsync(int(ff.Fd()))
+ if err != nil {
+ t.Fatalf("Fsync = %v", err)
+ }
+
+ if !f.f.gotfsync {
+ t.Errorf("never received expected fsync call")
+ }
+
+ ff.Close()
+ if f.name != "foo" {
+ t.Errorf("create1 name=%q want foo", f.name)
+ }
+}
+
+// Test Create + WriteAll + Remove
+
+type create2 struct {
+ dir
+ name string
+ f *writeAll
+ fooExists bool
+}
+
+func (f *create2) Create(req *CreateRequest, resp *CreateResponse, intr Intr) (Node, Handle, Error) {
+ f.name = req.Name
+ f.f = &writeAll{}
+ return f.f, f.f, nil
+}
+
+func (f *create2) Lookup(name string, intr Intr) (Node, Error) {
+ if f.fooExists && name == "foo" {
+ return file{}, nil
+ }
+ return nil, ENOENT
+}
+
+func (f *create2) Remove(r *RemoveRequest, intr Intr) Error {
+ if f.fooExists && r.Name == "foo" && !r.Dir {
+ f.fooExists = false
+ return nil
+ }
+ return ENOENT
+}
+
+func (f *create2) test(path string, t *testing.T) {
+ f.name = ""
+ err := ioutil.WriteFile(path+"/foo", []byte(hi), 0666)
+ if err != nil {
+ t.Fatalf("create2 WriteFile: %v", err)
+ }
+ if string(f.f.data) != hi {
+ t.Fatalf("create2 writeAll = %q, want %q", f.f.data, hi)
+ }
+
+ f.fooExists = true
+ log.Printf("pre-Remove")
+ err = os.Remove(path + "/foo")
+ if err != nil {
+ t.Fatalf("Remove: %v", err)
+ }
+ err = os.Remove(path + "/foo")
+ if err == nil {
+ t.Fatalf("second Remove = nil; want some error")
+ }
+}
+
+// Test symlink + readlink
+
+type symlink1 struct {
+ dir
+ newName, target string
+}
+
+func (f *symlink1) Symlink(req *SymlinkRequest, intr Intr) (Node, Error) {
+ f.newName = req.NewName
+ f.target = req.Target
+ return symlink{target: req.Target}, nil
+}
+
+func (f *symlink1) test(path string, t *testing.T) {
+ const target = "/some-target"
+
+ err := os.Symlink(target, path+"/symlink.file")
+ if err != nil {
+ t.Errorf("os.Symlink: %v", err)
+ return
+ }
+
+ if f.newName != "symlink.file" {
+ t.Errorf("symlink newName = %q; want %q", f.newName, "symlink.file")
+ }
+ if f.target != target {
+ t.Errorf("symlink target = %q; want %q", f.target, target)
+ }
+
+ gotName, err := os.Readlink(path + "/symlink.file")
+ if err != nil {
+ t.Errorf("os.Readlink: %v", err)
+ return
+ }
+ if gotName != target {
+ t.Errorf("os.Readlink = %q; want %q", gotName, target)
+ }
+}
+
+// Test link
+
+type link1 struct {
+ dir
+ newName string
+}
+
+func (f *link1) Lookup(name string, intr Intr) (Node, Error) {
+ if name == "old" {
+ return file{}, nil
+ }
+ return nil, ENOENT
+}
+
+func (f *link1) Link(r *LinkRequest, old Node, intr Intr) (Node, Error) {
+ f.newName = r.NewName
+ return file{}, nil
+}
+
+func (f *link1) test(path string, t *testing.T) {
+ err := os.Link(path+"/old", path+"/new")
+ if err != nil {
+ t.Fatalf("Link: %v", err)
+ }
+ if f.newName != "new" {
+ t.Fatalf("saw Link for newName %q; want %q", f.newName, "new")
+ }
+}
+
+// Test Rename
+
+type rename1 struct {
+ dir
+ renames int
+}
+
+func (f *rename1) Lookup(name string, intr Intr) (Node, Error) {
+ if name == "old" {
+ return file{}, nil
+ }
+ return nil, ENOENT
+}
+
+func (f *rename1) Rename(r *RenameRequest, newDir Node, intr Intr) Error {
+ if r.OldName == "old" && r.NewName == "new" && newDir == f {
+ f.renames++
+ return nil
+ }
+ return EIO
+}
+
+func (f *rename1) test(path string, t *testing.T) {
+ err := os.Rename(path+"/old", path+"/new")
+ if err != nil {
+ t.Fatalf("Rename: %v", err)
+ }
+ if f.renames != 1 {
+ t.Fatalf("expected rename didn't happen")
+ }
+ err = os.Rename(path+"/old2", path+"/new2")
+ if err == nil {
+ t.Fatal("expected error on second Rename; got nil")
+ }
+}
+
+// Test Release.
+
+type release struct {
+ file
+ did bool
+}
+
+func (r *release) Release(*ReleaseRequest, Intr) Error {
+ r.did = true
+ return nil
+}
+
+func (r *release) test(path string, t *testing.T) {
+ r.did = false
+ f, err := os.Open(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ f.Close()
+ time.Sleep(1 * time.Second)
+ if !r.did {
+ t.Error("Close did not Release")
+ }
+}
+
+// Test mknod
+
+type mknod1 struct {
+ dir
+ gotr *MknodRequest
+}
+
+func (f *mknod1) Mknod(r *MknodRequest, intr Intr) (Node, Error) {
+ f.gotr = r
+ return fifo{}, nil
+}
+
+func (f *mknod1) test(path string, t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Logf("skipping unless root")
+ return
+ }
+ defer syscall.Umask(syscall.Umask(0))
+ err := syscall.Mknod(path+"/node", syscall.S_IFIFO|0666, 123)
+ if err != nil {
+ t.Fatalf("Mknod: %v", err)
+ }
+ if f.gotr == nil {
+ t.Fatalf("no recorded MknodRequest")
+ }
+ if g, e := f.gotr.Name, "node"; g != e {
+ t.Errorf("got Name = %q; want %q", g, e)
+ }
+ if g, e := f.gotr.Rdev, uint32(123); g != e {
+ if runtime.GOOS == "linux" {
+ // Linux fuse doesn't echo back the rdev if the node
+ // isn't a device (we're using a FIFO here, as that
+ // bit is portable.)
+ } else {
+ t.Errorf("got Rdev = %v; want %v", g, e)
+ }
+ }
+ if g, e := f.gotr.Mode, os.FileMode(os.ModeNamedPipe|0666); g != e {
+ t.Errorf("got Mode = %v; want %v", g, e)
+ }
+ t.Logf("Got request: %#v", f.gotr)
+}
+
+type file struct{}
+type dir struct{}
+type fifo struct{}
+type symlink struct {
+ target string
+}
+
+func (f file) Attr() Attr { return Attr{Mode: 0666} }
+func (f dir) Attr() Attr { return Attr{Mode: os.ModeDir | 0777} }
+func (f fifo) Attr() Attr { return Attr{Mode: os.ModeNamedPipe | 0666} }
+func (f symlink) Attr() Attr { return Attr{Mode: os.ModeSymlink | 0666} }
+
+func (f symlink) Readlink(*ReadlinkRequest, Intr) (string, Error) {
+ return f.target, nil
+}
+
+type testFS struct{}
+
+func (testFS) Root() (Node, Error) {
+ return testFS{}, nil
+}
+
+func (testFS) Attr() Attr {
+ return Attr{Mode: os.ModeDir | 0555}
+}
+
+func (testFS) Lookup(name string, intr Intr) (Node, Error) {
+ for _, tt := range fuseTests {
+ if tt.name == name {
+ return tt.node, nil
+ }
+ }
+ return nil, ENOENT
+}
+
+func (testFS) ReadDir(intr Intr) ([]Dirent, Error) {
+ var dirs []Dirent
+ for _, tt := range fuseTests {
+ if *fuseRun == "" || *fuseRun == tt.name {
+ log.Printf("Readdir; adding %q", tt.name)
+ dirs = append(dirs, Dirent{Name: tt.name})
+ }
+ }
+ return dirs, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/hellofs/hello.go b/vendor/github.com/mattermost/rsc/fuse/hellofs/hello.go
new file mode 100644
index 000000000..d915473f1
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/hellofs/hello.go
@@ -0,0 +1,62 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Hellofs implements a simple "hello world" file system.
+package main
+
+import (
+ "log"
+ "os"
+
+ "github.com/mattermost/rsc/fuse"
+)
+
+func main() {
+ c, err := fuse.Mount("/mnt/hellofs")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ c.Serve(FS{})
+}
+
+// FS implements the hello world file system.
+type FS struct{}
+
+func (FS) Root() (fuse.Node, fuse.Error) {
+ return Dir{}, nil
+}
+
+// Dir implements both Node and Handle for the root directory.
+type Dir struct{}
+
+func (Dir) Attr() fuse.Attr {
+ return fuse.Attr{Mode: os.ModeDir | 0555}
+}
+
+func (Dir) Lookup(name string, intr fuse.Intr) (fuse.Node, fuse.Error) {
+ if name == "hello" {
+ return File{}, nil
+ }
+ return nil, fuse.ENOENT
+}
+
+var dirDirs = []fuse.Dirent{
+ {Inode: 2, Name: "hello", Type: 0},
+}
+
+func (Dir) ReadDir(intr fuse.Intr) ([]fuse.Dirent, fuse.Error) {
+ return dirDirs, nil
+}
+
+// File implements both Node and Handle for the hello file.
+type File struct{}
+
+func (File) Attr() fuse.Attr {
+ return fuse.Attr{Mode: 0444}
+}
+
+func (File) ReadAll(intr fuse.Intr) ([]byte, fuse.Error) {
+ return []byte("hello, world\n"), nil
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/mount_darwin.go b/vendor/github.com/mattermost/rsc/fuse/mount_darwin.go
new file mode 100644
index 000000000..5e2caaa76
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/mount_darwin.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: Rewrite using package syscall not cgo
+
+package fuse
+
+/*
+
+// Adapted from Plan 9 from User Space's src/cmd/9pfuse/fuse.c,
+// which carries this notice:
+//
+// The files in this directory are subject to the following license.
+//
+// The author of this software is Russ Cox.
+//
+// Copyright (c) 2006 Russ Cox
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose without fee is hereby granted, provided that this entire notice
+// is included in all copies of any software which is or includes a copy
+// or modification of this software and in all copies of the supporting
+// documentation for such software.
+//
+// THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY
+// OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS
+// FITNESS FOR ANY PARTICULAR PURPOSE.
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#define nil ((void*)0)
+
+static int
+mountfuse(char *mtpt, char **err)
+{
+ int i, pid, fd, r;
+ char buf[200];
+ struct vfsconf vfs;
+ char *f;
+
+ if(getvfsbyname("fusefs", &vfs) < 0){
+ if(access(f="/Library/Filesystems/osxfusefs.fs"
+ "/Support/load_osxfusefs", 0) < 0){
+ *err = strdup("cannot find load_fusefs");
+ return -1;
+ }
+ if((r=system(f)) < 0){
+ snprintf(buf, sizeof buf, "%s: %s", f, strerror(errno));
+ *err = strdup(buf);
+ return -1;
+ }
+ if(r != 0){
+ snprintf(buf, sizeof buf, "load_fusefs failed: exit %d", r);
+ *err = strdup(buf);
+ return -1;
+ }
+ if(getvfsbyname("osxfusefs", &vfs) < 0){
+ snprintf(buf, sizeof buf, "getvfsbyname osxfusefs: %s", strerror(errno));
+ *err = strdup(buf);
+ return -1;
+ }
+ }
+
+ // Look for available FUSE device.
+ for(i=0;; i++){
+ snprintf(buf, sizeof buf, "/dev/osxfuse%d", i);
+ if(access(buf, 0) < 0){
+ *err = strdup("no available fuse devices");
+ return -1;
+ }
+ if((fd = open(buf, O_RDWR)) >= 0)
+ break;
+ }
+
+ pid = fork();
+ if(pid < 0)
+ return -1;
+ if(pid == 0){
+ snprintf(buf, sizeof buf, "%d", fd);
+ setenv("MOUNT_FUSEFS_CALL_BY_LIB", "", 1);
+ // Different versions of MacFUSE put the
+ // mount_fusefs binary in different places.
+ // Try all.
+ // Leopard location
+ setenv("MOUNT_FUSEFS_DAEMON_PATH",
+ "/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs", 1);
+ execl("/Library/Filesystems/osxfusefs.fs/Support/mount_osxfusefs",
+ "mount_osxfusefs",
+ "-o", "iosize=4096", buf, mtpt, nil);
+ fprintf(stderr, "exec mount_osxfusefs: %s\n", strerror(errno));
+ _exit(1);
+ }
+ return fd;
+}
+
+*/
+import "C"
+
+import "unsafe"
+
+func mount(dir string) (int, string) {
+ errp := (**C.char)(C.malloc(16))
+ *errp = nil
+ defer C.free(unsafe.Pointer(errp))
+ cdir := C.CString(dir)
+ defer C.free(unsafe.Pointer(cdir))
+ fd := C.mountfuse(cdir, errp)
+ var err string
+ if *errp != nil {
+ err = C.GoString(*errp)
+ }
+ return int(fd), err
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/mount_linux.go b/vendor/github.com/mattermost/rsc/fuse/mount_linux.go
new file mode 100644
index 000000000..e5bc58b8a
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/mount_linux.go
@@ -0,0 +1,67 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fuse
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "os/exec"
+ "syscall"
+)
+
+func mount(dir string) (fusefd int, errmsg string) {
+ fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
+ if err != nil {
+ return -1, fmt.Sprintf("socketpair error: %v", err)
+ }
+ defer syscall.Close(fds[0])
+ defer syscall.Close(fds[1])
+
+ cmd := exec.Command("/bin/fusermount", "--", dir)
+ cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
+
+ writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
+ defer writeFile.Close()
+ cmd.ExtraFiles = []*os.File{writeFile}
+
+ out, err := cmd.CombinedOutput()
+ if len(out) > 0 || err != nil {
+ return -1, fmt.Sprintf("fusermount: %q, %v", out, err)
+ }
+
+ readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
+ defer readFile.Close()
+ c, err := net.FileConn(readFile)
+ if err != nil {
+ return -1, fmt.Sprintf("FileConn from fusermount socket: %v", err)
+ }
+ defer c.Close()
+
+ uc, ok := c.(*net.UnixConn)
+ if !ok {
+ return -1, fmt.Sprintf("unexpected FileConn type; expected UnixConn, got %T", c)
+ }
+
+ buf := make([]byte, 32) // expect 1 byte
+ oob := make([]byte, 32) // expect 24 bytes
+ _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
+ scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
+ if err != nil {
+ return -1, fmt.Sprintf("ParseSocketControlMessage: %v", err)
+ }
+ if len(scms) != 1 {
+ return -1, fmt.Sprintf("expected 1 SocketControlMessage; got scms = %#v", scms)
+ }
+ scm := scms[0]
+ gotFds, err := syscall.ParseUnixRights(&scm)
+ if err != nil {
+ return -1, fmt.Sprintf("syscall.ParseUnixRights: %v", err)
+ }
+ if len(gotFds) != 1 {
+ return -1, fmt.Sprintf("wanted 1 fd; got %#v", gotFds)
+ }
+ return gotFds[0], ""
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/serve.go b/vendor/github.com/mattermost/rsc/fuse/serve.go
new file mode 100644
index 000000000..fa4f27e3f
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/serve.go
@@ -0,0 +1,1022 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// FUSE service loop, for servers that wish to use it.
+
+package fuse
+
+import (
+ "fmt"
+ "hash/fnv"
+ "io"
+ "log"
+ "os"
+ "path"
+ "sync"
+ "syscall"
+ "time"
+)
+
+// TODO: FINISH DOCS
+
+// An Intr is a channel that signals that a request has been interrupted.
+// Being able to receive from the channel means the request has been
+// interrupted.
+type Intr chan struct{}
+
+func (Intr) String() string { return "fuse.Intr" }
+
+// An FS is the interface required of a file system.
+//
+// Root() (Node, Error)
+//
+// Root is called to obtain the Node for the file system root.
+//
+// Optional Methods
+//
+// An FS implementation may implement
+// additional methods to handle the corresponding FUSE requests:
+//
+// Init(req *InitRequest, resp *InitResponse) Error
+//
+// Init is called to initialize the FUSE connection.
+// It can inspect the request and adjust the response as desired.
+// The default response sets MaxReadahead to 0 and MaxWrite to 4096.
+// Init must return promptly.
+//
+// Statfs(resp *StatfsResponse, intr Intr) Error
+//
+// Statfs is called to obtain file system metadata. It should write that data to resp.
+//
+// Rename(req *RenameRequest, intr Intr) Error
+//
+// XXXX this is not implemented like this. Instead, Rename is a method
+// on the source dierctory node, and takes a newDir Node parameter. Fix it like this?
+// Rename is called to rename the file req.OldName in the directory req.OldDir to
+// become the file req.NewName in the directory req.NewDir.
+//
+type FS interface {
+ Root() (Node, Error)
+}
+
+// A Node is the interface required of a file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// Getattr(resp *GetattrResponse, intr Intr) fuse.Error
+//
+// Getattr obtains the standard metadata for the receiver.
+// It should store that metadata in resp.
+//
+// Open(xxx, intr Intr) (Handle, fuse.Error)
+//
+// Open opens the receiver.
+// XXX note about access. XXX OpenFlags.
+// XXX note that the Node may be a file or directory.
+//
+// Optional Methods
+//
+// An Node implementation may implement additional methods
+// to handle the corresponding FUSE requests.
+//
+// These optional requests can be called for both file and directory nodes:
+//
+// Access
+//
+// Access checks whether the calling context has permission for
+// the given operations on the receiver. If so, Access should return nil. If not, Access should
+// return EPERM. Note that this call affects the result of the access(2) system call
+// but not the open(2) system call. If Access is not implemented, the Node behaves
+// as if it always returns nil (permission granted), relying on checks in Open instead.
+//
+// Getxattr
+//
+// Getxattr obtains an extended attribute for the receiver.
+// XXX
+//
+// Listxattr
+//
+// Listxattr lists the extended attributes recorded for the receiver.
+//
+// Removexattr
+//
+// Removexattr removes an extended attribute from the receiver.
+//
+// Setattr
+//
+// Setattr sets the standard metadata for the receiver.
+//
+// Setxattr
+//
+// Setxattr sets an extended attribute for the receiver.
+//
+// Optional Directory Methods
+//
+// These optional requests will be called only for directory nodes:
+//
+// Create(xxx)
+//
+// Create creates
+//
+// Link(xxx)
+//
+// Link XXX
+//
+// Lookup(name string, intr Intr) (Node, Error)
+//
+// Lookup looks up a specific entry in the receiver,
+// which must be a directory. Lookup should return a Node
+// corresponding to the entry. If the name does not exist in
+// the directory, Lookup should return nil, err.
+//
+// Lookup need not to handle the names "." and "..".
+//
+// Mkdir
+//
+// Mkdir creates XXX
+//
+// Mknod XXX
+//
+// XXX
+//
+// Remove
+//
+// Remove removes the entry with the given name from
+// the receiver, which must be a directory. The entry to be removed
+// may correspond to a file (unlink) or to a directory (rmdir).
+//
+// Symlink
+//
+// Symlink creates a new symbolic link in the receiver, which must be a directory.
+// The entry
+//
+// Optional Symlink Methods
+//
+// This optional request will be called only for symbolic link nodes:
+//
+// Readlink
+//
+// Readlink reads a symbolic link.
+type Node interface {
+ Attr() Attr
+}
+
+var startTime = time.Now()
+
+func nodeAttr(inode uint64, n Node) (attr Attr) {
+ attr = n.Attr()
+ if attr.Nlink == 0 {
+ attr.Nlink = 1
+ }
+ if attr.Atime.IsZero() {
+ attr.Atime = startTime
+ }
+ if attr.Mtime.IsZero() {
+ attr.Mtime = startTime
+ }
+ if attr.Ctime.IsZero() {
+ attr.Ctime = startTime
+ }
+ if attr.Crtime.IsZero() {
+ attr.Crtime = startTime
+ }
+ if attr.Inode == 0 {
+ attr.Inode = inode
+ }
+ return
+}
+
+// A Handle is the interface required of an opened file or directory.
+// See the documentation for type FS for general information
+// pertaining to all methods.
+//
+// Flush
+//
+// Flush is called each time the file or directory is closed. Because there can be
+// multiple file descriptors referring to a single opened file, Flush can be called
+// multiple times.
+//
+// Optional Methods
+//
+// A Handle implementation may implement additional methods to handle
+// the corresponding FUSE requests. The most common to implement are
+// Read, ReadDir, and Write.
+//
+// Fsync
+//
+// Getlk
+//
+// Read
+//
+// Readdir
+//
+// Release
+//
+// Setlk
+//
+// Setlkw
+//
+// Write
+//
+type Handle interface {
+}
+
+// Serve serves the FUSE connection by making calls to the methods
+// of fs and the Nodes and Handles it makes available. It returns only
+// when the connection has been closed or an unexpected error occurs.
+func (c *Conn) Serve(fs FS) error {
+ if c.req != nil {
+ panic("fuse: Serve called twice")
+ }
+ c.req = map[RequestID]*serveRequest{}
+
+ root, err := fs.Root()
+ if err != nil {
+ return fmt.Errorf("cannot obtain root node: %v", syscall.Errno(err.(Errno)).Error())
+ }
+ c.node = append(c.node, nil, &serveNode{name: "/", node: root})
+ c.handle = append(c.handle, nil)
+
+ for {
+ req, err := c.ReadRequest()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+
+ go c.serve(fs, req)
+ }
+ return nil
+}
+
+type serveConn struct {
+ meta sync.Mutex
+ req map[RequestID]*serveRequest
+ node []*serveNode
+ handle []*serveHandle
+ freeNode []NodeID
+ freeHandle []HandleID
+ nodeGen uint64
+ nodeHandles []map[HandleID]bool // open handles for a node; slice index is NodeID
+}
+
+type serveRequest struct {
+ Request Request
+ Intr Intr
+}
+
+type serveNode struct {
+ name string
+ node Node
+ inode uint64
+ isDir bool
+}
+
+func (sn *serveNode) attr() (attr Attr) {
+ attr = nodeAttr(sn.inode, sn.node)
+ if attr.Inode == 0 {
+ sn.inode = hash(sn.name)
+ attr.Inode = sn.inode
+ }
+ sn.isDir = attr.Mode&os.ModeDir != 0
+ return
+}
+
+func hash(s string) uint64 {
+ f := fnv.New64()
+ f.Write([]byte(s))
+ return f.Sum64()
+}
+
+type serveHandle struct {
+ handle Handle
+ readData []byte
+ trunc bool
+ writeData []byte
+ nodeID NodeID
+}
+
+func (c *Conn) saveNode(name string, node Node) (id NodeID, gen uint64, sn *serveNode) {
+ sn = &serveNode{name: name, node: node}
+ c.meta.Lock()
+ if n := len(c.freeNode); n > 0 {
+ id = c.freeNode[n-1]
+ c.freeNode = c.freeNode[:n-1]
+ c.node[id] = sn
+ c.nodeGen++
+ } else {
+ id = NodeID(len(c.node))
+ c.node = append(c.node, sn)
+ }
+ gen = c.nodeGen
+ c.meta.Unlock()
+ return
+}
+
+func (c *Conn) saveHandle(handle Handle, nodeID NodeID) (id HandleID, shandle *serveHandle) {
+ c.meta.Lock()
+ shandle = &serveHandle{handle: handle, nodeID: nodeID}
+ if n := len(c.freeHandle); n > 0 {
+ id = c.freeHandle[n-1]
+ c.freeHandle = c.freeHandle[:n-1]
+ c.handle[id] = shandle
+ } else {
+ id = HandleID(len(c.handle))
+ c.handle = append(c.handle, shandle)
+ }
+
+ // Update mapping from node ID -> set of open Handle IDs.
+ for len(c.nodeHandles) <= int(nodeID) {
+ c.nodeHandles = append(c.nodeHandles, nil)
+ }
+ if c.nodeHandles[nodeID] == nil {
+ c.nodeHandles[nodeID] = make(map[HandleID]bool)
+ }
+ c.nodeHandles[nodeID][id] = true
+
+ c.meta.Unlock()
+ return
+}
+
+func (c *Conn) dropNode(id NodeID) {
+ c.meta.Lock()
+ c.node[id] = nil
+ if len(c.nodeHandles) > int(id) {
+ c.nodeHandles[id] = nil
+ }
+ c.freeNode = append(c.freeNode, id)
+ c.meta.Unlock()
+}
+
+func (c *Conn) dropHandle(id HandleID) {
+ c.meta.Lock()
+ h := c.handle[id]
+ delete(c.nodeHandles[h.nodeID], id)
+ c.handle[id] = nil
+ c.freeHandle = append(c.freeHandle, id)
+ c.meta.Unlock()
+}
+
+func (c *Conn) serve(fs FS, r Request) {
+ intr := make(Intr)
+ req := &serveRequest{Request: r, Intr: intr}
+
+ Debugf("<- %s", req)
+ var node Node
+ var handle Handle
+ var snode *serveNode
+ var shandle *serveHandle
+ c.meta.Lock()
+ hdr := r.Hdr()
+ if id := hdr.Node; id != 0 {
+ if id < NodeID(len(c.node)) {
+ snode = c.node[uint(id)]
+ }
+ if snode == nil {
+ c.meta.Unlock()
+ println("missing node", id, len(c.node), snode)
+ Debugf("-> %#x %v", hdr.ID, ESTALE)
+ r.RespondError(ESTALE)
+ return
+ }
+ node = snode.node
+ }
+ if id := r.handle(); id != 0 {
+ if id < HandleID(len(c.handle)) {
+ shandle = c.handle[uint(id)]
+ }
+ if shandle == nil {
+ println("missing handle", id, len(c.handle), shandle)
+ c.meta.Unlock()
+ Debugf("-> %#x %v", hdr.ID, ESTALE)
+ r.RespondError(ESTALE)
+ return
+ }
+ handle = shandle.handle
+ }
+ intr = make(chan struct{})
+ if c.req[hdr.ID] != nil {
+ // This happens with OSXFUSE. Assume it's okay and
+ // that we'll never see an interrupt for this one.
+ // Otherwise everything wedges. TODO: Report to OSXFUSE?
+ intr = nil
+ } else {
+ c.req[hdr.ID] = req
+ }
+ c.meta.Unlock()
+
+ // Call this before responding.
+ // After responding is too late: we might get another request
+ // with the same ID and be very confused.
+ done := func(resp interface{}) {
+ Debugf("-> %#x %v", hdr.ID, resp)
+ c.meta.Lock()
+ c.req[hdr.ID] = nil
+ c.meta.Unlock()
+ }
+
+ switch r := r.(type) {
+ default:
+ // Note: To FUSE, ENOSYS means "this server never implements this request."
+ // It would be inappropriate to return ENOSYS for other operations in this
+ // switch that might only be unavailable in some contexts, not all.
+ done(ENOSYS)
+ r.RespondError(ENOSYS)
+
+ // FS operations.
+ case *InitRequest:
+ s := &InitResponse{
+ MaxWrite: 4096,
+ }
+ if fs, ok := fs.(interface {
+ Init(*InitRequest, *InitResponse, Intr) Error
+ }); ok {
+ if err := fs.Init(r, s, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ }
+ done(s)
+ r.Respond(s)
+
+ case *StatfsRequest:
+ s := &StatfsResponse{}
+ if fs, ok := fs.(interface {
+ Statfs(*StatfsRequest, *StatfsResponse, Intr) Error
+ }); ok {
+ if err := fs.Statfs(r, s, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ }
+ done(s)
+ r.Respond(s)
+
+ // Node operations.
+ case *GetattrRequest:
+ s := &GetattrResponse{}
+ if n, ok := node.(interface {
+ Getattr(*GetattrRequest, *GetattrResponse, Intr) Error
+ }); ok {
+ if err := n.Getattr(r, s, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ } else {
+ s.AttrValid = 1 * time.Minute
+ s.Attr = snode.attr()
+ }
+ done(s)
+ r.Respond(s)
+
+ case *SetattrRequest:
+ s := &SetattrResponse{}
+
+ // Special-case truncation, if no other bits are set
+ // and the open Handles all have a WriteAll method.
+ if r.Valid&SetattrSize != 0 && r.Size == 0 {
+ type writeAll interface {
+ WriteAll([]byte, Intr) Error
+ }
+ switch r.Valid {
+ case SetattrLockOwner | SetattrSize, SetattrSize:
+ // Seen on Linux. Handle isn't set.
+ c.meta.Lock()
+ for hid := range c.nodeHandles[hdr.Node] {
+ shandle := c.handle[hid]
+ if _, ok := shandle.handle.(writeAll); ok {
+ shandle.trunc = true
+ }
+ }
+ c.meta.Unlock()
+ case SetattrHandle | SetattrSize:
+ // Seen on OS X; the Handle is provided.
+ if _, ok := handle.(writeAll); ok {
+ shandle.trunc = true
+ }
+ }
+ }
+
+ log.Printf("setattr %v", r)
+ if n, ok := node.(interface {
+ Setattr(*SetattrRequest, *SetattrResponse, Intr) Error
+ }); ok {
+ if err := n.Setattr(r, s, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ done(s)
+ r.Respond(s)
+ break
+ }
+
+ if s.AttrValid == 0 {
+ s.AttrValid = 1 * time.Minute
+ }
+ s.Attr = snode.attr()
+ done(s)
+ r.Respond(s)
+
+ case *SymlinkRequest:
+ s := &SymlinkResponse{}
+ n, ok := node.(interface {
+ Symlink(*SymlinkRequest, Intr) (Node, Error)
+ })
+ if !ok {
+ done(EIO) // XXX or EPERM like Mkdir?
+ r.RespondError(EIO)
+ break
+ }
+ n2, err := n.Symlink(r, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ c.saveLookup(&s.LookupResponse, snode, r.NewName, n2)
+ done(s)
+ r.Respond(s)
+
+ case *ReadlinkRequest:
+ n, ok := node.(interface {
+ Readlink(*ReadlinkRequest, Intr) (string, Error)
+ })
+ if !ok {
+ done(EIO) /// XXX or EPERM?
+ r.RespondError(EIO)
+ break
+ }
+ target, err := n.Readlink(r, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ done(target)
+ r.Respond(target)
+
+ case *LinkRequest:
+ n, ok := node.(interface {
+ Link(r *LinkRequest, old Node, intr Intr) (Node, Error)
+ })
+ if !ok {
+ log.Printf("Node %T doesn't implement fuse Link", node)
+ done(EIO) /// XXX or EPERM?
+ r.RespondError(EIO)
+ break
+ }
+ c.meta.Lock()
+ var oldNode *serveNode
+ if int(r.OldNode) < len(c.node) {
+ oldNode = c.node[r.OldNode]
+ }
+ c.meta.Unlock()
+ if oldNode == nil {
+ log.Printf("In LinkRequest, node %d not found", r.OldNode)
+ done(EIO)
+ r.RespondError(EIO)
+ break
+ }
+ n2, err := n.Link(r, oldNode.node, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ s := &LookupResponse{}
+ c.saveLookup(s, snode, r.NewName, n2)
+ done(s)
+ r.Respond(s)
+
+ case *RemoveRequest:
+ n, ok := node.(interface {
+ Remove(*RemoveRequest, Intr) Error
+ })
+ if !ok {
+ done(EIO) /// XXX or EPERM?
+ r.RespondError(EIO)
+ break
+ }
+ err := n.Remove(r, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ done(nil)
+ r.Respond()
+
+ case *AccessRequest:
+ if n, ok := node.(interface {
+ Access(*AccessRequest, Intr) Error
+ }); ok {
+ if err := n.Access(r, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ }
+ done(r)
+ r.Respond()
+
+ case *LookupRequest:
+ var n2 Node
+ var err Error
+ s := &LookupResponse{}
+ if n, ok := node.(interface {
+ Lookup(string, Intr) (Node, Error)
+ }); ok {
+ n2, err = n.Lookup(r.Name, intr)
+ } else if n, ok := node.(interface {
+ Lookup(*LookupRequest, *LookupResponse, Intr) (Node, Error)
+ }); ok {
+ n2, err = n.Lookup(r, s, intr)
+ } else {
+ done(ENOENT)
+ r.RespondError(ENOENT)
+ break
+ }
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ c.saveLookup(s, snode, r.Name, n2)
+ done(s)
+ r.Respond(s)
+
+ case *MkdirRequest:
+ s := &MkdirResponse{}
+ n, ok := node.(interface {
+ Mkdir(*MkdirRequest, Intr) (Node, Error)
+ })
+ if !ok {
+ done(EPERM)
+ r.RespondError(EPERM)
+ break
+ }
+ n2, err := n.Mkdir(r, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ c.saveLookup(&s.LookupResponse, snode, r.Name, n2)
+ done(s)
+ r.Respond(s)
+
+ case *OpenRequest:
+ s := &OpenResponse{Flags: OpenDirectIO}
+ var h2 Handle
+ if n, ok := node.(interface {
+ Open(*OpenRequest, *OpenResponse, Intr) (Handle, Error)
+ }); ok {
+ hh, err := n.Open(r, s, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ h2 = hh
+ } else {
+ h2 = node
+ }
+ s.Handle, _ = c.saveHandle(h2, hdr.Node)
+ done(s)
+ r.Respond(s)
+
+ case *CreateRequest:
+ n, ok := node.(interface {
+ Create(*CreateRequest, *CreateResponse, Intr) (Node, Handle, Error)
+ })
+ if !ok {
+ // If we send back ENOSYS, FUSE will try mknod+open.
+ done(EPERM)
+ r.RespondError(EPERM)
+ break
+ }
+ s := &CreateResponse{OpenResponse: OpenResponse{Flags: OpenDirectIO}}
+ n2, h2, err := n.Create(r, s, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ c.saveLookup(&s.LookupResponse, snode, r.Name, n2)
+ h, shandle := c.saveHandle(h2, hdr.Node)
+ s.Handle = h
+ shandle.trunc = true
+ done(s)
+ r.Respond(s)
+
+ case *GetxattrRequest, *SetxattrRequest, *ListxattrRequest, *RemovexattrRequest:
+ // TODO: Use n.
+ done(ENOSYS)
+ r.RespondError(ENOSYS)
+
+ case *ForgetRequest:
+ n, ok := node.(interface {
+ Forget()
+ })
+ if ok {
+ n.Forget()
+ }
+ c.dropNode(hdr.Node)
+ done(r)
+ r.Respond()
+
+ // Handle operations.
+ case *ReadRequest:
+ s := &ReadResponse{Data: make([]byte, 0, r.Size)}
+ if snode.isDir {
+ if h, ok := handle.(interface {
+ ReadDir(Intr) ([]Dirent, Error)
+ }); ok {
+ if shandle.readData == nil {
+ attr := snode.attr()
+ dirs, err := h.ReadDir(intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ var data []byte
+ data = AppendDirent(data, Dirent{Inode: attr.Inode, Name: "."})
+ data = AppendDirent(data, Dirent{Inode: attr.Inode, Name: ".."})
+ for _, dir := range dirs {
+ if dir.Inode == 0 {
+ dir.Inode = hash(path.Join(snode.name, dir.Name))
+ }
+ data = AppendDirent(data, dir)
+ }
+ shandle.readData = data
+ }
+ HandleRead(r, s, shandle.readData)
+ done(s)
+ r.Respond(s)
+ break
+ }
+ } else {
+ if h, ok := handle.(interface {
+ ReadAll(Intr) ([]byte, Error)
+ }); ok {
+ if shandle.readData == nil {
+ data, err := h.ReadAll(intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ if data == nil {
+ data = []byte{}
+ }
+ shandle.readData = data
+ }
+ HandleRead(r, s, shandle.readData)
+ done(s)
+ r.Respond(s)
+ break
+ }
+ }
+ h, ok := handle.(interface {
+ Read(*ReadRequest, *ReadResponse, Intr) Error
+ })
+ if !ok {
+ fmt.Printf("NO READ FOR %T\n", handle)
+ done(EIO)
+ r.RespondError(EIO)
+ break
+ }
+ if err := h.Read(r, s, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ done(s)
+ r.Respond(s)
+
+ case *WriteRequest:
+ s := &WriteResponse{}
+ if shandle.trunc && r.Offset == int64(len(shandle.writeData)) {
+ shandle.writeData = append(shandle.writeData, r.Data...)
+ s.Size = len(r.Data)
+ done(s)
+ r.Respond(s)
+ break
+ }
+ if h, ok := handle.(interface {
+ Write(*WriteRequest, *WriteResponse, Intr) Error
+ }); ok {
+ if err := h.Write(r, s, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ done(s)
+ r.Respond(s)
+ break
+ }
+ println("NO WRITE")
+ done(EIO)
+ r.RespondError(EIO)
+
+ case *FlushRequest:
+ if shandle.trunc {
+ h := handle.(interface {
+ WriteAll([]byte, Intr) Error
+ })
+ if err := h.WriteAll(shandle.writeData, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ shandle.writeData = nil
+ shandle.trunc = false
+ }
+ if h, ok := handle.(interface {
+ Flush(*FlushRequest, Intr) Error
+ }); ok {
+ if err := h.Flush(r, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ }
+ done(nil)
+ r.Respond()
+
+ case *ReleaseRequest:
+ // No matter what, release the handle.
+ c.dropHandle(r.handle())
+ if h, ok := handle.(interface {
+ Release(*ReleaseRequest, Intr) Error
+ }); ok {
+ if err := h.Release(r, intr); err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ }
+ done(nil)
+ r.Respond()
+
+ case *DestroyRequest:
+ fs, ok := fs.(interface {
+ Destroy()
+ })
+ if ok {
+ fs.Destroy()
+ }
+ done(nil)
+ r.Respond()
+
+ case *RenameRequest:
+ c.meta.Lock()
+ var newDirNode *serveNode
+ if int(r.NewDir) < len(c.node) {
+ newDirNode = c.node[r.NewDir]
+ }
+ c.meta.Unlock()
+ if newDirNode == nil {
+ println("RENAME NEW DIR NODE NOT FOUND")
+ done(EIO)
+ r.RespondError(EIO)
+ break
+ }
+ n, ok := node.(interface {
+ Rename(r *RenameRequest, newDir Node, intr Intr) Error
+ })
+ if !ok {
+ log.Printf("Node %T missing Rename method", node)
+ done(EIO) // XXX or EPERM like Mkdir?
+ r.RespondError(EIO)
+ break
+ }
+ err := n.Rename(r, newDirNode.node, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ done(nil)
+ r.Respond()
+
+ case *MknodRequest:
+ n, ok := node.(interface {
+ Mknod(r *MknodRequest, intr Intr) (Node, Error)
+ })
+ if !ok {
+ log.Printf("Node %T missing Mknod method", node)
+ done(EIO)
+ r.RespondError(EIO)
+ break
+ }
+ n2, err := n.Mknod(r, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ s := &LookupResponse{}
+ c.saveLookup(s, snode, r.Name, n2)
+ done(s)
+ r.Respond(s)
+
+ case *FsyncRequest:
+ n, ok := node.(interface {
+ Fsync(r *FsyncRequest, intr Intr) Error
+ })
+ if !ok {
+ log.Printf("Node %T missing Fsync method", node)
+ done(EIO)
+ r.RespondError(EIO)
+ break
+ }
+ err := n.Fsync(r, intr)
+ if err != nil {
+ done(err)
+ r.RespondError(err)
+ break
+ }
+ done(nil)
+ r.Respond()
+
+ /* case *FsyncdirRequest:
+ done(ENOSYS)
+ r.RespondError(ENOSYS)
+
+ case *GetlkRequest, *SetlkRequest, *SetlkwRequest:
+ done(ENOSYS)
+ r.RespondError(ENOSYS)
+
+ // One of a kind.
+ case *InterruptRequest:
+ c.meta.Lock()
+ ireq := c.req[r.OldID]
+ if ireq != nil && ireq.Intr != nil {
+ close(ireq.Intr)
+ ireq.Intr = nil
+ }
+ c.meta.Unlock()
+ done(nil)
+ r.Respond()
+
+ case *BmapRequest:
+ done(ENOSYS)
+ r.RespondError(ENOSYS)
+
+ case *SetvolnameRequest, *GetxtimesRequest, *ExchangeRequest:
+ done(ENOSYS)
+ r.RespondError(ENOSYS)
+ */
+ }
+}
+
+func (c *Conn) saveLookup(s *LookupResponse, snode *serveNode, elem string, n2 Node) {
+ name := path.Join(snode.name, elem)
+ var sn *serveNode
+ s.Node, s.Generation, sn = c.saveNode(name, n2)
+ if s.EntryValid == 0 {
+ s.EntryValid = 1 * time.Minute
+ }
+ if s.AttrValid == 0 {
+ s.AttrValid = 1 * time.Minute
+ }
+ s.Attr = sn.attr()
+}
+
+// HandleRead handles a read request assuming that data is the entire file content.
+// It adjusts the amount returned in resp according to req.Offset and req.Size.
+func HandleRead(req *ReadRequest, resp *ReadResponse, data []byte) {
+ if req.Offset >= int64(len(data)) {
+ data = nil
+ } else {
+ data = data[req.Offset:]
+ }
+ if len(data) > req.Size {
+ data = data[:req.Size]
+ }
+ n := copy(resp.Data[:req.Size], data)
+ resp.Data = resp.Data[:n]
+}
+
+// DataHandle returns a read-only Handle that satisfies reads
+// using the given data.
+func DataHandle(data []byte) Handle {
+ return &dataHandle{data}
+}
+
+type dataHandle struct {
+ data []byte
+}
+
+func (d *dataHandle) Read(intr Intr) ([]byte, Error) {
+ return d.data, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/fuse/tree.go b/vendor/github.com/mattermost/rsc/fuse/tree.go
new file mode 100644
index 000000000..fec0a748f
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/fuse/tree.go
@@ -0,0 +1,93 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// FUSE directory tree, for servers that wish to use it with the service loop.
+
+package fuse
+
+import (
+ "os"
+ pathpkg "path"
+ "strings"
+)
+
+// A Tree implements a basic directory tree for FUSE.
+type Tree struct {
+ tree
+}
+
+func (t *Tree) Root() (Node, Error) {
+ return &t.tree, nil
+}
+
+// Add adds the path to the tree, resolving to the given node.
+// If path or a prefix of path has already been added to the tree,
+// Add panics.
+func (t *Tree) Add(path string, node Node) {
+ path = pathpkg.Clean("/" + path)[1:]
+ elems := strings.Split(path, "/")
+ dir := Node(&t.tree)
+ for i, elem := range elems {
+ dt, ok := dir.(*tree)
+ if !ok {
+ panic("fuse: Tree.Add for " + strings.Join(elems[:i], "/") + " and " + path)
+ }
+ n := dt.lookup(elem)
+ if n != nil {
+ if i+1 == len(elems) {
+ panic("fuse: Tree.Add for " + path + " conflicts with " + elem)
+ }
+ dir = n
+ } else {
+ if i+1 == len(elems) {
+ dt.add(elem, node)
+ } else {
+ dir = &tree{}
+ dt.add(elem, dir)
+ }
+ }
+ }
+}
+
+type treeDir struct {
+ name string
+ node Node
+}
+
+type tree struct {
+ dir []treeDir
+}
+
+func (t *tree) lookup(name string) Node {
+ for _, d := range t.dir {
+ if d.name == name {
+ return d.node
+ }
+ }
+ return nil
+}
+
+func (t *tree) add(name string, n Node) {
+ t.dir = append(t.dir, treeDir{name, n})
+}
+
+func (t *tree) Attr() Attr {
+ return Attr{Mode: os.ModeDir | 0555}
+}
+
+func (t *tree) Lookup(name string, intr Intr) (Node, Error) {
+ n := t.lookup(name)
+ if n != nil {
+ return n, nil
+ }
+ return nil, ENOENT
+}
+
+func (t *tree) ReadDir(intr Intr) ([]Dirent, Error) {
+ var out []Dirent
+ for _, d := range t.dir {
+ out = append(out, Dirent{Name: d.name})
+ }
+ return out, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/gf256/blog_test.go b/vendor/github.com/mattermost/rsc/gf256/blog_test.go
new file mode 100644
index 000000000..12cc7deb0
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/gf256/blog_test.go
@@ -0,0 +1,85 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains a straightforward implementation of
+// Reed-Solomon encoding, along with a benchmark.
+// It goes with http://research.swtch.com/field.
+//
+// For an optimized implementation, see gf256.go.
+
+package gf256
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+)
+
+// BlogECC writes to check the error correcting code bytes
+// for data using the given Reed-Solomon parameters.
+func BlogECC(rs *RSEncoder, m []byte, check []byte) {
+ if len(check) < rs.c {
+ panic("gf256: invalid check byte length")
+ }
+ if rs.c == 0 {
+ return
+ }
+
+ // The check bytes are the remainder after dividing
+ // data padded with c zeros by the generator polynomial.
+
+ // p = data padded with c zeros.
+ var p []byte
+ n := len(m) + rs.c
+ if len(rs.p) >= n {
+ p = rs.p
+ } else {
+ p = make([]byte, n)
+ }
+ copy(p, m)
+ for i := len(m); i < len(p); i++ {
+ p[i] = 0
+ }
+
+ gen := rs.gen
+
+ // Divide p by gen, leaving the remainder in p[len(data):].
+ // p[0] is the most significant term in p, and
+ // gen[0] is the most significant term in the generator.
+ for i := 0; i < len(m); i++ {
+ k := f.Mul(p[i], f.Inv(gen[0])) // k = pi / g0
+ // p -= k·g
+ for j, g := range gen {
+ p[i+j] = f.Add(p[i+j], f.Mul(k, g))
+ }
+ }
+
+ copy(check, p[len(m):])
+ rs.p = p
+}
+
+func BenchmarkBlogECC(b *testing.B) {
+ data := []byte{0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11}
+ check := []byte{0x29, 0x41, 0xb3, 0x93, 0x8, 0xe8, 0xa3, 0xe7, 0x63, 0x8f}
+ out := make([]byte, len(check))
+ rs := NewRSEncoder(f, len(check))
+ for i := 0; i < b.N; i++ {
+ BlogECC(rs, data, out)
+ }
+ b.SetBytes(int64(len(data)))
+ if !bytes.Equal(out, check) {
+ fmt.Printf("have %#v want %#v\n", out, check)
+ }
+}
+
+func TestBlogECC(t *testing.T) {
+ data := []byte{0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11}
+ check := []byte{0xa5, 0x24, 0xd4, 0xc1, 0xed, 0x36, 0xc7, 0x87, 0x2c, 0x55}
+ out := make([]byte, len(check))
+ rs := NewRSEncoder(f, len(check))
+ BlogECC(rs, data, out)
+ if !bytes.Equal(out, check) {
+ t.Errorf("have %x want %x", out, check)
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/gf256/gf256_test.go b/vendor/github.com/mattermost/rsc/gf256/gf256_test.go
new file mode 100644
index 000000000..f77fa7d67
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/gf256/gf256_test.go
@@ -0,0 +1,194 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gf256
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+)
+
+var f = NewField(0x11d, 2) // x^8 + x^4 + x^3 + x^2 + 1
+
+func TestBasic(t *testing.T) {
+ if f.Exp(0) != 1 || f.Exp(1) != 2 || f.Exp(255) != 1 {
+ panic("bad Exp")
+ }
+}
+
+func TestECC(t *testing.T) {
+ data := []byte{0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11}
+ check := []byte{0xa5, 0x24, 0xd4, 0xc1, 0xed, 0x36, 0xc7, 0x87, 0x2c, 0x55}
+ out := make([]byte, len(check))
+ rs := NewRSEncoder(f, len(check))
+ rs.ECC(data, out)
+ if !bytes.Equal(out, check) {
+ t.Errorf("have %x want %x", out, check)
+ }
+}
+
+func TestLinear(t *testing.T) {
+ d1 := []byte{0x00, 0x00}
+ c1 := []byte{0x00, 0x00}
+ out := make([]byte, len(c1))
+ rs := NewRSEncoder(f, len(c1))
+ if rs.ECC(d1, out); !bytes.Equal(out, c1) {
+ t.Errorf("ECBytes(%x, %d) = %x, want 0", d1, len(c1), out)
+ }
+ d2 := []byte{0x00, 0x01}
+ c2 := make([]byte, 2)
+ rs.ECC(d2, c2)
+ d3 := []byte{0x00, 0x02}
+ c3 := make([]byte, 2)
+ rs.ECC(d3, c3)
+ cx := make([]byte, 2)
+ for i := range cx {
+ cx[i] = c2[i] ^ c3[i]
+ }
+ d4 := []byte{0x00, 0x03}
+ c4 := make([]byte, 2)
+ rs.ECC(d4, c4)
+ if !bytes.Equal(cx, c4) {
+ t.Errorf("ECBytes(%x, 2) = %x\nECBytes(%x, 2) = %x\nxor = %x\nECBytes(%x, 2) = %x",
+ d2, c2, d3, c3, cx, d4, c4)
+ }
+}
+
+func TestGaussJordan(t *testing.T) {
+ rs := NewRSEncoder(f, 2)
+ m := make([][]byte, 16)
+ for i := range m {
+ m[i] = make([]byte, 4)
+ m[i][i/8] = 1 << uint(i%8)
+ rs.ECC(m[i][:2], m[i][2:])
+ }
+ if false {
+ fmt.Printf("---\n")
+ for _, row := range m {
+ fmt.Printf("%x\n", row)
+ }
+ }
+ b := []uint{0, 1, 2, 3, 12, 13, 14, 15, 20, 21, 22, 23, 24, 25, 26, 27}
+ for i := 0; i < 16; i++ {
+ bi := b[i]
+ if m[i][bi/8]&(1<<(7-bi%8)) == 0 {
+ for j := i + 1; ; j++ {
+ if j >= len(m) {
+ t.Errorf("lost track for %d", bi)
+ break
+ }
+ if m[j][bi/8]&(1<<(7-bi%8)) != 0 {
+ m[i], m[j] = m[j], m[i]
+ break
+ }
+ }
+ }
+ for j := i + 1; j < len(m); j++ {
+ if m[j][bi/8]&(1<<(7-bi%8)) != 0 {
+ for k := range m[j] {
+ m[j][k] ^= m[i][k]
+ }
+ }
+ }
+ }
+ if false {
+ fmt.Printf("---\n")
+ for _, row := range m {
+ fmt.Printf("%x\n", row)
+ }
+ }
+ for i := 15; i >= 0; i-- {
+ bi := b[i]
+ for j := i - 1; j >= 0; j-- {
+ if m[j][bi/8]&(1<<(7-bi%8)) != 0 {
+ for k := range m[j] {
+ m[j][k] ^= m[i][k]
+ }
+ }
+ }
+ }
+ if false {
+ fmt.Printf("---\n")
+ for _, row := range m {
+ fmt.Printf("%x", row)
+ out := make([]byte, 2)
+ if rs.ECC(row[:2], out); !bytes.Equal(out, row[2:]) {
+ fmt.Printf(" - want %x", out)
+ }
+ fmt.Printf("\n")
+ }
+ }
+}
+
+func BenchmarkECC(b *testing.B) {
+ data := []byte{0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11}
+ check := []byte{0x29, 0x41, 0xb3, 0x93, 0x8, 0xe8, 0xa3, 0xe7, 0x63, 0x8f}
+ out := make([]byte, len(check))
+ rs := NewRSEncoder(f, len(check))
+ for i := 0; i < b.N; i++ {
+ rs.ECC(data, out)
+ }
+ b.SetBytes(int64(len(data)))
+ if !bytes.Equal(out, check) {
+ fmt.Printf("have %#v want %#v\n", out, check)
+ }
+}
+
+func TestGen(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ _, lg := f.gen(i)
+ if lg[0] != 0 {
+ t.Errorf("#%d: %x", i, lg)
+ }
+ }
+}
+
+func TestReducible(t *testing.T) {
+ var count = []int{1, 2, 3, 6, 9, 18, 30, 56, 99, 186} // oeis.org/A1037
+ for i, want := range count {
+ n := 0
+ for p := 1 << uint(i+2); p < 1<<uint(i+3); p++ {
+ if !reducible(p) {
+ n++
+ }
+ }
+ if n != want {
+ t.Errorf("#reducible(%d-bit) = %d, want %d", i+2, n, want)
+ }
+ }
+}
+
+func TestExhaustive(t *testing.T) {
+ for poly := 0x100; poly < 0x200; poly++ {
+ if reducible(poly) {
+ continue
+ }
+ α := 2
+ for !generates(α, poly) {
+ α++
+ }
+ f := NewField(poly, α)
+ for p := 0; p < 256; p++ {
+ for q := 0; q < 256; q++ {
+ fm := int(f.Mul(byte(p), byte(q)))
+ pm := mul(p, q, poly)
+ if fm != pm {
+ t.Errorf("NewField(%#x).Mul(%#x, %#x) = %#x, want %#x", poly, p, q, fm, pm)
+ }
+ }
+ }
+ }
+}
+
+func generates(α, poly int) bool {
+ x := α
+ for i := 0; i < 254; i++ {
+ if x == 1 {
+ return false
+ }
+ x = mul(x, α, poly)
+ }
+ return true
+}
diff --git a/vendor/github.com/mattermost/rsc/google/acme/Chat/main.go b/vendor/github.com/mattermost/rsc/google/acme/Chat/main.go
new file mode 100644
index 000000000..a161d8f10
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/google/acme/Chat/main.go
@@ -0,0 +1,575 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+/*
+TODO:
+ - Del of main window should move to other window.
+ - Editing main window should update status on \n or something like that.
+ - Make use of full names from roster
+*/
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "regexp"
+ "strings"
+ "time"
+
+ "code.google.com/p/goplan9/plan9/acme"
+ "github.com/mattermost/rsc/google"
+ "github.com/mattermost/rsc/xmpp"
+)
+
+var acmeDebug = flag.Bool("acmedebug", false, "print acme debugging")
+
+type Window struct {
+ *acme.Win // acme window
+ *acme.Event // most recent event received
+ err error // error reading event
+ typ string // kind of window "main", "chat"
+ name string // acme window title
+ remote string // for typ=="chat", remote address
+ dirty bool // window is dirty
+ blinky bool // window's dirty box is blinking
+
+ lastTime time.Time
+}
+
+type Msg struct {
+ w *Window // window where message belongs
+ *xmpp.Chat // recently received chat
+ err error // error reading chat message
+}
+
+var (
+ client *xmpp.Client // current xmpp client (can reconnect)
+ acct google.Account // google acct info
+ statusCache = make(map[string][]*xmpp.Presence)
+ active = make(map[string]*Window) // active windows
+ acmeChan = make(chan *Window) // acme events
+ msgChan = make(chan *Msg) // chat events
+ mainWin *Window
+ status = xmpp.Available
+ statusMsg = ""
+ lastActivity time.Time
+)
+
+const (
+ awayTime = 10 * time.Minute
+ extendedAwayTime = 30 * time.Minute
+)
+
+func usage() {
+ fmt.Fprintf(os.Stderr, "usage: Chat [-a acct] name...\n")
+ flag.PrintDefaults()
+ os.Exit(2)
+}
+
+var acctName = flag.String("a", "", "account to use")
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+
+ acct = google.Acct(*acctName)
+
+ aw, err := acme.New()
+ if err != nil {
+ log.Fatal(err)
+ }
+ aw.Name("Chat/" + acct.Nick + "/")
+
+ client, err = xmpp.NewClient("talk.google.com:443", acct.Email, acct.Password)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ w := &Window{Win: aw, typ: "main", name: "Chat/" + acct.Nick + "/"}
+ data, err := ioutil.ReadFile(google.Dir() + "/chat." + acct.Nick)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err == nil {
+ w.Write("body", data)
+ }
+ mainWin = w
+ active[w.name] = w
+ go w.readAcme()
+ client.Roster()
+ setStatus(status)
+ go w.readChat()
+ lastActivity = time.Now()
+
+ tick := time.Tick(0.5e9)
+Loop:
+ for len(active) > 0 {
+ select {
+ case w := <-acmeChan:
+ if w == nil {
+ // Sync with reader.
+ continue
+ }
+ if w.err != nil {
+ if active[w.name] == nil {
+ continue
+ }
+ log.Fatal(w.err)
+ }
+ if *acmeDebug {
+ fmt.Fprintf(os.Stderr, "%s %c%c %d,%d %q\n", w.name, w.C1, w.C2, w.Q0, w.Q1, w.Text)
+ }
+ if w.C1 == 'M' || w.C1 == 'K' {
+ lastActivity = time.Now()
+ if status != xmpp.Available {
+ setStatus(xmpp.Available)
+ }
+ }
+ if (w.C2 == 'x' || w.C2 == 'X') && string(w.Text) == "Del" {
+ // TODO: Hangup connection for w.typ == "acct"?
+ delete(active, w.name)
+ w.Del(true)
+ continue Loop
+ }
+
+ switch w.typ {
+ case "main":
+ switch w.C2 {
+ case 'L': // Button 3 in body: load chat window for contact.
+ w.expand()
+ fallthrough
+ case 'l': // Button 3 in tag
+ arg := string(w.Text)
+ showContact(arg)
+ continue Loop
+ }
+ case "chat":
+ if w.C1 == 'F' && w.C2 == 'I' {
+ continue Loop
+ }
+ if w.C1 != 'M' && w.C1 != 'K' {
+ break
+ }
+ if w.blinky {
+ w.blinky = false
+ w.Fprintf("ctl", "dirty\n")
+ }
+ switch w.C2 {
+ case 'X', 'x':
+ if string(w.Text) == "Ack" {
+ w.Fprintf("ctl", "clean\n")
+ }
+ case 'I':
+ w.sendMsg()
+ continue Loop
+ }
+ }
+ w.WriteEvent(w.Event)
+
+ case msg := <-msgChan:
+ w := msg.w
+ if msg.err != nil {
+ w.Fprintf("body", "ERROR: %s\n", msg.err)
+ continue Loop
+ }
+ you := msg.Remote
+ if i := strings.Index(you, "/"); i >= 0 {
+ you = you[:i]
+ }
+ switch msg.Type {
+ case "chat":
+ w := showContact(you)
+ text := strings.TrimSpace(msg.Text)
+ if text == "" {
+ // Probably a composing notification.
+ continue
+ }
+ w.message("> %s\n", text)
+ w.blinky = true
+ w.dirty = true
+
+ case "presence":
+ pr := msg.Presence
+ pr, new := savePresence(pr, you)
+ if !new {
+ continue
+ }
+ w := lookContact(you)
+ if w != nil {
+ w.status(pr)
+ }
+ mainStatus(pr, you)
+ }
+
+ case t := <-tick:
+ switch status {
+ case xmpp.Available:
+ if t.Sub(lastActivity) > awayTime {
+ setStatus(xmpp.Away)
+ }
+ case xmpp.Away:
+ if t.Sub(lastActivity) > extendedAwayTime {
+ setStatus(xmpp.ExtendedAway)
+ }
+ }
+ for _, w := range active {
+ if w.blinky {
+ w.dirty = !w.dirty
+ if w.dirty {
+ w.Fprintf("ctl", "dirty\n")
+ } else {
+ w.Fprintf("ctl", "clean\n")
+ }
+ }
+ }
+ }
+ }
+}
+
+func setStatus(st xmpp.Status) {
+ status = st
+ client.Status(status, statusMsg)
+ mainWin.statusTag(status, statusMsg)
+}
+
+func savePresence(pr *xmpp.Presence, you string) (pr1 *xmpp.Presence, new bool) {
+ old := cachedPresence(you)
+
+ pr.StatusMsg = strings.TrimSpace(pr.StatusMsg)
+ c := statusCache[you]
+ for i, p := range c {
+ if p.Remote == pr.Remote {
+ c[i] = pr
+ c[0], c[i] = c[i], c[0]
+ goto Best
+ }
+ }
+ c = append(c, pr)
+ c[0], c[len(c)-1] = c[len(c)-1], c[0]
+ statusCache[you] = c
+
+Best:
+ best := cachedPresence(you)
+ return best, old == nil || old.Status != best.Status || old.StatusMsg != best.StatusMsg
+}
+
+func cachedPresence(you string) *xmpp.Presence {
+ c := statusCache[you]
+ if len(c) == 0 {
+ return nil
+ }
+ best := c[0]
+ for _, p := range c {
+ if p.Status > best.Status {
+ best = p
+ }
+ }
+ return best
+}
+
+func short(st xmpp.Status) string {
+ switch st {
+ case xmpp.Unavailable:
+ return "?"
+ case xmpp.ExtendedAway:
+ return "x"
+ case xmpp.Away:
+ return "-"
+ case xmpp.Available:
+ return "+"
+ case xmpp.DoNotDisturb:
+ return "!"
+ }
+ return st.String()
+}
+
+func long(st xmpp.Status) string {
+ switch st {
+ case xmpp.Unavailable:
+ return "unavailable"
+ case xmpp.ExtendedAway:
+ return "offline"
+ case xmpp.Away:
+ return "away"
+ case xmpp.Available:
+ return "available"
+ case xmpp.DoNotDisturb:
+ return "busy"
+ }
+ return st.String()
+}
+
+func (w *Window) time() string {
+ /*
+ Auto-date chat windows:
+
+ Show date and time on first message.
+ Show time if minute is different from last message.
+ Show date if day is different from last message.
+
+ Oct 10 12:01 > hi
+ 12:03 hello there
+ 12:05 > what's up?
+
+ 12:10 [Away]
+ */
+ now := time.Now()
+ m1, d1, y1 := w.lastTime.Date()
+ m2, d2, y2 := now.Date()
+ w.lastTime = now
+
+ if m1 != m2 || d1 != d2 || y1 != y2 {
+ return now.Format("Jan 2 15:04 ")
+ }
+ return now.Format("15:04 ")
+}
+
+func (w *Window) status(pr *xmpp.Presence) {
+ msg := ""
+ if pr.StatusMsg != "" {
+ msg = ": " + pr.StatusMsg
+ }
+ w.message("[%s%s]\n", long(pr.Status), msg)
+
+ w.statusTag(pr.Status, pr.StatusMsg)
+}
+
+func (w *Window) statusTag(status xmpp.Status, statusMsg string) {
+ data, err := w.ReadAll("tag")
+ if err != nil {
+ log.Printf("read tag: %v", err)
+ return
+ }
+ //log.Printf("tag1: %s\n", data)
+ i := bytes.IndexByte(data, '|')
+ if i >= 0 {
+ data = data[i+1:]
+ } else {
+ data = nil
+ }
+ //log.Printf("tag2: %s\n", data)
+ j := bytes.IndexByte(data, '|')
+ if j >= 0 {
+ data = data[j+1:]
+ }
+ //log.Printf("tag3: %s\n", data)
+
+ msg := ""
+ if statusMsg != "" {
+ msg = " " + statusMsg
+ }
+ w.Ctl("cleartag\n")
+ w.Write("tag", []byte(" "+short(status)+msg+" |"+string(data)))
+}
+
+func mainStatus(pr *xmpp.Presence, you string) {
+ w := mainWin
+ if err := w.Addr("#0/^(.[ \t]+)?" + regexp.QuoteMeta(you) + "([ \t]*|$)/"); err != nil {
+ return
+ }
+ q0, q1, err := w.ReadAddr()
+ if err != nil {
+ log.Printf("ReadAddr: %s\n", err)
+ return
+ }
+ if err := w.Addr("#%d/"+regexp.QuoteMeta(you)+"/", q0); err != nil {
+ log.Printf("Addr2: %s\n", err)
+ }
+ q2, q3, err := w.ReadAddr()
+ if err != nil {
+ log.Printf("ReadAddr2: %s\n", err)
+ return
+ }
+
+ space := " "
+ if q1 > q3 || pr.StatusMsg == "" { // already have or don't need space
+ space = ""
+ }
+ if err := w.Addr("#%d/.*/", q1); err != nil {
+ log.Printf("Addr3: %s\n", err)
+ }
+ w.Fprintf("data", "%s%s", space, pr.StatusMsg)
+
+ space = ""
+ if q0 == q2 {
+ w.Addr("#%d,#%d", q0, q0)
+ space = " "
+ } else {
+ w.Addr("#%d,#%d", q0, q0+1)
+ }
+ w.Fprintf("data", "%s%s", short(pr.Status), space)
+}
+
+func (w *Window) expand() {
+ // Use selection if any.
+ w.Fprintf("ctl", "addr=dot\n")
+ q0, q1, err := w.ReadAddr()
+ if err == nil && q0 <= w.Q0 && w.Q0 <= q1 {
+ goto Read
+ }
+ if err = w.Addr("#%d-/[a-zA-Z0-9_@.\\-]*/,#%d+/[a-zA-Z0-9_@.\\-]*/", w.Q0, w.Q1); err != nil {
+ log.Printf("expand: %v", err)
+ return
+ }
+ q0, q1, err = w.ReadAddr()
+ if err != nil {
+ log.Printf("expand: %v", err)
+ return
+ }
+
+Read:
+ data, err := w.ReadAll("xdata")
+ if err != nil {
+ log.Printf("read: %v", err)
+ return
+ }
+ w.Text = data
+ w.Q0 = q0
+ w.Q1 = q1
+ return
+}
+
+// Invariant: in chat windows, the acme addr corresponds to the
+// empty string just before the input being typed. Text before addr
+// is the chat history (usually ending in a blank line).
+
+func (w *Window) message(format string, args ...interface{}) {
+ if *acmeDebug {
+ q0, q1, _ := w.ReadAddr()
+ log.Printf("message; addr=%d,%d", q0, q1)
+ }
+ if err := w.Addr(".-/\\n?\\n?/"); err != nil && *acmeDebug {
+ log.Printf("set addr: %s", err)
+ }
+ q0, _, _ := w.ReadAddr()
+ nl := ""
+ if q0 > 0 {
+ nl = "\n"
+ }
+ if *acmeDebug {
+ q0, q1, _ := w.ReadAddr()
+ log.Printf("inserting; addr=%d,%d", q0, q1)
+ }
+ w.Fprintf("data", nl+w.time()+format+"\n", args...)
+ if *acmeDebug {
+ q0, q1, _ := w.ReadAddr()
+ log.Printf("wrote; addr=%d,%d", q0, q1)
+ }
+}
+
+func (w *Window) sendMsg() {
+ if *acmeDebug {
+ q0, q1, _ := w.ReadAddr()
+ log.Printf("sendMsg; addr=%d,%d", q0, q1)
+ }
+ if err := w.Addr(`.,./(.|\n)*\n/`); err != nil {
+ if *acmeDebug {
+ q0, q1, _ := w.ReadAddr()
+ log.Printf("no text (%s); addr=%d,%d", err, q0, q1)
+ }
+ return
+ }
+ q0, q1, _ := w.ReadAddr()
+ if *acmeDebug {
+ log.Printf("found msg; addr=%d,%d", q0, q1)
+ }
+ line, _ := w.ReadAll("xdata")
+ trim := string(bytes.TrimSpace(line))
+ if len(trim) > 0 {
+ err := client.Send(xmpp.Chat{Remote: w.remote, Type: "chat", Text: trim})
+
+ // Select blank line before input (if any) and input.
+ w.Addr("#%d-/\\n?\\n?/,#%d", q0, q1)
+ if *acmeDebug {
+ q0, q1, _ := w.ReadAddr()
+ log.Printf("selected text; addr=%d,%d", q0, q1)
+ }
+ q0, _, _ := w.ReadAddr()
+
+ // Overwrite with \nmsg\n\n.
+ // Leaves addr after final \n, which is where we want it.
+ nl := ""
+ if q0 > 0 {
+ nl = "\n"
+ }
+ errstr := ""
+ if err != nil {
+ errstr = fmt.Sprintf("\n%s", errstr)
+ }
+ w.Fprintf("data", "%s%s%s%s\n\n", nl, w.time(), trim, errstr)
+ if *acmeDebug {
+ q0, q1, _ := w.ReadAddr()
+ log.Printf("wrote; addr=%d,%d", q0, q1)
+ }
+ w.Fprintf("ctl", "clean\n")
+ }
+}
+
+func (w *Window) readAcme() {
+ for {
+ e, err := w.ReadEvent()
+ if err != nil {
+ w.err = err
+ acmeChan <- w
+ break
+ }
+ //fmt.Printf("%c%c %d,%d %d,%d %#x %#q %#q %#q\n", e.C1, e.C2, e.Q0, e.Q1, e.OrigQ0, e.OrigQ1, e.Flag, e.Text, e.Arg, e.Loc)
+ w.Event = e
+ acmeChan <- w
+ acmeChan <- nil
+ }
+}
+
+func (w *Window) readChat() {
+ for {
+ msg, err := client.Recv()
+ if err != nil {
+ msgChan <- &Msg{w: w, err: err}
+ break
+ }
+ //fmt.Printf("%s\n", *msg)
+ msgChan <- &Msg{w: w, Chat: &msg}
+ }
+}
+
+func lookContact(you string) *Window {
+ return active["Chat/"+acct.Nick+"/"+you]
+}
+
+func showContact(you string) *Window {
+ w := lookContact(you)
+ if w != nil {
+ w.Ctl("show\n")
+ return w
+ }
+
+ ww, err := acme.New()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ name := "Chat/" + acct.Nick + "/" + you
+ ww.Name(name)
+ w = &Window{Win: ww, typ: "chat", name: name, remote: you}
+ w.Fprintf("body", "\n")
+ w.Addr("#1")
+ w.OpenEvent()
+ w.Fprintf("ctl", "cleartag\n")
+ w.Fprintf("tag", " Ack")
+ if p := cachedPresence(you); p != nil {
+ w.status(p)
+ }
+ active[name] = w
+ go w.readAcme()
+ return w
+}
+
+func randid() string {
+ return fmt.Sprint(time.Now())
+}
diff --git a/vendor/github.com/mattermost/rsc/google/chat.go b/vendor/github.com/mattermost/rsc/google/chat.go
new file mode 100644
index 000000000..8e9ae1c50
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/google/chat.go
@@ -0,0 +1,39 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package google
+
+import "github.com/mattermost/rsc/xmpp"
+
+type ChatID struct {
+ ID string
+ Email string
+ Status xmpp.Status
+ StatusMsg string
+}
+
+type ChatSend struct {
+ ID *ChatID
+ Msg xmpp.Chat
+}
+
+func (g *Client) ChatRecv(cid *ChatID) (*xmpp.Chat, error) {
+ var msg xmpp.Chat
+ if err := g.client.Call("goog.ChatRecv", cid, &msg); err != nil {
+ return nil, err
+ }
+ return &msg, nil
+}
+
+func (g *Client) ChatStatus(cid *ChatID) error {
+ return g.client.Call("goog.ChatRecv", cid, &Empty{})
+}
+
+func (g *Client) ChatSend(cid *ChatID, msg *xmpp.Chat) error {
+ return g.client.Call("goog.ChatSend", &ChatSend{cid, *msg}, &Empty{})
+}
+
+func (g *Client) ChatRoster(cid *ChatID) error {
+ return g.client.Call("goog.ChatRoster", cid, &Empty{})
+}
diff --git a/vendor/github.com/mattermost/rsc/google/gmail/gmail.go b/vendor/github.com/mattermost/rsc/google/gmail/gmail.go
new file mode 100644
index 000000000..1d4072ef7
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/google/gmail/gmail.go
@@ -0,0 +1,1241 @@
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "os/signal"
+ "regexp"
+ "sort"
+ "strings"
+ "time"
+
+ "github.com/mattermost/rsc/google"
+ "github.com/mattermost/rsc/imap"
+)
+
+var cmdtab = []struct {
+ Name string
+ Args int
+ F func(*Cmd, *imap.MsgPart) *imap.MsgPart
+ TF func(*Cmd, []*imap.Msg) *imap.MsgPart
+ Help string
+}{
+ {"+", 0, pluscmd, tpluscmd, "+ print the next message"},
+ {"a", 1, rcmd, nil, "a reply to sender and recipients"},
+ {"b", 0, bcmd, nil, "b print the next 10 headers"},
+ {"d", 0, dcmd, tdcmd, "d mark for deletion"},
+ {"f", 1, fcmd, tfcmd, "f forward message"},
+ {"h", 0, hcmd, nil, "h print elided message summary (,h for all)"},
+ {"help", 0, nil, nil, "help print this info"},
+ {"i", 0, icmd, nil, "i incorporate new mail"},
+ {"m", 0, mcmd, tmcmd, "m mute and delete thread (gmail only)"},
+ {"mime", 0, mimecmd, nil, "mime print message's MIME structure "},
+ {"p", 0, pcmd, nil, "p print the processed message"},
+ // { "p+", 0, pcmd, nil, "p print the processed message, showing all quoted text" },
+ {"P", 0, Pcmd, nil, "P print the raw message"},
+ {`"`, 0, quotecmd, nil, `" print a quoted version of msg`},
+ {"q", 0, qcmd, nil, "q exit and remove all deleted mail"},
+ {"r", 1, rcmd, nil, "r [addr] reply to sender plus any addrs specified"},
+ {"s", 1, scmd, tscmd, "s name copy message to named mailbox (label for gmail)"},
+ {"u", 0, ucmd, nil, "u remove deletion mark"},
+ // { "w", 1, wcmd, nil, "w file store message contents as file" },
+ {"W", 0, Wcmd, nil, "W open in web browser"},
+ {"x", 0, xcmd, nil, "x exit without flushing deleted messages"},
+ {"y", 0, ycmd, nil, "y synchronize with mail box"},
+ {"=", 1, eqcmd, nil, "= print current message number"},
+ {"|", 1, pipecmd, nil, "|cmd pipe message body to a command"},
+ // { "||", 1, rpipecmd, nil, "||cmd pipe raw message to a command" },
+ {"!", 1, bangcmd, nil, "!cmd run a command"},
+}
+
+func init() {
+ // Have to insert helpcmd by hand because it refers to cmdtab,
+ // so it would cause an init loop above.
+ for i := range cmdtab {
+ if cmdtab[i].Name == "help" {
+ cmdtab[i].F = helpcmd
+ }
+ }
+}
+
+type Cmd struct {
+ Name string
+ Args []string
+ Line string // Args[0:] original text
+ ArgLine string // Args[1:] original text
+ F func(*Cmd, *imap.MsgPart) *imap.MsgPart
+ TF func(*Cmd, []*imap.Msg) *imap.MsgPart
+ Delete bool
+ Thread bool
+ Targ *imap.MsgPart
+ Targs []*imap.Msg
+ A1, A2 int
+}
+
+var (
+ bin = bufio.NewReader(os.Stdin)
+ bout = bufio.NewWriter(os.Stdout)
+
+ acctName = flag.String("a", "", "account to use")
+
+ dot *imap.MsgPart // Selected messages
+
+ inbox *imap.Box
+ msgs []*imap.Msg
+ msgNum = make(map[*imap.Msg]int)
+ deleted = make(map[*imap.Msg]bool)
+ isGmail = false
+ acct google.Account
+ threaded bool
+ interrupted bool
+
+ maxfrom int
+ subjlen int
+)
+
+func nextMsg(m *imap.Msg) *imap.Msg {
+ i := msgNum[m]
+ i++
+ if i >= len(msgs) {
+ return nil
+ }
+ return msgs[i]
+}
+
+func main() {
+ flag.BoolVar(&imap.Debug, "imapdebug", false, "imap debugging trace")
+ flag.Parse()
+
+ acct = google.Acct(*acctName)
+
+ if args := flag.Args(); len(args) > 0 {
+ for i := range args {
+ args[i] = "-to=" + args[i]
+ }
+ cmd := exec.Command("gmailsend", append([]string{"-a", acct.Email, "-i"}, args...)...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ fmt.Fprintf(os.Stderr, "!%s\n", err)
+ os.Exit(1)
+ }
+ return
+ }
+
+ c, err := imap.NewClient(imap.TLS, "imap.gmail.com", acct.Email, acct.Password, "")
+ if err != nil {
+ log.Fatal(err)
+ }
+ isGmail = c.IsGmail()
+ threaded = isGmail
+
+ inbox = c.Inbox()
+ if err := inbox.Check(); err != nil {
+ log.Fatal(err)
+ }
+
+ msgs = inbox.Msgs()
+ maxfrom = 12
+ for i, m := range msgs {
+ msgNum[m] = i
+ if n := len(from(m.Hdr)); n > maxfrom {
+ maxfrom = n
+ }
+ }
+ if maxfrom > 20 {
+ maxfrom = 20
+ }
+ subjlen = 80 - maxfrom
+
+ rethread()
+
+ go func() {
+ for sig := range signal.Incoming {
+ if sig == os.SIGINT {
+ fmt.Fprintf(os.Stderr, "!interrupt\n")
+ interrupted = true
+ continue
+ }
+ if sig == os.SIGCHLD || sig == os.SIGWINCH {
+ continue
+ }
+ fmt.Fprintf(os.Stderr, "!%s\n", sig)
+ }
+ }()
+
+ for {
+ if dot != nil {
+ fmt.Fprintf(bout, "%d", msgNum[dot.Msg]+1)
+ if dot != &dot.Msg.Root {
+ fmt.Fprintf(bout, ".%s", dot.ID)
+ }
+ }
+ fmt.Fprintf(bout, ": ")
+ bout.Flush()
+
+ line, err := bin.ReadString('\n')
+ if err != nil {
+ break
+ }
+
+ cmd, err := parsecmd(line)
+ if err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ continue
+ }
+
+ if cmd.Targ != nil || cmd.Targs == nil && cmd.A2 == 0 {
+ x := cmd.F(cmd, cmd.Targ)
+ if x != nil {
+ dot = x
+ }
+ } else {
+ targs := cmd.Targs
+ if targs == nil {
+ delta := +1
+ if cmd.A1 > cmd.A2 {
+ delta = -1
+ }
+ for i := cmd.A1; i <= cmd.A2; i += delta {
+ if i < 1 || i > len(msgs) {
+ continue
+ }
+ targs = append(targs, msgs[i-1])
+ }
+ }
+ if cmd.Thread {
+ if !isGmail {
+ fmt.Fprintf(bout, "!need gmail for threaded command\n")
+ continue
+ }
+ byThread := make(map[uint64][]*imap.Msg)
+ for _, m := range msgs {
+ t := m.GmailThread
+ byThread[t] = append(byThread[t], m)
+ }
+ for _, m := range targs {
+ t := m.GmailThread
+ if byThread[t] != nil {
+ if cmd.TF != nil {
+ if x := cmd.TF(cmd, byThread[t]); x != nil {
+ dot = x
+ }
+ } else {
+ for _, mm := range byThread[t] {
+ x := cmd.F(cmd, &mm.Root)
+ if x != nil {
+ dot = x
+ }
+ }
+ }
+ }
+ delete(byThread, t)
+ }
+ continue
+ }
+ for _, m := range targs {
+ if cmd.Delete {
+ dcmd(cmd, &m.Root)
+ if cmd.Name == "p" {
+ // dp is a special case: it advances to the next message before the p.
+ next := nextMsg(m)
+ if next == nil {
+ fmt.Fprintf(bout, "!address\n")
+ dot = &m.Root
+ break
+ }
+ m = next
+ }
+ }
+ x := cmd.F(cmd, &m.Root)
+ if x != nil {
+ dot = x
+ }
+ // TODO: Break loop on interrupt.
+ }
+ }
+ }
+ qcmd(nil, nil)
+}
+
+func parsecmd(line string) (cmd *Cmd, err error) {
+ cmd = &Cmd{}
+ line = strings.TrimSpace(line)
+ if line == "" {
+ // Empty command is a special case: advance and print.
+ cmd.F = pcmd
+ if dot == nil {
+ cmd.A1 = 1
+ cmd.A2 = 1
+ } else {
+ n := msgNum[dot.Msg] + 2
+ if n > len(msgs) {
+ return nil, fmt.Errorf("out of messages")
+ }
+ cmd.A1 = n
+ cmd.A2 = n
+ }
+ return cmd, nil
+ }
+
+ // Global search?
+ if line[0] == 'g' {
+ line = line[1:]
+ if line == "" || line[0] != '/' {
+ // No search string means all messages.
+ cmd.A1 = 1
+ cmd.A2 = len(msgs)
+ } else if line[0] == '/' {
+ re, rest, err := parsere(line)
+ if err != nil {
+ return nil, err
+ }
+ line = rest
+ // Find all messages matching this search string.
+ var targ []*imap.Msg
+ for _, m := range msgs {
+ if re.MatchString(header(m)) {
+ targ = append(targ, m)
+ }
+ }
+ if len(targ) == 0 {
+ return nil, fmt.Errorf("no matches")
+ }
+ cmd.Targs = targ
+ }
+ } else {
+ // Parse an address.
+ a1, targ, rest, err := parseaddr(line, 1)
+ if err != nil {
+ return nil, err
+ }
+ if targ != nil {
+ cmd.Targ = targ
+ line = rest
+ } else {
+ if a1 < 1 || a1 > len(msgs) {
+ return nil, fmt.Errorf("message number %d out of range", a1)
+ }
+ cmd.A1 = a1
+ cmd.A2 = a1
+ a2 := a1
+ if rest != "" && rest[0] == ',' {
+ // This is an address range.
+ a2, targ, rest, err = parseaddr(rest[1:], len(msgs))
+ if err != nil {
+ return nil, err
+ }
+ if a2 < 1 || a2 > len(msgs) {
+ return nil, fmt.Errorf("message number %d out of range", a2)
+ }
+ cmd.A2 = a2
+ } else if rest == line {
+ // There was no address.
+ if dot == nil {
+ cmd.A1 = 1
+ cmd.A2 = 0
+ } else {
+ if dot != nil {
+ if dot == &dot.Msg.Root {
+ // If dot is a plain msg, use a range so that dp works.
+ cmd.A1 = msgNum[dot.Msg] + 1
+ cmd.A2 = cmd.A1
+ } else {
+ cmd.Targ = dot
+ }
+ }
+ }
+ }
+ line = rest
+ }
+ }
+
+ cmd.Line = strings.TrimSpace(line)
+
+ // Insert space after ! or | for tokenization.
+ switch {
+ case strings.HasPrefix(cmd.Line, "||"):
+ cmd.Line = cmd.Line[:2] + " " + cmd.Line[2:]
+ case strings.HasPrefix(cmd.Line, "!"), strings.HasPrefix(cmd.Line, "|"):
+ cmd.Line = cmd.Line[:1] + " " + cmd.Line[1:]
+ }
+
+ av := strings.Fields(cmd.Line)
+ cmd.Args = av
+ if len(av) == 0 || av[0] == "" {
+ // Default is to print.
+ cmd.F = pcmd
+ return cmd, nil
+ }
+
+ name := av[0]
+ cmd.ArgLine = strings.TrimSpace(cmd.Line[len(av[0]):])
+
+ // Hack to allow t prefix on all commands.
+ if len(name) >= 2 && name[0] == 't' {
+ cmd.Thread = true
+ name = name[1:]
+ }
+
+ // Hack to allow d prefix on all commands.
+ if len(name) >= 2 && name[0] == 'd' {
+ cmd.Delete = true
+ name = name[1:]
+ }
+ cmd.Name = name
+
+ // Search command table.
+ for _, ct := range cmdtab {
+ if ct.Name == name {
+ if ct.Args == 0 && len(av) > 1 {
+ return nil, fmt.Errorf("%s doesn't take an argument", name)
+ }
+ cmd.F = ct.F
+ cmd.TF = ct.TF
+ if name == "m" {
+ // mute applies to all thread no matter what
+ cmd.Thread = true
+ }
+ return cmd, nil
+ }
+ }
+ return nil, fmt.Errorf("unknown command %s", name)
+}
+
+func parseaddr(addr string, deflt int) (n int, targ *imap.MsgPart, rest string, err error) {
+ dot := dot
+ n = deflt
+ for {
+ old := addr
+ n, targ, rest, err = parseaddr1(addr, n, dot)
+ if targ != nil || rest == old || err != nil {
+ break
+ }
+ if n < 1 || n > len(msgs) {
+ return 0, nil, "", fmt.Errorf("message number %d out of range", n)
+ }
+ dot = &msgs[n-1].Root
+ addr = rest
+ }
+ return
+}
+
+func parseaddr1(addr string, deflt int, dot *imap.MsgPart) (n int, targ *imap.MsgPart, rest string, err error) {
+ base := 0
+ if dot != nil {
+ base = msgNum[dot.Msg] + 1
+ }
+ if addr == "" {
+ return deflt, nil, addr, nil
+ }
+ var i int
+ sign := 0
+ switch c := addr[0]; c {
+ case '+':
+ sign = +1
+ addr = addr[1:]
+ case '-':
+ sign = -1
+ addr = addr[1:]
+ case '.':
+ if base == 0 {
+ return 0, nil, "", fmt.Errorf("no message selected")
+ }
+ n = base
+ i = 1
+ goto HaveNumber
+ case '$':
+ if len(msgs) == 0 {
+ return 0, nil, "", fmt.Errorf("no messages")
+ }
+ n = len(msgs)
+ i = 1
+ goto HaveNumber
+ case '/', '?':
+ var re *regexp.Regexp
+ re, addr, err = parsere(addr)
+ if err != nil {
+ return
+ }
+ var delta int
+ if c == '/' {
+ delta = +1
+ } else {
+ delta = -1
+ }
+ for j := base + delta; 1 <= j && j <= len(msgs); j += delta {
+ if re.MatchString(header(msgs[j-1])) {
+ n = j
+ i = 0 // already cut addr
+ goto HaveNumber
+ }
+ }
+ err = fmt.Errorf("search")
+ return
+ // TODO case '%'
+ }
+ for i = 0; i < len(addr) && '0' <= addr[i] && addr[i] <= '9'; i++ {
+ n = 10*n + int(addr[i]) - '0'
+ }
+ if sign != 0 {
+ if n == 0 {
+ n = 1
+ }
+ n = base + n*sign
+ goto HaveNumber
+ }
+ if i == 0 {
+ return deflt, nil, addr, nil
+ }
+HaveNumber:
+ rest = addr[i:]
+ if i < len(addr) && addr[i] == '.' {
+ if n < 1 || n > len(msgs) {
+ err = fmt.Errorf("message number %d out of range", n)
+ return
+ }
+ targ = &msgs[n-1].Root
+ for i < len(addr) && addr[i] == '.' {
+ i++
+ var j int
+ n = 0
+ for j = i; j < len(addr) && '0' <= addr[j] && addr[j] <= '9'; j++ {
+ n = 10*n + int(addr[j]) - '0'
+ }
+ if j == i {
+ err = fmt.Errorf("malformed message number %s", addr[:j])
+ return
+ }
+ if n < 1 || n > len(targ.Child) {
+ err = fmt.Errorf("message number %s out of range", addr[:j])
+ return
+ }
+ targ = targ.Child[n-1]
+ i = j
+ }
+ n = 0
+ rest = addr[i:]
+ return
+ }
+ return
+}
+
+func parsere(addr string) (re *regexp.Regexp, rest string, err error) {
+ prog, rest, err := parseprog(addr)
+ if err != nil {
+ return
+ }
+ re, err = regexp.Compile(prog)
+ return
+}
+
+var lastProg string
+
+func parseprog(addr string) (prog string, rest string, err error) {
+ if len(addr) == 1 {
+ if lastProg != "" {
+ return lastProg, "", nil
+ }
+ err = fmt.Errorf("no search")
+ return
+ }
+ i := strings.Index(addr[1:], addr[:1])
+ if i < 0 {
+ prog = addr[1:]
+ rest = ""
+ } else {
+ i += 1 // adjust for slice in IndexByte arg
+ prog, rest = addr[1:i], addr[i+1:]
+ }
+ lastProg = prog
+ return
+}
+
+func bcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ var m *imap.Msg
+ if dot == nil {
+ if len(msgs) == 0 {
+ return nil
+ }
+ m = msgs[0]
+ } else {
+ m = dot.Msg
+ }
+ for i := 0; i < 10; i++ {
+ hcmd(c, &m.Root)
+ next := nextMsg(m)
+ if next == nil {
+ break
+ }
+ m = next
+ }
+ return &m.Root
+}
+
+func dcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ fmt.Fprintf(bout, "!address\n")
+ return nil
+ }
+ deleted[dot.Msg] = true
+ return &dot.Msg.Root
+}
+
+func tdcmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart {
+ if len(msgs) == 0 {
+ fmt.Fprintf(bout, "!address\n")
+ return nil
+ }
+ for _, m := range msgs {
+ deleted[m] = true
+ }
+ return &msgs[len(msgs)-1].Root
+}
+
+func ucmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ fmt.Fprintf(bout, "!address\n")
+ return nil
+ }
+ delete(deleted, dot.Msg)
+ return &dot.Msg.Root
+}
+
+func eqcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ fmt.Fprintf(bout, "0")
+ } else {
+ fmt.Fprintf(bout, "%d", msgNum[dot.Msg]+1)
+ if dot != &dot.Msg.Root {
+ fmt.Fprintf(bout, ".%s", dot.ID)
+ }
+ }
+ fmt.Fprintf(bout, "\n")
+ return nil
+}
+
+func from(h *imap.MsgHdr) string {
+ if len(h.From) < 1 {
+ return "?"
+ }
+ if name := h.From[0].Name; name != "" {
+ return name
+ }
+ return h.From[0].Email
+}
+
+func header(m *imap.Msg) string {
+ var t string
+ if time.Now().Sub(m.Date) > 365*24*time.Hour {
+ t = m.Date.Format("01/02 15:04")
+ } else {
+ t = m.Date.Format("01/02 2006 ")
+ }
+ ch := ' '
+ if len(m.Root.Child) > 1 || len(m.Root.Child) == 1 && len(m.Root.Child[0].Child) > 0 {
+ ch = 'H'
+ }
+ del := ' '
+ if deleted[m] {
+ del = 'd'
+ }
+ return fmt.Sprintf("%-3d %c%c %s %-*.*s %.*s",
+ msgNum[m]+1, ch, del, t,
+ maxfrom, maxfrom, from(m.Hdr),
+ subjlen, m.Hdr.Subject)
+}
+
+func hcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot != nil {
+ fmt.Fprintf(bout, "%s\n", header(dot.Msg))
+ }
+ return nil
+}
+
+func helpcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ fmt.Fprint(bout, "Commands are of the form [<range>] <command> [args]\n")
+ fmt.Fprint(bout, "<range> := <addr> | <addr>','<addr>| 'g'<search>\n")
+ fmt.Fprint(bout, "<addr> := '.' | '$' | '^' | <number> | <search> | <addr>'+'<addr> | <addr>'-'<addr>\n")
+ fmt.Fprint(bout, "<search> := '/'<gmail search>'/' | '?'<gmail search>'?'\n")
+ fmt.Fprint(bout, "<command> :=\n")
+ for _, ct := range cmdtab {
+ fmt.Fprintf(bout, "%s\n", ct.Help)
+ }
+ return dot
+}
+
+func mimecmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot != nil {
+ mimeH(fmt.Sprint(msgNum[dot.Msg]+1), dot)
+ }
+ return nil
+}
+
+func mimeH(id string, p *imap.MsgPart) {
+ if p.ID != "" {
+ id = id + "." + p.ID
+ }
+ fmt.Fprintf(bout, "%s %s %s %#q %d\n", id, p.Type, p.Encoding+"/"+p.Charset, p.Name, p.Bytes)
+ for _, child := range p.Child {
+ mimeH(id, child)
+ }
+}
+
+func icmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ sync(false)
+ return nil
+}
+
+func ycmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ sync(true)
+ return nil
+}
+
+func tpluscmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart {
+ if len(msgs) == 0 {
+ return nil
+ }
+ m := nextMsg(msgs[len(msgs)-1])
+ if m == nil {
+ fmt.Fprintf(bout, "!no more messages\n")
+ return nil
+ }
+ return pcmd(c, &m.Root)
+}
+
+func pluscmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ return nil
+ }
+ m := nextMsg(dot.Msg)
+ if m == nil {
+ fmt.Fprintf(bout, "!no more messages\n")
+ return nil
+ }
+ return pcmd(c, &m.Root)
+}
+
+func addrlist(x []imap.Addr) string {
+ var b bytes.Buffer
+ for i, a := range x {
+ if i > 0 {
+ b.WriteString(", ")
+ }
+ b.WriteString(a.String())
+ }
+ return b.String()
+}
+
+func wpcmd(w io.Writer, c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ return nil
+ }
+ if dot == &dot.Msg.Root {
+ h := dot.Msg.Hdr
+ if len(h.From) > 0 {
+ fmt.Fprintf(w, "From: %s\n", addrlist(h.From))
+ }
+ fmt.Fprintf(w, "Date: %s\n", dot.Msg.Date)
+ if len(h.From) > 0 {
+ fmt.Fprintf(w, "To: %s\n", addrlist(h.To))
+ }
+ if len(h.CC) > 0 {
+ fmt.Fprintf(w, "CC: %s\n", addrlist(h.CC))
+ }
+ if len(h.BCC) > 0 {
+ fmt.Fprintf(w, "BCC: %s\n", addrlist(h.BCC))
+ }
+ if len(h.Subject) > 0 {
+ fmt.Fprintf(w, "Subject: %s\n", h.Subject)
+ }
+ fmt.Fprintf(w, "\n")
+ }
+ printMIME(w, dot, true)
+ fmt.Fprintf(w, "\n")
+ return dot
+}
+
+func pcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ defer bout.Flush()
+ return wpcmd(bout, c, dot)
+}
+
+func pipecmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ args := c.Args[1:]
+ if len(args) == 0 {
+ fmt.Fprintf(bout, "!no command\n")
+ return dot
+ }
+ bout.Flush()
+ cmd := exec.Command(args[0], args[1:]...)
+ w, err := cmd.StdinPipe()
+ if err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ return dot
+ }
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Start(); err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ return dot
+ }
+ wpcmd(w, c, dot)
+ w.Close()
+ if err := cmd.Wait(); err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ }
+ return dot
+}
+
+func bangcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ args := c.Args[1:]
+ if len(args) == 0 {
+ fmt.Fprintf(bout, "!no command\n")
+ return dot
+ }
+ bout.Flush()
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ }
+ return nil
+}
+
+func unixfrom(h *imap.MsgHdr) string {
+ if len(h.From) == 0 {
+ return ""
+ }
+ return h.From[0].Email
+}
+
+func unixtime(m *imap.Msg) string {
+ return dot.Msg.Date.Format("Mon Jan _2 15:04:05 MST 2006")
+}
+
+func Pcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ return nil
+ }
+ if dot == &dot.Msg.Root {
+ fmt.Fprintf(bout, "From %s %s\n",
+ unixfrom(dot.Msg.Hdr),
+ unixtime(dot.Msg))
+ }
+ bout.Write(dot.Raw())
+ return dot
+}
+
+func printMIME(w io.Writer, p *imap.MsgPart, top bool) {
+ switch {
+ case top && strings.HasPrefix(p.Type, "text/"):
+ text := p.ShortText()
+ if p.Type == "text/html" {
+ cmd := exec.Command("htmlfmt")
+ cmd.Stdin = bytes.NewBuffer(text)
+ if w == bout {
+ bout.Flush()
+ cmd.Stdout = os.Stdout
+ } else {
+ cmd.Stdout = w
+ }
+ if err := cmd.Run(); err != nil {
+ fmt.Fprintf(w, "%d.%s !%s\n", msgNum[p.Msg]+1, p.ID, err)
+ }
+ return
+ }
+ w.Write(text)
+ case p.Type == "text/plain":
+ if top {
+ panic("printMIME loop")
+ }
+ printMIME(w, p, true)
+ case p.Type == "multipart/alternative":
+ for _, pp := range p.Child {
+ if pp.Type == "text/plain" {
+ printMIME(w, pp, false)
+ return
+ }
+ }
+ if len(p.Child) > 0 {
+ printMIME(w, p.Child[0], false)
+ }
+ case strings.HasPrefix(p.Type, "multipart/"):
+ for _, pp := range p.Child {
+ printMIME(w, pp, false)
+ }
+ default:
+ fmt.Fprintf(w, "%d.%s !%s %s %s\n", msgNum[p.Msg]+1, p.ID, p.Type, p.Desc, p.Name)
+ }
+}
+
+func qcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ flushDeleted()
+ xcmd(c, dot)
+ panic("not reached")
+}
+
+type quoter struct {
+ bol bool
+ w io.Writer
+}
+
+func (q *quoter) Write(b []byte) (n int, err error) {
+ n = len(b)
+ err = nil
+ for len(b) > 0 {
+ if q.bol {
+ q.w.Write([]byte("> "))
+ q.bol = false
+ }
+ i := bytes.IndexByte(b, '\n')
+ if i < 0 {
+ i = len(b)
+ } else {
+ q.bol = true
+ i++
+ }
+ q.w.Write(b[:i])
+ b = b[i:]
+ }
+ return
+}
+
+func quotecmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ return nil
+ }
+ m := dot.Msg
+ if len(m.Hdr.From) != 0 {
+ a := m.Hdr.From[0]
+ name := a.Name
+ if name == "" {
+ name = a.Email
+ }
+ date := m.Date.Format("Jan 2, 2006 at 15:04")
+ fmt.Fprintf(bout, "On %s, %s wrote:\n", date, name)
+ }
+ printMIME(&quoter{true, bout}, dot, true)
+ return dot
+}
+
+func addre(s string) string {
+ if len(s) < 4 || !strings.EqualFold(s[:4], "re: ") {
+ return "Re: " + s
+ }
+ return s
+}
+
+func rcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil || dot.Msg.Hdr == nil {
+ fmt.Fprintf(bout, "!nothing to reply to\n")
+ return nil
+ }
+
+ h := dot.Msg.Hdr
+ replyTo := h.ReplyTo
+ have := make(map[string]bool)
+ if len(replyTo) == 0 {
+ replyTo = h.From
+ }
+ if c.Name[0] == 'a' {
+ for _, a := range replyTo {
+ have[a.Email] = true
+ }
+ for _, a := range append(append(append([]imap.Addr(nil), h.From...), h.To...), h.CC...) {
+ if !have[a.Email] {
+ have[a.Email] = true
+ replyTo = append(replyTo, a)
+ }
+ }
+ }
+ if len(replyTo) == 0 {
+ fmt.Fprintf(bout, "!no one to reply to\n")
+ return dot
+ }
+
+ args := []string{"-a", acct.Email, "-s", addre(h.Subject), "-in-reply-to", h.MessageID}
+ fmt.Fprintf(bout, "replying to:")
+ for _, a := range replyTo {
+ fmt.Fprintf(bout, " %s", a.Email)
+ args = append(args, "-to", a.String())
+ }
+ for _, arg := range c.Args[1:] {
+ fmt.Fprintf(bout, " %s", arg)
+ args = append(args, "-to", arg)
+ }
+ fmt.Fprintf(bout, "\n")
+ bout.Flush()
+ cmd := exec.Command("gmailsend", args...)
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ err := cmd.Run()
+ if err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ }
+ return dot
+}
+
+func fcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ fmt.Fprintf(bout, "!nothing to forward\n")
+ return nil
+ }
+
+ return fwd(c, dot, nil)
+}
+
+func tfcmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart {
+ if len(msgs) == 0 {
+ fmt.Fprintf(bout, "!nothing to forward\n")
+ return nil
+ }
+
+ return fwd(c, &msgs[len(msgs)-1].Root, msgs)
+}
+
+func fwd(c *Cmd, dot *imap.MsgPart, msgs []*imap.Msg) *imap.MsgPart {
+ addrs := c.Args[1:]
+ if len(addrs) == 0 {
+ fmt.Fprintf(bout, "!f command requires address to forward to\n")
+ return dot
+ }
+
+ h := dot.Msg.Hdr
+ args := []string{"-a", acct.Email, "-s", "Fwd: " + h.Subject, "-append", "/dev/fd/3"}
+ fmt.Fprintf(bout, "forwarding to:")
+ for _, arg := range addrs {
+ fmt.Fprintf(bout, " %s", arg)
+ args = append(args, "-to", arg)
+ }
+ fmt.Fprintf(bout, "\n")
+ bout.Flush()
+
+ cmd := exec.Command("gmailsend", args...)
+ r, w, err := os.Pipe()
+ if err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ return dot
+ }
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.ExtraFiles = []*os.File{r}
+ if err := cmd.Start(); err != nil {
+ r.Close()
+ fmt.Fprintf(bout, "!%s\n", err)
+ return dot
+ }
+ r.Close()
+ what := "message"
+ if len(msgs) > 1 {
+ what = "conversation"
+ }
+ fmt.Fprintf(w, "\n\n--- Forwarded %s ---\n", what)
+ if msgs == nil {
+ wpcmd(w, c, dot)
+ } else {
+ for _, m := range msgs {
+ wpcmd(w, c, &m.Root)
+ fmt.Fprintf(w, "\n\n")
+ }
+ }
+ w.Close()
+ if err := cmd.Wait(); err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ }
+ return dot
+}
+
+func rethread() {
+ if !threaded {
+ sort.Sort(byUIDRev(msgs))
+ } else {
+ byThread := make(map[uint64][]*imap.Msg)
+ for _, m := range msgs {
+ t := m.GmailThread
+ byThread[t] = append(byThread[t], m)
+ }
+
+ var threadList [][]*imap.Msg
+ for _, t := range byThread {
+ sort.Sort(byUID(t))
+ threadList = append(threadList, t)
+ }
+ sort.Sort(byUIDList(threadList))
+
+ msgs = msgs[:0]
+ for _, t := range threadList {
+ msgs = append(msgs, t...)
+ }
+ }
+ for i, m := range msgs {
+ msgNum[m] = i
+ }
+}
+
+type byUID []*imap.Msg
+
+func (l byUID) Less(i, j int) bool { return l[i].UID < l[j].UID }
+func (l byUID) Len() int { return len(l) }
+func (l byUID) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+
+type byUIDRev []*imap.Msg
+
+func (l byUIDRev) Less(i, j int) bool { return l[i].UID > l[j].UID }
+func (l byUIDRev) Len() int { return len(l) }
+func (l byUIDRev) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+
+type byUIDList [][]*imap.Msg
+
+func (l byUIDList) Less(i, j int) bool { return l[i][len(l[i])-1].UID > l[j][len(l[j])-1].UID }
+func (l byUIDList) Len() int { return len(l) }
+func (l byUIDList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+
+func subj(m *imap.Msg) string {
+ s := m.Hdr.Subject
+ for strings.HasPrefix(s, "Re: ") || strings.HasPrefix(s, "RE: ") {
+ s = s[4:]
+ }
+ return s
+}
+
+func mcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ c.ArgLine = "Muted"
+ scmd(c, dot)
+ return dcmd(c, dot)
+}
+
+func tmcmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart {
+ c.ArgLine = "Muted"
+ tscmd(c, msgs)
+ return tdcmd(c, msgs)
+}
+
+func scmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ return nil
+ }
+ return tscmd(c, []*imap.Msg{dot.Msg})
+}
+
+func tscmd(c *Cmd, msgs []*imap.Msg) *imap.MsgPart {
+ if len(msgs) == 0 {
+ return nil
+ }
+ arg := c.ArgLine
+ dot := &msgs[len(msgs)-1].Root
+ if arg == "" {
+ fmt.Fprintf(bout, "!s needs mailbox (label) name as argument\n")
+ return dot
+ }
+ if strings.EqualFold(arg, "Muted") {
+ if err := dot.Msg.Box.Mute(msgs); err != nil {
+ fmt.Fprintf(bout, "!mute: %s\n", err)
+ }
+ } else {
+ dst := dot.Msg.Box.Client.Box(arg)
+ if dst == nil {
+ fmt.Fprintf(bout, "!unknown mailbox %#q", arg)
+ return dot
+ }
+ if err := dst.Copy(msgs); err != nil {
+ fmt.Fprintf(bout, "!s %#q: %s\n", arg, err)
+ }
+ }
+ return dot
+}
+
+func Wcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ if dot == nil {
+ return nil
+ }
+ if !isGmail {
+ fmt.Fprintf(bout, "!cmd W requires gmail\n")
+ return dot
+ }
+ url := fmt.Sprintf("https://mail.google.com/mail/b/%s/?shva=1#inbox/%x", acct.Email, dot.Msg.GmailThread)
+ if err := exec.Command("open", url).Run(); err != nil {
+ fmt.Fprintf(bout, "!%s\n", err)
+ }
+ return dot
+}
+
+func xcmd(c *Cmd, dot *imap.MsgPart) *imap.MsgPart {
+ // TODO: remove saved attachments?
+ os.Exit(0)
+ panic("not reached")
+}
+
+func flushDeleted() {
+ var toDelete []*imap.Msg
+ for m := range deleted {
+ toDelete = append(toDelete, m)
+ }
+ if len(toDelete) == 0 {
+ return
+ }
+ fmt.Fprintf(os.Stderr, "!deleting %d\n", len(toDelete))
+ err := inbox.Delete(toDelete)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "!deleting: %s\n", err)
+ }
+}
+
+func loadNew() {
+ if err := inbox.Check(); err != nil {
+ fmt.Fprintf(os.Stderr, "!inbox: %s\n", err)
+ }
+
+ old := make(map[*imap.Msg]bool)
+ for _, m := range msgs {
+ old[m] = true
+ }
+
+ nnew := 0
+ new := inbox.Msgs()
+ for _, m := range new {
+ if old[m] {
+ delete(old, m)
+ } else {
+ msgs = append(msgs, m)
+ nnew++
+ }
+ }
+ if nnew > 0 {
+ fmt.Fprintf(os.Stderr, "!%d new messages\n", nnew)
+ }
+ for m := range old {
+ // Deleted
+ m.Flags |= imap.FlagDeleted
+ delete(deleted, m)
+ }
+}
+
+func sync(delete bool) {
+ if delete {
+ flushDeleted()
+ }
+ loadNew()
+ if delete {
+ w := 0
+ for _, m := range msgs {
+ if !m.Deleted() {
+ msgs[w] = m
+ w++
+ }
+ }
+ msgs = msgs[:w]
+ }
+ rethread()
+}
diff --git a/vendor/github.com/mattermost/rsc/google/gmailsend/send.go b/vendor/github.com/mattermost/rsc/google/gmailsend/send.go
new file mode 100644
index 000000000..ace6eb12b
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/google/gmailsend/send.go
@@ -0,0 +1,370 @@
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "flag"
+ "fmt"
+ "io"
+ "net/smtp"
+ "os"
+ "regexp"
+ "strings"
+
+ "github.com/mattermost/rsc/google"
+)
+
+func enc(s string) string {
+ // TODO =? .. ?=
+ return s
+}
+
+type Addr struct {
+ Name string
+ Email string
+}
+
+func (a Addr) enc() string {
+ if a.Name == "" {
+ return "<" + a.Email + ">"
+ }
+ if a.Email == "" {
+ return enc(a.Name) + ":;"
+ }
+ return enc(a.Name) + " <" + a.Email + ">"
+}
+
+type Addrs []Addr
+
+func (a *Addrs) String() string {
+ return "[addrlist]"
+}
+
+func (a Addrs) has(s string) bool {
+ for _, aa := range a {
+ if aa.Email == s {
+ return true
+ }
+ }
+ return false
+}
+
+func (a *Addrs) Set(s string) bool {
+ s = strings.TrimSpace(s)
+ if strings.HasSuffix(s, ">") {
+ j := strings.LastIndex(s, "<")
+ if j >= 0 {
+ *a = append(*a, Addr{strings.TrimSpace(s[:j]), s[j+1 : len(s)-1]})
+ return true
+ }
+ }
+
+ if strings.Contains(s, " ") {
+ fmt.Fprintf(os.Stderr, "invalid address: %s", s)
+ os.Exit(2)
+ }
+ *a = append(*a, Addr{"", s})
+ return true
+}
+
+func (a *Addrs) parseLine(s string) {
+ for _, f := range strings.Split(s, ",") {
+ f = strings.TrimSpace(f)
+ if f != "" {
+ a.Set(f)
+ }
+ }
+}
+
+func (a Addrs) fixDomain() {
+ i := strings.Index(acct.Email, "@")
+ if i < 0 {
+ return
+ }
+ dom := acct.Email[i:]
+ for i := range a {
+ if a[i].Email != "" && !strings.Contains(a[i].Email, "@") {
+ a[i].Email += dom
+ }
+ }
+}
+
+var from, to, cc, bcc, replyTo Addrs
+var inReplyTo, subject string
+var appendFile = flag.String("append", "", "file to append to end of body")
+
+var acct google.Account
+var acctName = flag.String("a", "", "account to use")
+var inputHeader = flag.Bool("i", false, "read additional header lines from stdin")
+
+func holdmode() {
+ if os.Getenv("TERM") == "9term" {
+ // forgive me
+ os.Stdout.WriteString("\x1B];*9term-hold+\x07")
+ }
+}
+
+func match(line, prefix string, arg *string) bool {
+ if len(line) < len(prefix) || !strings.EqualFold(line[:len(prefix)], prefix) {
+ return false
+ }
+ *arg = strings.TrimSpace(line[len(prefix):])
+ return true
+}
+
+func main() {
+ flag.StringVar(&inReplyTo, "in-reply-to", "", "In-Reply-To")
+ flag.StringVar(&subject, "s", "", "Subject")
+ flag.Var(&from, "from", "From (can repeat)")
+ flag.Var(&to, "to", "To (can repeat)")
+ flag.Var(&cc, "cc", "CC (can repeat)")
+ flag.Var(&bcc, "bcc", "BCC (can repeat)")
+ flag.Var(&replyTo, "replyTo", "Reply-To (can repeat)")
+
+ flag.Parse()
+ if flag.NArg() != 0 && !*inputHeader {
+ flag.Usage()
+ }
+
+ var body bytes.Buffer
+ input := bufio.NewReader(os.Stdin)
+ if *inputHeader {
+ holdmode()
+ Loop:
+ for {
+ s, err := input.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ break Loop
+ }
+ fmt.Fprintf(os.Stderr, "reading stdin: %s\n", err)
+ os.Exit(2)
+ }
+ var arg string
+ switch {
+ default:
+ if ok, _ := regexp.MatchString(`^\S+:`, s); ok {
+ fmt.Fprintf(os.Stderr, "unknown header line: %s", s)
+ os.Exit(2)
+ }
+ body.WriteString(s)
+ break Loop
+ case match(s, "from:", &arg):
+ from.parseLine(arg)
+ case match(s, "to:", &arg):
+ to.parseLine(arg)
+ case match(s, "cc:", &arg):
+ cc.parseLine(arg)
+ case match(s, "bcc:", &arg):
+ bcc.parseLine(arg)
+ case match(s, "reply-to:", &arg):
+ replyTo.parseLine(arg)
+ case match(s, "subject:", &arg):
+ subject = arg
+ case match(s, "in-reply-to:", &arg):
+ inReplyTo = arg
+ }
+ }
+ }
+
+ acct = google.Acct(*acctName)
+ from.fixDomain()
+ to.fixDomain()
+ cc.fixDomain()
+ bcc.fixDomain()
+ replyTo.fixDomain()
+
+ smtpTo := append(append(to, cc...), bcc...)
+
+ if len(from) == 0 {
+ // TODO: Much better
+ name := ""
+ email := acct.Email
+ if email == "rsc@swtch.com" || email == "rsc@google.com" {
+ name = "Russ Cox"
+ }
+ if email == "rsc@google.com" && (smtpTo.has("go@googlecode.com") || smtpTo.has("golang-dev@googlegroups.com") || smtpTo.has("golang-nuts@googlegroups.com")) {
+ from = append(from, Addr{name, "rsc@golang.org"})
+ } else {
+ from = append(from, Addr{name, email})
+ }
+ }
+
+ if len(from) > 1 {
+ fmt.Fprintf(os.Stderr, "missing -from\n")
+ os.Exit(2)
+ }
+
+ if len(to)+len(cc)+len(bcc) == 0 {
+ fmt.Fprintf(os.Stderr, "missing destinations\n")
+ os.Exit(2)
+ }
+
+ if !*inputHeader {
+ holdmode()
+ }
+ _, err := io.Copy(&body, input)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "reading stdin: %s\n", err)
+ os.Exit(2)
+ }
+
+ if *appendFile != "" {
+ f, err := os.Open(*appendFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "append: %s\n", err)
+ os.Exit(2)
+ }
+ _, err = io.Copy(&body, f)
+ f.Close()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "append: %s\n", err)
+ os.Exit(2)
+ }
+ }
+
+ var msg bytes.Buffer
+ fmt.Fprintf(&msg, "MIME-Version: 1.0\n")
+ if len(from) > 0 {
+ fmt.Fprintf(&msg, "From: ")
+ for i, a := range from {
+ if i > 0 {
+ fmt.Fprintf(&msg, ", ")
+ }
+ fmt.Fprintf(&msg, "%s", a.enc())
+ }
+ fmt.Fprintf(&msg, "\n")
+ }
+ if len(to) > 0 {
+ fmt.Fprintf(&msg, "To: ")
+ for i, a := range to {
+ if i > 0 {
+ fmt.Fprintf(&msg, ", ")
+ }
+ fmt.Fprintf(&msg, "%s", a.enc())
+ }
+ fmt.Fprintf(&msg, "\n")
+ }
+ if len(cc) > 0 {
+ fmt.Fprintf(&msg, "CC: ")
+ for i, a := range cc {
+ if i > 0 {
+ fmt.Fprintf(&msg, ", ")
+ }
+ fmt.Fprintf(&msg, "%s", a.enc())
+ }
+ fmt.Fprintf(&msg, "\n")
+ }
+ if len(replyTo) > 0 {
+ fmt.Fprintf(&msg, "Reply-To: ")
+ for i, a := range replyTo {
+ if i > 0 {
+ fmt.Fprintf(&msg, ", ")
+ }
+ fmt.Fprintf(&msg, "%s", a.enc())
+ }
+ fmt.Fprintf(&msg, "\n")
+ }
+ if inReplyTo != "" {
+ fmt.Fprintf(&msg, "In-Reply-To: %s\n", inReplyTo)
+ }
+ if subject != "" {
+ fmt.Fprintf(&msg, "Subject: %s\n", enc(subject))
+ }
+ fmt.Fprintf(&msg, "Date: xxx\n")
+ fmt.Fprintf(&msg, "Content-Type: text/plain; charset=\"utf-8\"\n")
+ fmt.Fprintf(&msg, "Content-Transfer-Encoding: base64\n")
+ fmt.Fprintf(&msg, "\n")
+ enc64 := base64.StdEncoding.EncodeToString(body.Bytes())
+ for len(enc64) > 72 {
+ fmt.Fprintf(&msg, "%s\n", enc64[:72])
+ enc64 = enc64[72:]
+ }
+ fmt.Fprintf(&msg, "%s\n\n", enc64)
+
+ auth := smtp.PlainAuth(
+ "",
+ acct.Email,
+ acct.Password,
+ "smtp.gmail.com",
+ )
+ var smtpToEmail []string
+ for _, a := range smtpTo {
+ if a.Email != "" {
+ smtpToEmail = append(smtpToEmail, a.Email)
+ }
+ }
+
+ if err := sendMail("smtp.gmail.com:587", auth, from[0].Email, smtpToEmail, msg.Bytes()); err != nil {
+ fmt.Fprintf(os.Stderr, "sending mail: %s\n", err)
+ os.Exit(2)
+ }
+}
+
+/*
+ MIME-Version: 1.0
+Subject: commit/plan9port: rsc: 9term: hold mode back door
+From: Bitbucket <commits-noreply@bitbucket.org>
+To: plan9port-dev@googlegroups.com
+Date: Tue, 11 Oct 2011 13:34:30 -0000
+Message-ID: <20111011133430.31146.55070@bitbucket13.managed.contegix.com>
+Reply-To: commits-noreply@bitbucket.org
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: quoted-printable
+
+1 new changeset in plan9port:
+
+http://bitbucket.org/rsc/plan9port/changeset/8735d7708a1b/
+changeset: 8735d7708a1b
+user: rsc
+date: 2011-10-11 15:34:25
+summary: 9term: hold mode back door
+
+R=3Drsc
+http://codereview.appspot.com/5248056
+affected #: 2 files (-1 bytes)
+
+Repository URL: https://bitbucket.org/rsc/plan9port/
+
+--
+
+This is a commit notification from bitbucket.org. You are receiving
+this because you have the service enabled, addressing the recipient of
+this email.
+
+*/
+
+func sendMail(addr string, a smtp.Auth, from string, to []string, msg []byte) error {
+ c, err := smtp.Dial(addr)
+ if err != nil {
+ return err
+ }
+ if err = c.StartTLS(nil); err != nil {
+ return err
+ }
+ if err = c.Auth(a); err != nil {
+ return err
+ }
+ if err = c.Mail(from); err != nil {
+ return err
+ }
+ for _, addr := range to {
+ if err = c.Rcpt(addr); err != nil {
+ return err
+ }
+ }
+ w, err := c.Data()
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(msg)
+ if err != nil {
+ return err
+ }
+ err = w.Close()
+ if err != nil {
+ return err
+ }
+ return c.Quit()
+}
diff --git a/vendor/github.com/mattermost/rsc/google/googleserver/chat.go b/vendor/github.com/mattermost/rsc/google/googleserver/chat.go
new file mode 100644
index 000000000..8b064dc92
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/google/googleserver/chat.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: Add ChatHangup.
+// TODO: Auto-hangup chats that are gone.
+
+package main
+
+import (
+ "fmt"
+
+ "github.com/mattermost/rsc/google"
+ "github.com/mattermost/rsc/xmpp"
+)
+
+type chatClient struct {
+ email string
+ id string
+ xmpp *xmpp.Client
+}
+
+var chatClients = map[string]*chatClient{}
+
+func (*Server) chatClient(cid *google.ChatID) (*chatClient, error) {
+ id := cid.ID
+ cc := chatClients[cid.ID]
+ if cc == nil {
+ a := google.Cfg.AccountByEmail(cid.Email)
+ if a == nil {
+ return nil, fmt.Errorf("unknown account %s", cid.Email)
+ }
+ // New client.
+ cli, err := xmpp.NewClient("talk.google.com:443", a.Email, a.Password)
+ if err != nil {
+ return nil, err
+ }
+ cc = &chatClient{email: a.Email, id: id, xmpp: cli}
+ cc.xmpp.Status(cid.Status, cid.StatusMsg)
+ chatClients[id] = cc
+ }
+ return cc, nil
+}
+
+func (srv *Server) ChatRecv(cid *google.ChatID, msg *xmpp.Chat) error {
+ cc, err := srv.chatClient(cid)
+ if err != nil {
+ return err
+ }
+ chat, err := cc.xmpp.Recv()
+ if err != nil {
+ return err
+ }
+ *msg = chat
+ return nil
+}
+
+func (srv *Server) ChatStatus(cid *google.ChatID, _ *Empty) error {
+ cc, err := srv.chatClient(cid)
+ if err != nil {
+ return err
+ }
+ return cc.xmpp.Status(cid.Status, cid.StatusMsg)
+}
+
+func (srv *Server) ChatSend(arg *google.ChatSend, _ *Empty) error {
+ cc, err := srv.chatClient(arg.ID)
+ if err != nil {
+ return err
+ }
+ return cc.xmpp.Send(arg.Msg)
+}
+
+func (srv *Server) ChatRoster(cid *google.ChatID, _ *Empty) error {
+ cc, err := srv.chatClient(cid)
+ if err != nil {
+ return err
+ }
+ return cc.xmpp.Roster()
+}
diff --git a/vendor/github.com/mattermost/rsc/google/googleserver/main.go b/vendor/github.com/mattermost/rsc/google/googleserver/main.go
new file mode 100644
index 000000000..2cd022446
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/google/googleserver/main.go
@@ -0,0 +1,139 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ // "flag"
+ "bufio"
+ "fmt"
+ "log"
+ "net"
+ "net/rpc"
+ "os"
+ "strings"
+ "syscall"
+
+ "github.com/mattermost/rsc/google"
+ "github.com/mattermost/rsc/xmpp"
+)
+
+func main() {
+ google.ReadConfig()
+ switch os.Args[1] {
+ case "add":
+ google.Cfg.Account = append(google.Cfg.Account, &google.Account{Email: os.Args[2], Password: os.Args[3]})
+ google.WriteConfig()
+ case "serve":
+ serve()
+ case "accounts":
+ c, err := google.Dial()
+ if err != nil {
+ log.Fatal(err)
+ }
+ out, err := c.Accounts()
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, email := range out {
+ fmt.Printf("%s\n", email)
+ }
+ case "ping":
+ c, err := google.Dial()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := c.Ping(); err != nil {
+ log.Fatal(err)
+ }
+ case "chat":
+ c, err := google.Dial()
+ if err != nil {
+ log.Fatal(err)
+ }
+ cid := &google.ChatID{ID: "1", Email: os.Args[2], Status: xmpp.Available, StatusMsg: ""}
+ go chatRecv(c, cid)
+ c.ChatRoster(cid)
+ b := bufio.NewReader(os.Stdin)
+ for {
+ line, err := b.ReadString('\n')
+ if err != nil {
+ log.Fatal(err)
+ }
+ line = line[:len(line)-1]
+ i := strings.Index(line, ": ")
+ if i < 0 {
+ log.Printf("<who>: <msg>, please")
+ continue
+ }
+ who, msg := line[:i], line[i+2:]
+ if err := c.ChatSend(cid, &xmpp.Chat{Remote: who, Type: "chat", Text: msg}); err != nil {
+ log.Fatal(err)
+ }
+ }
+ }
+}
+
+func chatRecv(c *google.Client, cid *google.ChatID) {
+ for {
+ msg, err := c.ChatRecv(cid)
+ if err != nil {
+ log.Fatal(err)
+ }
+ switch msg.Type {
+ case "roster":
+ for _, contact := range msg.Roster {
+ fmt.Printf("%v\n", contact)
+ }
+ case "presence":
+ fmt.Printf("%v\n", msg.Presence)
+ case "chat":
+ fmt.Printf("%s: %s\n", msg.Remote, msg.Text)
+ default:
+ fmt.Printf("<%s>\n", msg.Type)
+ }
+ }
+}
+
+func listen() net.Listener {
+ socket := google.Dir() + "/socket"
+ os.Remove(socket)
+ l, err := net.Listen("unix", socket)
+ if err != nil {
+ log.Fatal(err)
+ }
+ return l
+}
+
+func serve() {
+ f, err := os.OpenFile(google.Dir()+"/log", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.SetOutput(f)
+ syscall.Dup2(f.Fd(), 2)
+ os.Stdout = f
+ os.Stderr = f
+ l := listen()
+ rpc.RegisterName("goog", &Server{})
+ rpc.Accept(l)
+ log.Fatal("rpc.Accept finished: server exiting")
+}
+
+type Server struct{}
+
+type Empty google.Empty
+
+func (*Server) Ping(*Empty, *Empty) error {
+ return nil
+}
+
+func (*Server) Accounts(_ *Empty, out *[]string) error {
+ var email []string
+ for _, a := range google.Cfg.Account {
+ email = append(email, a.Email)
+ }
+ *out = email
+ return nil
+}
diff --git a/vendor/github.com/mattermost/rsc/google/main.go b/vendor/github.com/mattermost/rsc/google/main.go
new file mode 100644
index 000000000..b11a6eefb
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/google/main.go
@@ -0,0 +1,181 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO: Something about redialing.
+
+package google
+
+import (
+ // "flag"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/rpc"
+ "os"
+ "os/exec"
+ "syscall"
+ "time"
+)
+
+func Dir() string {
+ dir := os.Getenv("HOME") + "/.goog"
+ st, err := os.Stat(dir)
+ if err != nil {
+ if err := os.Mkdir(dir, 0700); err != nil {
+ log.Fatal(err)
+ }
+ st, err = os.Stat(dir)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ if !st.IsDir() {
+ log.Fatalf("%s exists but is not a directory", dir)
+ }
+ if st.Mode()&0077 != 0 {
+ log.Fatalf("%s exists but allows group or other permissions: %#o", dir, st.Mode()&0777)
+ }
+ return dir
+}
+
+func Dial() (*Client, error) {
+ socket := Dir() + "/socket"
+ c, err := net.Dial("unix", socket)
+ if err == nil {
+ return &Client{rpc.NewClient(c)}, nil
+ }
+ log.Print("starting server")
+ os.Remove(socket)
+ runServer()
+ for i := 0; i < 50; i++ {
+ c, err = net.Dial("unix", socket)
+ if err == nil {
+ return &Client{rpc.NewClient(c)}, nil
+ }
+ time.Sleep(200e6)
+ if i == 0 {
+ log.Print("waiting for server...")
+ }
+ }
+ return nil, err
+}
+
+type Client struct {
+ client *rpc.Client
+}
+
+type Empty struct{}
+
+func (g *Client) Ping() error {
+ return g.client.Call("goog.Ping", &Empty{}, &Empty{})
+}
+
+func (g *Client) Accounts() ([]string, error) {
+ var out []string
+ if err := g.client.Call("goog.Accounts", &Empty{}, &out); err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func runServer() {
+ cmd := exec.Command("googleserver", "serve")
+ cmd.SysProcAttr = &syscall.SysProcAttr{}
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+}
+
+type Config struct {
+ Account []*Account
+}
+
+type Account struct {
+ Email string
+ Password string
+ Nick string
+}
+
+func (cfg *Config) AccountByEmail(email string) *Account {
+ for _, a := range cfg.Account {
+ if a.Email == email {
+ return a
+ }
+ }
+ return nil
+}
+
+var Cfg Config
+
+func ReadConfig() {
+ file := Dir() + "/config"
+ st, err := os.Stat(file)
+ if err != nil {
+ return
+ }
+ if st.Mode()&0077 != 0 {
+ log.Fatalf("%s exists but allows group or other permissions: %#o", file, st.Mode()&0777)
+ }
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ Cfg = Config{}
+ if err := json.Unmarshal(data, &Cfg); err != nil {
+ log.Fatal(err)
+ }
+}
+
+func WriteConfig() {
+ file := Dir() + "/config"
+ st, err := os.Stat(file)
+ if err != nil {
+ if err := ioutil.WriteFile(file, nil, 0600); err != nil {
+ log.Fatal(err)
+ }
+ st, err = os.Stat(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ if st.Mode()&0077 != 0 {
+ log.Fatalf("%s exists but allows group or other permissions: %#o", file, st.Mode()&0777)
+ }
+ data, err := json.MarshalIndent(&Cfg, "", "\t")
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := ioutil.WriteFile(file, data, 0600); err != nil {
+ log.Fatal(err)
+ }
+ st, err = os.Stat(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if st.Mode()&0077 != 0 {
+ log.Fatalf("%s allows group or other permissions after writing: %#o", file, st.Mode()&0777)
+ }
+}
+
+func Acct(name string) Account {
+ ReadConfig()
+ if name == "" {
+ if len(Cfg.Account) == 0 {
+ fmt.Fprintf(os.Stderr, "no accounts configured\n")
+ os.Exit(2)
+ }
+ return *Cfg.Account[0]
+ }
+
+ for _, a := range Cfg.Account {
+ if a.Email == name || a.Nick == name {
+ return *a
+ }
+ }
+ fmt.Fprintf(os.Stderr, "cannot find account %#q", name)
+ os.Exit(2)
+ panic("not reached")
+}
diff --git a/vendor/github.com/mattermost/rsc/gtfs/gtfs.pb.go b/vendor/github.com/mattermost/rsc/gtfs/gtfs.pb.go
new file mode 100644
index 000000000..7a91a74d5
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/gtfs/gtfs.pb.go
@@ -0,0 +1,440 @@
+// Code generated by protoc-gen-go from "crashme/gtfs.proto"
+// DO NOT EDIT!
+
+package gtfs
+
+import proto "code.google.com/p/goprotobuf/proto"
+import "math"
+
+// Reference proto, math & os imports to suppress error if they are not otherwise used.
+var _ = proto.GetString
+var _ = math.Inf
+var _ error
+
+type FeedHeader_Incrementality int32
+
+const (
+ FeedHeader_FULL_DATASET FeedHeader_Incrementality = 0
+ FeedHeader_DIFFERENTIAL FeedHeader_Incrementality = 1
+)
+
+var FeedHeader_Incrementality_name = map[int32]string{
+ 0: "FULL_DATASET",
+ 1: "DIFFERENTIAL",
+}
+var FeedHeader_Incrementality_value = map[string]int32{
+ "FULL_DATASET": 0,
+ "DIFFERENTIAL": 1,
+}
+
+func NewFeedHeader_Incrementality(x FeedHeader_Incrementality) *FeedHeader_Incrementality {
+ e := FeedHeader_Incrementality(x)
+ return &e
+}
+func (x FeedHeader_Incrementality) String() string {
+ return proto.EnumName(FeedHeader_Incrementality_name, int32(x))
+}
+
+type TripUpdate_StopTimeUpdate_ScheduleRelationship int32
+
+const (
+ TripUpdate_StopTimeUpdate_SCHEDULED TripUpdate_StopTimeUpdate_ScheduleRelationship = 0
+ TripUpdate_StopTimeUpdate_SKIPPED TripUpdate_StopTimeUpdate_ScheduleRelationship = 1
+ TripUpdate_StopTimeUpdate_NO_DATA TripUpdate_StopTimeUpdate_ScheduleRelationship = 2
+)
+
+var TripUpdate_StopTimeUpdate_ScheduleRelationship_name = map[int32]string{
+ 0: "SCHEDULED",
+ 1: "SKIPPED",
+ 2: "NO_DATA",
+}
+var TripUpdate_StopTimeUpdate_ScheduleRelationship_value = map[string]int32{
+ "SCHEDULED": 0,
+ "SKIPPED": 1,
+ "NO_DATA": 2,
+}
+
+func NewTripUpdate_StopTimeUpdate_ScheduleRelationship(x TripUpdate_StopTimeUpdate_ScheduleRelationship) *TripUpdate_StopTimeUpdate_ScheduleRelationship {
+ e := TripUpdate_StopTimeUpdate_ScheduleRelationship(x)
+ return &e
+}
+func (x TripUpdate_StopTimeUpdate_ScheduleRelationship) String() string {
+ return proto.EnumName(TripUpdate_StopTimeUpdate_ScheduleRelationship_name, int32(x))
+}
+
+type VehiclePosition_VehicleStopStatus int32
+
+const (
+ VehiclePosition_INCOMING_AT VehiclePosition_VehicleStopStatus = 0
+ VehiclePosition_STOPPED_AT VehiclePosition_VehicleStopStatus = 1
+ VehiclePosition_IN_TRANSIT_TO VehiclePosition_VehicleStopStatus = 2
+)
+
+var VehiclePosition_VehicleStopStatus_name = map[int32]string{
+ 0: "INCOMING_AT",
+ 1: "STOPPED_AT",
+ 2: "IN_TRANSIT_TO",
+}
+var VehiclePosition_VehicleStopStatus_value = map[string]int32{
+ "INCOMING_AT": 0,
+ "STOPPED_AT": 1,
+ "IN_TRANSIT_TO": 2,
+}
+
+func NewVehiclePosition_VehicleStopStatus(x VehiclePosition_VehicleStopStatus) *VehiclePosition_VehicleStopStatus {
+ e := VehiclePosition_VehicleStopStatus(x)
+ return &e
+}
+func (x VehiclePosition_VehicleStopStatus) String() string {
+ return proto.EnumName(VehiclePosition_VehicleStopStatus_name, int32(x))
+}
+
+type VehiclePosition_CongestionLevel int32
+
+const (
+ VehiclePosition_UNKNOWN_CONGESTION_LEVEL VehiclePosition_CongestionLevel = 0
+ VehiclePosition_RUNNING_SMOOTHLY VehiclePosition_CongestionLevel = 1
+ VehiclePosition_STOP_AND_GO VehiclePosition_CongestionLevel = 2
+ VehiclePosition_CONGESTION VehiclePosition_CongestionLevel = 3
+ VehiclePosition_SEVERE_CONGESTION VehiclePosition_CongestionLevel = 4
+)
+
+var VehiclePosition_CongestionLevel_name = map[int32]string{
+ 0: "UNKNOWN_CONGESTION_LEVEL",
+ 1: "RUNNING_SMOOTHLY",
+ 2: "STOP_AND_GO",
+ 3: "CONGESTION",
+ 4: "SEVERE_CONGESTION",
+}
+var VehiclePosition_CongestionLevel_value = map[string]int32{
+ "UNKNOWN_CONGESTION_LEVEL": 0,
+ "RUNNING_SMOOTHLY": 1,
+ "STOP_AND_GO": 2,
+ "CONGESTION": 3,
+ "SEVERE_CONGESTION": 4,
+}
+
+func NewVehiclePosition_CongestionLevel(x VehiclePosition_CongestionLevel) *VehiclePosition_CongestionLevel {
+ e := VehiclePosition_CongestionLevel(x)
+ return &e
+}
+func (x VehiclePosition_CongestionLevel) String() string {
+ return proto.EnumName(VehiclePosition_CongestionLevel_name, int32(x))
+}
+
+type Alert_Cause int32
+
+const (
+ Alert_UNKNOWN_CAUSE Alert_Cause = 1
+ Alert_OTHER_CAUSE Alert_Cause = 2
+ Alert_TECHNICAL_PROBLEM Alert_Cause = 3
+ Alert_STRIKE Alert_Cause = 4
+ Alert_DEMONSTRATION Alert_Cause = 5
+ Alert_ACCIDENT Alert_Cause = 6
+ Alert_HOLIDAY Alert_Cause = 7
+ Alert_WEATHER Alert_Cause = 8
+ Alert_MAINTENANCE Alert_Cause = 9
+ Alert_CONSTRUCTION Alert_Cause = 10
+ Alert_POLICE_ACTIVITY Alert_Cause = 11
+ Alert_MEDICAL_EMERGENCY Alert_Cause = 12
+)
+
+var Alert_Cause_name = map[int32]string{
+ 1: "UNKNOWN_CAUSE",
+ 2: "OTHER_CAUSE",
+ 3: "TECHNICAL_PROBLEM",
+ 4: "STRIKE",
+ 5: "DEMONSTRATION",
+ 6: "ACCIDENT",
+ 7: "HOLIDAY",
+ 8: "WEATHER",
+ 9: "MAINTENANCE",
+ 10: "CONSTRUCTION",
+ 11: "POLICE_ACTIVITY",
+ 12: "MEDICAL_EMERGENCY",
+}
+var Alert_Cause_value = map[string]int32{
+ "UNKNOWN_CAUSE": 1,
+ "OTHER_CAUSE": 2,
+ "TECHNICAL_PROBLEM": 3,
+ "STRIKE": 4,
+ "DEMONSTRATION": 5,
+ "ACCIDENT": 6,
+ "HOLIDAY": 7,
+ "WEATHER": 8,
+ "MAINTENANCE": 9,
+ "CONSTRUCTION": 10,
+ "POLICE_ACTIVITY": 11,
+ "MEDICAL_EMERGENCY": 12,
+}
+
+func NewAlert_Cause(x Alert_Cause) *Alert_Cause {
+ e := Alert_Cause(x)
+ return &e
+}
+func (x Alert_Cause) String() string {
+ return proto.EnumName(Alert_Cause_name, int32(x))
+}
+
+type Alert_Effect int32
+
+const (
+ Alert_NO_SERVICE Alert_Effect = 1
+ Alert_REDUCED_SERVICE Alert_Effect = 2
+ Alert_SIGNIFICANT_DELAYS Alert_Effect = 3
+ Alert_DETOUR Alert_Effect = 4
+ Alert_ADDITIONAL_SERVICE Alert_Effect = 5
+ Alert_MODIFIED_SERVICE Alert_Effect = 6
+ Alert_OTHER_EFFECT Alert_Effect = 7
+ Alert_UNKNOWN_EFFECT Alert_Effect = 8
+ Alert_STOP_MOVED Alert_Effect = 9
+)
+
+var Alert_Effect_name = map[int32]string{
+ 1: "NO_SERVICE",
+ 2: "REDUCED_SERVICE",
+ 3: "SIGNIFICANT_DELAYS",
+ 4: "DETOUR",
+ 5: "ADDITIONAL_SERVICE",
+ 6: "MODIFIED_SERVICE",
+ 7: "OTHER_EFFECT",
+ 8: "UNKNOWN_EFFECT",
+ 9: "STOP_MOVED",
+}
+var Alert_Effect_value = map[string]int32{
+ "NO_SERVICE": 1,
+ "REDUCED_SERVICE": 2,
+ "SIGNIFICANT_DELAYS": 3,
+ "DETOUR": 4,
+ "ADDITIONAL_SERVICE": 5,
+ "MODIFIED_SERVICE": 6,
+ "OTHER_EFFECT": 7,
+ "UNKNOWN_EFFECT": 8,
+ "STOP_MOVED": 9,
+}
+
+func NewAlert_Effect(x Alert_Effect) *Alert_Effect {
+ e := Alert_Effect(x)
+ return &e
+}
+func (x Alert_Effect) String() string {
+ return proto.EnumName(Alert_Effect_name, int32(x))
+}
+
+type TripDescriptor_ScheduleRelationship int32
+
+const (
+ TripDescriptor_SCHEDULED TripDescriptor_ScheduleRelationship = 0
+ TripDescriptor_ADDED TripDescriptor_ScheduleRelationship = 1
+ TripDescriptor_UNSCHEDULED TripDescriptor_ScheduleRelationship = 2
+ TripDescriptor_CANCELED TripDescriptor_ScheduleRelationship = 3
+ TripDescriptor_REPLACEMENT TripDescriptor_ScheduleRelationship = 5
+)
+
+var TripDescriptor_ScheduleRelationship_name = map[int32]string{
+ 0: "SCHEDULED",
+ 1: "ADDED",
+ 2: "UNSCHEDULED",
+ 3: "CANCELED",
+ 5: "REPLACEMENT",
+}
+var TripDescriptor_ScheduleRelationship_value = map[string]int32{
+ "SCHEDULED": 0,
+ "ADDED": 1,
+ "UNSCHEDULED": 2,
+ "CANCELED": 3,
+ "REPLACEMENT": 5,
+}
+
+func NewTripDescriptor_ScheduleRelationship(x TripDescriptor_ScheduleRelationship) *TripDescriptor_ScheduleRelationship {
+ e := TripDescriptor_ScheduleRelationship(x)
+ return &e
+}
+func (x TripDescriptor_ScheduleRelationship) String() string {
+ return proto.EnumName(TripDescriptor_ScheduleRelationship_name, int32(x))
+}
+
+type FeedMessage struct {
+ Header *FeedHeader `protobuf:"bytes,1,req,name=header" json:"header"`
+ Entity []*FeedEntity `protobuf:"bytes,2,rep,name=entity" json:"entity"`
+ XXX_unrecognized []byte
+}
+
+func (this *FeedMessage) Reset() { *this = FeedMessage{} }
+func (this *FeedMessage) String() string { return proto.CompactTextString(this) }
+
+type FeedHeader struct {
+ GtfsRealtimeVersion *string `protobuf:"bytes,1,req,name=gtfs_realtime_version" json:"gtfs_realtime_version"`
+ Incrementality *FeedHeader_Incrementality `protobuf:"varint,2,opt,name=incrementality,enum=transit_realtime.FeedHeader_Incrementality,def=0" json:"incrementality"`
+ Timestamp *uint64 `protobuf:"varint,3,opt,name=timestamp" json:"timestamp"`
+ XXX_unrecognized []byte
+}
+
+func (this *FeedHeader) Reset() { *this = FeedHeader{} }
+func (this *FeedHeader) String() string { return proto.CompactTextString(this) }
+
+const Default_FeedHeader_Incrementality FeedHeader_Incrementality = FeedHeader_FULL_DATASET
+
+type FeedEntity struct {
+ Id *string `protobuf:"bytes,1,req,name=id" json:"id"`
+ IsDeleted *bool `protobuf:"varint,2,opt,name=is_deleted,def=0" json:"is_deleted"`
+ TripUpdate *TripUpdate `protobuf:"bytes,3,opt,name=trip_update" json:"trip_update"`
+ Vehicle *VehiclePosition `protobuf:"bytes,4,opt,name=vehicle" json:"vehicle"`
+ Alert *Alert `protobuf:"bytes,5,opt,name=alert" json:"alert"`
+ XXX_unrecognized []byte
+}
+
+func (this *FeedEntity) Reset() { *this = FeedEntity{} }
+func (this *FeedEntity) String() string { return proto.CompactTextString(this) }
+
+const Default_FeedEntity_IsDeleted bool = false
+
+type TripUpdate struct {
+ Trip *TripDescriptor `protobuf:"bytes,1,req,name=trip" json:"trip"`
+ Vehicle *VehicleDescriptor `protobuf:"bytes,3,opt,name=vehicle" json:"vehicle"`
+ StopTimeUpdate []*TripUpdate_StopTimeUpdate `protobuf:"bytes,2,rep,name=stop_time_update" json:"stop_time_update"`
+ XXX_unrecognized []byte
+}
+
+func (this *TripUpdate) Reset() { *this = TripUpdate{} }
+func (this *TripUpdate) String() string { return proto.CompactTextString(this) }
+
+type TripUpdate_StopTimeEvent struct {
+ Delay *int32 `protobuf:"varint,1,opt,name=delay" json:"delay"`
+ Time *int64 `protobuf:"varint,2,opt,name=time" json:"time"`
+ Uncertainty *int32 `protobuf:"varint,3,opt,name=uncertainty" json:"uncertainty"`
+ XXX_unrecognized []byte
+}
+
+func (this *TripUpdate_StopTimeEvent) Reset() { *this = TripUpdate_StopTimeEvent{} }
+func (this *TripUpdate_StopTimeEvent) String() string { return proto.CompactTextString(this) }
+
+type TripUpdate_StopTimeUpdate struct {
+ StopSequence *uint32 `protobuf:"varint,1,opt,name=stop_sequence" json:"stop_sequence"`
+ StopId *string `protobuf:"bytes,4,opt,name=stop_id" json:"stop_id"`
+ Arrival *TripUpdate_StopTimeEvent `protobuf:"bytes,2,opt,name=arrival" json:"arrival"`
+ Departure *TripUpdate_StopTimeEvent `protobuf:"bytes,3,opt,name=departure" json:"departure"`
+ ScheduleRelationship *TripUpdate_StopTimeUpdate_ScheduleRelationship `protobuf:"varint,5,opt,name=schedule_relationship,enum=transit_realtime.TripUpdate_StopTimeUpdate_ScheduleRelationship,def=0" json:"schedule_relationship"`
+ XXX_unrecognized []byte
+}
+
+func (this *TripUpdate_StopTimeUpdate) Reset() { *this = TripUpdate_StopTimeUpdate{} }
+func (this *TripUpdate_StopTimeUpdate) String() string { return proto.CompactTextString(this) }
+
+const Default_TripUpdate_StopTimeUpdate_ScheduleRelationship TripUpdate_StopTimeUpdate_ScheduleRelationship = TripUpdate_StopTimeUpdate_SCHEDULED
+
+type VehiclePosition struct {
+ Trip *TripDescriptor `protobuf:"bytes,1,opt,name=trip" json:"trip"`
+ Vehicle *VehicleDescriptor `protobuf:"bytes,8,opt,name=vehicle" json:"vehicle"`
+ Position *Position `protobuf:"bytes,2,opt,name=position" json:"position"`
+ CurrentStopSequence *uint32 `protobuf:"varint,3,opt,name=current_stop_sequence" json:"current_stop_sequence"`
+ StopId *string `protobuf:"bytes,7,opt,name=stop_id" json:"stop_id"`
+ CurrentStatus *VehiclePosition_VehicleStopStatus `protobuf:"varint,4,opt,name=current_status,enum=transit_realtime.VehiclePosition_VehicleStopStatus,def=2" json:"current_status"`
+ Timestamp *uint64 `protobuf:"varint,5,opt,name=timestamp" json:"timestamp"`
+ CongestionLevel *VehiclePosition_CongestionLevel `protobuf:"varint,6,opt,name=congestion_level,enum=transit_realtime.VehiclePosition_CongestionLevel" json:"congestion_level"`
+ XXX_unrecognized []byte
+}
+
+func (this *VehiclePosition) Reset() { *this = VehiclePosition{} }
+func (this *VehiclePosition) String() string { return proto.CompactTextString(this) }
+
+const Default_VehiclePosition_CurrentStatus VehiclePosition_VehicleStopStatus = VehiclePosition_IN_TRANSIT_TO
+
+type Alert struct {
+ ActivePeriod []*TimeRange `protobuf:"bytes,1,rep,name=active_period" json:"active_period"`
+ InformedEntity []*EntitySelector `protobuf:"bytes,5,rep,name=informed_entity" json:"informed_entity"`
+ Cause *Alert_Cause `protobuf:"varint,6,opt,name=cause,enum=transit_realtime.Alert_Cause,def=1" json:"cause"`
+ Effect *Alert_Effect `protobuf:"varint,7,opt,name=effect,enum=transit_realtime.Alert_Effect,def=8" json:"effect"`
+ Url *TranslatedString `protobuf:"bytes,8,opt,name=url" json:"url"`
+ HeaderText *TranslatedString `protobuf:"bytes,10,opt,name=header_text" json:"header_text"`
+ DescriptionText *TranslatedString `protobuf:"bytes,11,opt,name=description_text" json:"description_text"`
+ XXX_unrecognized []byte
+}
+
+func (this *Alert) Reset() { *this = Alert{} }
+func (this *Alert) String() string { return proto.CompactTextString(this) }
+
+const Default_Alert_Cause Alert_Cause = Alert_UNKNOWN_CAUSE
+const Default_Alert_Effect Alert_Effect = Alert_UNKNOWN_EFFECT
+
+type TimeRange struct {
+ Start *uint64 `protobuf:"varint,1,opt,name=start" json:"start"`
+ End *uint64 `protobuf:"varint,2,opt,name=end" json:"end"`
+ XXX_unrecognized []byte
+}
+
+func (this *TimeRange) Reset() { *this = TimeRange{} }
+func (this *TimeRange) String() string { return proto.CompactTextString(this) }
+
+type Position struct {
+ Latitude *float32 `protobuf:"fixed32,1,req,name=latitude" json:"latitude"`
+ Longitude *float32 `protobuf:"fixed32,2,req,name=longitude" json:"longitude"`
+ Bearing *float32 `protobuf:"fixed32,3,opt,name=bearing" json:"bearing"`
+ Odometer *float64 `protobuf:"fixed64,4,opt,name=odometer" json:"odometer"`
+ Speed *float32 `protobuf:"fixed32,5,opt,name=speed" json:"speed"`
+ XXX_unrecognized []byte
+}
+
+func (this *Position) Reset() { *this = Position{} }
+func (this *Position) String() string { return proto.CompactTextString(this) }
+
+type TripDescriptor struct {
+ TripId *string `protobuf:"bytes,1,opt,name=trip_id" json:"trip_id"`
+ RouteId *string `protobuf:"bytes,5,opt,name=route_id" json:"route_id"`
+ StartTime *string `protobuf:"bytes,2,opt,name=start_time" json:"start_time"`
+ StartDate *string `protobuf:"bytes,3,opt,name=start_date" json:"start_date"`
+ ScheduleRelationship *TripDescriptor_ScheduleRelationship `protobuf:"varint,4,opt,name=schedule_relationship,enum=transit_realtime.TripDescriptor_ScheduleRelationship" json:"schedule_relationship"`
+ XXX_unrecognized []byte
+}
+
+func (this *TripDescriptor) Reset() { *this = TripDescriptor{} }
+func (this *TripDescriptor) String() string { return proto.CompactTextString(this) }
+
+type VehicleDescriptor struct {
+ Id *string `protobuf:"bytes,1,opt,name=id" json:"id"`
+ Label *string `protobuf:"bytes,2,opt,name=label" json:"label"`
+ LicensePlate *string `protobuf:"bytes,3,opt,name=license_plate" json:"license_plate"`
+ XXX_unrecognized []byte
+}
+
+func (this *VehicleDescriptor) Reset() { *this = VehicleDescriptor{} }
+func (this *VehicleDescriptor) String() string { return proto.CompactTextString(this) }
+
+type EntitySelector struct {
+ AgencyId *string `protobuf:"bytes,1,opt,name=agency_id" json:"agency_id"`
+ RouteId *string `protobuf:"bytes,2,opt,name=route_id" json:"route_id"`
+ RouteType *int32 `protobuf:"varint,3,opt,name=route_type" json:"route_type"`
+ Trip *TripDescriptor `protobuf:"bytes,4,opt,name=trip" json:"trip"`
+ StopId *string `protobuf:"bytes,5,opt,name=stop_id" json:"stop_id"`
+ XXX_unrecognized []byte
+}
+
+func (this *EntitySelector) Reset() { *this = EntitySelector{} }
+func (this *EntitySelector) String() string { return proto.CompactTextString(this) }
+
+type TranslatedString struct {
+ Translation []*TranslatedString_Translation `protobuf:"bytes,1,rep,name=translation" json:"translation"`
+ XXX_unrecognized []byte
+}
+
+func (this *TranslatedString) Reset() { *this = TranslatedString{} }
+func (this *TranslatedString) String() string { return proto.CompactTextString(this) }
+
+type TranslatedString_Translation struct {
+ Text *string `protobuf:"bytes,1,req,name=text" json:"text"`
+ Language *string `protobuf:"bytes,2,opt,name=language" json:"language"`
+ XXX_unrecognized []byte
+}
+
+func (this *TranslatedString_Translation) Reset() { *this = TranslatedString_Translation{} }
+func (this *TranslatedString_Translation) String() string { return proto.CompactTextString(this) }
+
+func init() {
+ proto.RegisterEnum("transit_realtime.FeedHeader_Incrementality", FeedHeader_Incrementality_name, FeedHeader_Incrementality_value)
+ proto.RegisterEnum("transit_realtime.TripUpdate_StopTimeUpdate_ScheduleRelationship", TripUpdate_StopTimeUpdate_ScheduleRelationship_name, TripUpdate_StopTimeUpdate_ScheduleRelationship_value)
+ proto.RegisterEnum("transit_realtime.VehiclePosition_VehicleStopStatus", VehiclePosition_VehicleStopStatus_name, VehiclePosition_VehicleStopStatus_value)
+ proto.RegisterEnum("transit_realtime.VehiclePosition_CongestionLevel", VehiclePosition_CongestionLevel_name, VehiclePosition_CongestionLevel_value)
+ proto.RegisterEnum("transit_realtime.Alert_Cause", Alert_Cause_name, Alert_Cause_value)
+ proto.RegisterEnum("transit_realtime.Alert_Effect", Alert_Effect_name, Alert_Effect_value)
+ proto.RegisterEnum("transit_realtime.TripDescriptor_ScheduleRelationship", TripDescriptor_ScheduleRelationship_name, TripDescriptor_ScheduleRelationship_value)
+}
diff --git a/vendor/github.com/mattermost/rsc/imap/Makefile b/vendor/github.com/mattermost/rsc/imap/Makefile
new file mode 100644
index 000000000..8dd3d2be4
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/Makefile
@@ -0,0 +1,15 @@
+include $(GOROOT)/src/Make.inc
+
+# TARG=code.google.com/p/rsc/imap
+
+TARG=rsc.googlecode.com/hg/imap
+GOFILES=\
+ decode.go\
+ imap.go\
+ mail.go\
+ sx.go\
+ tcs.go\
+
+GCIMPORTS=-I$(GOPATH)/pkg/$(GOOS)_$(GOARCH)
+
+include $(GOROOT)/src/Make.pkg
diff --git a/vendor/github.com/mattermost/rsc/imap/decode.go b/vendor/github.com/mattermost/rsc/imap/decode.go
new file mode 100644
index 000000000..ebeb1d7d7
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/decode.go
@@ -0,0 +1,227 @@
+package imap
+
+import (
+ "bytes"
+ "encoding/base64"
+ "strings"
+ "unicode"
+)
+
+func decode2047chunk(s string) (conv []byte, rest string, ok bool) {
+ // s is =?...
+ // and should be =?charset?e?text?=
+ j := strings.Index(s[2:], "?")
+ if j < 0 {
+ return
+ }
+ j += 2
+ if j+2 >= len(s) || s[j+2] != '?' {
+ return
+ }
+ k := strings.Index(s[j+3:], "?=")
+ if k < 0 {
+ return
+ }
+ k += j + 3
+
+ charset, enc, text, rest := s[2:j], s[j+1], s[j+3:k], s[k+2:]
+ var encoding string
+ switch enc {
+ default:
+ return
+ case 'q', 'Q':
+ encoding = "quoted-printable"
+ case 'b', 'B':
+ encoding = "base64"
+ }
+
+ dat := decodeText([]byte(text), encoding, charset, true)
+ if dat == nil {
+ return
+ }
+ return dat, rest, true
+}
+
+func decodeQP(dat []byte, underscore bool) []byte {
+ out := make([]byte, len(dat))
+ w := 0
+ for i := 0; i < len(dat); i++ {
+ c := dat[i]
+ if underscore && c == '_' {
+ out[w] = ' '
+ w++
+ continue
+ }
+ if c == '\r' {
+ continue
+ }
+ if c == '=' {
+ if i+1 < len(dat) && dat[i+1] == '\n' {
+ i++
+ continue
+ }
+ if i+2 < len(dat) && dat[i+1] == '\r' && dat[i+2] == '\n' {
+ i += 2
+ continue
+ }
+ if i+2 < len(dat) {
+ v := unhex(dat[i+1])<<4 | unhex(dat[i+2])
+ if v >= 0 {
+ out[w] = byte(v)
+ w++
+ i += 2
+ continue
+ }
+ }
+ }
+ out[w] = c
+ w++
+ }
+ return out[:w]
+}
+
+func nocrnl(dat []byte) []byte {
+ w := 0
+ for _, c := range dat {
+ if c != '\r' && c != '\n' {
+ dat[w] = c
+ w++
+ }
+ }
+ return dat[:w]
+}
+
+func decode64(dat []byte) []byte {
+ out := make([]byte, len(dat))
+ copy(out, dat)
+ out = nocrnl(out)
+ n, err := base64.StdEncoding.Decode(out, out)
+ if err != nil {
+ return nil
+ }
+ return out[:n]
+}
+
+func decodeText(dat []byte, encoding, charset string, underscore bool) []byte {
+ odat := dat
+ switch strlwr(encoding) {
+ case "quoted-printable":
+ dat = decodeQP(dat, underscore)
+ case "base64":
+ dat = decode64(dat)
+ }
+ if dat == nil {
+ return nil
+ }
+ if bytes.IndexByte(dat, '\r') >= 0 {
+ if &odat[0] == &dat[0] {
+ dat = append([]byte(nil), dat...)
+ }
+ dat = nocr(dat)
+ }
+
+ charset = strlwr(charset)
+ if charset == "utf-8" || charset == "us-ascii" {
+ return dat
+ }
+ if charset == "iso-8859-1" {
+ // Avoid allocation for iso-8859-1 that is really just ascii.
+ for _, c := range dat {
+ if c >= 0x80 {
+ goto NeedConv
+ }
+ }
+ return dat
+ NeedConv:
+ }
+
+ // TODO: big5, iso-2022-jp
+
+ tab := convtab[charset]
+ if tab == nil {
+ return dat
+ }
+ var b bytes.Buffer
+ for _, c := range dat {
+ if tab[c] < 0 {
+ b.WriteRune(unicode.ReplacementChar)
+ } else {
+ b.WriteRune(tab[c])
+ }
+ }
+ return b.Bytes()
+}
+
+var convtab = map[string]*[256]rune{
+ "iso-8859-1": &tab_iso8859_1,
+ "iso-8859-2": &tab_iso8859_2,
+ "iso-8859-3": &tab_iso8859_3,
+ "iso-8859-4": &tab_iso8859_4,
+ "iso-8859-5": &tab_iso8859_5,
+ "iso-8859-6": &tab_iso8859_6,
+ "iso-8859-7": &tab_iso8859_7,
+ "iso-8859-8": &tab_iso8859_8,
+ "iso-8859-9": &tab_iso8859_9,
+ "iso-8859-10": &tab_iso8859_10,
+ "iso-8859-15": &tab_iso8859_15,
+ "koi8-r": &tab_koi8,
+ "windows-1250": &tab_cp1250,
+ "windows-1251": &tab_cp1251,
+ "windows-1252": &tab_cp1252,
+ "windows-1253": &tab_cp1253,
+ "windows-1254": &tab_cp1254,
+ "windows-1255": &tab_cp1255,
+ "windows-1256": &tab_cp1256,
+ "windows-1257": &tab_cp1257,
+ "windows-1258": &tab_cp1258,
+}
+
+func unrfc2047(s string) string {
+ if !strings.Contains(s, "=?") {
+ return s
+ }
+ var buf bytes.Buffer
+ for {
+ // =?charset?e?text?=
+ i := strings.Index(s, "=?")
+ if i < 0 {
+ break
+ }
+ conv, rest, ok := decode2047chunk(s[i:])
+ if !ok {
+ buf.WriteString(s[:i+2])
+ s = s[i+2:]
+ continue
+ }
+ buf.WriteString(s[:i])
+ buf.Write(conv)
+ s = rest
+ }
+ buf.WriteString(s)
+ return buf.String()
+}
+
+func lwr(c rune) rune {
+ if 'A' <= c && c <= 'Z' {
+ return c + 'a' - 'A'
+ }
+ return c
+}
+
+func strlwr(s string) string {
+ return strings.Map(lwr, s)
+}
+
+func unhex(c byte) int {
+ switch {
+ case '0' <= c && c <= '9':
+ return int(c) - '0'
+ case 'a' <= c && c <= 'f':
+ return int(c) - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return int(c) - 'A' + 10
+ }
+ return -1
+}
+
+// TODO: Will need modified UTF-7 eventually.
diff --git a/vendor/github.com/mattermost/rsc/imap/decode_test.go b/vendor/github.com/mattermost/rsc/imap/decode_test.go
new file mode 100644
index 000000000..84c31f63a
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/decode_test.go
@@ -0,0 +1,26 @@
+package imap
+
+import "testing"
+
+var unrfc2047Tests = []struct {
+ in, out string
+}{
+ {"hello world", "hello world"},
+ {"hello =?iso-8859-1?q?this is some text?=", "hello this is some text"},
+ {"=?US-ASCII?Q?Keith_Moore?=", "Keith Moore"},
+ {"=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=", "Keld Jørn Simonsen"},
+ {"=?ISO-8859-1?Q?Andr=E9?= Pirard", "André Pirard"},
+ {"=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=", "If you can read this yo"},
+ {"=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=", "u understand the example."},
+ {"=?ISO-8859-1?Q?Olle_J=E4rnefors?=", "Olle Järnefors"},
+ // {"=?iso-2022-jp?B?GyRCTTVKISRKP006SiRyS34kPyQ3JEZKcz03JCIkahsoQg==?=", ""},
+ {"=?UTF-8?B?Ik5pbHMgTy4gU2Vsw6VzZGFsIg==?=", `"Nils O. Selåsdal"`},
+}
+
+func TestUnrfc2047(t *testing.T) {
+ for _, tt := range unrfc2047Tests {
+ if out := unrfc2047(tt.in); out != tt.out {
+ t.Errorf("unrfc2047(%#q) = %#q, want %#q", tt.in, out, tt.out)
+ }
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/imap/imap.go b/vendor/github.com/mattermost/rsc/imap/imap.go
new file mode 100644
index 000000000..6555984d2
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/imap.go
@@ -0,0 +1,1110 @@
+package imap
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/md5"
+ "crypto/tls"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+ "sync"
+)
+
+var Debug = false
+
+const tag = "#"
+
+// A Mode specifies the IMAP connection mode.
+type Mode int
+
+const (
+ Unencrypted Mode = iota // unencrypted TCP connection
+ StartTLS // use IMAP STARTTLS command - unimplemented!
+ TLS // direct TLS connection
+ Command // exec shell command (server name)
+)
+
+type lock struct {
+ locked bool
+ mu sync.Mutex
+}
+
+func (l *lock) lock() {
+ l.mu.Lock()
+ l.locked = true
+}
+
+func (l *lock) unlock() {
+ l.mustBeLocked()
+ l.locked = false
+ l.mu.Unlock()
+}
+
+func (l *lock) mustBeLocked() {
+ if !l.locked {
+ panic("not locked")
+ }
+}
+
+type Client struct {
+ server string
+ user string
+ passwd string
+ mode Mode
+ root string
+
+ io lock
+ rw io.ReadWriteCloser // i/o to server
+ b *bufio.Reader // buffered rw
+ autoReconnect bool // reconnect on failure
+ connected bool // rw is active
+
+ data lock
+ capability map[string]bool
+ flags Flags
+ boxByName map[string]*Box // all known boxes
+ allBox []*Box // all known boxes (do we need this?)
+ rootBox *Box // root of box tree
+ inbox *Box // inbox (special, not in tree)
+ box *Box // selected (current) box
+ nextBox *Box // next box to select (do we need this?)
+}
+
+func NewClient(mode Mode, server, user, passwd string, root string) (*Client, error) {
+ c := &Client{
+ server: server,
+ user: user,
+ passwd: passwd,
+ mode: mode,
+ root: root,
+ boxByName: map[string]*Box{},
+ }
+ c.io.lock()
+ if err := c.reconnect(); err != nil {
+ return nil, err
+ }
+ c.autoReconnect = true
+ c.io.unlock()
+
+ return c, nil
+}
+
+func (c *Client) Close() error {
+ c.io.lock()
+ c.autoReconnect = false
+ c.connected = false
+ if c.rw != nil {
+ c.rw.Close()
+ c.rw = nil
+ }
+ c.io.unlock()
+ return nil
+}
+
+func (c *Client) reconnect() error {
+ c.io.mustBeLocked()
+ c.autoReconnect = false
+ if c.rw != nil {
+ c.rw.Close()
+ c.rw = nil
+ }
+
+ if Debug {
+ log.Printf("dial %s...", c.server)
+ }
+ rw, err := dial(c.server, c.mode)
+ if err != nil {
+ return err
+ }
+
+ c.rw = rw
+ c.connected = true
+ c.capability = nil
+ c.box = nil
+ if Debug {
+ c.b = bufio.NewReader(&tee{rw, os.Stderr})
+ } else {
+ c.b = bufio.NewReader(rw)
+ }
+ x, err := c.rdsx()
+ if x == nil {
+ err = fmt.Errorf("no greeting from %s: %v", c.server, err)
+ goto Error
+ }
+ if len(x.sx) < 2 || !x.sx[0].isAtom("*") || !x.sx[1].isAtom("PREAUTH") {
+ if !x.ok() {
+ err = fmt.Errorf("bad greeting - %s", x)
+ goto Error
+ }
+ if err = c.login(); err != nil {
+ goto Error
+ }
+ }
+ if c.capability == nil {
+ if err = c.cmd(nil, "CAPABILITY"); err != nil {
+ goto Error
+ }
+ if c.capability == nil {
+ err = fmt.Errorf("CAPABILITY command did not return capability list")
+ goto Error
+ }
+ }
+ if err := c.getBoxes(); err != nil {
+ goto Error
+ }
+ c.autoReconnect = true
+ return nil
+
+Error:
+ if c.rw != nil {
+ c.rw.Close()
+ c.rw = nil
+ }
+ c.autoReconnect = true
+ c.connected = false
+ return err
+}
+
+var testDial func(string, Mode) (io.ReadWriteCloser, error)
+
+func dial(server string, mode Mode) (io.ReadWriteCloser, error) {
+ if testDial != nil {
+ return testDial(server, mode)
+ }
+ switch mode {
+ default:
+ // also case Unencrypted
+ return net.Dial("tcp", server+":143")
+ case StartTLS:
+ return nil, fmt.Errorf("StartTLS not supported")
+ case TLS:
+ return tls.Dial("tcp", server+":993", nil)
+ case Command:
+ cmd := exec.Command("sh", "-c", server)
+ cmd.Stderr = os.Stderr
+ r, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, err
+ }
+ w, err := cmd.StdinPipe()
+ if err != nil {
+ r.Close()
+ return nil, err
+ }
+ if err := cmd.Start(); err != nil {
+ r.Close()
+ w.Close()
+ return nil, err
+ }
+ return &pipe2{r, w}, nil
+ }
+ panic("not reached")
+}
+
+type pipe2 struct {
+ io.ReadCloser
+ io.WriteCloser
+}
+
+func (p *pipe2) Close() error {
+ p.ReadCloser.Close()
+ p.WriteCloser.Close()
+ return nil
+}
+
+type tee struct {
+ r io.Reader
+ w io.Writer
+}
+
+func (t tee) Read(p []byte) (n int, err error) {
+ n, err = t.r.Read(p)
+ if n > 0 {
+ t.w.Write(p[0:n])
+ }
+ return
+}
+
+func (c *Client) rdsx() (*sx, error) {
+ c.io.mustBeLocked()
+ return rdsx(c.b)
+}
+
+type sxError struct {
+ x *sx
+}
+
+func (e *sxError) Error() string { return e.x.String() }
+
+func (c *Client) cmd(b *Box, format string, args ...interface{}) error {
+ x, err := c.cmdsx(b, format, args...)
+ if err != nil {
+ return err
+ }
+ if !x.ok() {
+ return &sxError{x}
+ }
+ return nil
+}
+
+// cmdsx0 runs a single command and return the sx. Does not redial.
+func (c *Client) cmdsx0(format string, args ...interface{}) (*sx, error) {
+ c.io.mustBeLocked()
+ if c.rw == nil || !c.connected {
+ return nil, fmt.Errorf("not connected")
+ }
+
+ cmd := fmt.Sprintf(format, args...)
+ if Debug {
+ fmt.Fprintf(os.Stderr, ">>> %s %s\n", tag, cmd)
+ }
+ if _, err := fmt.Fprintf(c.rw, "%s %s\r\n", tag, cmd); err != nil {
+ c.connected = false
+ return nil, err
+ }
+ return c.waitsx()
+}
+
+// cmdsx runs a command on box b. It does redial.
+func (c *Client) cmdsx(b *Box, format string, args ...interface{}) (*sx, error) {
+ c.io.mustBeLocked()
+ c.nextBox = b
+
+Trying:
+ for tries := 0; ; tries++ {
+ if c.rw == nil || !c.connected {
+ if !c.autoReconnect {
+ return nil, fmt.Errorf("not connected")
+ }
+ if err := c.reconnect(); err != nil {
+ return nil, err
+ }
+ if b != nil && c.nextBox == nil {
+ // box disappeared on reconnect
+ return nil, fmt.Errorf("box is gone")
+ }
+ }
+
+ if b != nil && b != c.box {
+ if c.box != nil {
+ // TODO c.box.init = false
+ }
+ c.box = b
+ if _, err := c.cmdsx0("SELECT %s", iquote(b.Name)); err != nil {
+ c.box = nil
+ if tries++; tries == 1 && (c.rw == nil || !c.connected) {
+ continue Trying
+ }
+ return nil, err
+ }
+ }
+
+ x, err := c.cmdsx0(format, args...)
+ if err != nil {
+ if tries++; tries == 1 && (c.rw == nil || !c.connected) {
+ continue Trying
+ }
+ return nil, err
+ }
+ return x, nil
+ }
+ panic("not reached")
+}
+
+func (c *Client) waitsx() (*sx, error) {
+ c.io.mustBeLocked()
+ for {
+ x, err := c.rdsx()
+ if err != nil {
+ c.connected = false
+ return nil, err
+ }
+ if len(x.sx) >= 1 && x.sx[0].kind == sxAtom {
+ if x.sx[0].isAtom(tag) {
+ return x, nil
+ }
+ if x.sx[0].isAtom("*") {
+ c.unexpected(x)
+ }
+ }
+ if x.kind == sxList && len(x.sx) == 0 {
+ c.connected = false
+ return nil, fmt.Errorf("empty response")
+ }
+ }
+ panic("not reached")
+}
+
+func iquote(s string) string {
+ if s == "" {
+ return `""`
+ }
+
+ for i := 0; i < len(s); i++ {
+ if s[i] >= 0x80 || s[i] <= ' ' || s[i] == '\\' || s[i] == '"' {
+ goto Quote
+ }
+ }
+ return s
+
+Quote:
+ var b bytes.Buffer
+ b.WriteByte('"')
+ for i := 0; i < len(s); i++ {
+ if s[i] == '\\' || s[i] == '"' {
+ b.WriteByte('\\')
+ }
+ b.WriteByte(s[i])
+ }
+ b.WriteByte('"')
+ return b.String()
+}
+
+func (c *Client) login() error {
+ c.io.mustBeLocked()
+ x, err := c.cmdsx(nil, "LOGIN %s %s", iquote(c.user), iquote(c.passwd))
+ if err != nil {
+ return err
+ }
+ if !x.ok() {
+ return fmt.Errorf("login rejected: %s", x)
+ }
+ return nil
+}
+
+func (c *Client) getBoxes() error {
+ c.io.mustBeLocked()
+ for _, b := range c.allBox {
+ b.dead = true
+ // b.exists = 0
+ // b.maxSeen = 0
+ }
+ list := "LIST"
+ if c.capability["XLIST"] { // Gmail extension
+ list = "XLIST"
+ }
+ if err := c.cmd(nil, "%s %s *", list, iquote(c.root)); err != nil {
+ return err
+ }
+ if err := c.cmd(nil, "%s %s INBOX", list, iquote(c.root)); err != nil {
+ return err
+ }
+ if c.nextBox != nil && c.nextBox.dead {
+ c.nextBox = nil
+ }
+ for _, b := range c.allBox {
+ if b.dead {
+ delete(c.boxByName, b.Name)
+ }
+ b.firstNum = 0
+ }
+ c.allBox = boxTrim(c.allBox)
+ for _, b := range c.allBox {
+ b.child = boxTrim(b.child)
+ }
+ return nil
+}
+
+func boxTrim(list []*Box) []*Box {
+ w := 0
+ for _, b := range list {
+ if !b.dead {
+ list[w] = b
+ w++
+ }
+ }
+ return list[:w]
+}
+
+const maxFetch = 1000
+
+func (c *Client) setAutoReconnect(b bool) {
+ c.autoReconnect = b
+}
+
+func (c *Client) check(b *Box) error {
+ c.io.mustBeLocked()
+ if b.dead {
+ return fmt.Errorf("box is gone")
+ }
+
+ b.load = true
+
+ // Update exists count.
+ if err := c.cmd(b, "NOOP"); err != nil {
+ return err
+ }
+
+ // Have to get through this in one session.
+ // Caller can call again if we get disconnected
+ // and return an error.
+ c.autoReconnect = false
+ defer c.setAutoReconnect(true)
+
+ // First load after reconnect: figure out what changed.
+ if b.firstNum == 0 && len(b.msgByUID) > 0 {
+ var lo, hi uint32 = 1<<32 - 1, 0
+ for _, m := range b.msgByUID {
+ m.dead = true
+ uid := uint32(m.UID)
+ if lo > uid {
+ lo = uid
+ }
+ if hi < uid {
+ hi = uid
+ }
+ m.num = 0
+ }
+ if err := c.cmd(b, "UID FETCH %d:%d FLAGS", lo, hi); err != nil {
+ return err
+ }
+ for _, m := range b.msgByUID {
+ if m.dead {
+ delete(b.msgByUID, m.UID)
+ }
+ }
+ }
+
+ // First-ever load.
+ if b.firstNum == 0 {
+ if b.exists <= maxFetch {
+ b.firstNum = 1
+ } else {
+ b.firstNum = b.exists - maxFetch + 1
+ }
+ n := b.exists - b.firstNum + 1
+ b.msgByNum = make([]*Msg, n)
+ return c.fetchBox(b, b.firstNum, 0)
+ }
+
+ if b.exists <= b.maxSeen {
+ return nil
+ }
+ return c.fetchBox(b, b.maxSeen, 0)
+}
+
+func (c *Client) fetchBox(b *Box, lo int, hi int) error {
+ c.io.mustBeLocked()
+ if b != c.box {
+ if err := c.cmd(b, "NOOP"); err != nil {
+ return err
+ }
+ }
+ extra := ""
+ if c.IsGmail() {
+ extra = " X-GM-MSGID X-GM-THRID X-GM-LABELS"
+ }
+ slo := fmt.Sprint(lo)
+ shi := "*"
+ if hi > 0 {
+ shi = fmt.Sprint(hi)
+ }
+ return c.cmd(b, "FETCH %s:%s (FLAGS UID INTERNALDATE RFC822.SIZE ENVELOPE BODY%s)", slo, shi, extra)
+}
+
+func (c *Client) IsGmail() bool {
+ return c.capability["X-GM-EXT-1"]
+}
+
+// Table-driven IMAP "unexpected response" parser.
+// All the interesting data is in the unexpected responses.
+
+var unextab = []struct {
+ num int
+ name string
+ fmt string
+ fn func(*Client, *sx)
+}{
+ {0, "BYE", "", xbye},
+ {0, "CAPABILITY", "", xcapability},
+ {0, "FLAGS", "AAL", xflags},
+ {0, "LIST", "AALSS", xlist},
+ {0, "XLIST", "AALSS", xlist},
+ {0, "OK", "", xok},
+ // {0, "SEARCH", "AAN*", xsearch},
+ {1, "EXISTS", "ANA", xexists},
+ {1, "EXPUNGE", "ANA", xexpunge},
+ {1, "FETCH", "ANAL", xfetch},
+ // {1, "RECENT", "ANA", xrecent}, // why do we care?
+}
+
+func (c *Client) unexpected(x *sx) {
+ c.io.mustBeLocked()
+ var num int
+ var name string
+
+ if len(x.sx) >= 3 && x.sx[1].kind == sxNumber && x.sx[2].kind == sxAtom {
+ num = 1
+ name = string(x.sx[2].data)
+ } else if len(x.sx) >= 2 && x.sx[1].kind == sxAtom {
+ num = 0
+ name = string(x.sx[1].data)
+ } else {
+ return
+ }
+
+ c.data.lock()
+ for _, t := range unextab {
+ if t.num == num && strings.EqualFold(t.name, name) {
+ if t.fmt != "" && !x.match(t.fmt) {
+ log.Printf("malformd %s: %s", name, x)
+ continue
+ }
+ t.fn(c, x)
+ }
+ }
+ c.data.unlock()
+}
+
+func xbye(c *Client, x *sx) {
+ c.io.mustBeLocked()
+ c.rw.Close()
+ c.rw = nil
+ c.connected = false
+}
+
+func xflags(c *Client, x *sx) {
+ c.data.mustBeLocked()
+ // This response contains in x.sx[2] the list of flags
+ // that can be validly attached to messages in c.box.
+ if b := c.box; b != nil {
+ c.flags = x.sx[2].parseFlags()
+ }
+}
+
+func xcapability(c *Client, x *sx) {
+ c.data.mustBeLocked()
+ c.capability = make(map[string]bool)
+ for _, xx := range x.sx[2:] {
+ if xx.kind == sxAtom {
+ c.capability[string(xx.data)] = true
+ }
+ }
+}
+
+func xlist(c *Client, x *sx) {
+ c.data.mustBeLocked()
+ s := string(x.sx[4].data)
+ t := string(x.sx[3].data)
+
+ // INBOX is the special name for the main mailbox.
+ // All the other mailbox names have the root prefix removed, if applicable.
+ inbox := strings.EqualFold(s, "inbox")
+ if inbox {
+ s = "inbox"
+ }
+
+ b := c.newBox(s, t, inbox)
+ if b == nil {
+ return
+ }
+ if inbox {
+ c.inbox = b
+ }
+ if s == c.root {
+ c.rootBox = b
+ }
+ b.dead = false
+ b.flags = x.sx[2].parseFlags()
+}
+
+func xexists(c *Client, x *sx) {
+ c.data.mustBeLocked()
+ if b := c.box; b != nil {
+ b.exists = int(x.sx[1].number)
+ if b.exists < b.maxSeen {
+ b.maxSeen = b.exists
+ }
+ }
+}
+
+func xexpunge(c *Client, x *sx) {
+ c.data.mustBeLocked()
+ if b := c.box; b != nil {
+ n := int(x.sx[1].number)
+ bynum := b.msgByNum
+ if bynum != nil {
+ if n < b.firstNum {
+ b.firstNum--
+ } else if n < b.firstNum+len(bynum) {
+ copy(bynum[n-b.firstNum:], bynum[n-b.firstNum+1:])
+ b.msgByNum = bynum[:len(bynum)-1]
+ } else {
+ log.Printf("expunge unexpected message %d %d %d", b.firstNum, b.exists, b.firstNum+len(bynum))
+ }
+ }
+ if n <= b.exists {
+ b.exists--
+ }
+ }
+}
+
+// Table-driven OK info parser.
+
+var oktab = []struct {
+ name string
+ kind sxKind
+ fn func(*Client, *Box, *sx)
+}{
+ {"UIDVALIDITY", sxNumber, xokuidvalidity},
+ {"PERMANENTFLAGS", sxList, xokpermflags},
+ {"UNSEEN", sxNumber, xokunseen},
+ {"READ-WRITE", 0, xokreadwrite},
+ {"READ-ONLY", 0, xokreadonly},
+}
+
+func xok(c *Client, x *sx) {
+ c.data.mustBeLocked()
+ b := c.box
+ if b == nil {
+ return
+ }
+ if len(x.sx) >= 4 && x.sx[2].kind == sxAtom && x.sx[2].data[0] == '[' {
+ var arg *sx
+ if x.sx[3].kind == sxAtom && x.sx[3].data[0] == ']' {
+ arg = nil
+ } else if x.sx[4].kind == sxAtom && x.sx[4].data[0] == ']' {
+ arg = x.sx[3]
+ } else {
+ log.Printf("cannot parse OK: %s", x)
+ return
+ }
+ x.sx[2].data = x.sx[2].data[1:]
+ for _, t := range oktab {
+ if x.sx[2].isAtom(t.name) {
+ if t.kind != 0 && (arg == nil || arg.kind != t.kind) {
+ log.Printf("malformed %s: %s", t.name, arg)
+ continue
+ }
+ t.fn(c, b, arg)
+ }
+ }
+ }
+}
+
+func xokuidvalidity(c *Client, b *Box, x *sx) {
+ c.data.mustBeLocked()
+ n := uint32(x.number)
+ if b.validity != n {
+ if b.msgByUID != nil {
+ log.Printf("imap: UID validity reset for %s", b.Name)
+ }
+ b.validity = n
+ b.maxSeen = 0
+ b.firstNum = 0
+ b.msgByNum = nil
+ b.msgByUID = nil
+ }
+}
+
+func xokpermflags(c *Client, b *Box, x *sx) {
+ c.data.mustBeLocked()
+ b.permFlags = x.parseFlags()
+}
+
+func xokunseen(c *Client, b *Box, x *sx) {
+ c.data.mustBeLocked()
+ b.unseen = int(x.number)
+}
+
+func xokreadwrite(c *Client, b *Box, x *sx) {
+ c.data.mustBeLocked()
+ b.readOnly = false
+}
+
+func xokreadonly(c *Client, b *Box, x *sx) {
+ c.data.mustBeLocked()
+ b.readOnly = true
+}
+
+// Table-driven FETCH message info parser.
+
+var msgtab = []struct {
+ name string
+ fn func(*Msg, *sx, *sx)
+}{
+ {"FLAGS", xmsgflags},
+ {"INTERNALDATE", xmsgdate},
+ {"RFC822.SIZE", xmsgrfc822size},
+ {"ENVELOPE", xmsgenvelope},
+ {"X-GM-MSGID", xmsggmmsgid},
+ {"X-GM-THRID", xmsggmthrid},
+ {"BODY", xmsgbody},
+ {"BODY[", xmsgbodydata},
+}
+
+func xfetch(c *Client, x *sx) {
+ c.data.mustBeLocked()
+ if c.box == nil {
+ log.Printf("FETCH but no open box: %s", x)
+ return
+ }
+
+ // * 152 FETCH (UID 185 FLAGS() ...)
+ n := x.sx[1].number
+ xx := x.sx[3]
+ if len(xx.sx)%2 != 0 {
+ log.Printf("malformed FETCH: %s", x)
+ return
+ }
+ var uid uint64
+ for i := 0; i < len(xx.sx); i += 2 {
+ if xx.sx[i].isAtom("UID") {
+ if xx.sx[i+1].kind == sxNumber {
+ uid = uint64(xx.sx[i+1].number) | uint64(c.box.validity)<<32
+ goto HaveUID
+ }
+ }
+ }
+ // This happens; too bad.
+ // log.Printf("FETCH without UID: %s", x)
+ return
+
+HaveUID:
+ if m := c.box.msgByUID[uid]; m != nil && m.dead {
+ // FETCH during box garbage collection.
+ m.dead = false
+ m.num = int(n)
+ return
+ }
+ m := c.box.newMsg(uid, int(n))
+ for i := 0; i < len(xx.sx); i += 2 {
+ k, v := xx.sx[i], xx.sx[i+1]
+ for _, t := range msgtab {
+ if k.isAtom(t.name) {
+ t.fn(m, k, v)
+ }
+ }
+ }
+}
+
+func xmsggmmsgid(m *Msg, k, v *sx) {
+ m.GmailID = uint64(v.number)
+}
+
+func xmsggmthrid(m *Msg, k, v *sx) {
+ m.GmailThread = uint64(v.number)
+}
+
+func xmsgflags(m *Msg, k, v *sx) {
+ m.Flags = v.parseFlags()
+}
+
+func xmsgrfc822size(m *Msg, k, v *sx) {
+ m.Bytes = v.number
+}
+
+func xmsgdate(m *Msg, k, v *sx) {
+ m.Date = v.parseDate()
+}
+
+func xmsgenvelope(m *Msg, k, v *sx) {
+ m.Hdr = parseEnvelope(v)
+}
+
+func parseEnvelope(v *sx) *MsgHdr {
+ if v.kind != sxList || !v.match("SSLLLLLLSS") {
+ log.Printf("bad envelope: %s", v)
+ return nil
+ }
+
+ hdr := &MsgHdr{
+ Date: v.sx[0].nstring(),
+ Subject: unrfc2047(v.sx[1].nstring()),
+ From: parseAddrs(v.sx[2]),
+ Sender: parseAddrs(v.sx[3]),
+ ReplyTo: parseAddrs(v.sx[4]),
+ To: parseAddrs(v.sx[5]),
+ CC: parseAddrs(v.sx[6]),
+ BCC: parseAddrs(v.sx[7]),
+ InReplyTo: unrfc2047(v.sx[8].nstring()),
+ MessageID: unrfc2047(v.sx[9].nstring()),
+ }
+
+ h := md5.New()
+ fmt.Fprintf(h, "date: %s\n", hdr.Date)
+ fmt.Fprintf(h, "subject: %s\n", hdr.Subject)
+ fmt.Fprintf(h, "from: %s\n", hdr.From)
+ fmt.Fprintf(h, "sender: %s\n", hdr.Sender)
+ fmt.Fprintf(h, "replyto: %s\n", hdr.ReplyTo)
+ fmt.Fprintf(h, "to: %s\n", hdr.To)
+ fmt.Fprintf(h, "cc: %s\n", hdr.CC)
+ fmt.Fprintf(h, "bcc: %s\n", hdr.BCC)
+ fmt.Fprintf(h, "inreplyto: %s\n", hdr.InReplyTo)
+ fmt.Fprintf(h, "messageid: %s\n", hdr.MessageID)
+ hdr.Digest = fmt.Sprintf("%x", h.Sum(nil))
+
+ return hdr
+}
+
+func parseAddrs(x *sx) []Addr {
+ var addr []Addr
+ for _, xx := range x.sx {
+ if !xx.match("SSSS") {
+ log.Printf("bad address: %s", x)
+ continue
+ }
+ name := unrfc2047(xx.sx[0].nstring())
+ // sx[1] is route
+ local := unrfc2047(xx.sx[2].nstring())
+ host := unrfc2047(xx.sx[3].nstring())
+ if local == "" || host == "" {
+ // rfc822 group syntax
+ addr = append(addr, Addr{name, ""})
+ continue
+ }
+ addr = append(addr, Addr{name, local + "@" + host})
+ }
+ return addr
+}
+
+func xmsgbody(m *Msg, k, v *sx) {
+ if v.isNil() {
+ return
+ }
+ if v.kind != sxList {
+ log.Printf("bad body: %s", v)
+ }
+
+ // To follow the structure exactly we should be doing this
+ // to m.NewPart(m.Part[0]) with type message/rfc822,
+ // but the extra layer is redundant - what else would be in
+ // a mailbox?
+ parseStructure(&m.Root, v)
+ n := m.num
+ if m.Box.maxSeen < n {
+ m.Box.maxSeen = n
+ }
+}
+
+func parseStructure(p *MsgPart, x *sx) {
+ if x.isNil() {
+ return
+ }
+ if x.kind != sxList {
+ log.Printf("bad structure: %s", x)
+ return
+ }
+ if x.sx[0].isList() {
+ // multipart
+ var i int
+ for i = 0; i < len(x.sx) && x.sx[i].isList(); i++ {
+ parseStructure(p.newPart(), x.sx[i])
+ }
+ if i != len(x.sx)-1 || !x.sx[i].isString() {
+ log.Printf("bad multipart structure: %s", x)
+ p.Type = "multipart/mixed"
+ return
+ }
+ s := strlwr(x.sx[i].nstring())
+ p.Type = "multipart/" + s
+ return
+ }
+
+ // single type
+ if len(x.sx) < 2 || !x.sx[0].isString() {
+ log.Printf("bad type structure: %s", x)
+ return
+ }
+ s := strlwr(x.sx[0].nstring())
+ t := strlwr(x.sx[1].nstring())
+ p.Type = s + "/" + t
+ if len(x.sx) < 7 || !x.sx[2].isList() || !x.sx[3].isString() || !x.sx[4].isString() || !x.sx[5].isString() || !x.sx[6].isNumber() {
+ log.Printf("bad part structure: %s", x)
+ return
+ }
+ parseParams(p, x.sx[2])
+ p.ContentID = x.sx[3].nstring()
+ p.Desc = x.sx[4].nstring()
+ p.Encoding = x.sx[5].nstring()
+ p.Bytes = x.sx[6].number
+ if p.Type == "message/rfc822" {
+ if len(x.sx) < 10 || !x.sx[7].isList() || !x.sx[8].isList() || !x.sx[9].isNumber() {
+ log.Printf("bad rfc822 structure: %s", x)
+ return
+ }
+ p.Hdr = parseEnvelope(x.sx[7])
+ parseStructure(p.newPart(), x.sx[8])
+ p.Lines = x.sx[9].number
+ }
+ if s == "text" {
+ if len(x.sx) < 8 || !x.sx[7].isNumber() {
+ log.Printf("bad text structure: %s", x)
+ return
+ }
+ p.Lines = x.sx[7].number
+ }
+}
+
+func parseParams(p *MsgPart, x *sx) {
+ if x.isNil() {
+ return
+ }
+ if len(x.sx)%2 != 0 {
+ log.Printf("bad message params: %s", x)
+ return
+ }
+
+ for i := 0; i < len(x.sx); i += 2 {
+ k, v := x.sx[i].nstring(), x.sx[i+1].nstring()
+ k = strlwr(k)
+ switch strlwr(k) {
+ case "charset":
+ p.Charset = strlwr(v)
+ case "name":
+ p.Name = v
+ }
+ }
+}
+
+func (c *Client) fetch(p *MsgPart, what string) {
+ c.io.mustBeLocked()
+ id := p.ID
+ if what != "" {
+ if id != "" {
+ id += "."
+ }
+ id += what
+ }
+ c.cmd(p.Msg.Box, "UID FETCH %d BODY[%s]", p.Msg.UID&(1<<32-1), id)
+}
+
+func xmsgbodydata(m *Msg, k, v *sx) {
+ // k.data is []byte("BODY[...")
+ name := string(k.data[5:])
+ if i := strings.Index(name, "]"); i >= 0 {
+ name = name[:i]
+ }
+
+ p := &m.Root
+ for name != "" && '1' <= name[0] && name[0] <= '9' {
+ var num int
+ num, name = parseNum(name)
+ if num == 0 {
+ log.Printf("unexpected body name: %s", k.data)
+ return
+ }
+ num--
+ if num >= len(p.Child) {
+ log.Printf("invalid body name: %s", k.data)
+ return
+ }
+ p = p.Child[num]
+ }
+
+ switch strlwr(name) {
+ case "":
+ p.raw = v.nbytes()
+ case "mime":
+ p.mimeHeader = nocr(v.nbytes())
+ case "header":
+ p.rawHeader = nocr(v.nbytes())
+ case "text":
+ p.rawBody = nocr(v.nbytes())
+ }
+}
+
+func parseNum(name string) (int, string) {
+ rest := ""
+ i := strings.Index(name, ".")
+ if i >= 0 {
+ name, rest = name[:i], name[i+1:]
+ }
+ n, _ := strconv.Atoi(name)
+ return n, rest
+}
+
+func nocr(b []byte) []byte {
+ w := 0
+ for _, c := range b {
+ if c != '\r' {
+ b[w] = c
+ w++
+ }
+ }
+ return b[:w]
+}
+
+type uidList []*Msg
+
+func (l uidList) String() string {
+ var b bytes.Buffer
+ for i, m := range l {
+ if i > 0 {
+ b.WriteByte(',')
+ }
+ fmt.Fprintf(&b, "%d", m.UID&(1<<32-1))
+ }
+ return b.String()
+}
+
+func (c *Client) deleteList(msgs []*Msg) error {
+ if len(msgs) == 0 {
+ return nil
+ }
+ c.io.mustBeLocked()
+
+ b := msgs[0].Box
+ for _, m := range msgs {
+ if m.Box != b {
+ return fmt.Errorf("messages span boxes: %q and %q", b.Name, m.Box.Name)
+ }
+ if uint32(m.UID>>32) != b.validity {
+ return fmt.Errorf("stale message")
+ }
+ }
+
+ err := c.cmd(b, "UID STORE %s +FLAGS (\\Deleted)", uidList(msgs))
+ if err == nil && c.box == b {
+ err = c.cmd(b, "EXPUNGE")
+ }
+ return err
+}
+
+func (c *Client) copyList(dst, src *Box, msgs []*Msg) error {
+ if len(msgs) == 0 {
+ return nil
+ }
+ c.io.mustBeLocked()
+
+ for _, m := range msgs {
+ if m.Box != src {
+ return fmt.Errorf("messages span boxes: %q and %q", src.Name, m.Box.Name)
+ }
+ if uint32(m.UID>>32) != src.validity {
+ return fmt.Errorf("stale message")
+ }
+ }
+
+ var name string
+ if dst == c.inbox {
+ name = "INBOX"
+ } else {
+ name = iquote(dst.Name)
+ }
+ return c.cmd(src, "UID COPY %s %s", uidList(msgs), name)
+}
+
+func (c *Client) muteList(src *Box, msgs []*Msg) error {
+ if len(msgs) == 0 {
+ return nil
+ }
+ c.io.mustBeLocked()
+
+ for _, m := range msgs {
+ if m.Box != src {
+ return fmt.Errorf("messages span boxes: %q and %q", src.Name, m.Box.Name)
+ }
+ if uint32(m.UID>>32) != src.validity {
+ return fmt.Errorf("stale message")
+ }
+ }
+
+ return c.cmd(src, "UID STORE %s +X-GM-LABELS (\\Muted)", uidList(msgs))
+}
diff --git a/vendor/github.com/mattermost/rsc/imap/imap_test.go b/vendor/github.com/mattermost/rsc/imap/imap_test.go
new file mode 100644
index 000000000..75737fcc8
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/imap_test.go
@@ -0,0 +1,433 @@
+package imap
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/mattermost/rsc/google"
+)
+
+// NOTE: web address is https://mail.google.com/mail/b/rsc@swtch.com/?shva=1#inbox/132e5fd3a6a3c17b
+// where the last is the hex for the thread id.
+// have to have the #inbox part right too. #label/Hello+World/...
+// or #all as a fallback
+
+// TODO: ID command support (RFC 2971)
+
+const mock = true
+
+var user = "rsc@swtch.com"
+var pw, _ = ioutil.ReadFile("/Users/rsc/.swtchpass")
+
+func TestImap(t *testing.T) {
+ var user, pw string
+ if mock {
+ testDial = fakeDial
+ user = "gre@host.com"
+ pw = "password"
+ } else {
+ acct := google.Acct("rsc@swtch.com")
+ user = acct.Email
+ pw = acct.Password
+ }
+ c, err := NewClient(TLS, "imap.gmail.com", user, pw, "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ inbox := c.Inbox()
+ msgs := inbox.Msgs()
+
+ for _, m := range msgs {
+ if m.UID == 611764547<<32|57046 {
+ // c.io.lock()
+ // c.cmd(c.boxByName[`[Gmail]/All Mail`], `UID SEARCH X-GM-RAW "label:russcox@gmail.com in:inbox in:unread -in:muted"`)
+ // c.cmd(c.inbox, `UID SEARCH X-GM-RAW "label:russcox@gmail.com in:inbox in:unread -in:muted"`)
+ // c.cmd(c.boxByName[`To Read`], `UID SEARCH X-GM-RAW "label:russcox@gmail.com in:inbox in:unread -in:muted"`)
+ // c.cmd(c.boxByName[`[Gmail]/All Mail`], `UID SEARCH X-GM-RAW "label:russcox@gmail.com in:inbox in:unread -in:muted"`)
+ // c.fetch(m.Root.Child[0], "")
+ // c.io.unlock()
+ fmt.Println("--")
+ fmt.Println("From:", m.Hdr.From)
+ fmt.Println("To:", m.Hdr.To)
+ fmt.Println("Subject:", m.Hdr.Subject)
+ fmt.Println("M-Date:", time.Unix(m.Date, 0))
+ fmt.Println("Date:", m.Hdr.Date)
+ fmt.Println()
+ fmt.Println(string(m.Root.Child[0].Text()))
+ fmt.Println("--")
+ }
+ }
+ c.Close()
+}
+
+func fakeDial(server string, mode Mode) (io.ReadWriteCloser, error) {
+ r1, w1 := io.Pipe()
+ r2, w2 := io.Pipe()
+ go fakeServer(&pipe2{r1, w2})
+ return &pipe2{r2, w1}, nil
+}
+
+func fakeServer(rw io.ReadWriteCloser) {
+ b := bufio.NewReader(rw)
+ rw.Write([]byte(fakeReply[""]))
+ for {
+ line, err := b.ReadString('\n')
+ if err != nil {
+ break
+ }
+ reply := fakeReply[strings.TrimSpace(line)]
+ if reply == "" {
+ rw.Write([]byte("* BYE\r\n"))
+ break
+ }
+ rw.Write([]byte(reply))
+ }
+ rw.Close()
+}
+
+var fakeReply = map[string]string{
+ ``: "* OK Gimap ready for requests from 71.232.17.63 k7if4537693qcx.66\r\n",
+ `# LOGIN gre@host.com password`: "* CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE\r\n" +
+ "# OK gre@host.com Grace Emlin authenticated (Success)\r\n",
+ `# XLIST "" INBOX`: `* XLIST (\HasNoChildren \Inbox) "/" "Inbox"` + "\r\n" +
+ "# OK Success\r\n",
+ `# XLIST "" *`: `* XLIST (\HasNoChildren \Inbox) "/" "Inbox"` + "\r\n" +
+ `* XLIST (\HasNoChildren) "/" "Someday"` + "\r\n" +
+ `* XLIST (\HasNoChildren) "/" "To Read"` + "\r\n" +
+ `* XLIST (\HasNoChildren) "/" "Waiting"` + "\r\n" +
+ `* XLIST (\Noselect \HasChildren) "/" "[Gmail]"` + "\r\n" +
+ `* XLIST (\HasNoChildren \AllMail) "/" "[Gmail]/All Mail"` + "\r\n" +
+ `* XLIST (\HasNoChildren \Drafts) "/" "[Gmail]/Drafts"` + "\r\n" +
+ `* XLIST (\HasNoChildren \Important) "/" "[Gmail]/Important"` + "\r\n" +
+ `* XLIST (\HasNoChildren \Sent) "/" "[Gmail]/Sent Mail"` + "\r\n" +
+ `* XLIST (\HasNoChildren \Spam) "/" "[Gmail]/Spam"` + "\r\n" +
+ `* XLIST (\HasNoChildren \Starred) "/" "[Gmail]/Starred"` + "\r\n" +
+ `* XLIST (\HasNoChildren \Trash) "/" "[Gmail]/Trash"` + "\r\n" +
+ `* XLIST (\HasNoChildren) "/" "russcox@gmail.com"` + "\r\n" +
+ "# OK Success\r\n",
+ `# LIST "" INBOX`: `* LIST (\HasNoChildren) "/" "INBOX"` + "\r\n" +
+ "# OK Success\r\n",
+ `# LIST "" *`: `* LIST (\HasNoChildren) "/" "INBOX"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "Someday"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "To Read"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "Waiting"` + "\r\n" +
+ `* LIST (\Noselect \HasChildren) "/" "[Gmail]"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "[Gmail]/All Mail"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "[Gmail]/Drafts"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "[Gmail]/Important"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "[Gmail]/Sent Mail"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "[Gmail]/Spam"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "[Gmail]/Starred"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "[Gmail]/Trash"` + "\r\n" +
+ `* LIST (\HasNoChildren) "/" "russcox@gmail.com"` + "\r\n" +
+ "# OK Success\r\n",
+ `# SELECT inbox`: `* FLAGS (\Answered \Flagged \Draft \Deleted \Seen)` + "\r\n" +
+ `* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen \*)] Flags permitted.` + "\r\n" +
+ `* OK [UIDVALIDITY 611764547] UIDs valid.` + "\r\n" +
+ `* 9 EXISTS` + "\r\n" +
+ `* 0 RECENT` + "\r\n" +
+ `* OK [UIDNEXT 57027] Predicted next UID.` + "\r\n" +
+ "# OK [READ-WRITE] inbox selected. (Success)\r\n",
+ `# UID FETCH 1:* (FLAGS)`: `* 1 FETCH (UID 46074 FLAGS (\Seen))` + "\r\n" +
+ `* 2 FETCH (UID 49094 FLAGS (\Seen))` + "\r\n" +
+ `* 3 FETCH (UID 49317 FLAGS (\Seen))` + "\r\n" +
+ `* 4 FETCH (UID 49424 FLAGS (\Flagged \Seen))` + "\r\n" +
+ `* 5 FETCH (UID 49595 FLAGS (\Seen))` + "\r\n" +
+ `* 6 FETCH (UID 49810 FLAGS (\Seen))` + "\r\n" +
+ `* 7 FETCH (UID 50579 FLAGS (\Seen))` + "\r\n" +
+ `* 8 FETCH (UID 50597 FLAGS (\Seen))` + "\r\n" +
+ `* 9 FETCH (UID 50598 FLAGS (\Seen))` + "\r\n" +
+ "# OK Success\r\n",
+ `# FETCH 1:* (UID FLAGS)`: `* 1 FETCH (UID 46074 FLAGS (\Seen))` + "\r\n" +
+ `* 2 FETCH (UID 49094 FLAGS (\Seen))` + "\r\n" +
+ `* 3 FETCH (UID 49317 FLAGS (\Seen))` + "\r\n" +
+ `* 4 FETCH (UID 49424 FLAGS (\Flagged \Seen))` + "\r\n" +
+ `* 5 FETCH (UID 49595 FLAGS (\Seen))` + "\r\n" +
+ `* 6 FETCH (UID 49810 FLAGS (\Seen))` + "\r\n" +
+ `* 7 FETCH (UID 50579 FLAGS (\Seen))` + "\r\n" +
+ `* 8 FETCH (UID 50597 FLAGS (\Seen))` + "\r\n" +
+ `* 9 FETCH (UID 50598 FLAGS (\Seen))` + "\r\n" +
+ "# OK Success\r\n",
+ `# NOOP`: "# OK Success\r\n",
+ `# UID FETCH 1:* (FLAGS X-GM-MSGID X-GM-THRID)`: `* 1 FETCH (X-GM-THRID 1371690017835349492 X-GM-MSGID 1371690017835349492 UID 46074 FLAGS (\Seen))` + "\r\n" +
+ `* 2 FETCH (X-GM-THRID 1370053443095117076 X-GM-MSGID 1374032778063810116 UID 49094 FLAGS (\Seen))` + "\r\n" +
+ `* 3 FETCH (X-GM-THRID 1370053443095117076 X-GM-MSGID 1374171123044094435 UID 49317 FLAGS (\Seen))` + "\r\n" +
+ `* 4 FETCH (X-GM-THRID 1374260005724669308 X-GM-MSGID 1374260005724669308 UID 49424 FLAGS (\Flagged \Seen))` + "\r\n" +
+ `* 5 FETCH (X-GM-THRID 1374399840419707240 X-GM-MSGID 1374399840419707240 UID 49595 FLAGS (\Seen))` + "\r\n" +
+ `* 6 FETCH (X-GM-THRID 1374564698687599195 X-GM-MSGID 1374564698687599195 UID 49810 FLAGS (\Seen))` + "\r\n" +
+ `* 7 FETCH (X-GM-THRID 1353701773219222407 X-GM-MSGID 1375207927094695931 UID 50579 FLAGS (\Seen))` + "\r\n" +
+ `* 8 FETCH (X-GM-THRID 1375017086705541883 X-GM-MSGID 1375220323861690146 UID 50597 FLAGS (\Seen))` + "\r\n" +
+ `* 9 FETCH (X-GM-THRID 1353701773219222407 X-GM-MSGID 1375220551142026521 UID 50598 FLAGS (\Seen))` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 1:* (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE X-GM-MSGID X-GM-THRID)`: `* 1 FETCH (X-GM-THRID 1371690017835349492 X-GM-MSGID 1371690017835349492 UID 46074 RFC822.SIZE 5700 INTERNALDATE "15-Jun-2011 13:45:39 +0000" FLAGS (\Seen) ENVELOPE ("Wed, 15 Jun 2011 13:45:35 +0000" "[re2-dev] Issue 40 in re2: Please make RE2::Rewrite public" ((NIL NIL "re2" "googlecode.com")) ((NIL NIL "re2-dev" "googlegroups.com")) ((NIL NIL "codesite-noreply" "google.com")) ((NIL NIL "re2-dev" "googlegroups.com")) NIL NIL NIL "<0-13244084390050003171-8842966241254494762-re2=googlecode.com@googlecode.com>"))` + "\r\n" +
+ `* 2 FETCH (X-GM-THRID 1370053443095117076 X-GM-MSGID 1374032778063810116 UID 49094 RFC822.SIZE 3558 INTERNALDATE "11-Jul-2011 10:22:49 +0000" FLAGS (\Seen) ENVELOPE ("Mon, 11 Jul 2011 12:22:46 +0200" "Re: [re2-dev] Re: Issue 39 in re2: Eiffel wrapper for RE2" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Russ Cox" NIL "rsc" "swtch.com")) NIL NIL "<CADSkJJWthFb61R1tqJxZP1SxTPuwY_BBW5ToLuzX2UpHSvsy9w@mail.gmail.com>" "<4E1ACEF6.4060609@gmail.com>"))` + "\r\n" +
+ `* 3 FETCH (X-GM-THRID 1370053443095117076 X-GM-MSGID 1374171123044094435 UID 49317 RFC822.SIZE 3323 INTERNALDATE "12-Jul-2011 23:01:46 +0000" FLAGS (\Seen) ENVELOPE ("Wed, 13 Jul 2011 01:01:41 +0200" "Re: [re2-dev] Re: Issue 39 in re2: Eiffel wrapper for RE2" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Russ Cox" NIL "rsc" "swtch.com")) NIL NIL "<CADSkJJV+E-0Xtm=dpiSHLbwkZjZ=zDDoE1t1w0CiGYa+pVz66g@mail.gmail.com>" "<4E1CD255.6060807@gmail.com>"))` + "\r\n" +
+ `* 4 FETCH (X-GM-THRID 1374260005724669308 X-GM-MSGID 1374260005724669308 UID 49424 RFC822.SIZE 2681 INTERNALDATE "13-Jul-2011 22:34:31 +0000" FLAGS (\Flagged \Seen) ENVELOPE ("Wed, 13 Jul 2011 16:33:43 -0600" "Minor correction for venti(8) user manual for running plan9port on Linux" (("Xing" NIL "xinglin" "cs.utah.edu")) (("Xing" NIL "xinglin" "cs.utah.edu")) (("Xing" NIL "xinglin" "cs.utah.edu")) ((NIL NIL "rsc" "swtch.com")) (("Xing Lin" NIL "xinglin" "cs.utah.edu") ("Raghuveer Pullakandam" NIL "rgv" "cs.utah.edu") ("Robert Ricci" NIL "ricci" "cs.utah.edu") ("Eric Eide" NIL "eeide" "cs.utah.edu")) NIL NIL "<1310596423.3866.11.camel@xing-utah-cs>"))` + "\r\n" +
+ `* 5 FETCH (X-GM-THRID 1374399840419707240 X-GM-MSGID 1374399840419707240 UID 49595 RFC822.SIZE 6496 INTERNALDATE "15-Jul-2011 11:37:07 +0000" FLAGS (\Seen) ENVELOPE ("Fri, 15 Jul 2011 13:36:54 +0200" "[re2-dev] MSVC not exporting VariadicFunction2<.. FullMatchN>::operator()(..) but VariadicFunction2<.. PartialMatchN>::operator()(..)" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) NIL NIL NIL "<4E202656.7010408@gmail.com>"))` + "\r\n" +
+ `* 6 FETCH (X-GM-THRID 1374564698687599195 X-GM-MSGID 1374564698687599195 UID 49810 RFC822.SIZE 5485 INTERNALDATE "17-Jul-2011 07:17:29 +0000" FLAGS (\Seen) ENVELOPE ("Sun, 17 Jul 2011 00:17:28 -0700" "Acme IRC client patch" (("Ethan Burns" NIL "burns.ethan" "gmail.com")) (("Ethan Burns" NIL "burns.ethan" "gmail.com")) (("Ethan Burns" NIL "burns.ethan" "gmail.com")) ((NIL NIL "rsc" "swtch.com")) NIL NIL NIL "<CAGE=Ei0bmAjsYYDxCgtDObuxX_tCU18RcWTe6siwemXAuKqDfg@mail.gmail.com>"))` + "\r\n" +
+ `* 7 FETCH (X-GM-THRID 1353701773219222407 X-GM-MSGID 1375207927094695931 UID 50579 RFC822.SIZE 4049 INTERNALDATE "24-Jul-2011 09:41:19 +0000" FLAGS (\Seen) ENVELOPE ("Sun, 24 Jul 2011 02:41:14 -0700 (PDT)" "Re: [re2-dev] Re: MSVC build" ((NIL NIL "talgil" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) ((NIL NIL "re2-dev" "googlegroups.com")) ((NIL NIL "re2-dev" "googlegroups.com")) (("ioannis" NIL "ioannis.e" "gmail.com")) NIL "<AANLkTin8_-yDr8tcb9SosfQ_iAM6RmfzpLQB0gX0vv6w@mail.gmail.com>" "<24718992.6777.1311500475040.JavaMail.geo-discussion-forums@yqyy3>"))` + "\r\n" +
+ `* 8 FETCH (X-GM-THRID 1375017086705541883 X-GM-MSGID 1375220323861690146 UID 50597 RFC822.SIZE 3070 INTERNALDATE "24-Jul-2011 12:58:22 +0000" FLAGS (\Seen) ENVELOPE ("Sun, 24 Jul 2011 14:58:15 +0200" "Re: [re2-dev] Rearranging platform dependant features" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Russ Cox" NIL "rsc" "swtch.com")) NIL NIL "<CADSkJJV+eCPkkhsepo5k0w+dqVo0fQOana2bWp4BexGOrCSSUQ@mail.gmail.com>" "<4E2C16E7.3060500@gmail.com>"))` + "\r\n" +
+ `* 9 FETCH (X-GM-THRID 1353701773219222407 X-GM-MSGID 1375220551142026521 UID 50598 RFC822.SIZE 5744 INTERNALDATE "24-Jul-2011 13:01:59 +0000" FLAGS (\Seen) ENVELOPE ("Sun, 24 Jul 2011 15:01:49 +0200" "Re: [re2-dev] Re: MSVC build" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) NIL NIL "<24718992.6777.1311500475040.JavaMail.geo-discussion-forums@yqyy3>" "<4E2C17BD.6000702@gmail.com>"))` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57047:* (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY X-GM-MSGID X-GM-THRID X-GM-LABELS)`: `* 9 FETCH (X-GM-THRID 1382192619814696847 X-GM-MSGID 1382192619814696847 X-GM-LABELS ("\\Important" russcox@gmail.com) UID 57046 RFC822.SIZE 4170 INTERNALDATE "09-Oct-2011 12:00:02 +0000" FLAGS () ENVELOPE ("Sun, 09 Oct 2011 12:00:02 +0000" "You have no events scheduled today." (("Google Calendar" NIL "calendar-notification" "google.com")) (("Google Calendar" NIL "calendar-notification" "google.com")) (("Russ Cox" NIL "russcox" "gmail.com")) (("Russ Cox" NIL "russcox" "gmail.com")) NIL NIL NIL "<bcaec501c5be15fc7204aedc6af6@google.com>") BODY (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "DELSP" "yes" "FORMAT" "flowed") NIL NIL "7BIT" 465 11)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 914 12) "ALTERNATIVE"))` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 1:* (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY X-GM-MSGID X-GM-THRID X-GM-LABELS)`: `* 1 FETCH (X-GM-THRID 1371690017835349492 X-GM-MSGID 1371690017835349492 X-GM-LABELS () UID 46074 RFC822.SIZE 5700 INTERNALDATE "15-Jun-2011 13:45:39 +0000" FLAGS (\Seen) ENVELOPE ("Wed, 15 Jun 2011 13:45:35 +0000" "[re2-dev] Issue 40 in re2: Please make RE2::Rewrite public" ((NIL NIL "re2" "googlecode.com")) ((NIL NIL "re2-dev" "googlegroups.com")) ((NIL NIL "codesite-noreply" "google.com")) ((NIL NIL "re2-dev" "googlegroups.com")) NIL NIL NIL "<0-13244084390050003171-8842966241254494762-re2=googlecode.com@googlecode.com>") BODY ("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "DELSP" "yes" "FORMAT" "flowed") NIL NIL "7BIT" 389 11))` + "\r\n" +
+ `* 2 FETCH (X-GM-THRID 1370053443095117076 X-GM-MSGID 1374032778063810116 X-GM-LABELS ("\\Important") UID 49094 RFC822.SIZE 3558 INTERNALDATE "11-Jul-2011 10:22:49 +0000" FLAGS (\Seen) ENVELOPE ("Mon, 11 Jul 2011 12:22:46 +0200" "Re: [re2-dev] Re: Issue 39 in re2: Eiffel wrapper for RE2" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Russ Cox" NIL "rsc" "swtch.com")) NIL NIL "<CADSkJJWthFb61R1tqJxZP1SxTPuwY_BBW5ToLuzX2UpHSvsy9w@mail.gmail.com>" "<4E1ACEF6.4060609@gmail.com>") BODY ("TEXT" "PLAIN" ("CHARSET" "UTF-8" "FORMAT" "flowed") NIL NIL "7BIT" 766 24))` + "\r\n" +
+ `* 3 FETCH (X-GM-THRID 1370053443095117076 X-GM-MSGID 1374171123044094435 X-GM-LABELS ("\\Important") UID 49317 RFC822.SIZE 3323 INTERNALDATE "12-Jul-2011 23:01:46 +0000" FLAGS (\Seen) ENVELOPE ("Wed, 13 Jul 2011 01:01:41 +0200" "Re: [re2-dev] Re: Issue 39 in re2: Eiffel wrapper for RE2" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Russ Cox" NIL "rsc" "swtch.com")) NIL NIL "<CADSkJJV+E-0Xtm=dpiSHLbwkZjZ=zDDoE1t1w0CiGYa+pVz66g@mail.gmail.com>" "<4E1CD255.6060807@gmail.com>") BODY ("TEXT" "PLAIN" ("CHARSET" "UTF-8" "FORMAT" "flowed") NIL NIL "7BIT" 435 12))` + "\r\n" +
+ `* 4 FETCH (X-GM-THRID 1374260005724669308 X-GM-MSGID 1374260005724669308 X-GM-LABELS ("\\Important" "\\Starred") UID 49424 RFC822.SIZE 2681 INTERNALDATE "13-Jul-2011 22:34:31 +0000" FLAGS (\Flagged \Seen) ENVELOPE ("Wed, 13 Jul 2011 16:33:43 -0600" "Minor correction for venti(8) user manual for running plan9port on Linux" (("Xing" NIL "xinglin" "cs.utah.edu")) (("Xing" NIL "xinglin" "cs.utah.edu")) (("Xing" NIL "xinglin" "cs.utah.edu")) ((NIL NIL "rsc" "swtch.com")) (("Xing Lin" NIL "xinglin" "cs.utah.edu") ("Raghuveer Pullakandam" NIL "rgv" "cs.utah.edu") ("Robert Ricci" NIL "ricci" "cs.utah.edu") ("Eric Eide" NIL "eeide" "cs.utah.edu")) NIL NIL "<1310596423.3866.11.camel@xing-utah-cs>") BODY ("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "8BIT" 789 25))` + "\r\n" +
+ `* 5 FETCH (X-GM-THRID 1374399840419707240 X-GM-MSGID 1374399840419707240 X-GM-LABELS ("\\Important") UID 49595 RFC822.SIZE 6496 INTERNALDATE "15-Jul-2011 11:37:07 +0000" FLAGS (\Seen) ENVELOPE ("Fri, 15 Jul 2011 13:36:54 +0200" "[re2-dev] MSVC not exporting VariadicFunction2<.. FullMatchN>::operator()(..) but VariadicFunction2<.. PartialMatchN>::operator()(..)" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) NIL NIL NIL "<4E202656.7010408@gmail.com>") BODY ("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "FORMAT" "flowed") NIL NIL "7BIT" 1660 34))` + "\r\n" +
+ `* 6 FETCH (X-GM-THRID 1374564698687599195 X-GM-MSGID 1374564698687599195 X-GM-LABELS ("\\Important") UID 49810 RFC822.SIZE 5485 INTERNALDATE "17-Jul-2011 07:17:29 +0000" FLAGS (\Seen) ENVELOPE ("Sun, 17 Jul 2011 00:17:28 -0700" "Acme IRC client patch" (("Ethan Burns" NIL "burns.ethan" "gmail.com")) (("Ethan Burns" NIL "burns.ethan" "gmail.com")) (("Ethan Burns" NIL "burns.ethan" "gmail.com")) ((NIL NIL "rsc" "swtch.com")) NIL NIL NIL "<CAGE=Ei0bmAjsYYDxCgtDObuxX_tCU18RcWTe6siwemXAuKqDfg@mail.gmail.com>") BODY (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "7BIT" 443 13)("TEXT" "X-PATCH" ("CHARSET" "US-ASCII" "NAME" "emote.patch") NIL NIL "BASE64" 2774 35) "MIXED"))` + "\r\n" +
+ `* 7 FETCH (X-GM-THRID 1353701773219222407 X-GM-MSGID 1375207927094695931 X-GM-LABELS ("\\Important") UID 50579 RFC822.SIZE 4049 INTERNALDATE "24-Jul-2011 09:41:19 +0000" FLAGS (\Seen) ENVELOPE ("Sun, 24 Jul 2011 02:41:14 -0700 (PDT)" "Re: [re2-dev] Re: MSVC build" ((NIL NIL "talgil" "gmail.com")) ((NIL NIL "re2-dev" "googlegroups.com")) ((NIL NIL "re2-dev" "googlegroups.com")) ((NIL NIL "re2-dev" "googlegroups.com")) (("ioannis" NIL "ioannis.e" "gmail.com")) NIL "<AANLkTin8_-yDr8tcb9SosfQ_iAM6RmfzpLQB0gX0vv6w@mail.gmail.com>" "<24718992.6777.1311500475040.JavaMail.geo-discussion-forums@yqyy3>") BODY (("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "7BIT" 133 8)("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "7BIT" 211 0) "ALTERNATIVE"))` + "\r\n" +
+ `* 8 FETCH (X-GM-THRID 1375017086705541883 X-GM-MSGID 1375220323861690146 X-GM-LABELS ("\\Important") UID 50597 RFC822.SIZE 3070 INTERNALDATE "24-Jul-2011 12:58:22 +0000" FLAGS (\Seen) ENVELOPE ("Sun, 24 Jul 2011 14:58:15 +0200" "Re: [re2-dev] Rearranging platform dependant features" (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Pontus Carlsson" NIL "pontusjoncarlsson" "gmail.com")) (("Russ Cox" NIL "rsc" "swtch.com")) NIL NIL "<CADSkJJV+eCPkkhsepo5k0w+dqVo0fQOana2bWp4BexGOrCSSUQ@mail.gmail.com>" "<4E2C16E7.3060500@gmail.com>") BODY ("TEXT" "PLAIN" ("CHARSET" "UTF-8" "FORMAT" "flowed") NIL NIL "7BIT" 450 10))` + "\r\n" +
+ `* 9 FETCH (X-GM-THRID 1382192619814696847 X-GM-MSGID 1382192619814696847 X-GM-LABELS ("\\Important" russcox@gmail.com) UID 57046 RFC822.SIZE 4170 INTERNALDATE "09-Oct-2011 12:00:02 +0000" FLAGS () ENVELOPE ("Sun, 09 Oct 2011 12:00:02 +0000" "You have no events scheduled today." (("Google Calendar" NIL "calendar-notification" "google.com")) (("Google Calendar" NIL "calendar-notification" "google.com")) (("Russ Cox" NIL "russcox" "gmail.com")) (("Russ Cox" NIL "russcox" "gmail.com")) NIL NIL NIL "<bcaec501c5be15fc7204aedc6af6@google.com>") BODY (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "DELSP" "yes" "FORMAT" "flowed") NIL NIL "7BIT" 465 11)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 914 12) "ALTERNATIVE"))` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[1]`: `* 9 FETCH (UID 57046 BODY[1] {465}` + "\r\n" +
+ `russcox@gmail.com, you have no events scheduled today Sun Oct 9, 2011.` + "\r\n" +
+ `` + "\r\n" +
+ `View your calendar at https://www.google.com/calendar/` + "\r\n" +
+ `` + "\r\n" +
+ `You are receiving this email at the account russcox@gmail.com because you ` + "\r\n" +
+ `are subscribed to receive daily agendas for the following calendars: Russ ` + "\r\n" +
+ `Cox.` + "\r\n" +
+ `` + "\r\n" +
+ `To change which calendars you receive daily agendas for, please log in to ` + "\r\n" +
+ `https://www.google.com/calendar/ and change your notification settings for ` + "\r\n" +
+ `each calendar.` + "\r\n" +
+ `)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[1.TEXT]`: `* 9 FETCH (UID 57046 BODY[1.TEXT] NIL)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[1.HEADER]`: `* 9 FETCH (UID 57046 BODY[1.HEADER] NIL)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[1.MIME]`: `* 146 FETCH (UID 57046 BODY[1.MIME] {74}` + "\r\n" +
+ `Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes` + "\r\n" +
+ `` + "\r\n" +
+ `)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[2]`: `* 146 FETCH (UID 57046 BODY[2] {914}` + "\r\n" +
+ `<div style=3D"padding:10px 7px;font-size:14px;line-height:1.4;font-family:A=` + "\r\n" +
+ `rial,Sans-serif;text-align:left;bgcolor=3D#ffffff"><a href=3D"https://www.g=` + "\r\n" +
+ `oogle.com/calendar/"><img style=3D"border-width:0" src=3D"https://www.googl=` + "\r\n" +
+ `e.com/calendar/images/calendar_logo_sm_en.gif" alt=3D"Google Calendar"></a>` + "\r\n" +
+ `<p style=3D"margin:0;color:#0">russcox@gmail.com,&nbsp;you have no events s=` + "\r\n" +
+ `cheduled today <b>Sun Oct 9, 2011</b></p>` + "\r\n" +
+ `<p style=3D"font-family:Arial,Sans-serif;color:#666;font-size:11px">You are=` + "\r\n" +
+ ` receiving this email at the account russcox@gmail.com because you are subs=` + "\r\n" +
+ `cribed to receive daily agendas for the following calendars: Russ Cox.</p>` + "\r\n" +
+ `<p style=3D"font-family:Arial,Sans-serif;color:#666;font-size:11px">To chan=` + "\r\n" +
+ `ge which calendars you receive daily agendas for, please log in to https://=` + "\r\n" +
+ `www.google.com/calendar/ and change your notification settings for each cal=` + "\r\n" +
+ `endar.</p></div>)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[2.TEXT]`: `* 9 FETCH (UID 57046 BODY[2.TEXT] NIL)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[2.HEADER]`: `* 9 FETCH (UID 57046 BODY[2.HEADER] NIL)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[2.MIME]`: `* 146 FETCH (UID 57046 BODY[2.MIME] {92}` + "\r\n" +
+ `Content-Type: text/html; charset=ISO-8859-1` + "\r\n" +
+ `Content-Transfer-Encoding: quoted-printable` + "\r\n" +
+ `` + "\r\n" +
+ `)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[]`: `* 146 FETCH (UID 57046 BODY[] {4170}` + "\r\n" +
+ `Delivered-To: rsc@swtch.com` + "\r\n" +
+ `Received: by 10.216.54.148 with SMTP id i20cs32329wec;` + "\r\n" +
+ ` Sun, 9 Oct 2011 05:00:30 -0700 (PDT)` + "\r\n" +
+ `Received: by 10.227.11.2 with SMTP id r2mr4751812wbr.43.1318161630585;` + "\r\n" +
+ ` Sun, 09 Oct 2011 05:00:30 -0700 (PDT)` + "\r\n" +
+ `DomainKey-Status: good` + "\r\n" +
+ `Received-SPF: softfail (google.com: best guess record for domain of transitioning 3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com does not designate <unknown> as permitted sender)` + "\r\n" +
+ `Received: by 10.241.227.90 with POP3 id 26mf2646912wyj.48;` + "\r\n" +
+ ` Sun, 09 Oct 2011 05:00:29 -0700 (PDT)` + "\r\n" +
+ `X-Gmail-Fetch-Info: russcox@gmail.com 1 smtp.gmail.com 995 russcox` + "\r\n" +
+ `Delivered-To: russcox@gmail.com` + "\r\n" +
+ `Received: by 10.142.76.10 with SMTP id y10cs75487wfa;` + "\r\n" +
+ ` Sun, 9 Oct 2011 05:00:08 -0700 (PDT)` + "\r\n" +
+ `Return-Path: <3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com>` + "\r\n" +
+ `Received-SPF: pass (google.com: domain of 3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com designates 10.52.73.100 as permitted sender) client-ip=10.52.73.100;` + "\r\n" +
+ `Authentication-Results: mr.google.com; spf=pass (google.com: domain of 3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com designates 10.52.73.100 as permitted sender) smtp.mail=3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com; dkim=pass header.i=3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com` + "\r\n" +
+ `Received: from mr.google.com ([10.52.73.100])` + "\r\n" +
+ ` by 10.52.73.100 with SMTP id k4mr8053242vdv.5.1318161606360 (num_hops = 1);` + "\r\n" +
+ ` Sun, 09 Oct 2011 05:00:06 -0700 (PDT)` + "\r\n" +
+ `DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;` + "\r\n" +
+ ` d=google.com; s=beta;` + "\r\n" +
+ ` h=mime-version:reply-to:auto-submitted:message-id:date:subject:from` + "\r\n" +
+ ` :to:content-type;` + "\r\n" +
+ ` bh=SGjz0F4q+eFVkoC4yzLKQKvlxTKiUsYbO/KPI+3KOE8=;` + "\r\n" +
+ ` b=LRBkWBW7ZZ4UJYa7b92zfHa0ZM1K1d0wP/jbgmDw2OZTWtgDICZb30dzhFUfNVdxeN` + "\r\n" +
+ ` kdMFbRhTLP5NpSXWhbDw==` + "\r\n" +
+ `MIME-Version: 1.0` + "\r\n" +
+ `Received: by 10.52.73.100 with SMTP id k4mr5244039vdv.5.1318161602706; Sun, 09` + "\r\n" +
+ ` Oct 2011 05:00:02 -0700 (PDT)` + "\r\n" +
+ `Reply-To: Russ Cox <russcox@gmail.com>` + "\r\n" +
+ `Auto-Submitted: auto-generated` + "\r\n" +
+ `Message-ID: <bcaec501c5be15fc7204aedc6af6@google.com>` + "\r\n" +
+ `Date: Sun, 09 Oct 2011 12:00:02 +0000` + "\r\n" +
+ `Subject: You have no events scheduled today.` + "\r\n" +
+ `From: Google Calendar <calendar-notification@google.com>` + "\r\n" +
+ `To: Russ Cox <russcox@gmail.com>` + "\r\n" +
+ `Content-Type: multipart/alternative; boundary=bcaec501c5be15fc6504aedc6af3` + "\r\n" +
+ `` + "\r\n" +
+ `--bcaec501c5be15fc6504aedc6af3` + "\r\n" +
+ `Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes` + "\r\n" +
+ `` + "\r\n" +
+ `russcox@gmail.com, you have no events scheduled today Sun Oct 9, 2011.` + "\r\n" +
+ `` + "\r\n" +
+ `View your calendar at https://www.google.com/calendar/` + "\r\n" +
+ `` + "\r\n" +
+ `You are receiving this email at the account russcox@gmail.com because you ` + "\r\n" +
+ `are subscribed to receive daily agendas for the following calendars: Russ ` + "\r\n" +
+ `Cox.` + "\r\n" +
+ `` + "\r\n" +
+ `To change which calendars you receive daily agendas for, please log in to ` + "\r\n" +
+ `https://www.google.com/calendar/ and change your notification settings for ` + "\r\n" +
+ `each calendar.` + "\r\n" +
+ `` + "\r\n" +
+ `--bcaec501c5be15fc6504aedc6af3` + "\r\n" +
+ `Content-Type: text/html; charset=ISO-8859-1` + "\r\n" +
+ `Content-Transfer-Encoding: quoted-printable` + "\r\n" +
+ `` + "\r\n" +
+ `<div style=3D"padding:10px 7px;font-size:14px;line-height:1.4;font-family:A=` + "\r\n" +
+ `rial,Sans-serif;text-align:left;bgcolor=3D#ffffff"><a href=3D"https://www.g=` + "\r\n" +
+ `oogle.com/calendar/"><img style=3D"border-width:0" src=3D"https://www.googl=` + "\r\n" +
+ `e.com/calendar/images/calendar_logo_sm_en.gif" alt=3D"Google Calendar"></a>` + "\r\n" +
+ `<p style=3D"margin:0;color:#0">russcox@gmail.com,&nbsp;you have no events s=` + "\r\n" +
+ `cheduled today <b>Sun Oct 9, 2011</b></p>` + "\r\n" +
+ `<p style=3D"font-family:Arial,Sans-serif;color:#666;font-size:11px">You are=` + "\r\n" +
+ ` receiving this email at the account russcox@gmail.com because you are subs=` + "\r\n" +
+ `cribed to receive daily agendas for the following calendars: Russ Cox.</p>` + "\r\n" +
+ `<p style=3D"font-family:Arial,Sans-serif;color:#666;font-size:11px">To chan=` + "\r\n" +
+ `ge which calendars you receive daily agendas for, please log in to https://=` + "\r\n" +
+ `www.google.com/calendar/ and change your notification settings for each cal=` + "\r\n" +
+ `endar.</p></div>` + "\r\n" +
+ `--bcaec501c5be15fc6504aedc6af3--` + "\r\n" +
+ `)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[TEXT]`: `* 146 FETCH (UID 57046 BODY[TEXT] {1647}` + "\r\n" +
+ `--bcaec501c5be15fc6504aedc6af3` + "\r\n" +
+ `Content-Type: text/plain; charset=ISO-8859-1; format=flowed; delsp=yes` + "\r\n" +
+ `` + "\r\n" +
+ `russcox@gmail.com, you have no events scheduled today Sun Oct 9, 2011.` + "\r\n" +
+ `` + "\r\n" +
+ `View your calendar at https://www.google.com/calendar/` + "\r\n" +
+ `` + "\r\n" +
+ `You are receiving this email at the account russcox@gmail.com because you ` + "\r\n" +
+ `are subscribed to receive daily agendas for the following calendars: Russ ` + "\r\n" +
+ `Cox.` + "\r\n" +
+ `` + "\r\n" +
+ `To change which calendars you receive daily agendas for, please log in to ` + "\r\n" +
+ `https://www.google.com/calendar/ and change your notification settings for ` + "\r\n" +
+ `each calendar.` + "\r\n" +
+ `` + "\r\n" +
+ `--bcaec501c5be15fc6504aedc6af3` + "\r\n" +
+ `Content-Type: text/html; charset=ISO-8859-1` + "\r\n" +
+ `Content-Transfer-Encoding: quoted-printable` + "\r\n" +
+ `` + "\r\n" +
+ `<div style=3D"padding:10px 7px;font-size:14px;line-height:1.4;font-family:A=` + "\r\n" +
+ `rial,Sans-serif;text-align:left;bgcolor=3D#ffffff"><a href=3D"https://www.g=` + "\r\n" +
+ `oogle.com/calendar/"><img style=3D"border-width:0" src=3D"https://www.googl=` + "\r\n" +
+ `e.com/calendar/images/calendar_logo_sm_en.gif" alt=3D"Google Calendar"></a>` + "\r\n" +
+ `<p style=3D"margin:0;color:#0">russcox@gmail.com,&nbsp;you have no events s=` + "\r\n" +
+ `cheduled today <b>Sun Oct 9, 2011</b></p>` + "\r\n" +
+ `<p style=3D"font-family:Arial,Sans-serif;color:#666;font-size:11px">You are=` + "\r\n" +
+ ` receiving this email at the account russcox@gmail.com because you are subs=` + "\r\n" +
+ `cribed to receive daily agendas for the following calendars: Russ Cox.</p>` + "\r\n" +
+ `<p style=3D"font-family:Arial,Sans-serif;color:#666;font-size:11px">To chan=` + "\r\n" +
+ `ge which calendars you receive daily agendas for, please log in to https://=` + "\r\n" +
+ `www.google.com/calendar/ and change your notification settings for each cal=` + "\r\n" +
+ `endar.</p></div>` + "\r\n" +
+ `--bcaec501c5be15fc6504aedc6af3--` + "\r\n" +
+ `)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[HEADER]`: `* 146 FETCH (UID 57046 BODY[HEADER] {2453}` + "\r\n" +
+ `Delivered-To: rsc@swtch.com` + "\r\n" +
+ `Received: by 10.216.54.148 with SMTP id i20cs32329wec; Sun, 9 Oct 2011` + "\r\n" +
+ ` 05:00:30 -0700 (PDT)` + "\r\n" +
+ `Received: by 10.227.11.2 with SMTP id r2mr4751812wbr.43.1318161630585; Sun, 09` + "\r\n" +
+ ` Oct 2011 05:00:30 -0700 (PDT)` + "\r\n" +
+ `DomainKey-Status: good` + "\r\n" +
+ `Received-SPF: softfail (google.com: best guess record for domain of` + "\r\n" +
+ ` transitioning` + "\r\n" +
+ ` 3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com` + "\r\n" +
+ ` does not designate <unknown> as permitted sender)` + "\r\n" +
+ `Received: by 10.241.227.90 with POP3 id 26mf2646912wyj.48; Sun, 09 Oct 2011` + "\r\n" +
+ ` 05:00:29 -0700 (PDT)` + "\r\n" +
+ `X-Gmail-Fetch-Info: russcox@gmail.com 1 smtp.gmail.com 995 russcox` + "\r\n" +
+ `Delivered-To: russcox@gmail.com` + "\r\n" +
+ `Received: by 10.142.76.10 with SMTP id y10cs75487wfa; Sun, 9 Oct 2011 05:00:08` + "\r\n" +
+ ` -0700 (PDT)` + "\r\n" +
+ `Return-Path: <3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com>` + "\r\n" +
+ `Received-SPF: pass (google.com: domain of` + "\r\n" +
+ ` 3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com` + "\r\n" +
+ ` designates 10.52.73.100 as permitted sender) client-ip=10.52.73.100;` + "\r\n" +
+ `Authentication-Results: mr.google.com; spf=pass (google.com: domain of` + "\r\n" +
+ ` 3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com` + "\r\n" +
+ ` designates 10.52.73.100 as permitted sender)` + "\r\n" +
+ ` smtp.mail=3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com;` + "\r\n" +
+ ` dkim=pass` + "\r\n" +
+ ` header.i=3woyRTgcJB5sMPNN7JSBH5DG.7JHMPNN7JSBH5DG.7JH@calendar-server.bounces.google.com` + "\r\n" +
+ `Received: from mr.google.com ([10.52.73.100]) by 10.52.73.100 with SMTP id` + "\r\n" +
+ ` k4mr8053242vdv.5.1318161606360 (num_hops = 1); Sun, 09 Oct 2011 05:00:06` + "\r\n" +
+ ` -0700 (PDT)` + "\r\n" +
+ `DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=beta;` + "\r\n" +
+ ` h=mime-version:reply-to:auto-submitted:message-id:date:subject:from` + "\r\n" +
+ ` :to:content-type; bh=SGjz0F4q+eFVkoC4yzLKQKvlxTKiUsYbO/KPI+3KOE8=;` + "\r\n" +
+ ` b=LRBkWBW7ZZ4UJYa7b92zfHa0ZM1K1d0wP/jbgmDw2OZTWtgDICZb30dzhFUfNVdxeN` + "\r\n" +
+ ` kdMFbRhTLP5NpSXWhbDw==` + "\r\n" +
+ `MIME-Version: 1.0` + "\r\n" +
+ `Received: by 10.52.73.100 with SMTP id k4mr5244039vdv.5.1318161602706; Sun, 09` + "\r\n" +
+ ` Oct 2011 05:00:02 -0700 (PDT)` + "\r\n" +
+ `Reply-To: Russ Cox <russcox@gmail.com>` + "\r\n" +
+ `Auto-Submitted: auto-generated` + "\r\n" +
+ `Message-ID: <bcaec501c5be15fc7204aedc6af6@google.com>` + "\r\n" +
+ `Date: Sun, 09 Oct 2011 12:00:02 +0000` + "\r\n" +
+ `Subject: You have no events scheduled today.` + "\r\n" +
+ `From: Google Calendar <calendar-notification@google.com>` + "\r\n" +
+ `To: Russ Cox <russcox@gmail.com>` + "\r\n" +
+ `Content-Type: multipart/alternative; boundary=bcaec501c5be15fc6504aedc6af3` + "\r\n" +
+ `` + "\r\n" +
+ `)` + "\r\n" +
+ "# OK Success\r\n",
+ `# UID FETCH 57046 BODY[MIME]`: "# BAD Could not parse command\r\n",
+}
+
+/*
+ mail sending
+
+package main
+
+import (
+ "log"
+ "io/ioutil"
+ "smtp"
+ "time"
+)
+var pw, _ = ioutil.ReadFile("/Users/rsc/.swtchpass")
+var msg = `From: "Russ Cox" <rsc@golang.org>
+To: "Russ Cox" <rsc@google.com>
+Subject: test from Go
+
+This is a message sent from Go
+`
+
+BUG: Does not *REQUIRE* auth. Should.
+
+func main() {
+ auth := smtp.PlainAuth(
+ "",
+ "rsc@swtch.com",
+ string(pw),
+ "smtp.gmail.com",
+ )
+ if err := smtp.SendMail("smtp.gmail.com:587", auth, "rsc@swtch.com", []string{"rsc@google.com"}, []byte(msg+time.LocalTime().String())); err != nil {
+ log.Fatal(err)
+ }
+ println("SENT")
+}
+*/
diff --git a/vendor/github.com/mattermost/rsc/imap/mail.go b/vendor/github.com/mattermost/rsc/imap/mail.go
new file mode 100644
index 000000000..365540f82
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/mail.go
@@ -0,0 +1,468 @@
+package imap
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "regexp"
+ "sort"
+ "strings"
+ "time"
+)
+
+type Flags uint32
+
+const (
+ FlagJunk Flags = 1 << iota
+ FlagNonJunk
+ FlagReplied
+ FlagFlagged
+ FlagDeleted
+ FlagDraft
+ FlagRecent
+ FlagSeen
+ FlagNoInferiors
+ FlagNoSelect
+ FlagMarked
+ FlagUnMarked
+ FlagHasChildren
+ FlagHasNoChildren
+ FlagInbox // Gmail extension
+ FlagAllMail // Gmail extension
+ FlagDrafts // Gmail extension
+ FlagSent // Gmail extension
+ FlagSpam // Gmail extension
+ FlagStarred // Gmail extension
+ FlagTrash // Gmail extension
+ FlagImportant // Gmail extension
+)
+
+var flagNames = []string{
+ "Junk",
+ "NonJunk",
+ "\\Answered",
+ "\\Flagged",
+ "\\Deleted",
+ "\\Draft",
+ "\\Recent",
+ "\\Seen",
+ "\\NoInferiors",
+ "\\NoSelect",
+ "\\Marked",
+ "\\UnMarked",
+ "\\HasChildren",
+ "\\HasNoChildren",
+ "\\Inbox",
+ "\\AllMail",
+ "\\Drafts",
+ "\\Sent",
+ "\\Spam",
+ "\\Starred",
+ "\\Trash",
+ "\\Important",
+}
+
+// A Box represents an IMAP mailbox.
+type Box struct {
+ Name string // name of mailbox
+ Elem string // last element in name
+ Client *Client
+
+ parent *Box // parent in hierarchy
+ child []*Box // child boxes
+ dead bool // box no longer exists
+ inbox bool // box is inbox
+ flags Flags // allowed flags
+ permFlags Flags // client-modifiable permanent flags
+ readOnly bool // box is read-only
+
+ exists int // number of messages in box (according to server)
+ maxSeen int // maximum message number seen (for polling)
+ unseen int // number of first unseen message
+ validity uint32 // UID validity base number
+ load bool // if false, don't track full set of messages
+ firstNum int // 0 means box not loaded
+ msgByNum []*Msg
+ msgByUID map[uint64]*Msg
+}
+
+func (c *Client) Boxes() []*Box {
+ c.data.lock()
+ defer c.data.unlock()
+
+ box := make([]*Box, len(c.allBox))
+ copy(box, c.allBox)
+ return box
+}
+
+func (c *Client) Box(name string) *Box {
+ c.data.lock()
+ defer c.data.unlock()
+
+ return c.boxByName[name]
+}
+
+func (c *Client) Inbox() *Box {
+ c.data.lock()
+ defer c.data.unlock()
+
+ return c.inbox
+}
+
+func (c *Client) newBox(name, sep string, inbox bool) *Box {
+ c.data.mustBeLocked()
+ if b := c.boxByName[name]; b != nil {
+ return b
+ }
+
+ b := &Box{
+ Name: name,
+ Elem: name,
+ Client: c,
+ inbox: inbox,
+ }
+ if !inbox {
+ b.parent = c.rootBox
+ }
+ if !inbox && sep != "" && name != c.root {
+ if i := strings.LastIndex(name, sep); i >= 0 {
+ b.Elem = name[i+len(sep):]
+ b.parent = c.newBox(name[:i], sep, false)
+ }
+ }
+ c.allBox = append(c.allBox, b)
+ c.boxByName[name] = b
+ if b.parent != nil {
+ b.parent.child = append(b.parent.child, b)
+ }
+ return b
+}
+
+// A Msg represents an IMAP message.
+type Msg struct {
+ Box *Box // box containing message
+ Date time.Time // date
+ Flags Flags // message flags
+ Bytes int64 // size in bytes
+ Lines int64 // number of lines
+ Hdr *MsgHdr // MIME header
+ Root MsgPart // top-level message part
+ GmailID uint64 // Gmail message id
+ GmailThread uint64 // Gmail thread id
+ UID uint64 // unique id for this message
+
+ deleted bool
+ dead bool
+ num int // message number in box (changes)
+}
+
+// TODO: Return os.Error too
+
+type byUID []*Msg
+
+func (x byUID) Len() int { return len(x) }
+func (x byUID) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byUID) Less(i, j int) bool { return x[i].UID < x[j].UID }
+
+func (b *Box) Msgs() []*Msg {
+ b.Client.data.lock()
+ defer b.Client.data.unlock()
+
+ msgs := make([]*Msg, len(b.msgByUID))
+ n := 0
+ for _, m := range b.msgByUID {
+ msgs[n] = m
+ n++
+ }
+ sort.Sort(byUID(msgs))
+ return msgs
+}
+
+func (b *Box) newMsg(uid uint64, id int) *Msg {
+ b.Client.data.mustBeLocked()
+ if m := b.msgByUID[uid]; m != nil {
+ return m
+ }
+ if b.msgByUID == nil {
+ b.msgByUID = map[uint64]*Msg{}
+ }
+ m := &Msg{
+ UID: uid,
+ Box: b,
+ num: id,
+ }
+ m.Root.Msg = m
+ if b.load {
+ if b.firstNum == 0 {
+ b.firstNum = id
+ }
+ if id < b.firstNum {
+ log.Printf("warning: unexpected id %d < %d", id, b.firstNum)
+ byNum := make([]*Msg, len(b.msgByNum)+b.firstNum-id)
+ copy(byNum[b.firstNum-id:], b.msgByNum)
+ b.msgByNum = byNum
+ b.firstNum = id
+ }
+ if id-b.firstNum < len(b.msgByNum) {
+ b.msgByNum[id-b.firstNum] = m
+ } else {
+ if id-b.firstNum > len(b.msgByNum) {
+ log.Printf("warning: unexpected id %d > %d", id, b.firstNum+len(b.msgByNum))
+ byNum := make([]*Msg, id-b.firstNum)
+ copy(byNum, b.msgByNum)
+ b.msgByNum = byNum
+ }
+ b.msgByNum = append(b.msgByNum, m)
+ }
+ }
+ b.msgByUID[uid] = m
+ return m
+}
+
+func (b *Box) Delete(msgs []*Msg) error {
+ for _, m := range msgs {
+ if m.Box != b {
+ return fmt.Errorf("messages not from this box")
+ }
+ }
+ b.Client.io.lock()
+ defer b.Client.io.unlock()
+ err := b.Client.deleteList(msgs)
+ if err == nil {
+ b.Client.data.lock()
+ defer b.Client.data.unlock()
+ for _, m := range msgs {
+ if m.Flags&FlagDeleted != 0 {
+ delete(b.msgByUID, m.UID)
+ }
+ }
+ }
+ return err
+}
+
+func (b *Box) Copy(msgs []*Msg) error {
+ if len(msgs) == 0 {
+ return nil
+ }
+ src := msgs[0].Box
+ for _, m := range msgs {
+ if m.Box != src {
+ return fmt.Errorf("messages span boxes: %q and %q", src.Name, m.Box.Name)
+ }
+ }
+ b.Client.io.lock()
+ defer b.Client.io.unlock()
+ return b.Client.copyList(b, src, msgs)
+}
+
+func (b *Box) Mute(msgs []*Msg) error {
+ if len(msgs) == 0 {
+ return nil
+ }
+ for _, m := range msgs {
+ if m.Box != b {
+ return fmt.Errorf("messages not from this box")
+ }
+ }
+ b.Client.io.lock()
+ defer b.Client.io.unlock()
+ return b.Client.muteList(b, msgs)
+}
+
+func (b *Box) Check() error {
+ b.Client.io.lock()
+ defer b.Client.io.unlock()
+
+ return b.Client.check(b)
+}
+
+func (m *Msg) Deleted() bool {
+ // Racy but okay. Can add a lock later if it matters.
+ return m.Flags&FlagDeleted != 0
+}
+
+// A Hdr represents a message header.
+type MsgHdr struct {
+ Date string
+ Subject string
+ From []Addr
+ Sender []Addr
+ ReplyTo []Addr
+ To []Addr
+ CC []Addr
+ BCC []Addr
+ InReplyTo string
+ MessageID string
+ Digest string
+}
+
+// An Addr represents a single, named email address.
+// If Name is empty, only the email address is known.
+// If Email is empty, the Addr represents an unspecified (but named) group.
+type Addr struct {
+ Name string
+ Email string
+}
+
+func (a Addr) String() string {
+ if a.Email == "" {
+ return a.Name
+ }
+ if a.Name == "" {
+ return a.Email
+ }
+ return a.Name + " <" + a.Email + ">"
+}
+
+// A MsgPart represents a single part of a MIME-encoded message.
+type MsgPart struct {
+ Msg *Msg // containing message
+ Type string
+ ContentID string
+ Desc string
+ Encoding string
+ Bytes int64
+ Lines int64
+ Charset string
+ Name string
+ Hdr *MsgHdr
+ ID string
+ Child []*MsgPart
+
+ raw []byte // raw message
+ rawHeader []byte // raw RFC-2822 header, for message/rfc822
+ rawBody []byte // raw RFC-2822 body, for message/rfc822
+ mimeHeader []byte // mime header, for attachments
+}
+
+func (p *MsgPart) newPart() *MsgPart {
+ p.Msg.Box.Client.data.mustBeLocked()
+ dot := "."
+ if p.ID == "" { // no dot at root
+ dot = ""
+ }
+ pp := &MsgPart{
+ Msg: p.Msg,
+ ID: fmt.Sprint(p.ID, dot, 1+len(p.Child)),
+ }
+ p.Child = append(p.Child, pp)
+ return pp
+}
+
+func (p *MsgPart) Text() []byte {
+ c := p.Msg.Box.Client
+ var raw []byte
+ c.data.lock()
+ if p == &p.Msg.Root {
+ raw = p.rawBody
+ c.data.unlock()
+ if raw == nil {
+ c.io.lock()
+ if raw = p.rawBody; raw == nil {
+ c.fetch(p, "TEXT")
+ raw = p.rawBody
+ }
+ c.io.unlock()
+ }
+ } else {
+ raw = p.raw
+ c.data.unlock()
+ if raw == nil {
+ c.io.lock()
+ if raw = p.raw; raw == nil {
+ c.fetch(p, "")
+ raw = p.raw
+ }
+ c.io.unlock()
+ }
+ }
+ return decodeText(raw, p.Encoding, p.Charset, false)
+}
+
+func (p *MsgPart) Raw() []byte {
+ c := p.Msg.Box.Client
+ var raw []byte
+ c.data.lock()
+ raw = p.rawBody
+ c.data.unlock()
+ if raw == nil {
+ c.io.lock()
+ if raw = p.rawBody; raw == nil {
+ c.fetch(p, "")
+ raw = p.rawBody
+ }
+ c.io.unlock()
+ }
+ return raw
+}
+
+var sigDash = []byte("\n--\n")
+var quote = []byte("\n> ")
+var nl = []byte("\n")
+
+var onwrote = regexp.MustCompile(`\A\s*On .* wrote:\s*\z`)
+
+func (p *MsgPart) ShortText() []byte {
+ t := p.Text()
+
+ return shortText(t)
+}
+
+func shortText(t []byte) []byte {
+ if t == nil {
+ return nil
+ }
+
+ // Cut signature.
+ i := bytes.LastIndex(t, sigDash)
+ j := bytes.LastIndex(t, quote)
+ if i > j && bytes.Count(t[i+1:], nl) <= 10 {
+ t = t[:i+1]
+ }
+
+ // Cut trailing quoted text.
+ for {
+ rest, last := lastLine(t)
+ trim := bytes.TrimSpace(last)
+ if len(rest) < len(t) && (len(trim) == 0 || trim[0] == '>') {
+ t = rest
+ continue
+ }
+ break
+ }
+
+ // Cut 'On foo.*wrote:' line.
+ rest, last := lastLine(t)
+ if onwrote.Match(last) {
+ t = rest
+ }
+
+ // Cut trailing blank lines.
+ for {
+ rest, last := lastLine(t)
+ trim := bytes.TrimSpace(last)
+ if len(rest) < len(t) && len(trim) == 0 {
+ t = rest
+ continue
+ }
+ break
+ }
+
+ // Cut signature again.
+ i = bytes.LastIndex(t, sigDash)
+ j = bytes.LastIndex(t, quote)
+ if i > j && bytes.Count(t[i+1:], nl) <= 10 {
+ t = t[:i+1]
+ }
+
+ return t
+}
+
+func lastLine(t []byte) (rest, last []byte) {
+ n := len(t)
+ if n > 0 && t[n-1] == '\n' {
+ n--
+ }
+ j := bytes.LastIndex(t[:n], nl)
+ return t[:j+1], t[j+1:]
+}
diff --git a/vendor/github.com/mattermost/rsc/imap/mail_test.go b/vendor/github.com/mattermost/rsc/imap/mail_test.go
new file mode 100644
index 000000000..3c1aec860
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/mail_test.go
@@ -0,0 +1,335 @@
+package imap
+
+import "testing"
+
+var shortTextTests = []struct {
+ in, out string
+}{
+ {
+ in: `From: Brad Fitzpatrick <bradfitz@golang.org>
+Date: Tue Oct 18 18:23:11 EDT 2011
+To: r@golang.org, golang-dev@googlegroups.com, reply@codereview.appspotmail.com
+Subject: Re: [golang-dev] code review 5307043: rpc: don't panic on write error. (issue 5307043)
+
+Here's a test:
+
+bradfitz@gopher:~/go/src/pkg/rpc$ hg diff
+diff -r b7f9a5e9b87f src/pkg/rpc/server_test.go
+--- a/src/pkg/rpc/server_test.go Tue Oct 18 17:01:42 2011 -0500
++++ b/src/pkg/rpc/server_test.go Tue Oct 18 15:22:19 2011 -0700
+@@ -467,6 +467,27 @@
+ fmt.Printf("mallocs per HTTP rpc round trip: %d\n",
+countMallocs(dialHTTP, t))
+ }
+
++type writeCrasher struct{}
++
++func (writeCrasher) Close() os.Error {
++ return nil
++}
++
++func (writeCrasher) Read(p []byte) (int, os.Error) {
++ return 0, os.EOF
++}
++
++func (writeCrasher) Write(p []byte) (int, os.Error) {
++ return 0, os.NewError("fake write failure")
++}
++
++func TestClientWriteError(t *testing.T) {
++ c := NewClient(writeCrasher{})
++ res := false
++ c.Call("foo", 1, &res)
++}
++
+ func benchmarkEndToEnd(dial func() (*Client, os.Error), b *testing.B) {
+ b.StopTimer()
+ once.Do(startServer)
+
+
+On Tue, Oct 18, 2011 at 3:12 PM, <r@golang.org> wrote:
+
+> Reviewers: golang-dev_googlegroups.com,
+>
+> Message:
+> Hello golang-dev@googlegroups.com,
+>
+> I'd like you to review this change to
+> https://go.googlecode.com/hg/
+>
+>
+> Description:
+> rpc: don't panic on write error.
+> The mechanism to record the error in the call is already in place.
+> Fixes issue 2382.
+>
+> Please review this at http://codereview.appspot.com/**5307043/<http://codereview.appspot.com/5307043/>
+>
+> Affected files:
+> M src/pkg/rpc/client.go
+>
+>
+> Index: src/pkg/rpc/client.go
+> ==============================**==============================**=======
+> --- a/src/pkg/rpc/client.go
+> +++ b/src/pkg/rpc/client.go
+> @@ -85,7 +85,8 @@
+> client.request.Seq = c.seq
+> client.request.ServiceMethod = c.ServiceMethod
+> if err := client.codec.WriteRequest(&**client.request, c.Args); err
+> != nil {
+> - panic("rpc: client encode error: " + err.String())
+> + c.Error = err
+> + c.done()
+> }
+> }
+>
+> @@ -251,10 +252,10 @@
+> // the same Call object. If done is nil, Go will allocate a new channel.
+> // If non-nil, done must be buffered or Go will deliberately crash.
+> func (client *Client) Go(serviceMethod string, args interface{}, reply
+> interface{}, done chan *Call) *Call {
+> - c := new(Call)
+> - c.ServiceMethod = serviceMethod
+> - c.Args = args
+> - c.Reply = reply
+> + call := new(Call)
+> + call.ServiceMethod = serviceMethod
+> + call.Args = args
+> + call.Reply = reply
+> if done == nil {
+> done = make(chan *Call, 10) // buffered.
+> } else {
+> @@ -266,14 +267,14 @@
+> log.Panic("rpc: done channel is unbuffered")
+> }
+> }
+> - c.Done = done
+> + call.Done = done
+> if client.shutdown {
+> - c.Error = ErrShutdown
+> - c.done()
+> - return c
+> + call.Error = ErrShutdown
+> + call.done()
+> + return call
+> }
+> - client.send(c)
+> - return c
+> + client.send(call)
+> + return call
+> }
+>
+> // Call invokes the named function, waits for it to complete, and returns
+> its error status.
+>
+>
+>
+
+`,
+ out: `From: Brad Fitzpatrick <bradfitz@golang.org>
+Date: Tue Oct 18 18:23:11 EDT 2011
+To: r@golang.org, golang-dev@googlegroups.com, reply@codereview.appspotmail.com
+Subject: Re: [golang-dev] code review 5307043: rpc: don't panic on write error. (issue 5307043)
+
+Here's a test:
+
+bradfitz@gopher:~/go/src/pkg/rpc$ hg diff
+diff -r b7f9a5e9b87f src/pkg/rpc/server_test.go
+--- a/src/pkg/rpc/server_test.go Tue Oct 18 17:01:42 2011 -0500
++++ b/src/pkg/rpc/server_test.go Tue Oct 18 15:22:19 2011 -0700
+@@ -467,6 +467,27 @@
+ fmt.Printf("mallocs per HTTP rpc round trip: %d\n",
+countMallocs(dialHTTP, t))
+ }
+
++type writeCrasher struct{}
++
++func (writeCrasher) Close() os.Error {
++ return nil
++}
++
++func (writeCrasher) Read(p []byte) (int, os.Error) {
++ return 0, os.EOF
++}
++
++func (writeCrasher) Write(p []byte) (int, os.Error) {
++ return 0, os.NewError("fake write failure")
++}
++
++func TestClientWriteError(t *testing.T) {
++ c := NewClient(writeCrasher{})
++ res := false
++ c.Call("foo", 1, &res)
++}
++
+ func benchmarkEndToEnd(dial func() (*Client, os.Error), b *testing.B) {
+ b.StopTimer()
+ once.Do(startServer)
+`,
+ },
+ {
+ in: `From: David Symonds <dsymonds@golang.org>
+Date: Tue Oct 18 18:17:52 EDT 2011
+To: reply@codereview.appspotmail.com, r@golang.org, golang-dev@googlegroups.com
+Subject: Re: [golang-dev] code review 5307043: rpc: don't panic on write error. (issue 5307043)
+
+LGTM
+On Oct 19, 2011 9:12 AM, <r@golang.org> wrote:
+
+> Reviewers: golang-dev_googlegroups.com,
+>
+> Message:
+> Hello golang-dev@googlegroups.com,
+>
+> I'd like you to review this change to
+> https://go.googlecode.com/hg/
+>
+>
+> Description:
+> rpc: don't panic on write error.
+> The mechanism to record the error in the call is already in place.
+> Fixes issue 2382.
+>
+> Please review this at http://codereview.appspot.com/**5307043/<http://codereview.appspot.com/5307043/>
+>
+> Affected files:
+> M src/pkg/rpc/client.go
+>
+>
+> Index: src/pkg/rpc/client.go
+> ==============================**==============================**=======
+> --- a/src/pkg/rpc/client.go
+> +++ b/src/pkg/rpc/client.go
+> @@ -85,7 +85,8 @@
+> client.request.Seq = c.seq
+> client.request.ServiceMethod = c.ServiceMethod
+> if err := client.codec.WriteRequest(&**client.request, c.Args); err
+> != nil {
+> - panic("rpc: client encode error: " + err.String())
+> + c.Error = err
+> + c.done()
+> }
+> }
+>
+> @@ -251,10 +252,10 @@
+> // the same Call object. If done is nil, Go will allocate a new channel.
+> // If non-nil, done must be buffered or Go will deliberately crash.
+> func (client *Client) Go(serviceMethod string, args interface{}, reply
+> interface{}, done chan *Call) *Call {
+> - c := new(Call)
+> - c.ServiceMethod = serviceMethod
+> - c.Args = args
+> - c.Reply = reply
+> + call := new(Call)
+> + call.ServiceMethod = serviceMethod
+> + call.Args = args
+> + call.Reply = reply
+> if done == nil {
+> done = make(chan *Call, 10) // buffered.
+> } else {
+> @@ -266,14 +267,14 @@
+> log.Panic("rpc: done channel is unbuffered")
+> }
+> }
+> - c.Done = done
+> + call.Done = done
+> if client.shutdown {
+> - c.Error = ErrShutdown
+> - c.done()
+> - return c
+> + call.Error = ErrShutdown
+> + call.done()
+> + return call
+> }
+> - client.send(c)
+> - return c
+> + client.send(call)
+> + return call
+> }
+>
+> // Call invokes the named function, waits for it to complete, and returns
+> its error status.
+>
+>
+>
+
+`,
+ out: `From: David Symonds <dsymonds@golang.org>
+Date: Tue Oct 18 18:17:52 EDT 2011
+To: reply@codereview.appspotmail.com, r@golang.org, golang-dev@googlegroups.com
+Subject: Re: [golang-dev] code review 5307043: rpc: don't panic on write error. (issue 5307043)
+
+LGTM
+`,
+ },
+ {
+ in: `From: Brad Fitzpatrick <bradfitz@golang.org>
+Date: Tue Oct 18 23:26:07 EDT 2011
+To: rsc@golang.org, golang-dev@googlegroups.com, reply@codereview.appspotmail.com
+Subject: Re: [golang-dev] code review 5297044: gotest: use $GCFLAGS like make does (issue 5297044)
+
+LGTM
+
+On Tue, Oct 18, 2011 at 7:52 PM, <rsc@golang.org> wrote:
+
+> Reviewers: golang-dev_googlegroups.com,
+>
+> Message:
+> Hello golang-dev@googlegroups.com,
+>
+> I'd like you to review this change to
+> https://go.googlecode.com/hg/
+>
+>
+> Description:
+> gotest: use $GCFLAGS like make does
+>
+> Please review this at http://codereview.appspot.com/**5297044/<http://codereview.appspot.com/5297044/>
+>
+> Affected files:
+> M src/cmd/gotest/gotest.go
+>
+>
+> Index: src/cmd/gotest/gotest.go
+> ==============================**==============================**=======
+> --- a/src/cmd/gotest/gotest.go
+> +++ b/src/cmd/gotest/gotest.go
+> @@ -153,8 +153,12 @@
+> if gc == "" {
+> gc = O + "g"
+> }
+> - XGC = []string{gc, "-I", "_test", "-o", "_xtest_." + O}
+> - GC = []string{gc, "-I", "_test", "_testmain.go"}
+> + var gcflags []string
+> + if gf := strings.TrimSpace(os.Getenv("**GCFLAGS")); gf != "" {
+> + gcflags = strings.Fields(gf)
+> + }
+> + XGC = append([]string{gc, "-I", "_test", "-o", "_xtest_." + O},
+> gcflags...)
+> + GC = append(append([]string{gc, "-I", "_test"}, gcflags...),
+> "_testmain.go")
+> gl := os.Getenv("GL")
+> if gl == "" {
+> gl = O + "l"
+>
+>
+>
+`,
+ out: `From: Brad Fitzpatrick <bradfitz@golang.org>
+Date: Tue Oct 18 23:26:07 EDT 2011
+To: rsc@golang.org, golang-dev@googlegroups.com, reply@codereview.appspotmail.com
+Subject: Re: [golang-dev] code review 5297044: gotest: use $GCFLAGS like make does (issue 5297044)
+
+LGTM
+`,
+ },
+}
+
+func TestShortText(t *testing.T) {
+ for i, tt := range shortTextTests {
+ if out := string(shortText([]byte(tt.in))); out != tt.out {
+ t.Errorf("#%d: = %q, want %q\n", i, out, tt.out)
+ }
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/imap/rfc2045.txt b/vendor/github.com/mattermost/rsc/imap/rfc2045.txt
new file mode 100644
index 000000000..9f286b1a9
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/rfc2045.txt
@@ -0,0 +1,1739 @@
+
+
+
+
+
+
+Network Working Group N. Freed
+Request for Comments: 2045 Innosoft
+Obsoletes: 1521, 1522, 1590 N. Borenstein
+Category: Standards Track First Virtual
+ November 1996
+
+
+ Multipurpose Internet Mail Extensions
+ (MIME) Part One:
+ Format of Internet Message Bodies
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Abstract
+
+ STD 11, RFC 822, defines a message representation protocol specifying
+ considerable detail about US-ASCII message headers, and leaves the
+ message content, or message body, as flat US-ASCII text. This set of
+ documents, collectively called the Multipurpose Internet Mail
+ Extensions, or MIME, redefines the format of messages to allow for
+
+ (1) textual message bodies in character sets other than
+ US-ASCII,
+
+ (2) an extensible set of different formats for non-textual
+ message bodies,
+
+ (3) multi-part message bodies, and
+
+ (4) textual header information in character sets other than
+ US-ASCII.
+
+ These documents are based on earlier work documented in RFC 934, STD
+ 11, and RFC 1049, but extends and revises them. Because RFC 822 said
+ so little about message bodies, these documents are largely
+ orthogonal to (rather than a revision of) RFC 822.
+
+ This initial document specifies the various headers used to describe
+ the structure of MIME messages. The second document, RFC 2046,
+ defines the general structure of the MIME media typing system and
+ defines an initial set of media types. The third document, RFC 2047,
+ describes extensions to RFC 822 to allow non-US-ASCII text data in
+
+
+
+Freed & Borenstein Standards Track [Page 1]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ Internet mail header fields. The fourth document, RFC 2048, specifies
+ various IANA registration procedures for MIME-related facilities. The
+ fifth and final document, RFC 2049, describes MIME conformance
+ criteria as well as providing some illustrative examples of MIME
+ message formats, acknowledgements, and the bibliography.
+
+ These documents are revisions of RFCs 1521, 1522, and 1590, which
+ themselves were revisions of RFCs 1341 and 1342. An appendix in RFC
+ 2049 describes differences and changes from previous versions.
+
+Table of Contents
+
+ 1. Introduction ......................................... 3
+ 2. Definitions, Conventions, and Generic BNF Grammar .... 5
+ 2.1 CRLF ................................................ 5
+ 2.2 Character Set ....................................... 6
+ 2.3 Message ............................................. 6
+ 2.4 Entity .............................................. 6
+ 2.5 Body Part ........................................... 7
+ 2.6 Body ................................................ 7
+ 2.7 7bit Data ........................................... 7
+ 2.8 8bit Data ........................................... 7
+ 2.9 Binary Data ......................................... 7
+ 2.10 Lines .............................................. 7
+ 3. MIME Header Fields ................................... 8
+ 4. MIME-Version Header Field ............................ 8
+ 5. Content-Type Header Field ............................ 10
+ 5.1 Syntax of the Content-Type Header Field ............. 12
+ 5.2 Content-Type Defaults ............................... 14
+ 6. Content-Transfer-Encoding Header Field ............... 14
+ 6.1 Content-Transfer-Encoding Syntax .................... 14
+ 6.2 Content-Transfer-Encodings Semantics ................ 15
+ 6.3 New Content-Transfer-Encodings ...................... 16
+ 6.4 Interpretation and Use .............................. 16
+ 6.5 Translating Encodings ............................... 18
+ 6.6 Canonical Encoding Model ............................ 19
+ 6.7 Quoted-Printable Content-Transfer-Encoding .......... 19
+ 6.8 Base64 Content-Transfer-Encoding .................... 24
+ 7. Content-ID Header Field .............................. 26
+ 8. Content-Description Header Field ..................... 27
+ 9. Additional MIME Header Fields ........................ 27
+ 10. Summary ............................................. 27
+ 11. Security Considerations ............................. 27
+ 12. Authors' Addresses .................................. 28
+ A. Collected Grammar .................................... 29
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 2]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+1. Introduction
+
+ Since its publication in 1982, RFC 822 has defined the standard
+ format of textual mail messages on the Internet. Its success has
+ been such that the RFC 822 format has been adopted, wholly or
+ partially, well beyond the confines of the Internet and the Internet
+ SMTP transport defined by RFC 821. As the format has seen wider use,
+ a number of limitations have proven increasingly restrictive for the
+ user community.
+
+ RFC 822 was intended to specify a format for text messages. As such,
+ non-text messages, such as multimedia messages that might include
+ audio or images, are simply not mentioned. Even in the case of text,
+ however, RFC 822 is inadequate for the needs of mail users whose
+ languages require the use of character sets richer than US-ASCII.
+ Since RFC 822 does not specify mechanisms for mail containing audio,
+ video, Asian language text, or even text in most European languages,
+ additional specifications are needed.
+
+ One of the notable limitations of RFC 821/822 based mail systems is
+ the fact that they limit the contents of electronic mail messages to
+ relatively short lines (e.g. 1000 characters or less [RFC-821]) of
+ 7bit US-ASCII. This forces users to convert any non-textual data
+ that they may wish to send into seven-bit bytes representable as
+ printable US-ASCII characters before invoking a local mail UA (User
+ Agent, a program with which human users send and receive mail).
+ Examples of such encodings currently used in the Internet include
+ pure hexadecimal, uuencode, the 3-in-4 base 64 scheme specified in
+ RFC 1421, the Andrew Toolkit Representation [ATK], and many others.
+
+ The limitations of RFC 822 mail become even more apparent as gateways
+ are designed to allow for the exchange of mail messages between RFC
+ 822 hosts and X.400 hosts. X.400 [X400] specifies mechanisms for the
+ inclusion of non-textual material within electronic mail messages.
+ The current standards for the mapping of X.400 messages to RFC 822
+ messages specify either that X.400 non-textual material must be
+ converted to (not encoded in) IA5Text format, or that they must be
+ discarded, notifying the RFC 822 user that discarding has occurred.
+ This is clearly undesirable, as information that a user may wish to
+ receive is lost. Even though a user agent may not have the
+ capability of dealing with the non-textual material, the user might
+ have some mechanism external to the UA that can extract useful
+ information from the material. Moreover, it does not allow for the
+ fact that the message may eventually be gatewayed back into an X.400
+ message handling system (i.e., the X.400 message is "tunneled"
+ through Internet mail), where the non-textual information would
+ definitely become useful again.
+
+
+
+
+Freed & Borenstein Standards Track [Page 3]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ This document describes several mechanisms that combine to solve most
+ of these problems without introducing any serious incompatibilities
+ with the existing world of RFC 822 mail. In particular, it
+ describes:
+
+ (1) A MIME-Version header field, which uses a version
+ number to declare a message to be conformant with MIME
+ and allows mail processing agents to distinguish
+ between such messages and those generated by older or
+ non-conformant software, which are presumed to lack
+ such a field.
+
+ (2) A Content-Type header field, generalized from RFC 1049,
+ which can be used to specify the media type and subtype
+ of data in the body of a message and to fully specify
+ the native representation (canonical form) of such
+ data.
+
+ (3) A Content-Transfer-Encoding header field, which can be
+ used to specify both the encoding transformation that
+ was applied to the body and the domain of the result.
+ Encoding transformations other than the identity
+ transformation are usually applied to data in order to
+ allow it to pass through mail transport mechanisms
+ which may have data or character set limitations.
+
+ (4) Two additional header fields that can be used to
+ further describe the data in a body, the Content-ID and
+ Content-Description header fields.
+
+ All of the header fields defined in this document are subject to the
+ general syntactic rules for header fields specified in RFC 822. In
+ particular, all of these header fields except for Content-Disposition
+ can include RFC 822 comments, which have no semantic content and
+ should be ignored during MIME processing.
+
+ Finally, to specify and promote interoperability, RFC 2049 provides a
+ basic applicability statement for a subset of the above mechanisms
+ that defines a minimal level of "conformance" with this document.
+
+ HISTORICAL NOTE: Several of the mechanisms described in this set of
+ documents may seem somewhat strange or even baroque at first reading.
+ It is important to note that compatibility with existing standards
+ AND robustness across existing practice were two of the highest
+ priorities of the working group that developed this set of documents.
+ In particular, compatibility was always favored over elegance.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 4]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ Please refer to the current edition of the "Internet Official
+ Protocol Standards" for the standardization state and status of this
+ protocol. RFC 822 and STD 3, RFC 1123 also provide essential
+ background for MIME since no conforming implementation of MIME can
+ violate them. In addition, several other informational RFC documents
+ will be of interest to the MIME implementor, in particular RFC 1344,
+ RFC 1345, and RFC 1524.
+
+2. Definitions, Conventions, and Generic BNF Grammar
+
+ Although the mechanisms specified in this set of documents are all
+ described in prose, most are also described formally in the augmented
+ BNF notation of RFC 822. Implementors will need to be familiar with
+ this notation in order to understand this set of documents, and are
+ referred to RFC 822 for a complete explanation of the augmented BNF
+ notation.
+
+ Some of the augmented BNF in this set of documents makes named
+ references to syntax rules defined in RFC 822. A complete formal
+ grammar, then, is obtained by combining the collected grammar
+ appendices in each document in this set with the BNF of RFC 822 plus
+ the modifications to RFC 822 defined in RFC 1123 (which specifically
+ changes the syntax for `return', `date' and `mailbox').
+
+ All numeric and octet values are given in decimal notation in this
+ set of documents. All media type values, subtype values, and
+ parameter names as defined are case-insensitive. However, parameter
+ values are case-sensitive unless otherwise specified for the specific
+ parameter.
+
+ FORMATTING NOTE: Notes, such at this one, provide additional
+ nonessential information which may be skipped by the reader without
+ missing anything essential. The primary purpose of these non-
+ essential notes is to convey information about the rationale of this
+ set of documents, or to place these documents in the proper
+ historical or evolutionary context. Such information may in
+ particular be skipped by those who are focused entirely on building a
+ conformant implementation, but may be of use to those who wish to
+ understand why certain design choices were made.
+
+2.1. CRLF
+
+ The term CRLF, in this set of documents, refers to the sequence of
+ octets corresponding to the two US-ASCII characters CR (decimal value
+ 13) and LF (decimal value 10) which, taken together, in this order,
+ denote a line break in RFC 822 mail.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 5]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+2.2. Character Set
+
+ The term "character set" is used in MIME to refer to a method of
+ converting a sequence of octets into a sequence of characters. Note
+ that unconditional and unambiguous conversion in the other direction
+ is not required, in that not all characters may be representable by a
+ given character set and a character set may provide more than one
+ sequence of octets to represent a particular sequence of characters.
+
+ This definition is intended to allow various kinds of character
+ encodings, from simple single-table mappings such as US-ASCII to
+ complex table switching methods such as those that use ISO 2022's
+ techniques, to be used as character sets. However, the definition
+ associated with a MIME character set name must fully specify the
+ mapping to be performed. In particular, use of external profiling
+ information to determine the exact mapping is not permitted.
+
+ NOTE: The term "character set" was originally to describe such
+ straightforward schemes as US-ASCII and ISO-8859-1 which have a
+ simple one-to-one mapping from single octets to single characters.
+ Multi-octet coded character sets and switching techniques make the
+ situation more complex. For example, some communities use the term
+ "character encoding" for what MIME calls a "character set", while
+ using the phrase "coded character set" to denote an abstract mapping
+ from integers (not octets) to characters.
+
+2.3. Message
+
+ The term "message", when not further qualified, means either a
+ (complete or "top-level") RFC 822 message being transferred on a
+ network, or a message encapsulated in a body of type "message/rfc822"
+ or "message/partial".
+
+2.4. Entity
+
+ The term "entity", refers specifically to the MIME-defined header
+ fields and contents of either a message or one of the parts in the
+ body of a multipart entity. The specification of such entities is
+ the essence of MIME. Since the contents of an entity are often
+ called the "body", it makes sense to speak about the body of an
+ entity. Any sort of field may be present in the header of an entity,
+ but only those fields whose names begin with "content-" actually have
+ any MIME-related meaning. Note that this does NOT imply thay they
+ have no meaning at all -- an entity that is also a message has non-
+ MIME header fields whose meanings are defined by RFC 822.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 6]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+2.5. Body Part
+
+ The term "body part" refers to an entity inside of a multipart
+ entity.
+
+2.6. Body
+
+ The term "body", when not further qualified, means the body of an
+ entity, that is, the body of either a message or of a body part.
+
+ NOTE: The previous four definitions are clearly circular. This is
+ unavoidable, since the overall structure of a MIME message is indeed
+ recursive.
+
+2.7. 7bit Data
+
+ "7bit data" refers to data that is all represented as relatively
+ short lines with 998 octets or less between CRLF line separation
+ sequences [RFC-821]. No octets with decimal values greater than 127
+ are allowed and neither are NULs (octets with decimal value 0). CR
+ (decimal value 13) and LF (decimal value 10) octets only occur as
+ part of CRLF line separation sequences.
+
+2.8. 8bit Data
+
+ "8bit data" refers to data that is all represented as relatively
+ short lines with 998 octets or less between CRLF line separation
+ sequences [RFC-821]), but octets with decimal values greater than 127
+ may be used. As with "7bit data" CR and LF octets only occur as part
+ of CRLF line separation sequences and no NULs are allowed.
+
+2.9. Binary Data
+
+ "Binary data" refers to data where any sequence of octets whatsoever
+ is allowed.
+
+2.10. Lines
+
+ "Lines" are defined as sequences of octets separated by a CRLF
+ sequences. This is consistent with both RFC 821 and RFC 822.
+ "Lines" only refers to a unit of data in a message, which may or may
+ not correspond to something that is actually displayed by a user
+ agent.
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 7]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+3. MIME Header Fields
+
+ MIME defines a number of new RFC 822 header fields that are used to
+ describe the content of a MIME entity. These header fields occur in
+ at least two contexts:
+
+ (1) As part of a regular RFC 822 message header.
+
+ (2) In a MIME body part header within a multipart
+ construct.
+
+ The formal definition of these header fields is as follows:
+
+ entity-headers := [ content CRLF ]
+ [ encoding CRLF ]
+ [ id CRLF ]
+ [ description CRLF ]
+ *( MIME-extension-field CRLF )
+
+ MIME-message-headers := entity-headers
+ fields
+ version CRLF
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+
+ MIME-part-headers := entity-headers
+ [ fields ]
+ ; Any field not beginning with
+ ; "content-" can have no defined
+ ; meaning and may be ignored.
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+
+ The syntax of the various specific MIME header fields will be
+ described in the following sections.
+
+4. MIME-Version Header Field
+
+ Since RFC 822 was published in 1982, there has really been only one
+ format standard for Internet messages, and there has been little
+ perceived need to declare the format standard in use. This document
+ is an independent specification that complements RFC 822. Although
+ the extensions in this document have been defined in such a way as to
+ be compatible with RFC 822, there are still circumstances in which it
+ might be desirable for a mail-processing agent to know whether a
+ message was composed with the new standard in mind.
+
+
+
+Freed & Borenstein Standards Track [Page 8]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ Therefore, this document defines a new header field, "MIME-Version",
+ which is to be used to declare the version of the Internet message
+ body format standard in use.
+
+ Messages composed in accordance with this document MUST include such
+ a header field, with the following verbatim text:
+
+ MIME-Version: 1.0
+
+ The presence of this header field is an assertion that the message
+ has been composed in compliance with this document.
+
+ Since it is possible that a future document might extend the message
+ format standard again, a formal BNF is given for the content of the
+ MIME-Version field:
+
+ version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+
+ Thus, future format specifiers, which might replace or extend "1.0",
+ are constrained to be two integer fields, separated by a period. If
+ a message is received with a MIME-version value other than "1.0", it
+ cannot be assumed to conform with this document.
+
+ Note that the MIME-Version header field is required at the top level
+ of a message. It is not required for each body part of a multipart
+ entity. It is required for the embedded headers of a body of type
+ "message/rfc822" or "message/partial" if and only if the embedded
+ message is itself claimed to be MIME-conformant.
+
+ It is not possible to fully specify how a mail reader that conforms
+ with MIME as defined in this document should treat a message that
+ might arrive in the future with some value of MIME-Version other than
+ "1.0".
+
+ It is also worth noting that version control for specific media types
+ is not accomplished using the MIME-Version mechanism. In particular,
+ some formats (such as application/postscript) have version numbering
+ conventions that are internal to the media format. Where such
+ conventions exist, MIME does nothing to supersede them. Where no
+ such conventions exist, a MIME media type might use a "version"
+ parameter in the content-type field if necessary.
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 9]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ NOTE TO IMPLEMENTORS: When checking MIME-Version values any RFC 822
+ comment strings that are present must be ignored. In particular, the
+ following four MIME-Version fields are equivalent:
+
+ MIME-Version: 1.0
+
+ MIME-Version: 1.0 (produced by MetaSend Vx.x)
+
+ MIME-Version: (produced by MetaSend Vx.x) 1.0
+
+ MIME-Version: 1.(produced by MetaSend Vx.x)0
+
+ In the absence of a MIME-Version field, a receiving mail user agent
+ (whether conforming to MIME requirements or not) may optionally
+ choose to interpret the body of the message according to local
+ conventions. Many such conventions are currently in use and it
+ should be noted that in practice non-MIME messages can contain just
+ about anything.
+
+ It is impossible to be certain that a non-MIME mail message is
+ actually plain text in the US-ASCII character set since it might well
+ be a message that, using some set of nonstandard local conventions
+ that predate MIME, includes text in another character set or non-
+ textual data presented in a manner that cannot be automatically
+ recognized (e.g., a uuencoded compressed UNIX tar file).
+
+5. Content-Type Header Field
+
+ The purpose of the Content-Type field is to describe the data
+ contained in the body fully enough that the receiving user agent can
+ pick an appropriate agent or mechanism to present the data to the
+ user, or otherwise deal with the data in an appropriate manner. The
+ value in this field is called a media type.
+
+ HISTORICAL NOTE: The Content-Type header field was first defined in
+ RFC 1049. RFC 1049 used a simpler and less powerful syntax, but one
+ that is largely compatible with the mechanism given here.
+
+ The Content-Type header field specifies the nature of the data in the
+ body of an entity by giving media type and subtype identifiers, and
+ by providing auxiliary information that may be required for certain
+ media types. After the media type and subtype names, the remainder
+ of the header field is simply a set of parameters, specified in an
+ attribute=value notation. The ordering of parameters is not
+ significant.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 10]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ In general, the top-level media type is used to declare the general
+ type of data, while the subtype specifies a specific format for that
+ type of data. Thus, a media type of "image/xyz" is enough to tell a
+ user agent that the data is an image, even if the user agent has no
+ knowledge of the specific image format "xyz". Such information can
+ be used, for example, to decide whether or not to show a user the raw
+ data from an unrecognized subtype -- such an action might be
+ reasonable for unrecognized subtypes of text, but not for
+ unrecognized subtypes of image or audio. For this reason, registered
+ subtypes of text, image, audio, and video should not contain embedded
+ information that is really of a different type. Such compound
+ formats should be represented using the "multipart" or "application"
+ types.
+
+ Parameters are modifiers of the media subtype, and as such do not
+ fundamentally affect the nature of the content. The set of
+ meaningful parameters depends on the media type and subtype. Most
+ parameters are associated with a single specific subtype. However, a
+ given top-level media type may define parameters which are applicable
+ to any subtype of that type. Parameters may be required by their
+ defining content type or subtype or they may be optional. MIME
+ implementations must ignore any parameters whose names they do not
+ recognize.
+
+ For example, the "charset" parameter is applicable to any subtype of
+ "text", while the "boundary" parameter is required for any subtype of
+ the "multipart" media type.
+
+ There are NO globally-meaningful parameters that apply to all media
+ types. Truly global mechanisms are best addressed, in the MIME
+ model, by the definition of additional Content-* header fields.
+
+ An initial set of seven top-level media types is defined in RFC 2046.
+ Five of these are discrete types whose content is essentially opaque
+ as far as MIME processing is concerned. The remaining two are
+ composite types whose contents require additional handling by MIME
+ processors.
+
+ This set of top-level media types is intended to be substantially
+ complete. It is expected that additions to the larger set of
+ supported types can generally be accomplished by the creation of new
+ subtypes of these initial types. In the future, more top-level types
+ may be defined only by a standards-track extension to this standard.
+ If another top-level type is to be used for any reason, it must be
+ given a name starting with "X-" to indicate its non-standard status
+ and to avoid a potential conflict with a future official name.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 11]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+5.1. Syntax of the Content-Type Header Field
+
+ In the Augmented BNF notation of RFC 822, a Content-Type header field
+ value is defined as follows:
+
+ content := "Content-Type" ":" type "/" subtype
+ *(";" parameter)
+ ; Matching of media type and subtype
+ ; is ALWAYS case-insensitive.
+
+ type := discrete-type / composite-type
+
+ discrete-type := "text" / "image" / "audio" / "video" /
+ "application" / extension-token
+
+ composite-type := "message" / "multipart" / extension-token
+
+ extension-token := ietf-token / x-token
+
+ ietf-token := <An extension token defined by a
+ standards-track RFC and registered
+ with IANA.>
+
+ x-token := <The two characters "X-" or "x-" followed, with
+ no intervening white space, by any token>
+
+ subtype := extension-token / iana-token
+
+ iana-token := <A publicly-defined extension token. Tokens
+ of this form must be registered with IANA
+ as specified in RFC 2048.>
+
+ parameter := attribute "=" value
+
+ attribute := token
+ ; Matching of attributes
+ ; is ALWAYS case-insensitive.
+
+ value := token / quoted-string
+
+ token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+ or tspecials>
+
+ tspecials := "(" / ")" / "<" / ">" / "@" /
+ "," / ";" / ":" / "\" / <">
+ "/" / "[" / "]" / "?" / "="
+ ; Must be in quoted-string,
+ ; to use within parameter values
+
+
+
+Freed & Borenstein Standards Track [Page 12]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ Note that the definition of "tspecials" is the same as the RFC 822
+ definition of "specials" with the addition of the three characters
+ "/", "?", and "=", and the removal of ".".
+
+ Note also that a subtype specification is MANDATORY -- it may not be
+ omitted from a Content-Type header field. As such, there are no
+ default subtypes.
+
+ The type, subtype, and parameter names are not case sensitive. For
+ example, TEXT, Text, and TeXt are all equivalent top-level media
+ types. Parameter values are normally case sensitive, but sometimes
+ are interpreted in a case-insensitive fashion, depending on the
+ intended use. (For example, multipart boundaries are case-sensitive,
+ but the "access-type" parameter for message/External-body is not
+ case-sensitive.)
+
+ Note that the value of a quoted string parameter does not include the
+ quotes. That is, the quotation marks in a quoted-string are not a
+ part of the value of the parameter, but are merely used to delimit
+ that parameter value. In addition, comments are allowed in
+ accordance with RFC 822 rules for structured header fields. Thus the
+ following two forms
+
+ Content-type: text/plain; charset=us-ascii (Plain text)
+
+ Content-type: text/plain; charset="us-ascii"
+
+ are completely equivalent.
+
+ Beyond this syntax, the only syntactic constraint on the definition
+ of subtype names is the desire that their uses must not conflict.
+ That is, it would be undesirable to have two different communities
+ using "Content-Type: application/foobar" to mean two different
+ things. The process of defining new media subtypes, then, is not
+ intended to be a mechanism for imposing restrictions, but simply a
+ mechanism for publicizing their definition and usage. There are,
+ therefore, two acceptable mechanisms for defining new media subtypes:
+
+ (1) Private values (starting with "X-") may be defined
+ bilaterally between two cooperating agents without
+ outside registration or standardization. Such values
+ cannot be registered or standardized.
+
+ (2) New standard values should be registered with IANA as
+ described in RFC 2048.
+
+ The second document in this set, RFC 2046, defines the initial set of
+ media types for MIME.
+
+
+
+Freed & Borenstein Standards Track [Page 13]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+5.2. Content-Type Defaults
+
+ Default RFC 822 messages without a MIME Content-Type header are taken
+ by this protocol to be plain text in the US-ASCII character set,
+ which can be explicitly specified as:
+
+ Content-type: text/plain; charset=us-ascii
+
+ This default is assumed if no Content-Type header field is specified.
+ It is also recommend that this default be assumed when a
+ syntactically invalid Content-Type header field is encountered. In
+ the presence of a MIME-Version header field and the absence of any
+ Content-Type header field, a receiving User Agent can also assume
+ that plain US-ASCII text was the sender's intent. Plain US-ASCII
+ text may still be assumed in the absence of a MIME-Version or the
+ presence of an syntactically invalid Content-Type header field, but
+ the sender's intent might have been otherwise.
+
+6. Content-Transfer-Encoding Header Field
+
+ Many media types which could be usefully transported via email are
+ represented, in their "natural" format, as 8bit character or binary
+ data. Such data cannot be transmitted over some transfer protocols.
+ For example, RFC 821 (SMTP) restricts mail messages to 7bit US-ASCII
+ data with lines no longer than 1000 characters including any trailing
+ CRLF line separator.
+
+ It is necessary, therefore, to define a standard mechanism for
+ encoding such data into a 7bit short line format. Proper labelling
+ of unencoded material in less restrictive formats for direct use over
+ less restrictive transports is also desireable. This document
+ specifies that such encodings will be indicated by a new "Content-
+ Transfer-Encoding" header field. This field has not been defined by
+ any previous standard.
+
+6.1. Content-Transfer-Encoding Syntax
+
+ The Content-Transfer-Encoding field's value is a single token
+ specifying the type of encoding, as enumerated below. Formally:
+
+ encoding := "Content-Transfer-Encoding" ":" mechanism
+
+ mechanism := "7bit" / "8bit" / "binary" /
+ "quoted-printable" / "base64" /
+ ietf-token / x-token
+
+ These values are not case sensitive -- Base64 and BASE64 and bAsE64
+ are all equivalent. An encoding type of 7BIT requires that the body
+
+
+
+Freed & Borenstein Standards Track [Page 14]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ is already in a 7bit mail-ready representation. This is the default
+ value -- that is, "Content-Transfer-Encoding: 7BIT" is assumed if the
+ Content-Transfer-Encoding header field is not present.
+
+6.2. Content-Transfer-Encodings Semantics
+
+ This single Content-Transfer-Encoding token actually provides two
+ pieces of information. It specifies what sort of encoding
+ transformation the body was subjected to and hence what decoding
+ operation must be used to restore it to its original form, and it
+ specifies what the domain of the result is.
+
+ The transformation part of any Content-Transfer-Encodings specifies,
+ either explicitly or implicitly, a single, well-defined decoding
+ algorithm, which for any sequence of encoded octets either transforms
+ it to the original sequence of octets which was encoded, or shows
+ that it is illegal as an encoded sequence. Content-Transfer-
+ Encodings transformations never depend on any additional external
+ profile information for proper operation. Note that while decoders
+ must produce a single, well-defined output for a valid encoding no
+ such restrictions exist for encoders: Encoding a given sequence of
+ octets to different, equivalent encoded sequences is perfectly legal.
+
+ Three transformations are currently defined: identity, the "quoted-
+ printable" encoding, and the "base64" encoding. The domains are
+ "binary", "8bit" and "7bit".
+
+ The Content-Transfer-Encoding values "7bit", "8bit", and "binary" all
+ mean that the identity (i.e. NO) encoding transformation has been
+ performed. As such, they serve simply as indicators of the domain of
+ the body data, and provide useful information about the sort of
+ encoding that might be needed for transmission in a given transport
+ system. The terms "7bit data", "8bit data", and "binary data" are
+ all defined in Section 2.
+
+ The quoted-printable and base64 encodings transform their input from
+ an arbitrary domain into material in the "7bit" range, thus making it
+ safe to carry over restricted transports. The specific definition of
+ the transformations are given below.
+
+ The proper Content-Transfer-Encoding label must always be used.
+ Labelling unencoded data containing 8bit characters as "7bit" is not
+ allowed, nor is labelling unencoded non-line-oriented data as
+ anything other than "binary" allowed.
+
+ Unlike media subtypes, a proliferation of Content-Transfer-Encoding
+ values is both undesirable and unnecessary. However, establishing
+ only a single transformation into the "7bit" domain does not seem
+
+
+
+Freed & Borenstein Standards Track [Page 15]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ possible. There is a tradeoff between the desire for a compact and
+ efficient encoding of largely- binary data and the desire for a
+ somewhat readable encoding of data that is mostly, but not entirely,
+ 7bit. For this reason, at least two encoding mechanisms are
+ necessary: a more or less readable encoding (quoted-printable) and a
+ "dense" or "uniform" encoding (base64).
+
+ Mail transport for unencoded 8bit data is defined in RFC 1652. As of
+ the initial publication of this document, there are no standardized
+ Internet mail transports for which it is legitimate to include
+ unencoded binary data in mail bodies. Thus there are no
+ circumstances in which the "binary" Content-Transfer-Encoding is
+ actually valid in Internet mail. However, in the event that binary
+ mail transport becomes a reality in Internet mail, or when MIME is
+ used in conjunction with any other binary-capable mail transport
+ mechanism, binary bodies must be labelled as such using this
+ mechanism.
+
+ NOTE: The five values defined for the Content-Transfer-Encoding field
+ imply nothing about the media type other than the algorithm by which
+ it was encoded or the transport system requirements if unencoded.
+
+6.3. New Content-Transfer-Encodings
+
+ Implementors may, if necessary, define private Content-Transfer-
+ Encoding values, but must use an x-token, which is a name prefixed by
+ "X-", to indicate its non-standard status, e.g., "Content-Transfer-
+ Encoding: x-my-new-encoding". Additional standardized Content-
+ Transfer-Encoding values must be specified by a standards-track RFC.
+ The requirements such specifications must meet are given in RFC 2048.
+ As such, all content-transfer-encoding namespace except that
+ beginning with "X-" is explicitly reserved to the IETF for future
+ use.
+
+ Unlike media types and subtypes, the creation of new Content-
+ Transfer-Encoding values is STRONGLY discouraged, as it seems likely
+ to hinder interoperability with little potential benefit
+
+6.4. Interpretation and Use
+
+ If a Content-Transfer-Encoding header field appears as part of a
+ message header, it applies to the entire body of that message. If a
+ Content-Transfer-Encoding header field appears as part of an entity's
+ headers, it applies only to the body of that entity. If an entity is
+ of type "multipart" the Content-Transfer-Encoding is not permitted to
+ have any value other than "7bit", "8bit" or "binary". Even more
+ severe restrictions apply to some subtypes of the "message" type.
+
+
+
+
+Freed & Borenstein Standards Track [Page 16]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ It should be noted that most media types are defined in terms of
+ octets rather than bits, so that the mechanisms described here are
+ mechanisms for encoding arbitrary octet streams, not bit streams. If
+ a bit stream is to be encoded via one of these mechanisms, it must
+ first be converted to an 8bit byte stream using the network standard
+ bit order ("big-endian"), in which the earlier bits in a stream
+ become the higher-order bits in a 8bit byte. A bit stream not ending
+ at an 8bit boundary must be padded with zeroes. RFC 2046 provides a
+ mechanism for noting the addition of such padding in the case of the
+ application/octet-stream media type, which has a "padding" parameter.
+
+ The encoding mechanisms defined here explicitly encode all data in
+ US-ASCII. Thus, for example, suppose an entity has header fields
+ such as:
+
+ Content-Type: text/plain; charset=ISO-8859-1
+ Content-transfer-encoding: base64
+
+ This must be interpreted to mean that the body is a base64 US-ASCII
+ encoding of data that was originally in ISO-8859-1, and will be in
+ that character set again after decoding.
+
+ Certain Content-Transfer-Encoding values may only be used on certain
+ media types. In particular, it is EXPRESSLY FORBIDDEN to use any
+ encodings other than "7bit", "8bit", or "binary" with any composite
+ media type, i.e. one that recursively includes other Content-Type
+ fields. Currently the only composite media types are "multipart" and
+ "message". All encodings that are desired for bodies of type
+ multipart or message must be done at the innermost level, by encoding
+ the actual body that needs to be encoded.
+
+ It should also be noted that, by definition, if a composite entity
+ has a transfer-encoding value such as "7bit", but one of the enclosed
+ entities has a less restrictive value such as "8bit", then either the
+ outer "7bit" labelling is in error, because 8bit data are included,
+ or the inner "8bit" labelling placed an unnecessarily high demand on
+ the transport system because the actual included data were actually
+ 7bit-safe.
+
+ NOTE ON ENCODING RESTRICTIONS: Though the prohibition against using
+ content-transfer-encodings on composite body data may seem overly
+ restrictive, it is necessary to prevent nested encodings, in which
+ data are passed through an encoding algorithm multiple times, and
+ must be decoded multiple times in order to be properly viewed.
+ Nested encodings add considerable complexity to user agents: Aside
+ from the obvious efficiency problems with such multiple encodings,
+ they can obscure the basic structure of a message. In particular,
+ they can imply that several decoding operations are necessary simply
+
+
+
+Freed & Borenstein Standards Track [Page 17]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ to find out what types of bodies a message contains. Banning nested
+ encodings may complicate the job of certain mail gateways, but this
+ seems less of a problem than the effect of nested encodings on user
+ agents.
+
+ Any entity with an unrecognized Content-Transfer-Encoding must be
+ treated as if it has a Content-Type of "application/octet-stream",
+ regardless of what the Content-Type header field actually says.
+
+ NOTE ON THE RELATIONSHIP BETWEEN CONTENT-TYPE AND CONTENT-TRANSFER-
+ ENCODING: It may seem that the Content-Transfer-Encoding could be
+ inferred from the characteristics of the media that is to be encoded,
+ or, at the very least, that certain Content-Transfer-Encodings could
+ be mandated for use with specific media types. There are several
+ reasons why this is not the case. First, given the varying types of
+ transports used for mail, some encodings may be appropriate for some
+ combinations of media types and transports but not for others. (For
+ example, in an 8bit transport, no encoding would be required for text
+ in certain character sets, while such encodings are clearly required
+ for 7bit SMTP.)
+
+ Second, certain media types may require different types of transfer
+ encoding under different circumstances. For example, many PostScript
+ bodies might consist entirely of short lines of 7bit data and hence
+ require no encoding at all. Other PostScript bodies (especially
+ those using Level 2 PostScript's binary encoding mechanism) may only
+ be reasonably represented using a binary transport encoding.
+ Finally, since the Content-Type field is intended to be an open-ended
+ specification mechanism, strict specification of an association
+ between media types and encodings effectively couples the
+ specification of an application protocol with a specific lower-level
+ transport. This is not desirable since the developers of a media
+ type should not have to be aware of all the transports in use and
+ what their limitations are.
+
+6.5. Translating Encodings
+
+ The quoted-printable and base64 encodings are designed so that
+ conversion between them is possible. The only issue that arises in
+ such a conversion is the handling of hard line breaks in quoted-
+ printable encoding output. When converting from quoted-printable to
+ base64 a hard line break in the quoted-printable form represents a
+ CRLF sequence in the canonical form of the data. It must therefore be
+ converted to a corresponding encoded CRLF in the base64 form of the
+ data. Similarly, a CRLF sequence in the canonical form of the data
+ obtained after base64 decoding must be converted to a quoted-
+ printable hard line break, but ONLY when converting text data.
+
+
+
+
+Freed & Borenstein Standards Track [Page 18]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+6.6. Canonical Encoding Model
+
+ There was some confusion, in the previous versions of this RFC,
+ regarding the model for when email data was to be converted to
+ canonical form and encoded, and in particular how this process would
+ affect the treatment of CRLFs, given that the representation of
+ newlines varies greatly from system to system, and the relationship
+ between content-transfer-encodings and character sets. A canonical
+ model for encoding is presented in RFC 2049 for this reason.
+
+6.7. Quoted-Printable Content-Transfer-Encoding
+
+ The Quoted-Printable encoding is intended to represent data that
+ largely consists of octets that correspond to printable characters in
+ the US-ASCII character set. It encodes the data in such a way that
+ the resulting octets are unlikely to be modified by mail transport.
+ If the data being encoded are mostly US-ASCII text, the encoded form
+ of the data remains largely recognizable by humans. A body which is
+ entirely US-ASCII may also be encoded in Quoted-Printable to ensure
+ the integrity of the data should the message pass through a
+ character-translating, and/or line-wrapping gateway.
+
+ In this encoding, octets are to be represented as determined by the
+ following rules:
+
+ (1) (General 8bit representation) Any octet, except a CR or
+ LF that is part of a CRLF line break of the canonical
+ (standard) form of the data being encoded, may be
+ represented by an "=" followed by a two digit
+ hexadecimal representation of the octet's value. The
+ digits of the hexadecimal alphabet, for this purpose,
+ are "0123456789ABCDEF". Uppercase letters must be
+ used; lowercase letters are not allowed. Thus, for
+ example, the decimal value 12 (US-ASCII form feed) can
+ be represented by "=0C", and the decimal value 61 (US-
+ ASCII EQUAL SIGN) can be represented by "=3D". This
+ rule must be followed except when the following rules
+ allow an alternative encoding.
+
+ (2) (Literal representation) Octets with decimal values of
+ 33 through 60 inclusive, and 62 through 126, inclusive,
+ MAY be represented as the US-ASCII characters which
+ correspond to those octets (EXCLAMATION POINT through
+ LESS THAN, and GREATER THAN through TILDE,
+ respectively).
+
+ (3) (White Space) Octets with values of 9 and 32 MAY be
+ represented as US-ASCII TAB (HT) and SPACE characters,
+
+
+
+Freed & Borenstein Standards Track [Page 19]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ respectively, but MUST NOT be so represented at the end
+ of an encoded line. Any TAB (HT) or SPACE characters
+ on an encoded line MUST thus be followed on that line
+ by a printable character. In particular, an "=" at the
+ end of an encoded line, indicating a soft line break
+ (see rule #5) may follow one or more TAB (HT) or SPACE
+ characters. It follows that an octet with decimal
+ value 9 or 32 appearing at the end of an encoded line
+ must be represented according to Rule #1. This rule is
+ necessary because some MTAs (Message Transport Agents,
+ programs which transport messages from one user to
+ another, or perform a portion of such transfers) are
+ known to pad lines of text with SPACEs, and others are
+ known to remove "white space" characters from the end
+ of a line. Therefore, when decoding a Quoted-Printable
+ body, any trailing white space on a line must be
+ deleted, as it will necessarily have been added by
+ intermediate transport agents.
+
+ (4) (Line Breaks) A line break in a text body, represented
+ as a CRLF sequence in the text canonical form, must be
+ represented by a (RFC 822) line break, which is also a
+ CRLF sequence, in the Quoted-Printable encoding. Since
+ the canonical representation of media types other than
+ text do not generally include the representation of
+ line breaks as CRLF sequences, no hard line breaks
+ (i.e. line breaks that are intended to be meaningful
+ and to be displayed to the user) can occur in the
+ quoted-printable encoding of such types. Sequences
+ like "=0D", "=0A", "=0A=0D" and "=0D=0A" will routinely
+ appear in non-text data represented in quoted-
+ printable, of course.
+
+ Note that many implementations may elect to encode the
+ local representation of various content types directly
+ rather than converting to canonical form first,
+ encoding, and then converting back to local
+ representation. In particular, this may apply to plain
+ text material on systems that use newline conventions
+ other than a CRLF terminator sequence. Such an
+ implementation optimization is permissible, but only
+ when the combined canonicalization-encoding step is
+ equivalent to performing the three steps separately.
+
+ (5) (Soft Line Breaks) The Quoted-Printable encoding
+ REQUIRES that encoded lines be no more than 76
+ characters long. If longer lines are to be encoded
+ with the Quoted-Printable encoding, "soft" line breaks
+
+
+
+Freed & Borenstein Standards Track [Page 20]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ must be used. An equal sign as the last character on a
+ encoded line indicates such a non-significant ("soft")
+ line break in the encoded text.
+
+ Thus if the "raw" form of the line is a single unencoded line that
+ says:
+
+ Now's the time for all folk to come to the aid of their country.
+
+ This can be represented, in the Quoted-Printable encoding, as:
+
+ Now's the time =
+ for all folk to come=
+ to the aid of their country.
+
+ This provides a mechanism with which long lines are encoded in such a
+ way as to be restored by the user agent. The 76 character limit does
+ not count the trailing CRLF, but counts all other characters,
+ including any equal signs.
+
+ Since the hyphen character ("-") may be represented as itself in the
+ Quoted-Printable encoding, care must be taken, when encapsulating a
+ quoted-printable encoded body inside one or more multipart entities,
+ to ensure that the boundary delimiter does not appear anywhere in the
+ encoded body. (A good strategy is to choose a boundary that includes
+ a character sequence such as "=_" which can never appear in a
+ quoted-printable body. See the definition of multipart messages in
+ RFC 2046.)
+
+ NOTE: The quoted-printable encoding represents something of a
+ compromise between readability and reliability in transport. Bodies
+ encoded with the quoted-printable encoding will work reliably over
+ most mail gateways, but may not work perfectly over a few gateways,
+ notably those involving translation into EBCDIC. A higher level of
+ confidence is offered by the base64 Content-Transfer-Encoding. A way
+ to get reasonably reliable transport through EBCDIC gateways is to
+ also quote the US-ASCII characters
+
+ !"#$@[\]^`{|}~
+
+ according to rule #1.
+
+ Because quoted-printable data is generally assumed to be line-
+ oriented, it is to be expected that the representation of the breaks
+ between the lines of quoted-printable data may be altered in
+ transport, in the same manner that plain text mail has always been
+ altered in Internet mail when passing between systems with differing
+ newline conventions. If such alterations are likely to constitute a
+
+
+
+Freed & Borenstein Standards Track [Page 21]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ corruption of the data, it is probably more sensible to use the
+ base64 encoding rather than the quoted-printable encoding.
+
+ NOTE: Several kinds of substrings cannot be generated according to
+ the encoding rules for the quoted-printable content-transfer-
+ encoding, and hence are formally illegal if they appear in the output
+ of a quoted-printable encoder. This note enumerates these cases and
+ suggests ways to handle such illegal substrings if any are
+ encountered in quoted-printable data that is to be decoded.
+
+ (1) An "=" followed by two hexadecimal digits, one or both
+ of which are lowercase letters in "abcdef", is formally
+ illegal. A robust implementation might choose to
+ recognize them as the corresponding uppercase letters.
+
+ (2) An "=" followed by a character that is neither a
+ hexadecimal digit (including "abcdef") nor the CR
+ character of a CRLF pair is illegal. This case can be
+ the result of US-ASCII text having been included in a
+ quoted-printable part of a message without itself
+ having been subjected to quoted-printable encoding. A
+ reasonable approach by a robust implementation might be
+ to include the "=" character and the following
+ character in the decoded data without any
+ transformation and, if possible, indicate to the user
+ that proper decoding was not possible at this point in
+ the data.
+
+ (3) An "=" cannot be the ultimate or penultimate character
+ in an encoded object. This could be handled as in case
+ (2) above.
+
+ (4) Control characters other than TAB, or CR and LF as
+ parts of CRLF pairs, must not appear. The same is true
+ for octets with decimal values greater than 126. If
+ found in incoming quoted-printable data by a decoder, a
+ robust implementation might exclude them from the
+ decoded data and warn the user that illegal characters
+ were discovered.
+
+ (5) Encoded lines must not be longer than 76 characters,
+ not counting the trailing CRLF. If longer lines are
+ found in incoming, encoded data, a robust
+ implementation might nevertheless decode the lines, and
+ might report the erroneous encoding to the user.
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 22]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ WARNING TO IMPLEMENTORS: If binary data is encoded in quoted-
+ printable, care must be taken to encode CR and LF characters as "=0D"
+ and "=0A", respectively. In particular, a CRLF sequence in binary
+ data should be encoded as "=0D=0A". Otherwise, if CRLF were
+ represented as a hard line break, it might be incorrectly decoded on
+ platforms with different line break conventions.
+
+ For formalists, the syntax of quoted-printable data is described by
+ the following grammar:
+
+ quoted-printable := qp-line *(CRLF qp-line)
+
+ qp-line := *(qp-segment transport-padding CRLF)
+ qp-part transport-padding
+
+ qp-part := qp-section
+ ; Maximum length of 76 characters
+
+ qp-segment := qp-section *(SPACE / TAB) "="
+ ; Maximum length of 76 characters
+
+ qp-section := [*(ptext / SPACE / TAB) ptext]
+
+ ptext := hex-octet / safe-char
+
+ safe-char := <any octet with decimal value of 33 through
+ 60 inclusive, and 62 through 126>
+ ; Characters not listed as "mail-safe" in
+ ; RFC 2049 are also not recommended.
+
+ hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
+ ; Octet must be used for characters > 127, =,
+ ; SPACEs or TABs at the ends of lines, and is
+ ; recommended for any character not listed in
+ ; RFC 2049 as "mail-safe".
+
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+
+ IMPORTANT: The addition of LWSP between the elements shown in this
+ BNF is NOT allowed since this BNF does not specify a structured
+ header field.
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 23]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+6.8. Base64 Content-Transfer-Encoding
+
+ The Base64 Content-Transfer-Encoding is designed to represent
+ arbitrary sequences of octets in a form that need not be humanly
+ readable. The encoding and decoding algorithms are simple, but the
+ encoded data are consistently only about 33 percent larger than the
+ unencoded data. This encoding is virtually identical to the one used
+ in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ NOTE: This subset has the important property that it is represented
+ identically in all versions of ISO 646, including US-ASCII, and all
+ characters in the subset are also represented identically in all
+ versions of EBCDIC. Other popular encodings, such as the encoding
+ used by the uuencode utility, Macintosh binhex 4.0 [RFC-1741], and
+ the base85 encoding specified as part of Level 2 PostScript, do not
+ share these properties, and thus do not fulfill the portability
+ requirements a binary transport encoding for mail must meet.
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+ When encoding a bit stream via the base64 encoding, the bit stream
+ must be presumed to be ordered with the most-significant-bit first.
+ That is, the first bit in the stream will be the high-order bit in
+ the first 8bit byte, and the eighth bit will be the low-order bit in
+ the first 8bit byte, and so on.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string. These characters, identified in Table 1, below, are
+ selected so as to be universally representable, and the set excludes
+ characters with particular significance to SMTP (e.g., ".", CR, LF)
+ and to the multipart boundary delimiters defined in RFC 2046 (e.g.,
+ "-").
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 24]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ The encoded output stream must be represented in lines of no more
+ than 76 characters each. All line breaks or other characters not
+ found in Table 1 must be ignored by decoding software. In base64
+ data, characters other than those in Table 1, line breaks, and other
+ white space probably indicate a transmission error, about which a
+ warning message or even a message rejection might be appropriate
+ under some circumstances.
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a body. When fewer than 24 input bits
+ are available in an input group, zero bits are added (on the right)
+ to form an integral number of 6-bit groups. Padding at the end of
+ the data is performed using the "=" character. Since all base64
+ input is an integral number of octets, only the following cases can
+ arise: (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded output will be
+ an integral multiple of 4 characters with no "=" padding, (2) the
+ final quantum of encoding input is exactly 8 bits; here, the final
+ unit of encoded output will be two characters followed by two "="
+ padding characters, or (3) the final quantum of encoding input is
+ exactly 16 bits; here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+
+ Because it is used only for padding at the end of the data, the
+ occurrence of any "=" characters may be taken as evidence that the
+ end of the data has been reached (without truncation in transit). No
+
+
+
+Freed & Borenstein Standards Track [Page 25]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ such assurance is possible, however, when the number of octets
+ transmitted was a multiple of three and no "=" characters are
+ present.
+
+ Any characters outside of the base64 alphabet are to be ignored in
+ base64-encoded data.
+
+ Care must be taken to use the proper octets for line breaks if base64
+ encoding is applied directly to text material that has not been
+ converted to canonical form. In particular, text line breaks must be
+ converted into CRLF sequences prior to base64 encoding. The
+ important thing to note is that this may be done directly by the
+ encoder rather than in a prior canonicalization step in some
+ implementations.
+
+ NOTE: There is no need to worry about quoting potential boundary
+ delimiters within base64-encoded bodies within multipart entities
+ because no hyphen characters are used in the base64 encoding.
+
+7. Content-ID Header Field
+
+ In constructing a high-level user agent, it may be desirable to allow
+ one body to make reference to another. Accordingly, bodies may be
+ labelled using the "Content-ID" header field, which is syntactically
+ identical to the "Message-ID" header field:
+
+ id := "Content-ID" ":" msg-id
+
+ Like the Message-ID values, Content-ID values must be generated to be
+ world-unique.
+
+ The Content-ID value may be used for uniquely identifying MIME
+ entities in several contexts, particularly for caching data
+ referenced by the message/external-body mechanism. Although the
+ Content-ID header is generally optional, its use is MANDATORY in
+ implementations which generate data of the optional MIME media type
+ "message/external-body". That is, each message/external-body entity
+ must have a Content-ID field to permit caching of such data.
+
+ It is also worth noting that the Content-ID value has special
+ semantics in the case of the multipart/alternative media type. This
+ is explained in the section of RFC 2046 dealing with
+ multipart/alternative.
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 26]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+8. Content-Description Header Field
+
+ The ability to associate some descriptive information with a given
+ body is often desirable. For example, it may be useful to mark an
+ "image" body as "a picture of the Space Shuttle Endeavor." Such text
+ may be placed in the Content-Description header field. This header
+ field is always optional.
+
+ description := "Content-Description" ":" *text
+
+ The description is presumed to be given in the US-ASCII character
+ set, although the mechanism specified in RFC 2047 may be used for
+ non-US-ASCII Content-Description values.
+
+9. Additional MIME Header Fields
+
+ Future documents may elect to define additional MIME header fields
+ for various purposes. Any new header field that further describes
+ the content of a message should begin with the string "Content-" to
+ allow such fields which appear in a message header to be
+ distinguished from ordinary RFC 822 message header fields.
+
+ MIME-extension-field := <Any RFC 822 header field which
+ begins with the string
+ "Content-">
+
+10. Summary
+
+ Using the MIME-Version, Content-Type, and Content-Transfer-Encoding
+ header fields, it is possible to include, in a standardized way,
+ arbitrary types of data with RFC 822 conformant mail messages. No
+ restrictions imposed by either RFC 821 or RFC 822 are violated, and
+ care has been taken to avoid problems caused by additional
+ restrictions imposed by the characteristics of some Internet mail
+ transport mechanisms (see RFC 2049).
+
+ The next document in this set, RFC 2046, specifies the initial set of
+ media types that can be labelled and transported using these headers.
+
+11. Security Considerations
+
+ Security issues are discussed in the second document in this set, RFC
+ 2046.
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 27]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+12. Authors' Addresses
+
+ For more information, the authors of this document are best contacted
+ via Internet mail:
+
+ Ned Freed
+ Innosoft International, Inc.
+ 1050 East Garvey Avenue South
+ West Covina, CA 91790
+ USA
+
+ Phone: +1 818 919 3600
+ Fax: +1 818 919 3614
+ EMail: ned@innosoft.com
+
+
+ Nathaniel S. Borenstein
+ First Virtual Holdings
+ 25 Washington Avenue
+ Morristown, NJ 07960
+ USA
+
+ Phone: +1 201 540 8967
+ Fax: +1 201 993 3032
+ EMail: nsb@nsb.fv.com
+
+
+ MIME is a result of the work of the Internet Engineering Task Force
+ Working Group on RFC 822 Extensions. The chairman of that group,
+ Greg Vaudreuil, may be reached at:
+
+ Gregory M. Vaudreuil
+ Octel Network Services
+ 17080 Dallas Parkway
+ Dallas, TX 75248-1905
+ USA
+
+ EMail: Greg.Vaudreuil@Octel.Com
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 28]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+Appendix A -- Collected Grammar
+
+ This appendix contains the complete BNF grammar for all the syntax
+ specified by this document.
+
+ By itself, however, this grammar is incomplete. It refers by name to
+ several syntax rules that are defined by RFC 822. Rather than
+ reproduce those definitions here, and risk unintentional differences
+ between the two, this document simply refers the reader to RFC 822
+ for the remaining definitions. Wherever a term is undefined, it
+ refers to the RFC 822 definition.
+
+ attribute := token
+ ; Matching of attributes
+ ; is ALWAYS case-insensitive.
+
+ composite-type := "message" / "multipart" / extension-token
+
+ content := "Content-Type" ":" type "/" subtype
+ *(";" parameter)
+ ; Matching of media type and subtype
+ ; is ALWAYS case-insensitive.
+
+ description := "Content-Description" ":" *text
+
+ discrete-type := "text" / "image" / "audio" / "video" /
+ "application" / extension-token
+
+ encoding := "Content-Transfer-Encoding" ":" mechanism
+
+ entity-headers := [ content CRLF ]
+ [ encoding CRLF ]
+ [ id CRLF ]
+ [ description CRLF ]
+ *( MIME-extension-field CRLF )
+
+ extension-token := ietf-token / x-token
+
+ hex-octet := "=" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
+ ; Octet must be used for characters > 127, =,
+ ; SPACEs or TABs at the ends of lines, and is
+ ; recommended for any character not listed in
+ ; RFC 2049 as "mail-safe".
+
+ iana-token := <A publicly-defined extension token. Tokens
+ of this form must be registered with IANA
+ as specified in RFC 2048.>
+
+
+
+
+Freed & Borenstein Standards Track [Page 29]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ ietf-token := <An extension token defined by a
+ standards-track RFC and registered
+ with IANA.>
+
+ id := "Content-ID" ":" msg-id
+
+ mechanism := "7bit" / "8bit" / "binary" /
+ "quoted-printable" / "base64" /
+ ietf-token / x-token
+
+ MIME-extension-field := <Any RFC 822 header field which
+ begins with the string
+ "Content-">
+
+ MIME-message-headers := entity-headers
+ fields
+ version CRLF
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+
+ MIME-part-headers := entity-headers
+ [fields]
+ ; Any field not beginning with
+ ; "content-" can have no defined
+ ; meaning and may be ignored.
+ ; The ordering of the header
+ ; fields implied by this BNF
+ ; definition should be ignored.
+
+ parameter := attribute "=" value
+
+ ptext := hex-octet / safe-char
+
+ qp-line := *(qp-segment transport-padding CRLF)
+ qp-part transport-padding
+
+ qp-part := qp-section
+ ; Maximum length of 76 characters
+
+ qp-section := [*(ptext / SPACE / TAB) ptext]
+
+ qp-segment := qp-section *(SPACE / TAB) "="
+ ; Maximum length of 76 characters
+
+ quoted-printable := qp-line *(CRLF qp-line)
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 30]
+
+RFC 2045 Internet Message Bodies November 1996
+
+
+ safe-char := <any octet with decimal value of 33 through
+ 60 inclusive, and 62 through 126>
+ ; Characters not listed as "mail-safe" in
+ ; RFC 2049 are also not recommended.
+
+ subtype := extension-token / iana-token
+
+ token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+ or tspecials>
+
+ transport-padding := *LWSP-char
+ ; Composers MUST NOT generate
+ ; non-zero length transport
+ ; padding, but receivers MUST
+ ; be able to handle padding
+ ; added by message transports.
+
+ tspecials := "(" / ")" / "<" / ">" / "@" /
+ "," / ";" / ":" / "\" / <">
+ "/" / "[" / "]" / "?" / "="
+ ; Must be in quoted-string,
+ ; to use within parameter values
+
+ type := discrete-type / composite-type
+
+ value := token / quoted-string
+
+ version := "MIME-Version" ":" 1*DIGIT "." 1*DIGIT
+
+ x-token := <The two characters "X-" or "x-" followed, with
+ no intervening white space, by any token>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Freed & Borenstein Standards Track [Page 31]
+
diff --git a/vendor/github.com/mattermost/rsc/imap/rfc2971.txt b/vendor/github.com/mattermost/rsc/imap/rfc2971.txt
new file mode 100644
index 000000000..9e7264dcc
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/rfc2971.txt
@@ -0,0 +1,451 @@
+
+
+
+
+
+
+Network Working Group T. Showalter
+Request for Comments: 2971 Mirapoint, Inc.
+Category: Standards Track October 2000
+
+
+ IMAP4 ID extension
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+Abstract
+
+ The ID extension to the Internet Message Access Protocol - Version
+ 4rev1 (IMAP4rev1) protocol allows the server and client to exchange
+ identification information on their implementation in order to make
+ bug reports and usage statistics more complete.
+
+1. Introduction
+
+ The IMAP4rev1 protocol described in [IMAP4rev1] provides a method for
+ accessing remote mail stores, but it provides no facility to
+ advertise what program a client or server uses to provide service.
+ This makes it difficult for implementors to get complete bug reports
+ from users, as it is frequently difficult to know what client or
+ server is in use.
+
+ Additionally, some sites may wish to assemble usage statistics based
+ on what clients are used, but in an an environment where users are
+ permitted to obtain and maintain their own clients this is difficult
+ to accomplish.
+
+ The ID command provides a facility to advertise information on what
+ programs are being used along with contact information (should bugs
+ ever occur).
+
+
+
+
+
+
+
+
+Showalter Standards Track [Page 1]
+
+RFC 2971 IMAP4 ID extension October 2000
+
+
+2. Conventions Used in this Document
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in [KEYWORDS].
+
+ The conventions used in this document are the same as specified in
+ [IMAP4rev1]. In examples, "C:" and "S:" indicate lines sent by the
+ client and server respectively. Line breaks have been inserted for
+ readability.
+
+3. Specification
+
+ The sole purpose of the ID extension is to enable clients and servers
+ to exchange information on their implementations for the purposes of
+ statistical analysis and problem determination.
+
+ This information is be submitted to a server by any client wishing to
+ provide information for statistical purposes, provided the server
+ advertises its willingness to take the information with the atom "ID"
+ included in the list of capabilities returned by the CAPABILITY
+ command.
+
+ Implementations MUST NOT make operational changes based on the data
+ sent as part of the ID command or response. The ID command is for
+ human consumption only, and is not to be used in improving the
+ performance of clients or servers.
+
+ This includes, but is not limited to, the following:
+
+ Servers MUST NOT attempt to work around client bugs by using
+ information from the ID command. Clients MUST NOT attempt to work
+ around server bugs based on the ID response.
+
+ Servers MUST NOT provide features to a client or otherwise
+ optimize for a particular client by using information from the ID
+ command. Clients MUST NOT provide features to a server or
+ otherwise optimize for a particular server based on the ID
+ response.
+
+ Servers MUST NOT deny access to or refuse service for a client
+ based on information from the ID command. Clients MUST NOT refuse
+ to operate or limit their operation with a server based on the ID
+ response.
+
+
+
+
+
+
+
+Showalter Standards Track [Page 2]
+
+RFC 2971 IMAP4 ID extension October 2000
+
+
+ Rationale: It is imperative that this extension not supplant IMAP's
+ CAPABILITY mechanism with a ad-hoc approach where implementations
+ guess each other's features based on who they claim to be.
+
+ Implementations MUST NOT send false information in an ID command.
+
+ Implementations MAY send less information than they have available or
+ no information at all. Such behavior may be useful to preserve user
+ privacy. See Security Considerations, section 7.
+
+3.1. ID Command
+
+ Arguments: client parameter list or NIL
+
+ Responses: OPTIONAL untagged response: ID
+
+ Result: OK identification information accepted
+ BAD command unknown or arguments invalid
+
+ Implementation identification information is sent by the client with
+ the ID command.
+
+ This command is valid in any state.
+
+ The information sent is in the form of a list of field/value pairs.
+ Fields are permitted to be any IMAP4 string, and values are permitted
+ to be any IMAP4 string or NIL. A value of NIL indicates that the
+ client can not or will not specify this information. The client may
+ also send NIL instead of the list, indicating that it wants to send
+ no information, but would still accept a server response.
+
+ The available fields are defined in section 3.3.
+
+ Example: C: a023 ID ("name" "sodr" "version" "19.34" "vendor"
+ "Pink Floyd Music Limited")
+ S: * ID NIL
+ S: a023 OK ID completed
+
+3.2. ID Response
+
+ Contents: server parameter list
+
+ In response to an ID command issued by the client, the server replies
+ with a tagged response containing information on its implementation.
+ The format is the same as the client list.
+
+
+
+
+
+
+Showalter Standards Track [Page 3]
+
+RFC 2971 IMAP4 ID extension October 2000
+
+
+ Example: C: a042 ID NIL
+ S: * ID ("name" "Cyrus" "version" "1.5" "os" "sunos"
+ "os-version" "5.5" "support-url"
+ "mailto:cyrus-bugs+@andrew.cmu.edu")
+ S: a042 OK ID command completed
+
+ A server MUST send a tagged ID response to an ID command. However, a
+ server MAY send NIL in place of the list.
+
+3.3. Defined Field Values
+
+ Any string may be sent as a field, but the following are defined to
+ describe certain values that might be sent. Implementations are free
+ to send none, any, or all of these. Strings are not case-sensitive.
+ Field strings MUST NOT be longer than 30 octets. Value strings MUST
+ NOT be longer than 1024 octets. Implementations MUST NOT send more
+ than 30 field-value pairs.
+
+ name Name of the program
+ version Version number of the program
+ os Name of the operating system
+ os-version Version of the operating system
+ vendor Vendor of the client/server
+ support-url URL to contact for support
+ address Postal address of contact/vendor
+ date Date program was released, specified as a date-time
+ in IMAP4rev1
+ command Command used to start the program
+ arguments Arguments supplied on the command line, if any
+ if any
+ environment Description of environment, i.e., UNIX environment
+ variables or Windows registry settings
+
+ Implementations MUST NOT use contact information to submit automatic
+ bug reports. Implementations may include information from an ID
+ response in a report automatically prepared, but are prohibited from
+ sending the report without user authorization.
+
+ It is preferable to find the name and version of the underlying
+ operating system at runtime in cases where this is possible.
+
+ Information sent via an ID response may violate user privacy. See
+ Security Considerations, section 7.
+
+ Implementations MUST NOT send the same field name more than once.
+
+
+
+
+
+
+Showalter Standards Track [Page 4]
+
+RFC 2971 IMAP4 ID extension October 2000
+
+
+4. Formal Syntax
+
+ This syntax is intended to augment the grammar specified in
+ [IMAP4rev1] in order to provide for the ID command. This
+ specification uses the augmented Backus-Naur Form (BNF) notation as
+ used in [IMAP4rev1].
+
+ command_any ::= "CAPABILITY" / "LOGOUT" / "NOOP" / x_command / id
+ ;; adds id command to command_any in [IMAP4rev1]
+
+ id ::= "ID" SPACE id_params_list
+
+ id_response ::= "ID" SPACE id_params_list
+
+ id_params_list ::= "(" #(string SPACE nstring) ")" / nil
+ ;; list of field value pairs
+
+ response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
+ mailbox_data / message_data / capability_data / id_response)
+
+5. Use of the ID extension with Firewalls and Other Intermediaries
+
+ There exist proxies, firewalls, and other intermediary systems that
+ can intercept an IMAP session and make changes to the data exchanged
+ in the session. Such intermediaries are not anticipated by the IMAP4
+ protocol design and are not within the scope of the IMAP4 standard.
+ However, in order for the ID command to be useful in the presence of
+ such intermediaries, those intermediaries need to take special note
+ of the ID command and response. In particular, if an intermediary
+ changes any part of the IMAP session it must also change the ID
+ command to advertise its presence.
+
+ A firewall MAY act to block transmission of specific information
+ fields in the ID command and response that it believes reveal
+ information that could expose a security vulnerability. However, a
+ firewall SHOULD NOT disable the extension, when present, entirely,
+ and SHOULD NOT unconditionally remove either the client or server
+ list.
+
+ Finally, it should be noted that a firewall, when handling a
+ CAPABILITY response, MUST NOT allow the names of extensions to be
+ returned to the client that the firewall has no knowledge of.
+
+
+
+
+
+
+
+
+
+Showalter Standards Track [Page 5]
+
+RFC 2971 IMAP4 ID extension October 2000
+
+
+6. References
+
+ [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", RFC 2119, March 1997.
+
+ [IMAP4rev1] Crispin, M., "Internet Message Access Protocol - Version
+ 4rev1", RFC 2060, October 1996.
+
+ [RFC-822] Crocker, D., "Standard for the Format of ARPA Internet
+ Text Messages", STD 11, RFC 822, August 1982.
+
+7. Security Considerations
+
+ This extension has the danger of violating the privacy of users if
+ misused. Clients and servers should notify users that they implement
+ and enable the ID command.
+
+ It is highly desirable that implementations provide a method of
+ disabling ID support, perhaps by not sending ID at all, or by sending
+ NIL as the argument to the ID command or response.
+
+ Implementors must exercise extreme care in adding fields sent as part
+ of an ID command or response. Some fields, including a processor ID
+ number, Ethernet address, or other unique (or mostly unique)
+ identifier allow tracking of users in ways that violate user privacy
+ expectations.
+
+ Having implementation information of a given client or server may
+ make it easier for an attacker to gain unauthorized access due to
+ security holes.
+
+ Since this command includes arbitrary data and does not require the
+ user to authenticate, server implementations are cautioned to guard
+ against an attacker sending arbitrary garbage data in order to fill
+ up the ID log. In particular, if a server naively logs each ID
+ command to disk without inspecting it, an attacker can simply fire up
+ thousands of connections and send a few kilobytes of random data.
+ Servers have to guard against this. Methods include truncating
+ abnormally large responses; collating responses by storing only a
+ single copy, then keeping a counter of the number of times that
+ response has been seen; keeping only particularly interesting parts
+ of responses; and only logging responses of users who actually log
+ in.
+
+ Security is affected by firewalls which modify the IMAP protocol
+ stream; see section 5, Use of the ID Extension with Firewalls and
+ Other Intermediaries, for more information.
+
+
+
+
+Showalter Standards Track [Page 6]
+
+RFC 2971 IMAP4 ID extension October 2000
+
+
+8. Author's Address
+
+ Tim Showalter
+ Mirapoint, Inc.
+ 909 Hermosa Ct.
+ Sunnyvale, CA 94095
+
+ EMail: tjs@mirapoint.com
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Showalter Standards Track [Page 7]
+
+RFC 2971 IMAP4 ID extension October 2000
+
+
+9. Full Copyright Statement
+
+ Copyright (C) The Internet Society (2000). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Showalter Standards Track [Page 8]
+
diff --git a/vendor/github.com/mattermost/rsc/imap/rfc3501.txt b/vendor/github.com/mattermost/rsc/imap/rfc3501.txt
new file mode 100644
index 000000000..5ab48e17c
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/rfc3501.txt
@@ -0,0 +1,6051 @@
+
+
+
+
+
+
+Network Working Group M. Crispin
+Request for Comments: 3501 University of Washington
+Obsoletes: 2060 March 2003
+Category: Standards Track
+
+
+ INTERNET MESSAGE ACCESS PROTOCOL - VERSION 4rev1
+
+Status of this Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+Abstract
+
+ The Internet Message Access Protocol, Version 4rev1 (IMAP4rev1)
+ allows a client to access and manipulate electronic mail messages on
+ a server. IMAP4rev1 permits manipulation of mailboxes (remote
+ message folders) in a way that is functionally equivalent to local
+ folders. IMAP4rev1 also provides the capability for an offline
+ client to resynchronize with the server.
+
+ IMAP4rev1 includes operations for creating, deleting, and renaming
+ mailboxes, checking for new messages, permanently removing messages,
+ setting and clearing flags, RFC 2822 and RFC 2045 parsing, searching,
+ and selective fetching of message attributes, texts, and portions
+ thereof. Messages in IMAP4rev1 are accessed by the use of numbers.
+ These numbers are either message sequence numbers or unique
+ identifiers.
+
+ IMAP4rev1 supports a single server. A mechanism for accessing
+ configuration information to support multiple IMAP4rev1 servers is
+ discussed in RFC 2244.
+
+ IMAP4rev1 does not specify a means of posting mail; this function is
+ handled by a mail transfer protocol such as RFC 2821.
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 1]
+
+RFC 3501 IMAPv4 March 2003
+
+
+Table of Contents
+
+ IMAP4rev1 Protocol Specification ................................ 4
+ 1. How to Read This Document ............................... 4
+ 1.1. Organization of This Document ........................... 4
+ 1.2. Conventions Used in This Document ....................... 4
+ 1.3. Special Notes to Implementors ........................... 5
+ 2. Protocol Overview ....................................... 6
+ 2.1. Link Level .............................................. 6
+ 2.2. Commands and Responses .................................. 6
+ 2.2.1. Client Protocol Sender and Server Protocol Receiver ..... 6
+ 2.2.2. Server Protocol Sender and Client Protocol Receiver ..... 7
+ 2.3. Message Attributes ...................................... 8
+ 2.3.1. Message Numbers ......................................... 8
+ 2.3.1.1. Unique Identifier (UID) Message Attribute ....... 8
+ 2.3.1.2. Message Sequence Number Message Attribute ....... 10
+ 2.3.2. Flags Message Attribute ................................. 11
+ 2.3.3. Internal Date Message Attribute ......................... 12
+ 2.3.4. [RFC-2822] Size Message Attribute ....................... 12
+ 2.3.5. Envelope Structure Message Attribute .................... 12
+ 2.3.6. Body Structure Message Attribute ........................ 12
+ 2.4. Message Texts ........................................... 13
+ 3. State and Flow Diagram .................................. 13
+ 3.1. Not Authenticated State ................................. 13
+ 3.2. Authenticated State ..................................... 13
+ 3.3. Selected State .......................................... 13
+ 3.4. Logout State ............................................ 14
+ 4. Data Formats ............................................ 16
+ 4.1. Atom .................................................... 16
+ 4.2. Number .................................................. 16
+ 4.3. String .................................................. 16
+ 4.3.1. 8-bit and Binary Strings ................................ 17
+ 4.4. Parenthesized List ...................................... 17
+ 4.5. NIL ..................................................... 17
+ 5. Operational Considerations .............................. 18
+ 5.1. Mailbox Naming .......................................... 18
+ 5.1.1. Mailbox Hierarchy Naming ................................ 19
+ 5.1.2. Mailbox Namespace Naming Convention ..................... 19
+ 5.1.3. Mailbox International Naming Convention ................. 19
+ 5.2. Mailbox Size and Message Status Updates ................. 21
+ 5.3. Response when no Command in Progress .................... 21
+ 5.4. Autologout Timer ........................................ 22
+ 5.5. Multiple Commands in Progress ........................... 22
+ 6. Client Commands ........................................ 23
+ 6.1. Client Commands - Any State ............................ 24
+ 6.1.1. CAPABILITY Command ..................................... 24
+ 6.1.2. NOOP Command ........................................... 25
+ 6.1.3. LOGOUT Command ......................................... 26
+
+
+
+Crispin Standards Track [Page 2]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 6.2. Client Commands - Not Authenticated State .............. 26
+ 6.2.1. STARTTLS Command ....................................... 27
+ 6.2.2. AUTHENTICATE Command ................................... 28
+ 6.2.3. LOGIN Command .......................................... 30
+ 6.3. Client Commands - Authenticated State .................. 31
+ 6.3.1. SELECT Command ......................................... 32
+ 6.3.2. EXAMINE Command ........................................ 34
+ 6.3.3. CREATE Command ......................................... 34
+ 6.3.4. DELETE Command ......................................... 35
+ 6.3.5. RENAME Command ......................................... 37
+ 6.3.6. SUBSCRIBE Command ...................................... 39
+ 6.3.7. UNSUBSCRIBE Command .................................... 39
+ 6.3.8. LIST Command ........................................... 40
+ 6.3.9. LSUB Command ........................................... 43
+ 6.3.10. STATUS Command ......................................... 44
+ 6.3.11. APPEND Command ......................................... 46
+ 6.4. Client Commands - Selected State ....................... 47
+ 6.4.1. CHECK Command .......................................... 47
+ 6.4.2. CLOSE Command .......................................... 48
+ 6.4.3. EXPUNGE Command ........................................ 49
+ 6.4.4. SEARCH Command ......................................... 49
+ 6.4.5. FETCH Command .......................................... 54
+ 6.4.6. STORE Command .......................................... 58
+ 6.4.7. COPY Command ........................................... 59
+ 6.4.8. UID Command ............................................ 60
+ 6.5. Client Commands - Experimental/Expansion ............... 62
+ 6.5.1. X<atom> Command ........................................ 62
+ 7. Server Responses ....................................... 62
+ 7.1. Server Responses - Status Responses .................... 63
+ 7.1.1. OK Response ............................................ 65
+ 7.1.2. NO Response ............................................ 66
+ 7.1.3. BAD Response ........................................... 66
+ 7.1.4. PREAUTH Response ....................................... 67
+ 7.1.5. BYE Response ........................................... 67
+ 7.2. Server Responses - Server and Mailbox Status ........... 68
+ 7.2.1. CAPABILITY Response .................................... 68
+ 7.2.2. LIST Response .......................................... 69
+ 7.2.3. LSUB Response .......................................... 70
+ 7.2.4 STATUS Response ........................................ 70
+ 7.2.5. SEARCH Response ........................................ 71
+ 7.2.6. FLAGS Response ......................................... 71
+ 7.3. Server Responses - Mailbox Size ........................ 71
+ 7.3.1. EXISTS Response ........................................ 71
+ 7.3.2. RECENT Response ........................................ 72
+ 7.4. Server Responses - Message Status ...................... 72
+ 7.4.1. EXPUNGE Response ....................................... 72
+ 7.4.2. FETCH Response ......................................... 73
+ 7.5. Server Responses - Command Continuation Request ........ 79
+
+
+
+Crispin Standards Track [Page 3]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 8. Sample IMAP4rev1 connection ............................ 80
+ 9. Formal Syntax .......................................... 81
+ 10. Author's Note .......................................... 92
+ 11. Security Considerations ................................ 92
+ 11.1. STARTTLS Security Considerations ....................... 92
+ 11.2. Other Security Considerations .......................... 93
+ 12. IANA Considerations .................................... 94
+ Appendices ..................................................... 95
+ A. References ............................................. 95
+ B. Changes from RFC 2060 .................................. 97
+ C. Key Word Index ......................................... 103
+ Author's Address ............................................... 107
+ Full Copyright Statement ....................................... 108
+
+IMAP4rev1 Protocol Specification
+
+1. How to Read This Document
+
+1.1. Organization of This Document
+
+ This document is written from the point of view of the implementor of
+ an IMAP4rev1 client or server. Beyond the protocol overview in
+ section 2, it is not optimized for someone trying to understand the
+ operation of the protocol. The material in sections 3 through 5
+ provides the general context and definitions with which IMAP4rev1
+ operates.
+
+ Sections 6, 7, and 9 describe the IMAP commands, responses, and
+ syntax, respectively. The relationships among these are such that it
+ is almost impossible to understand any of them separately. In
+ particular, do not attempt to deduce command syntax from the command
+ section alone; instead refer to the Formal Syntax section.
+
+1.2. Conventions Used in This Document
+
+ "Conventions" are basic principles or procedures. Document
+ conventions are noted in this section.
+
+ In examples, "C:" and "S:" indicate lines sent by the client and
+ server respectively.
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "MAY", and "OPTIONAL" in this document are to
+ be interpreted as described in [KEYWORDS].
+
+ The word "can" (not "may") is used to refer to a possible
+ circumstance or situation, as opposed to an optional facility of the
+ protocol.
+
+
+
+Crispin Standards Track [Page 4]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ "User" is used to refer to a human user, whereas "client" refers to
+ the software being run by the user.
+
+ "Connection" refers to the entire sequence of client/server
+ interaction from the initial establishment of the network connection
+ until its termination.
+
+ "Session" refers to the sequence of client/server interaction from
+ the time that a mailbox is selected (SELECT or EXAMINE command) until
+ the time that selection ends (SELECT or EXAMINE of another mailbox,
+ CLOSE command, or connection termination).
+
+ Characters are 7-bit US-ASCII unless otherwise specified. Other
+ character sets are indicated using a "CHARSET", as described in
+ [MIME-IMT] and defined in [CHARSET]. CHARSETs have important
+ additional semantics in addition to defining character set; refer to
+ these documents for more detail.
+
+ There are several protocol conventions in IMAP. These refer to
+ aspects of the specification which are not strictly part of the IMAP
+ protocol, but reflect generally-accepted practice. Implementations
+ need to be aware of these conventions, and avoid conflicts whether or
+ not they implement the convention. For example, "&" may not be used
+ as a hierarchy delimiter since it conflicts with the Mailbox
+ International Naming Convention, and other uses of "&" in mailbox
+ names are impacted as well.
+
+1.3. Special Notes to Implementors
+
+ Implementors of the IMAP protocol are strongly encouraged to read the
+ IMAP implementation recommendations document [IMAP-IMPLEMENTATION] in
+ conjunction with this document, to help understand the intricacies of
+ this protocol and how best to build an interoperable product.
+
+ IMAP4rev1 is designed to be upwards compatible from the [IMAP2] and
+ unpublished IMAP2bis protocols. IMAP4rev1 is largely compatible with
+ the IMAP4 protocol described in RFC 1730; the exception being in
+ certain facilities added in RFC 1730 that proved problematic and were
+ subsequently removed. In the course of the evolution of IMAP4rev1,
+ some aspects in the earlier protocols have become obsolete. Obsolete
+ commands, responses, and data formats which an IMAP4rev1
+ implementation can encounter when used with an earlier implementation
+ are described in [IMAP-OBSOLETE].
+
+ Other compatibility issues with IMAP2bis, the most common variant of
+ the earlier protocol, are discussed in [IMAP-COMPAT]. A full
+ discussion of compatibility issues with rare (and presumed extinct)
+
+
+
+
+Crispin Standards Track [Page 5]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ variants of [IMAP2] is in [IMAP-HISTORICAL]; this document is
+ primarily of historical interest.
+
+ IMAP was originally developed for the older [RFC-822] standard, and
+ as a consequence several fetch items in IMAP incorporate "RFC822" in
+ their name. With the exception of RFC822.SIZE, there are more modern
+ replacements; for example, the modern version of RFC822.HEADER is
+ BODY.PEEK[HEADER]. In all cases, "RFC822" should be interpreted as a
+ reference to the updated [RFC-2822] standard.
+
+2. Protocol Overview
+
+2.1. Link Level
+
+ The IMAP4rev1 protocol assumes a reliable data stream such as that
+ provided by TCP. When TCP is used, an IMAP4rev1 server listens on
+ port 143.
+
+2.2. Commands and Responses
+
+ An IMAP4rev1 connection consists of the establishment of a
+ client/server network connection, an initial greeting from the
+ server, and client/server interactions. These client/server
+ interactions consist of a client command, server data, and a server
+ completion result response.
+
+ All interactions transmitted by client and server are in the form of
+ lines, that is, strings that end with a CRLF. The protocol receiver
+ of an IMAP4rev1 client or server is either reading a line, or is
+ reading a sequence of octets with a known count followed by a line.
+
+2.2.1. Client Protocol Sender and Server Protocol Receiver
+
+ The client command begins an operation. Each client command is
+ prefixed with an identifier (typically a short alphanumeric string,
+ e.g., A0001, A0002, etc.) called a "tag". A different tag is
+ generated by the client for each command.
+
+ Clients MUST follow the syntax outlined in this specification
+ strictly. It is a syntax error to send a command with missing or
+ extraneous spaces or arguments.
+
+ There are two cases in which a line from the client does not
+ represent a complete command. In one case, a command argument is
+ quoted with an octet count (see the description of literal in String
+ under Data Formats); in the other case, the command arguments require
+ server feedback (see the AUTHENTICATE command). In either case, the
+
+
+
+
+Crispin Standards Track [Page 6]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ server sends a command continuation request response if it is ready
+ for the octets (if appropriate) and the remainder of the command.
+ This response is prefixed with the token "+".
+
+ Note: If instead, the server detected an error in the
+ command, it sends a BAD completion response with a tag
+ matching the command (as described below) to reject the
+ command and prevent the client from sending any more of the
+ command.
+
+ It is also possible for the server to send a completion
+ response for some other command (if multiple commands are
+ in progress), or untagged data. In either case, the
+ command continuation request is still pending; the client
+ takes the appropriate action for the response, and reads
+ another response from the server. In all cases, the client
+ MUST send a complete command (including receiving all
+ command continuation request responses and command
+ continuations for the command) before initiating a new
+ command.
+
+ The protocol receiver of an IMAP4rev1 server reads a command line
+ from the client, parses the command and its arguments, and transmits
+ server data and a server command completion result response.
+
+2.2.2. Server Protocol Sender and Client Protocol Receiver
+
+ Data transmitted by the server to the client and status responses
+ that do not indicate command completion are prefixed with the token
+ "*", and are called untagged responses.
+
+ Server data MAY be sent as a result of a client command, or MAY be
+ sent unilaterally by the server. There is no syntactic difference
+ between server data that resulted from a specific command and server
+ data that were sent unilaterally.
+
+ The server completion result response indicates the success or
+ failure of the operation. It is tagged with the same tag as the
+ client command which began the operation. Thus, if more than one
+ command is in progress, the tag in a server completion response
+ identifies the command to which the response applies. There are
+ three possible server completion responses: OK (indicating success),
+ NO (indicating failure), or BAD (indicating a protocol error such as
+ unrecognized command or command syntax error).
+
+ Servers SHOULD enforce the syntax outlined in this specification
+ strictly. Any client command with a protocol syntax error, including
+ (but not limited to) missing or extraneous spaces or arguments,
+
+
+
+Crispin Standards Track [Page 7]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ SHOULD be rejected, and the client given a BAD server completion
+ response.
+
+ The protocol receiver of an IMAP4rev1 client reads a response line
+ from the server. It then takes action on the response based upon the
+ first token of the response, which can be a tag, a "*", or a "+".
+
+ A client MUST be prepared to accept any server response at all times.
+ This includes server data that was not requested. Server data SHOULD
+ be recorded, so that the client can reference its recorded copy
+ rather than sending a command to the server to request the data. In
+ the case of certain server data, the data MUST be recorded.
+
+ This topic is discussed in greater detail in the Server Responses
+ section.
+
+2.3. Message Attributes
+
+ In addition to message text, each message has several attributes
+ associated with it. These attributes can be retrieved individually
+ or in conjunction with other attributes or message texts.
+
+2.3.1. Message Numbers
+
+ Messages in IMAP4rev1 are accessed by one of two numbers; the unique
+ identifier or the message sequence number.
+
+
+2.3.1.1. Unique Identifier (UID) Message Attribute
+
+ A 32-bit value assigned to each message, which when used with the
+ unique identifier validity value (see below) forms a 64-bit value
+ that MUST NOT refer to any other message in the mailbox or any
+ subsequent mailbox with the same name forever. Unique identifiers
+ are assigned in a strictly ascending fashion in the mailbox; as each
+ message is added to the mailbox it is assigned a higher UID than the
+ message(s) which were added previously. Unlike message sequence
+ numbers, unique identifiers are not necessarily contiguous.
+
+ The unique identifier of a message MUST NOT change during the
+ session, and SHOULD NOT change between sessions. Any change of
+ unique identifiers between sessions MUST be detectable using the
+ UIDVALIDITY mechanism discussed below. Persistent unique identifiers
+ are required for a client to resynchronize its state from a previous
+ session with the server (e.g., disconnected or offline access
+ clients); this is discussed further in [IMAP-DISC].
+
+
+
+
+
+Crispin Standards Track [Page 8]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Associated with every mailbox are two values which aid in unique
+ identifier handling: the next unique identifier value and the unique
+ identifier validity value.
+
+ The next unique identifier value is the predicted value that will be
+ assigned to a new message in the mailbox. Unless the unique
+ identifier validity also changes (see below), the next unique
+ identifier value MUST have the following two characteristics. First,
+ the next unique identifier value MUST NOT change unless new messages
+ are added to the mailbox; and second, the next unique identifier
+ value MUST change whenever new messages are added to the mailbox,
+ even if those new messages are subsequently expunged.
+
+ Note: The next unique identifier value is intended to
+ provide a means for a client to determine whether any
+ messages have been delivered to the mailbox since the
+ previous time it checked this value. It is not intended to
+ provide any guarantee that any message will have this
+ unique identifier. A client can only assume, at the time
+ that it obtains the next unique identifier value, that
+ messages arriving after that time will have a UID greater
+ than or equal to that value.
+
+ The unique identifier validity value is sent in a UIDVALIDITY
+ response code in an OK untagged response at mailbox selection time.
+ If unique identifiers from an earlier session fail to persist in this
+ session, the unique identifier validity value MUST be greater than
+ the one used in the earlier session.
+
+ Note: Ideally, unique identifiers SHOULD persist at all
+ times. Although this specification recognizes that failure
+ to persist can be unavoidable in certain server
+ environments, it STRONGLY ENCOURAGES message store
+ implementation techniques that avoid this problem. For
+ example:
+
+ 1) Unique identifiers MUST be strictly ascending in the
+ mailbox at all times. If the physical message store is
+ re-ordered by a non-IMAP agent, this requires that the
+ unique identifiers in the mailbox be regenerated, since
+ the former unique identifiers are no longer strictly
+ ascending as a result of the re-ordering.
+
+ 2) If the message store has no mechanism to store unique
+ identifiers, it must regenerate unique identifiers at
+ each session, and each session must have a unique
+ UIDVALIDITY value.
+
+
+
+
+Crispin Standards Track [Page 9]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 3) If the mailbox is deleted and a new mailbox with the
+ same name is created at a later date, the server must
+ either keep track of unique identifiers from the
+ previous instance of the mailbox, or it must assign a
+ new UIDVALIDITY value to the new instance of the
+ mailbox. A good UIDVALIDITY value to use in this case
+ is a 32-bit representation of the creation date/time of
+ the mailbox. It is alright to use a constant such as
+ 1, but only if it guaranteed that unique identifiers
+ will never be reused, even in the case of a mailbox
+ being deleted (or renamed) and a new mailbox by the
+ same name created at some future time.
+
+ 4) The combination of mailbox name, UIDVALIDITY, and UID
+ must refer to a single immutable message on that server
+ forever. In particular, the internal date, [RFC-2822]
+ size, envelope, body structure, and message texts
+ (RFC822, RFC822.HEADER, RFC822.TEXT, and all BODY[...]
+ fetch data items) must never change. This does not
+ include message numbers, nor does it include attributes
+ that can be set by a STORE command (e.g., FLAGS).
+
+
+2.3.1.2. Message Sequence Number Message Attribute
+
+ A relative position from 1 to the number of messages in the mailbox.
+ This position MUST be ordered by ascending unique identifier. As
+ each new message is added, it is assigned a message sequence number
+ that is 1 higher than the number of messages in the mailbox before
+ that new message was added.
+
+ Message sequence numbers can be reassigned during the session. For
+ example, when a message is permanently removed (expunged) from the
+ mailbox, the message sequence number for all subsequent messages is
+ decremented. The number of messages in the mailbox is also
+ decremented. Similarly, a new message can be assigned a message
+ sequence number that was once held by some other message prior to an
+ expunge.
+
+ In addition to accessing messages by relative position in the
+ mailbox, message sequence numbers can be used in mathematical
+ calculations. For example, if an untagged "11 EXISTS" is received,
+ and previously an untagged "8 EXISTS" was received, three new
+ messages have arrived with message sequence numbers of 9, 10, and 11.
+ Another example, if message 287 in a 523 message mailbox has UID
+ 12345, there are exactly 286 messages which have lesser UIDs and 236
+ messages which have greater UIDs.
+
+
+
+
+Crispin Standards Track [Page 10]
+
+RFC 3501 IMAPv4 March 2003
+
+
+2.3.2. Flags Message Attribute
+
+ A list of zero or more named tokens associated with the message. A
+ flag is set by its addition to this list, and is cleared by its
+ removal. There are two types of flags in IMAP4rev1. A flag of
+ either type can be permanent or session-only.
+
+ A system flag is a flag name that is pre-defined in this
+ specification. All system flags begin with "\". Certain system
+ flags (\Deleted and \Seen) have special semantics described
+ elsewhere. The currently-defined system flags are:
+
+ \Seen
+ Message has been read
+
+ \Answered
+ Message has been answered
+
+ \Flagged
+ Message is "flagged" for urgent/special attention
+
+ \Deleted
+ Message is "deleted" for removal by later EXPUNGE
+
+ \Draft
+ Message has not completed composition (marked as a draft).
+
+ \Recent
+ Message is "recently" arrived in this mailbox. This session
+ is the first session to have been notified about this
+ message; if the session is read-write, subsequent sessions
+ will not see \Recent set for this message. This flag can not
+ be altered by the client.
+
+ If it is not possible to determine whether or not this
+ session is the first session to be notified about a message,
+ then that message SHOULD be considered recent.
+
+ If multiple connections have the same mailbox selected
+ simultaneously, it is undefined which of these connections
+ will see newly-arrived messages with \Recent set and which
+ will see it without \Recent set.
+
+ A keyword is defined by the server implementation. Keywords do not
+ begin with "\". Servers MAY permit the client to define new keywords
+ in the mailbox (see the description of the PERMANENTFLAGS response
+ code for more information).
+
+
+
+
+Crispin Standards Track [Page 11]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ A flag can be permanent or session-only on a per-flag basis.
+ Permanent flags are those which the client can add or remove from the
+ message flags permanently; that is, concurrent and subsequent
+ sessions will see any change in permanent flags. Changes to session
+ flags are valid only in that session.
+
+ Note: The \Recent system flag is a special case of a
+ session flag. \Recent can not be used as an argument in a
+ STORE or APPEND command, and thus can not be changed at
+ all.
+
+2.3.3. Internal Date Message Attribute
+
+ The internal date and time of the message on the server. This
+ is not the date and time in the [RFC-2822] header, but rather a
+ date and time which reflects when the message was received. In
+ the case of messages delivered via [SMTP], this SHOULD be the
+ date and time of final delivery of the message as defined by
+ [SMTP]. In the case of messages delivered by the IMAP4rev1 COPY
+ command, this SHOULD be the internal date and time of the source
+ message. In the case of messages delivered by the IMAP4rev1
+ APPEND command, this SHOULD be the date and time as specified in
+ the APPEND command description. All other cases are
+ implementation defined.
+
+2.3.4. [RFC-2822] Size Message Attribute
+
+ The number of octets in the message, as expressed in [RFC-2822]
+ format.
+
+2.3.5. Envelope Structure Message Attribute
+
+ A parsed representation of the [RFC-2822] header of the message.
+ Note that the IMAP Envelope structure is not the same as an
+ [SMTP] envelope.
+
+2.3.6. Body Structure Message Attribute
+
+ A parsed representation of the [MIME-IMB] body structure
+ information of the message.
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 12]
+
+RFC 3501 IMAPv4 March 2003
+
+
+2.4. Message Texts
+
+ In addition to being able to fetch the full [RFC-2822] text of a
+ message, IMAP4rev1 permits the fetching of portions of the full
+ message text. Specifically, it is possible to fetch the
+ [RFC-2822] message header, [RFC-2822] message body, a [MIME-IMB]
+ body part, or a [MIME-IMB] header.
+
+3. State and Flow Diagram
+
+ Once the connection between client and server is established, an
+ IMAP4rev1 connection is in one of four states. The initial
+ state is identified in the server greeting. Most commands are
+ only valid in certain states. It is a protocol error for the
+ client to attempt a command while the connection is in an
+ inappropriate state, and the server will respond with a BAD or
+ NO (depending upon server implementation) command completion
+ result.
+
+3.1. Not Authenticated State
+
+ In the not authenticated state, the client MUST supply
+ authentication credentials before most commands will be
+ permitted. This state is entered when a connection starts
+ unless the connection has been pre-authenticated.
+
+3.2. Authenticated State
+
+ In the authenticated state, the client is authenticated and MUST
+ select a mailbox to access before commands that affect messages
+ will be permitted. This state is entered when a
+ pre-authenticated connection starts, when acceptable
+ authentication credentials have been provided, after an error in
+ selecting a mailbox, or after a successful CLOSE command.
+
+3.3. Selected State
+
+ In a selected state, a mailbox has been selected to access.
+ This state is entered when a mailbox has been successfully
+ selected.
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 13]
+
+RFC 3501 IMAPv4 March 2003
+
+
+3.4. Logout State
+
+ In the logout state, the connection is being terminated. This
+ state can be entered as a result of a client request (via the
+ LOGOUT command) or by unilateral action on the part of either
+ the client or server.
+
+ If the client requests the logout state, the server MUST send an
+ untagged BYE response and a tagged OK response to the LOGOUT
+ command before the server closes the connection; and the client
+ MUST read the tagged OK response to the LOGOUT command before
+ the client closes the connection.
+
+ A server MUST NOT unilaterally close the connection without
+ sending an untagged BYE response that contains the reason for
+ having done so. A client SHOULD NOT unilaterally close the
+ connection, and instead SHOULD issue a LOGOUT command. If the
+ server detects that the client has unilaterally closed the
+ connection, the server MAY omit the untagged BYE response and
+ simply close its connection.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 14]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ +----------------------+
+ |connection established|
+ +----------------------+
+ ||
+ \/
+ +--------------------------------------+
+ | server greeting |
+ +--------------------------------------+
+ || (1) || (2) || (3)
+ \/ || ||
+ +-----------------+ || ||
+ |Not Authenticated| || ||
+ +-----------------+ || ||
+ || (7) || (4) || ||
+ || \/ \/ ||
+ || +----------------+ ||
+ || | Authenticated |<=++ ||
+ || +----------------+ || ||
+ || || (7) || (5) || (6) ||
+ || || \/ || ||
+ || || +--------+ || ||
+ || || |Selected|==++ ||
+ || || +--------+ ||
+ || || || (7) ||
+ \/ \/ \/ \/
+ +--------------------------------------+
+ | Logout |
+ +--------------------------------------+
+ ||
+ \/
+ +-------------------------------+
+ |both sides close the connection|
+ +-------------------------------+
+
+ (1) connection without pre-authentication (OK greeting)
+ (2) pre-authenticated connection (PREAUTH greeting)
+ (3) rejected connection (BYE greeting)
+ (4) successful LOGIN or AUTHENTICATE command
+ (5) successful SELECT or EXAMINE command
+ (6) CLOSE command, or failed SELECT or EXAMINE command
+ (7) LOGOUT command, server shutdown, or connection closed
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 15]
+
+RFC 3501 IMAPv4 March 2003
+
+
+4. Data Formats
+
+ IMAP4rev1 uses textual commands and responses. Data in
+ IMAP4rev1 can be in one of several forms: atom, number, string,
+ parenthesized list, or NIL. Note that a particular data item
+ may take more than one form; for example, a data item defined as
+ using "astring" syntax may be either an atom or a string.
+
+4.1. Atom
+
+ An atom consists of one or more non-special characters.
+
+4.2. Number
+
+ A number consists of one or more digit characters, and
+ represents a numeric value.
+
+4.3. String
+
+ A string is in one of two forms: either literal or quoted
+ string. The literal form is the general form of string. The
+ quoted string form is an alternative that avoids the overhead of
+ processing a literal at the cost of limitations of characters
+ which may be used.
+
+ A literal is a sequence of zero or more octets (including CR and
+ LF), prefix-quoted with an octet count in the form of an open
+ brace ("{"), the number of octets, close brace ("}"), and CRLF.
+ In the case of literals transmitted from server to client, the
+ CRLF is immediately followed by the octet data. In the case of
+ literals transmitted from client to server, the client MUST wait
+ to receive a command continuation request (described later in
+ this document) before sending the octet data (and the remainder
+ of the command).
+
+ A quoted string is a sequence of zero or more 7-bit characters,
+ excluding CR and LF, with double quote (<">) characters at each
+ end.
+
+ The empty string is represented as either "" (a quoted string
+ with zero characters between double quotes) or as {0} followed
+ by CRLF (a literal with an octet count of 0).
+
+ Note: Even if the octet count is 0, a client transmitting a
+ literal MUST wait to receive a command continuation request.
+
+
+
+
+
+
+Crispin Standards Track [Page 16]
+
+RFC 3501 IMAPv4 March 2003
+
+
+4.3.1. 8-bit and Binary Strings
+
+ 8-bit textual and binary mail is supported through the use of a
+ [MIME-IMB] content transfer encoding. IMAP4rev1 implementations MAY
+ transmit 8-bit or multi-octet characters in literals, but SHOULD do
+ so only when the [CHARSET] is identified.
+
+ Although a BINARY body encoding is defined, unencoded binary strings
+ are not permitted. A "binary string" is any string with NUL
+ characters. Implementations MUST encode binary data into a textual
+ form, such as BASE64, before transmitting the data. A string with an
+ excessive amount of CTL characters MAY also be considered to be
+ binary.
+
+4.4. Parenthesized List
+
+ Data structures are represented as a "parenthesized list"; a sequence
+ of data items, delimited by space, and bounded at each end by
+ parentheses. A parenthesized list can contain other parenthesized
+ lists, using multiple levels of parentheses to indicate nesting.
+
+ The empty list is represented as () -- a parenthesized list with no
+ members.
+
+4.5. NIL
+
+ The special form "NIL" represents the non-existence of a particular
+ data item that is represented as a string or parenthesized list, as
+ distinct from the empty string "" or the empty parenthesized list ().
+
+ Note: NIL is never used for any data item which takes the
+ form of an atom. For example, a mailbox name of "NIL" is a
+ mailbox named NIL as opposed to a non-existent mailbox
+ name. This is because mailbox uses "astring" syntax which
+ is an atom or a string. Conversely, an addr-name of NIL is
+ a non-existent personal name, because addr-name uses
+ "nstring" syntax which is NIL or a string, but never an
+ atom.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 17]
+
+RFC 3501 IMAPv4 March 2003
+
+
+5. Operational Considerations
+
+ The following rules are listed here to ensure that all IMAP4rev1
+ implementations interoperate properly.
+
+5.1. Mailbox Naming
+
+ Mailbox names are 7-bit. Client implementations MUST NOT attempt to
+ create 8-bit mailbox names, and SHOULD interpret any 8-bit mailbox
+ names returned by LIST or LSUB as UTF-8. Server implementations
+ SHOULD prohibit the creation of 8-bit mailbox names, and SHOULD NOT
+ return 8-bit mailbox names in LIST or LSUB. See section 5.1.3 for
+ more information on how to represent non-ASCII mailbox names.
+
+ Note: 8-bit mailbox names were undefined in earlier
+ versions of this protocol. Some sites used a local 8-bit
+ character set to represent non-ASCII mailbox names. Such
+ usage is not interoperable, and is now formally deprecated.
+
+ The case-insensitive mailbox name INBOX is a special name reserved to
+ mean "the primary mailbox for this user on this server". The
+ interpretation of all other names is implementation-dependent.
+
+ In particular, this specification takes no position on case
+ sensitivity in non-INBOX mailbox names. Some server implementations
+ are fully case-sensitive; others preserve case of a newly-created
+ name but otherwise are case-insensitive; and yet others coerce names
+ to a particular case. Client implementations MUST interact with any
+ of these. If a server implementation interprets non-INBOX mailbox
+ names as case-insensitive, it MUST treat names using the
+ international naming convention specially as described in section
+ 5.1.3.
+
+ There are certain client considerations when creating a new mailbox
+ name:
+
+ 1) Any character which is one of the atom-specials (see the Formal
+ Syntax) will require that the mailbox name be represented as a
+ quoted string or literal.
+
+ 2) CTL and other non-graphic characters are difficult to represent
+ in a user interface and are best avoided.
+
+ 3) Although the list-wildcard characters ("%" and "*") are valid
+ in a mailbox name, it is difficult to use such mailbox names
+ with the LIST and LSUB commands due to the conflict with
+ wildcard interpretation.
+
+
+
+
+Crispin Standards Track [Page 18]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 4) Usually, a character (determined by the server implementation)
+ is reserved to delimit levels of hierarchy.
+
+ 5) Two characters, "#" and "&", have meanings by convention, and
+ should be avoided except when used in that convention.
+
+5.1.1. Mailbox Hierarchy Naming
+
+ If it is desired to export hierarchical mailbox names, mailbox names
+ MUST be left-to-right hierarchical using a single character to
+ separate levels of hierarchy. The same hierarchy separator character
+ is used for all levels of hierarchy within a single name.
+
+5.1.2. Mailbox Namespace Naming Convention
+
+ By convention, the first hierarchical element of any mailbox name
+ which begins with "#" identifies the "namespace" of the remainder of
+ the name. This makes it possible to disambiguate between different
+ types of mailbox stores, each of which have their own namespaces.
+
+ For example, implementations which offer access to USENET
+ newsgroups MAY use the "#news" namespace to partition the
+ USENET newsgroup namespace from that of other mailboxes.
+ Thus, the comp.mail.misc newsgroup would have a mailbox
+ name of "#news.comp.mail.misc", and the name
+ "comp.mail.misc" can refer to a different object (e.g., a
+ user's private mailbox).
+
+5.1.3. Mailbox International Naming Convention
+
+ By convention, international mailbox names in IMAP4rev1 are specified
+ using a modified version of the UTF-7 encoding described in [UTF-7].
+ Modified UTF-7 may also be usable in servers that implement an
+ earlier version of this protocol.
+
+ In modified UTF-7, printable US-ASCII characters, except for "&",
+ represent themselves; that is, characters with octet values 0x20-0x25
+ and 0x27-0x7e. The character "&" (0x26) is represented by the
+ two-octet sequence "&-".
+
+ All other characters (octet values 0x00-0x1f and 0x7f-0xff) are
+ represented in modified BASE64, with a further modification from
+ [UTF-7] that "," is used instead of "/". Modified BASE64 MUST NOT be
+ used to represent any printing US-ASCII character which can represent
+ itself.
+
+
+
+
+
+
+Crispin Standards Track [Page 19]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ "&" is used to shift to modified BASE64 and "-" to shift back to
+ US-ASCII. There is no implicit shift from BASE64 to US-ASCII, and
+ null shifts ("-&" while in BASE64; note that "&-" while in US-ASCII
+ means "&") are not permitted. However, all names start in US-ASCII,
+ and MUST end in US-ASCII; that is, a name that ends with a non-ASCII
+ ISO-10646 character MUST end with a "-").
+
+ The purpose of these modifications is to correct the following
+ problems with UTF-7:
+
+ 1) UTF-7 uses the "+" character for shifting; this conflicts with
+ the common use of "+" in mailbox names, in particular USENET
+ newsgroup names.
+
+ 2) UTF-7's encoding is BASE64 which uses the "/" character; this
+ conflicts with the use of "/" as a popular hierarchy delimiter.
+
+ 3) UTF-7 prohibits the unencoded usage of "\"; this conflicts with
+ the use of "\" as a popular hierarchy delimiter.
+
+ 4) UTF-7 prohibits the unencoded usage of "~"; this conflicts with
+ the use of "~" in some servers as a home directory indicator.
+
+ 5) UTF-7 permits multiple alternate forms to represent the same
+ string; in particular, printable US-ASCII characters can be
+ represented in encoded form.
+
+ Although modified UTF-7 is a convention, it establishes certain
+ requirements on server handling of any mailbox name with an
+ embedded "&" character. In particular, server implementations
+ MUST preserve the exact form of the modified BASE64 portion of a
+ modified UTF-7 name and treat that text as case-sensitive, even if
+ names are otherwise case-insensitive or case-folded.
+
+ Server implementations SHOULD verify that any mailbox name with an
+ embedded "&" character, used as an argument to CREATE, is: in the
+ correctly modified UTF-7 syntax, has no superfluous shifts, and
+ has no encoding in modified BASE64 of any printing US-ASCII
+ character which can represent itself. However, client
+ implementations MUST NOT depend upon the server doing this, and
+ SHOULD NOT attempt to create a mailbox name with an embedded "&"
+ character unless it complies with the modified UTF-7 syntax.
+
+ Server implementations which export a mail store that does not
+ follow the modified UTF-7 convention MUST convert to modified
+ UTF-7 any mailbox name that contains either non-ASCII characters
+ or the "&" character.
+
+
+
+
+Crispin Standards Track [Page 20]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ For example, here is a mailbox name which mixes English,
+ Chinese, and Japanese text:
+ ~peter/mail/&U,BTFw-/&ZeVnLIqe-
+
+ For example, the string "&Jjo!" is not a valid mailbox
+ name because it does not contain a shift to US-ASCII
+ before the "!". The correct form is "&Jjo-!". The
+ string "&U,BTFw-&ZeVnLIqe-" is not permitted because it
+ contains a superfluous shift. The correct form is
+ "&U,BTF2XlZyyKng-".
+
+5.2. Mailbox Size and Message Status Updates
+
+ At any time, a server can send data that the client did not request.
+ Sometimes, such behavior is REQUIRED. For example, agents other than
+ the server MAY add messages to the mailbox (e.g., new message
+ delivery), change the flags of the messages in the mailbox (e.g.,
+ simultaneous access to the same mailbox by multiple agents), or even
+ remove messages from the mailbox. A server MUST send mailbox size
+ updates automatically if a mailbox size change is observed during the
+ processing of a command. A server SHOULD send message flag updates
+ automatically, without requiring the client to request such updates
+ explicitly.
+
+ Special rules exist for server notification of a client about the
+ removal of messages to prevent synchronization errors; see the
+ description of the EXPUNGE response for more detail. In particular,
+ it is NOT permitted to send an EXISTS response that would reduce the
+ number of messages in the mailbox; only the EXPUNGE response can do
+ this.
+
+ Regardless of what implementation decisions a client makes on
+ remembering data from the server, a client implementation MUST record
+ mailbox size updates. It MUST NOT assume that any command after the
+ initial mailbox selection will return the size of the mailbox.
+
+5.3. Response when no Command in Progress
+
+ Server implementations are permitted to send an untagged response
+ (except for EXPUNGE) while there is no command in progress. Server
+ implementations that send such responses MUST deal with flow control
+ considerations. Specifically, they MUST either (1) verify that the
+ size of the data does not exceed the underlying transport's available
+ window size, or (2) use non-blocking writes.
+
+
+
+
+
+
+
+Crispin Standards Track [Page 21]
+
+RFC 3501 IMAPv4 March 2003
+
+
+5.4. Autologout Timer
+
+ If a server has an inactivity autologout timer, the duration of that
+ timer MUST be at least 30 minutes. The receipt of ANY command from
+ the client during that interval SHOULD suffice to reset the
+ autologout timer.
+
+5.5. Multiple Commands in Progress
+
+ The client MAY send another command without waiting for the
+ completion result response of a command, subject to ambiguity rules
+ (see below) and flow control constraints on the underlying data
+ stream. Similarly, a server MAY begin processing another command
+ before processing the current command to completion, subject to
+ ambiguity rules. However, any command continuation request responses
+ and command continuations MUST be negotiated before any subsequent
+ command is initiated.
+
+ The exception is if an ambiguity would result because of a command
+ that would affect the results of other commands. Clients MUST NOT
+ send multiple commands without waiting if an ambiguity would result.
+ If the server detects a possible ambiguity, it MUST execute commands
+ to completion in the order given by the client.
+
+ The most obvious example of ambiguity is when a command would affect
+ the results of another command, e.g., a FETCH of a message's flags
+ and a STORE of that same message's flags.
+
+ A non-obvious ambiguity occurs with commands that permit an untagged
+ EXPUNGE response (commands other than FETCH, STORE, and SEARCH),
+ since an untagged EXPUNGE response can invalidate sequence numbers in
+ a subsequent command. This is not a problem for FETCH, STORE, or
+ SEARCH commands because servers are prohibited from sending EXPUNGE
+ responses while any of those commands are in progress. Therefore, if
+ the client sends any command other than FETCH, STORE, or SEARCH, it
+ MUST wait for the completion result response before sending a command
+ with message sequence numbers.
+
+ Note: UID FETCH, UID STORE, and UID SEARCH are different
+ commands from FETCH, STORE, and SEARCH. If the client
+ sends a UID command, it must wait for a completion result
+ response before sending a command with message sequence
+ numbers.
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 22]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ For example, the following non-waiting command sequences are invalid:
+
+ FETCH + NOOP + STORE
+ STORE + COPY + FETCH
+ COPY + COPY
+ CHECK + FETCH
+
+ The following are examples of valid non-waiting command sequences:
+
+ FETCH + STORE + SEARCH + CHECK
+ STORE + COPY + EXPUNGE
+
+ UID SEARCH + UID SEARCH may be valid or invalid as a non-waiting
+ command sequence, depending upon whether or not the second UID
+ SEARCH contains message sequence numbers.
+
+6. Client Commands
+
+ IMAP4rev1 commands are described in this section. Commands are
+ organized by the state in which the command is permitted. Commands
+ which are permitted in multiple states are listed in the minimum
+ permitted state (for example, commands valid in authenticated and
+ selected state are listed in the authenticated state commands).
+
+ Command arguments, identified by "Arguments:" in the command
+ descriptions below, are described by function, not by syntax. The
+ precise syntax of command arguments is described in the Formal Syntax
+ section.
+
+ Some commands cause specific server responses to be returned; these
+ are identified by "Responses:" in the command descriptions below.
+ See the response descriptions in the Responses section for
+ information on these responses, and the Formal Syntax section for the
+ precise syntax of these responses. It is possible for server data to
+ be transmitted as a result of any command. Thus, commands that do
+ not specifically require server data specify "no specific responses
+ for this command" instead of "none".
+
+ The "Result:" in the command description refers to the possible
+ tagged status responses to a command, and any special interpretation
+ of these status responses.
+
+ The state of a connection is only changed by successful commands
+ which are documented as changing state. A rejected command (BAD
+ response) never changes the state of the connection or of the
+ selected mailbox. A failed command (NO response) generally does not
+ change the state of the connection or of the selected mailbox; the
+ exception being the SELECT and EXAMINE commands.
+
+
+
+Crispin Standards Track [Page 23]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.1. Client Commands - Any State
+
+ The following commands are valid in any state: CAPABILITY, NOOP, and
+ LOGOUT.
+
+6.1.1. CAPABILITY Command
+
+ Arguments: none
+
+ Responses: REQUIRED untagged response: CAPABILITY
+
+ Result: OK - capability completed
+ BAD - command unknown or arguments invalid
+
+ The CAPABILITY command requests a listing of capabilities that the
+ server supports. The server MUST send a single untagged
+ CAPABILITY response with "IMAP4rev1" as one of the listed
+ capabilities before the (tagged) OK response.
+
+ A capability name which begins with "AUTH=" indicates that the
+ server supports that particular authentication mechanism. All
+ such names are, by definition, part of this specification. For
+ example, the authorization capability for an experimental
+ "blurdybloop" authenticator would be "AUTH=XBLURDYBLOOP" and not
+ "XAUTH=BLURDYBLOOP" or "XAUTH=XBLURDYBLOOP".
+
+ Other capability names refer to extensions, revisions, or
+ amendments to this specification. See the documentation of the
+ CAPABILITY response for additional information. No capabilities,
+ beyond the base IMAP4rev1 set defined in this specification, are
+ enabled without explicit client action to invoke the capability.
+
+ Client and server implementations MUST implement the STARTTLS,
+ LOGINDISABLED, and AUTH=PLAIN (described in [IMAP-TLS])
+ capabilities. See the Security Considerations section for
+ important information.
+
+ See the section entitled "Client Commands -
+ Experimental/Expansion" for information about the form of site or
+ implementation-specific capabilities.
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 24]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Example: C: abcd CAPABILITY
+ S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI
+ LOGINDISABLED
+ S: abcd OK CAPABILITY completed
+ C: efgh STARTTLS
+ S: efgh OK STARTLS completed
+ <TLS negotiation, further commands are under [TLS] layer>
+ C: ijkl CAPABILITY
+ S: * CAPABILITY IMAP4rev1 AUTH=GSSAPI AUTH=PLAIN
+ S: ijkl OK CAPABILITY completed
+
+
+6.1.2. NOOP Command
+
+ Arguments: none
+
+ Responses: no specific responses for this command (but see below)
+
+ Result: OK - noop completed
+ BAD - command unknown or arguments invalid
+
+ The NOOP command always succeeds. It does nothing.
+
+ Since any command can return a status update as untagged data, the
+ NOOP command can be used as a periodic poll for new messages or
+ message status updates during a period of inactivity (this is the
+ preferred method to do this). The NOOP command can also be used
+ to reset any inactivity autologout timer on the server.
+
+ Example: C: a002 NOOP
+ S: a002 OK NOOP completed
+ . . .
+ C: a047 NOOP
+ S: * 22 EXPUNGE
+ S: * 23 EXISTS
+ S: * 3 RECENT
+ S: * 14 FETCH (FLAGS (\Seen \Deleted))
+ S: a047 OK NOOP completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 25]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.1.3. LOGOUT Command
+
+ Arguments: none
+
+ Responses: REQUIRED untagged response: BYE
+
+ Result: OK - logout completed
+ BAD - command unknown or arguments invalid
+
+ The LOGOUT command informs the server that the client is done with
+ the connection. The server MUST send a BYE untagged response
+ before the (tagged) OK response, and then close the network
+ connection.
+
+ Example: C: A023 LOGOUT
+ S: * BYE IMAP4rev1 Server logging out
+ S: A023 OK LOGOUT completed
+ (Server and client then close the connection)
+
+6.2. Client Commands - Not Authenticated State
+
+ In the not authenticated state, the AUTHENTICATE or LOGIN command
+ establishes authentication and enters the authenticated state. The
+ AUTHENTICATE command provides a general mechanism for a variety of
+ authentication techniques, privacy protection, and integrity
+ checking; whereas the LOGIN command uses a traditional user name and
+ plaintext password pair and has no means of establishing privacy
+ protection or integrity checking.
+
+ The STARTTLS command is an alternate form of establishing session
+ privacy protection and integrity checking, but does not establish
+ authentication or enter the authenticated state.
+
+ Server implementations MAY allow access to certain mailboxes without
+ establishing authentication. This can be done by means of the
+ ANONYMOUS [SASL] authenticator described in [ANONYMOUS]. An older
+ convention is a LOGIN command using the userid "anonymous"; in this
+ case, a password is required although the server may choose to accept
+ any password. The restrictions placed on anonymous users are
+ implementation-dependent.
+
+ Once authenticated (including as anonymous), it is not possible to
+ re-enter not authenticated state.
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 26]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
+ the following commands are valid in the not authenticated state:
+ STARTTLS, AUTHENTICATE and LOGIN. See the Security Considerations
+ section for important information about these commands.
+
+6.2.1. STARTTLS Command
+
+ Arguments: none
+
+ Responses: no specific response for this command
+
+ Result: OK - starttls completed, begin TLS negotiation
+ BAD - command unknown or arguments invalid
+
+ A [TLS] negotiation begins immediately after the CRLF at the end
+ of the tagged OK response from the server. Once a client issues a
+ STARTTLS command, it MUST NOT issue further commands until a
+ server response is seen and the [TLS] negotiation is complete.
+
+ The server remains in the non-authenticated state, even if client
+ credentials are supplied during the [TLS] negotiation. This does
+ not preclude an authentication mechanism such as EXTERNAL (defined
+ in [SASL]) from using client identity determined by the [TLS]
+ negotiation.
+
+ Once [TLS] has been started, the client MUST discard cached
+ information about server capabilities and SHOULD re-issue the
+ CAPABILITY command. This is necessary to protect against man-in-
+ the-middle attacks which alter the capabilities list prior to
+ STARTTLS. The server MAY advertise different capabilities after
+ STARTTLS.
+
+ Example: C: a001 CAPABILITY
+ S: * CAPABILITY IMAP4rev1 STARTTLS LOGINDISABLED
+ S: a001 OK CAPABILITY completed
+ C: a002 STARTTLS
+ S: a002 OK Begin TLS negotiation now
+ <TLS negotiation, further commands are under [TLS] layer>
+ C: a003 CAPABILITY
+ S: * CAPABILITY IMAP4rev1 AUTH=PLAIN
+ S: a003 OK CAPABILITY completed
+ C: a004 LOGIN joe password
+ S: a004 OK LOGIN completed
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 27]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.2.2. AUTHENTICATE Command
+
+ Arguments: authentication mechanism name
+
+ Responses: continuation data can be requested
+
+ Result: OK - authenticate completed, now in authenticated state
+ NO - authenticate failure: unsupported authentication
+ mechanism, credentials rejected
+ BAD - command unknown or arguments invalid,
+ authentication exchange cancelled
+
+ The AUTHENTICATE command indicates a [SASL] authentication
+ mechanism to the server. If the server supports the requested
+ authentication mechanism, it performs an authentication protocol
+ exchange to authenticate and identify the client. It MAY also
+ negotiate an OPTIONAL security layer for subsequent protocol
+ interactions. If the requested authentication mechanism is not
+ supported, the server SHOULD reject the AUTHENTICATE command by
+ sending a tagged NO response.
+
+ The AUTHENTICATE command does not support the optional "initial
+ response" feature of [SASL]. Section 5.1 of [SASL] specifies how
+ to handle an authentication mechanism which uses an initial
+ response.
+
+ The service name specified by this protocol's profile of [SASL] is
+ "imap".
+
+ The authentication protocol exchange consists of a series of
+ server challenges and client responses that are specific to the
+ authentication mechanism. A server challenge consists of a
+ command continuation request response with the "+" token followed
+ by a BASE64 encoded string. The client response consists of a
+ single line consisting of a BASE64 encoded string. If the client
+ wishes to cancel an authentication exchange, it issues a line
+ consisting of a single "*". If the server receives such a
+ response, it MUST reject the AUTHENTICATE command by sending a
+ tagged BAD response.
+
+ If a security layer is negotiated through the [SASL]
+ authentication exchange, it takes effect immediately following the
+ CRLF that concludes the authentication exchange for the client,
+ and the CRLF of the tagged OK response for the server.
+
+ While client and server implementations MUST implement the
+ AUTHENTICATE command itself, it is not required to implement any
+ authentication mechanisms other than the PLAIN mechanism described
+
+
+
+Crispin Standards Track [Page 28]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ in [IMAP-TLS]. Also, an authentication mechanism is not required
+ to support any security layers.
+
+ Note: a server implementation MUST implement a
+ configuration in which it does NOT permit any plaintext
+ password mechanisms, unless either the STARTTLS command
+ has been negotiated or some other mechanism that
+ protects the session from password snooping has been
+ provided. Server sites SHOULD NOT use any configuration
+ which permits a plaintext password mechanism without
+ such a protection mechanism against password snooping.
+ Client and server implementations SHOULD implement
+ additional [SASL] mechanisms that do not use plaintext
+ passwords, such the GSSAPI mechanism described in [SASL]
+ and/or the [DIGEST-MD5] mechanism.
+
+ Servers and clients can support multiple authentication
+ mechanisms. The server SHOULD list its supported authentication
+ mechanisms in the response to the CAPABILITY command so that the
+ client knows which authentication mechanisms to use.
+
+ A server MAY include a CAPABILITY response code in the tagged OK
+ response of a successful AUTHENTICATE command in order to send
+ capabilities automatically. It is unnecessary for a client to
+ send a separate CAPABILITY command if it recognizes these
+ automatic capabilities. This should only be done if a security
+ layer was not negotiated by the AUTHENTICATE command, because the
+ tagged OK response as part of an AUTHENTICATE command is not
+ protected by encryption/integrity checking. [SASL] requires the
+ client to re-issue a CAPABILITY command in this case.
+
+ If an AUTHENTICATE command fails with a NO response, the client
+ MAY try another authentication mechanism by issuing another
+ AUTHENTICATE command. It MAY also attempt to authenticate by
+ using the LOGIN command (see section 6.2.3 for more detail). In
+ other words, the client MAY request authentication types in
+ decreasing order of preference, with the LOGIN command as a last
+ resort.
+
+ The authorization identity passed from the client to the server
+ during the authentication exchange is interpreted by the server as
+ the user name whose privileges the client is requesting.
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 29]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Example: S: * OK IMAP4rev1 Server
+ C: A001 AUTHENTICATE GSSAPI
+ S: +
+ C: YIIB+wYJKoZIhvcSAQICAQBuggHqMIIB5qADAgEFoQMCAQ6iBw
+ MFACAAAACjggEmYYIBIjCCAR6gAwIBBaESGxB1Lndhc2hpbmd0
+ b24uZWR1oi0wK6ADAgEDoSQwIhsEaW1hcBsac2hpdmFtcy5jYW
+ Mud2FzaGluZ3Rvbi5lZHWjgdMwgdCgAwIBAaEDAgEDooHDBIHA
+ cS1GSa5b+fXnPZNmXB9SjL8Ollj2SKyb+3S0iXMljen/jNkpJX
+ AleKTz6BQPzj8duz8EtoOuNfKgweViyn/9B9bccy1uuAE2HI0y
+ C/PHXNNU9ZrBziJ8Lm0tTNc98kUpjXnHZhsMcz5Mx2GR6dGknb
+ I0iaGcRerMUsWOuBmKKKRmVMMdR9T3EZdpqsBd7jZCNMWotjhi
+ vd5zovQlFqQ2Wjc2+y46vKP/iXxWIuQJuDiisyXF0Y8+5GTpAL
+ pHDc1/pIGmMIGjoAMCAQGigZsEgZg2on5mSuxoDHEA1w9bcW9n
+ FdFxDKpdrQhVGVRDIzcCMCTzvUboqb5KjY1NJKJsfjRQiBYBdE
+ NKfzK+g5DlV8nrw81uOcP8NOQCLR5XkoMHC0Dr/80ziQzbNqhx
+ O6652Npft0LQwJvenwDI13YxpwOdMXzkWZN/XrEqOWp6GCgXTB
+ vCyLWLlWnbaUkZdEYbKHBPjd8t/1x5Yg==
+ S: + YGgGCSqGSIb3EgECAgIAb1kwV6ADAgEFoQMCAQ+iSzBJoAMC
+ AQGiQgRAtHTEuOP2BXb9sBYFR4SJlDZxmg39IxmRBOhXRKdDA0
+ uHTCOT9Bq3OsUTXUlk0CsFLoa8j+gvGDlgHuqzWHPSQg==
+ C:
+ S: + YDMGCSqGSIb3EgECAgIBAAD/////6jcyG4GE3KkTzBeBiVHe
+ ceP2CWY0SR0fAQAgAAQEBAQ=
+ C: YDMGCSqGSIb3EgECAgIBAAD/////3LQBHXTpFfZgrejpLlLImP
+ wkhbfa2QteAQAgAG1yYwE=
+ S: A001 OK GSSAPI authentication successful
+
+ Note: The line breaks within server challenges and client
+ responses are for editorial clarity and are not in real
+ authenticators.
+
+
+6.2.3. LOGIN Command
+
+ Arguments: user name
+ password
+
+ Responses: no specific responses for this command
+
+ Result: OK - login completed, now in authenticated state
+ NO - login failure: user name or password rejected
+ BAD - command unknown or arguments invalid
+
+ The LOGIN command identifies the client to the server and carries
+ the plaintext password authenticating this user.
+
+
+
+
+
+
+Crispin Standards Track [Page 30]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ A server MAY include a CAPABILITY response code in the tagged OK
+ response to a successful LOGIN command in order to send
+ capabilities automatically. It is unnecessary for a client to
+ send a separate CAPABILITY command if it recognizes these
+ automatic capabilities.
+
+ Example: C: a001 LOGIN SMITH SESAME
+ S: a001 OK LOGIN completed
+
+ Note: Use of the LOGIN command over an insecure network
+ (such as the Internet) is a security risk, because anyone
+ monitoring network traffic can obtain plaintext passwords.
+ The LOGIN command SHOULD NOT be used except as a last
+ resort, and it is recommended that client implementations
+ have a means to disable any automatic use of the LOGIN
+ command.
+
+ Unless either the STARTTLS command has been negotiated or
+ some other mechanism that protects the session from
+ password snooping has been provided, a server
+ implementation MUST implement a configuration in which it
+ advertises the LOGINDISABLED capability and does NOT permit
+ the LOGIN command. Server sites SHOULD NOT use any
+ configuration which permits the LOGIN command without such
+ a protection mechanism against password snooping. A client
+ implementation MUST NOT send a LOGIN command if the
+ LOGINDISABLED capability is advertised.
+
+6.3. Client Commands - Authenticated State
+
+ In the authenticated state, commands that manipulate mailboxes as
+ atomic entities are permitted. Of these commands, the SELECT and
+ EXAMINE commands will select a mailbox for access and enter the
+ selected state.
+
+ In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
+ the following commands are valid in the authenticated state: SELECT,
+ EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB,
+ STATUS, and APPEND.
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 31]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.3.1. SELECT Command
+
+ Arguments: mailbox name
+
+ Responses: REQUIRED untagged responses: FLAGS, EXISTS, RECENT
+ REQUIRED OK untagged responses: UNSEEN, PERMANENTFLAGS,
+ UIDNEXT, UIDVALIDITY
+
+ Result: OK - select completed, now in selected state
+ NO - select failure, now in authenticated state: no
+ such mailbox, can't access mailbox
+ BAD - command unknown or arguments invalid
+
+ The SELECT command selects a mailbox so that messages in the
+ mailbox can be accessed. Before returning an OK to the client,
+ the server MUST send the following untagged data to the client.
+ Note that earlier versions of this protocol only required the
+ FLAGS, EXISTS, and RECENT untagged data; consequently, client
+ implementations SHOULD implement default behavior for missing data
+ as discussed with the individual item.
+
+ FLAGS Defined flags in the mailbox. See the description
+ of the FLAGS response for more detail.
+
+ <n> EXISTS The number of messages in the mailbox. See the
+ description of the EXISTS response for more detail.
+
+ <n> RECENT The number of messages with the \Recent flag set.
+ See the description of the RECENT response for more
+ detail.
+
+ OK [UNSEEN <n>]
+ The message sequence number of the first unseen
+ message in the mailbox. If this is missing, the
+ client can not make any assumptions about the first
+ unseen message in the mailbox, and needs to issue a
+ SEARCH command if it wants to find it.
+
+ OK [PERMANENTFLAGS (<list of flags>)]
+ A list of message flags that the client can change
+ permanently. If this is missing, the client should
+ assume that all flags can be changed permanently.
+
+ OK [UIDNEXT <n>]
+ The next unique identifier value. Refer to section
+ 2.3.1.1 for more information. If this is missing,
+ the client can not make any assumptions about the
+ next unique identifier value.
+
+
+
+Crispin Standards Track [Page 32]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ OK [UIDVALIDITY <n>]
+ The unique identifier validity value. Refer to
+ section 2.3.1.1 for more information. If this is
+ missing, the server does not support unique
+ identifiers.
+
+ Only one mailbox can be selected at a time in a connection;
+ simultaneous access to multiple mailboxes requires multiple
+ connections. The SELECT command automatically deselects any
+ currently selected mailbox before attempting the new selection.
+ Consequently, if a mailbox is selected and a SELECT command that
+ fails is attempted, no mailbox is selected.
+
+ If the client is permitted to modify the mailbox, the server
+ SHOULD prefix the text of the tagged OK response with the
+ "[READ-WRITE]" response code.
+
+ If the client is not permitted to modify the mailbox but is
+ permitted read access, the mailbox is selected as read-only, and
+ the server MUST prefix the text of the tagged OK response to
+ SELECT with the "[READ-ONLY]" response code. Read-only access
+ through SELECT differs from the EXAMINE command in that certain
+ read-only mailboxes MAY permit the change of permanent state on a
+ per-user (as opposed to global) basis. Netnews messages marked in
+ a server-based .newsrc file are an example of such per-user
+ permanent state that can be modified with read-only mailboxes.
+
+ Example: C: A142 SELECT INBOX
+ S: * 172 EXISTS
+ S: * 1 RECENT
+ S: * OK [UNSEEN 12] Message 12 is first unseen
+ S: * OK [UIDVALIDITY 3857529045] UIDs valid
+ S: * OK [UIDNEXT 4392] Predicted next UID
+ S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+ S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+ S: A142 OK [READ-WRITE] SELECT completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 33]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.3.2. EXAMINE Command
+
+ Arguments: mailbox name
+
+ Responses: REQUIRED untagged responses: FLAGS, EXISTS, RECENT
+ REQUIRED OK untagged responses: UNSEEN, PERMANENTFLAGS,
+ UIDNEXT, UIDVALIDITY
+
+ Result: OK - examine completed, now in selected state
+ NO - examine failure, now in authenticated state: no
+ such mailbox, can't access mailbox
+ BAD - command unknown or arguments invalid
+
+ The EXAMINE command is identical to SELECT and returns the same
+ output; however, the selected mailbox is identified as read-only.
+ No changes to the permanent state of the mailbox, including
+ per-user state, are permitted; in particular, EXAMINE MUST NOT
+ cause messages to lose the \Recent flag.
+
+ The text of the tagged OK response to the EXAMINE command MUST
+ begin with the "[READ-ONLY]" response code.
+
+ Example: C: A932 EXAMINE blurdybloop
+ S: * 17 EXISTS
+ S: * 2 RECENT
+ S: * OK [UNSEEN 8] Message 8 is first unseen
+ S: * OK [UIDVALIDITY 3857529045] UIDs valid
+ S: * OK [UIDNEXT 4392] Predicted next UID
+ S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+ S: * OK [PERMANENTFLAGS ()] No permanent flags permitted
+ S: A932 OK [READ-ONLY] EXAMINE completed
+
+
+6.3.3. CREATE Command
+
+ Arguments: mailbox name
+
+ Responses: no specific responses for this command
+
+ Result: OK - create completed
+ NO - create failure: can't create mailbox with that name
+ BAD - command unknown or arguments invalid
+
+ The CREATE command creates a mailbox with the given name. An OK
+ response is returned only if a new mailbox with that name has been
+ created. It is an error to attempt to create INBOX or a mailbox
+ with a name that refers to an extant mailbox. Any error in
+ creation will return a tagged NO response.
+
+
+
+Crispin Standards Track [Page 34]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ If the mailbox name is suffixed with the server's hierarchy
+ separator character (as returned from the server by a LIST
+ command), this is a declaration that the client intends to create
+ mailbox names under this name in the hierarchy. Server
+ implementations that do not require this declaration MUST ignore
+ the declaration. In any case, the name created is without the
+ trailing hierarchy delimiter.
+
+ If the server's hierarchy separator character appears elsewhere in
+ the name, the server SHOULD create any superior hierarchical names
+ that are needed for the CREATE command to be successfully
+ completed. In other words, an attempt to create "foo/bar/zap" on
+ a server in which "/" is the hierarchy separator character SHOULD
+ create foo/ and foo/bar/ if they do not already exist.
+
+ If a new mailbox is created with the same name as a mailbox which
+ was deleted, its unique identifiers MUST be greater than any
+ unique identifiers used in the previous incarnation of the mailbox
+ UNLESS the new incarnation has a different unique identifier
+ validity value. See the description of the UID command for more
+ detail.
+
+ Example: C: A003 CREATE owatagusiam/
+ S: A003 OK CREATE completed
+ C: A004 CREATE owatagusiam/blurdybloop
+ S: A004 OK CREATE completed
+
+ Note: The interpretation of this example depends on whether
+ "/" was returned as the hierarchy separator from LIST. If
+ "/" is the hierarchy separator, a new level of hierarchy
+ named "owatagusiam" with a member called "blurdybloop" is
+ created. Otherwise, two mailboxes at the same hierarchy
+ level are created.
+
+
+6.3.4. DELETE Command
+
+ Arguments: mailbox name
+
+ Responses: no specific responses for this command
+
+ Result: OK - delete completed
+ NO - delete failure: can't delete mailbox with that name
+ BAD - command unknown or arguments invalid
+
+
+
+
+
+
+
+Crispin Standards Track [Page 35]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The DELETE command permanently removes the mailbox with the given
+ name. A tagged OK response is returned only if the mailbox has
+ been deleted. It is an error to attempt to delete INBOX or a
+ mailbox name that does not exist.
+
+ The DELETE command MUST NOT remove inferior hierarchical names.
+ For example, if a mailbox "foo" has an inferior "foo.bar"
+ (assuming "." is the hierarchy delimiter character), removing
+ "foo" MUST NOT remove "foo.bar". It is an error to attempt to
+ delete a name that has inferior hierarchical names and also has
+ the \Noselect mailbox name attribute (see the description of the
+ LIST response for more details).
+
+ It is permitted to delete a name that has inferior hierarchical
+ names and does not have the \Noselect mailbox name attribute. In
+ this case, all messages in that mailbox are removed, and the name
+ will acquire the \Noselect mailbox name attribute.
+
+ The value of the highest-used unique identifier of the deleted
+ mailbox MUST be preserved so that a new mailbox created with the
+ same name will not reuse the identifiers of the former
+ incarnation, UNLESS the new incarnation has a different unique
+ identifier validity value. See the description of the UID command
+ for more detail.
+
+ Examples: C: A682 LIST "" *
+ S: * LIST () "/" blurdybloop
+ S: * LIST (\Noselect) "/" foo
+ S: * LIST () "/" foo/bar
+ S: A682 OK LIST completed
+ C: A683 DELETE blurdybloop
+ S: A683 OK DELETE completed
+ C: A684 DELETE foo
+ S: A684 NO Name "foo" has inferior hierarchical names
+ C: A685 DELETE foo/bar
+ S: A685 OK DELETE Completed
+ C: A686 LIST "" *
+ S: * LIST (\Noselect) "/" foo
+ S: A686 OK LIST completed
+ C: A687 DELETE foo
+ S: A687 OK DELETE Completed
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 36]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ C: A82 LIST "" *
+ S: * LIST () "." blurdybloop
+ S: * LIST () "." foo
+ S: * LIST () "." foo.bar
+ S: A82 OK LIST completed
+ C: A83 DELETE blurdybloop
+ S: A83 OK DELETE completed
+ C: A84 DELETE foo
+ S: A84 OK DELETE Completed
+ C: A85 LIST "" *
+ S: * LIST () "." foo.bar
+ S: A85 OK LIST completed
+ C: A86 LIST "" %
+ S: * LIST (\Noselect) "." foo
+ S: A86 OK LIST completed
+
+
+6.3.5. RENAME Command
+
+ Arguments: existing mailbox name
+ new mailbox name
+
+ Responses: no specific responses for this command
+
+ Result: OK - rename completed
+ NO - rename failure: can't rename mailbox with that name,
+ can't rename to mailbox with that name
+ BAD - command unknown or arguments invalid
+
+ The RENAME command changes the name of a mailbox. A tagged OK
+ response is returned only if the mailbox has been renamed. It is
+ an error to attempt to rename from a mailbox name that does not
+ exist or to a mailbox name that already exists. Any error in
+ renaming will return a tagged NO response.
+
+ If the name has inferior hierarchical names, then the inferior
+ hierarchical names MUST also be renamed. For example, a rename of
+ "foo" to "zap" will rename "foo/bar" (assuming "/" is the
+ hierarchy delimiter character) to "zap/bar".
+
+ If the server's hierarchy separator character appears in the name,
+ the server SHOULD create any superior hierarchical names that are
+ needed for the RENAME command to complete successfully. In other
+ words, an attempt to rename "foo/bar/zap" to baz/rag/zowie on a
+ server in which "/" is the hierarchy separator character SHOULD
+ create baz/ and baz/rag/ if they do not already exist.
+
+
+
+
+
+Crispin Standards Track [Page 37]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The value of the highest-used unique identifier of the old mailbox
+ name MUST be preserved so that a new mailbox created with the same
+ name will not reuse the identifiers of the former incarnation,
+ UNLESS the new incarnation has a different unique identifier
+ validity value. See the description of the UID command for more
+ detail.
+
+ Renaming INBOX is permitted, and has special behavior. It moves
+ all messages in INBOX to a new mailbox with the given name,
+ leaving INBOX empty. If the server implementation supports
+ inferior hierarchical names of INBOX, these are unaffected by a
+ rename of INBOX.
+
+ Examples: C: A682 LIST "" *
+ S: * LIST () "/" blurdybloop
+ S: * LIST (\Noselect) "/" foo
+ S: * LIST () "/" foo/bar
+ S: A682 OK LIST completed
+ C: A683 RENAME blurdybloop sarasoop
+ S: A683 OK RENAME completed
+ C: A684 RENAME foo zowie
+ S: A684 OK RENAME Completed
+ C: A685 LIST "" *
+ S: * LIST () "/" sarasoop
+ S: * LIST (\Noselect) "/" zowie
+ S: * LIST () "/" zowie/bar
+ S: A685 OK LIST completed
+
+ C: Z432 LIST "" *
+ S: * LIST () "." INBOX
+ S: * LIST () "." INBOX.bar
+ S: Z432 OK LIST completed
+ C: Z433 RENAME INBOX old-mail
+ S: Z433 OK RENAME completed
+ C: Z434 LIST "" *
+ S: * LIST () "." INBOX
+ S: * LIST () "." INBOX.bar
+ S: * LIST () "." old-mail
+ S: Z434 OK LIST completed
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 38]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.3.6. SUBSCRIBE Command
+
+ Arguments: mailbox
+
+ Responses: no specific responses for this command
+
+ Result: OK - subscribe completed
+ NO - subscribe failure: can't subscribe to that name
+ BAD - command unknown or arguments invalid
+
+ The SUBSCRIBE command adds the specified mailbox name to the
+ server's set of "active" or "subscribed" mailboxes as returned by
+ the LSUB command. This command returns a tagged OK response only
+ if the subscription is successful.
+
+ A server MAY validate the mailbox argument to SUBSCRIBE to verify
+ that it exists. However, it MUST NOT unilaterally remove an
+ existing mailbox name from the subscription list even if a mailbox
+ by that name no longer exists.
+
+ Note: This requirement is because a server site can
+ choose to routinely remove a mailbox with a well-known
+ name (e.g., "system-alerts") after its contents expire,
+ with the intention of recreating it when new contents
+ are appropriate.
+
+
+ Example: C: A002 SUBSCRIBE #news.comp.mail.mime
+ S: A002 OK SUBSCRIBE completed
+
+
+6.3.7. UNSUBSCRIBE Command
+
+ Arguments: mailbox name
+
+ Responses: no specific responses for this command
+
+ Result: OK - unsubscribe completed
+ NO - unsubscribe failure: can't unsubscribe that name
+ BAD - command unknown or arguments invalid
+
+ The UNSUBSCRIBE command removes the specified mailbox name from
+ the server's set of "active" or "subscribed" mailboxes as returned
+ by the LSUB command. This command returns a tagged OK response
+ only if the unsubscription is successful.
+
+ Example: C: A002 UNSUBSCRIBE #news.comp.mail.mime
+ S: A002 OK UNSUBSCRIBE completed
+
+
+
+Crispin Standards Track [Page 39]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.3.8. LIST Command
+
+ Arguments: reference name
+ mailbox name with possible wildcards
+
+ Responses: untagged responses: LIST
+
+ Result: OK - list completed
+ NO - list failure: can't list that reference or name
+ BAD - command unknown or arguments invalid
+
+ The LIST command returns a subset of names from the complete set
+ of all names available to the client. Zero or more untagged LIST
+ replies are returned, containing the name attributes, hierarchy
+ delimiter, and name; see the description of the LIST reply for
+ more detail.
+
+ The LIST command SHOULD return its data quickly, without undue
+ delay. For example, it SHOULD NOT go to excess trouble to
+ calculate the \Marked or \Unmarked status or perform other
+ processing; if each name requires 1 second of processing, then a
+ list of 1200 names would take 20 minutes!
+
+ An empty ("" string) reference name argument indicates that the
+ mailbox name is interpreted as by SELECT. The returned mailbox
+ names MUST match the supplied mailbox name pattern. A non-empty
+ reference name argument is the name of a mailbox or a level of
+ mailbox hierarchy, and indicates the context in which the mailbox
+ name is interpreted.
+
+ An empty ("" string) mailbox name argument is a special request to
+ return the hierarchy delimiter and the root name of the name given
+ in the reference. The value returned as the root MAY be the empty
+ string if the reference is non-rooted or is an empty string. In
+ all cases, a hierarchy delimiter (or NIL if there is no hierarchy)
+ is returned. This permits a client to get the hierarchy delimiter
+ (or find out that the mailbox names are flat) even when no
+ mailboxes by that name currently exist.
+
+ The reference and mailbox name arguments are interpreted into a
+ canonical form that represents an unambiguous left-to-right
+ hierarchy. The returned mailbox names will be in the interpreted
+ form.
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 40]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Note: The interpretation of the reference argument is
+ implementation-defined. It depends upon whether the
+ server implementation has a concept of the "current
+ working directory" and leading "break out characters",
+ which override the current working directory.
+
+ For example, on a server which exports a UNIX or NT
+ filesystem, the reference argument contains the current
+ working directory, and the mailbox name argument would
+ contain the name as interpreted in the current working
+ directory.
+
+ If a server implementation has no concept of break out
+ characters, the canonical form is normally the reference
+ name appended with the mailbox name. Note that if the
+ server implements the namespace convention (section
+ 5.1.2), "#" is a break out character and must be treated
+ as such.
+
+ If the reference argument is not a level of mailbox
+ hierarchy (that is, it is a \NoInferiors name), and/or
+ the reference argument does not end with the hierarchy
+ delimiter, it is implementation-dependent how this is
+ interpreted. For example, a reference of "foo/bar" and
+ mailbox name of "rag/baz" could be interpreted as
+ "foo/bar/rag/baz", "foo/barrag/baz", or "foo/rag/baz".
+ A client SHOULD NOT use such a reference argument except
+ at the explicit request of the user. A hierarchical
+ browser MUST NOT make any assumptions about server
+ interpretation of the reference unless the reference is
+ a level of mailbox hierarchy AND ends with the hierarchy
+ delimiter.
+
+ Any part of the reference argument that is included in the
+ interpreted form SHOULD prefix the interpreted form. It SHOULD
+ also be in the same form as the reference name argument. This
+ rule permits the client to determine if the returned mailbox name
+ is in the context of the reference argument, or if something about
+ the mailbox argument overrode the reference argument. Without
+ this rule, the client would have to have knowledge of the server's
+ naming semantics including what characters are "breakouts" that
+ override a naming context.
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 41]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ For example, here are some examples of how references
+ and mailbox names might be interpreted on a UNIX-based
+ server:
+
+ Reference Mailbox Name Interpretation
+ ------------ ------------ --------------
+ ~smith/Mail/ foo.* ~smith/Mail/foo.*
+ archive/ % archive/%
+ #news. comp.mail.* #news.comp.mail.*
+ ~smith/Mail/ /usr/doc/foo /usr/doc/foo
+ archive/ ~fred/Mail/* ~fred/Mail/*
+
+ The first three examples demonstrate interpretations in
+ the context of the reference argument. Note that
+ "~smith/Mail" SHOULD NOT be transformed into something
+ like "/u2/users/smith/Mail", or it would be impossible
+ for the client to determine that the interpretation was
+ in the context of the reference.
+
+ The character "*" is a wildcard, and matches zero or more
+ characters at this position. The character "%" is similar to "*",
+ but it does not match a hierarchy delimiter. If the "%" wildcard
+ is the last character of a mailbox name argument, matching levels
+ of hierarchy are also returned. If these levels of hierarchy are
+ not also selectable mailboxes, they are returned with the
+ \Noselect mailbox name attribute (see the description of the LIST
+ response for more details).
+
+ Server implementations are permitted to "hide" otherwise
+ accessible mailboxes from the wildcard characters, by preventing
+ certain characters or names from matching a wildcard in certain
+ situations. For example, a UNIX-based server might restrict the
+ interpretation of "*" so that an initial "/" character does not
+ match.
+
+ The special name INBOX is included in the output from LIST, if
+ INBOX is supported by this server for this user and if the
+ uppercase string "INBOX" matches the interpreted reference and
+ mailbox name arguments with wildcards as described above. The
+ criteria for omitting INBOX is whether SELECT INBOX will return
+ failure; it is not relevant whether the user's real INBOX resides
+ on this or some other server.
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 42]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Example: C: A101 LIST "" ""
+ S: * LIST (\Noselect) "/" ""
+ S: A101 OK LIST Completed
+ C: A102 LIST #news.comp.mail.misc ""
+ S: * LIST (\Noselect) "." #news.
+ S: A102 OK LIST Completed
+ C: A103 LIST /usr/staff/jones ""
+ S: * LIST (\Noselect) "/" /
+ S: A103 OK LIST Completed
+ C: A202 LIST ~/Mail/ %
+ S: * LIST (\Noselect) "/" ~/Mail/foo
+ S: * LIST () "/" ~/Mail/meetings
+ S: A202 OK LIST completed
+
+
+6.3.9. LSUB Command
+
+ Arguments: reference name
+ mailbox name with possible wildcards
+
+ Responses: untagged responses: LSUB
+
+ Result: OK - lsub completed
+ NO - lsub failure: can't list that reference or name
+ BAD - command unknown or arguments invalid
+
+ The LSUB command returns a subset of names from the set of names
+ that the user has declared as being "active" or "subscribed".
+ Zero or more untagged LSUB replies are returned. The arguments to
+ LSUB are in the same form as those for LIST.
+
+ The returned untagged LSUB response MAY contain different mailbox
+ flags from a LIST untagged response. If this should happen, the
+ flags in the untagged LIST are considered more authoritative.
+
+ A special situation occurs when using LSUB with the % wildcard.
+ Consider what happens if "foo/bar" (with a hierarchy delimiter of
+ "/") is subscribed but "foo" is not. A "%" wildcard to LSUB must
+ return foo, not foo/bar, in the LSUB response, and it MUST be
+ flagged with the \Noselect attribute.
+
+ The server MUST NOT unilaterally remove an existing mailbox name
+ from the subscription list even if a mailbox by that name no
+ longer exists.
+
+
+
+
+
+
+
+Crispin Standards Track [Page 43]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Example: C: A002 LSUB "#news." "comp.mail.*"
+ S: * LSUB () "." #news.comp.mail.mime
+ S: * LSUB () "." #news.comp.mail.misc
+ S: A002 OK LSUB completed
+ C: A003 LSUB "#news." "comp.%"
+ S: * LSUB (\NoSelect) "." #news.comp.mail
+ S: A003 OK LSUB completed
+
+
+6.3.10. STATUS Command
+
+ Arguments: mailbox name
+ status data item names
+
+ Responses: untagged responses: STATUS
+
+ Result: OK - status completed
+ NO - status failure: no status for that name
+ BAD - command unknown or arguments invalid
+
+ The STATUS command requests the status of the indicated mailbox.
+ It does not change the currently selected mailbox, nor does it
+ affect the state of any messages in the queried mailbox (in
+ particular, STATUS MUST NOT cause messages to lose the \Recent
+ flag).
+
+ The STATUS command provides an alternative to opening a second
+ IMAP4rev1 connection and doing an EXAMINE command on a mailbox to
+ query that mailbox's status without deselecting the current
+ mailbox in the first IMAP4rev1 connection.
+
+ Unlike the LIST command, the STATUS command is not guaranteed to
+ be fast in its response. Under certain circumstances, it can be
+ quite slow. In some implementations, the server is obliged to
+ open the mailbox read-only internally to obtain certain status
+ information. Also unlike the LIST command, the STATUS command
+ does not accept wildcards.
+
+ Note: The STATUS command is intended to access the
+ status of mailboxes other than the currently selected
+ mailbox. Because the STATUS command can cause the
+ mailbox to be opened internally, and because this
+ information is available by other means on the selected
+ mailbox, the STATUS command SHOULD NOT be used on the
+ currently selected mailbox.
+
+
+
+
+
+
+Crispin Standards Track [Page 44]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The STATUS command MUST NOT be used as a "check for new
+ messages in the selected mailbox" operation (refer to
+ sections 7, 7.3.1, and 7.3.2 for more information about
+ the proper method for new message checking).
+
+ Because the STATUS command is not guaranteed to be fast
+ in its results, clients SHOULD NOT expect to be able to
+ issue many consecutive STATUS commands and obtain
+ reasonable performance.
+
+ The currently defined status data items that can be requested are:
+
+ MESSAGES
+ The number of messages in the mailbox.
+
+ RECENT
+ The number of messages with the \Recent flag set.
+
+ UIDNEXT
+ The next unique identifier value of the mailbox. Refer to
+ section 2.3.1.1 for more information.
+
+ UIDVALIDITY
+ The unique identifier validity value of the mailbox. Refer to
+ section 2.3.1.1 for more information.
+
+ UNSEEN
+ The number of messages which do not have the \Seen flag set.
+
+
+ Example: C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
+ S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
+ S: A042 OK STATUS completed
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 45]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.3.11. APPEND Command
+
+ Arguments: mailbox name
+ OPTIONAL flag parenthesized list
+ OPTIONAL date/time string
+ message literal
+
+ Responses: no specific responses for this command
+
+ Result: OK - append completed
+ NO - append error: can't append to that mailbox, error
+ in flags or date/time or message text
+ BAD - command unknown or arguments invalid
+
+ The APPEND command appends the literal argument as a new message
+ to the end of the specified destination mailbox. This argument
+ SHOULD be in the format of an [RFC-2822] message. 8-bit
+ characters are permitted in the message. A server implementation
+ that is unable to preserve 8-bit data properly MUST be able to
+ reversibly convert 8-bit APPEND data to 7-bit using a [MIME-IMB]
+ content transfer encoding.
+
+ Note: There MAY be exceptions, e.g., draft messages, in
+ which required [RFC-2822] header lines are omitted in
+ the message literal argument to APPEND. The full
+ implications of doing so MUST be understood and
+ carefully weighed.
+
+ If a flag parenthesized list is specified, the flags SHOULD be set
+ in the resulting message; otherwise, the flag list of the
+ resulting message is set to empty by default. In either case, the
+ Recent flag is also set.
+
+ If a date-time is specified, the internal date SHOULD be set in
+ the resulting message; otherwise, the internal date of the
+ resulting message is set to the current date and time by default.
+
+ If the append is unsuccessful for any reason, the mailbox MUST be
+ restored to its state before the APPEND attempt; no partial
+ appending is permitted.
+
+ If the destination mailbox does not exist, a server MUST return an
+ error, and MUST NOT automatically create the mailbox. Unless it
+ is certain that the destination mailbox can not be created, the
+ server MUST send the response code "[TRYCREATE]" as the prefix of
+ the text of the tagged NO response. This gives a hint to the
+ client that it can attempt a CREATE command and retry the APPEND
+ if the CREATE is successful.
+
+
+
+Crispin Standards Track [Page 46]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ If the mailbox is currently selected, the normal new message
+ actions SHOULD occur. Specifically, the server SHOULD notify the
+ client immediately via an untagged EXISTS response. If the server
+ does not do so, the client MAY issue a NOOP command (or failing
+ that, a CHECK command) after one or more APPEND commands.
+
+ Example: C: A003 APPEND saved-messages (\Seen) {310}
+ S: + Ready for literal data
+ C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+ C: From: Fred Foobar <foobar@Blurdybloop.COM>
+ C: Subject: afternoon meeting
+ C: To: mooch@owatagu.siam.edu
+ C: Message-Id: <B27397-0100000@Blurdybloop.COM>
+ C: MIME-Version: 1.0
+ C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+ C:
+ C: Hello Joe, do you think we can meet at 3:30 tomorrow?
+ C:
+ S: A003 OK APPEND completed
+
+ Note: The APPEND command is not used for message delivery,
+ because it does not provide a mechanism to transfer [SMTP]
+ envelope information.
+
+6.4. Client Commands - Selected State
+
+ In the selected state, commands that manipulate messages in a mailbox
+ are permitted.
+
+ In addition to the universal commands (CAPABILITY, NOOP, and LOGOUT),
+ and the authenticated state commands (SELECT, EXAMINE, CREATE,
+ DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, STATUS, and
+ APPEND), the following commands are valid in the selected state:
+ CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, and UID.
+
+6.4.1. CHECK Command
+
+ Arguments: none
+
+ Responses: no specific responses for this command
+
+ Result: OK - check completed
+ BAD - command unknown or arguments invalid
+
+ The CHECK command requests a checkpoint of the currently selected
+ mailbox. A checkpoint refers to any implementation-dependent
+ housekeeping associated with the mailbox (e.g., resolving the
+ server's in-memory state of the mailbox with the state on its
+
+
+
+Crispin Standards Track [Page 47]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ disk) that is not normally executed as part of each command. A
+ checkpoint MAY take a non-instantaneous amount of real time to
+ complete. If a server implementation has no such housekeeping
+ considerations, CHECK is equivalent to NOOP.
+
+ There is no guarantee that an EXISTS untagged response will happen
+ as a result of CHECK. NOOP, not CHECK, SHOULD be used for new
+ message polling.
+
+ Example: C: FXXZ CHECK
+ S: FXXZ OK CHECK Completed
+
+
+6.4.2. CLOSE Command
+
+ Arguments: none
+
+ Responses: no specific responses for this command
+
+ Result: OK - close completed, now in authenticated state
+ BAD - command unknown or arguments invalid
+
+ The CLOSE command permanently removes all messages that have the
+ \Deleted flag set from the currently selected mailbox, and returns
+ to the authenticated state from the selected state. No untagged
+ EXPUNGE responses are sent.
+
+ No messages are removed, and no error is given, if the mailbox is
+ selected by an EXAMINE command or is otherwise selected read-only.
+
+ Even if a mailbox is selected, a SELECT, EXAMINE, or LOGOUT
+ command MAY be issued without previously issuing a CLOSE command.
+ The SELECT, EXAMINE, and LOGOUT commands implicitly close the
+ currently selected mailbox without doing an expunge. However,
+ when many messages are deleted, a CLOSE-LOGOUT or CLOSE-SELECT
+ sequence is considerably faster than an EXPUNGE-LOGOUT or
+ EXPUNGE-SELECT because no untagged EXPUNGE responses (which the
+ client would probably ignore) are sent.
+
+ Example: C: A341 CLOSE
+ S: A341 OK CLOSE completed
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 48]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.4.3. EXPUNGE Command
+
+ Arguments: none
+
+ Responses: untagged responses: EXPUNGE
+
+ Result: OK - expunge completed
+ NO - expunge failure: can't expunge (e.g., permission
+ denied)
+ BAD - command unknown or arguments invalid
+
+ The EXPUNGE command permanently removes all messages that have the
+ \Deleted flag set from the currently selected mailbox. Before
+ returning an OK to the client, an untagged EXPUNGE response is
+ sent for each message that is removed.
+
+ Example: C: A202 EXPUNGE
+ S: * 3 EXPUNGE
+ S: * 3 EXPUNGE
+ S: * 5 EXPUNGE
+ S: * 8 EXPUNGE
+ S: A202 OK EXPUNGE completed
+
+ Note: In this example, messages 3, 4, 7, and 11 had the
+ \Deleted flag set. See the description of the EXPUNGE
+ response for further explanation.
+
+
+6.4.4. SEARCH Command
+
+ Arguments: OPTIONAL [CHARSET] specification
+ searching criteria (one or more)
+
+ Responses: REQUIRED untagged response: SEARCH
+
+ Result: OK - search completed
+ NO - search error: can't search that [CHARSET] or
+ criteria
+ BAD - command unknown or arguments invalid
+
+ The SEARCH command searches the mailbox for messages that match
+ the given searching criteria. Searching criteria consist of one
+ or more search keys. The untagged SEARCH response from the server
+ contains a listing of message sequence numbers corresponding to
+ those messages that match the searching criteria.
+
+
+
+
+
+
+Crispin Standards Track [Page 49]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ When multiple keys are specified, the result is the intersection
+ (AND function) of all the messages that match those keys. For
+ example, the criteria DELETED FROM "SMITH" SINCE 1-Feb-1994 refers
+ to all deleted messages from Smith that were placed in the mailbox
+ since February 1, 1994. A search key can also be a parenthesized
+ list of one or more search keys (e.g., for use with the OR and NOT
+ keys).
+
+ Server implementations MAY exclude [MIME-IMB] body parts with
+ terminal content media types other than TEXT and MESSAGE from
+ consideration in SEARCH matching.
+
+ The OPTIONAL [CHARSET] specification consists of the word
+ "CHARSET" followed by a registered [CHARSET]. It indicates the
+ [CHARSET] of the strings that appear in the search criteria.
+ [MIME-IMB] content transfer encodings, and [MIME-HDRS] strings in
+ [RFC-2822]/[MIME-IMB] headers, MUST be decoded before comparing
+ text in a [CHARSET] other than US-ASCII. US-ASCII MUST be
+ supported; other [CHARSET]s MAY be supported.
+
+ If the server does not support the specified [CHARSET], it MUST
+ return a tagged NO response (not a BAD). This response SHOULD
+ contain the BADCHARSET response code, which MAY list the
+ [CHARSET]s supported by the server.
+
+ In all search keys that use strings, a message matches the key if
+ the string is a substring of the field. The matching is
+ case-insensitive.
+
+ The defined search keys are as follows. Refer to the Formal
+ Syntax section for the precise syntactic definitions of the
+ arguments.
+
+ <sequence set>
+ Messages with message sequence numbers corresponding to the
+ specified message sequence number set.
+
+ ALL
+ All messages in the mailbox; the default initial key for
+ ANDing.
+
+ ANSWERED
+ Messages with the \Answered flag set.
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 50]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ BCC <string>
+ Messages that contain the specified string in the envelope
+ structure's BCC field.
+
+ BEFORE <date>
+ Messages whose internal date (disregarding time and timezone)
+ is earlier than the specified date.
+
+ BODY <string>
+ Messages that contain the specified string in the body of the
+ message.
+
+ CC <string>
+ Messages that contain the specified string in the envelope
+ structure's CC field.
+
+ DELETED
+ Messages with the \Deleted flag set.
+
+ DRAFT
+ Messages with the \Draft flag set.
+
+ FLAGGED
+ Messages with the \Flagged flag set.
+
+ FROM <string>
+ Messages that contain the specified string in the envelope
+ structure's FROM field.
+
+ HEADER <field-name> <string>
+ Messages that have a header with the specified field-name (as
+ defined in [RFC-2822]) and that contains the specified string
+ in the text of the header (what comes after the colon). If the
+ string to search is zero-length, this matches all messages that
+ have a header line with the specified field-name regardless of
+ the contents.
+
+ KEYWORD <flag>
+ Messages with the specified keyword flag set.
+
+ LARGER <n>
+ Messages with an [RFC-2822] size larger than the specified
+ number of octets.
+
+ NEW
+ Messages that have the \Recent flag set but not the \Seen flag.
+ This is functionally equivalent to "(RECENT UNSEEN)".
+
+
+
+
+Crispin Standards Track [Page 51]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ NOT <search-key>
+ Messages that do not match the specified search key.
+
+ OLD
+ Messages that do not have the \Recent flag set. This is
+ functionally equivalent to "NOT RECENT" (as opposed to "NOT
+ NEW").
+
+ ON <date>
+ Messages whose internal date (disregarding time and timezone)
+ is within the specified date.
+
+ OR <search-key1> <search-key2>
+ Messages that match either search key.
+
+ RECENT
+ Messages that have the \Recent flag set.
+
+ SEEN
+ Messages that have the \Seen flag set.
+
+ SENTBEFORE <date>
+ Messages whose [RFC-2822] Date: header (disregarding time and
+ timezone) is earlier than the specified date.
+
+ SENTON <date>
+ Messages whose [RFC-2822] Date: header (disregarding time and
+ timezone) is within the specified date.
+
+ SENTSINCE <date>
+ Messages whose [RFC-2822] Date: header (disregarding time and
+ timezone) is within or later than the specified date.
+
+ SINCE <date>
+ Messages whose internal date (disregarding time and timezone)
+ is within or later than the specified date.
+
+ SMALLER <n>
+ Messages with an [RFC-2822] size smaller than the specified
+ number of octets.
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 52]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ SUBJECT <string>
+ Messages that contain the specified string in the envelope
+ structure's SUBJECT field.
+
+ TEXT <string>
+ Messages that contain the specified string in the header or
+ body of the message.
+
+ TO <string>
+ Messages that contain the specified string in the envelope
+ structure's TO field.
+
+ UID <sequence set>
+ Messages with unique identifiers corresponding to the specified
+ unique identifier set. Sequence set ranges are permitted.
+
+ UNANSWERED
+ Messages that do not have the \Answered flag set.
+
+ UNDELETED
+ Messages that do not have the \Deleted flag set.
+
+ UNDRAFT
+ Messages that do not have the \Draft flag set.
+
+ UNFLAGGED
+ Messages that do not have the \Flagged flag set.
+
+ UNKEYWORD <flag>
+ Messages that do not have the specified keyword flag set.
+
+ UNSEEN
+ Messages that do not have the \Seen flag set.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 53]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Example: C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"
+ S: * SEARCH 2 84 882
+ S: A282 OK SEARCH completed
+ C: A283 SEARCH TEXT "string not in mailbox"
+ S: * SEARCH
+ S: A283 OK SEARCH completed
+ C: A284 SEARCH CHARSET UTF-8 TEXT {6}
+ C: XXXXXX
+ S: * SEARCH 43
+ S: A284 OK SEARCH completed
+
+ Note: Since this document is restricted to 7-bit ASCII
+ text, it is not possible to show actual UTF-8 data. The
+ "XXXXXX" is a placeholder for what would be 6 octets of
+ 8-bit data in an actual transaction.
+
+
+6.4.5. FETCH Command
+
+ Arguments: sequence set
+ message data item names or macro
+
+ Responses: untagged responses: FETCH
+
+ Result: OK - fetch completed
+ NO - fetch error: can't fetch that data
+ BAD - command unknown or arguments invalid
+
+ The FETCH command retrieves data associated with a message in the
+ mailbox. The data items to be fetched can be either a single atom
+ or a parenthesized list.
+
+ Most data items, identified in the formal syntax under the
+ msg-att-static rule, are static and MUST NOT change for any
+ particular message. Other data items, identified in the formal
+ syntax under the msg-att-dynamic rule, MAY change, either as a
+ result of a STORE command or due to external events.
+
+ For example, if a client receives an ENVELOPE for a
+ message when it already knows the envelope, it can
+ safely ignore the newly transmitted envelope.
+
+ There are three macros which specify commonly-used sets of data
+ items, and can be used instead of data items. A macro must be
+ used by itself, and not in conjunction with other macros or data
+ items.
+
+
+
+
+
+Crispin Standards Track [Page 54]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ ALL
+ Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
+
+ FAST
+ Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)
+
+ FULL
+ Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE
+ BODY)
+
+ The currently defined data items that can be fetched are:
+
+ BODY
+ Non-extensible form of BODYSTRUCTURE.
+
+ BODY[<section>]<<partial>>
+ The text of a particular body section. The section
+ specification is a set of zero or more part specifiers
+ delimited by periods. A part specifier is either a part number
+ or one of the following: HEADER, HEADER.FIELDS,
+ HEADER.FIELDS.NOT, MIME, and TEXT. An empty section
+ specification refers to the entire message, including the
+ header.
+
+ Every message has at least one part number. Non-[MIME-IMB]
+ messages, and non-multipart [MIME-IMB] messages with no
+ encapsulated message, only have a part 1.
+
+ Multipart messages are assigned consecutive part numbers, as
+ they occur in the message. If a particular part is of type
+ message or multipart, its parts MUST be indicated by a period
+ followed by the part number within that nested multipart part.
+
+ A part of type MESSAGE/RFC822 also has nested part numbers,
+ referring to parts of the MESSAGE part's body.
+
+ The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part
+ specifiers can be the sole part specifier or can be prefixed by
+ one or more numeric part specifiers, provided that the numeric
+ part specifier refers to a part of type MESSAGE/RFC822. The
+ MIME part specifier MUST be prefixed by one or more numeric
+ part specifiers.
+
+ The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part
+ specifiers refer to the [RFC-2822] header of the message or of
+ an encapsulated [MIME-IMT] MESSAGE/RFC822 message.
+ HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of
+ field-name (as defined in [RFC-2822]) names, and return a
+
+
+
+Crispin Standards Track [Page 55]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ subset of the header. The subset returned by HEADER.FIELDS
+ contains only those header fields with a field-name that
+ matches one of the names in the list; similarly, the subset
+ returned by HEADER.FIELDS.NOT contains only the header fields
+ with a non-matching field-name. The field-matching is
+ case-insensitive but otherwise exact. Subsetting does not
+ exclude the [RFC-2822] delimiting blank line between the header
+ and the body; the blank line is included in all header fetches,
+ except in the case of a message which has no body and no blank
+ line.
+
+ The MIME part specifier refers to the [MIME-IMB] header for
+ this part.
+
+ The TEXT part specifier refers to the text body of the message,
+ omitting the [RFC-2822] header.
+
+ Here is an example of a complex message with some of its
+ part specifiers:
+
+ HEADER ([RFC-2822] header of the message)
+ TEXT ([RFC-2822] text body of the message) MULTIPART/MIXED
+ 1 TEXT/PLAIN
+ 2 APPLICATION/OCTET-STREAM
+ 3 MESSAGE/RFC822
+ 3.HEADER ([RFC-2822] header of the message)
+ 3.TEXT ([RFC-2822] text body of the message) MULTIPART/MIXED
+ 3.1 TEXT/PLAIN
+ 3.2 APPLICATION/OCTET-STREAM
+ 4 MULTIPART/MIXED
+ 4.1 IMAGE/GIF
+ 4.1.MIME ([MIME-IMB] header for the IMAGE/GIF)
+ 4.2 MESSAGE/RFC822
+ 4.2.HEADER ([RFC-2822] header of the message)
+ 4.2.TEXT ([RFC-2822] text body of the message) MULTIPART/MIXED
+ 4.2.1 TEXT/PLAIN
+ 4.2.2 MULTIPART/ALTERNATIVE
+ 4.2.2.1 TEXT/PLAIN
+ 4.2.2.2 TEXT/RICHTEXT
+
+
+ It is possible to fetch a substring of the designated text.
+ This is done by appending an open angle bracket ("<"), the
+ octet position of the first desired octet, a period, the
+ maximum number of octets desired, and a close angle bracket
+ (">") to the part specifier. If the starting octet is beyond
+ the end of the text, an empty string is returned.
+
+
+
+
+Crispin Standards Track [Page 56]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Any partial fetch that attempts to read beyond the end of the
+ text is truncated as appropriate. A partial fetch that starts
+ at octet 0 is returned as a partial fetch, even if this
+ truncation happened.
+
+ Note: This means that BODY[]<0.2048> of a 1500-octet message
+ will return BODY[]<0> with a literal of size 1500, not
+ BODY[].
+
+ Note: A substring fetch of a HEADER.FIELDS or
+ HEADER.FIELDS.NOT part specifier is calculated after
+ subsetting the header.
+
+ The \Seen flag is implicitly set; if this causes the flags to
+ change, they SHOULD be included as part of the FETCH responses.
+
+ BODY.PEEK[<section>]<<partial>>
+ An alternate form of BODY[<section>] that does not implicitly
+ set the \Seen flag.
+
+ BODYSTRUCTURE
+ The [MIME-IMB] body structure of the message. This is computed
+ by the server by parsing the [MIME-IMB] header fields in the
+ [RFC-2822] header and [MIME-IMB] headers.
+
+ ENVELOPE
+ The envelope structure of the message. This is computed by the
+ server by parsing the [RFC-2822] header into the component
+ parts, defaulting various fields as necessary.
+
+ FLAGS
+ The flags that are set for this message.
+
+ INTERNALDATE
+ The internal date of the message.
+
+ RFC822
+ Functionally equivalent to BODY[], differing in the syntax of
+ the resulting untagged FETCH data (RFC822 is returned).
+
+ RFC822.HEADER
+ Functionally equivalent to BODY.PEEK[HEADER], differing in the
+ syntax of the resulting untagged FETCH data (RFC822.HEADER is
+ returned).
+
+ RFC822.SIZE
+ The [RFC-2822] size of the message.
+
+
+
+
+Crispin Standards Track [Page 57]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ RFC822.TEXT
+ Functionally equivalent to BODY[TEXT], differing in the syntax
+ of the resulting untagged FETCH data (RFC822.TEXT is returned).
+
+ UID
+ The unique identifier for the message.
+
+
+ Example: C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
+ S: * 2 FETCH ....
+ S: * 3 FETCH ....
+ S: * 4 FETCH ....
+ S: A654 OK FETCH completed
+
+
+6.4.6. STORE Command
+
+ Arguments: sequence set
+ message data item name
+ value for message data item
+
+ Responses: untagged responses: FETCH
+
+ Result: OK - store completed
+ NO - store error: can't store that data
+ BAD - command unknown or arguments invalid
+
+ The STORE command alters data associated with a message in the
+ mailbox. Normally, STORE will return the updated value of the
+ data with an untagged FETCH response. A suffix of ".SILENT" in
+ the data item name prevents the untagged FETCH, and the server
+ SHOULD assume that the client has determined the updated value
+ itself or does not care about the updated value.
+
+ Note: Regardless of whether or not the ".SILENT" suffix
+ was used, the server SHOULD send an untagged FETCH
+ response if a change to a message's flags from an
+ external source is observed. The intent is that the
+ status of the flags is determinate without a race
+ condition.
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 58]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The currently defined data items that can be stored are:
+
+ FLAGS <flag list>
+ Replace the flags for the message (other than \Recent) with the
+ argument. The new value of the flags is returned as if a FETCH
+ of those flags was done.
+
+ FLAGS.SILENT <flag list>
+ Equivalent to FLAGS, but without returning a new value.
+
+ +FLAGS <flag list>
+ Add the argument to the flags for the message. The new value
+ of the flags is returned as if a FETCH of those flags was done.
+
+ +FLAGS.SILENT <flag list>
+ Equivalent to +FLAGS, but without returning a new value.
+
+ -FLAGS <flag list>
+ Remove the argument from the flags for the message. The new
+ value of the flags is returned as if a FETCH of those flags was
+ done.
+
+ -FLAGS.SILENT <flag list>
+ Equivalent to -FLAGS, but without returning a new value.
+
+
+ Example: C: A003 STORE 2:4 +FLAGS (\Deleted)
+ S: * 2 FETCH (FLAGS (\Deleted \Seen))
+ S: * 3 FETCH (FLAGS (\Deleted))
+ S: * 4 FETCH (FLAGS (\Deleted \Flagged \Seen))
+ S: A003 OK STORE completed
+
+
+6.4.7. COPY Command
+
+ Arguments: sequence set
+ mailbox name
+
+ Responses: no specific responses for this command
+
+ Result: OK - copy completed
+ NO - copy error: can't copy those messages or to that
+ name
+ BAD - command unknown or arguments invalid
+
+
+
+
+
+
+
+Crispin Standards Track [Page 59]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The COPY command copies the specified message(s) to the end of the
+ specified destination mailbox. The flags and internal date of the
+ message(s) SHOULD be preserved, and the Recent flag SHOULD be set,
+ in the copy.
+
+ If the destination mailbox does not exist, a server SHOULD return
+ an error. It SHOULD NOT automatically create the mailbox. Unless
+ it is certain that the destination mailbox can not be created, the
+ server MUST send the response code "[TRYCREATE]" as the prefix of
+ the text of the tagged NO response. This gives a hint to the
+ client that it can attempt a CREATE command and retry the COPY if
+ the CREATE is successful.
+
+ If the COPY command is unsuccessful for any reason, server
+ implementations MUST restore the destination mailbox to its state
+ before the COPY attempt.
+
+ Example: C: A003 COPY 2:4 MEETING
+ S: A003 OK COPY completed
+
+
+6.4.8. UID Command
+
+ Arguments: command name
+ command arguments
+
+ Responses: untagged responses: FETCH, SEARCH
+
+ Result: OK - UID command completed
+ NO - UID command error
+ BAD - command unknown or arguments invalid
+
+ The UID command has two forms. In the first form, it takes as its
+ arguments a COPY, FETCH, or STORE command with arguments
+ appropriate for the associated command. However, the numbers in
+ the sequence set argument are unique identifiers instead of
+ message sequence numbers. Sequence set ranges are permitted, but
+ there is no guarantee that unique identifiers will be contiguous.
+
+ A non-existent unique identifier is ignored without any error
+ message generated. Thus, it is possible for a UID FETCH command
+ to return an OK without any data or a UID COPY or UID STORE to
+ return an OK without performing any operations.
+
+ In the second form, the UID command takes a SEARCH command with
+ SEARCH command arguments. The interpretation of the arguments is
+ the same as with SEARCH; however, the numbers returned in a SEARCH
+ response for a UID SEARCH command are unique identifiers instead
+
+
+
+Crispin Standards Track [Page 60]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ of message sequence numbers. For example, the command UID SEARCH
+ 1:100 UID 443:557 returns the unique identifiers corresponding to
+ the intersection of two sequence sets, the message sequence number
+ range 1:100 and the UID range 443:557.
+
+ Note: in the above example, the UID range 443:557
+ appears. The same comment about a non-existent unique
+ identifier being ignored without any error message also
+ applies here. Hence, even if neither UID 443 or 557
+ exist, this range is valid and would include an existing
+ UID 495.
+
+ Also note that a UID range of 559:* always includes the
+ UID of the last message in the mailbox, even if 559 is
+ higher than any assigned UID value. This is because the
+ contents of a range are independent of the order of the
+ range endpoints. Thus, any UID range with * as one of
+ the endpoints indicates at least one message (the
+ message with the highest numbered UID), unless the
+ mailbox is empty.
+
+ The number after the "*" in an untagged FETCH response is always a
+ message sequence number, not a unique identifier, even for a UID
+ command response. However, server implementations MUST implicitly
+ include the UID message data item as part of any FETCH response
+ caused by a UID command, regardless of whether a UID was specified
+ as a message data item to the FETCH.
+
+
+ Note: The rule about including the UID message data item as part
+ of a FETCH response primarily applies to the UID FETCH and UID
+ STORE commands, including a UID FETCH command that does not
+ include UID as a message data item. Although it is unlikely that
+ the other UID commands will cause an untagged FETCH, this rule
+ applies to these commands as well.
+
+ Example: C: A999 UID FETCH 4827313:4828442 FLAGS
+ S: * 23 FETCH (FLAGS (\Seen) UID 4827313)
+ S: * 24 FETCH (FLAGS (\Seen) UID 4827943)
+ S: * 25 FETCH (FLAGS (\Seen) UID 4828442)
+ S: A999 OK UID FETCH completed
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 61]
+
+RFC 3501 IMAPv4 March 2003
+
+
+6.5. Client Commands - Experimental/Expansion
+
+
+6.5.1. X<atom> Command
+
+ Arguments: implementation defined
+
+ Responses: implementation defined
+
+ Result: OK - command completed
+ NO - failure
+ BAD - command unknown or arguments invalid
+
+ Any command prefixed with an X is an experimental command.
+ Commands which are not part of this specification, a standard or
+ standards-track revision of this specification, or an
+ IESG-approved experimental protocol, MUST use the X prefix.
+
+ Any added untagged responses issued by an experimental command
+ MUST also be prefixed with an X. Server implementations MUST NOT
+ send any such untagged responses, unless the client requested it
+ by issuing the associated experimental command.
+
+ Example: C: a441 CAPABILITY
+ S: * CAPABILITY IMAP4rev1 XPIG-LATIN
+ S: a441 OK CAPABILITY completed
+ C: A442 XPIG-LATIN
+ S: * XPIG-LATIN ow-nay eaking-spay ig-pay atin-lay
+ S: A442 OK XPIG-LATIN ompleted-cay
+
+7. Server Responses
+
+ Server responses are in three forms: status responses, server data,
+ and command continuation request. The information contained in a
+ server response, identified by "Contents:" in the response
+ descriptions below, is described by function, not by syntax. The
+ precise syntax of server responses is described in the Formal Syntax
+ section.
+
+ The client MUST be prepared to accept any response at all times.
+
+ Status responses can be tagged or untagged. Tagged status responses
+ indicate the completion result (OK, NO, or BAD status) of a client
+ command, and have a tag matching the command.
+
+ Some status responses, and all server data, are untagged. An
+ untagged response is indicated by the token "*" instead of a tag.
+ Untagged status responses indicate server greeting, or server status
+
+
+
+Crispin Standards Track [Page 62]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ that does not indicate the completion of a command (for example, an
+ impending system shutdown alert). For historical reasons, untagged
+ server data responses are also called "unsolicited data", although
+ strictly speaking, only unilateral server data is truly
+ "unsolicited".
+
+ Certain server data MUST be recorded by the client when it is
+ received; this is noted in the description of that data. Such data
+ conveys critical information which affects the interpretation of all
+ subsequent commands and responses (e.g., updates reflecting the
+ creation or destruction of messages).
+
+ Other server data SHOULD be recorded for later reference; if the
+ client does not need to record the data, or if recording the data has
+ no obvious purpose (e.g., a SEARCH response when no SEARCH command is
+ in progress), the data SHOULD be ignored.
+
+ An example of unilateral untagged server data occurs when the IMAP
+ connection is in the selected state. In the selected state, the
+ server checks the mailbox for new messages as part of command
+ execution. Normally, this is part of the execution of every command;
+ hence, a NOOP command suffices to check for new messages. If new
+ messages are found, the server sends untagged EXISTS and RECENT
+ responses reflecting the new size of the mailbox. Server
+ implementations that offer multiple simultaneous access to the same
+ mailbox SHOULD also send appropriate unilateral untagged FETCH and
+ EXPUNGE responses if another agent changes the state of any message
+ flags or expunges any messages.
+
+ Command continuation request responses use the token "+" instead of a
+ tag. These responses are sent by the server to indicate acceptance
+ of an incomplete client command and readiness for the remainder of
+ the command.
+
+7.1. Server Responses - Status Responses
+
+ Status responses are OK, NO, BAD, PREAUTH and BYE. OK, NO, and BAD
+ can be tagged or untagged. PREAUTH and BYE are always untagged.
+
+ Status responses MAY include an OPTIONAL "response code". A response
+ code consists of data inside square brackets in the form of an atom,
+ possibly followed by a space and arguments. The response code
+ contains additional information or status codes for client software
+ beyond the OK/NO/BAD condition, and are defined when there is a
+ specific action that a client can take based upon the additional
+ information.
+
+
+
+
+
+Crispin Standards Track [Page 63]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The currently defined response codes are:
+
+ ALERT
+
+ The human-readable text contains a special alert that MUST be
+ presented to the user in a fashion that calls the user's
+ attention to the message.
+
+ BADCHARSET
+
+ Optionally followed by a parenthesized list of charsets. A
+ SEARCH failed because the given charset is not supported by
+ this implementation. If the optional list of charsets is
+ given, this lists the charsets that are supported by this
+ implementation.
+
+ CAPABILITY
+
+ Followed by a list of capabilities. This can appear in the
+ initial OK or PREAUTH response to transmit an initial
+ capabilities list. This makes it unnecessary for a client to
+ send a separate CAPABILITY command if it recognizes this
+ response.
+
+ PARSE
+
+ The human-readable text represents an error in parsing the
+ [RFC-2822] header or [MIME-IMB] headers of a message in the
+ mailbox.
+
+ PERMANENTFLAGS
+
+ Followed by a parenthesized list of flags, indicates which of
+ the known flags the client can change permanently. Any flags
+ that are in the FLAGS untagged response, but not the
+ PERMANENTFLAGS list, can not be set permanently. If the client
+ attempts to STORE a flag that is not in the PERMANENTFLAGS
+ list, the server will either ignore the change or store the
+ state change for the remainder of the current session only.
+ The PERMANENTFLAGS list can also include the special flag \*,
+ which indicates that it is possible to create new keywords by
+ attempting to store those flags in the mailbox.
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 64]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ READ-ONLY
+
+ The mailbox is selected read-only, or its access while selected
+ has changed from read-write to read-only.
+
+ READ-WRITE
+
+ The mailbox is selected read-write, or its access while
+ selected has changed from read-only to read-write.
+
+ TRYCREATE
+
+ An APPEND or COPY attempt is failing because the target mailbox
+ does not exist (as opposed to some other reason). This is a
+ hint to the client that the operation can succeed if the
+ mailbox is first created by the CREATE command.
+
+ UIDNEXT
+
+ Followed by a decimal number, indicates the next unique
+ identifier value. Refer to section 2.3.1.1 for more
+ information.
+
+ UIDVALIDITY
+
+ Followed by a decimal number, indicates the unique identifier
+ validity value. Refer to section 2.3.1.1 for more information.
+
+ UNSEEN
+
+ Followed by a decimal number, indicates the number of the first
+ message without the \Seen flag set.
+
+ Additional response codes defined by particular client or server
+ implementations SHOULD be prefixed with an "X" until they are
+ added to a revision of this protocol. Client implementations
+ SHOULD ignore response codes that they do not recognize.
+
+7.1.1. OK Response
+
+ Contents: OPTIONAL response code
+ human-readable text
+
+ The OK response indicates an information message from the server.
+ When tagged, it indicates successful completion of the associated
+ command. The human-readable text MAY be presented to the user as
+ an information message. The untagged form indicates an
+
+
+
+
+Crispin Standards Track [Page 65]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ information-only message; the nature of the information MAY be
+ indicated by a response code.
+
+ The untagged form is also used as one of three possible greetings
+ at connection startup. It indicates that the connection is not
+ yet authenticated and that a LOGIN command is needed.
+
+ Example: S: * OK IMAP4rev1 server ready
+ C: A001 LOGIN fred blurdybloop
+ S: * OK [ALERT] System shutdown in 10 minutes
+ S: A001 OK LOGIN Completed
+
+
+7.1.2. NO Response
+
+ Contents: OPTIONAL response code
+ human-readable text
+
+ The NO response indicates an operational error message from the
+ server. When tagged, it indicates unsuccessful completion of the
+ associated command. The untagged form indicates a warning; the
+ command can still complete successfully. The human-readable text
+ describes the condition.
+
+ Example: C: A222 COPY 1:2 owatagusiam
+ S: * NO Disk is 98% full, please delete unnecessary data
+ S: A222 OK COPY completed
+ C: A223 COPY 3:200 blurdybloop
+ S: * NO Disk is 98% full, please delete unnecessary data
+ S: * NO Disk is 99% full, please delete unnecessary data
+ S: A223 NO COPY failed: disk is full
+
+
+7.1.3. BAD Response
+
+ Contents: OPTIONAL response code
+ human-readable text
+
+ The BAD response indicates an error message from the server. When
+ tagged, it reports a protocol-level error in the client's command;
+ the tag indicates the command that caused the error. The untagged
+ form indicates a protocol-level error for which the associated
+ command can not be determined; it can also indicate an internal
+ server failure. The human-readable text describes the condition.
+
+
+
+
+
+
+
+Crispin Standards Track [Page 66]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Example: C: ...very long command line...
+ S: * BAD Command line too long
+ C: ...empty line...
+ S: * BAD Empty command line
+ C: A443 EXPUNGE
+ S: * BAD Disk crash, attempting salvage to a new disk!
+ S: * OK Salvage successful, no data lost
+ S: A443 OK Expunge completed
+
+
+7.1.4. PREAUTH Response
+
+ Contents: OPTIONAL response code
+ human-readable text
+
+ The PREAUTH response is always untagged, and is one of three
+ possible greetings at connection startup. It indicates that the
+ connection has already been authenticated by external means; thus
+ no LOGIN command is needed.
+
+ Example: S: * PREAUTH IMAP4rev1 server logged in as Smith
+
+
+7.1.5. BYE Response
+
+ Contents: OPTIONAL response code
+ human-readable text
+
+ The BYE response is always untagged, and indicates that the server
+ is about to close the connection. The human-readable text MAY be
+ displayed to the user in a status report by the client. The BYE
+ response is sent under one of four conditions:
+
+ 1) as part of a normal logout sequence. The server will close
+ the connection after sending the tagged OK response to the
+ LOGOUT command.
+
+ 2) as a panic shutdown announcement. The server closes the
+ connection immediately.
+
+ 3) as an announcement of an inactivity autologout. The server
+ closes the connection immediately.
+
+ 4) as one of three possible greetings at connection startup,
+ indicating that the server is not willing to accept a
+ connection from this client. The server closes the
+ connection immediately.
+
+
+
+
+Crispin Standards Track [Page 67]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The difference between a BYE that occurs as part of a normal
+ LOGOUT sequence (the first case) and a BYE that occurs because of
+ a failure (the other three cases) is that the connection closes
+ immediately in the failure case. In all cases the client SHOULD
+ continue to read response data from the server until the
+ connection is closed; this will ensure that any pending untagged
+ or completion responses are read and processed.
+
+ Example: S: * BYE Autologout; idle for too long
+
+7.2. Server Responses - Server and Mailbox Status
+
+ These responses are always untagged. This is how server and mailbox
+ status data are transmitted from the server to the client. Many of
+ these responses typically result from a command with the same name.
+
+7.2.1. CAPABILITY Response
+
+ Contents: capability listing
+
+ The CAPABILITY response occurs as a result of a CAPABILITY
+ command. The capability listing contains a space-separated
+ listing of capability names that the server supports. The
+ capability listing MUST include the atom "IMAP4rev1".
+
+ In addition, client and server implementations MUST implement the
+ STARTTLS, LOGINDISABLED, and AUTH=PLAIN (described in [IMAP-TLS])
+ capabilities. See the Security Considerations section for
+ important information.
+
+ A capability name which begins with "AUTH=" indicates that the
+ server supports that particular authentication mechanism.
+
+ The LOGINDISABLED capability indicates that the LOGIN command is
+ disabled, and that the server will respond with a tagged NO
+ response to any attempt to use the LOGIN command even if the user
+ name and password are valid. An IMAP client MUST NOT issue the
+ LOGIN command if the server advertises the LOGINDISABLED
+ capability.
+
+ Other capability names indicate that the server supports an
+ extension, revision, or amendment to the IMAP4rev1 protocol.
+ Server responses MUST conform to this document until the client
+ issues a command that uses the associated capability.
+
+ Capability names MUST either begin with "X" or be standard or
+ standards-track IMAP4rev1 extensions, revisions, or amendments
+ registered with IANA. A server MUST NOT offer unregistered or
+
+
+
+Crispin Standards Track [Page 68]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ non-standard capability names, unless such names are prefixed with
+ an "X".
+
+ Client implementations SHOULD NOT require any capability name
+ other than "IMAP4rev1", and MUST ignore any unknown capability
+ names.
+
+ A server MAY send capabilities automatically, by using the
+ CAPABILITY response code in the initial PREAUTH or OK responses,
+ and by sending an updated CAPABILITY response code in the tagged
+ OK response as part of a successful authentication. It is
+ unnecessary for a client to send a separate CAPABILITY command if
+ it recognizes these automatic capabilities.
+
+ Example: S: * CAPABILITY IMAP4rev1 STARTTLS AUTH=GSSAPI XPIG-LATIN
+
+
+7.2.2. LIST Response
+
+ Contents: name attributes
+ hierarchy delimiter
+ name
+
+ The LIST response occurs as a result of a LIST command. It
+ returns a single name that matches the LIST specification. There
+ can be multiple LIST responses for a single LIST command.
+
+ Four name attributes are defined:
+
+ \Noinferiors
+ It is not possible for any child levels of hierarchy to exist
+ under this name; no child levels exist now and none can be
+ created in the future.
+
+ \Noselect
+ It is not possible to use this name as a selectable mailbox.
+
+ \Marked
+ The mailbox has been marked "interesting" by the server; the
+ mailbox probably contains messages that have been added since
+ the last time the mailbox was selected.
+
+ \Unmarked
+ The mailbox does not contain any additional messages since the
+ last time the mailbox was selected.
+
+
+
+
+
+
+Crispin Standards Track [Page 69]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ If it is not feasible for the server to determine whether or not
+ the mailbox is "interesting", or if the name is a \Noselect name,
+ the server SHOULD NOT send either \Marked or \Unmarked.
+
+ The hierarchy delimiter is a character used to delimit levels of
+ hierarchy in a mailbox name. A client can use it to create child
+ mailboxes, and to search higher or lower levels of naming
+ hierarchy. All children of a top-level hierarchy node MUST use
+ the same separator character. A NIL hierarchy delimiter means
+ that no hierarchy exists; the name is a "flat" name.
+
+ The name represents an unambiguous left-to-right hierarchy, and
+ MUST be valid for use as a reference in LIST and LSUB commands.
+ Unless \Noselect is indicated, the name MUST also be valid as an
+ argument for commands, such as SELECT, that accept mailbox names.
+
+ Example: S: * LIST (\Noselect) "/" ~/Mail/foo
+
+
+7.2.3. LSUB Response
+
+ Contents: name attributes
+ hierarchy delimiter
+ name
+
+ The LSUB response occurs as a result of an LSUB command. It
+ returns a single name that matches the LSUB specification. There
+ can be multiple LSUB responses for a single LSUB command. The
+ data is identical in format to the LIST response.
+
+ Example: S: * LSUB () "." #news.comp.mail.misc
+
+
+7.2.4 STATUS Response
+
+ Contents: name
+ status parenthesized list
+
+ The STATUS response occurs as a result of an STATUS command. It
+ returns the mailbox name that matches the STATUS specification and
+ the requested mailbox status information.
+
+ Example: S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 70]
+
+RFC 3501 IMAPv4 March 2003
+
+
+7.2.5. SEARCH Response
+
+ Contents: zero or more numbers
+
+ The SEARCH response occurs as a result of a SEARCH or UID SEARCH
+ command. The number(s) refer to those messages that match the
+ search criteria. For SEARCH, these are message sequence numbers;
+ for UID SEARCH, these are unique identifiers. Each number is
+ delimited by a space.
+
+ Example: S: * SEARCH 2 3 6
+
+
+7.2.6. FLAGS Response
+
+ Contents: flag parenthesized list
+
+ The FLAGS response occurs as a result of a SELECT or EXAMINE
+ command. The flag parenthesized list identifies the flags (at a
+ minimum, the system-defined flags) that are applicable for this
+ mailbox. Flags other than the system flags can also exist,
+ depending on server implementation.
+
+ The update from the FLAGS response MUST be recorded by the client.
+
+ Example: S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+
+
+7.3. Server Responses - Mailbox Size
+
+ These responses are always untagged. This is how changes in the size
+ of the mailbox are transmitted from the server to the client.
+ Immediately following the "*" token is a number that represents a
+ message count.
+
+7.3.1. EXISTS Response
+
+ Contents: none
+
+ The EXISTS response reports the number of messages in the mailbox.
+ This response occurs as a result of a SELECT or EXAMINE command,
+ and if the size of the mailbox changes (e.g., new messages).
+
+ The update from the EXISTS response MUST be recorded by the
+ client.
+
+ Example: S: * 23 EXISTS
+
+
+
+
+Crispin Standards Track [Page 71]
+
+RFC 3501 IMAPv4 March 2003
+
+
+7.3.2. RECENT Response
+
+ Contents: none
+
+ The RECENT response reports the number of messages with the
+ \Recent flag set. This response occurs as a result of a SELECT or
+ EXAMINE command, and if the size of the mailbox changes (e.g., new
+ messages).
+
+ Note: It is not guaranteed that the message sequence
+ numbers of recent messages will be a contiguous range of
+ the highest n messages in the mailbox (where n is the
+ value reported by the RECENT response). Examples of
+ situations in which this is not the case are: multiple
+ clients having the same mailbox open (the first session
+ to be notified will see it as recent, others will
+ probably see it as non-recent), and when the mailbox is
+ re-ordered by a non-IMAP agent.
+
+ The only reliable way to identify recent messages is to
+ look at message flags to see which have the \Recent flag
+ set, or to do a SEARCH RECENT.
+
+ The update from the RECENT response MUST be recorded by the
+ client.
+
+ Example: S: * 5 RECENT
+
+
+7.4. Server Responses - Message Status
+
+ These responses are always untagged. This is how message data are
+ transmitted from the server to the client, often as a result of a
+ command with the same name. Immediately following the "*" token is a
+ number that represents a message sequence number.
+
+7.4.1. EXPUNGE Response
+
+ Contents: none
+
+ The EXPUNGE response reports that the specified message sequence
+ number has been permanently removed from the mailbox. The message
+ sequence number for each successive message in the mailbox is
+ immediately decremented by 1, and this decrement is reflected in
+ message sequence numbers in subsequent responses (including other
+ untagged EXPUNGE responses).
+
+
+
+
+
+Crispin Standards Track [Page 72]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ The EXPUNGE response also decrements the number of messages in the
+ mailbox; it is not necessary to send an EXISTS response with the
+ new value.
+
+ As a result of the immediate decrement rule, message sequence
+ numbers that appear in a set of successive EXPUNGE responses
+ depend upon whether the messages are removed starting from lower
+ numbers to higher numbers, or from higher numbers to lower
+ numbers. For example, if the last 5 messages in a 9-message
+ mailbox are expunged, a "lower to higher" server will send five
+ untagged EXPUNGE responses for message sequence number 5, whereas
+ a "higher to lower server" will send successive untagged EXPUNGE
+ responses for message sequence numbers 9, 8, 7, 6, and 5.
+
+ An EXPUNGE response MUST NOT be sent when no command is in
+ progress, nor while responding to a FETCH, STORE, or SEARCH
+ command. This rule is necessary to prevent a loss of
+ synchronization of message sequence numbers between client and
+ server. A command is not "in progress" until the complete command
+ has been received; in particular, a command is not "in progress"
+ during the negotiation of command continuation.
+
+ Note: UID FETCH, UID STORE, and UID SEARCH are different
+ commands from FETCH, STORE, and SEARCH. An EXPUNGE
+ response MAY be sent during a UID command.
+
+ The update from the EXPUNGE response MUST be recorded by the
+ client.
+
+ Example: S: * 44 EXPUNGE
+
+
+7.4.2. FETCH Response
+
+ Contents: message data
+
+ The FETCH response returns data about a message to the client.
+ The data are pairs of data item names and their values in
+ parentheses. This response occurs as the result of a FETCH or
+ STORE command, as well as by unilateral server decision (e.g.,
+ flag updates).
+
+ The current data items are:
+
+ BODY
+ A form of BODYSTRUCTURE without extension data.
+
+
+
+
+
+Crispin Standards Track [Page 73]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ BODY[<section>]<<origin octet>>
+ A string expressing the body contents of the specified section.
+ The string SHOULD be interpreted by the client according to the
+ content transfer encoding, body type, and subtype.
+
+ If the origin octet is specified, this string is a substring of
+ the entire body contents, starting at that origin octet. This
+ means that BODY[]<0> MAY be truncated, but BODY[] is NEVER
+ truncated.
+
+ Note: The origin octet facility MUST NOT be used by a server
+ in a FETCH response unless the client specifically requested
+ it by means of a FETCH of a BODY[<section>]<<partial>> data
+ item.
+
+ 8-bit textual data is permitted if a [CHARSET] identifier is
+ part of the body parameter parenthesized list for this section.
+ Note that headers (part specifiers HEADER or MIME, or the
+ header portion of a MESSAGE/RFC822 part), MUST be 7-bit; 8-bit
+ characters are not permitted in headers. Note also that the
+ [RFC-2822] delimiting blank line between the header and the
+ body is not affected by header line subsetting; the blank line
+ is always included as part of header data, except in the case
+ of a message which has no body and no blank line.
+
+ Non-textual data such as binary data MUST be transfer encoded
+ into a textual form, such as BASE64, prior to being sent to the
+ client. To derive the original binary data, the client MUST
+ decode the transfer encoded string.
+
+ BODYSTRUCTURE
+ A parenthesized list that describes the [MIME-IMB] body
+ structure of a message. This is computed by the server by
+ parsing the [MIME-IMB] header fields, defaulting various fields
+ as necessary.
+
+ For example, a simple text message of 48 lines and 2279 octets
+ can have a body structure of: ("TEXT" "PLAIN" ("CHARSET"
+ "US-ASCII") NIL NIL "7BIT" 2279 48)
+
+ Multiple parts are indicated by parenthesis nesting. Instead
+ of a body type as the first element of the parenthesized list,
+ there is a sequence of one or more nested body structures. The
+ second element of the parenthesized list is the multipart
+ subtype (mixed, digest, parallel, alternative, etc.).
+
+
+
+
+
+
+Crispin Standards Track [Page 74]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ For example, a two part message consisting of a text and a
+ BASE64-encoded text attachment can have a body structure of:
+ (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
+ 23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
+ "<960723163407.20117h@cac.washington.edu>" "Compiler diff"
+ "BASE64" 4554 73) "MIXED")
+
+ Extension data follows the multipart subtype. Extension data
+ is never returned with the BODY fetch, but can be returned with
+ a BODYSTRUCTURE fetch. Extension data, if present, MUST be in
+ the defined order. The extension data of a multipart body part
+ are in the following order:
+
+ body parameter parenthesized list
+ A parenthesized list of attribute/value pairs [e.g., ("foo"
+ "bar" "baz" "rag") where "bar" is the value of "foo", and
+ "rag" is the value of "baz"] as defined in [MIME-IMB].
+
+ body disposition
+ A parenthesized list, consisting of a disposition type
+ string, followed by a parenthesized list of disposition
+ attribute/value pairs as defined in [DISPOSITION].
+
+ body language
+ A string or parenthesized list giving the body language
+ value as defined in [LANGUAGE-TAGS].
+
+ body location
+ A string list giving the body content URI as defined in
+ [LOCATION].
+
+ Any following extension data are not yet defined in this
+ version of the protocol. Such extension data can consist of
+ zero or more NILs, strings, numbers, or potentially nested
+ parenthesized lists of such data. Client implementations that
+ do a BODYSTRUCTURE fetch MUST be prepared to accept such
+ extension data. Server implementations MUST NOT send such
+ extension data until it has been defined by a revision of this
+ protocol.
+
+ The basic fields of a non-multipart body part are in the
+ following order:
+
+ body type
+ A string giving the content media type name as defined in
+ [MIME-IMB].
+
+
+
+
+
+Crispin Standards Track [Page 75]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ body subtype
+ A string giving the content subtype name as defined in
+ [MIME-IMB].
+
+ body parameter parenthesized list
+ A parenthesized list of attribute/value pairs [e.g., ("foo"
+ "bar" "baz" "rag") where "bar" is the value of "foo" and
+ "rag" is the value of "baz"] as defined in [MIME-IMB].
+
+ body id
+ A string giving the content id as defined in [MIME-IMB].
+
+ body description
+ A string giving the content description as defined in
+ [MIME-IMB].
+
+ body encoding
+ A string giving the content transfer encoding as defined in
+ [MIME-IMB].
+
+ body size
+ A number giving the size of the body in octets. Note that
+ this size is the size in its transfer encoding and not the
+ resulting size after any decoding.
+
+ A body type of type MESSAGE and subtype RFC822 contains,
+ immediately after the basic fields, the envelope structure,
+ body structure, and size in text lines of the encapsulated
+ message.
+
+ A body type of type TEXT contains, immediately after the basic
+ fields, the size of the body in text lines. Note that this
+ size is the size in its content transfer encoding and not the
+ resulting size after any decoding.
+
+ Extension data follows the basic fields and the type-specific
+ fields listed above. Extension data is never returned with the
+ BODY fetch, but can be returned with a BODYSTRUCTURE fetch.
+ Extension data, if present, MUST be in the defined order.
+
+ The extension data of a non-multipart body part are in the
+ following order:
+
+ body MD5
+ A string giving the body MD5 value as defined in [MD5].
+
+
+
+
+
+
+Crispin Standards Track [Page 76]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ body disposition
+ A parenthesized list with the same content and function as
+ the body disposition for a multipart body part.
+
+ body language
+ A string or parenthesized list giving the body language
+ value as defined in [LANGUAGE-TAGS].
+
+ body location
+ A string list giving the body content URI as defined in
+ [LOCATION].
+
+ Any following extension data are not yet defined in this
+ version of the protocol, and would be as described above under
+ multipart extension data.
+
+ ENVELOPE
+ A parenthesized list that describes the envelope structure of a
+ message. This is computed by the server by parsing the
+ [RFC-2822] header into the component parts, defaulting various
+ fields as necessary.
+
+ The fields of the envelope structure are in the following
+ order: date, subject, from, sender, reply-to, to, cc, bcc,
+ in-reply-to, and message-id. The date, subject, in-reply-to,
+ and message-id fields are strings. The from, sender, reply-to,
+ to, cc, and bcc fields are parenthesized lists of address
+ structures.
+
+ An address structure is a parenthesized list that describes an
+ electronic mail address. The fields of an address structure
+ are in the following order: personal name, [SMTP]
+ at-domain-list (source route), mailbox name, and host name.
+
+ [RFC-2822] group syntax is indicated by a special form of
+ address structure in which the host name field is NIL. If the
+ mailbox name field is also NIL, this is an end of group marker
+ (semi-colon in RFC 822 syntax). If the mailbox name field is
+ non-NIL, this is a start of group marker, and the mailbox name
+ field holds the group name phrase.
+
+ If the Date, Subject, In-Reply-To, and Message-ID header lines
+ are absent in the [RFC-2822] header, the corresponding member
+ of the envelope is NIL; if these header lines are present but
+ empty the corresponding member of the envelope is the empty
+ string.
+
+
+
+
+
+Crispin Standards Track [Page 77]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Note: some servers may return a NIL envelope member in the
+ "present but empty" case. Clients SHOULD treat NIL and
+ empty string as identical.
+
+ Note: [RFC-2822] requires that all messages have a valid
+ Date header. Therefore, the date member in the envelope can
+ not be NIL or the empty string.
+
+ Note: [RFC-2822] requires that the In-Reply-To and
+ Message-ID headers, if present, have non-empty content.
+ Therefore, the in-reply-to and message-id members in the
+ envelope can not be the empty string.
+
+ If the From, To, cc, and bcc header lines are absent in the
+ [RFC-2822] header, or are present but empty, the corresponding
+ member of the envelope is NIL.
+
+ If the Sender or Reply-To lines are absent in the [RFC-2822]
+ header, or are present but empty, the server sets the
+ corresponding member of the envelope to be the same value as
+ the from member (the client is not expected to know to do
+ this).
+
+ Note: [RFC-2822] requires that all messages have a valid
+ From header. Therefore, the from, sender, and reply-to
+ members in the envelope can not be NIL.
+
+ FLAGS
+ A parenthesized list of flags that are set for this message.
+
+ INTERNALDATE
+ A string representing the internal date of the message.
+
+ RFC822
+ Equivalent to BODY[].
+
+ RFC822.HEADER
+ Equivalent to BODY[HEADER]. Note that this did not result in
+ \Seen being set, because RFC822.HEADER response data occurs as
+ a result of a FETCH of RFC822.HEADER. BODY[HEADER] response
+ data occurs as a result of a FETCH of BODY[HEADER] (which sets
+ \Seen) or BODY.PEEK[HEADER] (which does not set \Seen).
+
+ RFC822.SIZE
+ A number expressing the [RFC-2822] size of the message.
+
+
+
+
+
+
+Crispin Standards Track [Page 78]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ RFC822.TEXT
+ Equivalent to BODY[TEXT].
+
+ UID
+ A number expressing the unique identifier of the message.
+
+
+ Example: S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827)
+
+
+7.5. Server Responses - Command Continuation Request
+
+ The command continuation request response is indicated by a "+" token
+ instead of a tag. This form of response indicates that the server is
+ ready to accept the continuation of a command from the client. The
+ remainder of this response is a line of text.
+
+ This response is used in the AUTHENTICATE command to transmit server
+ data to the client, and request additional client data. This
+ response is also used if an argument to any command is a literal.
+
+ The client is not permitted to send the octets of the literal unless
+ the server indicates that it is expected. This permits the server to
+ process commands and reject errors on a line-by-line basis. The
+ remainder of the command, including the CRLF that terminates a
+ command, follows the octets of the literal. If there are any
+ additional command arguments, the literal octets are followed by a
+ space and those arguments.
+
+ Example: C: A001 LOGIN {11}
+ S: + Ready for additional command text
+ C: FRED FOOBAR {7}
+ S: + Ready for additional command text
+ C: fat man
+ S: A001 OK LOGIN completed
+ C: A044 BLURDYBLOOP {102856}
+ S: A044 BAD No such command as "BLURDYBLOOP"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 79]
+
+RFC 3501 IMAPv4 March 2003
+
+
+8. Sample IMAP4rev1 connection
+
+ The following is a transcript of an IMAP4rev1 connection. A long
+ line in this sample is broken for editorial clarity.
+
+S: * OK IMAP4rev1 Service Ready
+C: a001 login mrc secret
+S: a001 OK LOGIN completed
+C: a002 select inbox
+S: * 18 EXISTS
+S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+S: * 2 RECENT
+S: * OK [UNSEEN 17] Message 17 is the first unseen message
+S: * OK [UIDVALIDITY 3857529045] UIDs valid
+S: a002 OK [READ-WRITE] SELECT completed
+C: a003 fetch 12 full
+S: * 12 FETCH (FLAGS (\Seen) INTERNALDATE "17-Jul-1996 02:44:25 -0700"
+ RFC822.SIZE 4286 ENVELOPE ("Wed, 17 Jul 1996 02:23:25 -0700 (PDT)"
+ "IMAP4rev1 WG mtg summary and minutes"
+ (("Terry Gray" NIL "gray" "cac.washington.edu"))
+ (("Terry Gray" NIL "gray" "cac.washington.edu"))
+ (("Terry Gray" NIL "gray" "cac.washington.edu"))
+ ((NIL NIL "imap" "cac.washington.edu"))
+ ((NIL NIL "minutes" "CNRI.Reston.VA.US")
+ ("John Klensin" NIL "KLENSIN" "MIT.EDU")) NIL NIL
+ "<B27397-0100000@cac.washington.edu>")
+ BODY ("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 3028
+ 92))
+S: a003 OK FETCH completed
+C: a004 fetch 12 body[header]
+S: * 12 FETCH (BODY[HEADER] {342}
+S: Date: Wed, 17 Jul 1996 02:23:25 -0700 (PDT)
+S: From: Terry Gray <gray@cac.washington.edu>
+S: Subject: IMAP4rev1 WG mtg summary and minutes
+S: To: imap@cac.washington.edu
+S: cc: minutes@CNRI.Reston.VA.US, John Klensin <KLENSIN@MIT.EDU>
+S: Message-Id: <B27397-0100000@cac.washington.edu>
+S: MIME-Version: 1.0
+S: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+S:
+S: )
+S: a004 OK FETCH completed
+C: a005 store 12 +flags \deleted
+S: * 12 FETCH (FLAGS (\Seen \Deleted))
+S: a005 OK +FLAGS completed
+C: a006 logout
+S: * BYE IMAP4rev1 server terminating connection
+S: a006 OK LOGOUT completed
+
+
+
+Crispin Standards Track [Page 80]
+
+RFC 3501 IMAPv4 March 2003
+
+
+9. Formal Syntax
+
+ The following syntax specification uses the Augmented Backus-Naur
+ Form (ABNF) notation as specified in [ABNF].
+
+ In the case of alternative or optional rules in which a later rule
+ overlaps an earlier rule, the rule which is listed earlier MUST take
+ priority. For example, "\Seen" when parsed as a flag is the \Seen
+ flag name and not a flag-extension, even though "\Seen" can be parsed
+ as a flag-extension. Some, but not all, instances of this rule are
+ noted below.
+
+ Note: [ABNF] rules MUST be followed strictly; in
+ particular:
+
+ (1) Except as noted otherwise, all alphabetic characters
+ are case-insensitive. The use of upper or lower case
+ characters to define token strings is for editorial clarity
+ only. Implementations MUST accept these strings in a
+ case-insensitive fashion.
+
+ (2) In all cases, SP refers to exactly one space. It is
+ NOT permitted to substitute TAB, insert additional spaces,
+ or otherwise treat SP as being equivalent to LWSP.
+
+ (3) The ASCII NUL character, %x00, MUST NOT be used at any
+ time.
+
+address = "(" addr-name SP addr-adl SP addr-mailbox SP
+ addr-host ")"
+
+addr-adl = nstring
+ ; Holds route from [RFC-2822] route-addr if
+ ; non-NIL
+
+addr-host = nstring
+ ; NIL indicates [RFC-2822] group syntax.
+ ; Otherwise, holds [RFC-2822] domain name
+
+addr-mailbox = nstring
+ ; NIL indicates end of [RFC-2822] group; if
+ ; non-NIL and addr-host is NIL, holds
+ ; [RFC-2822] group name.
+ ; Otherwise, holds [RFC-2822] local-part
+ ; after removing [RFC-2822] quoting
+
+
+
+
+
+
+Crispin Standards Track [Page 81]
+
+RFC 3501 IMAPv4 March 2003
+
+
+addr-name = nstring
+ ; If non-NIL, holds phrase from [RFC-2822]
+ ; mailbox after removing [RFC-2822] quoting
+
+append = "APPEND" SP mailbox [SP flag-list] [SP date-time] SP
+ literal
+
+astring = 1*ASTRING-CHAR / string
+
+ASTRING-CHAR = ATOM-CHAR / resp-specials
+
+atom = 1*ATOM-CHAR
+
+ATOM-CHAR = <any CHAR except atom-specials>
+
+atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards /
+ quoted-specials / resp-specials
+
+authenticate = "AUTHENTICATE" SP auth-type *(CRLF base64)
+
+auth-type = atom
+ ; Defined by [SASL]
+
+base64 = *(4base64-char) [base64-terminal]
+
+base64-char = ALPHA / DIGIT / "+" / "/"
+ ; Case-sensitive
+
+base64-terminal = (2base64-char "==") / (3base64-char "=")
+
+body = "(" (body-type-1part / body-type-mpart) ")"
+
+body-extension = nstring / number /
+ "(" body-extension *(SP body-extension) ")"
+ ; Future expansion. Client implementations
+ ; MUST accept body-extension fields. Server
+ ; implementations MUST NOT generate
+ ; body-extension fields except as defined by
+ ; future standard or standards-track
+ ; revisions of this specification.
+
+body-ext-1part = body-fld-md5 [SP body-fld-dsp [SP body-fld-lang
+ [SP body-fld-loc *(SP body-extension)]]]
+ ; MUST NOT be returned on non-extensible
+ ; "BODY" fetch
+
+
+
+
+
+
+Crispin Standards Track [Page 82]
+
+RFC 3501 IMAPv4 March 2003
+
+
+body-ext-mpart = body-fld-param [SP body-fld-dsp [SP body-fld-lang
+ [SP body-fld-loc *(SP body-extension)]]]
+ ; MUST NOT be returned on non-extensible
+ ; "BODY" fetch
+
+body-fields = body-fld-param SP body-fld-id SP body-fld-desc SP
+ body-fld-enc SP body-fld-octets
+
+body-fld-desc = nstring
+
+body-fld-dsp = "(" string SP body-fld-param ")" / nil
+
+body-fld-enc = (DQUOTE ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+ "QUOTED-PRINTABLE") DQUOTE) / string
+
+body-fld-id = nstring
+
+body-fld-lang = nstring / "(" string *(SP string) ")"
+
+body-fld-loc = nstring
+
+body-fld-lines = number
+
+body-fld-md5 = nstring
+
+body-fld-octets = number
+
+body-fld-param = "(" string SP string *(SP string SP string) ")" / nil
+
+body-type-1part = (body-type-basic / body-type-msg / body-type-text)
+ [SP body-ext-1part]
+
+body-type-basic = media-basic SP body-fields
+ ; MESSAGE subtype MUST NOT be "RFC822"
+
+body-type-mpart = 1*body SP media-subtype
+ [SP body-ext-mpart]
+
+body-type-msg = media-message SP body-fields SP envelope
+ SP body SP body-fld-lines
+
+body-type-text = media-text SP body-fields SP body-fld-lines
+
+capability = ("AUTH=" auth-type) / atom
+ ; New capabilities MUST begin with "X" or be
+ ; registered with IANA as standard or
+ ; standards-track
+
+
+
+
+Crispin Standards Track [Page 83]
+
+RFC 3501 IMAPv4 March 2003
+
+
+capability-data = "CAPABILITY" *(SP capability) SP "IMAP4rev1"
+ *(SP capability)
+ ; Servers MUST implement the STARTTLS, AUTH=PLAIN,
+ ; and LOGINDISABLED capabilities
+ ; Servers which offer RFC 1730 compatibility MUST
+ ; list "IMAP4" as the first capability.
+
+CHAR8 = %x01-ff
+ ; any OCTET except NUL, %x00
+
+command = tag SP (command-any / command-auth / command-nonauth /
+ command-select) CRLF
+ ; Modal based on state
+
+command-any = "CAPABILITY" / "LOGOUT" / "NOOP" / x-command
+ ; Valid in all states
+
+command-auth = append / create / delete / examine / list / lsub /
+ rename / select / status / subscribe / unsubscribe
+ ; Valid only in Authenticated or Selected state
+
+command-nonauth = login / authenticate / "STARTTLS"
+ ; Valid only when in Not Authenticated state
+
+command-select = "CHECK" / "CLOSE" / "EXPUNGE" / copy / fetch / store /
+ uid / search
+ ; Valid only when in Selected state
+
+continue-req = "+" SP (resp-text / base64) CRLF
+
+copy = "COPY" SP sequence-set SP mailbox
+
+create = "CREATE" SP mailbox
+ ; Use of INBOX gives a NO error
+
+date = date-text / DQUOTE date-text DQUOTE
+
+date-day = 1*2DIGIT
+ ; Day of month
+
+date-day-fixed = (SP DIGIT) / 2DIGIT
+ ; Fixed-format version of date-day
+
+date-month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+
+date-text = date-day "-" date-month "-" date-year
+
+
+
+
+Crispin Standards Track [Page 84]
+
+RFC 3501 IMAPv4 March 2003
+
+
+date-year = 4DIGIT
+
+date-time = DQUOTE date-day-fixed "-" date-month "-" date-year
+ SP time SP zone DQUOTE
+
+delete = "DELETE" SP mailbox
+ ; Use of INBOX gives a NO error
+
+digit-nz = %x31-39
+ ; 1-9
+
+envelope = "(" env-date SP env-subject SP env-from SP
+ env-sender SP env-reply-to SP env-to SP env-cc SP
+ env-bcc SP env-in-reply-to SP env-message-id ")"
+
+env-bcc = "(" 1*address ")" / nil
+
+env-cc = "(" 1*address ")" / nil
+
+env-date = nstring
+
+env-from = "(" 1*address ")" / nil
+
+env-in-reply-to = nstring
+
+env-message-id = nstring
+
+env-reply-to = "(" 1*address ")" / nil
+
+env-sender = "(" 1*address ")" / nil
+
+env-subject = nstring
+
+env-to = "(" 1*address ")" / nil
+
+examine = "EXAMINE" SP mailbox
+
+fetch = "FETCH" SP sequence-set SP ("ALL" / "FULL" / "FAST" /
+ fetch-att / "(" fetch-att *(SP fetch-att) ")")
+
+fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
+ "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
+ "BODY" ["STRUCTURE"] / "UID" /
+ "BODY" section ["<" number "." nz-number ">"] /
+ "BODY.PEEK" section ["<" number "." nz-number ">"]
+
+
+
+
+
+
+Crispin Standards Track [Page 85]
+
+RFC 3501 IMAPv4 March 2003
+
+
+flag = "\Answered" / "\Flagged" / "\Deleted" /
+ "\Seen" / "\Draft" / flag-keyword / flag-extension
+ ; Does not include "\Recent"
+
+flag-extension = "\" atom
+ ; Future expansion. Client implementations
+ ; MUST accept flag-extension flags. Server
+ ; implementations MUST NOT generate
+ ; flag-extension flags except as defined by
+ ; future standard or standards-track
+ ; revisions of this specification.
+
+flag-fetch = flag / "\Recent"
+
+flag-keyword = atom
+
+flag-list = "(" [flag *(SP flag)] ")"
+
+flag-perm = flag / "\*"
+
+greeting = "*" SP (resp-cond-auth / resp-cond-bye) CRLF
+
+header-fld-name = astring
+
+header-list = "(" header-fld-name *(SP header-fld-name) ")"
+
+list = "LIST" SP mailbox SP list-mailbox
+
+list-mailbox = 1*list-char / string
+
+list-char = ATOM-CHAR / list-wildcards / resp-specials
+
+list-wildcards = "%" / "*"
+
+literal = "{" number "}" CRLF *CHAR8
+ ; Number represents the number of CHAR8s
+
+login = "LOGIN" SP userid SP password
+
+lsub = "LSUB" SP mailbox SP list-mailbox
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 86]
+
+RFC 3501 IMAPv4 March 2003
+
+
+mailbox = "INBOX" / astring
+ ; INBOX is case-insensitive. All case variants of
+ ; INBOX (e.g., "iNbOx") MUST be interpreted as INBOX
+ ; not as an astring. An astring which consists of
+ ; the case-insensitive sequence "I" "N" "B" "O" "X"
+ ; is considered to be INBOX and not an astring.
+ ; Refer to section 5.1 for further
+ ; semantic details of mailbox names.
+
+mailbox-data = "FLAGS" SP flag-list / "LIST" SP mailbox-list /
+ "LSUB" SP mailbox-list / "SEARCH" *(SP nz-number) /
+ "STATUS" SP mailbox SP "(" [status-att-list] ")" /
+ number SP "EXISTS" / number SP "RECENT"
+
+mailbox-list = "(" [mbx-list-flags] ")" SP
+ (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
+
+mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
+ *(SP mbx-list-oflag) /
+ mbx-list-oflag *(SP mbx-list-oflag)
+
+mbx-list-oflag = "\Noinferiors" / flag-extension
+ ; Other flags; multiple possible per LIST response
+
+mbx-list-sflag = "\Noselect" / "\Marked" / "\Unmarked"
+ ; Selectability flags; only one per LIST response
+
+media-basic = ((DQUOTE ("APPLICATION" / "AUDIO" / "IMAGE" /
+ "MESSAGE" / "VIDEO") DQUOTE) / string) SP
+ media-subtype
+ ; Defined in [MIME-IMT]
+
+media-message = DQUOTE "MESSAGE" DQUOTE SP DQUOTE "RFC822" DQUOTE
+ ; Defined in [MIME-IMT]
+
+media-subtype = string
+ ; Defined in [MIME-IMT]
+
+media-text = DQUOTE "TEXT" DQUOTE SP media-subtype
+ ; Defined in [MIME-IMT]
+
+message-data = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
+
+msg-att = "(" (msg-att-dynamic / msg-att-static)
+ *(SP (msg-att-dynamic / msg-att-static)) ")"
+
+msg-att-dynamic = "FLAGS" SP "(" [flag-fetch *(SP flag-fetch)] ")"
+ ; MAY change for a message
+
+
+
+Crispin Standards Track [Page 87]
+
+RFC 3501 IMAPv4 March 2003
+
+
+msg-att-static = "ENVELOPE" SP envelope / "INTERNALDATE" SP date-time /
+ "RFC822" [".HEADER" / ".TEXT"] SP nstring /
+ "RFC822.SIZE" SP number /
+ "BODY" ["STRUCTURE"] SP body /
+ "BODY" section ["<" number ">"] SP nstring /
+ "UID" SP uniqueid
+ ; MUST NOT change for a message
+
+nil = "NIL"
+
+nstring = string / nil
+
+number = 1*DIGIT
+ ; Unsigned 32-bit integer
+ ; (0 <= n < 4,294,967,296)
+
+nz-number = digit-nz *DIGIT
+ ; Non-zero unsigned 32-bit integer
+ ; (0 < n < 4,294,967,296)
+
+password = astring
+
+quoted = DQUOTE *QUOTED-CHAR DQUOTE
+
+QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> /
+ "\" quoted-specials
+
+quoted-specials = DQUOTE / "\"
+
+rename = "RENAME" SP mailbox SP mailbox
+ ; Use of INBOX as a destination gives a NO error
+
+response = *(continue-req / response-data) response-done
+
+response-data = "*" SP (resp-cond-state / resp-cond-bye /
+ mailbox-data / message-data / capability-data) CRLF
+
+response-done = response-tagged / response-fatal
+
+response-fatal = "*" SP resp-cond-bye CRLF
+ ; Server closes connection immediately
+
+response-tagged = tag SP resp-cond-state CRLF
+
+resp-cond-auth = ("OK" / "PREAUTH") SP resp-text
+ ; Authentication condition
+
+
+
+
+
+Crispin Standards Track [Page 88]
+
+RFC 3501 IMAPv4 March 2003
+
+
+resp-cond-bye = "BYE" SP resp-text
+
+resp-cond-state = ("OK" / "NO" / "BAD") SP resp-text
+ ; Status condition
+
+resp-specials = "]"
+
+resp-text = ["[" resp-text-code "]" SP] text
+
+resp-text-code = "ALERT" /
+ "BADCHARSET" [SP "(" astring *(SP astring) ")" ] /
+ capability-data / "PARSE" /
+ "PERMANENTFLAGS" SP "("
+ [flag-perm *(SP flag-perm)] ")" /
+ "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+ "UIDNEXT" SP nz-number / "UIDVALIDITY" SP nz-number /
+ "UNSEEN" SP nz-number /
+ atom [SP 1*<any TEXT-CHAR except "]">]
+
+search = "SEARCH" [SP "CHARSET" SP astring] 1*(SP search-key)
+ ; CHARSET argument to MUST be registered with IANA
+
+search-key = "ALL" / "ANSWERED" / "BCC" SP astring /
+ "BEFORE" SP date / "BODY" SP astring /
+ "CC" SP astring / "DELETED" / "FLAGGED" /
+ "FROM" SP astring / "KEYWORD" SP flag-keyword /
+ "NEW" / "OLD" / "ON" SP date / "RECENT" / "SEEN" /
+ "SINCE" SP date / "SUBJECT" SP astring /
+ "TEXT" SP astring / "TO" SP astring /
+ "UNANSWERED" / "UNDELETED" / "UNFLAGGED" /
+ "UNKEYWORD" SP flag-keyword / "UNSEEN" /
+ ; Above this line were in [IMAP2]
+ "DRAFT" / "HEADER" SP header-fld-name SP astring /
+ "LARGER" SP number / "NOT" SP search-key /
+ "OR" SP search-key SP search-key /
+ "SENTBEFORE" SP date / "SENTON" SP date /
+ "SENTSINCE" SP date / "SMALLER" SP number /
+ "UID" SP sequence-set / "UNDRAFT" / sequence-set /
+ "(" search-key *(SP search-key) ")"
+
+section = "[" [section-spec] "]"
+
+section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
+ "TEXT"
+ ; top-level or MESSAGE/RFC822 part
+
+section-part = nz-number *("." nz-number)
+ ; body part nesting
+
+
+
+Crispin Standards Track [Page 89]
+
+RFC 3501 IMAPv4 March 2003
+
+
+section-spec = section-msgtext / (section-part ["." section-text])
+
+section-text = section-msgtext / "MIME"
+ ; text other than actual body part (headers, etc.)
+
+select = "SELECT" SP mailbox
+
+seq-number = nz-number / "*"
+ ; message sequence number (COPY, FETCH, STORE
+ ; commands) or unique identifier (UID COPY,
+ ; UID FETCH, UID STORE commands).
+ ; * represents the largest number in use. In
+ ; the case of message sequence numbers, it is
+ ; the number of messages in a non-empty mailbox.
+ ; In the case of unique identifiers, it is the
+ ; unique identifier of the last message in the
+ ; mailbox or, if the mailbox is empty, the
+ ; mailbox's current UIDNEXT value.
+ ; The server should respond with a tagged BAD
+ ; response to a command that uses a message
+ ; sequence number greater than the number of
+ ; messages in the selected mailbox. This
+ ; includes "*" if the selected mailbox is empty.
+
+seq-range = seq-number ":" seq-number
+ ; two seq-number values and all values between
+ ; these two regardless of order.
+ ; Example: 2:4 and 4:2 are equivalent and indicate
+ ; values 2, 3, and 4.
+ ; Example: a unique identifier sequence range of
+ ; 3291:* includes the UID of the last message in
+ ; the mailbox, even if that value is less than 3291.
+
+sequence-set = (seq-number / seq-range) *("," sequence-set)
+ ; set of seq-number values, regardless of order.
+ ; Servers MAY coalesce overlaps and/or execute the
+ ; sequence in any order.
+ ; Example: a message sequence number set of
+ ; 2,4:7,9,12:* for a mailbox with 15 messages is
+ ; equivalent to 2,4,5,6,7,9,12,13,14,15
+ ; Example: a message sequence number set of *:4,5:7
+ ; for a mailbox with 10 messages is equivalent to
+ ; 10,9,8,7,6,5,4,5,6,7 and MAY be reordered and
+ ; overlap coalesced to be 4,5,6,7,8,9,10.
+
+status = "STATUS" SP mailbox SP
+ "(" status-att *(SP status-att) ")"
+
+
+
+
+Crispin Standards Track [Page 90]
+
+RFC 3501 IMAPv4 March 2003
+
+
+status-att = "MESSAGES" / "RECENT" / "UIDNEXT" / "UIDVALIDITY" /
+ "UNSEEN"
+
+status-att-list = status-att SP number *(SP status-att SP number)
+
+store = "STORE" SP sequence-set SP store-att-flags
+
+store-att-flags = (["+" / "-"] "FLAGS" [".SILENT"]) SP
+ (flag-list / (flag *(SP flag)))
+
+string = quoted / literal
+
+subscribe = "SUBSCRIBE" SP mailbox
+
+tag = 1*<any ASTRING-CHAR except "+">
+
+text = 1*TEXT-CHAR
+
+TEXT-CHAR = <any CHAR except CR and LF>
+
+time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
+ ; Hours minutes seconds
+
+uid = "UID" SP (copy / fetch / search / store)
+ ; Unique identifiers used instead of message
+ ; sequence numbers
+
+uniqueid = nz-number
+ ; Strictly ascending
+
+unsubscribe = "UNSUBSCRIBE" SP mailbox
+
+userid = astring
+
+x-command = "X" atom <experimental command arguments>
+
+zone = ("+" / "-") 4DIGIT
+ ; Signed four-digit value of hhmm representing
+ ; hours and minutes east of Greenwich (that is,
+ ; the amount that the given time differs from
+ ; Universal Time). Subtracting the timezone
+ ; from the given time will give the UT form.
+ ; The Universal Time zone is "+0000".
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 91]
+
+RFC 3501 IMAPv4 March 2003
+
+
+10. Author's Note
+
+ This document is a revision or rewrite of earlier documents, and
+ supercedes the protocol specification in those documents: RFC 2060,
+ RFC 1730, unpublished IMAP2bis.TXT document, RFC 1176, and RFC 1064.
+
+11. Security Considerations
+
+ IMAP4rev1 protocol transactions, including electronic mail data, are
+ sent in the clear over the network unless protection from snooping is
+ negotiated. This can be accomplished either by the use of STARTTLS,
+ negotiated privacy protection in the AUTHENTICATE command, or some
+ other protection mechanism.
+
+11.1. STARTTLS Security Considerations
+
+ The specification of the STARTTLS command and LOGINDISABLED
+ capability in this document replaces that in [IMAP-TLS]. [IMAP-TLS]
+ remains normative for the PLAIN [SASL] authenticator.
+
+ IMAP client and server implementations MUST implement the
+ TLS_RSA_WITH_RC4_128_MD5 [TLS] cipher suite, and SHOULD implement the
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [TLS] cipher suite. This is
+ important as it assures that any two compliant implementations can be
+ configured to interoperate. All other cipher suites are OPTIONAL.
+ Note that this is a change from section 2.1 of [IMAP-TLS].
+
+ During the [TLS] negotiation, the client MUST check its understanding
+ of the server hostname against the server's identity as presented in
+ the server Certificate message, in order to prevent man-in-the-middle
+ attacks. If the match fails, the client SHOULD either ask for
+ explicit user confirmation, or terminate the connection and indicate
+ that the server's identity is suspect. Matching is performed
+ according to these rules:
+
+ The client MUST use the server hostname it used to open the
+ connection as the value to compare against the server name
+ as expressed in the server certificate. The client MUST
+ NOT use any form of the server hostname derived from an
+ insecure remote source (e.g., insecure DNS lookup). CNAME
+ canonicalization is not done.
+
+ If a subjectAltName extension of type dNSName is present in
+ the certificate, it SHOULD be used as the source of the
+ server's identity.
+
+ Matching is case-insensitive.
+
+
+
+
+Crispin Standards Track [Page 92]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ A "*" wildcard character MAY be used as the left-most name
+ component in the certificate. For example, *.example.com
+ would match a.example.com, foo.example.com, etc. but would
+ not match example.com.
+
+ If the certificate contains multiple names (e.g., more than
+ one dNSName field), then a match with any one of the fields
+ is considered acceptable.
+
+ Both the client and server MUST check the result of the STARTTLS
+ command and subsequent [TLS] negotiation to see whether acceptable
+ authentication or privacy was achieved.
+
+11.2. Other Security Considerations
+
+ A server error message for an AUTHENTICATE command which fails due to
+ invalid credentials SHOULD NOT detail why the credentials are
+ invalid.
+
+ Use of the LOGIN command sends passwords in the clear. This can be
+ avoided by using the AUTHENTICATE command with a [SASL] mechanism
+ that does not use plaintext passwords, by first negotiating
+ encryption via STARTTLS or some other protection mechanism.
+
+ A server implementation MUST implement a configuration that, at the
+ time of authentication, requires:
+ (1) The STARTTLS command has been negotiated.
+ OR
+ (2) Some other mechanism that protects the session from password
+ snooping has been provided.
+ OR
+ (3) The following measures are in place:
+ (a) The LOGINDISABLED capability is advertised, and [SASL]
+ mechanisms (such as PLAIN) using plaintext passwords are NOT
+ advertised in the CAPABILITY list.
+ AND
+ (b) The LOGIN command returns an error even if the password is
+ correct.
+ AND
+ (c) The AUTHENTICATE command returns an error with all [SASL]
+ mechanisms that use plaintext passwords, even if the password
+ is correct.
+
+ A server error message for a failing LOGIN command SHOULD NOT specify
+ that the user name, as opposed to the password, is invalid.
+
+ A server SHOULD have mechanisms in place to limit or delay failed
+ AUTHENTICATE/LOGIN attempts.
+
+
+
+Crispin Standards Track [Page 93]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ Additional security considerations are discussed in the section
+ discussing the AUTHENTICATE and LOGIN commands.
+
+12. IANA Considerations
+
+ IMAP4 capabilities are registered by publishing a standards track or
+ IESG approved experimental RFC. The registry is currently located
+ at:
+
+ http://www.iana.org/assignments/imap4-capabilities
+
+ As this specification revises the STARTTLS and LOGINDISABLED
+ extensions previously defined in [IMAP-TLS], the registry will be
+ updated accordingly.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 94]
+
+RFC 3501 IMAPv4 March 2003
+
+
+Appendices
+
+A. Normative References
+
+ The following documents contain definitions or specifications that
+ are necessary to understand this document properly:
+ [ABNF] Crocker, D. and P. Overell, "Augmented BNF for
+ Syntax Specifications: ABNF", RFC 2234,
+ November 1997.
+
+ [ANONYMOUS] Newman, C., "Anonymous SASL Mechanism", RFC
+ 2245, November 1997.
+
+ [CHARSET] Freed, N. and J. Postel, "IANA Character Set
+ Registration Procedures", RFC 2978, October
+ 2000.
+
+ [DIGEST-MD5] Leach, P. and C. Newman, "Using Digest
+ Authentication as a SASL Mechanism", RFC 2831,
+ May 2000.
+
+ [DISPOSITION] Troost, R., Dorner, S. and K. Moore,
+ "Communicating Presentation Information in
+ Internet Messages: The Content-Disposition
+ Header", RFC 2183, August 1997.
+
+ [IMAP-TLS] Newman, C., "Using TLS with IMAP, POP3 and
+ ACAP", RFC 2595, June 1999.
+
+ [KEYWORDS] Bradner, S., "Key words for use in RFCs to
+ Indicate Requirement Levels", BCP 14, RFC 2119,
+ March 1997.
+
+ [LANGUAGE-TAGS] Alvestrand, H., "Tags for the Identification of
+ Languages", BCP 47, RFC 3066, January 2001.
+
+ [LOCATION] Palme, J., Hopmann, A. and N. Shelness, "MIME
+ Encapsulation of Aggregate Documents, such as
+ HTML (MHTML)", RFC 2557, March 1999.
+
+ [MD5] Myers, J. and M. Rose, "The Content-MD5 Header
+ Field", RFC 1864, October 1995.
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 95]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ [MIME-HDRS] Moore, K., "MIME (Multipurpose Internet Mail
+ Extensions) Part Three: Message Header
+ Extensions for Non-ASCII Text", RFC 2047,
+ November 1996.
+
+ [MIME-IMB] Freed, N. and N. Borenstein, "MIME
+ (Multipurpose Internet Mail Extensions) Part
+ One: Format of Internet Message Bodies", RFC
+ 2045, November 1996.
+
+ [MIME-IMT] Freed, N. and N. Borenstein, "MIME
+ (Multipurpose Internet Mail Extensions) Part
+ Two: Media Types", RFC 2046, November 1996.
+
+ [RFC-2822] Resnick, P., "Internet Message Format", RFC
+ 2822, April 2001.
+
+ [SASL] Myers, J., "Simple Authentication and Security
+ Layer (SASL)", RFC 2222, October 1997.
+
+ [TLS] Dierks, T. and C. Allen, "The TLS Protocol
+ Version 1.0", RFC 2246, January 1999.
+
+ [UTF-7] Goldsmith, D. and M. Davis, "UTF-7: A Mail-Safe
+ Transformation Format of Unicode", RFC 2152,
+ May 1997.
+
+ The following documents describe quality-of-implementation issues
+ that should be carefully considered when implementing this protocol:
+
+ [IMAP-IMPLEMENTATION] Leiba, B., "IMAP Implementation
+ Recommendations", RFC 2683, September 1999.
+
+ [IMAP-MULTIACCESS] Gahrns, M., "IMAP4 Multi-Accessed Mailbox
+ Practice", RFC 2180, July 1997.
+
+A.1 Informative References
+
+ The following documents describe related protocols:
+
+ [IMAP-DISC] Austein, R., "Synchronization Operations for
+ Disconnected IMAP4 Clients", Work in Progress.
+
+ [IMAP-MODEL] Crispin, M., "Distributed Electronic Mail
+ Models in IMAP4", RFC 1733, December 1994.
+
+
+
+
+
+
+Crispin Standards Track [Page 96]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ [ACAP] Newman, C. and J. Myers, "ACAP -- Application
+ Configuration Access Protocol", RFC 2244,
+ November 1997.
+
+ [SMTP] Klensin, J., "Simple Mail Transfer Protocol",
+ STD 10, RFC 2821, April 2001.
+
+ The following documents are historical or describe historical aspects
+ of this protocol:
+
+ [IMAP-COMPAT] Crispin, M., "IMAP4 Compatibility with
+ IMAP2bis", RFC 2061, December 1996.
+
+ [IMAP-HISTORICAL] Crispin, M., "IMAP4 Compatibility with IMAP2
+ and IMAP2bis", RFC 1732, December 1994.
+
+ [IMAP-OBSOLETE] Crispin, M., "Internet Message Access Protocol
+ - Obsolete Syntax", RFC 2062, December 1996.
+
+ [IMAP2] Crispin, M., "Interactive Mail Access Protocol
+ - Version 2", RFC 1176, August 1990.
+
+ [RFC-822] Crocker, D., "Standard for the Format of ARPA
+ Internet Text Messages", STD 11, RFC 822,
+ August 1982.
+
+ [RFC-821] Postel, J., "Simple Mail Transfer Protocol",
+ STD 10, RFC 821, August 1982.
+
+B. Changes from RFC 2060
+
+ 1) Clarify description of unique identifiers and their semantics.
+
+ 2) Fix the SELECT description to clarify that UIDVALIDITY is required
+ in the SELECT and EXAMINE responses.
+
+ 3) Added an example of a failing search.
+
+ 4) Correct store-att-flags: "#flag" should be "1#flag".
+
+ 5) Made search and section rules clearer.
+
+ 6) Correct the STORE example.
+
+ 7) Correct "BASE645" misspelling.
+
+ 8) Remove extraneous close parenthesis in example of two-part message
+ with text and BASE64 attachment.
+
+
+
+Crispin Standards Track [Page 97]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 9) Remove obsolete "MAILBOX" response from mailbox-data.
+
+ 10) A spurious "<" in the rule for mailbox-data was removed.
+
+ 11) Add CRLF to continue-req.
+
+ 12) Specifically exclude "]" from the atom in resp-text-code.
+
+ 13) Clarify that clients and servers should adhere strictly to the
+ protocol syntax.
+
+ 14) Emphasize in 5.2 that EXISTS can not be used to shrink a mailbox.
+
+ 15) Add NEWNAME to resp-text-code.
+
+ 16) Clarify that the empty string, not NIL, is used as arguments to
+ LIST.
+
+ 17) Clarify that NIL can be returned as a hierarchy delimiter for the
+ empty string mailbox name argument if the mailbox namespace is flat.
+
+ 18) Clarify that addr-mailbox and addr-name have RFC-2822 quoting
+ removed.
+
+ 19) Update UTF-7 reference.
+
+ 20) Fix example in 6.3.11.
+
+ 21) Clarify that non-existent UIDs are ignored.
+
+ 22) Update DISPOSITION reference.
+
+ 23) Expand state diagram.
+
+ 24) Clarify that partial fetch responses are only returned in
+ response to a partial fetch command.
+
+ 25) Add UIDNEXT response code. Correct UIDVALIDITY definition
+ reference.
+
+ 26) Further clarification of "can" vs. "MAY".
+
+ 27) Reference RFC-2119.
+
+ 28) Clarify that superfluous shifts are not permitted in modified
+ UTF-7.
+
+ 29) Clarify that there are no implicit shifts in modified UTF-7.
+
+
+
+Crispin Standards Track [Page 98]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 30) Clarify that "INBOX" in a mailbox name is always INBOX, even if
+ it is given as a string.
+
+ 31) Add missing open parenthesis in media-basic grammar rule.
+
+ 32) Correct attribute syntax in mailbox-data.
+
+ 33) Add UIDNEXT to EXAMINE responses.
+
+ 34) Clarify UNSEEN, PERMANENTFLAGS, UIDVALIDITY, and UIDNEXT
+ responses in SELECT and EXAMINE. They are required now, but weren't
+ in older versions.
+
+ 35) Update references with RFC numbers.
+
+ 36) Flush text-mime2.
+
+ 37) Clarify that modified UTF-7 names must be case-sensitive and that
+ violating the convention should be avoided.
+
+ 38) Correct UID FETCH example.
+
+ 39) Clarify UID FETCH, UID STORE, and UID SEARCH vs. untagged EXPUNGE
+ responses.
+
+ 40) Clarify the use of the word "convention".
+
+ 41) Clarify that a command is not "in progress" until it has been
+ fully received (specifically, that a command is not "in progress"
+ during command continuation negotiation).
+
+ 42) Clarify envelope defaulting.
+
+ 43) Clarify that SP means one and only one space character.
+
+ 44) Forbid silly states in LIST response.
+
+ 45) Clarify that the ENVELOPE, INTERNALDATE, RFC822*, BODY*, and UID
+ for a message is static.
+
+ 46) Add BADCHARSET response code.
+
+ 47) Update formal syntax to [ABNF] conventions.
+
+ 48) Clarify trailing hierarchy delimiter in CREATE semantics.
+
+ 49) Clarify that the "blank line" is the [RFC-2822] delimiting blank
+ line.
+
+
+
+Crispin Standards Track [Page 99]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 50) Clarify that RENAME should also create hierarchy as needed for
+ the command to complete.
+
+ 51) Fix body-ext-mpart to not require language if disposition
+ present.
+
+ 52) Clarify the RFC822.HEADER response.
+
+ 53) Correct missing space after charset astring in search.
+
+ 54) Correct missing quote for BADCHARSET in resp-text-code.
+
+ 55) Clarify that ALL, FAST, and FULL preclude any other data items
+ appearing.
+
+ 56) Clarify semantics of reference argument in LIST.
+
+ 57) Clarify that a null string for SEARCH HEADER X-FOO means any
+ message with a header line with a field-name of X-FOO regardless of
+ the text of the header.
+
+ 58) Specifically reserve 8-bit mailbox names for future use as UTF-8.
+
+ 59) It is not an error for the client to store a flag that is not in
+ the PERMANENTFLAGS list; however, the server will either ignore the
+ change or make the change in the session only.
+
+ 60) Correct/clarify the text regarding superfluous shifts.
+
+ 61) Correct typographic errors in the "Changes" section.
+
+ 62) Clarify that STATUS must not be used to check for new messages in
+ the selected mailbox
+
+ 63) Clarify LSUB behavior with "%" wildcard.
+
+ 64) Change AUTHORIZATION to AUTHENTICATE in section 7.5.
+
+ 65) Clarify description of multipart body type.
+
+ 66) Clarify that STORE FLAGS does not affect \Recent.
+
+ 67) Change "west" to "east" in description of timezone.
+
+ 68) Clarify that commands which break command pipelining must wait
+ for a completion result response.
+
+ 69) Clarify that EXAMINE does not affect \Recent.
+
+
+
+Crispin Standards Track [Page 100]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 70) Make description of MIME structure consistent.
+
+ 71) Clarify that date searches disregard the time and timezone of the
+ INTERNALDATE or Date: header. In other words, "ON 13-APR-2000" means
+ messages with an INTERNALDATE text which starts with "13-APR-2000",
+ even if timezone differential from the local timezone is sufficient
+ to move that INTERNALDATE into the previous or next day.
+
+ 72) Clarify that the header fetches don't add a blank line if one
+ isn't in the [RFC-2822] message.
+
+ 73) Clarify (in discussion of UIDs) that messages are immutable.
+
+ 74) Add an example of CHARSET searching.
+
+ 75) Clarify in SEARCH that keywords are a type of flag.
+
+ 76) Clarify the mandatory nature of the SELECT data responses.
+
+ 77) Add optional CAPABILITY response code in the initial OK or
+ PREAUTH.
+
+ 78) Add note that server can send an untagged CAPABILITY command as
+ part of the responses to AUTHENTICATE and LOGIN.
+
+ 79) Remove statement about it being unnecessary to issue a CAPABILITY
+ command more than once in a connection. That statement is no longer
+ true.
+
+ 80) Clarify that untagged EXPUNGE decrements the number of messages
+ in the mailbox.
+
+ 81) Fix definition of "body" (concatenation has tighter binding than
+ alternation).
+
+ 82) Add a new "Special Notes to Implementors" section with reference
+ to [IMAP-IMPLEMENTATION].
+
+ 83) Clarify that an untagged CAPABILITY response to an AUTHENTICATE
+ command should only be done if a security layer was not negotiated.
+
+ 84) Change the definition of atom to exclude "]". Update astring to
+ include "]" for compatibility with the past. Remove resp-text-atom.
+
+ 85) Remove NEWNAME. It can't work because mailbox names can be
+ literals and can include "]". Functionality can be addressed via
+ referrals.
+
+
+
+
+Crispin Standards Track [Page 101]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 86) Move modified UTF-7 rationale in order to have more logical
+ paragraph flow.
+
+ 87) Clarify UID uniqueness guarantees with the use of MUST.
+
+ 88) Note that clients should read response data until the connection
+ is closed instead of immediately closing on a BYE.
+
+ 89) Change RFC-822 references to RFC-2822.
+
+ 90) Clarify that RFC-2822 should be followed instead of RFC-822.
+
+ 91) Change recommendation of optional automatic capabilities in LOGIN
+ and AUTHENTICATE to use the CAPABILITY response code in the tagged
+ OK. This is more interoperable than an unsolicited untagged
+ CAPABILITY response.
+
+ 92) STARTTLS and AUTH=PLAIN are mandatory to implement; add
+ recommendations for other [SASL] mechanisms.
+
+ 93) Clarify that a "connection" (as opposed to "server" or "command")
+ is in one of the four states.
+
+ 94) Clarify that a failed or rejected command does not change state.
+
+ 95) Split references between normative and informative.
+
+ 96) Discuss authentication failure issues in security section.
+
+ 97) Clarify that a data item is not necessarily of only one data
+ type.
+
+ 98) Clarify that sequence ranges are independent of order.
+
+ 99) Change an example to clarify that superfluous shifts in
+ Modified-UTF7 can not be fixed just by omitting the shift. The
+ entire string must be recalculated.
+
+ 100) Change Envelope Structure definition since [RFC-2822] uses
+ "envelope" to refer to the [SMTP] envelope and not the envelope data
+ that appears in the [RFC-2822] header.
+
+ 101) Expand on RFC822.HEADER response data vs. BODY[HEADER].
+
+ 102) Clarify Logout state semantics, change ASCII art.
+
+ 103) Security changes to comply with IESG requirements.
+
+
+
+
+Crispin Standards Track [Page 102]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ 104) Add definition for body URI.
+
+ 105) Break sequence range definition into three rules, with rewritten
+ descriptions for each.
+
+ 106) Move STARTTLS and LOGINDISABLED here from [IMAP-TLS].
+
+ 107) Add IANA Considerations section.
+
+ 108) Clarify valid client assumptions for new message UIDs vs.
+ UIDNEXT.
+
+ 109) Clarify that changes to permanentflags affect concurrent
+ sessions as well as subsequent sessions.
+
+ 110) Clarify that authenticated state can be entered by the CLOSE
+ command.
+
+ 111) Emphasize that SELECT and EXAMINE are the exceptions to the rule
+ that a failing command does not change state.
+
+ 112) Clarify that newly-appended messages have the Recent flag set.
+
+ 113) Clarify that newly-copied messages SHOULD have the Recent flag
+ set.
+
+ 114) Clarify that UID commands always return the UID in FETCH
+ responses.
+
+C. Key Word Index
+
+ +FLAGS <flag list> (store command data item) ............... 59
+ +FLAGS.SILENT <flag list> (store command data item) ........ 59
+ -FLAGS <flag list> (store command data item) ............... 59
+ -FLAGS.SILENT <flag list> (store command data item) ........ 59
+ ALERT (response code) ...................................... 64
+ ALL (fetch item) ........................................... 55
+ ALL (search key) ........................................... 50
+ ANSWERED (search key) ...................................... 50
+ APPEND (command) ........................................... 45
+ AUTHENTICATE (command) ..................................... 27
+ BAD (response) ............................................. 66
+ BADCHARSET (response code) ................................. 64
+ BCC <string> (search key) .................................. 51
+ BEFORE <date> (search key) ................................. 51
+ BODY (fetch item) .......................................... 55
+ BODY (fetch result) ........................................ 73
+ BODY <string> (search key) ................................. 51
+
+
+
+Crispin Standards Track [Page 103]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ BODY.PEEK[<section>]<<partial>> (fetch item) ............... 57
+ BODYSTRUCTURE (fetch item) ................................. 57
+ BODYSTRUCTURE (fetch result) ............................... 74
+ BODY[<section>]<<origin octet>> (fetch result) ............. 74
+ BODY[<section>]<<partial>> (fetch item) .................... 55
+ BYE (response) ............................................. 67
+ Body Structure (message attribute) ......................... 12
+ CAPABILITY (command) ....................................... 24
+ CAPABILITY (response code) ................................. 64
+ CAPABILITY (response) ...................................... 68
+ CC <string> (search key) ................................... 51
+ CHECK (command) ............................................ 47
+ CLOSE (command) ............................................ 48
+ COPY (command) ............................................. 59
+ CREATE (command) ........................................... 34
+ DELETE (command) ........................................... 35
+ DELETED (search key) ....................................... 51
+ DRAFT (search key) ......................................... 51
+ ENVELOPE (fetch item) ...................................... 57
+ ENVELOPE (fetch result) .................................... 77
+ EXAMINE (command) .......................................... 33
+ EXISTS (response) .......................................... 71
+ EXPUNGE (command) .......................................... 48
+ EXPUNGE (response) ......................................... 72
+ Envelope Structure (message attribute) ..................... 12
+ FAST (fetch item) .......................................... 55
+ FETCH (command) ............................................ 54
+ FETCH (response) ........................................... 73
+ FLAGGED (search key) ....................................... 51
+ FLAGS (fetch item) ......................................... 57
+ FLAGS (fetch result) ....................................... 78
+ FLAGS (response) ........................................... 71
+ FLAGS <flag list> (store command data item) ................ 59
+ FLAGS.SILENT <flag list> (store command data item) ......... 59
+ FROM <string> (search key) ................................. 51
+ FULL (fetch item) .......................................... 55
+ Flags (message attribute) .................................. 11
+ HEADER (part specifier) .................................... 55
+ HEADER <field-name> <string> (search key) .................. 51
+ HEADER.FIELDS <header-list> (part specifier) ............... 55
+ HEADER.FIELDS.NOT <header-list> (part specifier) ........... 55
+ INTERNALDATE (fetch item) .................................. 57
+ INTERNALDATE (fetch result) ................................ 78
+ Internal Date (message attribute) .......................... 12
+ KEYWORD <flag> (search key) ................................ 51
+ Keyword (type of flag) ..................................... 11
+ LARGER <n> (search key) .................................... 51
+ LIST (command) ............................................. 40
+
+
+
+Crispin Standards Track [Page 104]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ LIST (response) ............................................ 69
+ LOGIN (command) ............................................ 30
+ LOGOUT (command) ........................................... 25
+ LSUB (command) ............................................. 43
+ LSUB (response) ............................................ 70
+ MAY (specification requirement term) ....................... 4
+ MESSAGES (status item) ..................................... 45
+ MIME (part specifier) ...................................... 56
+ MUST (specification requirement term) ...................... 4
+ MUST NOT (specification requirement term) .................. 4
+ Message Sequence Number (message attribute) ................ 10
+ NEW (search key) ........................................... 51
+ NO (response) .............................................. 66
+ NOOP (command) ............................................. 25
+ NOT <search-key> (search key) .............................. 52
+ OK (response) .............................................. 65
+ OLD (search key) ........................................... 52
+ ON <date> (search key) ..................................... 52
+ OPTIONAL (specification requirement term) .................. 4
+ OR <search-key1> <search-key2> (search key) ................ 52
+ PARSE (response code) ...................................... 64
+ PERMANENTFLAGS (response code) ............................. 64
+ PREAUTH (response) ......................................... 67
+ Permanent Flag (class of flag) ............................. 12
+ READ-ONLY (response code) .................................. 65
+ READ-WRITE (response code) ................................. 65
+ RECENT (response) .......................................... 72
+ RECENT (search key) ........................................ 52
+ RECENT (status item) ....................................... 45
+ RENAME (command) ........................................... 37
+ REQUIRED (specification requirement term) .................. 4
+ RFC822 (fetch item) ........................................ 57
+ RFC822 (fetch result) ...................................... 78
+ RFC822.HEADER (fetch item) ................................. 57
+ RFC822.HEADER (fetch result) ............................... 78
+ RFC822.SIZE (fetch item) ................................... 57
+ RFC822.SIZE (fetch result) ................................. 78
+ RFC822.TEXT (fetch item) ................................... 58
+ RFC822.TEXT (fetch result) ................................. 79
+ SEARCH (command) ........................................... 49
+ SEARCH (response) .......................................... 71
+ SEEN (search key) .......................................... 52
+ SELECT (command) ........................................... 31
+ SENTBEFORE <date> (search key) ............................. 52
+ SENTON <date> (search key) ................................. 52
+ SENTSINCE <date> (search key) .............................. 52
+ SHOULD (specification requirement term) .................... 4
+ SHOULD NOT (specification requirement term) ................ 4
+
+
+
+Crispin Standards Track [Page 105]
+
+RFC 3501 IMAPv4 March 2003
+
+
+ SINCE <date> (search key) .................................. 52
+ SMALLER <n> (search key) ................................... 52
+ STARTTLS (command) ......................................... 27
+ STATUS (command) ........................................... 44
+ STATUS (response) .......................................... 70
+ STORE (command) ............................................ 58
+ SUBJECT <string> (search key) .............................. 53
+ SUBSCRIBE (command) ........................................ 38
+ Session Flag (class of flag) ............................... 12
+ System Flag (type of flag) ................................. 11
+ TEXT (part specifier) ...................................... 56
+ TEXT <string> (search key) ................................. 53
+ TO <string> (search key) ................................... 53
+ TRYCREATE (response code) .................................. 65
+ UID (command) .............................................. 60
+ UID (fetch item) ........................................... 58
+ UID (fetch result) ......................................... 79
+ UID <sequence set> (search key) ............................ 53
+ UIDNEXT (response code) .................................... 65
+ UIDNEXT (status item) ...................................... 45
+ UIDVALIDITY (response code) ................................ 65
+ UIDVALIDITY (status item) .................................. 45
+ UNANSWERED (search key) .................................... 53
+ UNDELETED (search key) ..................................... 53
+ UNDRAFT (search key) ....................................... 53
+ UNFLAGGED (search key) ..................................... 53
+ UNKEYWORD <flag> (search key) .............................. 53
+ UNSEEN (response code) ..................................... 65
+ UNSEEN (search key) ........................................ 53
+ UNSEEN (status item) ....................................... 45
+ UNSUBSCRIBE (command) ...................................... 39
+ Unique Identifier (UID) (message attribute) ................ 8
+ X<atom> (command) .......................................... 62
+ [RFC-2822] Size (message attribute) ........................ 12
+ \Answered (system flag) .................................... 11
+ \Deleted (system flag) ..................................... 11
+ \Draft (system flag) ....................................... 11
+ \Flagged (system flag) ..................................... 11
+ \Marked (mailbox name attribute) ........................... 69
+ \Noinferiors (mailbox name attribute) ...................... 69
+ \Noselect (mailbox name attribute) ......................... 69
+ \Recent (system flag) ...................................... 11
+ \Seen (system flag) ........................................ 11
+ \Unmarked (mailbox name attribute) ......................... 69
+
+
+
+
+
+
+
+Crispin Standards Track [Page 106]
+
+RFC 3501 IMAPv4 March 2003
+
+
+Author's Address
+
+ Mark R. Crispin
+ Networks and Distributed Computing
+ University of Washington
+ 4545 15th Avenue NE
+ Seattle, WA 98105-4527
+
+ Phone: (206) 543-5762
+
+ EMail: MRC@CAC.Washington.EDU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 107]
+
+RFC 3501 IMAPv4 March 2003
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2003). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns. v This
+ document and the information contained herein is provided on an "AS
+ IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK
+ FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+ LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL
+ NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY
+ OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Crispin Standards Track [Page 108]
+
diff --git a/vendor/github.com/mattermost/rsc/imap/sx.go b/vendor/github.com/mattermost/rsc/imap/sx.go
new file mode 100644
index 000000000..8b0e361fa
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/sx.go
@@ -0,0 +1,350 @@
+package imap
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "strings"
+ "time"
+)
+
+type sxKind int
+
+const (
+ sxNone sxKind = iota
+ sxAtom
+ sxString
+ sxNumber
+ sxList
+)
+
+type sx struct {
+ kind sxKind
+ data []byte
+ number int64
+ sx []*sx
+}
+
+func rdsx(b *bufio.Reader) (*sx, error) {
+ x := &sx{kind: sxList}
+ for {
+ xx, err := rdsx1(b)
+ if err != nil {
+ return nil, err
+ }
+ if xx == nil {
+ break
+ }
+ x.sx = append(x.sx, xx)
+ }
+ return x, nil
+}
+
+func rdsx1(b *bufio.Reader) (*sx, error) {
+ c, err := b.ReadByte()
+ if c == ' ' {
+ c, err = b.ReadByte()
+ }
+ if c == '\r' {
+ c, err = b.ReadByte()
+ }
+ if err != nil {
+ return nil, err
+ }
+ if c == '\n' {
+ return nil, nil
+ }
+ if c == ')' { // end of list
+ b.UnreadByte()
+ return nil, nil
+ }
+ if c == '(' { // parenthesized list
+ x, err := rdsx(b)
+ if err != nil {
+ return nil, err
+ }
+ c, err = b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c != ')' {
+ // oops! not good
+ b.UnreadByte()
+ }
+ return x, nil
+ }
+ if c == '{' { // length-prefixed string
+ n := 0
+ for {
+ c, _ = b.ReadByte()
+ if c < '0' || c > '9' {
+ break
+ }
+ n = n*10 + int(c) - '0'
+ }
+ if c != '}' {
+ // oops! not good
+ b.UnreadByte()
+ }
+ c, err = b.ReadByte()
+ if c != '\r' {
+ // oops! not good
+ }
+ c, err = b.ReadByte()
+ if c != '\n' {
+ // oops! not good
+ }
+ data := make([]byte, n)
+ if _, err := io.ReadFull(b, data); err != nil {
+ return nil, err
+ }
+ return &sx{kind: sxString, data: data}, nil
+ }
+ if c == '"' { // quoted string
+ var data []byte
+ for {
+ c, err = b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c == '"' {
+ break
+ }
+ if c == '\\' {
+ c, _ = b.ReadByte()
+ }
+ data = append(data, c)
+ }
+ return &sx{kind: sxString, data: data}, nil
+ }
+ if '0' <= c && c <= '9' { // number
+ n := int64(c) - '0'
+ for {
+ c, err := b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c < '0' || c > '9' {
+ break
+ }
+ n = n*10 + int64(c) - '0'
+ }
+ b.UnreadByte()
+ return &sx{kind: sxNumber, number: n}, nil
+ }
+
+ // atom
+ nbr := 0
+ var data []byte
+ data = append(data, c)
+ for {
+ c, err = b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c <= ' ' || c == '(' || c == ')' || c == '{' || c == '}' {
+ break
+ }
+ if c == '[' {
+ // allow embedded brackets as in BODY[]
+ if data[0] == '[' {
+ break
+ }
+ nbr++
+ }
+ if c == ']' {
+ if nbr <= 0 {
+ break
+ }
+ nbr--
+ }
+ data = append(data, c)
+ }
+ if c != ' ' {
+ b.UnreadByte()
+ }
+ return &sx{kind: sxAtom, data: data}, nil
+}
+
+func (x *sx) ok() bool {
+ return len(x.sx) >= 2 && x.sx[1].kind == sxAtom && strings.EqualFold(string(x.sx[1].data), "ok")
+}
+
+func (x *sx) String() string {
+ var b bytes.Buffer
+ x.fmt(&b, true)
+ return b.String()
+}
+
+func (x *sx) fmt(b *bytes.Buffer, paren bool) {
+ if x == nil {
+ return
+ }
+ switch x.kind {
+ case sxAtom, sxString:
+ fmt.Fprintf(b, "%q", x.data)
+ case sxNumber:
+ fmt.Fprintf(b, "%d", x.number)
+ case sxList:
+ if paren {
+ b.WriteByte('(')
+ }
+ for i, xx := range x.sx {
+ if i > 0 {
+ b.WriteByte(' ')
+ }
+ xx.fmt(b, paren)
+ }
+ if paren {
+ b.WriteByte(')')
+ }
+ default:
+ b.WriteByte('?')
+ }
+}
+
+var bytesNIL = []byte("NIL")
+
+var fmtKind = []sxKind{
+ 'L': sxList,
+ 'S': sxString,
+ 'N': sxNumber,
+ 'A': sxAtom,
+}
+
+func (x *sx) match(format string) bool {
+ done := false
+ c := format[0]
+ for i := 0; i < len(x.sx); i++ {
+ if !done {
+ if i >= len(format) {
+ log.Printf("sxmatch: too short")
+ return false
+ }
+ if format[i] == '*' {
+ done = true
+ } else {
+ c = format[i]
+ }
+ }
+ xx := x.sx[i]
+ if xx.kind == sxAtom && xx.isNil() {
+ if c == 'L' {
+ xx.kind = sxList
+ xx.data = nil
+ } else if c == 'S' {
+ xx.kind = sxString
+ xx.data = nil
+ }
+ }
+ if xx.kind == sxAtom && c == 'S' {
+ xx.kind = sxString
+ }
+ if xx.kind != fmtKind[c] {
+ log.Printf("sxmatch: %s not %c", xx, c)
+ return false
+ }
+ }
+ if len(format) > len(x.sx) {
+ log.Printf("sxmatch: too long")
+ return false
+ }
+ return true
+}
+
+func (x *sx) isAtom(name string) bool {
+ if x == nil || x.kind != sxAtom {
+ return false
+ }
+ data := x.data
+ n := len(name)
+ if n > 0 && name[n-1] == '[' {
+ i := bytes.IndexByte(data, '[')
+ if i < 0 {
+ return false
+ }
+ data = data[:i]
+ name = name[:n-1]
+ }
+ for i := 0; i < len(name); i++ {
+ if i >= len(data) || lwr(rune(data[i])) != lwr(rune(name[i])) {
+ return false
+ }
+ }
+ return len(name) == len(data)
+}
+
+func (x *sx) isString() bool {
+ if x.isNil() {
+ return true
+ }
+ if x.kind == sxAtom {
+ x.kind = sxString
+ }
+ return x.kind == sxString
+}
+
+func (x *sx) isNumber() bool {
+ return x.kind == sxNumber
+}
+
+func (x *sx) isNil() bool {
+ return x == nil ||
+ x.kind == sxList && len(x.sx) == 0 ||
+ x.kind == sxAtom && bytes.Equal(x.data, bytesNIL)
+}
+
+func (x *sx) isList() bool {
+ return x.isNil() || x.kind == sxList
+}
+
+func (x *sx) parseFlags() Flags {
+ if x.kind != sxList {
+ log.Printf("malformed flags: %s", x)
+ return 0
+ }
+
+ f := Flags(0)
+SX:
+ for _, xx := range x.sx {
+ if xx.kind != sxAtom {
+ continue
+ }
+ for i, name := range flagNames {
+ if xx.isAtom(name) {
+ f |= 1 << uint(i)
+ continue SX
+ }
+ }
+ if Debug {
+ log.Printf("unknown flag: %v", xx)
+ }
+ }
+ return f
+}
+
+func (x *sx) parseDate() time.Time {
+ if x.kind != sxString {
+ log.Printf("malformed date: %s", x)
+ return time.Time{}
+ }
+
+ t, err := time.Parse("02-Jan-2006 15:04:05 -0700", string(x.data))
+ if err != nil {
+ log.Printf("malformed date: %s (%s)", x, err)
+ }
+ return t
+}
+
+func (x *sx) nstring() string {
+ return string(x.nbytes())
+}
+
+func (x *sx) nbytes() []byte {
+ if x.isNil() {
+ return nil
+ }
+ return x.data
+}
diff --git a/vendor/github.com/mattermost/rsc/imap/sx_test.go b/vendor/github.com/mattermost/rsc/imap/sx_test.go
new file mode 100644
index 000000000..9644209ca
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/sx_test.go
@@ -0,0 +1,60 @@
+package imap
+
+import (
+ "bufio"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var sxTests = []struct {
+ in string
+ out *sx
+}{
+ {"1234", &sx{kind: sxNumber, number: 1234}},
+ {"hello", &sx{kind: sxAtom, data: []byte("hello")}},
+ {"hello[world]", &sx{kind: sxAtom, data: []byte("hello[world]")}},
+ {`"h\\ello"`, &sx{kind: sxString, data: []byte(`h\ello`)}},
+ {"{6}\r\nh\\ello", &sx{kind: sxString, data: []byte(`h\ello`)}},
+ {`(hello "world" (again) ())`,
+ &sx{
+ kind: sxList,
+ sx: []*sx{
+ &sx{
+ kind: sxAtom,
+ data: []byte("hello"),
+ },
+ &sx{
+ kind: sxString,
+ data: []byte("world"),
+ },
+ &sx{
+ kind: sxList,
+ sx: []*sx{
+ &sx{
+ kind: sxAtom,
+ data: []byte("again"),
+ },
+ },
+ },
+ &sx{
+ kind: sxList,
+ },
+ },
+ },
+ },
+}
+
+func TestSx(t *testing.T) {
+ for _, tt := range sxTests {
+ b := bufio.NewReader(strings.NewReader(tt.in + "\n"))
+ sx, err := rdsx1(b)
+ if err != nil {
+ t.Errorf("parse %s: %v", tt.in, err)
+ continue
+ }
+ if !reflect.DeepEqual(sx, tt.out) {
+ t.Errorf("rdsx1(%s) = %v, want %v", tt.in, sx, tt.out)
+ }
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/imap/tcs.go b/vendor/github.com/mattermost/rsc/imap/tcs.go
new file mode 100644
index 000000000..6a0939e01
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/tcs.go
@@ -0,0 +1,602 @@
+package imap
+
+// NOTE(rsc): These belong elsewhere but the existing charset
+// packages seem too complicated.
+
+var tab_iso8859_1 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+}
+
+var tab_iso8859_2 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7,
+ 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b,
+ 0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7,
+ 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c,
+ 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
+ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+ 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
+ 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+ 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
+ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+ 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
+ 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9,
+}
+
+var tab_iso8859_3 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, 0x0126, 0x02d8, 0x00a3, 0x00a4, -1, 0x0124, 0x00a7,
+ 0x00a8, 0x0130, 0x015e, 0x011e, 0x0134, 0x00ad, -1, 0x017b,
+ 0x00b0, 0x0127, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x0125, 0x00b7,
+ 0x00b8, 0x0131, 0x015f, 0x011f, 0x0135, 0x00bd, -1, 0x017c,
+ 0x00c0, 0x00c1, 0x00c2, -1, 0x00c4, 0x010a, 0x0108, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ -1, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x0120, 0x00d6, 0x00d7,
+ 0x011c, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x016c, 0x015c, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, -1, 0x00e4, 0x010b, 0x0109, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ -1, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x0121, 0x00f6, 0x00f7,
+ 0x011d, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x016d, 0x015d, 0x02d9,
+}
+
+var tab_iso8859_4 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, 0x0104, 0x0138, 0x0156, 0x00a4, 0x0128, 0x013b, 0x00a7,
+ 0x00a8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00ad, 0x017d, 0x00af,
+ 0x00b0, 0x0105, 0x02db, 0x0157, 0x00b4, 0x0129, 0x013c, 0x02c7,
+ 0x00b8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014a, 0x017e, 0x014b,
+ 0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e,
+ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x012a,
+ 0x0110, 0x0145, 0x014c, 0x0136, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+ 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x0168, 0x016a, 0x00df,
+ 0x0101, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x012f,
+ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x012b,
+ 0x0111, 0x0146, 0x014d, 0x0137, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x0169, 0x016b, 0x02d9,
+}
+
+var tab_iso8859_5 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
+ 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x00ad, 0x040e, 0x040f,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+ 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x00a7, 0x045e, 0x045f,
+}
+
+var tab_iso8859_6 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, -1, -1, -1, 0x00a4, -1, -1, -1,
+ -1, -1, -1, -1, 0x060c, 0x00ad, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 0x061b, -1, -1, -1, 0x061f,
+ -1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062a, 0x062b, 0x062c, 0x062d, 0x062e, 0x062f,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637,
+ 0x0638, 0x0639, 0x063a, -1, -1, -1, -1, -1,
+ 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647,
+ 0x0648, 0x0649, 0x064a, 0x064b, 0x064c, 0x064d, 0x064e, 0x064f,
+ 0x0650, 0x0651, 0x0652, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+}
+
+var tab_iso8859_7 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, 0x2018, 0x2019, 0x00a3, -1, -1, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, -1, 0x00ab, 0x00ac, 0x00ad, -1, 0x2015,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x0384, 0x0385, 0x0386, 0x00b7,
+ 0x0388, 0x0389, 0x038a, 0x00bb, 0x038c, 0x00bd, 0x038e, 0x038f,
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
+ 0x03a0, 0x03a1, -1, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
+ 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03ae, 0x03af,
+ 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+ 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, -1,
+}
+
+var tab_iso8859_8 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, -1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00d7, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x203e,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00f7, 0x00bb, 0x00bc, 0x00bd, 0x00be, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, 0x2017,
+ 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+ 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+ 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+ 0x05e8, 0x05e9, 0x05ea, -1, -1, -1, -1, -1,
+}
+
+var tab_iso8859_9 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x011e, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7,
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x0130, 0x015e, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x011f, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x0131, 0x015f, 0x00ff,
+}
+
+var tab_iso8859_10 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0x00a0, 0x0104, 0x0112, 0x0122, 0x012a, 0x0128, 0x0136, 0x00a7,
+ 0x013b, 0x0110, 0x0160, 0x0166, 0x017d, 0x00ad, 0x016a, 0x014a,
+ 0x00b0, 0x0105, 0x0113, 0x0123, 0x012b, 0x0129, 0x0137, 0x00b7,
+ 0x013c, 0x0110, 0x0161, 0x0167, 0x017e, 0x2014, 0x016b, 0x014b,
+ 0x0100, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x012e,
+ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x0116, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x0145, 0x014c, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x0168,
+ 0x00d8, 0x0172, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+ 0x0101, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x012f,
+ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x0117, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x0146, 0x014d, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x0169,
+ 0x00f8, 0x0173, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x0138,
+}
+
+var tab_iso8859_15 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0x20ac, 0xa5, 0x0160, 0xa7, 0x0161, 0xa9, 0xaa, 0xab, 0xac, 0xad,
+ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0x017d, 0xb5, 0xb6, 0xb7, 0x017e, 0xb9, 0xba, 0xbb,
+ 0x0152, 0x0153, 0x0178, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+ 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8,
+ 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6,
+ 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+}
+
+var tab_koi8 = [256]rune{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 0x044e, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
+ 0x0445, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e,
+ 0x043f, 0x044f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432,
+ 0x044c, 0x044b, 0x0437, 0x0448, 0x044d, 0x0449, 0x0447, 0x044a,
+ 0x042e, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413,
+ 0x0425, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e,
+ 0x041f, 0x042f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
+ 0x042c, 0x042b, 0x0417, 0x0428, 0x042d, 0x0429, 0x0427, 0x042a,
+}
+
+var tab_cp1250 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, -1, 0x201A, -1, 0x201E, 0x2026, 0x2020, 0x2021,
+ -1, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179,
+ -1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ -1, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A,
+ 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B,
+ 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C,
+ 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
+ 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
+ 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
+ 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
+ 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
+ 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
+ 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
+ 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9,
+}
+var tab_cp1251 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
+ 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ -1, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
+ 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
+ 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
+ 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
+ 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
+ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+}
+var tab_cp1252 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, -1, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, -1, 0x017D, -1,
+ -1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, -1, 0x017E, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+}
+var tab_cp1253 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, -1, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ -1, 0x2030, -1, 0x2039, -1, -1, -1, -1,
+ -1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ -1, 0x2122, -1, 0x203A, -1, -1, -1, -1,
+ 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, -1, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7,
+ 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
+ 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ 0x03A0, 0x03A1, -1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+ 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+ 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, -1,
+}
+var tab_cp1254 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, -1, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, -1, -1, -1,
+ -1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, -1, -1, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF,
+}
+var tab_cp1255 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, -1, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, -1, 0x2039, -1, -1, -1, -1,
+ -1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, -1, 0x203A, -1, -1, -1, -1,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+ 0x05B8, 0x05B9, -1, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3,
+ 0x05F4, -1, -1, -1, -1, -1, -1, -1,
+ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+ 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+ 0x05E8, 0x05E9, 0x05EA, -1, -1, 0x200E, 0x200F, -1,
+}
+var tab_cp1256 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688,
+ 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA,
+ 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F,
+ 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627,
+ 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F,
+ 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7,
+ 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643,
+ 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF,
+ 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7,
+ 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2,
+}
+var tab_cp1257 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, -1, 0x201A, -1, 0x201E, 0x2026, 0x2020, 0x2021,
+ -1, 0x2030, -1, 0x2039, -1, 0x00A8, 0x02C7, 0x00B8,
+ -1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ -1, 0x2122, -1, 0x203A, -1, 0x00AF, 0x02DB, -1,
+ 0x00A0, -1, 0x00A2, 0x00A3, 0x00A4, -1, 0x00A6, 0x00A7,
+ 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
+ 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
+ 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
+ 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
+ 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
+ 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
+ 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
+ 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
+ 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9,
+}
+var tab_cp1258 = [256]rune{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ 0x20AC, -1, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
+ 0x02C6, 0x2030, -1, 0x2039, 0x0152, -1, -1, -1,
+ -1, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
+ 0x02DC, 0x2122, -1, 0x203A, 0x0153, -1, -1, 0x0178,
+ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+ 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
+ 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF,
+ 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7,
+ 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF,
+ 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+ 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF,
+ 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7,
+ 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF,
+}
diff --git a/vendor/github.com/mattermost/rsc/keychain/doc.go b/vendor/github.com/mattermost/rsc/keychain/doc.go
new file mode 100644
index 000000000..e7e21fd2e
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/keychain/doc.go
@@ -0,0 +1,28 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package keychain implements access to the passwords and other keys
+// stored in the system-provided keychain.
+package keychain
+
+// BUG(rsc): Package keychain is only implemented on OS X.
+
+import (
+ "fmt"
+)
+
+// UserPasswd returns the user name and password for authenticating
+// to the named server. If the user argument is non-empty, UserPasswd
+// restricts its search to passwords for the named user.
+func UserPasswd(server, preferredUser string) (user, passwd string, err error) {
+ user, passwd, err = userPasswd(server, preferredUser)
+ if err != nil {
+ if preferredUser != "" {
+ err = fmt.Errorf("loading password for %s@%s: %v", preferredUser, server, err)
+ } else {
+ err = fmt.Errorf("loading password for %s: %v", server, err)
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/mattermost/rsc/keychain/mac.go b/vendor/github.com/mattermost/rsc/keychain/mac.go
new file mode 100644
index 000000000..523579169
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/keychain/mac.go
@@ -0,0 +1,107 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package keychain
+
+/*
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+#include <CoreServices/CoreServices.h>
+
+#cgo LDFLAGS: -framework CoreFoundation -framework Security
+
+static char*
+mac2c(CFStringRef s)
+{
+ char *p;
+ int n;
+
+ n = CFStringGetLength(s)*8;
+ p = malloc(n);
+ CFStringGetCString(s, p, n, kCFStringEncodingUTF8);
+ return p;
+}
+
+void
+keychain_getpasswd(char *user0, char *server, char **user, char **passwd, char **error)
+{
+ OSStatus st;
+ UInt32 len;
+ void *data;
+ SecKeychainItemRef it;
+ CFStringRef str;
+
+ *user = NULL;
+ *passwd = NULL;
+ *error = NULL;
+
+ st = SecKeychainFindInternetPassword(
+ NULL, // default keychain
+ strlen(server), server,
+ 0, NULL, // security domain
+ strlen(user0), user0, // account name
+ 0, NULL, // path
+ 0, // port
+ 0, // protocol type
+ kSecAuthenticationTypeDefault,
+ &len,
+ &data,
+ &it);
+ if(st != 0) {
+ str = SecCopyErrorMessageString(st, NULL);
+ *error = mac2c(str);
+ CFRelease(str);
+ return;
+ }
+ *passwd = malloc(len+1);
+ memmove(*passwd, data, len);
+ (*passwd)[len] = '\0';
+ SecKeychainItemFreeContent(NULL, data);
+
+ SecKeychainAttribute attr = {kSecAccountItemAttr, 0, NULL};
+ SecKeychainAttributeList attrl = {1, &attr};
+ st = SecKeychainItemCopyContent(
+ it,
+ NULL,
+ &attrl,
+ 0, NULL);
+ if(st != 0) {
+ str = SecCopyErrorMessageString(st, NULL);
+ *error = mac2c(str);
+ CFRelease(str);
+ return;
+ }
+ data = attr.data;
+ len = attr.length;
+ *user = malloc(len+1);
+ memmove(*user, data, len);
+ (*user)[len] = '\0';
+ SecKeychainItemFreeContent(&attrl, NULL);
+}
+*/
+import "C"
+
+import (
+ "errors"
+ "unsafe"
+)
+
+func userPasswd(server, user string) (user1, passwd string, err error) {
+ cServer := C.CString(server)
+ cUser := C.CString(user)
+ defer C.free(unsafe.Pointer(cServer))
+ defer C.free(unsafe.Pointer(cUser))
+
+ var cPasswd, cError *C.char
+ C.keychain_getpasswd(cUser, cServer, &cUser, &cPasswd, &cError)
+ defer C.free(unsafe.Pointer(cUser))
+ defer C.free(unsafe.Pointer(cPasswd))
+ defer C.free(unsafe.Pointer(cError))
+
+ if cError != nil {
+ return "", "", errors.New(C.GoString(cError))
+ }
+
+ return C.GoString(cUser), C.GoString(cPasswd), nil
+}
diff --git a/vendor/github.com/mattermost/rsc/mbta/Passages.pb b/vendor/github.com/mattermost/rsc/mbta/Passages.pb
new file mode 100644
index 000000000..5eb9e900e
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/mbta/Passages.pb
Binary files differ
diff --git a/vendor/github.com/mattermost/rsc/mbta/Vehicles.pb b/vendor/github.com/mattermost/rsc/mbta/Vehicles.pb
new file mode 100644
index 000000000..98d90c800
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/mbta/Vehicles.pb
Binary files differ
diff --git a/vendor/github.com/mattermost/rsc/mbta/mbta.go b/vendor/github.com/mattermost/rsc/mbta/mbta.go
new file mode 100644
index 000000000..c8c68e6e2
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/mbta/mbta.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "io/ioutil"
+ "log"
+ "os"
+
+ "code.google.com/p/goprotobuf/proto"
+ "github.com/mattermost/rsc/gtfs"
+)
+
+func main() {
+ log.SetFlags(0)
+ if len(os.Args) != 2 {
+ log.Fatal("usage: mbta file.pb")
+ }
+ pb, err := ioutil.ReadFile(os.Args[1])
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var feed gtfs.FeedMessage
+ if err := proto.Unmarshal(pb, &feed); err != nil {
+ log.Fatal(err)
+ }
+
+ proto.MarshalText(os.Stdout, &feed)
+}
diff --git a/vendor/github.com/mattermost/rsc/mkapp b/vendor/github.com/mattermost/rsc/mkapp
new file mode 100755
index 000000000..1a52931f1
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/mkapp
@@ -0,0 +1,51 @@
+#!/bin/bash
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Run this script in your app root directory, the one containing
+# the app.yaml file. Then point appcfg.py or dev_appserver.py
+# at './tmp' instead of '.'.
+#
+# It creates a symlink forest in a subdirectory named 'tmp' that
+# includes all the files from packages under your app root as
+# well as any packages from your $GOPATH that are needed by
+# the app packages. This makes deployment to App Engine
+# bring in just the packages you need, without manual chasing
+# of dependencies. Perhaps some day appcfg.py and dev_appserver.py
+# will work this way by default.
+
+set -e
+rm -rf tmp
+dirs=$(find . -type d)
+mkdir tmp
+
+for i in *
+do
+ case "$i" in
+ tmp | *.go)
+ ;;
+ *)
+ ln -s ../$i tmp/$i
+ esac
+done
+
+# Like App Engine
+export GOOS=linux
+export GOARCH=amd64
+
+mkdir tmp/_go_top
+cp $(go list -f '{{range .GoFiles}}{{.}} {{end}}') tmp/_go_top
+
+dirs=$(go list -e -f '{{if not .Standard}}{{.ImportPath}} {{end}}' $(go list -f '{{range .Deps}}{{.}} {{end}}' $dirs))
+for import in $dirs
+do
+ case "$import" in
+ appengine | appengine/*)
+ ;;
+ *)
+ mkdir -p tmp/$import
+ files=$(go list -f '{{range .GoFiles}}{{$.Dir}}/{{.}} {{end}}' $import)
+ ln -s $files tmp/$import 2>&1 | grep -v 'is a directory' || true # ignore subdirectory warnings
+ esac
+done
diff --git a/vendor/github.com/mattermost/rsc/plist/plist.go b/vendor/github.com/mattermost/rsc/plist/plist.go
new file mode 100644
index 000000000..1c76bface
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/plist/plist.go
@@ -0,0 +1,179 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package plist implements parsing of Apple plist files.
+package plist
+
+import (
+ "bytes"
+ "fmt"
+ "reflect"
+ "strconv"
+)
+
+func next(data []byte) (skip, tag, rest []byte) {
+ i := bytes.IndexByte(data, '<')
+ if i < 0 {
+ return data, nil, nil
+ }
+ j := bytes.IndexByte(data[i:], '>')
+ if j < 0 {
+ return data, nil, nil
+ }
+ j += i + 1
+ return data[:i], data[i:j], data[j:]
+}
+
+func Unmarshal(data []byte, v interface{}) error {
+ _, tag, data := next(data)
+ if !bytes.HasPrefix(tag, []byte("<plist")) {
+ return fmt.Errorf("not a plist")
+ }
+
+ data, err := unmarshalValue(data, reflect.ValueOf(v))
+ if err != nil {
+ return err
+ }
+ _, tag, data = next(data)
+ if !bytes.Equal(tag, []byte("</plist>")) {
+ return fmt.Errorf("junk on end of plist")
+ }
+ return nil
+}
+
+func unmarshalValue(data []byte, v reflect.Value) (rest []byte, err error) {
+ _, tag, data := next(data)
+ if tag == nil {
+ return nil, fmt.Errorf("unexpected end of data")
+ }
+
+ if v.Kind() == reflect.Ptr {
+ if v.IsNil() {
+ v.Set(reflect.New(v.Type().Elem()))
+ }
+ v = v.Elem()
+ }
+
+ switch string(tag) {
+ case "<dict>":
+ t := v.Type()
+ if v.Kind() != reflect.Struct {
+ return nil, fmt.Errorf("cannot unmarshal <dict> into non-struct %s", v.Type())
+ }
+ Dict:
+ for {
+ _, tag, data = next(data)
+ if len(tag) == 0 {
+ return nil, fmt.Errorf("eof inside <dict>")
+ }
+ if string(tag) == "</dict>" {
+ break
+ }
+ if string(tag) != "<key>" {
+ return nil, fmt.Errorf("unexpected tag %s inside <dict>", tag)
+ }
+ var body []byte
+ body, tag, data = next(data)
+ if len(tag) == 0 {
+ return nil, fmt.Errorf("eof inside <dict>")
+ }
+ if string(tag) != "</key>" {
+ return nil, fmt.Errorf("unexpected tag %s inside <dict>", tag)
+ }
+ name := string(body)
+ var i int
+ for i = 0; i < t.NumField(); i++ {
+ f := t.Field(i)
+ if f.Name == name || f.Tag.Get("plist") == name {
+ data, err = unmarshalValue(data, v.Field(i))
+ continue Dict
+ }
+ }
+ data, err = skipValue(data)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return data, nil
+
+ case "<array>":
+ t := v.Type()
+ if v.Kind() != reflect.Slice {
+ return nil, fmt.Errorf("cannot unmarshal <array> into non-slice %s", v.Type())
+ }
+ for {
+ _, tag, rest := next(data)
+ if len(tag) == 0 {
+ return nil, fmt.Errorf("eof inside <array>")
+ }
+ if string(tag) == "</array>" {
+ data = rest
+ break
+ }
+ elem := reflect.New(t.Elem()).Elem()
+ data, err = unmarshalValue(data, elem)
+ if err != nil {
+ return nil, err
+ }
+ v.Set(reflect.Append(v, elem))
+ }
+ return data, nil
+
+ case "<string>":
+ if v.Kind() != reflect.String {
+ return nil, fmt.Errorf("cannot unmarshal <string> into non-string %s", v.Type())
+ }
+ body, etag, data := next(data)
+ if len(etag) == 0 {
+ return nil, fmt.Errorf("eof inside <string>")
+ }
+ if string(etag) != "</string>" {
+ return nil, fmt.Errorf("expected </string> but got %s", etag)
+ }
+ v.SetString(string(body)) // TODO: unescape
+ return data, nil
+
+ case "<integer>":
+ if v.Kind() != reflect.Int {
+ return nil, fmt.Errorf("cannot unmarshal <integer> into non-int %s", v.Type())
+ }
+ body, etag, data := next(data)
+ if len(etag) == 0 {
+ return nil, fmt.Errorf("eof inside <integer>")
+ }
+ if string(etag) != "</integer>" {
+ return nil, fmt.Errorf("expected </integer> but got %s", etag)
+ }
+ i, err := strconv.Atoi(string(body))
+ if err != nil {
+ return nil, fmt.Errorf("non-integer in <integer> tag: %s", body)
+ }
+ v.SetInt(int64(i))
+ return data, nil
+ }
+ return nil, fmt.Errorf("unexpected tag %s", tag)
+}
+
+func skipValue(data []byte) (rest []byte, err error) {
+ n := 0
+ for {
+ var tag []byte
+ _, tag, data = next(data)
+ if len(tag) == 0 {
+ return nil, fmt.Errorf("unexpected eof")
+ }
+ if tag[1] == '/' {
+ if n == 0 {
+ return nil, fmt.Errorf("unexpected closing tag")
+ }
+ n--
+ if n == 0 {
+ break
+ }
+ } else {
+ n++
+ }
+ }
+ return data, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/plist/plist_test.go b/vendor/github.com/mattermost/rsc/plist/plist_test.go
new file mode 100644
index 000000000..42f496c67
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/plist/plist_test.go
@@ -0,0 +1,110 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package plist
+
+import (
+ "reflect"
+ "testing"
+)
+
+var thePlist = `<plist version="1.0">
+ <dict>
+ <key>BucketUUID</key>
+ <string>C218A47D-DAFB-4476-9C67-597E556D7D8A</string>
+ <key>BucketName</key>
+ <string>rsc</string>
+ <key>ComputerUUID</key>
+ <string>E7859547-BB9C-41C0-871E-858A0526BAE7</string>
+ <key>LocalPath</key>
+ <string>/Users/rsc</string>
+ <key>LocalMountPoint</key>
+ <string>/Users</string>
+ <key>IgnoredRelativePaths</key>
+ <array>
+ <string>/.Trash</string>
+ <string>/go/pkg</string>
+ <string>/go1/pkg</string>
+ <string>/Library/Caches</string>
+ </array>
+ <key>Excludes</key>
+ <dict>
+ <key>excludes</key>
+ <array>
+ <dict>
+ <key>type</key>
+ <integer>2</integer>
+ <key>text</key>
+ <string>.unison.</string>
+ </dict>
+ </array>
+ </dict>
+ </dict>
+</plist>
+`
+
+var plistTests = []struct {
+ in string
+ out interface{}
+}{
+ {
+ thePlist,
+ &MyStruct{
+ BucketUUID: "C218A47D-DAFB-4476-9C67-597E556D7D8A",
+ BucketName: "rsc",
+ ComputerUUID: "E7859547-BB9C-41C0-871E-858A0526BAE7",
+ LocalPath: "/Users/rsc",
+ LocalMountPoint: "/Users",
+ IgnoredRelativePaths: []string{
+ "/.Trash",
+ "/go/pkg",
+ "/go1/pkg",
+ "/Library/Caches",
+ },
+ Excludes: Exclude1{
+ Excludes: []Exclude2{
+ {Type: 2,
+ Text: ".unison.",
+ },
+ },
+ },
+ },
+ },
+ {
+ thePlist,
+ &struct{}{},
+ },
+}
+
+type MyStruct struct {
+ BucketUUID string
+ BucketName string
+ ComputerUUID string
+ LocalPath string
+ LocalMountPoint string
+ IgnoredRelativePaths []string
+ Excludes Exclude1
+}
+
+type Exclude1 struct {
+ Excludes []Exclude2 `plist:"excludes"`
+}
+
+type Exclude2 struct {
+ Type int `plist:"type"`
+ Text string `plist:"text"`
+}
+
+func TestUnmarshal(t *testing.T) {
+ for _, tt := range plistTests {
+ v := reflect.New(reflect.ValueOf(tt.out).Type().Elem()).Interface()
+ if err := Unmarshal([]byte(tt.in), v); err != nil {
+ t.Errorf("%s", err)
+ continue
+ }
+ if !reflect.DeepEqual(tt.out, v) {
+ t.Errorf("unmarshal not equal")
+ }
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/qr/coding/qr_test.go b/vendor/github.com/mattermost/rsc/qr/coding/qr_test.go
new file mode 100644
index 000000000..b8199bb51
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/qr/coding/qr_test.go
@@ -0,0 +1,133 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package coding
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/mattermost/rsc/gf256"
+ "github.com/mattermost/rsc/qr/libqrencode"
+)
+
+func test(t *testing.T, v Version, l Level, text ...Encoding) bool {
+ s := ""
+ ty := libqrencode.EightBit
+ switch x := text[0].(type) {
+ case String:
+ s = string(x)
+ case Alpha:
+ s = string(x)
+ ty = libqrencode.Alphanumeric
+ case Num:
+ s = string(x)
+ ty = libqrencode.Numeric
+ }
+ key, err := libqrencode.Encode(libqrencode.Version(v), libqrencode.Level(l), ty, s)
+ if err != nil {
+ t.Errorf("libqrencode.Encode(%v, %v, %d, %#q): %v", v, l, ty, s, err)
+ return false
+ }
+ mask := (^key.Pixel[8][2]&1)<<2 | (key.Pixel[8][3]&1)<<1 | (^key.Pixel[8][4] & 1)
+ p, err := NewPlan(v, l, Mask(mask))
+ if err != nil {
+ t.Errorf("NewPlan(%v, L, %d): %v", v, err, mask)
+ return false
+ }
+ if len(p.Pixel) != len(key.Pixel) {
+ t.Errorf("%v: NewPlan uses %dx%d, libqrencode uses %dx%d", v, len(p.Pixel), len(p.Pixel), len(key.Pixel), len(key.Pixel))
+ return false
+ }
+ c, err := p.Encode(text...)
+ if err != nil {
+ t.Errorf("Encode: %v", err)
+ return false
+ }
+ badpix := 0
+Pixel:
+ for y, prow := range p.Pixel {
+ for x, pix := range prow {
+ pix &^= Black
+ if c.Black(x, y) {
+ pix |= Black
+ }
+
+ keypix := key.Pixel[y][x]
+ want := Pixel(0)
+ switch {
+ case keypix&libqrencode.Finder != 0:
+ want = Position.Pixel()
+ case keypix&libqrencode.Alignment != 0:
+ want = Alignment.Pixel()
+ case keypix&libqrencode.Timing != 0:
+ want = Timing.Pixel()
+ case keypix&libqrencode.Format != 0:
+ want = Format.Pixel()
+ want |= OffsetPixel(pix.Offset()) // sic
+ want |= pix & Invert
+ case keypix&libqrencode.PVersion != 0:
+ want = PVersion.Pixel()
+ case keypix&libqrencode.DataECC != 0:
+ if pix.Role() == Check || pix.Role() == Extra {
+ want = pix.Role().Pixel()
+ } else {
+ want = Data.Pixel()
+ }
+ want |= OffsetPixel(pix.Offset())
+ want |= pix & Invert
+ default:
+ want = Unused.Pixel()
+ }
+ if keypix&libqrencode.Black != 0 {
+ want |= Black
+ }
+ if pix != want {
+ t.Errorf("%v/%v: Pixel[%d][%d] = %v, want %v %#x", v, mask, y, x, pix, want, keypix)
+ if badpix++; badpix >= 100 {
+ t.Errorf("stopping after %d bad pixels", badpix)
+ break Pixel
+ }
+ }
+ }
+ }
+ return badpix == 0
+}
+
+var input = []Encoding{
+ String("hello"),
+ Num("1"),
+ Num("12"),
+ Num("123"),
+ Alpha("AB"),
+ Alpha("ABC"),
+}
+
+func TestVersion(t *testing.T) {
+ badvers := 0
+Version:
+ for v := Version(1); v <= 40; v++ {
+ for l := L; l <= H; l++ {
+ for _, in := range input {
+ if !test(t, v, l, in) {
+ if badvers++; badvers >= 10 {
+ t.Errorf("stopping after %d bad versions", badvers)
+ break Version
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestEncode(t *testing.T) {
+ data := []byte{0x10, 0x20, 0x0c, 0x56, 0x61, 0x80, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11, 0xec, 0x11}
+ check := []byte{0xa5, 0x24, 0xd4, 0xc1, 0xed, 0x36, 0xc7, 0x87, 0x2c, 0x55}
+ rs := gf256.NewRSEncoder(Field, len(check))
+ out := make([]byte, len(check))
+ rs.ECC(data, out)
+ if !bytes.Equal(out, check) {
+ t.Errorf("have %x want %x", out, check)
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/qr/libqrencode/Makefile b/vendor/github.com/mattermost/rsc/qr/libqrencode/Makefile
new file mode 100644
index 000000000..4c9591462
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/qr/libqrencode/Makefile
@@ -0,0 +1,4 @@
+include $(GOROOT)/src/Make.inc
+TARG=rsc.googlecode.com/hg/qr/libqrencode
+CGOFILES=qrencode.go
+include $(GOROOT)/src/Make.pkg
diff --git a/vendor/github.com/mattermost/rsc/qr/libqrencode/qrencode.go b/vendor/github.com/mattermost/rsc/qr/libqrencode/qrencode.go
new file mode 100644
index 000000000..f4ce3ffb6
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/qr/libqrencode/qrencode.go
@@ -0,0 +1,149 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package libqrencode wraps the C libqrencode library.
+// The qr package (in this package's parent directory)
+// does not use any C wrapping. This code is here only
+// for use during that package's tests.
+package libqrencode
+
+/*
+#cgo LDFLAGS: -lqrencode
+#include <qrencode.h>
+*/
+import "C"
+
+import (
+ "fmt"
+ "image"
+ "image/color"
+ "unsafe"
+)
+
+type Version int
+
+type Mode int
+
+const (
+ Numeric Mode = C.QR_MODE_NUM
+ Alphanumeric Mode = C.QR_MODE_AN
+ EightBit Mode = C.QR_MODE_8
+)
+
+type Level int
+
+const (
+ L Level = C.QR_ECLEVEL_L
+ M Level = C.QR_ECLEVEL_M
+ Q Level = C.QR_ECLEVEL_Q
+ H Level = C.QR_ECLEVEL_H
+)
+
+type Pixel int
+
+const (
+ Black Pixel = 1 << iota
+ DataECC
+ Format
+ PVersion
+ Timing
+ Alignment
+ Finder
+ NonData
+)
+
+type Code struct {
+ Version int
+ Width int
+ Pixel [][]Pixel
+ Scale int
+}
+
+func (*Code) ColorModel() color.Model {
+ return color.RGBAModel
+}
+
+func (c *Code) Bounds() image.Rectangle {
+ d := (c.Width + 8) * c.Scale
+ return image.Rect(0, 0, d, d)
+}
+
+var (
+ white color.Color = color.RGBA{0xFF, 0xFF, 0xFF, 0xFF}
+ black color.Color = color.RGBA{0x00, 0x00, 0x00, 0xFF}
+ blue color.Color = color.RGBA{0x00, 0x00, 0x80, 0xFF}
+ red color.Color = color.RGBA{0xFF, 0x40, 0x40, 0xFF}
+ yellow color.Color = color.RGBA{0xFF, 0xFF, 0x00, 0xFF}
+ gray color.Color = color.RGBA{0x80, 0x80, 0x80, 0xFF}
+ green color.Color = color.RGBA{0x22, 0x8B, 0x22, 0xFF}
+)
+
+func (c *Code) At(x, y int) color.Color {
+ x = x/c.Scale - 4
+ y = y/c.Scale - 4
+ if 0 <= x && x < c.Width && 0 <= y && y < c.Width {
+ switch p := c.Pixel[y][x]; {
+ case p&Black == 0:
+ // nothing
+ case p&DataECC != 0:
+ return black
+ case p&Format != 0:
+ return blue
+ case p&PVersion != 0:
+ return red
+ case p&Timing != 0:
+ return yellow
+ case p&Alignment != 0:
+ return gray
+ case p&Finder != 0:
+ return green
+ }
+ }
+ return white
+}
+
+type Chunk struct {
+ Mode Mode
+ Text string
+}
+
+func Encode(version Version, level Level, mode Mode, text string) (*Code, error) {
+ return EncodeChunk(version, level, Chunk{mode, text})
+}
+
+func EncodeChunk(version Version, level Level, chunk ...Chunk) (*Code, error) {
+ qi, err := C.QRinput_new2(C.int(version), C.QRecLevel(level))
+ if qi == nil {
+ return nil, fmt.Errorf("QRinput_new2: %v", err)
+ }
+ defer C.QRinput_free(qi)
+ for _, ch := range chunk {
+ data := []byte(ch.Text)
+ n, err := C.QRinput_append(qi, C.QRencodeMode(ch.Mode), C.int(len(data)), (*C.uchar)(&data[0]))
+ if n < 0 {
+ return nil, fmt.Errorf("QRinput_append %q: %v", data, err)
+ }
+ }
+
+ qc, err := C.QRcode_encodeInput(qi)
+ if qc == nil {
+ return nil, fmt.Errorf("QRinput_encodeInput: %v", err)
+ }
+
+ c := &Code{
+ Version: int(qc.version),
+ Width: int(qc.width),
+ Scale: 16,
+ }
+ pix := make([]Pixel, c.Width*c.Width)
+ cdat := (*[1000 * 1000]byte)(unsafe.Pointer(qc.data))[:len(pix)]
+ for i := range pix {
+ pix[i] = Pixel(cdat[i])
+ }
+ c.Pixel = make([][]Pixel, c.Width)
+ for i := range c.Pixel {
+ c.Pixel[i] = pix[i*c.Width : (i+1)*c.Width]
+ }
+ return c, nil
+}
diff --git a/vendor/github.com/mattermost/rsc/qr/png_test.go b/vendor/github.com/mattermost/rsc/qr/png_test.go
new file mode 100644
index 000000000..27a622924
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/qr/png_test.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package qr
+
+import (
+ "bytes"
+ "image"
+ "image/color"
+ "image/png"
+ "io/ioutil"
+ "testing"
+)
+
+func TestPNG(t *testing.T) {
+ c, err := Encode("hello, world", L)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pngdat := c.PNG()
+ if true {
+ ioutil.WriteFile("x.png", pngdat, 0666)
+ }
+ m, err := png.Decode(bytes.NewBuffer(pngdat))
+ if err != nil {
+ t.Fatal(err)
+ }
+ gm := m.(*image.Gray)
+
+ scale := c.Scale
+ siz := c.Size
+ nbad := 0
+ for y := 0; y < scale*(8+siz); y++ {
+ for x := 0; x < scale*(8+siz); x++ {
+ v := byte(255)
+ if c.Black(x/scale-4, y/scale-4) {
+ v = 0
+ }
+ if gv := gm.At(x, y).(color.Gray).Y; gv != v {
+ t.Errorf("%d,%d = %d, want %d", x, y, gv, v)
+ if nbad++; nbad >= 20 {
+ t.Fatalf("too many bad pixels")
+ }
+ }
+ }
+ }
+}
+
+func BenchmarkPNG(b *testing.B) {
+ c, err := Encode("0123456789012345678901234567890123456789", L)
+ if err != nil {
+ panic(err)
+ }
+ var bytes []byte
+ for i := 0; i < b.N; i++ {
+ bytes = c.PNG()
+ }
+ b.SetBytes(int64(len(bytes)))
+}
+
+func BenchmarkImagePNG(b *testing.B) {
+ c, err := Encode("0123456789012345678901234567890123456789", L)
+ if err != nil {
+ panic(err)
+ }
+ var buf bytes.Buffer
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ png.Encode(&buf, c.Image())
+ }
+ b.SetBytes(int64(buf.Len()))
+}
diff --git a/vendor/github.com/mattermost/rsc/qr/web/pic.go b/vendor/github.com/mattermost/rsc/qr/web/pic.go
new file mode 100644
index 000000000..6baef94d2
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/qr/web/pic.go
@@ -0,0 +1,506 @@
+package web
+
+import (
+ "bytes"
+ "fmt"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "net/http"
+ "strconv"
+ "strings"
+
+ "code.google.com/p/freetype-go/freetype"
+ "github.com/mattermost/rsc/appfs/fs"
+ "github.com/mattermost/rsc/qr"
+ "github.com/mattermost/rsc/qr/coding"
+)
+
+func makeImage(req *http.Request, caption, font string, pt, size, border, scale int, f func(x, y int) uint32) *image.RGBA {
+ d := (size + 2*border) * scale
+ csize := 0
+ if caption != "" {
+ if pt == 0 {
+ pt = 11
+ }
+ csize = pt * 2
+ }
+ c := image.NewRGBA(image.Rect(0, 0, d, d+csize))
+
+ // white
+ u := &image.Uniform{C: color.White}
+ draw.Draw(c, c.Bounds(), u, image.ZP, draw.Src)
+
+ for y := 0; y < size; y++ {
+ for x := 0; x < size; x++ {
+ r := image.Rect((x+border)*scale, (y+border)*scale, (x+border+1)*scale, (y+border+1)*scale)
+ rgba := f(x, y)
+ u.C = color.RGBA{byte(rgba >> 24), byte(rgba >> 16), byte(rgba >> 8), byte(rgba)}
+ draw.Draw(c, r, u, image.ZP, draw.Src)
+ }
+ }
+
+ if csize != 0 {
+ if font == "" {
+ font = "data/luxisr.ttf"
+ }
+ ctxt := fs.NewContext(req)
+ dat, _, err := ctxt.Read(font)
+ if err != nil {
+ panic(err)
+ }
+ tfont, err := freetype.ParseFont(dat)
+ if err != nil {
+ panic(err)
+ }
+ ft := freetype.NewContext()
+ ft.SetDst(c)
+ ft.SetDPI(100)
+ ft.SetFont(tfont)
+ ft.SetFontSize(float64(pt))
+ ft.SetSrc(image.NewUniform(color.Black))
+ ft.SetClip(image.Rect(0, 0, 0, 0))
+ wid, err := ft.DrawString(caption, freetype.Pt(0, 0))
+ if err != nil {
+ panic(err)
+ }
+ p := freetype.Pt(d, d+3*pt/2)
+ p.X -= wid.X
+ p.X /= 2
+ ft.SetClip(c.Bounds())
+ ft.DrawString(caption, p)
+ }
+
+ return c
+}
+
+func makeFrame(req *http.Request, font string, pt, vers, l, scale, dots int) image.Image {
+ lev := coding.Level(l)
+ p, err := coding.NewPlan(coding.Version(vers), lev, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ nd := p.DataBytes / p.Blocks
+ nc := p.CheckBytes / p.Blocks
+ extra := p.DataBytes - nd*p.Blocks
+
+ cap := fmt.Sprintf("QR v%d, %s", vers, lev)
+ if dots > 0 {
+ cap = fmt.Sprintf("QR v%d order, from bottom right", vers)
+ }
+ m := makeImage(req, cap, font, pt, len(p.Pixel), 0, scale, func(x, y int) uint32 {
+ pix := p.Pixel[y][x]
+ switch pix.Role() {
+ case coding.Data:
+ if dots > 0 {
+ return 0xffffffff
+ }
+ off := int(pix.Offset() / 8)
+ nd := nd
+ var i int
+ for i = 0; i < p.Blocks; i++ {
+ if i == extra {
+ nd++
+ }
+ if off < nd {
+ break
+ }
+ off -= nd
+ }
+ return blockColors[i%len(blockColors)]
+ case coding.Check:
+ if dots > 0 {
+ return 0xffffffff
+ }
+ i := (int(pix.Offset()/8) - p.DataBytes) / nc
+ return dark(blockColors[i%len(blockColors)])
+ }
+ if pix&coding.Black != 0 {
+ return 0x000000ff
+ }
+ return 0xffffffff
+ })
+
+ if dots > 0 {
+ b := m.Bounds()
+ for y := 0; y <= len(p.Pixel); y++ {
+ for x := 0; x < b.Dx(); x++ {
+ m.SetRGBA(x, y*scale-(y/len(p.Pixel)), color.RGBA{127, 127, 127, 255})
+ }
+ }
+ for x := 0; x <= len(p.Pixel); x++ {
+ for y := 0; y < b.Dx(); y++ {
+ m.SetRGBA(x*scale-(x/len(p.Pixel)), y, color.RGBA{127, 127, 127, 255})
+ }
+ }
+ order := make([]image.Point, (p.DataBytes+p.CheckBytes)*8+1)
+ for y, row := range p.Pixel {
+ for x, pix := range row {
+ if r := pix.Role(); r != coding.Data && r != coding.Check {
+ continue
+ }
+ // draw.Draw(m, m.Bounds().Add(image.Pt(x*scale, y*scale)), dot, image.ZP, draw.Over)
+ order[pix.Offset()] = image.Point{x*scale + scale/2, y*scale + scale/2}
+ }
+ }
+
+ for mode := 0; mode < 2; mode++ {
+ for i, p := range order {
+ q := order[i+1]
+ if q.X == 0 {
+ break
+ }
+ line(m, p, q, mode)
+ }
+ }
+ }
+ return m
+}
+
+func line(m *image.RGBA, p, q image.Point, mode int) {
+ x := 0
+ y := 0
+ dx := q.X - p.X
+ dy := q.Y - p.Y
+ xsign := +1
+ ysign := +1
+ if dx < 0 {
+ xsign = -1
+ dx = -dx
+ }
+ if dy < 0 {
+ ysign = -1
+ dy = -dy
+ }
+ pt := func() {
+ switch mode {
+ case 0:
+ for dx := -2; dx <= 2; dx++ {
+ for dy := -2; dy <= 2; dy++ {
+ if dy*dx <= -4 || dy*dx >= 4 {
+ continue
+ }
+ m.SetRGBA(p.X+x*xsign+dx, p.Y+y*ysign+dy, color.RGBA{255, 192, 192, 255})
+ }
+ }
+
+ case 1:
+ m.SetRGBA(p.X+x*xsign, p.Y+y*ysign, color.RGBA{128, 0, 0, 255})
+ }
+ }
+ if dx > dy {
+ for x < dx || y < dy {
+ pt()
+ x++
+ if float64(x)*float64(dy)/float64(dx)-float64(y) > 0.5 {
+ y++
+ }
+ }
+ } else {
+ for x < dx || y < dy {
+ pt()
+ y++
+ if float64(y)*float64(dx)/float64(dy)-float64(x) > 0.5 {
+ x++
+ }
+ }
+ }
+ pt()
+}
+
+func pngEncode(c image.Image) []byte {
+ var b bytes.Buffer
+ png.Encode(&b, c)
+ return b.Bytes()
+}
+
+// Frame handles a request for a single QR frame.
+func Frame(w http.ResponseWriter, req *http.Request) {
+ arg := func(s string) int { x, _ := strconv.Atoi(req.FormValue(s)); return x }
+ v := arg("v")
+ scale := arg("scale")
+ if scale == 0 {
+ scale = 8
+ }
+
+ w.Header().Set("Cache-Control", "public, max-age=3600")
+ w.Write(pngEncode(makeFrame(req, req.FormValue("font"), arg("pt"), v, arg("l"), scale, arg("dots"))))
+}
+
+// Frames handles a request for multiple QR frames.
+func Frames(w http.ResponseWriter, req *http.Request) {
+ vs := strings.Split(req.FormValue("v"), ",")
+
+ arg := func(s string) int { x, _ := strconv.Atoi(req.FormValue(s)); return x }
+ scale := arg("scale")
+ if scale == 0 {
+ scale = 8
+ }
+ font := req.FormValue("font")
+ pt := arg("pt")
+ dots := arg("dots")
+
+ var images []image.Image
+ l := arg("l")
+ for _, v := range vs {
+ l := l
+ if i := strings.Index(v, "."); i >= 0 {
+ l, _ = strconv.Atoi(v[i+1:])
+ v = v[:i]
+ }
+ vv, _ := strconv.Atoi(v)
+ images = append(images, makeFrame(req, font, pt, vv, l, scale, dots))
+ }
+
+ b := images[len(images)-1].Bounds()
+
+ dx := arg("dx")
+ if dx == 0 {
+ dx = b.Dx()
+ }
+ x, y := 0, 0
+ xmax := 0
+ sep := arg("sep")
+ if sep == 0 {
+ sep = 10
+ }
+ var points []image.Point
+ for i, m := range images {
+ if x > 0 {
+ x += sep
+ }
+ if x > 0 && x+m.Bounds().Dx() > dx {
+ y += sep + images[i-1].Bounds().Dy()
+ x = 0
+ }
+ points = append(points, image.Point{x, y})
+ x += m.Bounds().Dx()
+ if x > xmax {
+ xmax = x
+ }
+
+ }
+
+ c := image.NewRGBA(image.Rect(0, 0, xmax, y+b.Dy()))
+ for i, m := range images {
+ draw.Draw(c, c.Bounds().Add(points[i]), m, image.ZP, draw.Src)
+ }
+
+ w.Header().Set("Cache-Control", "public, max-age=3600")
+ w.Write(pngEncode(c))
+}
+
+// Mask handles a request for a single QR mask.
+func Mask(w http.ResponseWriter, req *http.Request) {
+ arg := func(s string) int { x, _ := strconv.Atoi(req.FormValue(s)); return x }
+ v := arg("v")
+ m := arg("m")
+ scale := arg("scale")
+ if scale == 0 {
+ scale = 8
+ }
+
+ w.Header().Set("Cache-Control", "public, max-age=3600")
+ w.Write(pngEncode(makeMask(req, req.FormValue("font"), arg("pt"), v, m, scale)))
+}
+
+// Masks handles a request for multiple QR masks.
+func Masks(w http.ResponseWriter, req *http.Request) {
+ arg := func(s string) int { x, _ := strconv.Atoi(req.FormValue(s)); return x }
+ v := arg("v")
+ scale := arg("scale")
+ if scale == 0 {
+ scale = 8
+ }
+ font := req.FormValue("font")
+ pt := arg("pt")
+ var mm []image.Image
+ for m := 0; m < 8; m++ {
+ mm = append(mm, makeMask(req, font, pt, v, m, scale))
+ }
+ dx := mm[0].Bounds().Dx()
+ dy := mm[0].Bounds().Dy()
+
+ sep := arg("sep")
+ if sep == 0 {
+ sep = 10
+ }
+ c := image.NewRGBA(image.Rect(0, 0, (dx+sep)*4-sep, (dy+sep)*2-sep))
+ for m := 0; m < 8; m++ {
+ x := (m % 4) * (dx + sep)
+ y := (m / 4) * (dy + sep)
+ draw.Draw(c, c.Bounds().Add(image.Pt(x, y)), mm[m], image.ZP, draw.Src)
+ }
+
+ w.Header().Set("Cache-Control", "public, max-age=3600")
+ w.Write(pngEncode(c))
+}
+
+var maskName = []string{
+ "(x+y) % 2",
+ "y % 2",
+ "x % 3",
+ "(x+y) % 3",
+ "(y/2 + x/3) % 2",
+ "xy%2 + xy%3",
+ "(xy%2 + xy%3) % 2",
+ "(xy%3 + (x+y)%2) % 2",
+}
+
+func makeMask(req *http.Request, font string, pt int, vers, mask, scale int) image.Image {
+ p, err := coding.NewPlan(coding.Version(vers), coding.L, coding.Mask(mask))
+ if err != nil {
+ panic(err)
+ }
+ m := makeImage(req, maskName[mask], font, pt, len(p.Pixel), 0, scale, func(x, y int) uint32 {
+ pix := p.Pixel[y][x]
+ switch pix.Role() {
+ case coding.Data, coding.Check:
+ if pix&coding.Invert != 0 {
+ return 0x000000ff
+ }
+ }
+ return 0xffffffff
+ })
+ return m
+}
+
+var blockColors = []uint32{
+ 0x7777ffff,
+ 0xffff77ff,
+ 0xff7777ff,
+ 0x77ffffff,
+ 0x1e90ffff,
+ 0xffffe0ff,
+ 0x8b6969ff,
+ 0x77ff77ff,
+ 0x9b30ffff,
+ 0x00bfffff,
+ 0x90e890ff,
+ 0xfff68fff,
+ 0xffec8bff,
+ 0xffa07aff,
+ 0xffa54fff,
+ 0xeee8aaff,
+ 0x98fb98ff,
+ 0xbfbfbfff,
+ 0x54ff9fff,
+ 0xffaeb9ff,
+ 0xb23aeeff,
+ 0xbbffffff,
+ 0x7fffd4ff,
+ 0xff7a7aff,
+ 0x00007fff,
+}
+
+func dark(x uint32) uint32 {
+ r, g, b, a := byte(x>>24), byte(x>>16), byte(x>>8), byte(x)
+ r = r/2 + r/4
+ g = g/2 + g/4
+ b = b/2 + b/4
+ return uint32(r)<<24 | uint32(g)<<16 | uint32(b)<<8 | uint32(a)
+}
+
+func clamp(x int) byte {
+ if x < 0 {
+ return 0
+ }
+ if x > 255 {
+ return 255
+ }
+ return byte(x)
+}
+
+func max(x, y int) int {
+ if x > y {
+ return x
+ }
+ return y
+}
+
+// Arrow handles a request for an arrow pointing in a given direction.
+func Arrow(w http.ResponseWriter, req *http.Request) {
+ arg := func(s string) int { x, _ := strconv.Atoi(req.FormValue(s)); return x }
+ dir := arg("dir")
+ size := arg("size")
+ if size == 0 {
+ size = 50
+ }
+ del := size / 10
+
+ m := image.NewRGBA(image.Rect(0, 0, size, size))
+
+ if dir == 4 {
+ draw.Draw(m, m.Bounds(), image.Black, image.ZP, draw.Src)
+ draw.Draw(m, image.Rect(5, 5, size-5, size-5), image.White, image.ZP, draw.Src)
+ }
+
+ pt := func(x, y int, c color.RGBA) {
+ switch dir {
+ case 0:
+ m.SetRGBA(x, y, c)
+ case 1:
+ m.SetRGBA(y, size-1-x, c)
+ case 2:
+ m.SetRGBA(size-1-x, size-1-y, c)
+ case 3:
+ m.SetRGBA(size-1-y, x, c)
+ }
+ }
+
+ for y := 0; y < size/2; y++ {
+ for x := 0; x < del && x < y; x++ {
+ pt(x, y, color.RGBA{0, 0, 0, 255})
+ }
+ for x := del; x < y-del; x++ {
+ pt(x, y, color.RGBA{128, 128, 255, 255})
+ }
+ for x := max(y-del, 0); x <= y; x++ {
+ pt(x, y, color.RGBA{0, 0, 0, 255})
+ }
+ }
+ for y := size / 2; y < size; y++ {
+ for x := 0; x < del && x < size-1-y; x++ {
+ pt(x, y, color.RGBA{0, 0, 0, 255})
+ }
+ for x := del; x < size-1-y-del; x++ {
+ pt(x, y, color.RGBA{128, 128, 192, 255})
+ }
+ for x := max(size-1-y-del, 0); x <= size-1-y; x++ {
+ pt(x, y, color.RGBA{0, 0, 0, 255})
+ }
+ }
+
+ w.Header().Set("Cache-Control", "public, max-age=3600")
+ w.Write(pngEncode(m))
+}
+
+// Encode encodes a string using the given version, level, and mask.
+func Encode(w http.ResponseWriter, req *http.Request) {
+ val := func(s string) int {
+ v, _ := strconv.Atoi(req.FormValue(s))
+ return v
+ }
+
+ l := coding.Level(val("l"))
+ v := coding.Version(val("v"))
+ enc := coding.String(req.FormValue("t"))
+ m := coding.Mask(val("m"))
+
+ p, err := coding.NewPlan(v, l, m)
+ if err != nil {
+ panic(err)
+ }
+ cc, err := p.Encode(enc)
+ if err != nil {
+ panic(err)
+ }
+
+ c := &qr.Code{Bitmap: cc.Bitmap, Size: cc.Size, Stride: cc.Stride, Scale: 8}
+ w.Header().Set("Content-Type", "image/png")
+ w.Header().Set("Cache-Control", "public, max-age=3600")
+ w.Write(c.PNG())
+}
+
diff --git a/vendor/github.com/mattermost/rsc/qr/web/play.go b/vendor/github.com/mattermost/rsc/qr/web/play.go
new file mode 100644
index 000000000..120f50b81
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/qr/web/play.go
@@ -0,0 +1,1118 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+QR data layout
+
+qr/
+ upload/
+ id.png
+ id.fix
+ flag/
+ id
+
+*/
+// TODO: Random seed taken from GET for caching, repeatability.
+// TODO: Flag for abuse button + some kind of dashboard.
+// TODO: +1 button on web page? permalink?
+// TODO: Flag for abuse button on permalinks too?
+// TODO: Make the page prettier.
+// TODO: Cache headers.
+
+package web
+
+import (
+ "bytes"
+ "crypto/md5"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "html/template"
+ "image"
+ "image/color"
+ _ "image/gif"
+ _ "image/jpeg"
+ "image/png"
+ "io"
+ "math/rand"
+ "net/http"
+ "net/url"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+
+ "github.com/mattermost/rsc/appfs/fs"
+ "github.com/mattermost/rsc/gf256"
+ "github.com/mattermost/rsc/qr"
+ "github.com/mattermost/rsc/qr/coding"
+ "github.com/mattermost/rsc/qr/web/resize"
+)
+
+func runTemplate(c *fs.Context, w http.ResponseWriter, name string, data interface{}) {
+ t := template.New("main")
+
+ main, _, err := c.Read(name)
+ if err != nil {
+ panic(err)
+ }
+ style, _, _ := c.Read("style.html")
+ main = append(main, style...)
+ _, err = t.Parse(string(main))
+ if err != nil {
+ panic(err)
+ }
+
+ var buf bytes.Buffer
+ if err := t.Execute(&buf, &data); err != nil {
+ panic(err)
+ }
+ w.Write(buf.Bytes())
+}
+
+func isImgName(s string) bool {
+ if len(s) != 32 {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if '0' <= s[i] && s[i] <= '9' || 'a' <= s[i] && s[i] <= 'f' {
+ continue
+ }
+ return false
+ }
+ return true
+}
+
+func isTagName(s string) bool {
+ if len(s) != 16 {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if '0' <= s[i] && s[i] <= '9' || 'a' <= s[i] && s[i] <= 'f' {
+ continue
+ }
+ return false
+ }
+ return true
+}
+
+// Draw is the handler for drawing a QR code.
+func Draw(w http.ResponseWriter, req *http.Request) {
+ ctxt := fs.NewContext(req)
+
+ url := req.FormValue("url")
+ if url == "" {
+ url = "http://swtch.com/qr"
+ }
+ if req.FormValue("upload") == "1" {
+ upload(w, req, url)
+ return
+ }
+
+ t0 := time.Now()
+ img := req.FormValue("i")
+ if !isImgName(img) {
+ img = "pjw"
+ }
+ if req.FormValue("show") == "png" {
+ i := loadSize(ctxt, img, 48)
+ var buf bytes.Buffer
+ png.Encode(&buf, i)
+ w.Write(buf.Bytes())
+ return
+ }
+ if req.FormValue("flag") == "1" {
+ flag(w, req, img, ctxt)
+ return
+ }
+ if req.FormValue("x") == "" {
+ var data = struct {
+ Name string
+ URL string
+ }{
+ Name: img,
+ URL: url,
+ }
+ runTemplate(ctxt, w, "qr/main.html", &data)
+ return
+ }
+
+ arg := func(s string) int { x, _ := strconv.Atoi(req.FormValue(s)); return x }
+ targ := makeTarg(ctxt, img, 17+4*arg("v")+arg("z"))
+
+ m := &Image{
+ Name: img,
+ Dx: arg("x"),
+ Dy: arg("y"),
+ URL: req.FormValue("u"),
+ Version: arg("v"),
+ Mask: arg("m"),
+ RandControl: arg("r") > 0,
+ Dither: arg("i") > 0,
+ OnlyDataBits: arg("d") > 0,
+ SaveControl: arg("c") > 0,
+ Scale: arg("scale"),
+ Target: targ,
+ Seed: int64(arg("s")),
+ Rotation: arg("o"),
+ Size: arg("z"),
+ }
+ if m.Version > 8 {
+ m.Version = 8
+ }
+
+ if m.Scale == 0 {
+ if arg("l") > 1 {
+ m.Scale = 8
+ } else {
+ m.Scale = 4
+ }
+ }
+ if m.Version >= 12 && m.Scale >= 4 {
+ m.Scale /= 2
+ }
+
+ if arg("l") == 1 {
+ data, err := json.Marshal(m)
+ if err != nil {
+ panic(err)
+ }
+ h := md5.New()
+ h.Write(data)
+ tag := fmt.Sprintf("%x", h.Sum(nil))[:16]
+ if err := ctxt.Write("qrsave/"+tag, data); err != nil {
+ panic(err)
+ }
+ http.Redirect(w, req, "/qr/show/" + tag, http.StatusTemporaryRedirect)
+ return
+ }
+
+ if err := m.Encode(req); err != nil {
+ fmt.Fprintf(w, "%s\n", err)
+ return
+ }
+
+ var dat []byte
+ switch {
+ case m.SaveControl:
+ dat = m.Control
+ default:
+ dat = m.Code.PNG()
+ }
+
+ if arg("l") > 0 {
+ w.Header().Set("Content-Type", "image/png")
+ w.Write(dat)
+ return
+ }
+
+ w.Header().Set("Content-Type", "text/html; charset=utf-8")
+ fmt.Fprint(w, "<center><img src=\"data:image/png;base64,")
+ io.WriteString(w, base64.StdEncoding.EncodeToString(dat))
+ fmt.Fprint(w, "\" /><br>")
+ fmt.Fprintf(w, "<form method=\"POST\" action=\"%s&l=1\"><input type=\"submit\" value=\"Save this QR code\"></form>\n", m.Link())
+ fmt.Fprintf(w, "</center>\n")
+ fmt.Fprintf(w, "<br><center><font size=-1>%v</font></center>\n", time.Now().Sub(t0))
+}
+
+func (m *Image) Small() bool {
+ return 8*(17+4*int(m.Version)) < 512
+}
+
+func (m *Image) Link() string {
+ s := fmt.Sprint
+ b := func(v bool) string {
+ if v {
+ return "1"
+ }
+ return "0"
+ }
+ val := url.Values{
+ "i": {m.Name},
+ "x": {s(m.Dx)},
+ "y": {s(m.Dy)},
+ "z": {s(m.Size)},
+ "u": {m.URL},
+ "v": {s(m.Version)},
+ "m": {s(m.Mask)},
+ "r": {b(m.RandControl)},
+ "t": {b(m.Dither)},
+ "d": {b(m.OnlyDataBits)},
+ "c": {b(m.SaveControl)},
+ "s": {s(m.Seed)},
+ }
+ return "/qr/draw?" + val.Encode()
+}
+
+// Show is the handler for showing a stored QR code.
+func Show(w http.ResponseWriter, req *http.Request) {
+ ctxt := fs.NewContext(req)
+ tag := req.URL.Path[len("/qr/show/"):]
+ png := strings.HasSuffix(tag, ".png")
+ if png {
+ tag = tag[:len(tag)-len(".png")]
+ }
+ if !isTagName(tag) {
+ fmt.Fprintf(w, "Sorry, QR code not found\n")
+ return
+ }
+ if req.FormValue("flag") == "1" {
+ flag(w, req, tag, ctxt)
+ return
+ }
+ data, _, err := ctxt.Read("qrsave/" + tag)
+ if err != nil {
+ fmt.Fprintf(w, "Sorry, QR code not found.\n")
+ return
+ }
+
+ var m Image
+ if err := json.Unmarshal(data, &m); err != nil {
+ panic(err)
+ }
+ m.Tag = tag
+
+ switch req.FormValue("size") {
+ case "big":
+ m.Scale *= 2
+ case "small":
+ m.Scale /= 2
+ }
+
+ if png {
+ if err := m.Encode(req); err != nil {
+ panic(err)
+ return
+ }
+ w.Header().Set("Cache-Control", "public, max-age=3600")
+ w.Write(m.Code.PNG())
+ return
+ }
+
+ w.Header().Set("Cache-Control", "public, max-age=300")
+ runTemplate(ctxt, w, "qr/permalink.html", &m)
+}
+
+func upload(w http.ResponseWriter, req *http.Request, link string) {
+ // Upload of a new image.
+ // Copied from Moustachio demo.
+ f, _, err := req.FormFile("image")
+ if err != nil {
+ fmt.Fprintf(w, "You need to select an image to upload.\n")
+ return
+ }
+ defer f.Close()
+
+ i, _, err := image.Decode(f)
+ if err != nil {
+ panic(err)
+ }
+
+ // Convert image to 128x128 gray+alpha.
+ b := i.Bounds()
+ const max = 128
+ // If it's gigantic, it's more efficient to downsample first
+ // and then resize; resizing will smooth out the roughness.
+ var i1 *image.RGBA
+ if b.Dx() > 4*max || b.Dy() > 4*max {
+ w, h := 2*max, 2*max
+ if b.Dx() > b.Dy() {
+ h = b.Dy() * h / b.Dx()
+ } else {
+ w = b.Dx() * w / b.Dy()
+ }
+ i1 = resize.Resample(i, b, w, h)
+ } else {
+ // "Resample" to same size, just to convert to RGBA.
+ i1 = resize.Resample(i, b, b.Dx(), b.Dy())
+ }
+ b = i1.Bounds()
+
+ // Encode to PNG.
+ dx, dy := 128, 128
+ if b.Dx() > b.Dy() {
+ dy = b.Dy() * dx / b.Dx()
+ } else {
+ dx = b.Dx() * dy / b.Dy()
+ }
+ i128 := resize.ResizeRGBA(i1, i1.Bounds(), dx, dy)
+
+ var buf bytes.Buffer
+ if err := png.Encode(&buf, i128); err != nil {
+ panic(err)
+ }
+
+ h := md5.New()
+ h.Write(buf.Bytes())
+ tag := fmt.Sprintf("%x", h.Sum(nil))[:32]
+
+ ctxt := fs.NewContext(req)
+ if err := ctxt.Write("qr/upload/"+tag+".png", buf.Bytes()); err != nil {
+ panic(err)
+ }
+
+ // Redirect with new image tag.
+ // Redirect to draw with new image tag.
+ http.Redirect(w, req, req.URL.Path+"?"+url.Values{"i": {tag}, "url": {link}}.Encode(), 302)
+}
+
+func flag(w http.ResponseWriter, req *http.Request, img string, ctxt *fs.Context) {
+ if !isImgName(img) && !isTagName(img) {
+ fmt.Fprintf(w, "Invalid image.\n")
+ return
+ }
+ data, _, _ := ctxt.Read("qr/flag/" + img)
+ data = append(data, '!')
+ ctxt.Write("qr/flag/" + img, data)
+
+ fmt.Fprintf(w, "Thank you. The image has been reported.\n")
+}
+
+func loadSize(ctxt *fs.Context, name string, max int) *image.RGBA {
+ data, _, err := ctxt.Read("qr/upload/" + name + ".png")
+ if err != nil {
+ panic(err)
+ }
+ i, _, err := image.Decode(bytes.NewBuffer(data))
+ if err != nil {
+ panic(err)
+ }
+ b := i.Bounds()
+ dx, dy := max, max
+ if b.Dx() > b.Dy() {
+ dy = b.Dy() * dx / b.Dx()
+ } else {
+ dx = b.Dx() * dy / b.Dy()
+ }
+ var irgba *image.RGBA
+ switch i := i.(type) {
+ case *image.RGBA:
+ irgba = resize.ResizeRGBA(i, i.Bounds(), dx, dy)
+ case *image.NRGBA:
+ irgba = resize.ResizeNRGBA(i, i.Bounds(), dx, dy)
+ }
+ return irgba
+}
+
+func makeTarg(ctxt *fs.Context, name string, max int) [][]int {
+ i := loadSize(ctxt, name, max)
+ b := i.Bounds()
+ dx, dy := b.Dx(), b.Dy()
+ targ := make([][]int, dy)
+ arr := make([]int, dx*dy)
+ for y := 0; y < dy; y++ {
+ targ[y], arr = arr[:dx], arr[dx:]
+ row := targ[y]
+ for x := 0; x < dx; x++ {
+ p := i.Pix[y*i.Stride+4*x:]
+ r, g, b, a := p[0], p[1], p[2], p[3]
+ if a == 0 {
+ row[x] = -1
+ } else {
+ row[x] = int((299*uint32(r) + 587*uint32(g) + 114*uint32(b) + 500) / 1000)
+ }
+ }
+ }
+ return targ
+}
+
+type Image struct {
+ Name string
+ Target [][]int
+ Dx int
+ Dy int
+ URL string
+ Tag string
+ Version int
+ Mask int
+ Scale int
+ Rotation int
+ Size int
+
+ // RandControl says to pick the pixels randomly.
+ RandControl bool
+ Seed int64
+
+ // Dither says to dither instead of using threshold pixel layout.
+ Dither bool
+
+ // OnlyDataBits says to use only data bits, not check bits.
+ OnlyDataBits bool
+
+ // Code is the final QR code.
+ Code *qr.Code
+
+ // Control is a PNG showing the pixels that we controlled.
+ // Pixels we don't control are grayed out.
+ SaveControl bool
+ Control []byte
+}
+
+type Pixinfo struct {
+ X int
+ Y int
+ Pix coding.Pixel
+ Targ byte
+ DTarg int
+ Contrast int
+ HardZero bool
+ Block *BitBlock
+ Bit uint
+}
+
+type Pixorder struct {
+ Off int
+ Priority int
+}
+
+type byPriority []Pixorder
+
+func (x byPriority) Len() int { return len(x) }
+func (x byPriority) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byPriority) Less(i, j int) bool { return x[i].Priority > x[j].Priority }
+
+func (m *Image) target(x, y int) (targ byte, contrast int) {
+ tx := x + m.Dx
+ ty := y + m.Dy
+ if ty < 0 || ty >= len(m.Target) || tx < 0 || tx >= len(m.Target[ty]) {
+ return 255, -1
+ }
+
+ v0 := m.Target[ty][tx]
+ if v0 < 0 {
+ return 255, -1
+ }
+ targ = byte(v0)
+
+ n := 0
+ sum := 0
+ sumsq := 0
+ const del = 5
+ for dy := -del; dy <= del; dy++ {
+ for dx := -del; dx <= del; dx++ {
+ if 0 <= ty+dy && ty+dy < len(m.Target) && 0 <= tx+dx && tx+dx < len(m.Target[ty+dy]) {
+ v := m.Target[ty+dy][tx+dx]
+ sum += v
+ sumsq += v * v
+ n++
+ }
+ }
+ }
+
+ avg := sum / n
+ contrast = sumsq/n - avg*avg
+ return
+}
+
+func (m *Image) rotate(p *coding.Plan, rot int) {
+ if rot == 0 {
+ return
+ }
+
+ N := len(p.Pixel)
+ pix := make([][]coding.Pixel, N)
+ apix := make([]coding.Pixel, N*N)
+ for i := range pix {
+ pix[i], apix = apix[:N], apix[N:]
+ }
+
+ switch rot {
+ case 0:
+ // ok
+ case 1:
+ for y := 0; y < N; y++ {
+ for x := 0; x < N; x++ {
+ pix[y][x] = p.Pixel[x][N-1-y]
+ }
+ }
+ case 2:
+ for y := 0; y < N; y++ {
+ for x := 0; x < N; x++ {
+ pix[y][x] = p.Pixel[N-1-y][N-1-x]
+ }
+ }
+ case 3:
+ for y := 0; y < N; y++ {
+ for x := 0; x < N; x++ {
+ pix[y][x] = p.Pixel[N-1-x][y]
+ }
+ }
+ }
+
+ p.Pixel = pix
+}
+
+func (m *Image) Encode(req *http.Request) error {
+ p, err := coding.NewPlan(coding.Version(m.Version), coding.L, coding.Mask(m.Mask))
+ if err != nil {
+ return err
+ }
+
+ m.rotate(p, m.Rotation)
+
+ rand := rand.New(rand.NewSource(m.Seed))
+
+ // QR parameters.
+ nd := p.DataBytes / p.Blocks
+ nc := p.CheckBytes / p.Blocks
+ extra := p.DataBytes - nd*p.Blocks
+ rs := gf256.NewRSEncoder(coding.Field, nc)
+
+ // Build information about pixels, indexed by data/check bit number.
+ pixByOff := make([]Pixinfo, (p.DataBytes+p.CheckBytes)*8)
+ expect := make([][]bool, len(p.Pixel))
+ for y, row := range p.Pixel {
+ expect[y] = make([]bool, len(row))
+ for x, pix := range row {
+ targ, contrast := m.target(x, y)
+ if m.RandControl && contrast >= 0 {
+ contrast = rand.Intn(128) + 64*((x+y)%2) + 64*((x+y)%3%2)
+ }
+ expect[y][x] = pix&coding.Black != 0
+ if r := pix.Role(); r == coding.Data || r == coding.Check {
+ pixByOff[pix.Offset()] = Pixinfo{X: x, Y: y, Pix: pix, Targ: targ, Contrast: contrast}
+ }
+ }
+ }
+
+Again:
+ // Count fixed initial data bits, prepare template URL.
+ url := m.URL + "#"
+ var b coding.Bits
+ coding.String(url).Encode(&b, p.Version)
+ coding.Num("").Encode(&b, p.Version)
+ bbit := b.Bits()
+ dbit := p.DataBytes*8 - bbit
+ if dbit < 0 {
+ return fmt.Errorf("cannot encode URL into available bits")
+ }
+ num := make([]byte, dbit/10*3)
+ for i := range num {
+ num[i] = '0'
+ }
+ b.Pad(dbit)
+ b.Reset()
+ coding.String(url).Encode(&b, p.Version)
+ coding.Num(num).Encode(&b, p.Version)
+ b.AddCheckBytes(p.Version, p.Level)
+ data := b.Bytes()
+
+ doff := 0 // data offset
+ coff := 0 // checksum offset
+ mbit := bbit + dbit/10*10
+
+ // Choose pixels.
+ bitblocks := make([]*BitBlock, p.Blocks)
+ for blocknum := 0; blocknum < p.Blocks; blocknum++ {
+ if blocknum == p.Blocks-extra {
+ nd++
+ }
+
+ bdata := data[doff/8 : doff/8+nd]
+ cdata := data[p.DataBytes+coff/8 : p.DataBytes+coff/8+nc]
+ bb := newBlock(nd, nc, rs, bdata, cdata)
+ bitblocks[blocknum] = bb
+
+ // Determine which bits in this block we can try to edit.
+ lo, hi := 0, nd*8
+ if lo < bbit-doff {
+ lo = bbit - doff
+ if lo > hi {
+ lo = hi
+ }
+ }
+ if hi > mbit-doff {
+ hi = mbit - doff
+ if hi < lo {
+ hi = lo
+ }
+ }
+
+ // Preserve [0, lo) and [hi, nd*8).
+ for i := 0; i < lo; i++ {
+ if !bb.canSet(uint(i), (bdata[i/8]>>uint(7-i&7))&1) {
+ return fmt.Errorf("cannot preserve required bits")
+ }
+ }
+ for i := hi; i < nd*8; i++ {
+ if !bb.canSet(uint(i), (bdata[i/8]>>uint(7-i&7))&1) {
+ return fmt.Errorf("cannot preserve required bits")
+ }
+ }
+
+ // Can edit [lo, hi) and checksum bits to hit target.
+ // Determine which ones to try first.
+ order := make([]Pixorder, (hi-lo)+nc*8)
+ for i := lo; i < hi; i++ {
+ order[i-lo].Off = doff + i
+ }
+ for i := 0; i < nc*8; i++ {
+ order[hi-lo+i].Off = p.DataBytes*8 + coff + i
+ }
+ if m.OnlyDataBits {
+ order = order[:hi-lo]
+ }
+ for i := range order {
+ po := &order[i]
+ po.Priority = pixByOff[po.Off].Contrast<<8 | rand.Intn(256)
+ }
+ sort.Sort(byPriority(order))
+
+ const mark = false
+ for i := range order {
+ po := &order[i]
+ pinfo := &pixByOff[po.Off]
+ bval := pinfo.Targ
+ if bval < 128 {
+ bval = 1
+ } else {
+ bval = 0
+ }
+ pix := pinfo.Pix
+ if pix&coding.Invert != 0 {
+ bval ^= 1
+ }
+ if pinfo.HardZero {
+ bval = 0
+ }
+
+ var bi int
+ if pix.Role() == coding.Data {
+ bi = po.Off - doff
+ } else {
+ bi = po.Off - p.DataBytes*8 - coff + nd*8
+ }
+ if bb.canSet(uint(bi), bval) {
+ pinfo.Block = bb
+ pinfo.Bit = uint(bi)
+ if mark {
+ p.Pixel[pinfo.Y][pinfo.X] = coding.Black
+ }
+ } else {
+ if pinfo.HardZero {
+ panic("hard zero")
+ }
+ if mark {
+ p.Pixel[pinfo.Y][pinfo.X] = 0
+ }
+ }
+ }
+ bb.copyOut()
+
+ const cheat = false
+ for i := 0; i < nd*8; i++ {
+ pinfo := &pixByOff[doff+i]
+ pix := p.Pixel[pinfo.Y][pinfo.X]
+ if bb.B[i/8]&(1<<uint(7-i&7)) != 0 {
+ pix ^= coding.Black
+ }
+ expect[pinfo.Y][pinfo.X] = pix&coding.Black != 0
+ if cheat {
+ p.Pixel[pinfo.Y][pinfo.X] = pix & coding.Black
+ }
+ }
+ for i := 0; i < nc*8; i++ {
+ pinfo := &pixByOff[p.DataBytes*8+coff+i]
+ pix := p.Pixel[pinfo.Y][pinfo.X]
+ if bb.B[nd+i/8]&(1<<uint(7-i&7)) != 0 {
+ pix ^= coding.Black
+ }
+ expect[pinfo.Y][pinfo.X] = pix&coding.Black != 0
+ if cheat {
+ p.Pixel[pinfo.Y][pinfo.X] = pix & coding.Black
+ }
+ }
+ doff += nd * 8
+ coff += nc * 8
+ }
+
+ // Pass over all pixels again, dithering.
+ if m.Dither {
+ for i := range pixByOff {
+ pinfo := &pixByOff[i]
+ pinfo.DTarg = int(pinfo.Targ)
+ }
+ for y, row := range p.Pixel {
+ for x, pix := range row {
+ if pix.Role() != coding.Data && pix.Role() != coding.Check {
+ continue
+ }
+ pinfo := &pixByOff[pix.Offset()]
+ if pinfo.Block == nil {
+ // did not choose this pixel
+ continue
+ }
+
+ pix := pinfo.Pix
+
+ pval := byte(1) // pixel value (black)
+ v := 0 // gray value (black)
+ targ := pinfo.DTarg
+ if targ >= 128 {
+ // want white
+ pval = 0
+ v = 255
+ }
+
+ bval := pval // bit value
+ if pix&coding.Invert != 0 {
+ bval ^= 1
+ }
+ if pinfo.HardZero && bval != 0 {
+ bval ^= 1
+ pval ^= 1
+ v ^= 255
+ }
+
+ // Set pixel value as we want it.
+ pinfo.Block.reset(pinfo.Bit, bval)
+
+ _, _ = x, y
+
+ err := targ - v
+ if x+1 < len(row) {
+ addDither(pixByOff, row[x+1], err*7/16)
+ }
+ if false && y+1 < len(p.Pixel) {
+ if x > 0 {
+ addDither(pixByOff, p.Pixel[y+1][x-1], err*3/16)
+ }
+ addDither(pixByOff, p.Pixel[y+1][x], err*5/16)
+ if x+1 < len(row) {
+ addDither(pixByOff, p.Pixel[y+1][x+1], err*1/16)
+ }
+ }
+ }
+ }
+
+ for _, bb := range bitblocks {
+ bb.copyOut()
+ }
+ }
+
+ noops := 0
+ // Copy numbers back out.
+ for i := 0; i < dbit/10; i++ {
+ // Pull out 10 bits.
+ v := 0
+ for j := 0; j < 10; j++ {
+ bi := uint(bbit + 10*i + j)
+ v <<= 1
+ v |= int((data[bi/8] >> (7 - bi&7)) & 1)
+ }
+ // Turn into 3 digits.
+ if v >= 1000 {
+ // Oops - too many 1 bits.
+ // We know the 512, 256, 128, 64, 32 bits are all set.
+ // Pick one at random to clear. This will break some
+ // checksum bits, but so be it.
+ println("oops", i, v)
+ pinfo := &pixByOff[bbit+10*i+3] // TODO random
+ pinfo.Contrast = 1e9 >> 8
+ pinfo.HardZero = true
+ noops++
+ }
+ num[i*3+0] = byte(v/100 + '0')
+ num[i*3+1] = byte(v/10%10 + '0')
+ num[i*3+2] = byte(v%10 + '0')
+ }
+ if noops > 0 {
+ goto Again
+ }
+
+ var b1 coding.Bits
+ coding.String(url).Encode(&b1, p.Version)
+ coding.Num(num).Encode(&b1, p.Version)
+ b1.AddCheckBytes(p.Version, p.Level)
+ if !bytes.Equal(b.Bytes(), b1.Bytes()) {
+ fmt.Printf("mismatch\n%d %x\n%d %x\n", len(b.Bytes()), b.Bytes(), len(b1.Bytes()), b1.Bytes())
+ panic("byte mismatch")
+ }
+
+ cc, err := p.Encode(coding.String(url), coding.Num(num))
+ if err != nil {
+ return err
+ }
+
+ if !m.Dither {
+ for y, row := range expect {
+ for x, pix := range row {
+ if cc.Black(x, y) != pix {
+ println("mismatch", x, y, p.Pixel[y][x].String())
+ }
+ }
+ }
+ }
+
+ m.Code = &qr.Code{Bitmap: cc.Bitmap, Size: cc.Size, Stride: cc.Stride, Scale: m.Scale}
+
+ if m.SaveControl {
+ m.Control = pngEncode(makeImage(req, "", "", 0, cc.Size, 4, m.Scale, func(x, y int) (rgba uint32) {
+ pix := p.Pixel[y][x]
+ if pix.Role() == coding.Data || pix.Role() == coding.Check {
+ pinfo := &pixByOff[pix.Offset()]
+ if pinfo.Block != nil {
+ if cc.Black(x, y) {
+ return 0x000000ff
+ }
+ return 0xffffffff
+ }
+ }
+ if cc.Black(x, y) {
+ return 0x3f3f3fff
+ }
+ return 0xbfbfbfff
+ }))
+ }
+
+ return nil
+}
+
+func addDither(pixByOff []Pixinfo, pix coding.Pixel, err int) {
+ if pix.Role() != coding.Data && pix.Role() != coding.Check {
+ return
+ }
+ pinfo := &pixByOff[pix.Offset()]
+ println("add", pinfo.X, pinfo.Y, pinfo.DTarg, err)
+ pinfo.DTarg += err
+}
+
+func readTarget(name string) ([][]int, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ m, err := png.Decode(f)
+ if err != nil {
+ return nil, fmt.Errorf("decode %s: %v", name, err)
+ }
+ rect := m.Bounds()
+ target := make([][]int, rect.Dy())
+ for i := range target {
+ target[i] = make([]int, rect.Dx())
+ }
+ for y, row := range target {
+ for x := range row {
+ a := int(color.RGBAModel.Convert(m.At(x, y)).(color.RGBA).A)
+ t := int(color.GrayModel.Convert(m.At(x, y)).(color.Gray).Y)
+ if a == 0 {
+ t = -1
+ }
+ row[x] = t
+ }
+ }
+ return target, nil
+}
+
+type BitBlock struct {
+ DataBytes int
+ CheckBytes int
+ B []byte
+ M [][]byte
+ Tmp []byte
+ RS *gf256.RSEncoder
+ bdata []byte
+ cdata []byte
+}
+
+func newBlock(nd, nc int, rs *gf256.RSEncoder, dat, cdata []byte) *BitBlock {
+ b := &BitBlock{
+ DataBytes: nd,
+ CheckBytes: nc,
+ B: make([]byte, nd+nc),
+ Tmp: make([]byte, nc),
+ RS: rs,
+ bdata: dat,
+ cdata: cdata,
+ }
+ copy(b.B, dat)
+ rs.ECC(b.B[:nd], b.B[nd:])
+ b.check()
+ if !bytes.Equal(b.Tmp, cdata) {
+ panic("cdata")
+ }
+
+ b.M = make([][]byte, nd*8)
+ for i := range b.M {
+ row := make([]byte, nd+nc)
+ b.M[i] = row
+ for j := range row {
+ row[j] = 0
+ }
+ row[i/8] = 1 << (7 - uint(i%8))
+ rs.ECC(row[:nd], row[nd:])
+ }
+ return b
+}
+
+func (b *BitBlock) check() {
+ b.RS.ECC(b.B[:b.DataBytes], b.Tmp)
+ if !bytes.Equal(b.B[b.DataBytes:], b.Tmp) {
+ fmt.Printf("ecc mismatch\n%x\n%x\n", b.B[b.DataBytes:], b.Tmp)
+ panic("mismatch")
+ }
+}
+
+func (b *BitBlock) reset(bi uint, bval byte) {
+ if (b.B[bi/8]>>(7-bi&7))&1 == bval {
+ // already has desired bit
+ return
+ }
+ // rows that have already been set
+ m := b.M[len(b.M):cap(b.M)]
+ for _, row := range m {
+ if row[bi/8]&(1<<(7-bi&7)) != 0 {
+ // Found it.
+ for j, v := range row {
+ b.B[j] ^= v
+ }
+ return
+ }
+ }
+ panic("reset of unset bit")
+}
+
+func (b *BitBlock) canSet(bi uint, bval byte) bool {
+ found := false
+ m := b.M
+ for j, row := range m {
+ if row[bi/8]&(1<<(7-bi&7)) == 0 {
+ continue
+ }
+ if !found {
+ found = true
+ if j != 0 {
+ m[0], m[j] = m[j], m[0]
+ }
+ continue
+ }
+ for k := range row {
+ row[k] ^= m[0][k]
+ }
+ }
+ if !found {
+ return false
+ }
+
+ targ := m[0]
+
+ // Subtract from saved-away rows too.
+ for _, row := range m[len(m):cap(m)] {
+ if row[bi/8]&(1<<(7-bi&7)) == 0 {
+ continue
+ }
+ for k := range row {
+ row[k] ^= targ[k]
+ }
+ }
+
+ // Found a row with bit #bi == 1 and cut that bit from all the others.
+ // Apply to data and remove from m.
+ if (b.B[bi/8]>>(7-bi&7))&1 != bval {
+ for j, v := range targ {
+ b.B[j] ^= v
+ }
+ }
+ b.check()
+ n := len(m) - 1
+ m[0], m[n] = m[n], m[0]
+ b.M = m[:n]
+
+ for _, row := range b.M {
+ if row[bi/8]&(1<<(7-bi&7)) != 0 {
+ panic("did not reduce")
+ }
+ }
+
+ return true
+}
+
+func (b *BitBlock) copyOut() {
+ b.check()
+ copy(b.bdata, b.B[:b.DataBytes])
+ copy(b.cdata, b.B[b.DataBytes:])
+}
+
+func showtable(w http.ResponseWriter, b *BitBlock, gray func(int) bool) {
+ nd := b.DataBytes
+ nc := b.CheckBytes
+
+ fmt.Fprintf(w, "<table class='matrix' cellspacing=0 cellpadding=0 border=0>\n")
+ line := func() {
+ fmt.Fprintf(w, "<tr height=1 bgcolor='#bbbbbb'><td colspan=%d>\n", (nd+nc)*8)
+ }
+ line()
+ dorow := func(row []byte) {
+ fmt.Fprintf(w, "<tr>\n")
+ for i := 0; i < (nd+nc)*8; i++ {
+ fmt.Fprintf(w, "<td")
+ v := row[i/8] >> uint(7-i&7) & 1
+ if gray(i) {
+ fmt.Fprintf(w, " class='gray'")
+ }
+ fmt.Fprintf(w, ">")
+ if v == 1 {
+ fmt.Fprintf(w, "1")
+ }
+ }
+ line()
+ }
+
+ m := b.M[len(b.M):cap(b.M)]
+ for i := len(m) - 1; i >= 0; i-- {
+ dorow(m[i])
+ }
+ m = b.M
+ for _, row := range b.M {
+ dorow(row)
+ }
+
+ fmt.Fprintf(w, "</table>\n")
+}
+
+func BitsTable(w http.ResponseWriter, req *http.Request) {
+ nd := 2
+ nc := 2
+ fmt.Fprintf(w, `<html>
+ <style type='text/css'>
+ .matrix {
+ font-family: sans-serif;
+ font-size: 0.8em;
+ }
+ table.matrix {
+ padding-left: 1em;
+ padding-right: 1em;
+ padding-top: 1em;
+ padding-bottom: 1em;
+ }
+ .matrix td {
+ padding-left: 0.3em;
+ padding-right: 0.3em;
+ border-left: 2px solid white;
+ border-right: 2px solid white;
+ text-align: center;
+ color: #aaa;
+ }
+ .matrix td.gray {
+ color: black;
+ background-color: #ddd;
+ }
+ </style>
+ `)
+ rs := gf256.NewRSEncoder(coding.Field, nc)
+ dat := make([]byte, nd+nc)
+ b := newBlock(nd, nc, rs, dat[:nd], dat[nd:])
+ for i := 0; i < nd*8; i++ {
+ b.canSet(uint(i), 0)
+ }
+ showtable(w, b, func(i int) bool { return i < nd*8 })
+
+ b = newBlock(nd, nc, rs, dat[:nd], dat[nd:])
+ for j := 0; j < (nd+nc)*8; j += 2 {
+ b.canSet(uint(j), 0)
+ }
+ showtable(w, b, func(i int) bool { return i%2 == 0 })
+
+}
diff --git a/vendor/github.com/mattermost/rsc/qr/web/resize/resize.go b/vendor/github.com/mattermost/rsc/qr/web/resize/resize.go
new file mode 100644
index 000000000..02c8b0040
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/qr/web/resize/resize.go
@@ -0,0 +1,152 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package resize
+
+import (
+ "image"
+ "image/color"
+)
+
+// average convert the sums to averages and returns the result.
+func average(sum []uint64, w, h int, n uint64) *image.RGBA {
+ ret := image.NewRGBA(image.Rect(0, 0, w, h))
+ for y := 0; y < h; y++ {
+ for x := 0; x < w; x++ {
+ index := 4 * (y*w + x)
+ pix := ret.Pix[y*ret.Stride+x*4:]
+ pix[0] = uint8(sum[index+0] / n)
+ pix[1] = uint8(sum[index+1] / n)
+ pix[2] = uint8(sum[index+2] / n)
+ pix[3] = uint8(sum[index+3] / n)
+ }
+ }
+ return ret
+}
+
+// ResizeRGBA returns a scaled copy of the RGBA image slice r of m.
+// The returned image has width w and height h.
+func ResizeRGBA(m *image.RGBA, r image.Rectangle, w, h int) *image.RGBA {
+ ww, hh := uint64(w), uint64(h)
+ dx, dy := uint64(r.Dx()), uint64(r.Dy())
+ // See comment in Resize.
+ n, sum := dx*dy, make([]uint64, 4*w*h)
+ for y := r.Min.Y; y < r.Max.Y; y++ {
+ pix := m.Pix[(y-r.Min.Y)*m.Stride:]
+ for x := r.Min.X; x < r.Max.X; x++ {
+ // Get the source pixel.
+ p := pix[(x-r.Min.X)*4:]
+ r64 := uint64(p[0])
+ g64 := uint64(p[1])
+ b64 := uint64(p[2])
+ a64 := uint64(p[3])
+ // Spread the source pixel over 1 or more destination rows.
+ py := uint64(y) * hh
+ for remy := hh; remy > 0; {
+ qy := dy - (py % dy)
+ if qy > remy {
+ qy = remy
+ }
+ // Spread the source pixel over 1 or more destination columns.
+ px := uint64(x) * ww
+ index := 4 * ((py/dy)*ww + (px / dx))
+ for remx := ww; remx > 0; {
+ qx := dx - (px % dx)
+ if qx > remx {
+ qx = remx
+ }
+ qxy := qx * qy
+ sum[index+0] += r64 * qxy
+ sum[index+1] += g64 * qxy
+ sum[index+2] += b64 * qxy
+ sum[index+3] += a64 * qxy
+ index += 4
+ px += qx
+ remx -= qx
+ }
+ py += qy
+ remy -= qy
+ }
+ }
+ }
+ return average(sum, w, h, n)
+}
+
+// ResizeNRGBA returns a scaled copy of the RGBA image slice r of m.
+// The returned image has width w and height h.
+func ResizeNRGBA(m *image.NRGBA, r image.Rectangle, w, h int) *image.RGBA {
+ ww, hh := uint64(w), uint64(h)
+ dx, dy := uint64(r.Dx()), uint64(r.Dy())
+ // See comment in Resize.
+ n, sum := dx*dy, make([]uint64, 4*w*h)
+ for y := r.Min.Y; y < r.Max.Y; y++ {
+ pix := m.Pix[(y-r.Min.Y)*m.Stride:]
+ for x := r.Min.X; x < r.Max.X; x++ {
+ // Get the source pixel.
+ p := pix[(x-r.Min.X)*4:]
+ r64 := uint64(p[0])
+ g64 := uint64(p[1])
+ b64 := uint64(p[2])
+ a64 := uint64(p[3])
+ r64 = (r64 * a64) / 255
+ g64 = (g64 * a64) / 255
+ b64 = (b64 * a64) / 255
+ // Spread the source pixel over 1 or more destination rows.
+ py := uint64(y) * hh
+ for remy := hh; remy > 0; {
+ qy := dy - (py % dy)
+ if qy > remy {
+ qy = remy
+ }
+ // Spread the source pixel over 1 or more destination columns.
+ px := uint64(x) * ww
+ index := 4 * ((py/dy)*ww + (px / dx))
+ for remx := ww; remx > 0; {
+ qx := dx - (px % dx)
+ if qx > remx {
+ qx = remx
+ }
+ qxy := qx * qy
+ sum[index+0] += r64 * qxy
+ sum[index+1] += g64 * qxy
+ sum[index+2] += b64 * qxy
+ sum[index+3] += a64 * qxy
+ index += 4
+ px += qx
+ remx -= qx
+ }
+ py += qy
+ remy -= qy
+ }
+ }
+ }
+ return average(sum, w, h, n)
+}
+
+// Resample returns a resampled copy of the image slice r of m.
+// The returned image has width w and height h.
+func Resample(m image.Image, r image.Rectangle, w, h int) *image.RGBA {
+ if w < 0 || h < 0 {
+ return nil
+ }
+ if w == 0 || h == 0 || r.Dx() <= 0 || r.Dy() <= 0 {
+ return image.NewRGBA(image.Rect(0, 0, w, h))
+ }
+ curw, curh := r.Dx(), r.Dy()
+ img := image.NewRGBA(image.Rect(0, 0, w, h))
+ for y := 0; y < h; y++ {
+ for x := 0; x < w; x++ {
+ // Get a source pixel.
+ subx := x * curw / w
+ suby := y * curh / h
+ r32, g32, b32, a32 := m.At(subx, suby).RGBA()
+ r := uint8(r32 >> 8)
+ g := uint8(g32 >> 8)
+ b := uint8(b32 >> 8)
+ a := uint8(a32 >> 8)
+ img.SetRGBA(x, y, color.RGBA{r, g, b, a})
+ }
+ }
+ return img
+}
diff --git a/vendor/github.com/mattermost/rsc/regexp/regmerge/copy.go b/vendor/github.com/mattermost/rsc/regexp/regmerge/copy.go
new file mode 100644
index 000000000..4e723260b
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/regexp/regmerge/copy.go
@@ -0,0 +1,225 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from code.google.com/p/codesearch/regexp/copy.go.
+
+// Copied from Go's regexp/syntax.
+// Formatters edited to handle instByteRange.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "regexp/syntax"
+ "sort"
+ "strconv"
+ "unicode"
+)
+
+// cleanClass sorts the ranges (pairs of elements of r),
+// merges them, and eliminates duplicates.
+func cleanClass(rp *[]rune) []rune {
+
+ // Sort by lo increasing, hi decreasing to break ties.
+ sort.Sort(ranges{rp})
+
+ r := *rp
+ if len(r) < 2 {
+ return r
+ }
+
+ // Merge abutting, overlapping.
+ w := 2 // write index
+ for i := 2; i < len(r); i += 2 {
+ lo, hi := r[i], r[i+1]
+ if lo <= r[w-1]+1 {
+ // merge with previous range
+ if hi > r[w-1] {
+ r[w-1] = hi
+ }
+ continue
+ }
+ // new disjoint range
+ r[w] = lo
+ r[w+1] = hi
+ w += 2
+ }
+
+ return r[:w]
+}
+
+// appendRange returns the result of appending the range lo-hi to the class r.
+func appendRange(r []rune, lo, hi rune) []rune {
+ // Expand last range or next to last range if it overlaps or abuts.
+ // Checking two ranges helps when appending case-folded
+ // alphabets, so that one range can be expanding A-Z and the
+ // other expanding a-z.
+ n := len(r)
+ for i := 2; i <= 4; i += 2 { // twice, using i=2, i=4
+ if n >= i {
+ rlo, rhi := r[n-i], r[n-i+1]
+ if lo <= rhi+1 && rlo <= hi+1 {
+ if lo < rlo {
+ r[n-i] = lo
+ }
+ if hi > rhi {
+ r[n-i+1] = hi
+ }
+ return r
+ }
+ }
+ }
+
+ return append(r, lo, hi)
+}
+
+const (
+ // minimum and maximum runes involved in folding.
+ // checked during test.
+ minFold = 0x0041
+ maxFold = 0x1044f
+)
+
+// appendFoldedRange returns the result of appending the range lo-hi
+// and its case folding-equivalent runes to the class r.
+func appendFoldedRange(r []rune, lo, hi rune) []rune {
+ // Optimizations.
+ if lo <= minFold && hi >= maxFold {
+ // Range is full: folding can't add more.
+ return appendRange(r, lo, hi)
+ }
+ if hi < minFold || lo > maxFold {
+ // Range is outside folding possibilities.
+ return appendRange(r, lo, hi)
+ }
+ if lo < minFold {
+ // [lo, minFold-1] needs no folding.
+ r = appendRange(r, lo, minFold-1)
+ lo = minFold
+ }
+ if hi > maxFold {
+ // [maxFold+1, hi] needs no folding.
+ r = appendRange(r, maxFold+1, hi)
+ hi = maxFold
+ }
+
+ // Brute force. Depend on appendRange to coalesce ranges on the fly.
+ for c := lo; c <= hi; c++ {
+ r = appendRange(r, c, c)
+ f := unicode.SimpleFold(c)
+ for f != c {
+ r = appendRange(r, f, f)
+ f = unicode.SimpleFold(f)
+ }
+ }
+ return r
+}
+
+// ranges implements sort.Interface on a []rune.
+// The choice of receiver type definition is strange
+// but avoids an allocation since we already have
+// a *[]rune.
+type ranges struct {
+ p *[]rune
+}
+
+func (ra ranges) Less(i, j int) bool {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ return p[i] < p[j] || p[i] == p[j] && p[i+1] > p[j+1]
+}
+
+func (ra ranges) Len() int {
+ return len(*ra.p) / 2
+}
+
+func (ra ranges) Swap(i, j int) {
+ p := *ra.p
+ i *= 2
+ j *= 2
+ p[i], p[i+1], p[j], p[j+1] = p[j], p[j+1], p[i], p[i+1]
+}
+
+func progString(p *syntax.Prog) string {
+ var b bytes.Buffer
+ dumpProg(&b, p)
+ return b.String()
+}
+
+func instString(i *syntax.Inst) string {
+ var b bytes.Buffer
+ dumpInst(&b, i)
+ return b.String()
+}
+
+func bw(b *bytes.Buffer, args ...string) {
+ for _, s := range args {
+ b.WriteString(s)
+ }
+}
+
+func dumpProg(b *bytes.Buffer, p *syntax.Prog) {
+ for j := range p.Inst {
+ i := &p.Inst[j]
+ pc := strconv.Itoa(j)
+ if len(pc) < 3 {
+ b.WriteString(" "[len(pc):])
+ }
+ if j == p.Start {
+ pc += "*"
+ }
+ bw(b, pc, "\t")
+ dumpInst(b, i)
+ bw(b, "\n")
+ }
+}
+
+func u32(i uint32) string {
+ return strconv.FormatUint(uint64(i), 10)
+}
+
+func dumpInst(b *bytes.Buffer, i *syntax.Inst) {
+ switch i.Op {
+ case syntax.InstAlt:
+ bw(b, "alt -> ", u32(i.Out), ", ", u32(i.Arg))
+ case syntax.InstAltMatch:
+ bw(b, "altmatch -> ", u32(i.Out), ", ", u32(i.Arg))
+ case syntax.InstCapture:
+ bw(b, "cap ", u32(i.Arg), " -> ", u32(i.Out))
+ case syntax.InstEmptyWidth:
+ bw(b, "empty ", u32(i.Arg), " -> ", u32(i.Out))
+ case syntax.InstMatch:
+ bw(b, "match")
+ case syntax.InstFail:
+ bw(b, "fail")
+ case syntax.InstNop:
+ bw(b, "nop -> ", u32(i.Out))
+ case instByteRange:
+ fmt.Fprintf(b, "byte %02x-%02x", (i.Arg>>8)&0xFF, i.Arg&0xFF)
+ if i.Arg&argFold != 0 {
+ bw(b, "/i")
+ }
+ bw(b, " -> ", u32(i.Out))
+
+ // Should not happen
+ case syntax.InstRune:
+ if i.Rune == nil {
+ // shouldn't happen
+ bw(b, "rune <nil>")
+ }
+ bw(b, "rune ", strconv.QuoteToASCII(string(i.Rune)))
+ if syntax.Flags(i.Arg)&syntax.FoldCase != 0 {
+ bw(b, "/i")
+ }
+ bw(b, " -> ", u32(i.Out))
+ case syntax.InstRune1:
+ bw(b, "rune1 ", strconv.QuoteToASCII(string(i.Rune)), " -> ", u32(i.Out))
+ case syntax.InstRuneAny:
+ bw(b, "any -> ", u32(i.Out))
+ case syntax.InstRuneAnyNotNL:
+ bw(b, "anynotnl -> ", u32(i.Out))
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/regexp/regmerge/main.go b/vendor/github.com/mattermost/rsc/regexp/regmerge/main.go
new file mode 100644
index 000000000..672337a04
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/regexp/regmerge/main.go
@@ -0,0 +1,96 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "regexp/syntax"
+ "runtime/pprof"
+)
+
+var maxState = flag.Int("m", 1e5, "maximum number of states to explore")
+var cpuprof = flag.String("cpuprofile", "", "cpu profile file")
+
+func main() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, "usage: regmerge [-m maxstate] regexp [regexp2 regexp3....]\n")
+ os.Exit(2)
+ }
+ flag.Parse()
+
+ if len(flag.Args()) < 1 {
+ flag.Usage()
+ }
+
+ os.Exit(run(flag.Args()))
+}
+
+func run(args []string) int {
+ if *cpuprof != "" {
+ f, err := os.Create(*cpuprof)
+ if err != nil {
+ log.Fatal(err)
+ }
+ pprof.StartCPUProfile(f)
+ defer pprof.StopCPUProfile()
+ }
+
+ m, err := compile(flag.Args()...)
+ if err != nil {
+ log.Fatal(err)
+ }
+ n := 100
+ for ;; n *= 2 {
+ if n >= *maxState {
+ if n >= 2* *maxState {
+ fmt.Printf("reached state limit\n")
+ return 1
+ }
+ n = *maxState
+ }
+ log.Printf("try %d states...\n", n)
+ s, err := m.findMatch(n)
+ if err == nil {
+ fmt.Printf("%q\n", s)
+ return 0
+ }
+ if err != ErrMemory {
+ fmt.Printf("failed: %s\n", err)
+ return 3
+ }
+ }
+ panic("unreachable")
+}
+
+func compile(exprs ...string) (*matcher, error) {
+ var progs []*syntax.Prog
+ for _, expr := range exprs {
+ re, err := syntax.Parse(expr, syntax.Perl)
+ if err != nil {
+ return nil, err
+ }
+ sre := re.Simplify()
+ prog, err := syntax.Compile(sre)
+ if err != nil {
+ return nil, err
+ }
+ if err := toByteProg(prog); err != nil {
+ return nil, err
+ }
+ progs = append(progs, prog)
+ }
+ m := &matcher{}
+ if err := m.init(joinProgs(progs), len(progs)); err != nil {
+ return nil, err
+ }
+ return m, nil
+}
+
+func bug() {
+ panic("regmerge: internal error")
+}
diff --git a/vendor/github.com/mattermost/rsc/regexp/regmerge/match.go b/vendor/github.com/mattermost/rsc/regexp/regmerge/match.go
new file mode 100644
index 000000000..6a4b1f967
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/regexp/regmerge/match.go
@@ -0,0 +1,406 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from code.google.com/p/codesearch/regexp/copy.go
+// and adapted for the problem of finding a matching string, not
+// testing whether a particular string matches.
+
+package main
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "hash/fnv"
+ "hash"
+ "log"
+ "regexp/syntax"
+)
+
+// A matcher holds the state for running regular expression search.
+type matcher struct {
+ buf []byte
+ prog *syntax.Prog // compiled program
+ dstate map[uint32]*dstate // dstate cache
+ start *dstate // start state
+ startLine *dstate // start state for beginning of line
+ z1, z2, z3 nstate // three temporary nstates
+ ids []int
+ numState int
+ maxState int
+ numByte int
+ numMatch int
+ undo [256]byte
+ all *dstate
+ allTail **dstate
+ h hash.Hash32
+}
+
+// An nstate corresponds to an NFA state.
+type nstate struct {
+ q Set // queue of program instructions
+ flag flags // flags (TODO)
+ needFlag syntax.EmptyOp
+}
+
+// The flags record state about a position between bytes in the text.
+type flags uint32
+
+const (
+ flagBOL flags = 1 << iota // beginning of line
+ flagEOL // end of line
+ flagBOT // beginning of text
+ flagEOT // end of text
+ flagWord // last byte was word byte
+)
+
+// A dstate corresponds to a DFA state.
+type dstate struct {
+ enc string // encoded nstate
+ nextAll *dstate
+ nextHash *dstate
+ prev *dstate
+ prevByte int
+ done bool
+}
+
+func (z *nstate) String() string {
+ return fmt.Sprintf("%v/%#x+%#x", z.q.Dense(), z.flag, z.needFlag)
+}
+
+// enc encodes z as a string.
+func (m *matcher) enc(z *nstate) []byte {
+ buf := m.buf[:0]
+ buf = append(buf, byte(z.needFlag), byte(z.flag))
+ ids := m.ids[:0]
+ for _, id := range z.q.Dense() {
+ ids = append(ids, int(id))
+ }
+ sortInts(ids)
+ last := ^uint32(0)
+ for _, id := range ids {
+ x := uint32(id)-last
+ last = uint32(id)
+ for x >= 0x80 {
+ buf = append(buf, byte(x)|0x80)
+ x >>= 7
+ }
+ buf = append(buf, byte(x))
+ }
+ m.buf = buf
+ return buf
+}
+
+// dec decodes the encoding s into z.
+func (m *matcher) dec(z *nstate, s string) {
+ b := append(m.buf[:0], s...)
+ m.buf = b
+ z.needFlag = syntax.EmptyOp(b[0])
+ b = b[1:]
+ i, n := binary.Uvarint(b)
+ if n <= 0 {
+ bug()
+ }
+ b = b[n:]
+ z.flag = flags(i)
+ z.q.Reset()
+ last := ^uint32(0)
+ for len(b) > 0 {
+ i, n = binary.Uvarint(b)
+ if n <= 0 {
+ bug()
+ }
+ b = b[n:]
+ last += uint32(i)
+ z.q.Add(last, 0, 0)
+ }
+}
+
+// init initializes the matcher.
+func (m *matcher) init(prog *syntax.Prog, n int) error {
+ m.prog = prog
+ m.dstate = make(map[uint32]*dstate)
+ m.numMatch = n
+ m.maxState = 10
+ m.allTail = &m.all
+ m.numByte = 256
+ for i := range m.undo {
+ m.undo[i] = byte(i)
+ }
+ m.h = fnv.New32()
+
+ m.z1.q.Init(uint32(len(prog.Inst)))
+ m.z2.q.Init(uint32(len(prog.Inst)))
+ m.z3.q.Init(uint32(len(prog.Inst)))
+ m.ids = make([]int, 0, len(prog.Inst))
+
+ m.addq(&m.z1.q, uint32(prog.Start), syntax.EmptyBeginLine|syntax.EmptyBeginText)
+ m.z1.flag = flagBOL | flagBOT
+ m.start = m.cache(&m.z1, nil, 0)
+
+ m.z1.q.Reset()
+ m.addq(&m.z1.q, uint32(prog.Start), syntax.EmptyBeginLine)
+ m.z1.flag = flagBOL
+ m.startLine = m.cache(&m.z1, nil, 0)
+
+ m.crunchProg()
+
+ return nil
+}
+
+// stepEmpty steps runq to nextq expanding according to flag.
+func (m *matcher) stepEmpty(runq, nextq *Set, flag syntax.EmptyOp) {
+ nextq.Reset()
+ for _, id := range runq.Dense() {
+ m.addq(nextq, id, flag)
+ }
+}
+
+// stepByte steps runq to nextq consuming c and then expanding according to flag.
+// It returns true if a match ends immediately before c.
+// c is either an input byte or endText.
+func (m *matcher) stepByte(runq, nextq *Set, c int, flag syntax.EmptyOp) (match bool) {
+ nextq.Reset()
+ m.addq(nextq, uint32(m.prog.Start), flag)
+
+ nmatch := 0
+ for _, id := range runq.Dense() {
+ i := &m.prog.Inst[id]
+ switch i.Op {
+ default:
+ continue
+ case syntax.InstMatch:
+ nmatch++
+ continue
+ case instByteRange:
+ if c == endText {
+ break
+ }
+ lo := int((i.Arg >> 8) & 0xFF)
+ hi := int(i.Arg & 0xFF)
+ if i.Arg&argFold != 0 && 'a' <= c && c <= 'z' {
+ c += 'A' - 'a'
+ }
+ if lo <= c && c <= hi {
+ m.addq(nextq, i.Out, flag)
+ }
+ }
+ }
+ return nmatch == m.numMatch
+}
+
+// addq adds id to the queue, expanding according to flag.
+func (m *matcher) addq(q *Set, id uint32, flag syntax.EmptyOp) {
+ if q.Has(id, 0) {
+ return
+ }
+ q.MustAdd(id)
+ i := &m.prog.Inst[id]
+ switch i.Op {
+ case syntax.InstCapture, syntax.InstNop:
+ m.addq(q, i.Out, flag)
+ case syntax.InstAlt, syntax.InstAltMatch:
+ m.addq(q, i.Out, flag)
+ m.addq(q, i.Arg, flag)
+ case syntax.InstEmptyWidth:
+ if syntax.EmptyOp(i.Arg)&^flag == 0 {
+ m.addq(q, i.Out, flag)
+ }
+ }
+}
+
+const endText = -1
+
+// computeNext computes the next DFA state if we're in d reading c (an input byte or endText).
+func (m *matcher) computeNext(this, next *nstate, d *dstate, c int) bool {
+ // compute flags in effect before c
+ flag := syntax.EmptyOp(0)
+ if this.flag&flagBOL != 0 {
+ flag |= syntax.EmptyBeginLine
+ }
+ if this.flag&flagBOT != 0 {
+ flag |= syntax.EmptyBeginText
+ }
+ if this.flag&flagWord != 0 {
+ if !isWordByte(c) {
+ flag |= syntax.EmptyWordBoundary
+ } else {
+ flag |= syntax.EmptyNoWordBoundary
+ }
+ } else {
+ if isWordByte(c) {
+ flag |= syntax.EmptyWordBoundary
+ } else {
+ flag |= syntax.EmptyNoWordBoundary
+ }
+ }
+ if c == '\n' {
+ flag |= syntax.EmptyEndLine
+ }
+ if c == endText {
+ flag |= syntax.EmptyEndLine | syntax.EmptyEndText
+ }
+
+ if flag &= this.needFlag; flag != 0 {
+ // re-expand queue using new flags.
+ // TODO: only do this when it matters
+ // (something is gating on word boundaries).
+ m.stepEmpty(&this.q, &next.q, flag)
+ this, next = next, &m.z3
+ }
+
+ // now compute flags after c.
+ flag = 0
+ next.flag = 0
+ if c == '\n' {
+ flag |= syntax.EmptyBeginLine
+ next.flag |= flagBOL
+ }
+ if isWordByte(c) {
+ next.flag |= flagWord
+ }
+
+ // re-add start, process rune + expand according to flags.
+ if m.stepByte(&this.q, &next.q, c, flag) {
+ return true
+ }
+ next.needFlag = m.queueFlag(&next.q)
+ if next.needFlag&syntax.EmptyBeginLine == 0 {
+ next.flag &^= flagBOL
+ }
+ if next.needFlag&(syntax.EmptyWordBoundary|syntax.EmptyNoWordBoundary) == 0{
+ next.flag &^= flagWord
+ }
+
+ m.cache(next, d, c)
+ return false
+}
+
+func (m *matcher) queueFlag(runq *Set) syntax.EmptyOp {
+ var e uint32
+ for _, id := range runq.Dense() {
+ i := &m.prog.Inst[id]
+ if i.Op == syntax.InstEmptyWidth {
+ e |= i.Arg
+ }
+ }
+ return syntax.EmptyOp(e)
+}
+
+func (m *matcher) hash(enc []byte) uint32 {
+ m.h.Reset()
+ m.h.Write(enc)
+ return m.h.Sum32()
+}
+
+func (m *matcher) find(h uint32, enc []byte) *dstate {
+Search:
+ for d := m.dstate[h]; d!=nil; d=d.nextHash {
+ s := d.enc
+ if len(s) != len(enc) {
+ continue Search
+ }
+ for i, b := range enc {
+ if s[i] != b {
+ continue Search
+ }
+ }
+ return d
+ }
+ return nil
+}
+
+func (m *matcher) cache(z *nstate, prev *dstate, prevByte int) *dstate {
+ enc := m.enc(z)
+ h := m.hash(enc)
+ d := m.find(h, enc)
+ if d != nil {
+ return d
+ }
+
+ if m.numState >= m.maxState {
+ panic(ErrMemory)
+ }
+ m.numState++
+ d = &dstate{
+ enc: string(enc),
+ prev: prev,
+ prevByte: prevByte,
+ nextHash: m.dstate[h],
+ }
+ m.dstate[h] = d
+ *m.allTail = d
+ m.allTail = &d.nextAll
+
+ return d
+}
+
+// isWordByte reports whether the byte c is a word character: ASCII only.
+// This is used to implement \b and \B. This is not right for Unicode, but:
+// - it's hard to get right in a byte-at-a-time matching world
+// (the DFA has only one-byte lookahead)
+// - this crude approximation is the same one PCRE uses
+func isWordByte(c int) bool {
+ return 'A' <= c && c <= 'Z' ||
+ 'a' <= c && c <= 'z' ||
+ '0' <= c && c <= '9' ||
+ c == '_'
+}
+
+var ErrNoMatch = errors.New("no matching strings")
+var ErrMemory = errors.New("exhausted memory")
+
+func (m *matcher) findMatch(maxState int) (s string, err error) {
+ defer func() {
+ switch r := recover().(type) {
+ case nil:
+ return
+ case error:
+ err = r
+ return
+ default:
+ panic(r)
+ }
+ }()
+
+ m.maxState = maxState
+ numState := 0
+ var d *dstate
+ var c int
+ for d = m.all; d != nil; d = d.nextAll {
+ numState++
+ if d.done {
+ continue
+ }
+ this, next := &m.z1, &m.z2
+ m.dec(this, d.enc)
+ if m.computeNext(this, next, d, endText) {
+ c = endText
+ goto Found
+ }
+ for _, cb := range m.undo[:m.numByte] {
+ if m.computeNext(this, next, d, int(cb)) {
+ c = int(cb)
+ goto Found
+ }
+ }
+ d.done = true
+ }
+ log.Printf("searched %d states; queued %d states", numState, m.numState)
+ return "", ErrNoMatch
+
+Found:
+ var buf []byte
+ if c >= 0 {
+ buf = append(buf, byte(c))
+ }
+ for d1 := d; d1.prev != nil; d1= d1.prev {
+ buf = append(buf, byte(d1.prevByte))
+ }
+ for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
+ buf[i], buf[j] = buf[j], buf[i]
+ }
+ log.Printf("searched %d states; queued %d states", numState, m.numState)
+ return string(buf), nil
+}
diff --git a/vendor/github.com/mattermost/rsc/regexp/regmerge/merge.go b/vendor/github.com/mattermost/rsc/regexp/regmerge/merge.go
new file mode 100644
index 000000000..15f51cfa7
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/regexp/regmerge/merge.go
@@ -0,0 +1,103 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code to merge (join) multiple regexp progs into a single prog.
+// New code; not copied from anywhere.
+
+package main
+
+import "regexp/syntax"
+
+func joinProgs(progs []*syntax.Prog) *syntax.Prog {
+ all := &syntax.Prog{}
+ for i, p := range progs {
+ n := len(all.Inst)
+ all.Inst = append(all.Inst, p.Inst...)
+ match := shiftInst(all.Inst[n:], n)
+ if match < 0 {
+ // no match instruction; give up
+ all.Inst = []syntax.Inst{{Op: syntax.InstFail}}
+ all.Start = 0
+ return all
+ }
+ match += n
+ m := len(all.Inst)
+ all.Inst = append(all.Inst,
+ syntax.Inst{Op: syntax.InstAlt, Out: uint32(p.Start+n), Arg: uint32(m+1)},
+ syntax.Inst{Op: instByteRange, Arg: 0x00FF, Out: uint32(m)},
+ syntax.Inst{Op: instByteRange, Arg: 0x00FF, Out: uint32(match)},
+ syntax.Inst{Op: syntax.InstMatch},
+ )
+ all.Inst[match] = syntax.Inst{Op: syntax.InstAlt, Out: uint32(m+2), Arg: uint32(m+3)}
+
+ if i == 0 {
+ all.Start = m
+ } else {
+ old := all.Start
+ all.Start = len(all.Inst)
+ all.Inst = append(all.Inst, syntax.Inst{Op: syntax.InstAlt, Out: uint32(old), Arg: uint32(m)})
+ }
+ }
+
+ return all
+}
+
+func shiftInst(inst []syntax.Inst, n int) int {
+ match := -1
+ for i := range inst {
+ ip := &inst[i]
+ ip.Out += uint32(n)
+ if ip.Op == syntax.InstMatch {
+ if match >= 0 {
+ panic("double match")
+ }
+ match = i
+ }
+ if ip.Op == syntax.InstAlt || ip.Op == syntax.InstAltMatch {
+ ip.Arg += uint32(n)
+ }
+ }
+ return match
+}
+
+func (m *matcher) crunchProg() {
+ var rewrite [256]byte
+
+ for i := range m.prog.Inst {
+ ip := &m.prog.Inst[i]
+ switch ip.Op {
+ case instByteRange:
+ lo, hi := byte(ip.Arg>>8), byte(ip.Arg)
+ rewrite[lo] = 1
+ if hi < 255 {
+ rewrite[hi+1] = 1
+ }
+ case syntax.InstEmptyWidth:
+ switch op := syntax.EmptyOp(ip.Arg); {
+ case op&(syntax.EmptyBeginLine|syntax.EmptyEndLine) != 0:
+ rewrite['\n'] = 1
+ rewrite['\n'+1] = 1
+ case op&(syntax.EmptyWordBoundary|syntax.EmptyNoWordBoundary) != 0:
+ rewrite['A'] = 1
+ rewrite['Z'+1] = 1
+ rewrite['a'] = 1
+ rewrite['z'+1] = 1
+ rewrite['0'] = 1
+ rewrite['9'+1] = 1
+ rewrite['_'] = 1
+ rewrite['_'+1] = 1
+ }
+ }
+ }
+
+ rewrite[0] = 0
+ for i := 1; i < 256; i++ {
+ rewrite[i] += rewrite[i-1]
+ }
+ m.numByte = int(rewrite[255]) + 1
+
+ for i := 255; i >= 0; i-- {
+ m.undo[rewrite[i]] = byte(i)
+ }
+}
diff --git a/vendor/github.com/mattermost/rsc/regexp/regmerge/sort.go b/vendor/github.com/mattermost/rsc/regexp/regmerge/sort.go
new file mode 100644
index 000000000..e40f87714
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/regexp/regmerge/sort.go
@@ -0,0 +1,199 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copy of go/src/pkg/sort/sort.go, specialized for []int
+// and to remove some array indexing.
+
+package main
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+// Insertion sort
+func insertionSort(data []int, a, b int) {
+ for i := a + 1; i < b; i++ {
+ for j := i; j > a && data[j] < data[j-1]; j-- {
+ data[j], data[j-1] = data[j-1], data[j]
+ }
+ }
+}
+
+// siftDown implements the heap property on data[lo, hi).
+// first is an offset into the array where the root of the heap lies.
+func siftDown(data []int, lo, hi, first int) {
+ root := lo
+ for {
+ child := 2*root + 1
+ if child >= hi {
+ break
+ }
+ if child+1 < hi && data[first+child] < data[first+child+1] {
+ child++
+ }
+ if !(data[first+root] < data[first+child]) {
+ return
+ }
+ data[first+root], data[first+child] = data[first+child], data[first+root]
+ root = child
+ }
+}
+
+func heapSort(data []int, a, b int) {
+ first := a
+ lo := 0
+ hi := b - a
+
+ // Build heap with greatest element at top.
+ for i := (hi - 1) / 2; i >= 0; i-- {
+ siftDown(data, i, hi, first)
+ }
+
+ // Pop elements, largest first, into end of data.
+ for i := hi - 1; i >= 0; i-- {
+ data[first], data[first+i] = data[first+i], data[first]
+ siftDown(data, lo, i, first)
+ }
+}
+
+// Quicksort, following Bentley and McIlroy,
+// ``Engineering a Sort Function,'' SP&E November 1993.
+
+// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a].
+func medianOfThree(data []int, a, b, c int) {
+ m0 := b
+ m1 := a
+ m2 := c
+ // bubble sort on 3 elements
+ if data[m1] < data[m0] {
+ data[m1], data[m0] = data[m0], data[m1]
+ }
+ if data[m2] < data[m1] {
+ data[m2], data[m1] = data[m1], data[m2]
+ }
+ if data[m1] < data[m0] {
+ data[m1], data[m0] = data[m0], data[m1]
+ }
+ // now data[m0] <= data[m1] <= data[m2]
+}
+
+func swapRange(data []int, a, b, n int) {
+ for i := 0; i < n; i++ {
+ data[a+i], data[b+i] = data[b+i], data[a+i]
+ }
+}
+
+func doPivot(data []int, lo, hi int) (midlo, midhi int) {
+ m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
+ if hi-lo > 40 {
+ // Tukey's ``Ninther,'' median of three medians of three.
+ s := (hi - lo) / 8
+ medianOfThree(data, lo, lo+s, lo+2*s)
+ medianOfThree(data, m, m-s, m+s)
+ medianOfThree(data, hi-1, hi-1-s, hi-1-2*s)
+ }
+ medianOfThree(data, lo, m, hi-1)
+
+ // Invariants are:
+ // data[lo] = pivot (set up by ChoosePivot)
+ // data[lo <= i < a] = pivot
+ // data[a <= i < b] < pivot
+ // data[b <= i < c] is unexamined
+ // data[c <= i < d] > pivot
+ // data[d <= i < hi] = pivot
+ //
+ // Once b meets c, can swap the "= pivot" sections
+ // into the middle of the slice.
+ pivot := lo
+ a, b, c, d := lo+1, lo+1, hi, hi
+ dpivot := data[pivot]
+ db, dc1 := data[b], data[c-1]
+ for b < c {
+ if db < dpivot { // data[b] < pivot
+ b++
+ if b < c {
+ db = data[b]
+ }
+ continue
+ }
+ if !(dpivot < db) { // data[b] = pivot
+ data[a], data[b] = db, data[a]
+ a++
+ b++
+ if b < c {
+ db = data[b]
+ }
+ continue
+ }
+ if dpivot < dc1 { // data[c-1] > pivot
+ c--
+ if c > 0 {
+ dc1 = data[c-1]
+ }
+ continue
+ }
+ if !(dc1 < dpivot) { // data[c-1] = pivot
+ data[c-1], data[d-1] = data[d-1], dc1
+ c--
+ d--
+ if c > 0 {
+ dc1 = data[c-1]
+ }
+ continue
+ }
+ // data[b] > pivot; data[c-1] < pivot
+ data[b], data[c-1] = dc1, db
+ b++
+ c--
+ if b < c {
+ db = data[b]
+ dc1 = data[c-1]
+ }
+ }
+
+ n := min(b-a, a-lo)
+ swapRange(data, lo, b-n, n)
+
+ n = min(hi-d, d-c)
+ swapRange(data, c, hi-n, n)
+
+ return lo + b - a, hi - (d - c)
+}
+
+func quickSort(data []int, a, b, maxDepth int) {
+ for b-a > 7 {
+ if maxDepth == 0 {
+ heapSort(data, a, b)
+ return
+ }
+ maxDepth--
+ mlo, mhi := doPivot(data, a, b)
+ // Avoiding recursion on the larger subproblem guarantees
+ // a stack depth of at most lg(b-a).
+ if mlo-a < b-mhi {
+ quickSort(data, a, mlo, maxDepth)
+ a = mhi // i.e., quickSort(data, mhi, b)
+ } else {
+ quickSort(data, mhi, b, maxDepth)
+ b = mlo // i.e., quickSort(data, a, mlo)
+ }
+ }
+ if b-a > 1 {
+ insertionSort(data, a, b)
+ }
+}
+
+func sortInts(data []int) {
+ // Switch to heapsort if depth of 2*ceil(lg(n)) is reached.
+ n := len(data)
+ maxDepth := 0
+ for 1<<uint(maxDepth) < n {
+ maxDepth++
+ }
+ maxDepth *= 2
+ quickSort(data, 0, n, maxDepth)
+}
diff --git a/vendor/github.com/mattermost/rsc/regexp/regmerge/sparse.go b/vendor/github.com/mattermost/rsc/regexp/regmerge/sparse.go
new file mode 100644
index 000000000..461027080
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/regexp/regmerge/sparse.go
@@ -0,0 +1,80 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from code.google.com/p/codesearch/sparse/set.go,
+// tweaked for better inlinability.
+
+package main
+
+// For comparison: running cindex over the Linux 2.6 kernel with this
+// implementation of trigram sets takes 11 seconds. If I change it to
+// a bitmap (which must be cleared between files) it takes 25 seconds.
+
+// A Set is a sparse set of uint32 values.
+// http://research.swtch.com/2008/03/using-uninitialized-memory-for-fun-and.html
+type Set struct {
+ dense []uint32
+ sparse []uint32
+}
+
+// NewSet returns a new Set with a given maximum size.
+// The set can contain numbers in [0, max-1].
+func NewSet(max uint32) *Set {
+ return &Set{
+ sparse: make([]uint32, max),
+ }
+}
+
+// Init initializes a Set to have a given maximum size.
+// The set can contain numbers in [0, max-1].
+func (s *Set) Init(max uint32) {
+ s.sparse = make([]uint32, max)
+}
+
+// Reset clears (empties) the set.
+func (s *Set) Reset() {
+ s.dense = s.dense[:0]
+}
+
+// Add adds x to the set if it is not already there.
+//
+// TODO: The ugly additional variables v and n make the
+// function inlinable. When the 6g inliner gets better
+// they will not be necessary.
+func (s *Set) Add(x uint32, v uint32, n int) {
+ v = s.sparse[x]
+ if v < uint32(len(s.dense)) && s.dense[v] == x {
+ return
+ }
+ n = len(s.dense)
+ s.sparse[x] = uint32(n)
+ s.dense = append(s.dense, x)
+}
+
+func (s *Set) MustAdd(x uint32) {
+ s.sparse[x] = uint32(len(s.dense))
+ s.dense = append(s.dense, x)
+}
+
+// Has reports whether x is in the set.
+//
+// TODO: The ugly additional variables v makes
+// function inlinable. When the 6g inliner gets better
+// it will not be necessary.
+func (s *Set) Has(x uint32, v uint32) bool {
+ v = s.sparse[x]
+ return v < uint32(len(s.dense)) && s.dense[v] == x
+}
+
+// Dense returns the values in the set.
+// The values are listed in the order in which they
+// were inserted.
+func (s *Set) Dense() []uint32 {
+ return s.dense
+}
+
+// Len returns the number of values in the set.
+func (s *Set) Len() int {
+ return len(s.dense)
+}
diff --git a/vendor/github.com/mattermost/rsc/regexp/regmerge/utf.go b/vendor/github.com/mattermost/rsc/regexp/regmerge/utf.go
new file mode 100644
index 000000000..605e01c10
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/regexp/regmerge/utf.go
@@ -0,0 +1,270 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copy of code.google.com/p/codesearch/regexp/utf.go.
+
+package main
+
+import (
+ "regexp/syntax"
+ "unicode"
+ "unicode/utf8"
+)
+
+const (
+ instFail = syntax.InstFail
+ instAlt = syntax.InstAlt
+ instByteRange = syntax.InstRune | 0x80 // local opcode
+
+ argFold = 1 << 16
+)
+
+func toByteProg(prog *syntax.Prog) error {
+ var b runeBuilder
+ for pc := range prog.Inst {
+ i := &prog.Inst[pc]
+ switch i.Op {
+ case syntax.InstRune, syntax.InstRune1:
+ // General rune range. PIA.
+ // TODO: Pick off single-byte case.
+ if lo, hi, fold, ok := oneByteRange(i); ok {
+ i.Op = instByteRange
+ i.Arg = uint32(lo)<<8 | uint32(hi)
+ if fold {
+ i.Arg |= argFold
+ }
+ break
+ }
+
+ r := i.Rune
+ if syntax.Flags(i.Arg)&syntax.FoldCase != 0 {
+ // Build folded list.
+ var rr []rune
+ if len(r) == 1 {
+ rr = appendFoldedRange(rr, r[0], r[0])
+ } else {
+ for j := 0; j < len(r); j += 2 {
+ rr = appendFoldedRange(rr, r[j], r[j+1])
+ }
+ }
+ r = rr
+ }
+
+ b.init(prog, uint32(pc), i.Out)
+ if len(r) == 1 {
+ b.addRange(r[0], r[0], false)
+ } else {
+ for j := 0; j < len(r); j += 2 {
+ b.addRange(r[j], r[j+1], false)
+ }
+ }
+
+ case syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+ // All runes.
+ // AnyNotNL should exclude \n but the line-at-a-time
+ // execution takes care of that for us.
+ b.init(prog, uint32(pc), i.Out)
+ b.addRange(0, unicode.MaxRune, false)
+ }
+ }
+ return nil
+}
+
+func oneByteRange(i *syntax.Inst) (lo, hi byte, fold, ok bool) {
+ if i.Op == syntax.InstRune1 {
+ r := i.Rune[0]
+ if r < utf8.RuneSelf {
+ return byte(r), byte(r), false, true
+ }
+ }
+ if i.Op != syntax.InstRune {
+ return
+ }
+ fold = syntax.Flags(i.Arg)&syntax.FoldCase != 0
+ if len(i.Rune) == 1 || len(i.Rune) == 2 && i.Rune[0] == i.Rune[1] {
+ r := i.Rune[0]
+ if r >= utf8.RuneSelf {
+ return
+ }
+ if fold && !asciiFold(r) {
+ return
+ }
+ return byte(r), byte(r), fold, true
+ }
+ if len(i.Rune) == 2 && i.Rune[1] < utf8.RuneSelf {
+ if fold {
+ for r := i.Rune[0]; r <= i.Rune[1]; r++ {
+ if asciiFold(r) {
+ return
+ }
+ }
+ }
+ return byte(i.Rune[0]), byte(i.Rune[1]), fold, true
+ }
+ if len(i.Rune) == 4 && i.Rune[0] == i.Rune[1] && i.Rune[2] == i.Rune[3] && unicode.SimpleFold(i.Rune[0]) == i.Rune[2] && unicode.SimpleFold(i.Rune[2]) == i.Rune[0] {
+ return byte(i.Rune[0]), byte(i.Rune[0]), true, true
+ }
+
+ return
+}
+
+func asciiFold(r rune) bool {
+ if r >= utf8.RuneSelf {
+ return false
+ }
+ r1 := unicode.SimpleFold(r)
+ if r1 >= utf8.RuneSelf {
+ return false
+ }
+ if r1 == r {
+ return true
+ }
+ return unicode.SimpleFold(r1) == r
+}
+
+func maxRune(n int) rune {
+ b := 0
+ if n == 1 {
+ b = 7
+ } else {
+ b = 8 - (n + 1) + 6*(n-1)
+ }
+ return 1<<uint(b) - 1
+}
+
+type cacheKey struct {
+ lo, hi uint8
+ fold bool
+ next uint32
+}
+
+type runeBuilder struct {
+ begin uint32
+ out uint32
+ cache map[cacheKey]uint32
+ p *syntax.Prog
+}
+
+func (b *runeBuilder) init(p *syntax.Prog, begin, out uint32) {
+ // We will rewrite p.Inst[begin] to hold the accumulated
+ // machine. For now, there is no match.
+ p.Inst[begin].Op = instFail
+
+ b.begin = begin
+ b.out = out
+ if b.cache == nil {
+ b.cache = make(map[cacheKey]uint32)
+ }
+ for k := range b.cache {
+ delete(b.cache, k)
+ }
+ b.p = p
+}
+
+func (b *runeBuilder) uncachedSuffix(lo, hi byte, fold bool, next uint32) uint32 {
+ if next == 0 {
+ next = b.out
+ }
+ pc := len(b.p.Inst)
+ i := syntax.Inst{Op: instByteRange, Arg: uint32(lo)<<8 | uint32(hi), Out: next}
+ if fold {
+ i.Arg |= argFold
+ }
+ b.p.Inst = append(b.p.Inst, i)
+ return uint32(pc)
+}
+
+func (b *runeBuilder) suffix(lo, hi byte, fold bool, next uint32) uint32 {
+ if lo < 0x80 || hi > 0xbf {
+ // Not a continuation byte, no need to cache.
+ return b.uncachedSuffix(lo, hi, fold, next)
+ }
+
+ key := cacheKey{lo, hi, fold, next}
+ if pc, ok := b.cache[key]; ok {
+ return pc
+ }
+
+ pc := b.uncachedSuffix(lo, hi, fold, next)
+ b.cache[key] = pc
+ return pc
+}
+
+func (b *runeBuilder) addBranch(pc uint32) {
+ // Add pc to the branch at the beginning.
+ i := &b.p.Inst[b.begin]
+ switch i.Op {
+ case syntax.InstFail:
+ i.Op = syntax.InstNop
+ i.Out = pc
+ return
+ case syntax.InstNop:
+ i.Op = syntax.InstAlt
+ i.Arg = pc
+ return
+ case syntax.InstAlt:
+ apc := uint32(len(b.p.Inst))
+ b.p.Inst = append(b.p.Inst, syntax.Inst{Op: instAlt, Out: i.Arg, Arg: pc})
+ i = &b.p.Inst[b.begin]
+ i.Arg = apc
+ b.begin = apc
+ }
+}
+
+func (b *runeBuilder) addRange(lo, hi rune, fold bool) {
+ if lo > hi {
+ return
+ }
+
+ // TODO: Pick off 80-10FFFF for special handling?
+ if lo == 0x80 && hi == 0x10FFFF {
+ }
+
+ // Split range into same-length sized ranges.
+ for i := 1; i < utf8.UTFMax; i++ {
+ max := maxRune(i)
+ if lo <= max && max < hi {
+ b.addRange(lo, max, fold)
+ b.addRange(max+1, hi, fold)
+ return
+ }
+ }
+
+ // ASCII range is special.
+ if hi < utf8.RuneSelf {
+ b.addBranch(b.suffix(byte(lo), byte(hi), fold, 0))
+ return
+ }
+
+ // Split range into sections that agree on leading bytes.
+ for i := 1; i < utf8.UTFMax; i++ {
+ m := rune(1)<<uint(6*i) - 1 // last i bytes of UTF-8 sequence
+ if lo&^m != hi&^m {
+ if lo&m != 0 {
+ b.addRange(lo, lo|m, fold)
+ b.addRange((lo|m)+1, hi, fold)
+ return
+ }
+ if hi&m != m {
+ b.addRange(lo, hi&^m-1, fold)
+ b.addRange(hi&^m, hi, fold)
+ return
+ }
+ }
+ }
+
+ // Finally. Generate byte matching equivalent for lo-hi.
+ var ulo, uhi [utf8.UTFMax]byte
+ n := utf8.EncodeRune(ulo[:], lo)
+ m := utf8.EncodeRune(uhi[:], hi)
+ if n != m {
+ panic("codesearch/regexp: bad utf-8 math")
+ }
+
+ pc := uint32(0)
+ for i := n - 1; i >= 0; i-- {
+ pc = b.suffix(ulo[i], uhi[i], false, pc)
+ }
+ b.addBranch(pc)
+}
diff --git a/vendor/github.com/mattermost/rsc/rosetta/graph/Makefile b/vendor/github.com/mattermost/rsc/rosetta/graph/Makefile
new file mode 100644
index 000000000..1cb49f788
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/rosetta/graph/Makefile
@@ -0,0 +1,7 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=rsc.googlecode.com/hg/rosetta/graph
+GOFILES=\
+ graph.go\
+
+include $(GOROOT)/src/Make.pkg
diff --git a/vendor/github.com/mattermost/rsc/rosetta/graph/graph.go b/vendor/github.com/mattermost/rsc/rosetta/graph/graph.go
new file mode 100644
index 000000000..359617d41
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/rosetta/graph/graph.go
@@ -0,0 +1,133 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Simple demonstration of a graph interface and
+// Dijkstra's algorithm built on top of that interface,
+// without using inheritance.
+
+package graph
+
+import "container/heap"
+
+// A Graph is the interface implemented by graphs that
+// this package can run algorithms on.
+type Graph interface {
+ // NumVertex returns the number of vertices in the graph.
+ NumVertex() int
+
+ // VertexID returns a vertex ID, 0 <= ID < NumVertex(), for v.
+ VertexID(v Vertex) int
+
+ // Neighbors returns a slice of vertices that are adjacent
+ // to v in the graph.
+ Neighbors(v Vertex) []Vertex
+}
+
+type Vertex interface {
+ String() string
+}
+
+// ShortestPath uses Dijkstra's algorithm to find the shortest
+// path from start to end in g. It returns the path as a slice of
+// vertices, with start first and end last. If there is no path,
+// ShortestPath returns nil.
+func ShortestPath(g Graph, start, end Vertex) []Vertex {
+ d := newDijkstra(g)
+
+ d.visit(start, 1, nil)
+ for !d.empty() {
+ p := d.next()
+ if g.VertexID(p.v) == g.VertexID(end) {
+ break
+ }
+ for _, v := range g.Neighbors(p.v) {
+ d.visit(v, p.depth+1, p)
+ }
+ }
+
+ p := d.pos(end)
+ if p.depth == 0 {
+ // unvisited - no path
+ return nil
+ }
+ path := make([]Vertex, p.depth)
+ for ; p != nil; p = p.parent {
+ path[p.depth-1] = p.v
+ }
+ return path
+}
+
+// A dpos is a position in the Dijkstra traversal.
+type dpos struct {
+ depth int
+ heapIndex int
+ v Vertex
+ parent *dpos
+}
+
+// A dijkstra is the Dijkstra traversal's work state.
+// It contains the heap queue and per-vertex information.
+type dijkstra struct {
+ g Graph
+ q []*dpos
+ byID []dpos
+}
+
+func newDijkstra(g Graph) *dijkstra {
+ d := &dijkstra{g: g}
+ d.byID = make([]dpos, g.NumVertex())
+ return d
+}
+
+func (d *dijkstra) pos(v Vertex) *dpos {
+ p := &d.byID[d.g.VertexID(v)]
+ p.v = v // in case this is the first time we've seen it
+ return p
+}
+
+func (d *dijkstra) visit(v Vertex, depth int, parent *dpos) {
+ p := d.pos(v)
+ if p.depth == 0 {
+ p.parent = parent
+ p.depth = depth
+ heap.Push(d, p)
+ }
+}
+
+func (d *dijkstra) empty() bool {
+ return len(d.q) == 0
+}
+
+func (d *dijkstra) next() *dpos {
+ return heap.Pop(d).(*dpos)
+}
+
+// Implementation of heap.Interface
+func (d *dijkstra) Len() int {
+ return len(d.q)
+}
+
+func (d *dijkstra) Less(i, j int) bool {
+ return d.q[i].depth < d.q[j].depth
+}
+
+func (d *dijkstra) Swap(i, j int) {
+ d.q[i], d.q[j] = d.q[j], d.q[i]
+ d.q[i].heapIndex = i
+ d.q[j].heapIndex = j
+}
+
+func (d *dijkstra) Push(x interface{}) {
+ p := x.(*dpos)
+ p.heapIndex = len(d.q)
+ d.q = append(d.q, p)
+}
+
+func (d *dijkstra) Pop() interface{} {
+ n := len(d.q)
+ x := d.q[n-1]
+ d.q = d.q[:n-1]
+ x.heapIndex = -1
+ return x
+}
diff --git a/vendor/github.com/mattermost/rsc/rosetta/maze/Makefile b/vendor/github.com/mattermost/rsc/rosetta/maze/Makefile
new file mode 100644
index 000000000..8a83abd05
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/rosetta/maze/Makefile
@@ -0,0 +1,8 @@
+include $(GOROOT)/src/Make.inc
+
+TARG=maze
+GOFILES=\
+ maze.go\
+
+include $(GOROOT)/src/Make.cmd
+
diff --git a/vendor/github.com/mattermost/rsc/rosetta/maze/maze.go b/vendor/github.com/mattermost/rsc/rosetta/maze/maze.go
new file mode 100644
index 000000000..3cd15d04f
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/rosetta/maze/maze.go
@@ -0,0 +1,191 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Rosetta Code-inspired maze generator and solver.
+// Demonstrates use of interfaces to separate algorithm
+// implementations (graph.ShortestPath, heap.*) from data.
+// (In contrast, multiple inheritance approaches require
+// you to store their data in your data structures as part
+// of the inheritance.)
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "math/rand"
+ "time"
+
+ "github.com/mattermost/rsc/rosetta/graph"
+)
+
+type Maze struct {
+ w, h int
+ grid [][]walls
+}
+
+type Dir uint
+
+const (
+ North Dir = iota
+ East
+ West
+ South
+)
+
+type walls uint8
+
+const allWalls walls = 1<<North | 1<<East | 1<<South | 1<<West
+
+var dirs = []struct {
+ δx, δy int
+}{
+ {0, -1},
+ {1, 0},
+ {-1, 0},
+ {0, 1},
+}
+
+// move returns the cell in the direction dir from position r, c.
+// It returns ok==false if there is no cell in that direction.
+func (m *Maze) move(x, y int, dir Dir) (nx, ny int, ok bool) {
+ nx = x + dirs[dir].δx
+ ny = y + dirs[dir].δy
+ ok = 0 <= nx && nx < m.w && 0 <= ny && ny < m.h
+ return
+}
+
+// Move returns the cell in the direction dir from position x, y
+// It returns ok==false if there is no cell in that direction
+// or if a wall blocks movement in that direction.
+func (m *Maze) Move(x, y int, dir Dir) (nx, ny int, ok bool) {
+ nx, ny, ok = m.move(x, y, dir)
+ ok = ok && m.grid[y][x]&(1<<dir) == 0
+ return
+}
+
+// NewMaze returns a new, randomly generated maze
+// of width w and height h.
+func NewMaze(w, h int) *Maze {
+ // Allocate one slice for the whole 2-d cell grid and break up into rows.
+ all := make([]walls, w*h)
+ for i := range all {
+ all[i] = allWalls
+ }
+ m := &Maze{w: w, h: h, grid: make([][]walls, h)}
+ for i := range m.grid {
+ m.grid[i], all = all[:w], all[w:]
+ }
+
+ // All cells start with all walls.
+ m.generate(rand.Intn(w), rand.Intn(h))
+
+ return m
+}
+
+func (m *Maze) generate(x, y int) {
+ i := rand.Intn(4)
+ for j := 0; j < 4; j++ {
+ dir := Dir(i+j) % 4
+ if nx, ny, ok := m.move(x, y, dir); ok && m.grid[ny][nx] == allWalls {
+ // break down wall
+ m.grid[y][x] &^= 1 << dir
+ m.grid[ny][nx] &^= 1 << (3 - dir)
+ m.generate(nx, ny)
+ }
+ }
+}
+
+// String returns a multi-line string representation of the maze.
+func (m *Maze) String() string {
+ return m.PathString(nil)
+}
+
+// PathString returns the multi-line string representation of the
+// maze with the path marked on it.
+func (m *Maze) PathString(path []graph.Vertex) string {
+ var b bytes.Buffer
+ wall := func(w, m walls, ch byte) {
+ if w&m != 0 {
+ b.WriteByte(ch)
+ } else {
+ b.WriteByte(' ')
+ }
+ }
+ for _, row := range m.grid {
+ b.WriteByte('+')
+ for _, cell := range row {
+ wall(cell, 1<<North, '-')
+ b.WriteByte('+')
+ }
+ b.WriteString("\n")
+ for _, cell := range row {
+ wall(cell, 1<<West, '|')
+ b.WriteByte(' ')
+ }
+ b.WriteString("|\n")
+ }
+ for i := 0; i < m.w; i++ {
+ b.WriteString("++")
+ }
+ b.WriteString("+")
+ grid := b.Bytes()
+
+ // Overlay path.
+ last := -1
+ for _, v := range path {
+ p := v.(pos)
+ i := (2*m.w+2)*(2*p.y+1) + 2*p.x + 1
+ grid[i] = '#'
+ if last != -1 {
+ grid[(i+last)/2] = '#'
+ }
+ last = i
+ }
+
+ return string(grid)
+}
+
+// Implement graph.Graph.
+
+type pos struct {
+ x, y int
+}
+
+func (p pos) String() string {
+ return fmt.Sprintf("%d,%d", p.x, p.y)
+}
+
+func (m *Maze) Neighbors(v graph.Vertex) []graph.Vertex {
+ p := v.(pos)
+ var neighbors []graph.Vertex
+ for dir := North; dir <= South; dir++ {
+ if nx, ny, ok := m.Move(p.x, p.y, dir); ok {
+ neighbors = append(neighbors, pos{nx, ny})
+ }
+ }
+ return neighbors
+}
+
+func (m *Maze) NumVertex() int {
+ return m.w * m.h
+}
+
+func (m *Maze) VertexID(v graph.Vertex) int {
+ p := v.(pos)
+ return p.y*m.w + p.x
+}
+
+func (m *Maze) Vertex(x, y int) graph.Vertex {
+ return pos{x, y}
+}
+
+func main() {
+ const w, h = 30, 10
+ rand.Seed(time.Now().UnixNano())
+
+ m := NewMaze(w, h)
+ path := graph.ShortestPath(m, m.Vertex(0, 0), m.Vertex(w-1, h-1))
+ fmt.Println(m.PathString(path))
+}
diff --git a/vendor/github.com/mattermost/rsc/s3get/main.go b/vendor/github.com/mattermost/rsc/s3get/main.go
new file mode 100644
index 000000000..579e8bb5f
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/s3get/main.go
@@ -0,0 +1,85 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// S3get fetches a single object from or lists the objects in an S3 bucket.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+
+ "github.com/mattermost/rsc/keychain"
+ "launchpad.net/goamz/aws"
+ "launchpad.net/goamz/s3"
+)
+
+var list = flag.Bool("l", false, "list buckets")
+var delim = flag.String("d", "", "list delimiter")
+
+func usage() {
+ fmt.Fprintf(os.Stderr, `usage: s3get [-l] bucket path
+
+s3get fetches a single object from or lists the objects
+in an S3 bucket.
+
+The -l flag causes s3get to list available paths.
+When using -l, path may be omitted.
+Otherwise the listing begins at path.
+
+s3get uses the user name and password in the local
+keychain for the server 's3.amazonaws.com' as the S3
+access key (user name) and secret key (password).
+`)
+ os.Exit(2)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ var buck, obj string
+ args := flag.Args()
+ switch len(args) {
+ case 1:
+ buck = args[0]
+ if !*list {
+ fmt.Fprintf(os.Stderr, "must specify path when not using -l")
+ os.Exit(2)
+ }
+ case 2:
+ buck = args[0]
+ obj = args[1]
+ default:
+ usage()
+ }
+
+ access, secret, err := keychain.UserPasswd("s3.amazonaws.com", "")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ auth := aws.Auth{AccessKey: access, SecretKey: secret}
+
+ b := s3.New(auth, aws.USEast).Bucket(buck)
+ if *list {
+ objs, prefixes, err := b.List("", *delim, obj, 0)
+ if err != nil {
+ log.Fatal(err)
+ }
+ for _, p := range prefixes {
+ fmt.Printf("%s\n", p)
+ }
+ for _, obj := range objs {
+ fmt.Printf("%s\n", obj.Key)
+ }
+ return
+ }
+
+ data, err := b.Get(obj)
+ if err != nil {
+ log.Fatal(err)
+ }
+ os.Stdout.Write(data)
+}
diff --git a/vendor/github.com/mattermost/rsc/smugmug/smug.go b/vendor/github.com/mattermost/rsc/smugmug/smug.go
new file mode 100644
index 000000000..8cb662223
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/smugmug/smug.go
@@ -0,0 +1,542 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package smugmug uses the SmugMug API to manipulate photo albums
+// stored on smugmug.com.
+package smugmug
+
+import (
+ "bytes"
+ "crypto/md5"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+)
+
+const smugUploadHost = "upload.smugmug.com"
+const smugAPI = "1.2.2"
+const smugURL = "https://secure.smugmug.com/services/api/json/" + smugAPI + "/"
+const smugURLUnencrypted = "http://api.smugmug.com/services/api/json/" + smugAPI + "/"
+
+// A Conn represents an authenticated connection to the SmugMug server.
+type Conn struct {
+ sessid string
+ apiKey string
+
+ NickName string
+}
+
+// A Category represents a single album category.
+type Category struct {
+ ID int `json:"id"`
+ Name string
+}
+
+type smugResult struct {
+ Stat string `json:"stat"`
+ Message string `json:"message"`
+}
+
+type loginResult struct {
+ Login struct {
+ Session struct {
+ ID string `json:"id"`
+ }
+ User struct {
+ ID int `json:"id"`
+ NickName string
+ DisplayName string
+ }
+ }
+}
+
+// Login logs into the SmugMug server with the given email address and password.
+// The apikey argument is the API Key for your application.
+// To obtain an API Key, see http://www.smugmug.com/hack/apikeys.
+func Login(email, passwd, apikey string) (*Conn, error) {
+ c := &Conn{}
+ var out loginResult
+ if err := c.do("smugmug.login.withPassword", &out, "APIKey", apikey, "EmailAddress", email, "Password", passwd); err != nil {
+ return nil, err
+ }
+
+ c.sessid = out.Login.Session.ID
+ if c.sessid == "" {
+ return nil, fmt.Errorf("SmugMug login appeared to succeed but did not return session ID")
+ }
+
+ c.NickName = out.Login.User.NickName
+ if c.NickName == "" {
+ return nil, fmt.Errorf("SmugMug login appeared to succeed but did not return User NickName")
+ }
+
+ return c, nil
+}
+
+// Categories returns the album categories for the user identified by the nick name.
+func (c *Conn) Categories(nick string) ([]*Category, error) {
+ var out struct {
+ Categories []*Category
+ }
+ if err := c.do("smugmug.categories.get", &out, "NickName", nick); err != nil {
+ return nil, err
+ }
+ return out.Categories, nil
+}
+
+// CreateCategory creates a category with the given name.
+func (c *Conn) CreateCategory(name string) (*Category, error) {
+ var out struct {
+ Category *Category
+ }
+ if err := c.do("smugmug.categories.create", &out, "Name", name); err != nil {
+ return nil, err
+ }
+ return out.Category, nil
+}
+
+// DeleteCategory deletes the category.
+func (c *Conn) DeleteCategory(cat *Category) error {
+ return c.do("smugmug.categories.delete", nil, "CategoryID", strconv.Itoa(cat.ID))
+}
+
+// An Album represents a single photo album.
+type Album struct {
+ ID int `json:"id"`
+ Key string
+ Title string
+ URL string
+}
+
+// Albums returns the albums for the user identified by the nick name.
+// Use c.NickName for the logged-in user.
+func (c *Conn) Albums(nick string) ([]*Album, error) {
+ var out struct {
+ Albums []*Album
+ }
+ if err := c.do("smugmug.albums.get", &out, "NickName", nick); err != nil {
+ return nil, err
+ }
+ return out.Albums, nil
+}
+
+// CreateAlbum creates a new album.
+func (c *Conn) CreateAlbum(title string) (*Album, error) {
+ var out struct {
+ Album *Album
+ }
+ if err := c.do("smugmug.albums.create", &out,
+ "Title", title,
+ "Public", "0",
+ "WorldSearchable", "0",
+ "SmugSearchable", "0",
+ ); err != nil {
+ return nil, err
+ }
+
+ if out.Album == nil || out.Album.Key == "" {
+ return nil, fmt.Errorf("unable to parse SmugMug result")
+ }
+ return out.Album, nil
+}
+
+// AlbumInfo returns detailed metadata about an album.
+func (c *Conn) AlbumInfo(album *Album) (*AlbumInfo, error) {
+ var out struct {
+ Album *AlbumInfo
+ }
+ if err := c.do("smugmug.albums.getInfo", &out,
+ "AlbumID", strconv.Itoa(album.ID),
+ "AlbumKey", album.Key,
+ ); err != nil {
+ return nil, err
+ }
+
+ if out.Album == nil || out.Album.ID == 0 {
+ return nil, fmt.Errorf("unable to parse SmugMug result")
+ }
+ return out.Album, nil
+}
+
+// An AlbumInfo lists the metadata for an album.
+type AlbumInfo struct {
+ ID int `json:"id"`
+ Key string
+ Title string
+
+ Backprinting string
+ BoutiquePackaging int
+ CanRank bool
+ Category *Category
+ Clean bool
+ ColorCorrection int
+ Comments bool
+ Community struct {
+ ID int `json:"id"`
+ Name string
+ }
+ Description string
+ EXIF bool
+ External bool
+ FamilyEdit bool
+ Filenames bool
+ FriendEdit bool
+ Geography bool
+ Header bool
+ HideOwner bool
+ Highlight struct {
+ ID int `json:"id"`
+ Key string
+ Type string
+ }
+ ImageCount int
+ InterceptShipping int
+ Keywords string
+ Larges bool
+ LastUpdated string
+ NiceName string
+ Originals bool
+ PackagingBranding bool
+ Password string
+ PasswordHint string
+ Passworded bool
+ Position int
+ Printable bool
+ Printmark struct {
+ ID int `json:"id"`
+ Name string
+ }
+ ProofDays int
+ Protected bool
+ Public bool
+ Share bool
+ SmugSearchable bool
+ SortDirection bool
+ SortMethod string
+ SquareThumbs bool
+ SubCategory *Category
+ Template struct {
+ ID int `json:"id"`
+ }
+ Theme struct {
+ ID int `json:"id"`
+ Key string
+ Type string
+ }
+ URL string
+ UnsharpAmount float64
+ UnsharpRadius float64
+ UnsharpSigma float64
+ Watermark struct {
+ ID int `json:"id"`
+ Name string
+ }
+ Watermarking bool
+ WorldSearchable bool
+ X2Larges bool
+ X3Larges bool
+ XLarges bool
+}
+
+// ChangeAlbum changes an album's settings.
+// The argument list is a sequence of key, value pairs.
+// The keys are the names of AlbumInfo struct fields,
+// and the values are string values. For a boolean field,
+// use "0" for false and "1" for true.
+//
+// Example:
+// c.ChangeAlbum(a, "Larges", "1", "Title", "My Album")
+//
+func (c *Conn) ChangeAlbum(album *Album, args ...string) error {
+ callArgs := append([]string{"AlbumID", strconv.Itoa(album.ID)}, args...)
+ return c.do("smugmug.albums.changeSettings", nil, callArgs...)
+}
+
+// DeleteAlbum deletes an album.
+func (c *Conn) DeleteAlbum(album *Album) error {
+ return c.do("smugmug.albums.delete", nil, "AlbumID", strconv.Itoa(album.ID))
+}
+
+// An Image represents a single SmugMug image.
+type Image struct {
+ ID int `json:"id"`
+ Key string
+ URL string
+}
+
+// Images returns a list of images for an album.
+func (c *Conn) Images(album *Album) ([]*Image, error) {
+ var out struct {
+ Album struct {
+ Images []*Image
+ }
+ }
+
+ if err := c.do("smugmug.images.get", &out,
+ "AlbumID", strconv.Itoa(album.ID),
+ "AlbumKey", album.Key,
+ "Heavy", "1",
+ ); err != nil {
+ return nil, err
+ }
+
+ return out.Album.Images, nil
+}
+
+// An ImageInfo lists the metadata for an image.
+type ImageInfo struct {
+ ID int `json:"id"`
+ Key string
+ Album *Album
+ Altitude int
+ Caption string
+ Date string
+ FileName string
+ Duration int
+ Format string
+ Height int
+ Hidden bool
+ Keywords string
+ LargeURL string
+ LastUpdated string
+ Latitude float64
+ LightboxURL string
+ Longitude float64
+ MD5Sum string
+ MediumURL string
+ OriginalURL string
+ Position int
+ Serial int
+ Size int
+ SmallURL string
+ ThumbURL string
+ TinyURL string
+ Video320URL string
+ Video640URL string
+ Video960URL string
+ Video1280URL string
+ Video1920URL string
+ Width int
+ X2LargeURL string
+ X3LargeURL string
+ XLargeURL string
+}
+
+// ImageInfo returns detailed metadata about an image.
+func (c *Conn) ImageInfo(image *Image) (*ImageInfo, error) {
+ var out struct {
+ Image *ImageInfo
+ }
+ if err := c.do("smugmug.images.getInfo", &out,
+ "ImageID", strconv.Itoa(image.ID),
+ "ImageKey", image.Key,
+ ); err != nil {
+ return nil, err
+ }
+
+ if out.Image == nil || out.Image.ID == 0 {
+ return nil, fmt.Errorf("unable to parse SmugMug result")
+ }
+ return out.Image, nil
+}
+
+// ChangeImage changes an image's settings.
+// The argument list is a sequence of key, value pairs.
+// The keys are the names of ImageInfo struct fields,
+// and the values are string values. For a boolean field,
+// use "0" for false and "1" for true.
+//
+// Example:
+// c.ChangeImage(a, "Caption", "me!", "Hidden", "0")
+//
+func (c *Conn) ChangeImage(image *Image, args ...string) error {
+ callArgs := append([]string{"ImageID", strconv.Itoa(image.ID)}, args...)
+ return c.do("smugmug.images.changeSettings", nil, callArgs...)
+}
+
+// An ImageEXIF lists the EXIF data associated with an image.
+type ImageEXIF struct {
+ ID int `json:"id"`
+ Key string
+ Aperture string
+ Brightness string
+ CCDWidth string
+ ColorSpace int
+ CompressedBitsPerPixel string
+ Contrast int
+ DateTime string
+ DateTimeDigitized string
+ DateTimeOriginal string
+ DigitalZoomRatio string
+ ExposureBiasValue string
+ ExposureMode int
+ ExposureProgram int
+ ExposureTime string
+ Flash int
+ FocalLength string
+ FocalLengthIn35mmFilm string
+ ISO int
+ LightSource int
+ Make string
+ Metering int
+ Model string
+ Saturation int
+ SensingMethod int
+ Sharpness int
+ SubjectDistance string
+ SubjectDistanceRange int
+ WhiteBalance int
+}
+
+// ImageInfo returns the EXIF data for an image.
+func (c *Conn) ImageEXIF(image *Image) (*ImageEXIF, error) {
+ var out struct {
+ Image *ImageEXIF
+ }
+ if err := c.do("smugmug.images.getEXIF", &out,
+ "ImageID", strconv.Itoa(image.ID),
+ "ImageKey", image.Key,
+ ); err != nil {
+ return nil, err
+ }
+
+ if out.Image == nil || out.Image.ID == 0 {
+ return nil, fmt.Errorf("unable to parse SmugMug result")
+ }
+ return out.Image, nil
+}
+
+// DeleteImage deletes an image.
+func (c *Conn) DeleteImage(image *Image) error {
+ return c.do("smugmug.images.delete", nil, "ImageID", strconv.Itoa(image.ID))
+}
+
+// AddImage uploads a new image to an album.
+// The name is the file name that will be displayed on SmugMug.
+// The data is the raw image data.
+func (c *Conn) AddImage(name string, data []byte, a *Album) (*Image, error) {
+ return c.upload(name, data, "AlbumID", a.ID)
+}
+
+// ReplaceImage replaces an image.
+// The name is the file name that will be displayed on SmugMug.
+// The data is the raw image data.
+func (c *Conn) ReplaceImage(name string, data []byte, image *Image) (*Image, error) {
+ return c.upload(name, data, "ImageID", image.ID)
+}
+
+func (c *Conn) upload(name string, data []byte, idkind string, id int) (*Image, error) {
+ h := md5.New()
+ h.Write(data)
+ digest := fmt.Sprintf("%x", h.Sum(nil))
+
+ req := &http.Request{
+ Method: "PUT",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: smugUploadHost,
+ Path: "/" + name,
+ },
+ ContentLength: int64(len(data)),
+ Header: http.Header{
+ "Content-MD5": {digest},
+ "X-Smug-SessionID": {c.sessid},
+ "X-Smug-Version": {smugAPI},
+ "X-Smug-ResponseType": {"JSON"},
+ "X-Smug-" + idkind: {strconv.Itoa(id)},
+ "X-Smug-FileName": {name},
+ },
+ Body: ioutil.NopCloser(bytes.NewBuffer(data)),
+ }
+
+ r, err := http.DefaultTransport.RoundTrip(req)
+ if err != nil {
+ return nil, fmt.Errorf("upload %s: %s", name, err)
+ }
+
+ var out struct {
+ Image *Image
+ }
+ if err := c.parseResult("upload", r, &out); err != nil {
+ return nil, fmt.Errorf("upload %s: %s", name, err)
+ }
+ return out.Image, nil
+}
+
+func (c *Conn) do(method string, dst interface{}, args ...string) (err error) {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("%s: %s", method, err)
+ }
+ }()
+
+ form := url.Values{
+ "method": {method},
+ "APIKey": {c.apiKey},
+ "Pretty": {"1"}, // nice-looking JSON
+ }
+ if c.sessid != "" {
+ form["SessionID"] = []string{c.sessid}
+ }
+ for i := 0; i < len(args); i += 2 {
+ key, val := args[i], args[i+1]
+ form[key] = []string{val}
+ }
+
+ url := smugURL
+ if !strings.Contains(method, "login") {
+ // I'd really prefer to use HTTPS for everything,
+ // but I get "invalid API key" if I do.
+ url = smugURLUnencrypted
+ }
+ r, err := http.Post(url, "application/x-www-form-urlencoded", strings.NewReader(form.Encode()))
+ if err != nil {
+ return err
+ }
+
+ return c.parseResult(method, r, dst)
+}
+
+func (c *Conn) parseResult(method string, r *http.Response, dst interface{}) error {
+ defer r.Body.Close()
+ if r.StatusCode != 200 {
+ return fmt.Errorf("HTTP %s", r.Status)
+ }
+ data, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return fmt.Errorf("reading body: %s", err)
+ }
+
+ var res smugResult
+ if err := json.Unmarshal(data, &res); err != nil {
+ return fmt.Errorf("parsing JSON result: %s", err)
+ }
+
+ // If there are no images, that's not an error.
+ // But SmugMug says it is.
+ if res.Stat == "fail" && method == "smugmug.images.get" && res.Message == "empty set - no images found" {
+ res.Stat = "ok"
+ data = []byte(`{"Images": []}`)
+ }
+
+ if res.Stat != "ok" {
+ msg := res.Stat
+ if res.Message != "" {
+ msg = res.Message
+ }
+ return fmt.Errorf("%s", msg)
+ }
+
+ if dst != nil {
+ if err := json.Unmarshal(data, dst); err != nil {
+ return fmt.Errorf("parsing JSON result: %s", err)
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/mattermost/rsc/smugmug/smugup/main.go b/vendor/github.com/mattermost/rsc/smugmug/smugup/main.go
new file mode 100644
index 000000000..0b40e9db6
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/smugmug/smugup/main.go
@@ -0,0 +1,158 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Smugup uploads a collection of photos to SmugMug.
+//
+// Run 'smugup -help' for details.
+package main
+
+import (
+ "crypto/md5"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+
+ "github.com/mattermost/rsc/keychain"
+ "github.com/mattermost/rsc/smugmug"
+)
+
+const apiKey = "8qH4UgiunBKpsYpvcBXftbCYNEreAZ0m"
+
+var usageMessage = `usage: smugup [options] 'album title' [photo.jpg ...]
+
+Smugup creates a new album with the given title if one does not already exist.
+Then uploads the list of images to the album. If a particular image
+already exists in the album, the JPG replaces the album image if the
+contents differ.
+
+Smugup fetches the SmugMug user name and password from the
+user's keychain.
+
+By default, new albums are created as private as possible: not public,
+not world searchable, and not SmugMug-searchable.
+
+Smugup prints the URL for the album when finished.
+
+The options are:
+
+ -u user
+ SmugMug user account name (email address).
+ This is not typically needed, as the user name found in the keychain will be used.
+`
+
+var smugUser = flag.String("u", "", "SmugMug user name")
+
+func usage() {
+ fmt.Fprint(os.Stderr, usageMessage)
+ os.Exit(2)
+}
+
+func main() {
+ flag.Usage = usage
+ flag.Parse()
+ log.SetFlags(0)
+
+ args := flag.Args()
+ if len(args) < 1 {
+ usage()
+ }
+ title, files := args[0], args[1:]
+
+ user, passwd, err := keychain.UserPasswd("smugmug.com", *smugUser)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ smug, err := smugmug.Login(user, passwd, apiKey)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ albums, err := smug.Albums(smug.NickName)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var a *smugmug.Album
+ for _, a = range albums {
+ if a.Title == title {
+ goto HaveAlbum
+ }
+ }
+
+ a, err = smug.CreateAlbum(title)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+HaveAlbum:
+ imageFiles := map[string]*smugmug.ImageInfo{}
+ if len(files) > 0 {
+ images, err := smug.Images(a)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ n := 0
+ c := make(chan *smugmug.ImageInfo)
+ rate := make(chan bool, 4)
+ for _, image := range images {
+ go func(image *smugmug.Image) {
+ rate <- true
+ info, err := smug.ImageInfo(image)
+ <-rate
+ if err != nil {
+ log.Print(err)
+ c <- nil
+ return
+ }
+ c <- info
+ }(image)
+ n++
+ }
+
+ for i := 0; i < n; i++ {
+ info := <-c
+ if info == nil {
+ continue
+ }
+ imageFiles[info.FileName] = info
+ }
+ }
+
+ for _, file := range files {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Print(err)
+ continue
+ }
+ _, elem := filepath.Split(file)
+ info := imageFiles[elem]
+ if info != nil {
+ h := md5.New()
+ h.Write(data)
+ digest := fmt.Sprintf("%x", h.Sum(nil))
+ if digest == info.MD5Sum {
+ // Already have that image.
+ continue
+ }
+ _, err = smug.ReplaceImage(file, data, &smugmug.Image{ID: info.ID})
+ } else {
+ _, err = smug.AddImage(file, data, a)
+ }
+ if err != nil {
+ log.Print(err)
+ }
+ }
+
+ info, err := smug.AlbumInfo(a)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%s\n", info.URL)
+}
diff --git a/vendor/github.com/mattermost/rsc/tmp/app b/vendor/github.com/mattermost/rsc/tmp/app
new file mode 120000
index 000000000..5df94d993
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/app
@@ -0,0 +1 @@
+../app \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/appfs b/vendor/github.com/mattermost/rsc/tmp/appfs
new file mode 120000
index 000000000..d38e0b442
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/appfs
@@ -0,0 +1 @@
+../appfs \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/arq b/vendor/github.com/mattermost/rsc/tmp/arq
new file mode 120000
index 000000000..25b25add9
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/arq
@@ -0,0 +1 @@
+../arq \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/blog b/vendor/github.com/mattermost/rsc/tmp/blog
new file mode 120000
index 000000000..c9e36e109
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/blog
@@ -0,0 +1 @@
+../blog \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/cmd b/vendor/github.com/mattermost/rsc/tmp/cmd
new file mode 120000
index 000000000..9287aae2a
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/cmd
@@ -0,0 +1 @@
+../cmd \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/crypt b/vendor/github.com/mattermost/rsc/tmp/crypt
new file mode 120000
index 000000000..22e80df6e
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/crypt
@@ -0,0 +1 @@
+../crypt \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/devweb b/vendor/github.com/mattermost/rsc/tmp/devweb
new file mode 120000
index 000000000..27bf20aa9
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/devweb
@@ -0,0 +1 @@
+../devweb \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/fuse b/vendor/github.com/mattermost/rsc/tmp/fuse
new file mode 120000
index 000000000..dad1b521b
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/fuse
@@ -0,0 +1 @@
+../fuse \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/gf256 b/vendor/github.com/mattermost/rsc/tmp/gf256
new file mode 120000
index 000000000..386a8217c
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/gf256
@@ -0,0 +1 @@
+../gf256 \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/google b/vendor/github.com/mattermost/rsc/tmp/google
new file mode 120000
index 000000000..cb899d262
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/google
@@ -0,0 +1 @@
+../google \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/gtfs b/vendor/github.com/mattermost/rsc/tmp/gtfs
new file mode 120000
index 000000000..a1dc5a7b6
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/gtfs
@@ -0,0 +1 @@
+../gtfs \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/imap b/vendor/github.com/mattermost/rsc/tmp/imap
new file mode 120000
index 000000000..006bdcfdf
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/imap
@@ -0,0 +1 @@
+../imap \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/keychain b/vendor/github.com/mattermost/rsc/tmp/keychain
new file mode 120000
index 000000000..4f18ef52d
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/keychain
@@ -0,0 +1 @@
+../keychain \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/mbta b/vendor/github.com/mattermost/rsc/tmp/mbta
new file mode 120000
index 000000000..858cac3c2
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/mbta
@@ -0,0 +1 @@
+../mbta \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/mkapp b/vendor/github.com/mattermost/rsc/tmp/mkapp
new file mode 120000
index 000000000..a60312f7d
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/mkapp
@@ -0,0 +1 @@
+../mkapp \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/plist b/vendor/github.com/mattermost/rsc/tmp/plist
new file mode 120000
index 000000000..9dc5f2029
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/plist
@@ -0,0 +1 @@
+../plist \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/qr b/vendor/github.com/mattermost/rsc/tmp/qr
new file mode 120000
index 000000000..78b229bd3
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/qr
@@ -0,0 +1 @@
+../qr \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/regexp b/vendor/github.com/mattermost/rsc/tmp/regexp
new file mode 120000
index 000000000..be8f6fd71
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/regexp
@@ -0,0 +1 @@
+../regexp \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/rosetta b/vendor/github.com/mattermost/rsc/tmp/rosetta
new file mode 120000
index 000000000..deb14d791
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/rosetta
@@ -0,0 +1 @@
+../rosetta \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/s3get b/vendor/github.com/mattermost/rsc/tmp/s3get
new file mode 120000
index 000000000..1bb5ed3a3
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/s3get
@@ -0,0 +1 @@
+../s3get \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/smugmug b/vendor/github.com/mattermost/rsc/tmp/smugmug
new file mode 120000
index 000000000..97f9b8229
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/smugmug
@@ -0,0 +1 @@
+../smugmug \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/tmp/xmpp b/vendor/github.com/mattermost/rsc/tmp/xmpp
new file mode 120000
index 000000000..f8abedc7c
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/tmp/xmpp
@@ -0,0 +1 @@
+../xmpp \ No newline at end of file
diff --git a/vendor/github.com/mattermost/rsc/xmpp/xmpp.go b/vendor/github.com/mattermost/rsc/xmpp/xmpp.go
new file mode 100644
index 000000000..6fa7e43cb
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/xmpp/xmpp.go
@@ -0,0 +1,572 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(rsc):
+// More precise error handling.
+// Presence functionality.
+// TODO(mattn):
+// Add proxy authentication.
+
+// Package xmpp implements a simple Google Talk client
+// using the XMPP protocol described in RFC 3920 and RFC 3921.
+package xmpp
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/tls"
+ "encoding/base64"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+)
+
+const (
+ nsStream = "http://etherx.jabber.org/streams"
+ nsTLS = "urn:ietf:params:xml:ns:xmpp-tls"
+ nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
+ nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
+ nsClient = "jabber:client"
+)
+
+var DefaultConfig tls.Config
+
+type Client struct {
+ tls *tls.Conn // connection to server
+ jid string // Jabber ID for our connection
+ p *xml.Decoder
+}
+
+// NewClient creates a new connection to a host given as "hostname" or "hostname:port".
+// If host is not specified, the DNS SRV should be used to find the host from the domainpart of the JID.
+// Default the port to 5222.
+func NewClient(host, user, passwd string) (*Client, error) {
+ addr := host
+
+ if strings.TrimSpace(host) == "" {
+ a := strings.SplitN(user, "@", 2)
+ if len(a) == 2 {
+ host = a[1]
+ }
+ }
+ a := strings.SplitN(host, ":", 2)
+ if len(a) == 1 {
+ host += ":5222"
+ }
+ proxy := os.Getenv("HTTP_PROXY")
+ if proxy == "" {
+ proxy = os.Getenv("http_proxy")
+ }
+ if proxy != "" {
+ url, err := url.Parse(proxy)
+ if err == nil {
+ addr = url.Host
+ }
+ }
+ c, err := net.Dial("tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+
+ if proxy != "" {
+ fmt.Fprintf(c, "CONNECT %s HTTP/1.1\r\n", host)
+ fmt.Fprintf(c, "Host: %s\r\n", host)
+ fmt.Fprintf(c, "\r\n")
+ br := bufio.NewReader(c)
+ req, _ := http.NewRequest("CONNECT", host, nil)
+ resp, err := http.ReadResponse(br, req)
+ if err != nil {
+ return nil, err
+ }
+ if resp.StatusCode != 200 {
+ f := strings.SplitN(resp.Status, " ", 2)
+ return nil, errors.New(f[1])
+ }
+ }
+
+ tlsconn := tls.Client(c, &DefaultConfig)
+ if err = tlsconn.Handshake(); err != nil {
+ return nil, err
+ }
+
+ if strings.LastIndex(host, ":") > 0 {
+ host = host[:strings.LastIndex(host, ":")]
+ }
+ if err = tlsconn.VerifyHostname(host); err != nil {
+ return nil, err
+ }
+
+ client := new(Client)
+ client.tls = tlsconn
+ if err := client.init(user, passwd); err != nil {
+ client.Close()
+ return nil, err
+ }
+ return client, nil
+}
+
+func (c *Client) Close() error {
+ return c.tls.Close()
+}
+
+func (c *Client) init(user, passwd string) error {
+ // For debugging: the following causes the plaintext of the connection to be duplicated to stdout.
+ // c.p = xml.NewParser(tee{c.tls, os.Stdout});
+ c.p = xml.NewDecoder(c.tls)
+
+ a := strings.SplitN(user, "@", 2)
+ if len(a) != 2 {
+ return errors.New("xmpp: invalid username (want user@domain): " + user)
+ }
+ user = a[0]
+ domain := a[1]
+
+ // Declare intent to be a jabber client.
+ fmt.Fprintf(c.tls, "<?xml version='1.0'?>\n"+
+ "<stream:stream to='%s' xmlns='%s'\n"+
+ " xmlns:stream='%s' version='1.0'>\n",
+ xmlEscape(domain), nsClient, nsStream)
+
+ // Server should respond with a stream opening.
+ se, err := nextStart(c.p)
+ if err != nil {
+ return err
+ }
+ if se.Name.Space != nsStream || se.Name.Local != "stream" {
+ return errors.New("xmpp: expected <stream> but got <" + se.Name.Local + "> in " + se.Name.Space)
+ }
+
+ // Now we're in the stream and can use Unmarshal.
+ // Next message should be <features> to tell us authentication options.
+ // See section 4.6 in RFC 3920.
+ var f streamFeatures
+ if err = c.p.Decode(&f); err != nil {
+ return errors.New("unmarshal <features>: " + err.Error())
+ }
+ havePlain := false
+ for _, m := range f.Mechanisms.Mechanism {
+ if m == "PLAIN" {
+ havePlain = true
+ break
+ }
+ }
+ if !havePlain {
+ return errors.New(fmt.Sprintf("PLAIN authentication is not an option: %v", f.Mechanisms.Mechanism))
+ }
+
+ // Plain authentication: send base64-encoded \x00 user \x00 password.
+ raw := "\x00" + user + "\x00" + passwd
+ enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
+ base64.StdEncoding.Encode(enc, []byte(raw))
+ fmt.Fprintf(c.tls, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>\n",
+ nsSASL, enc)
+
+ // Next message should be either success or failure.
+ name, val, err := next(c.p)
+ switch v := val.(type) {
+ case *saslSuccess:
+ case *saslFailure:
+ // v.Any is type of sub-element in failure,
+ // which gives a description of what failed.
+ return errors.New("auth failure: " + v.Any.Local)
+ default:
+ return errors.New("expected <success> or <failure>, got <" + name.Local + "> in " + name.Space)
+ }
+
+ // Now that we're authenticated, we're supposed to start the stream over again.
+ // Declare intent to be a jabber client.
+ fmt.Fprintf(c.tls, "<stream:stream to='%s' xmlns='%s'\n"+
+ " xmlns:stream='%s' version='1.0'>\n",
+ xmlEscape(domain), nsClient, nsStream)
+
+ // Here comes another <stream> and <features>.
+ se, err = nextStart(c.p)
+ if err != nil {
+ return err
+ }
+ if se.Name.Space != nsStream || se.Name.Local != "stream" {
+ return errors.New("expected <stream>, got <" + se.Name.Local + "> in " + se.Name.Space)
+ }
+ if err = c.p.Decode(&f); err != nil {
+ // TODO: often stream stop.
+ //return os.NewError("unmarshal <features>: " + err.String())
+ }
+
+ // Send IQ message asking to bind to the local user name.
+ fmt.Fprintf(c.tls, "<iq type='set' id='x'><bind xmlns='%s'/></iq>\n", nsBind)
+ var iq clientIQ
+ if err = c.p.Decode(&iq); err != nil {
+ return errors.New("unmarshal <iq>: " + err.Error())
+ }
+ if &iq.Bind == nil {
+ return errors.New("<iq> result missing <bind>")
+ }
+ c.jid = iq.Bind.Jid // our local id
+
+ // We're connected and can now receive and send messages.
+ c.Status(Away, "")
+ return nil
+}
+
+type Chat struct {
+ Remote string
+ Type string
+ Text string
+ Roster Roster
+ Presence *Presence
+}
+
+type Roster []Contact
+
+type Contact struct {
+ Remote string
+ Name string
+ Group []string
+}
+
+type Presence struct {
+ Remote string
+ Status Status
+ StatusMsg string
+ Priority int
+}
+
+func atoi(s string) int {
+ if s == "" {
+ return 0
+ }
+ n, err := strconv.Atoi(s)
+ if err != nil {
+ n = -1
+ }
+ return n
+}
+
+func statusCode(s string) Status {
+ for i, ss := range statusName {
+ if s == ss {
+ return Status(i)
+ }
+ }
+ return Available
+}
+
+// Recv wait next token of chat.
+func (c *Client) Recv() (chat Chat, err error) {
+ for {
+ _, val, err := next(c.p)
+ if err != nil {
+ return Chat{}, err
+ }
+ switch val := val.(type) {
+ case *clientMessage:
+ return Chat{Remote: val.From, Type: val.Type, Text: val.Body}, nil
+ case *clientQuery:
+ var r Roster
+ for _, item := range val.Item {
+ r = append(r, Contact{item.Jid, item.Name, item.Group})
+ }
+ return Chat{Type: "roster", Roster: r}, nil
+ case *clientPresence:
+ pr := &Presence{Remote: val.From, Status: statusCode(val.Show), StatusMsg: val.Status, Priority: atoi(val.Priority)}
+ if val.Type == "unavailable" {
+ pr.Status = Unavailable
+ }
+ return Chat{Remote: val.From, Type: "presence", Presence: pr}, nil
+ default:
+ //log.Printf("ignoring %T", val)
+ }
+ }
+ panic("unreachable")
+}
+
+// Send sends message text.
+func (c *Client) Send(chat Chat) error {
+ fmt.Fprintf(c.tls, "<message to='%s' from='%s' type='chat' xml:lang='en'>"+
+ "<body>%s</body></message>",
+ xmlEscape(chat.Remote), xmlEscape(c.jid),
+ xmlEscape(chat.Text))
+ return nil
+}
+
+// Roster asks for the chat roster.
+func (c *Client) Roster() error {
+ fmt.Fprintf(c.tls, "<iq from='%s' type='get' id='roster1'><query xmlns='jabber:iq:roster'/></iq>\n", xmlEscape(c.jid))
+ return nil
+}
+
+type Status int
+
+const (
+ Unavailable Status = iota
+ DoNotDisturb
+ ExtendedAway
+ Away
+ Available
+)
+
+var statusName = []string{
+ Unavailable: "unavailable",
+ DoNotDisturb: "dnd",
+ ExtendedAway: "xa",
+ Away: "away",
+ Available: "chat",
+}
+
+func (s Status) String() string {
+ return statusName[s]
+}
+
+func (c *Client) Status(status Status, msg string) error {
+ fmt.Fprintf(c.tls, "<presence xml:lang='en'><show>%s</show><status>%s</status></presence>", status, xmlEscape(msg))
+ return nil
+}
+
+// RFC 3920 C.1 Streams name space
+
+type streamFeatures struct {
+ XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
+ StartTLS tlsStartTLS
+ Mechanisms saslMechanisms
+ Bind bindBind
+ Session bool
+}
+
+type streamError struct {
+ XMLName xml.Name `xml:"http://etherx.jabber.org/streams error"`
+ Any xml.Name
+ Text string
+}
+
+// RFC 3920 C.3 TLS name space
+
+type tlsStartTLS struct {
+ XMLName xml.Name `xml:":ietf:params:xml:ns:xmpp-tls starttls"`
+ Required bool
+}
+
+type tlsProceed struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls proceed"`
+}
+
+type tlsFailure struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-tls failure"`
+}
+
+// RFC 3920 C.4 SASL name space
+
+type saslMechanisms struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl mechanisms"`
+ Mechanism []string
+}
+
+type saslAuth struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"`
+ Mechanism string `xml:"attr"`
+}
+
+type saslChallenge string
+
+type saslResponse string
+
+type saslAbort struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl abort"`
+}
+
+type saslSuccess struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"`
+}
+
+type saslFailure struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl failure"`
+ Any xml.Name
+}
+
+// RFC 3920 C.5 Resource binding name space
+
+type bindBind struct {
+ XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
+ Resource string
+ Jid string
+}
+
+// RFC 3921 B.1 jabber:client
+
+type clientMessage struct {
+ XMLName xml.Name `xml:"jabber:client message"`
+ From string `xml:"attr"`
+ Id string `xml:"attr"`
+ To string `xml:"attr"`
+ Type string `xml:"attr"` // chat, error, groupchat, headline, or normal
+
+ // These should technically be []clientText,
+ // but string is much more convenient.
+ Subject string
+ Body string
+ Thread string
+}
+
+type clientText struct {
+ Lang string `xml:"attr"`
+ Body string `xml:"chardata"`
+}
+
+type clientPresence struct {
+ XMLName xml.Name `xml:"jabber:client presence"`
+ From string `xml:"attr"`
+ Id string `xml:"attr"`
+ To string `xml:"attr"`
+ Type string `xml:"attr"` // error, probe, subscribe, subscribed, unavailable, unsubscribe, unsubscribed
+ Lang string `xml:"attr"`
+
+ Show string // away, chat, dnd, xa
+ Status string // sb []clientText
+ Priority string
+ Error *clientError
+}
+
+type clientIQ struct { // info/query
+ XMLName xml.Name `xml:"jabber:client iq"`
+ From string `xml:"attr"`
+ Id string `xml:"attr"`
+ To string `xml:"attr"`
+ Type string `xml:"attr"` // error, get, result, set
+ Error clientError
+ Bind bindBind
+ Query clientQuery
+}
+
+type clientError struct {
+ XMLName xml.Name `xml:"jabber:client error"`
+ Code string `xml:"attr"`
+ Type string `xml:"attr"`
+ Any xml.Name
+ Text string
+}
+
+type clientQuery struct {
+ Item []rosterItem
+}
+
+type rosterItem struct {
+ XMLName xml.Name `xml:"jabber:iq:roster item"`
+ Jid string `xml:"attr"`
+ Name string `xml:"attr"`
+ Subscription string `xml:"attr"`
+ Group []string
+}
+
+// Scan XML token stream to find next StartElement.
+func nextStart(p *xml.Decoder) (xml.StartElement, error) {
+ for {
+ t, err := p.Token()
+ if err != nil {
+ log.Fatal("token", err)
+ }
+ switch t := t.(type) {
+ case xml.StartElement:
+ return t, nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Scan XML token stream for next element and save into val.
+// If val == nil, allocate new element based on proto map.
+// Either way, return val.
+func next(p *xml.Decoder) (xml.Name, interface{}, error) {
+ // Read start element to find out what type we want.
+ se, err := nextStart(p)
+ if err != nil {
+ return xml.Name{}, nil, err
+ }
+
+ // Put it in an interface and allocate one.
+ var nv interface{}
+ switch se.Name.Space + " " + se.Name.Local {
+ case nsStream + " features":
+ nv = &streamFeatures{}
+ case nsStream + " error":
+ nv = &streamError{}
+ case nsTLS + " starttls":
+ nv = &tlsStartTLS{}
+ case nsTLS + " proceed":
+ nv = &tlsProceed{}
+ case nsTLS + " failure":
+ nv = &tlsFailure{}
+ case nsSASL + " mechanisms":
+ nv = &saslMechanisms{}
+ case nsSASL + " challenge":
+ nv = ""
+ case nsSASL + " response":
+ nv = ""
+ case nsSASL + " abort":
+ nv = &saslAbort{}
+ case nsSASL + " success":
+ nv = &saslSuccess{}
+ case nsSASL + " failure":
+ nv = &saslFailure{}
+ case nsBind + " bind":
+ nv = &bindBind{}
+ case nsClient + " message":
+ nv = &clientMessage{}
+ case nsClient + " presence":
+ nv = &clientPresence{}
+ case nsClient + " iq":
+ nv = &clientIQ{}
+ case nsClient + " error":
+ nv = &clientError{}
+ default:
+ return xml.Name{}, nil, errors.New("unexpected XMPP message " +
+ se.Name.Space + " <" + se.Name.Local + "/>")
+ }
+
+ // Unmarshal into that storage.
+ if err = p.DecodeElement(nv, &se); err != nil {
+ return xml.Name{}, nil, err
+ }
+ return se.Name, nv, err
+}
+
+var xmlSpecial = map[byte]string{
+ '<': "&lt;",
+ '>': "&gt;",
+ '"': "&quot;",
+ '\'': "&apos;",
+ '&': "&amp;",
+}
+
+func xmlEscape(s string) string {
+ var b bytes.Buffer
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if s, ok := xmlSpecial[c]; ok {
+ b.WriteString(s)
+ } else {
+ b.WriteByte(c)
+ }
+ }
+ return b.String()
+}
+
+type tee struct {
+ r io.Reader
+ w io.Writer
+}
+
+func (t tee) Read(p []byte) (n int, err error) {
+ n, err = t.r.Read(p)
+ if n > 0 {
+ t.w.Write(p[0:n])
+ }
+ return
+}
diff --git a/vendor/github.com/mssola/user_agent/all_test.go b/vendor/github.com/mssola/user_agent/all_test.go
new file mode 100644
index 000000000..f76f2882f
--- /dev/null
+++ b/vendor/github.com/mssola/user_agent/all_test.go
@@ -0,0 +1,529 @@
+// Copyright (C) 2012-2016 Miquel Sabaté Solà <mikisabate@gmail.com>
+// This file is licensed under the MIT license.
+// See the LICENSE file.
+
+package user_agent
+
+import (
+ "fmt"
+ "testing"
+)
+
+// Slice that contains all the tests. Each test is contained in a struct
+// that groups the title of the test, the User-Agent string to be tested and the expected value.
+var uastrings = []struct {
+ title string
+ ua string
+ expected string
+}{
+ // Bots
+ {
+ title: "GoogleBot",
+ ua: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
+ expected: "Mozilla:5.0 Browser:Googlebot-2.1 Bot:true Mobile:false",
+ },
+ {
+ title: "GoogleBotSmartphone",
+ ua: "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
+ expected: "Mozilla:5.0 Browser:Googlebot-2.1 Bot:true Mobile:true",
+ },
+ {
+ title: "BingBot",
+ ua: "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)",
+ expected: "Mozilla:5.0 Browser:bingbot-2.0 Bot:true Mobile:false",
+ },
+ {
+ title: "BaiduBot",
+ ua: "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)",
+ expected: "Mozilla:5.0 Browser:Baiduspider-2.0 Bot:true Mobile:false",
+ },
+ {
+ title: "Twitterbot",
+ ua: "Twitterbot",
+ expected: "Browser:Twitterbot Bot:true Mobile:false",
+ },
+ {
+ title: "YahooBot",
+ ua: "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)",
+ expected: "Mozilla:5.0 Browser:Yahoo! Slurp Bot:true Mobile:false",
+ },
+ {
+ title: "FacebookExternalHit",
+ ua: "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)",
+ expected: "Browser:facebookexternalhit-1.1 Bot:true Mobile:false",
+ },
+ {
+ title: "FacebookPlatform",
+ ua: "facebookplatform/1.0 (+http://developers.facebook.com)",
+ expected: "Browser:facebookplatform-1.0 Bot:true Mobile:false",
+ },
+ {
+ title: "FaceBot",
+ ua: "Facebot",
+ expected: "Browser:Facebot Bot:true Mobile:false",
+ },
+ {
+ title: "NutchCVS",
+ ua: "NutchCVS/0.8-dev (Nutch; http://lucene.apache.org/nutch/bot.html; nutch-agent@lucene.apache.org)",
+ expected: "Browser:NutchCVS Bot:true Mobile:false",
+ },
+ {
+ title: "MJ12bot",
+ ua: "Mozilla/5.0 (compatible; MJ12bot/v1.2.4; http://www.majestic12.co.uk/bot.php?+)",
+ expected: "Mozilla:5.0 Browser:MJ12bot-v1.2.4 Bot:true Mobile:false",
+ },
+ {
+ title: "MJ12bot",
+ ua: "MJ12bot/v1.0.8 (http://majestic12.co.uk/bot.php?+)",
+ expected: "Browser:MJ12bot Bot:true Mobile:false",
+ },
+ {
+ title: "AhrefsBot",
+ ua: "Mozilla/5.0 (compatible; AhrefsBot/4.0; +http://ahrefs.com/robot/)",
+ expected: "Mozilla:5.0 Browser:AhrefsBot-4.0 Bot:true Mobile:false",
+ },
+
+ // Internet Explorer
+ {
+ title: "IE10",
+ ua: "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 8 Browser:Internet Explorer-10.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "Tablet",
+ ua: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.2; ARM; Trident/6.0; Touch; .NET4.0E; .NET4.0C; Tablet PC 2.0)",
+ expected: "Mozilla:4.0 Platform:Windows OS:Windows 8 Browser:Internet Explorer-10.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "Touch",
+ ua: "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 8 Browser:Internet Explorer-10.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "Phone",
+ ua: "Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; SAMSUNG; SGH-i917)",
+ expected: "Mozilla:4.0 Platform:Windows OS:Windows Phone OS 7.0 Browser:Internet Explorer-7.0 Engine:Trident Bot:false Mobile:true",
+ },
+ {
+ title: "IE6",
+ ua: "Mozilla/4.0 (compatible; MSIE6.0; Windows NT 5.0; .NET CLR 1.1.4322)",
+ expected: "Mozilla:4.0 Platform:Windows OS:Windows 2000 Browser:Internet Explorer-6.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "IE8Compatibility",
+ ua: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; MS-RTC LM 8)",
+ expected: "Mozilla:4.0 Platform:Windows OS:Windows 7 Browser:Internet Explorer-8.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "IE10Compatibility",
+ ua: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; InfoPath.3; MS-RTC LM 8)",
+ expected: "Mozilla:4.0 Platform:Windows OS:Windows 7 Browser:Internet Explorer-10.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "IE11Win81",
+ ua: "Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 8.1 Browser:Internet Explorer-11.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "IE11Win7",
+ ua: "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 7 Browser:Internet Explorer-11.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "IE11b32Win7b64",
+ ua: "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 7 Browser:Internet Explorer-11.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "IE11b32Win7b64MDDRJS",
+ ua: "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; MDDRJS; rv:11.0) like Gecko",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 7 Browser:Internet Explorer-11.0 Engine:Trident Bot:false Mobile:false",
+ },
+ {
+ title: "IE11Compatibility",
+ ua: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.3; Trident/7.0)",
+ expected: "Mozilla:4.0 Platform:Windows OS:Windows 8.1 Browser:Internet Explorer-7.0 Engine:Trident Bot:false Mobile:false",
+ },
+
+ // Microsoft Edge
+ {
+ title: "EdgeDesktop",
+ ua: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 10 Browser:Edge-12.10240 Engine:EdgeHTML Bot:false Mobile:false",
+ },
+ {
+ title: "EdgeMobile",
+ ua: "Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; DEVICE INFO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.10240",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows Phone 10.0 Browser:Edge-12.10240 Engine:EdgeHTML Bot:false Mobile:true",
+ },
+
+ // Gecko
+ {
+ title: "FirefoxMac",
+ ua: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0b8) Gecko/20100101 Firefox/4.0b8",
+ expected: "Mozilla:5.0 Platform:Macintosh OS:Intel Mac OS X 10.6 Browser:Firefox-4.0b8 Engine:Gecko-20100101 Bot:false Mobile:false",
+ },
+ {
+ title: "FirefoxMacLoc",
+ ua: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13",
+ expected: "Mozilla:5.0 Platform:Macintosh OS:Intel Mac OS X 10.6 Localization:en-US Browser:Firefox-3.6.13 Engine:Gecko-20101203 Bot:false Mobile:false",
+ },
+ {
+ title: "FirefoxLinux",
+ ua: "Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20100101 Firefox/17.0",
+ expected: "Mozilla:5.0 Platform:X11 OS:Linux x86_64 Browser:Firefox-17.0 Engine:Gecko-20100101 Bot:false Mobile:false",
+ },
+ {
+ title: "FirefoxWin",
+ ua: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows XP Localization:en-US Browser:Firefox-2.0.0.14 Engine:Gecko-20080404 Bot:false Mobile:false",
+ },
+ {
+ title: "Firefox29Win7",
+ ua: "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 7 Browser:Firefox-29.0 Engine:Gecko-20100101 Bot:false Mobile:false",
+ },
+ {
+ title: "CaminoMac",
+ ua: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en; rv:1.8.1.14) Gecko/20080409 Camino/1.6 (like Firefox/2.0.0.14)",
+ expected: "Mozilla:5.0 Platform:Macintosh OS:Intel Mac OS X Localization:en Browser:Camino-1.6 Engine:Gecko-20080409 Bot:false Mobile:false",
+ },
+ {
+ title: "Iceweasel",
+ ua: "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061024 Iceweasel/2.0 (Debian-2.0+dfsg-1)",
+ expected: "Mozilla:5.0 Platform:X11 OS:Linux i686 Localization:en-US Browser:Iceweasel-2.0 Engine:Gecko-20061024 Bot:false Mobile:false",
+ },
+ {
+ title: "SeaMonkey",
+ ua: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.4) Gecko/20091017 SeaMonkey/2.0",
+ expected: "Mozilla:5.0 Platform:Macintosh OS:Intel Mac OS X 10.6 Localization:en-US Browser:SeaMonkey-2.0 Engine:Gecko-20091017 Bot:false Mobile:false",
+ },
+ {
+ title: "AndroidFirefox",
+ ua: "Mozilla/5.0 (Android; Mobile; rv:17.0) Gecko/17.0 Firefox/17.0",
+ expected: "Mozilla:5.0 Platform:Mobile OS:Android Browser:Firefox-17.0 Engine:Gecko-17.0 Bot:false Mobile:true",
+ },
+ {
+ title: "AndroidFirefoxTablet",
+ ua: "Mozilla/5.0 (Android; Tablet; rv:26.0) Gecko/26.0 Firefox/26.0",
+ expected: "Mozilla:5.0 Platform:Tablet OS:Android Browser:Firefox-26.0 Engine:Gecko-26.0 Bot:false Mobile:true",
+ },
+ {
+ title: "FirefoxOS",
+ ua: "Mozilla/5.0 (Mobile; rv:26.0) Gecko/26.0 Firefox/26.0",
+ expected: "Mozilla:5.0 Platform:Mobile OS:FirefoxOS Browser:Firefox-26.0 Engine:Gecko-26.0 Bot:false Mobile:true",
+ },
+ {
+ title: "FirefoxOSTablet",
+ ua: "Mozilla/5.0 (Tablet; rv:26.0) Gecko/26.0 Firefox/26.0",
+ expected: "Mozilla:5.0 Platform:Tablet OS:FirefoxOS Browser:Firefox-26.0 Engine:Gecko-26.0 Bot:false Mobile:true",
+ },
+ {
+ title: "FirefoxWinXP",
+ ua: "Mozilla/5.0 (Windows NT 5.2; rv:31.0) Gecko/20100101 Firefox/31.0",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows XP x64 Edition Browser:Firefox-31.0 Engine:Gecko-20100101 Bot:false Mobile:false",
+ },
+ {
+ title: "FirefoxMRA",
+ ua: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:24.0) Gecko/20130405 MRA 5.5 (build 02842) Firefox/24.0 (.NET CLR 3.5.30729)",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows XP Localization:en-US Browser:Firefox-24.0 Engine:Gecko-20130405 Bot:false Mobile:false",
+ },
+
+ // Opera
+ {
+ title: "OperaMac",
+ ua: "Opera/9.27 (Macintosh; Intel Mac OS X; U; en)",
+ expected: "Platform:Macintosh OS:Intel Mac OS X Localization:en Browser:Opera-9.27 Engine:Presto Bot:false Mobile:false",
+ },
+ {
+ title: "OperaWin",
+ ua: "Opera/9.27 (Windows NT 5.1; U; en)",
+ expected: "Platform:Windows OS:Windows XP Localization:en Browser:Opera-9.27 Engine:Presto Bot:false Mobile:false",
+ },
+ {
+ title: "OperaWinNoLocale",
+ ua: "Opera/9.80 (Windows NT 5.1) Presto/2.12.388 Version/12.10",
+ expected: "Platform:Windows OS:Windows XP Browser:Opera-9.80 Engine:Presto-2.12.388 Bot:false Mobile:false",
+ },
+ {
+ title: "OperaWin2Comment",
+ ua: "Opera/9.80 (Windows NT 6.0; WOW64) Presto/2.12.388 Version/12.15",
+ expected: "Platform:Windows OS:Windows Vista Browser:Opera-9.80 Engine:Presto-2.12.388 Bot:false Mobile:false",
+ },
+ {
+ title: "OperaMinimal",
+ ua: "Opera/9.80",
+ expected: "Browser:Opera-9.80 Engine:Presto Bot:false Mobile:false",
+ },
+ {
+ title: "OperaFull",
+ ua: "Opera/9.80 (Windows NT 6.0; U; en) Presto/2.2.15 Version/10.10",
+ expected: "Platform:Windows OS:Windows Vista Localization:en Browser:Opera-9.80 Engine:Presto-2.2.15 Bot:false Mobile:false",
+ },
+ {
+ title: "OperaLinux",
+ ua: "Opera/9.80 (X11; Linux x86_64) Presto/2.12.388 Version/12.10",
+ expected: "Platform:X11 OS:Linux x86_64 Browser:Opera-9.80 Engine:Presto-2.12.388 Bot:false Mobile:false",
+ },
+ {
+ title: "OperaAndroid",
+ ua: "Opera/9.80 (Android 4.2.1; Linux; Opera Mobi/ADR-1212030829) Presto/2.11.355 Version/12.10",
+ expected: "Platform:Android 4.2.1 OS:Linux Browser:Opera-9.80 Engine:Presto-2.11.355 Bot:false Mobile:true",
+ },
+ {
+ title: "OperaNested",
+ ua: "Opera/9.80 (Windows NT 5.1; MRA 6.0 (build 5831)) Presto/2.12.388 Version/12.10",
+ expected: "Platform:Windows OS:Windows XP Browser:Opera-9.80 Engine:Presto-2.12.388 Bot:false Mobile:false",
+ },
+ {
+ title: "OperaMRA",
+ ua: "Opera/9.80 (Windows NT 6.1; U; MRA 5.8 (build 4139); en) Presto/2.9.168 Version/11.50",
+ expected: "Platform:Windows OS:Windows 7 Localization:en Browser:Opera-9.80 Engine:Presto-2.9.168 Bot:false Mobile:false",
+ },
+
+ // Other
+ {
+ title: "Empty",
+ ua: "",
+ expected: "Bot:false Mobile:false",
+ },
+ {
+ title: "Nil",
+ ua: "nil",
+ expected: "Browser:nil Bot:false Mobile:false",
+ },
+ {
+ title: "Compatible",
+ ua: "Mozilla/4.0 (compatible)",
+ expected: "Browser:Mozilla-4.0 Bot:false Mobile:false",
+ },
+ {
+ title: "Mozilla",
+ ua: "Mozilla/5.0",
+ expected: "Browser:Mozilla-5.0 Bot:false Mobile:false",
+ },
+ {
+ title: "Amaya",
+ ua: "amaya/9.51 libwww/5.4.0",
+ expected: "Browser:amaya-9.51 Engine:libwww-5.4.0 Bot:false Mobile:false",
+ },
+ {
+ title: "Rails",
+ ua: "Rails Testing",
+ expected: "Browser:Rails Engine:Testing Bot:false Mobile:false",
+ },
+ {
+ title: "Python",
+ ua: "Python-urllib/2.7",
+ expected: "Browser:Python-urllib-2.7 Bot:false Mobile:false",
+ },
+ {
+ title: "Curl",
+ ua: "curl/7.28.1",
+ expected: "Browser:curl-7.28.1 Bot:false Mobile:false",
+ },
+
+ // WebKit
+ {
+ title: "ChromeLinux",
+ ua: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11",
+ expected: "Mozilla:5.0 Platform:X11 OS:Linux x86_64 Browser:Chrome-23.0.1271.97 Engine:AppleWebKit-537.11 Bot:false Mobile:false",
+ },
+ {
+ title: "ChromeWin7",
+ ua: "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.168 Safari/535.19",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows 7 Browser:Chrome-18.0.1025.168 Engine:AppleWebKit-535.19 Bot:false Mobile:false",
+ },
+ {
+ title: "ChromeMinimal",
+ ua: "Mozilla/5.0 AppleWebKit/534.10 Chrome/8.0.552.215 Safari/534.10",
+ expected: "Mozilla:5.0 Browser:Chrome-8.0.552.215 Engine:AppleWebKit-534.10 Bot:false Mobile:false",
+ },
+ {
+ title: "ChromeMac",
+ ua: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_5; en-US) AppleWebKit/534.10 (KHTML, like Gecko) Chrome/8.0.552.231 Safari/534.10",
+ expected: "Mozilla:5.0 Platform:Macintosh OS:Intel Mac OS X 10_6_5 Localization:en-US Browser:Chrome-8.0.552.231 Engine:AppleWebKit-534.10 Bot:false Mobile:false",
+ },
+ {
+ title: "SafariMac",
+ ua: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16",
+ expected: "Mozilla:5.0 Platform:Macintosh OS:Intel Mac OS X 10_6_3 Localization:en-us Browser:Safari-5.0 Engine:AppleWebKit-533.16 Bot:false Mobile:false",
+ },
+ {
+ title: "SafariWin",
+ ua: "Mozilla/5.0 (Windows; U; Windows NT 5.1; en) AppleWebKit/526.9 (KHTML, like Gecko) Version/4.0dp1 Safari/526.8",
+ expected: "Mozilla:5.0 Platform:Windows OS:Windows XP Localization:en Browser:Safari-4.0dp1 Engine:AppleWebKit-526.9 Bot:false Mobile:false",
+ },
+ {
+ title: "iPhone7",
+ ua: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_3 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11B511 Safari/9537.53",
+ expected: "Mozilla:5.0 Platform:iPhone OS:CPU iPhone OS 7_0_3 like Mac OS X Browser:Safari-7.0 Engine:AppleWebKit-537.51.1 Bot:false Mobile:true",
+ },
+ {
+ title: "iPhone",
+ ua: "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/4A102 Safari/419",
+ expected: "Mozilla:5.0 Platform:iPhone OS:CPU like Mac OS X Localization:en Browser:Safari-3.0 Engine:AppleWebKit-420.1 Bot:false Mobile:true",
+ },
+ {
+ title: "iPod",
+ ua: "Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/4A102 Safari/419",
+ expected: "Mozilla:5.0 Platform:iPod OS:CPU like Mac OS X Localization:en Browser:Safari-3.0 Engine:AppleWebKit-420.1 Bot:false Mobile:true",
+ },
+ {
+ title: "iPad",
+ ua: "Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B367 Safari/531.21.10",
+ expected: "Mozilla:5.0 Platform:iPad OS:CPU OS 3_2 like Mac OS X Localization:en-us Browser:Safari-4.0.4 Engine:AppleWebKit-531.21.10 Bot:false Mobile:true",
+ },
+ {
+ title: "webOS",
+ ua: "Mozilla/5.0 (webOS/1.4.0; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pre/1.1",
+ expected: "Mozilla:5.0 Platform:webOS OS:Palm Localization:en-US Browser:webOS-1.0 Engine:AppleWebKit-532.2 Bot:false Mobile:true",
+ },
+ {
+ title: "Android",
+ ua: "Mozilla/5.0 (Linux; U; Android 1.5; de-; HTC Magic Build/PLAT-RC33) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 1.5 Localization:de- Browser:Android-3.1.2 Engine:AppleWebKit-528.5+ Bot:false Mobile:true",
+ },
+ {
+ title: "BlackBerry",
+ ua: "Mozilla/5.0 (BlackBerry; U; BlackBerry 9800; en) AppleWebKit/534.1+ (KHTML, Like Gecko) Version/6.0.0.141 Mobile Safari/534.1+",
+ expected: "Mozilla:5.0 Platform:BlackBerry OS:BlackBerry 9800 Localization:en Browser:BlackBerry-6.0.0.141 Engine:AppleWebKit-534.1+ Bot:false Mobile:true",
+ },
+ {
+ title: "BB10",
+ ua: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.3+ (KHTML, like Gecko) Version/10.0.9.388 Mobile Safari/537.3+",
+ expected: "Mozilla:5.0 Platform:BlackBerry OS:BlackBerry Browser:BlackBerry-10.0.9.388 Engine:AppleWebKit-537.3+ Bot:false Mobile:true",
+ },
+ {
+ title: "Ericsson",
+ ua: "Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebKit/525 (KHTML, like Gecko) Version/3.0 Safari/525",
+ expected: "Mozilla:5.0 Platform:Symbian OS:SymbianOS/9.4 Browser:Symbian-3.0 Engine:AppleWebKit-525 Bot:false Mobile:true",
+ },
+ {
+ title: "ChromeAndroid",
+ ua: "Mozilla/5.0 (Linux; Android 4.2.1; Galaxy Nexus Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 4.2.1 Browser:Chrome-18.0.1025.166 Engine:AppleWebKit-535.19 Bot:false Mobile:true",
+ },
+ {
+ title: "WebkitNoPlatform",
+ ua: "Mozilla/5.0 (en-us) AppleWebKit/525.13 (KHTML, like Gecko; Google Web Preview) Version/3.1 Safari/525.13",
+ expected: "Mozilla:5.0 Platform:en-us Localization:en-us Browser:Safari-3.1 Engine:AppleWebKit-525.13 Bot:false Mobile:false",
+ },
+ {
+ title: "OperaWebkitMobile",
+ ua: "Mozilla/5.0 (Linux; Android 4.2.2; Galaxy Nexus Build/JDQ39) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Mobile Safari/537.31 OPR/14.0.1074.57453",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 4.2.2 Browser:Opera-14.0.1074.57453 Engine:AppleWebKit-537.31 Bot:false Mobile:true",
+ },
+ {
+ title: "OperaWebkitDesktop",
+ ua: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.58 Safari/537.31 OPR/14.0.1074.57453",
+ expected: "Mozilla:5.0 Platform:X11 OS:Linux x86_64 Browser:Opera-14.0.1074.57453 Engine:AppleWebKit-537.31 Bot:false Mobile:false",
+ },
+ {
+ title: "ChromeNothingAfterU",
+ ua: "Mozilla/5.0 (Linux; U) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.79 Safari/537.4",
+ expected: "Mozilla:5.0 Platform:Linux OS:Linux Browser:Chrome-22.0.1229.79 Engine:AppleWebKit-537.4 Bot:false Mobile:false",
+ },
+ {
+ title: "SafariOnSymbian",
+ ua: "Mozilla/5.0 (SymbianOS/9.1; U; [en-us]) AppleWebKit/413 (KHTML, like Gecko) Safari/413",
+ expected: "Mozilla:5.0 Platform:Symbian OS:SymbianOS/9.1 Browser:Symbian-413 Engine:AppleWebKit-413 Bot:false Mobile:true",
+ },
+
+ // Dalvik
+ {
+ title: "Dalvik - Dell:001DL",
+ ua: "Dalvik/1.2.0 (Linux; U; Android 2.2.2; 001DL Build/FRG83G)",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 2.2.2 Bot:false Mobile:true",
+ },
+ {
+ title: "Dalvik - HTC:001HT",
+ ua: "Dalvik/1.4.0 (Linux; U; Android 2.3.3; 001HT Build/GRI40)",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 2.3.3 Bot:false Mobile:true",
+ },
+ {
+ title: "Dalvik - ZTE:009Z",
+ ua: "Dalvik/1.4.0 (Linux; U; Android 2.3.4; 009Z Build/GINGERBREAD)",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 2.3.4 Bot:false Mobile:true",
+ },
+ {
+ title: "Dalvik - A850",
+ ua: "Dalvik/1.6.0 (Linux; U; Android 4.2.2; A850 Build/JDQ39) Configuration/CLDC-1.1; Opera Mini/att/4.2",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 4.2.2 Bot:false Mobile:true",
+ },
+ {
+ title: "Dalvik - Asus:T00Q",
+ ua: "Dalvik/1.6.0 (Linux; U; Android 4.4.2; ASUS_T00Q Build/KVT49L)/CLDC-1.1",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 4.4.2 Bot:false Mobile:true",
+ },
+ {
+ title: "Dalvik - W2430",
+ ua: "Dalvik/1.6.0 (Linux; U; Android 4.0.4; W2430 Build/IMM76D)014; Profile/MIDP-2.1 Configuration/CLDC-1",
+ expected: "Mozilla:5.0 Platform:Linux OS:Android 4.0.4 Bot:false Mobile:true",
+ },
+}
+
+// Internal: beautify the UserAgent reference into a string so it can be
+// tested later on.
+//
+// ua - a UserAgent reference.
+//
+// Returns a string that contains the beautified representation.
+func beautify(ua *UserAgent) (s string) {
+ if len(ua.Mozilla()) > 0 {
+ s += "Mozilla:" + ua.Mozilla() + " "
+ }
+ if len(ua.Platform()) > 0 {
+ s += "Platform:" + ua.Platform() + " "
+ }
+ if len(ua.OS()) > 0 {
+ s += "OS:" + ua.OS() + " "
+ }
+ if len(ua.Localization()) > 0 {
+ s += "Localization:" + ua.Localization() + " "
+ }
+ str1, str2 := ua.Browser()
+ if len(str1) > 0 {
+ s += "Browser:" + str1
+ if len(str2) > 0 {
+ s += "-" + str2 + " "
+ } else {
+ s += " "
+ }
+ }
+ str1, str2 = ua.Engine()
+ if len(str1) > 0 {
+ s += "Engine:" + str1
+ if len(str2) > 0 {
+ s += "-" + str2 + " "
+ } else {
+ s += " "
+ }
+ }
+ s += "Bot:" + fmt.Sprintf("%v", ua.Bot()) + " "
+ s += "Mobile:" + fmt.Sprintf("%v", ua.Mobile())
+ return s
+}
+
+// The test suite.
+func TestUserAgent(t *testing.T) {
+ for _, tt := range uastrings {
+ ua := New(tt.ua)
+ got := beautify(ua)
+ if tt.expected != got {
+ t.Errorf("\nTest %v\ngot: %q\nexpected %q\n", tt.title, got, tt.expected)
+ }
+ }
+}
+
+// Benchmark: it parses each User-Agent string on the uastrings slice b.N times.
+func BenchmarkUserAgent(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ b.StopTimer()
+ for _, tt := range uastrings {
+ ua := new(UserAgent)
+ b.StartTimer()
+ ua.Parse(tt.ua)
+ }
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/.gitignore b/vendor/github.com/nicksnyder/go-i18n/.gitignore
new file mode 100644
index 000000000..20e1aa8ff
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/.gitignore
@@ -0,0 +1,6 @@
+*.a
+_*
+output/
+.DS_Store
+*.test
+*.swp
diff --git a/vendor/github.com/nicksnyder/go-i18n/.travis.yml b/vendor/github.com/nicksnyder/go-i18n/.travis.yml
new file mode 100644
index 000000000..8558bb44f
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/.travis.yml
@@ -0,0 +1,8 @@
+language: go
+sudo: false
+go:
+ - 1.2
+ - 1.3
+ - 1.4
+ - 1.5
+ - tip
diff --git a/vendor/github.com/nicksnyder/go-i18n/CHANGELOG b/vendor/github.com/nicksnyder/go-i18n/CHANGELOG
new file mode 100644
index 000000000..c7949b143
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/CHANGELOG
@@ -0,0 +1,5 @@
+Feb 24, 2015
+- Add Korean
+
+Feb 18, 2015
+- Added ParseTranslationFileBytes so translation files may be loaded from an arbitrary serialization format, such as go-bindata.
diff --git a/vendor/github.com/nicksnyder/go-i18n/README.md b/vendor/github.com/nicksnyder/go-i18n/README.md
new file mode 100644
index 000000000..5aef540b3
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/README.md
@@ -0,0 +1,130 @@
+go-i18n [![Build Status](https://secure.travis-ci.org/nicksnyder/go-i18n.png?branch=master)](http://travis-ci.org/nicksnyder/go-i18n)
+=======
+
+go-i18n is a Go [package](#i18n-package) and a [command](#goi18n-command) that helps you translate Go programs into multiple languages.
+* Supports [pluralized strings](http://cldr.unicode.org/index/cldr-spec/plural-rules) for all 200+ languages in the [Unicode Common Locale Data Repository (CLDR)](http://www.unicode.org/cldr/charts/28/supplemental/language_plural_rules.html).
+ * Code and tests are [automatically generated](https://github.com/nicksnyder/go-i18n/tree/master/i18n/language/codegen) from [CLDR data](http://cldr.unicode.org/index/downloads)
+* Supports strings with named variables using [text/template](http://golang.org/pkg/text/template/) syntax.
+* Translation files are simple JSON or YAML.
+* [Documented](http://godoc.org/github.com/nicksnyder/go-i18n) and [tested](https://travis-ci.org/nicksnyder/go-i18n)!
+
+Package i18n [![GoDoc](http://godoc.org/github.com/nicksnyder/go-i18n?status.png)](http://godoc.org/github.com/nicksnyder/go-i18n/i18n)
+------------
+
+The i18n package provides runtime APIs for fetching translated strings.
+
+Command goi18n [![GoDoc](http://godoc.org/github.com/nicksnyder/go-i18n?status.png)](http://godoc.org/github.com/nicksnyder/go-i18n/goi18n)
+--------------
+
+The goi18n command provides functionality for managing the translation process.
+
+Installation
+------------
+
+Make sure you have [setup GOPATH](http://golang.org/doc/code.html#GOPATH).
+
+ go get -u github.com/nicksnyder/go-i18n/goi18n
+ goi18n -help
+
+Workflow
+--------
+
+A typical workflow looks like this:
+
+1. Add a new string to your source code.
+
+ ```go
+ T("settings_title")
+ ```
+
+2. Add the string to en-US.all.json
+
+ ```json
+ [
+ {
+ "id": "settings_title",
+ "translation": "Settings"
+ }
+ ]
+ ```
+
+3. Run goi18n
+
+ ```
+ goi18n path/to/*.all.json
+ ```
+
+4. Send `path/to/*.untranslated.json` to get translated.
+5. Run goi18n again to merge the translations
+
+ ```sh
+ goi18n path/to/*.all.json path/to/*.untranslated.json
+ ```
+
+Translation files
+-----------------
+
+A translation file stores translated and untranslated strings.
+
+Example:
+
+```json
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "one": "{{.Count}} day",
+ "other": "{{.Count}} days"
+ }
+ },
+ {
+ "id": "my_height_in_meters",
+ "translation": {
+ "one": "I am {{.Count}} meter tall.",
+ "other": "I am {{.Count}} meters tall."
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "Hello {{.Person}}"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread email.",
+ "other": "{{.Person}} has {{.Count}} unread emails."
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.",
+ "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": "Hello world"
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "one": "You have {{.Count}} unread email.",
+ "other": "You have {{.Count}} unread emails."
+ }
+ }
+]
+```
+
+Contributions
+-------------
+
+If you would like to submit a pull request, please
+
+1. Write tests
+2. Format code with [goimports](https://github.com/bradfitz/goimports).
+3. Read the [common code review comments](https://github.com/golang/go/wiki/CodeReviewComments).
+
+License
+-------
+go-i18n is available under the MIT license. See the [LICENSE](LICENSE) file for more info.
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go
new file mode 100644
index 000000000..10d244217
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/doc.go
@@ -0,0 +1,59 @@
+// The goi18n command formats and merges translation files.
+//
+// go get -u github.com/nicksnyder/go-i18n/goi18n
+// goi18n -help
+//
+// Help documentation:
+//
+// goi18n formats and merges translation files.
+//
+// Usage:
+//
+// goi18n [options] [files...]
+//
+// Translation files:
+//
+// A translation file contains the strings and translations for a single language.
+//
+// Translation file names must have a suffix of a supported format (e.g. .json) and
+// contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.).
+//
+// For each language represented by at least one input translation file, goi18n will produce 2 output files:
+//
+// xx-yy.all.format
+// This file contains all strings for the language (translated and untranslated).
+// Use this file when loading strings at runtime.
+//
+// xx-yy.untranslated.format
+// This file contains the strings that have not been translated for this language.
+// The translations for the strings in this file will be extracted from the source language.
+// After they are translated, merge them back into xx-yy.all.format using goi18n.
+//
+// Merging:
+//
+// goi18n will merge multiple translation files for the same language.
+// Duplicate translations will be merged into the existing translation.
+// Non-empty fields in the duplicate translation will overwrite those fields in the existing translation.
+// Empty fields in the duplicate translation are ignored.
+//
+// Adding a new language:
+//
+// To produce translation files for a new language, create an empty translation file with the
+// appropriate name and pass it in to goi18n.
+//
+// Options:
+//
+// -sourceLanguage tag
+// goi18n uses the strings from this language to seed the translations for other languages.
+// Default: en-us
+//
+// -outdir directory
+// goi18n writes the output translation files to this directory.
+// Default: .
+//
+// -format format
+// goi18n encodes the output translation files in this format.
+// Supported formats: json, yaml
+// Default: json
+//
+package main
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh b/vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh
new file mode 100644
index 000000000..094f479a5
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/gendoc.sh
@@ -0,0 +1,10 @@
+go install
+echo "// The goi18n command formats and merges translation files." > doc.go
+echo "//" >> doc.go
+echo "// go get -u github.com/nicksnyder/go-i18n/goi18n" >> doc.go
+echo "// goi18n -help" >> doc.go
+echo "//" >> doc.go
+echo "// Help documentation:" >> doc.go
+echo "//" >> doc.go
+goi18n -help | sed -e 's/^/\/\/ /' >> doc.go
+echo "package main" >> doc.go
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go
new file mode 100644
index 000000000..f57ea8175
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/goi18n.go
@@ -0,0 +1,82 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+)
+
+func usage() {
+ fmt.Printf(`goi18n formats and merges translation files.
+
+Usage:
+
+ goi18n [options] [files...]
+
+Translation files:
+
+ A translation file contains the strings and translations for a single language.
+
+ Translation file names must have a suffix of a supported format (e.g. .json) and
+ contain a valid language tag as defined by RFC 5646 (e.g. en-us, fr, zh-hant, etc.).
+
+ For each language represented by at least one input translation file, goi18n will produce 2 output files:
+
+ xx-yy.all.format
+ This file contains all strings for the language (translated and untranslated).
+ Use this file when loading strings at runtime.
+
+ xx-yy.untranslated.format
+ This file contains the strings that have not been translated for this language.
+ The translations for the strings in this file will be extracted from the source language.
+ After they are translated, merge them back into xx-yy.all.format using goi18n.
+
+Merging:
+
+ goi18n will merge multiple translation files for the same language.
+ Duplicate translations will be merged into the existing translation.
+ Non-empty fields in the duplicate translation will overwrite those fields in the existing translation.
+ Empty fields in the duplicate translation are ignored.
+
+Adding a new language:
+
+ To produce translation files for a new language, create an empty translation file with the
+ appropriate name and pass it in to goi18n.
+
+Options:
+
+ -sourceLanguage tag
+ goi18n uses the strings from this language to seed the translations for other languages.
+ Default: en-us
+
+ -outdir directory
+ goi18n writes the output translation files to this directory.
+ Default: .
+
+ -format format
+ goi18n encodes the output translation files in this format.
+ Supported formats: json, yaml
+ Default: json
+
+`)
+ os.Exit(1)
+}
+
+func main() {
+ flag.Usage = usage
+ sourceLanguage := flag.String("sourceLanguage", "en-us", "")
+ outdir := flag.String("outdir", ".", "")
+ format := flag.String("format", "json", "")
+ flag.Parse()
+
+ mc := &mergeCommand{
+ translationFiles: flag.Args(),
+ sourceLanguageTag: *sourceLanguage,
+ outdir: *outdir,
+ format: *format,
+ }
+ if err := mc.execute(); err != nil {
+ fmt.Println(err.Error())
+ os.Exit(1)
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go
new file mode 100644
index 000000000..1317fe958
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge.go
@@ -0,0 +1,127 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "gopkg.in/yaml.v2"
+ "io/ioutil"
+ "path/filepath"
+ "reflect"
+ "sort"
+
+ "github.com/nicksnyder/go-i18n/i18n/bundle"
+ "github.com/nicksnyder/go-i18n/i18n/language"
+ "github.com/nicksnyder/go-i18n/i18n/translation"
+)
+
+type mergeCommand struct {
+ translationFiles []string
+ sourceLanguageTag string
+ outdir string
+ format string
+}
+
+func (mc *mergeCommand) execute() error {
+ if len(mc.translationFiles) < 1 {
+ return fmt.Errorf("need at least one translation file to parse")
+ }
+
+ if lang := language.Parse(mc.sourceLanguageTag); lang == nil {
+ return fmt.Errorf("invalid source locale: %s", mc.sourceLanguageTag)
+ }
+
+ marshal, err := newMarshalFunc(mc.format)
+ if err != nil {
+ return err
+ }
+
+ bundle := bundle.New()
+ for _, tf := range mc.translationFiles {
+ if err := bundle.LoadTranslationFile(tf); err != nil {
+ return fmt.Errorf("failed to load translation file %s because %s\n", tf, err)
+ }
+ }
+
+ translations := bundle.Translations()
+ sourceLanguageTag := language.NormalizeTag(mc.sourceLanguageTag)
+ sourceTranslations := translations[sourceLanguageTag]
+ if sourceTranslations == nil {
+ return fmt.Errorf("no translations found for source locale %s", sourceLanguageTag)
+ }
+ for translationID, src := range sourceTranslations {
+ for _, localeTranslations := range translations {
+ if dst := localeTranslations[translationID]; dst == nil || reflect.TypeOf(src) != reflect.TypeOf(dst) {
+ localeTranslations[translationID] = src.UntranslatedCopy()
+ }
+ }
+ }
+
+ for localeID, localeTranslations := range translations {
+ lang := language.MustParse(localeID)[0]
+ all := filter(localeTranslations, func(t translation.Translation) translation.Translation {
+ return t.Normalize(lang)
+ })
+ if err := mc.writeFile("all", all, localeID, marshal); err != nil {
+ return err
+ }
+
+ untranslated := filter(localeTranslations, func(t translation.Translation) translation.Translation {
+ if t.Incomplete(lang) {
+ return t.Normalize(lang).Backfill(sourceTranslations[t.ID()])
+ }
+ return nil
+ })
+ if err := mc.writeFile("untranslated", untranslated, localeID, marshal); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+type marshalFunc func(interface{}) ([]byte, error)
+
+func (mc *mergeCommand) writeFile(label string, translations []translation.Translation, localeID string, marshal marshalFunc) error {
+ sort.Sort(translation.SortableByID(translations))
+ buf, err := marshal(marshalInterface(translations))
+ if err != nil {
+ return fmt.Errorf("failed to marshal %s strings to %s because %s", localeID, mc.format, err)
+ }
+ filename := filepath.Join(mc.outdir, fmt.Sprintf("%s.%s.%s", localeID, label, mc.format))
+ if err := ioutil.WriteFile(filename, buf, 0666); err != nil {
+ return fmt.Errorf("failed to write %s because %s", filename, err)
+ }
+ return nil
+}
+
+func filter(translations map[string]translation.Translation, filter func(translation.Translation) translation.Translation) []translation.Translation {
+ filtered := make([]translation.Translation, 0, len(translations))
+ for _, translation := range translations {
+ if t := filter(translation); t != nil {
+ filtered = append(filtered, t)
+ }
+ }
+ return filtered
+
+}
+
+func newMarshalFunc(format string) (marshalFunc, error) {
+ switch format {
+ case "json":
+ return func(v interface{}) ([]byte, error) {
+ return json.MarshalIndent(v, "", " ")
+ }, nil
+ case "yaml":
+ return func(v interface{}) ([]byte, error) {
+ return yaml.Marshal(v)
+ }, nil
+ }
+ return nil, fmt.Errorf("unsupported format: %s\n", format)
+}
+
+func marshalInterface(translations []translation.Translation) []interface{} {
+ mi := make([]interface{}, len(translations))
+ for i, translation := range translations {
+ mi[i] = translation.MarshalInterface()
+ }
+ return mi
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go
new file mode 100644
index 000000000..f0d0d47a1
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/merge_test.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+func TestMergeExecuteJSON(t *testing.T) {
+ files := []string{
+ "testdata/input/en-us.one.json",
+ "testdata/input/en-us.two.json",
+ "testdata/input/fr-fr.json",
+ "testdata/input/ar-ar.one.json",
+ "testdata/input/ar-ar.two.json",
+ }
+ testMergeExecute(t, files)
+}
+
+func TestMergeExecuteYAML(t *testing.T) {
+ files := []string{
+ "testdata/input/yaml/en-us.one.yaml",
+ "testdata/input/yaml/en-us.two.json",
+ "testdata/input/yaml/fr-fr.json",
+ "testdata/input/yaml/ar-ar.one.json",
+ "testdata/input/yaml/ar-ar.two.json",
+ }
+ testMergeExecute(t, files)
+}
+
+func testMergeExecute(t *testing.T, files []string) {
+ resetDir(t, "testdata/output")
+
+ mc := &mergeCommand{
+ translationFiles: files,
+ sourceLanguageTag: "en-us",
+ outdir: "testdata/output",
+ format: "json",
+ }
+ if err := mc.execute(); err != nil {
+ t.Fatal(err)
+ }
+
+ expectEqualFiles(t, "testdata/output/en-us.all.json", "testdata/expected/en-us.all.json")
+ expectEqualFiles(t, "testdata/output/ar-ar.all.json", "testdata/expected/ar-ar.all.json")
+ expectEqualFiles(t, "testdata/output/fr-fr.all.json", "testdata/expected/fr-fr.all.json")
+ expectEqualFiles(t, "testdata/output/en-us.untranslated.json", "testdata/expected/en-us.untranslated.json")
+ expectEqualFiles(t, "testdata/output/ar-ar.untranslated.json", "testdata/expected/ar-ar.untranslated.json")
+ expectEqualFiles(t, "testdata/output/fr-fr.untranslated.json", "testdata/expected/fr-fr.untranslated.json")
+}
+
+func resetDir(t *testing.T, dir string) {
+ if err := os.RemoveAll(dir); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Mkdir(dir, 0777); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func expectEqualFiles(t *testing.T, expectedName, actualName string) {
+ actual, err := ioutil.ReadFile(actualName)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected, err := ioutil.ReadFile(expectedName)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(actual, expected) {
+ t.Fatalf("contents of files did not match: %s, %s", expectedName, actualName)
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml
new file mode 100644
index 000000000..cdf9c8dc5
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/en-us.yaml
@@ -0,0 +1,30 @@
+- id: program_greeting
+ translation: "Hello world"
+
+- id: person_greeting
+ translation: "Hello {{.Person}}"
+
+- id: my_height_in_meters
+ translation:
+ one: "I am {{.Count}} meter tall."
+ other: "I am {{.Count}} meters tall."
+
+- id: your_unread_email_count
+ translation:
+ one: "You have {{.Count}} unread email."
+ other: "You have {{.Count}} unread emails."
+
+- id: person_unread_email_count
+ translation:
+ one: "{{.Person}} has {{.Count}} unread email."
+ other: "{{.Person}} has {{.Count}} unread emails."
+
+- id: person_unread_email_count_timeframe
+ translation:
+ one: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
+ other: "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
+
+- id: d_days
+ translation:
+ one: "{{.Count}} day"
+ other: "{{.Count}} days"
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json
new file mode 100644
index 000000000..26a72ff30
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.all.json
@@ -0,0 +1,65 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "few": "new arabic few translation of d_days",
+ "many": "arabic many translation of d_days",
+ "one": "arabic one translation of d_days",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "my_height_in_meters",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "new arabic translation of person_greeting"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "few": "arabic few translation of person_unread_email_count",
+ "many": "arabic many translation of person_unread_email_count",
+ "one": "arabic one translation of person_unread_email_count",
+ "other": "arabic other translation of person_unread_email_count",
+ "two": "arabic two translation of person_unread_email_count",
+ "zero": "arabic zero translation of person_unread_email_count"
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": ""
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ }
+] \ No newline at end of file
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json
new file mode 100644
index 000000000..a19fa0bee
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/ar-ar.untranslated.json
@@ -0,0 +1,50 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "few": "new arabic few translation of d_days",
+ "many": "arabic many translation of d_days",
+ "one": "arabic one translation of d_days",
+ "other": "{{.Count}} days",
+ "two": "{{.Count}} days",
+ "zero": "{{.Count}} days"
+ }
+ },
+ {
+ "id": "my_height_in_meters",
+ "translation": {
+ "few": "I am {{.Count}} meters tall.",
+ "many": "I am {{.Count}} meters tall.",
+ "one": "I am {{.Count}} meters tall.",
+ "other": "I am {{.Count}} meters tall.",
+ "two": "I am {{.Count}} meters tall.",
+ "zero": "I am {{.Count}} meters tall."
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "few": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.",
+ "many": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.",
+ "one": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.",
+ "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.",
+ "two": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.",
+ "zero": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": "Hello world"
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "few": "You have {{.Count}} unread emails.",
+ "many": "You have {{.Count}} unread emails.",
+ "one": "You have {{.Count}} unread emails.",
+ "other": "You have {{.Count}} unread emails.",
+ "two": "You have {{.Count}} unread emails.",
+ "zero": "You have {{.Count}} unread emails."
+ }
+ }
+] \ No newline at end of file
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json
new file mode 100644
index 000000000..5aedc235a
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.all.json
@@ -0,0 +1,45 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "one": "{{.Count}} day",
+ "other": "{{.Count}} days"
+ }
+ },
+ {
+ "id": "my_height_in_meters",
+ "translation": {
+ "one": "I am {{.Count}} meter tall.",
+ "other": "I am {{.Count}} meters tall."
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "Hello {{.Person}}"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread email.",
+ "other": "{{.Person}} has {{.Count}} unread emails."
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}.",
+ "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": "Hello world"
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "one": "You have {{.Count}} unread email.",
+ "other": "You have {{.Count}} unread emails."
+ }
+ }
+] \ No newline at end of file
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json
new file mode 100644
index 000000000..0637a088a
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/en-us.untranslated.json
@@ -0,0 +1 @@
+[] \ No newline at end of file
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json
new file mode 100644
index 000000000..20e0b8736
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.all.json
@@ -0,0 +1,45 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "one": "",
+ "other": ""
+ }
+ },
+ {
+ "id": "my_height_in_meters",
+ "translation": {
+ "one": "",
+ "other": ""
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": ""
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "one": "",
+ "other": ""
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "one": "",
+ "other": ""
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": ""
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "one": "",
+ "other": ""
+ }
+ }
+] \ No newline at end of file
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json
new file mode 100644
index 000000000..e2d3967c5
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/expected/fr-fr.untranslated.json
@@ -0,0 +1,45 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "one": "{{.Count}} days",
+ "other": "{{.Count}} days"
+ }
+ },
+ {
+ "id": "my_height_in_meters",
+ "translation": {
+ "one": "I am {{.Count}} meters tall.",
+ "other": "I am {{.Count}} meters tall."
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "Hello {{.Person}}"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread emails.",
+ "other": "{{.Person}} has {{.Count}} unread emails."
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}.",
+ "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": "Hello world"
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "one": "You have {{.Count}} unread emails.",
+ "other": "You have {{.Count}} unread emails."
+ }
+ }
+] \ No newline at end of file
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json
new file mode 100644
index 000000000..f5af1d6f4
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.one.json
@@ -0,0 +1,54 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "few": "arabic few translation of d_days",
+ "many": "arabic many translation of d_days",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "arabic translation of person_greeting"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "few": "arabic few translation of person_unread_email_count",
+ "many": "arabic many translation of person_unread_email_count",
+ "one": "arabic one translation of person_unread_email_count",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": ""
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ }
+]
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json
new file mode 100644
index 000000000..e98d7e9b2
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/ar-ar.two.json
@@ -0,0 +1,54 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "few": "new arabic few translation of d_days",
+ "many": "",
+ "one": "arabic one translation of d_days",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "new arabic translation of person_greeting"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "arabic other translation of person_unread_email_count",
+ "two": "arabic two translation of person_unread_email_count",
+ "zero": "arabic zero translation of person_unread_email_count"
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": ""
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ }
+]
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json
new file mode 100644
index 000000000..63a9d6ffb
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.one.json
@@ -0,0 +1,30 @@
+[
+ {
+ "id": "program_greeting",
+ "translation": "Hello world"
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "one": "You have {{.Count}} unread email.",
+ "other": "You have {{.Count}} unread emails."
+ }
+ },
+ {
+ "id": "my_height_in_meters",
+ "translation": {
+ "one": "I am {{.Count}} meter tall.",
+ "other": "I am {{.Count}} meters tall."
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
+ }
+ },
+ {
+ "id": "d_days",
+ "translation": "this should get overwritten"
+ }
+]
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json
new file mode 100644
index 000000000..dcc715c43
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/en-us.two.json
@@ -0,0 +1,26 @@
+[
+ {
+ "id": "person_greeting",
+ "translation": "Hello {{.Person}}"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread email.",
+ "other": "{{.Person}} has {{.Count}} unread emails."
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
+ }
+ },
+ {
+ "id": "d_days",
+ "translation": {
+ "one": "{{.Count}} day",
+ "other": "{{.Count}} days"
+ }
+ }
+]
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/fr-fr.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/fr-fr.json
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/fr-fr.json
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json
new file mode 100644
index 000000000..f5af1d6f4
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.one.json
@@ -0,0 +1,54 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "few": "arabic few translation of d_days",
+ "many": "arabic many translation of d_days",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "arabic translation of person_greeting"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "few": "arabic few translation of person_unread_email_count",
+ "many": "arabic many translation of person_unread_email_count",
+ "one": "arabic one translation of person_unread_email_count",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": ""
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ }
+]
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json
new file mode 100644
index 000000000..e98d7e9b2
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/ar-ar.two.json
@@ -0,0 +1,54 @@
+[
+ {
+ "id": "d_days",
+ "translation": {
+ "few": "new arabic few translation of d_days",
+ "many": "",
+ "one": "arabic one translation of d_days",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "person_greeting",
+ "translation": "new arabic translation of person_greeting"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "arabic other translation of person_unread_email_count",
+ "two": "arabic two translation of person_unread_email_count",
+ "zero": "arabic zero translation of person_unread_email_count"
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ },
+ {
+ "id": "program_greeting",
+ "translation": ""
+ },
+ {
+ "id": "your_unread_email_count",
+ "translation": {
+ "few": "",
+ "many": "",
+ "one": "",
+ "other": "",
+ "two": "",
+ "zero": ""
+ }
+ }
+]
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml
new file mode 100644
index 000000000..3ca8e380d
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.one.yaml
@@ -0,0 +1,19 @@
+- id: program_greeting
+ translation: Hello world
+
+- id: your_unread_email_count
+ translation:
+ one: You have {{.Count}} unread email.
+ other: You have {{.Count}} unread emails.
+
+- id: my_height_in_meters
+ translation:
+ one: I am {{.Count}} meter tall.
+ other: I am {{.Count}} meters tall.
+
+- id: person_unread_email_count_timeframe
+ translation:
+ one: "{{.Person}} has {{.Count}} unread email in the past {{.Timeframe}}."
+
+- id: d_days
+ translation: this should get overwritten \ No newline at end of file
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json
new file mode 100644
index 000000000..dcc715c43
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/en-us.two.json
@@ -0,0 +1,26 @@
+[
+ {
+ "id": "person_greeting",
+ "translation": "Hello {{.Person}}"
+ },
+ {
+ "id": "person_unread_email_count",
+ "translation": {
+ "one": "{{.Person}} has {{.Count}} unread email.",
+ "other": "{{.Person}} has {{.Count}} unread emails."
+ }
+ },
+ {
+ "id": "person_unread_email_count_timeframe",
+ "translation": {
+ "other": "{{.Person}} has {{.Count}} unread emails in the past {{.Timeframe}}."
+ }
+ },
+ {
+ "id": "d_days",
+ "translation": {
+ "one": "{{.Count}} day",
+ "other": "{{.Count}} days"
+ }
+ }
+]
diff --git a/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/fr-fr.json b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/fr-fr.json
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/goi18n/testdata/input/yaml/fr-fr.json
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go
new file mode 100644
index 000000000..b9c0a0593
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/bundle/bundle_test.go
@@ -0,0 +1,289 @@
+package bundle
+
+import (
+ "fmt"
+ "testing"
+
+ "reflect"
+ "sort"
+
+ "github.com/nicksnyder/go-i18n/i18n/language"
+ "github.com/nicksnyder/go-i18n/i18n/translation"
+)
+
+func TestMustLoadTranslationFile(t *testing.T) {
+ t.Skipf("not implemented")
+}
+
+func TestLoadTranslationFile(t *testing.T) {
+ t.Skipf("not implemented")
+}
+
+func TestParseTranslationFileBytes(t *testing.T) {
+ t.Skipf("not implemented")
+}
+
+func TestAddTranslation(t *testing.T) {
+ t.Skipf("not implemented")
+}
+
+func TestMustTfunc(t *testing.T) {
+ defer func() {
+ if r := recover(); r == nil {
+ t.Errorf("expected MustTfunc to panic")
+ }
+ }()
+ New().MustTfunc("invalid")
+}
+
+func TestLanguageTagsAndTranslationIDs(t *testing.T) {
+ b := New()
+ translationID := "translation_id"
+ englishLanguage := languageWithTag("en-US")
+ frenchLanguage := languageWithTag("fr-FR")
+ spanishLanguage := languageWithTag("es")
+ addFakeTranslation(t, b, englishLanguage, "English"+translationID)
+ addFakeTranslation(t, b, frenchLanguage, translationID)
+ addFakeTranslation(t, b, spanishLanguage, translationID)
+
+ tags := b.LanguageTags()
+ sort.Strings(tags)
+ compareTo := []string{englishLanguage.Tag, spanishLanguage.Tag, frenchLanguage.Tag}
+ if !reflect.DeepEqual(tags, compareTo) {
+ t.Errorf("LanguageTags() = %#v; expected: %#v", tags, compareTo)
+ }
+
+ ids := b.LanguageTranslationIDs(englishLanguage.Tag)
+ sort.Strings(ids)
+ compareTo = []string{"English" + translationID}
+ if !reflect.DeepEqual(ids, compareTo) {
+ t.Errorf("LanguageTranslationIDs() = %#v; expected: %#v", ids, compareTo)
+ }
+}
+
+func TestTfuncAndLanguage(t *testing.T) {
+ b := New()
+ translationID := "translation_id"
+ englishLanguage := languageWithTag("en-US")
+ frenchLanguage := languageWithTag("fr-FR")
+ spanishLanguage := languageWithTag("es")
+ chineseLanguage := languageWithTag("zh-hans-cn")
+ englishTranslation := addFakeTranslation(t, b, englishLanguage, translationID)
+ frenchTranslation := addFakeTranslation(t, b, frenchLanguage, translationID)
+ spanishTranslation := addFakeTranslation(t, b, spanishLanguage, translationID)
+ chineseTranslation := addFakeTranslation(t, b, chineseLanguage, translationID)
+
+ tests := []struct {
+ languageIDs []string
+ result string
+ expectedLanguage *language.Language
+ }{
+ {
+ []string{"invalid"},
+ translationID,
+ nil,
+ },
+ {
+ []string{"invalid", "invalid2"},
+ translationID,
+ nil,
+ },
+ {
+ []string{"invalid", "en-US"},
+ englishTranslation,
+ englishLanguage,
+ },
+ {
+ []string{"en-US", "invalid"},
+ englishTranslation,
+ englishLanguage,
+ },
+ {
+ []string{"en-US", "fr-FR"},
+ englishTranslation,
+ englishLanguage,
+ },
+ {
+ []string{"invalid", "es"},
+ spanishTranslation,
+ spanishLanguage,
+ },
+ {
+ []string{"zh-CN,fr-XX,es"},
+ spanishTranslation,
+ spanishLanguage,
+ },
+ {
+ []string{"fr"},
+ frenchTranslation,
+
+ // The language is still "fr" even though the translation is provided by "fr-FR"
+ languageWithTag("fr"),
+ },
+ {
+ []string{"zh"},
+ chineseTranslation,
+
+ // The language is still "zh" even though the translation is provided by "zh-hans-cn"
+ languageWithTag("zh"),
+ },
+ {
+ []string{"zh-hans"},
+ chineseTranslation,
+
+ // The language is still "zh-hans" even though the translation is provided by "zh-hans-cn"
+ languageWithTag("zh-hans"),
+ },
+ {
+ []string{"zh-hans-cn"},
+ chineseTranslation,
+ languageWithTag("zh-hans-cn"),
+ },
+ }
+
+ for i, test := range tests {
+ tf, lang, err := b.TfuncAndLanguage(test.languageIDs[0], test.languageIDs[1:]...)
+ if err != nil && test.expectedLanguage != nil {
+ t.Errorf("Tfunc(%v) = error{%q}; expected no error", test.languageIDs, err)
+ }
+ if err == nil && test.expectedLanguage == nil {
+ t.Errorf("Tfunc(%v) = nil error; expected error", test.languageIDs)
+ }
+ if result := tf(translationID); result != test.result {
+ t.Errorf("translation %d was %s; expected %s", i, result, test.result)
+ }
+ if (lang == nil && test.expectedLanguage != nil) ||
+ (lang != nil && test.expectedLanguage == nil) ||
+ (lang != nil && test.expectedLanguage != nil && lang.String() != test.expectedLanguage.String()) {
+ t.Errorf("lang %d was %s; expected %s", i, lang, test.expectedLanguage)
+ }
+ }
+}
+
+func addFakeTranslation(t *testing.T, b *Bundle, lang *language.Language, translationID string) string {
+ translation := fakeTranslation(lang, translationID)
+ b.AddTranslation(lang, testNewTranslation(t, map[string]interface{}{
+ "id": translationID,
+ "translation": translation,
+ }))
+ return translation
+}
+
+func fakeTranslation(lang *language.Language, translationID string) string {
+ return fmt.Sprintf("%s(%s)", lang.Tag, translationID)
+}
+
+func testNewTranslation(t *testing.T, data map[string]interface{}) translation.Translation {
+ translation, err := translation.NewTranslation(data)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return translation
+}
+
+func languageWithTag(tag string) *language.Language {
+ return language.MustParse(tag)[0]
+}
+
+func createBenchmarkTranslateFunc(b *testing.B, translationTemplate interface{}, count interface{}, expected string) func(data interface{}) {
+ bundle := New()
+ lang := "en-US"
+ translationID := "translation_id"
+ translation, err := translation.NewTranslation(map[string]interface{}{
+ "id": translationID,
+ "translation": translationTemplate,
+ })
+ if err != nil {
+ b.Fatal(err)
+ }
+ bundle.AddTranslation(languageWithTag(lang), translation)
+ tf, err := bundle.Tfunc(lang)
+ if err != nil {
+ b.Fatal(err)
+ }
+ return func(data interface{}) {
+ var result string
+ if count == nil {
+ result = tf(translationID, data)
+ } else {
+ result = tf(translationID, count, data)
+ }
+ if result != expected {
+ b.Fatalf("expected %q, got %q", expected, result)
+ }
+ }
+}
+
+func createBenchmarkPluralTranslateFunc(b *testing.B) func(data interface{}) {
+ translationTemplate := map[string]interface{}{
+ "one": "{{.Person}} is {{.Count}} year old.",
+ "other": "{{.Person}} is {{.Count}} years old.",
+ }
+ count := 26
+ expected := "Bob is 26 years old."
+ return createBenchmarkTranslateFunc(b, translationTemplate, count, expected)
+}
+
+func createBenchmarkNonPluralTranslateFunc(b *testing.B) func(data interface{}) {
+ translationTemplate := "Hi {{.Person}}!"
+ expected := "Hi Bob!"
+ return createBenchmarkTranslateFunc(b, translationTemplate, nil, expected)
+}
+
+func BenchmarkTranslateNonPluralWithMap(b *testing.B) {
+ data := map[string]interface{}{
+ "Person": "Bob",
+ }
+ tf := createBenchmarkNonPluralTranslateFunc(b)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ tf(data)
+ }
+}
+
+func BenchmarkTranslateNonPluralWithStruct(b *testing.B) {
+ data := struct{ Person string }{Person: "Bob"}
+ tf := createBenchmarkNonPluralTranslateFunc(b)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ tf(data)
+ }
+}
+
+func BenchmarkTranslateNonPluralWithStructPointer(b *testing.B) {
+ data := &struct{ Person string }{Person: "Bob"}
+ tf := createBenchmarkNonPluralTranslateFunc(b)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ tf(data)
+ }
+}
+
+func BenchmarkTranslatePluralWithMap(b *testing.B) {
+ data := map[string]interface{}{
+ "Person": "Bob",
+ }
+ tf := createBenchmarkPluralTranslateFunc(b)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ tf(data)
+ }
+}
+
+func BenchmarkTranslatePluralWithStruct(b *testing.B) {
+ data := struct{ Person string }{Person: "Bob"}
+ tf := createBenchmarkPluralTranslateFunc(b)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ tf(data)
+ }
+}
+
+func BenchmarkTranslatePluralWithStructPointer(b *testing.B) {
+ data := &struct{ Person string }{Person: "Bob"}
+ tf := createBenchmarkPluralTranslateFunc(b)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ tf(data)
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go
new file mode 100644
index 000000000..d2d9706a7
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/example_test.go
@@ -0,0 +1,63 @@
+package i18n_test
+
+import (
+ "fmt"
+
+ "github.com/nicksnyder/go-i18n/i18n"
+)
+
+func Example() {
+ i18n.MustLoadTranslationFile("../goi18n/testdata/expected/en-us.all.json")
+
+ T, _ := i18n.Tfunc("en-US")
+
+ bobMap := map[string]interface{}{"Person": "Bob"}
+ bobStruct := struct{ Person string }{Person: "Bob"}
+
+ fmt.Println(T("program_greeting"))
+ fmt.Println(T("person_greeting", bobMap))
+ fmt.Println(T("person_greeting", bobStruct))
+
+ fmt.Println(T("your_unread_email_count", 0))
+ fmt.Println(T("your_unread_email_count", 1))
+ fmt.Println(T("your_unread_email_count", 2))
+ fmt.Println(T("my_height_in_meters", "1.7"))
+
+ fmt.Println(T("person_unread_email_count", 0, bobMap))
+ fmt.Println(T("person_unread_email_count", 1, bobMap))
+ fmt.Println(T("person_unread_email_count", 2, bobMap))
+ fmt.Println(T("person_unread_email_count", 0, bobStruct))
+ fmt.Println(T("person_unread_email_count", 1, bobStruct))
+ fmt.Println(T("person_unread_email_count", 2, bobStruct))
+
+ fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": T("d_days", 0),
+ }))
+ fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": T("d_days", 1),
+ }))
+ fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": T("d_days", 2),
+ }))
+
+ // Output:
+ // Hello world
+ // Hello Bob
+ // Hello Bob
+ // You have 0 unread emails.
+ // You have 1 unread email.
+ // You have 2 unread emails.
+ // I am 1.7 meters tall.
+ // Bob has 0 unread emails.
+ // Bob has 1 unread email.
+ // Bob has 2 unread emails.
+ // Bob has 0 unread emails.
+ // Bob has 1 unread email.
+ // Bob has 2 unread emails.
+ // Bob has 3 unread emails in the past 0 days.
+ // Bob has 3 unread emails in the past 1 day.
+ // Bob has 3 unread emails in the past 2 days.
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go
new file mode 100644
index 000000000..962936610
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/exampletemplate_test.go
@@ -0,0 +1,63 @@
+package i18n_test
+
+import (
+ "github.com/nicksnyder/go-i18n/i18n"
+ "os"
+ "text/template"
+)
+
+var funcMap = map[string]interface{}{
+ "T": i18n.IdentityTfunc,
+}
+
+var tmpl = template.Must(template.New("").Funcs(funcMap).Parse(`
+{{T "program_greeting"}}
+{{T "person_greeting" .}}
+{{T "your_unread_email_count" 0}}
+{{T "your_unread_email_count" 1}}
+{{T "your_unread_email_count" 2}}
+{{T "person_unread_email_count" 0 .}}
+{{T "person_unread_email_count" 1 .}}
+{{T "person_unread_email_count" 2 .}}
+`))
+
+func Example_template() {
+ i18n.MustLoadTranslationFile("../goi18n/testdata/expected/en-us.all.json")
+
+ T, _ := i18n.Tfunc("en-US")
+ tmpl.Funcs(map[string]interface{}{
+ "T": T,
+ })
+
+ tmpl.Execute(os.Stdout, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": T("d_days", 1),
+ })
+
+ tmpl.Execute(os.Stdout, struct {
+ Person string
+ Timeframe string
+ }{
+ Person: "Bob",
+ Timeframe: T("d_days", 1),
+ })
+
+ // Output:
+ // Hello world
+ // Hello Bob
+ // You have 0 unread emails.
+ // You have 1 unread email.
+ // You have 2 unread emails.
+ // Bob has 0 unread emails.
+ // Bob has 1 unread email.
+ // Bob has 2 unread emails.
+ //
+ // Hello world
+ // Hello Bob
+ // You have 0 unread emails.
+ // You have 1 unread email.
+ // You have 2 unread emails.
+ // Bob has 0 unread emails.
+ // Bob has 1 unread email.
+ // Bob has 2 unread emails.
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go
new file mode 100644
index 000000000..b2e7bdcfe
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/exampleyaml_test.go
@@ -0,0 +1,62 @@
+package i18n_test
+
+import (
+ "fmt"
+ "github.com/nicksnyder/go-i18n/i18n"
+)
+
+func ExampleYAML() {
+ i18n.MustLoadTranslationFile("../goi18n/testdata/en-us.yaml")
+
+ T, _ := i18n.Tfunc("en-US")
+
+ bobMap := map[string]interface{}{"Person": "Bob"}
+ bobStruct := struct{ Person string }{Person: "Bob"}
+
+ fmt.Println(T("program_greeting"))
+ fmt.Println(T("person_greeting", bobMap))
+ fmt.Println(T("person_greeting", bobStruct))
+
+ fmt.Println(T("your_unread_email_count", 0))
+ fmt.Println(T("your_unread_email_count", 1))
+ fmt.Println(T("your_unread_email_count", 2))
+ fmt.Println(T("my_height_in_meters", "1.7"))
+
+ fmt.Println(T("person_unread_email_count", 0, bobMap))
+ fmt.Println(T("person_unread_email_count", 1, bobMap))
+ fmt.Println(T("person_unread_email_count", 2, bobMap))
+ fmt.Println(T("person_unread_email_count", 0, bobStruct))
+ fmt.Println(T("person_unread_email_count", 1, bobStruct))
+ fmt.Println(T("person_unread_email_count", 2, bobStruct))
+
+ fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": T("d_days", 0),
+ }))
+ fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": T("d_days", 1),
+ }))
+ fmt.Println(T("person_unread_email_count_timeframe", 3, map[string]interface{}{
+ "Person": "Bob",
+ "Timeframe": T("d_days", 2),
+ }))
+
+ // Output:
+ // Hello world
+ // Hello Bob
+ // Hello Bob
+ // You have 0 unread emails.
+ // You have 1 unread email.
+ // You have 2 unread emails.
+ // I am 1.7 meters tall.
+ // Bob has 0 unread emails.
+ // Bob has 1 unread email.
+ // Bob has 2 unread emails.
+ // Bob has 0 unread emails.
+ // Bob has 1 unread email.
+ // Bob has 2 unread emails.
+ // Bob has 3 unread emails in the past 0 days.
+ // Bob has 3 unread emails in the past 1 day.
+ // Bob has 3 unread emails in the past 2 days.
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh
new file mode 100644
index 000000000..a9fae846a
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/generate.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+go build && ./codegen -cout ../pluralspec_gen.go -tout ../pluralspec_gen_test.go && \
+ gofmt -w=true ../pluralspec_gen.go && \
+ gofmt -w=true ../pluralspec_gen_test.go && \
+ rm codegen
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go
new file mode 100644
index 000000000..5d6b6ad4f
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/main.go
@@ -0,0 +1,132 @@
+package main
+
+import (
+ "encoding/xml"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "text/template"
+)
+
+var usage = `%[1]s generates Go code to support CLDR plural rules.
+
+Usage: %[1]s [options]
+
+Options:
+
+`
+
+func main() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, usage, os.Args[0])
+ flag.PrintDefaults()
+ }
+ var in, cout, tout string
+ flag.StringVar(&in, "i", "plurals.xml", "the input XML file containing CLDR plural rules")
+ flag.StringVar(&cout, "cout", "", "the code output file")
+ flag.StringVar(&tout, "tout", "", "the test output file")
+ flag.BoolVar(&verbose, "v", false, "verbose output")
+ flag.Parse()
+
+ buf, err := ioutil.ReadFile(in)
+ if err != nil {
+ fatalf("failed to read file: %s", err)
+ }
+
+ var data SupplementalData
+ if err := xml.Unmarshal(buf, &data); err != nil {
+ fatalf("failed to unmarshal xml: %s", err)
+ }
+
+ count := 0
+ for _, pg := range data.PluralGroups {
+ count += len(pg.SplitLocales())
+ }
+ infof("parsed %d locales", count)
+
+ if cout != "" {
+ file := openWritableFile(cout)
+ if err := codeTemplate.Execute(file, data); err != nil {
+ fatalf("unable to execute code template because %s", err)
+ } else {
+ infof("generated %s", cout)
+ }
+ } else {
+ infof("not generating code file (use -cout)")
+ }
+
+ if tout != "" {
+ file := openWritableFile(tout)
+ if err := testTemplate.Execute(file, data); err != nil {
+ fatalf("unable to execute test template because %s", err)
+ } else {
+ infof("generated %s", tout)
+ }
+ } else {
+ infof("not generating test file (use -tout)")
+ }
+}
+
+func openWritableFile(name string) *os.File {
+ file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ fatalf("failed to write file %s because %s", name, err)
+ }
+ return file
+}
+
+var codeTemplate = template.Must(template.New("spec").Parse(`package language
+// This file is generated by i18n/language/codegen/generate.sh
+
+func init() {
+{{range .PluralGroups}}
+ registerPluralSpec({{printf "%#v" .SplitLocales}}, &PluralSpec{
+ Plurals: newPluralSet({{range $i, $e := .PluralRules}}{{if $i}}, {{end}}{{$e.CountTitle}}{{end}}),
+ PluralFunc: func(ops *operands) Plural { {{range .PluralRules}}{{if .GoCondition}}
+ // {{.Condition}}
+ if {{.GoCondition}} {
+ return {{.CountTitle}}
+ }{{end}}{{end}}
+ return Other
+ },
+ }){{end}}
+}
+`))
+
+var testTemplate = template.Must(template.New("spec").Parse(`package language
+// This file is generated by i18n/language/codegen/generate.sh
+
+import "testing"
+
+{{range .PluralGroups}}
+func Test{{.Name}}(t *testing.T) {
+ var tests []pluralTest
+ {{range .PluralRules}}
+ {{if .IntegerExamples}}tests = appendIntegerTests(tests, {{.CountTitle}}, {{printf "%#v" .IntegerExamples}}){{end}}
+ {{if .DecimalExamples}}tests = appendDecimalTests(tests, {{.CountTitle}}, {{printf "%#v" .DecimalExamples}}){{end}}
+ {{end}}
+ locales := {{printf "%#v" .SplitLocales}}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+{{end}}
+`))
+
+func infof(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, format+"\n", args...)
+}
+
+var verbose bool
+
+func verbosef(format string, args ...interface{}) {
+ if verbose {
+ infof(format, args...)
+ }
+}
+
+func fatalf(format string, args ...interface{}) {
+ infof("fatal: "+format+"\n", args...)
+ os.Exit(1)
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/plurals.xml b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/plurals.xml
new file mode 100644
index 000000000..cdd0b5296
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/plurals.xml
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE supplementalData SYSTEM "../../common/dtd/ldmlSupplemental.dtd">
+<!--
+Copyright © 1991-2015 Unicode, Inc.
+CLDR data files are interpreted according to the LDML specification (http://unicode.org/reports/tr35/)
+For terms of use, see http://www.unicode.org/copyright.html
+-->
+<supplementalData>
+ <version number="$Revision: 12002 $"/>
+ <plurals type="cardinal">
+ <!-- For a canonicalized list, use GeneratedPluralSamples -->
+
+ <!-- 1: other -->
+
+ <pluralRules locales="bm bo dz id ig ii in ja jbo jv jw kde kea km ko lkt lo ms my nqo root sah ses sg th to vi wo yo zh">
+ <pluralRule count="other"> @integer 0~15, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+
+ <!-- 2: one,other -->
+
+ <pluralRules locales="am as bn fa gu hi kn mr zu">
+ <pluralRule count="one">i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04</pluralRule>
+ <pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~2.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="ff fr hy kab">
+ <pluralRule count="one">i = 0,1 @integer 0, 1 @decimal 0.0~1.5</pluralRule>
+ <pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="ast ca de en et fi fy gl it ji nl sv sw ur yi">
+ <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
+ <pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="si">
+ <pluralRule count="one">n = 0,1 or i = 0 and f = 1 @integer 0, 1 @decimal 0.0, 0.1, 1.0, 0.00, 0.01, 1.00, 0.000, 0.001, 1.000, 0.0000, 0.0001, 1.0000</pluralRule>
+ <pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.2~0.9, 1.1~1.8, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="ak bh guw ln mg nso pa ti wa">
+ <pluralRule count="one">n = 0..1 @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000</pluralRule>
+ <pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="tzm">
+ <pluralRule count="one">n = 0..1 or n = 11..99 @integer 0, 1, 11~24 @decimal 0.0, 1.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0</pluralRule>
+ <pluralRule count="other"> @integer 2~10, 100~106, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="pt">
+ <pluralRule count="one">n = 0..2 and n != 2 @integer 0, 1 @decimal 0.0, 1.0, 0.00, 1.00, 0.000, 1.000, 0.0000, 1.0000</pluralRule>
+ <pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="af asa az bem bez bg brx ce cgg chr ckb dv ee el eo es eu fo fur gsw ha haw hu jgo jmc ka kaj kcg kk kkj kl ks ksb ku ky lb lg mas mgo ml mn nah nb nd ne nn nnh no nr ny nyn om or os pap ps rm rof rwk saq sdh seh sn so sq ss ssy st syr ta te teo tig tk tn tr ts ug uz ve vo vun wae xh xog">
+ <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
+ <pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="pt_PT">
+ <pluralRule count="one">n = 1 and v = 0 @integer 1</pluralRule>
+ <pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="da">
+ <pluralRule count="one">n = 1 or t != 0 and i = 0,1 @integer 1 @decimal 0.1~1.6</pluralRule>
+ <pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 2.0~3.4, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="is">
+ <pluralRule count="one">t = 0 and i % 10 = 1 and i % 100 != 11 or t != 0 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1~1.6, 10.1, 100.1, 1000.1, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="mk">
+ <pluralRule count="one">v = 0 and i % 10 = 1 or f % 10 = 1 @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 2~10, 12~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.2~1.0, 1.2~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="fil tl">
+ <pluralRule count="one">v = 0 and i = 1,2,3 or v = 0 and i % 10 != 4,6,9 or v != 0 and f % 10 != 4,6,9 @integer 0~3, 5, 7, 8, 10~13, 15, 17, 18, 20, 21, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.3, 0.5, 0.7, 0.8, 1.0~1.3, 1.5, 1.7, 1.8, 2.0, 2.1, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ <pluralRule count="other"> @integer 4, 6, 9, 14, 16, 19, 24, 26, 104, 1004, … @decimal 0.4, 0.6, 0.9, 1.4, 1.6, 1.9, 2.4, 2.6, 10.4, 100.4, 1000.4, …</pluralRule>
+ </pluralRules>
+
+ <!-- 3: zero,one,other -->
+
+ <pluralRules locales="lv prg">
+ <pluralRule count="zero">n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19 @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ <pluralRule count="one">n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.0, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule>
+ <pluralRule count="other"> @integer 2~9, 22~29, 102, 1002, … @decimal 0.2~0.9, 1.2~1.9, 10.2, 100.2, 1000.2, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="lag">
+ <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
+ <pluralRule count="one">i = 0,1 and n != 0 @integer 1 @decimal 0.1~1.6</pluralRule>
+ <pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="ksh">
+ <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
+ <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
+ <pluralRule count="other"> @integer 2~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+
+ <!-- 3: one,two,other -->
+
+ <pluralRules locales="iu kw naq se sma smi smj smn sms">
+ <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
+ <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
+ <pluralRule count="other"> @integer 0, 3~17, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+
+ <!-- 3: one,few,other -->
+
+ <pluralRules locales="shi">
+ <pluralRule count="one">i = 0 or n = 1 @integer 0, 1 @decimal 0.0~1.0, 0.00~0.04</pluralRule>
+ <pluralRule count="few">n = 2..10 @integer 2~10 @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00</pluralRule>
+ <pluralRule count="other"> @integer 11~26, 100, 1000, 10000, 100000, 1000000, … @decimal 1.1~1.9, 2.1~2.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="mo ro">
+ <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
+ <pluralRule count="few">v != 0 or n = 0 or n != 1 and n % 100 = 1..19 @integer 0, 2~16, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ <pluralRule count="other"> @integer 20~35, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="bs hr sh sr">
+ <pluralRule count="one">v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule>
+ <pluralRule count="few">v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 0.2~0.4, 1.2~1.4, 2.2~2.4, 3.2~3.4, 4.2~4.4, 5.2, 10.2, 100.2, 1000.2, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+
+ <!-- 4: one,two,few,other -->
+
+ <pluralRules locales="gd">
+ <pluralRule count="one">n = 1,11 @integer 1, 11 @decimal 1.0, 11.0, 1.00, 11.00, 1.000, 11.000, 1.0000</pluralRule>
+ <pluralRule count="two">n = 2,12 @integer 2, 12 @decimal 2.0, 12.0, 2.00, 12.00, 2.000, 12.000, 2.0000</pluralRule>
+ <pluralRule count="few">n = 3..10,13..19 @integer 3~10, 13~19 @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 3.00</pluralRule>
+ <pluralRule count="other"> @integer 0, 20~34, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="sl">
+ <pluralRule count="one">v = 0 and i % 100 = 1 @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, …</pluralRule>
+ <pluralRule count="two">v = 0 and i % 100 = 2 @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, …</pluralRule>
+ <pluralRule count="few">v = 0 and i % 100 = 3..4 or v != 0 @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="dsb hsb">
+ <pluralRule count="one">v = 0 and i % 100 = 1 or f % 100 = 1 @integer 1, 101, 201, 301, 401, 501, 601, 701, 1001, … @decimal 0.1, 1.1, 2.1, 3.1, 4.1, 5.1, 6.1, 7.1, 10.1, 100.1, 1000.1, …</pluralRule>
+ <pluralRule count="two">v = 0 and i % 100 = 2 or f % 100 = 2 @integer 2, 102, 202, 302, 402, 502, 602, 702, 1002, … @decimal 0.2, 1.2, 2.2, 3.2, 4.2, 5.2, 6.2, 7.2, 10.2, 100.2, 1000.2, …</pluralRule>
+ <pluralRule count="few">v = 0 and i % 100 = 3..4 or f % 100 = 3..4 @integer 3, 4, 103, 104, 203, 204, 303, 304, 403, 404, 503, 504, 603, 604, 703, 704, 1003, … @decimal 0.3, 0.4, 1.3, 1.4, 2.3, 2.4, 3.3, 3.4, 4.3, 4.4, 5.3, 5.4, 6.3, 6.4, 7.3, 7.4, 10.3, 100.3, 1000.3, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 0.5~1.0, 1.5~2.0, 2.5~2.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+
+ <!-- 4: one,two,many,other -->
+
+ <pluralRules locales="he iw">
+ <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
+ <pluralRule count="two">i = 2 and v = 0 @integer 2</pluralRule>
+ <pluralRule count="many">v = 0 and n != 0..10 and n % 10 = 0 @integer 20, 30, 40, 50, 60, 70, 80, 90, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 3~17, 101, 1001, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+
+ <!-- 4: one,few,many,other -->
+
+ <pluralRules locales="cs sk">
+ <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
+ <pluralRule count="few">i = 2..4 and v = 0 @integer 2~4</pluralRule>
+ <pluralRule count="many">v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="pl">
+ <pluralRule count="one">i = 1 and v = 0 @integer 1</pluralRule>
+ <pluralRule count="few">v = 0 and i % 10 = 2..4 and i % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …</pluralRule>
+ <pluralRule count="many">v = 0 and i != 1 and i % 10 = 0..1 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 12..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
+ <pluralRule count="other"> @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="be">
+ <pluralRule count="one">n % 10 = 1 and n % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, …</pluralRule>
+ <pluralRule count="few">n % 10 = 2..4 and n % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, … @decimal 2.0, 3.0, 4.0, 22.0, 23.0, 24.0, 32.0, 33.0, 102.0, 1002.0, …</pluralRule>
+ <pluralRule count="many">n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ <pluralRule count="other"> @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="lt">
+ <pluralRule count="one">n % 10 = 1 and n % 100 != 11..19 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 71.0, 81.0, 101.0, 1001.0, …</pluralRule>
+ <pluralRule count="few">n % 10 = 2..9 and n % 100 != 11..19 @integer 2~9, 22~29, 102, 1002, … @decimal 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 22.0, 102.0, 1002.0, …</pluralRule>
+ <pluralRule count="many">f != 0 @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.1, 1000.1, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 10~20, 30, 40, 50, 60, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="mt">
+ <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
+ <pluralRule count="few">n = 0 or n % 100 = 2..10 @integer 0, 2~10, 102~107, 1002, … @decimal 0.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 10.0, 102.0, 1002.0, …</pluralRule>
+ <pluralRule count="many">n % 100 = 11..19 @integer 11~19, 111~117, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, …</pluralRule>
+ <pluralRule count="other"> @integer 20~35, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="ru uk">
+ <pluralRule count="one">v = 0 and i % 10 = 1 and i % 100 != 11 @integer 1, 21, 31, 41, 51, 61, 71, 81, 101, 1001, …</pluralRule>
+ <pluralRule count="few">v = 0 and i % 10 = 2..4 and i % 100 != 12..14 @integer 2~4, 22~24, 32~34, 42~44, 52~54, 62, 102, 1002, …</pluralRule>
+ <pluralRule count="many">v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14 @integer 0, 5~19, 100, 1000, 10000, 100000, 1000000, …</pluralRule>
+ <pluralRule count="other"> @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+
+ <!-- 5: one,two,few,many,other -->
+
+ <pluralRules locales="br">
+ <pluralRule count="one">n % 10 = 1 and n % 100 != 11,71,91 @integer 1, 21, 31, 41, 51, 61, 81, 101, 1001, … @decimal 1.0, 21.0, 31.0, 41.0, 51.0, 61.0, 81.0, 101.0, 1001.0, …</pluralRule>
+ <pluralRule count="two">n % 10 = 2 and n % 100 != 12,72,92 @integer 2, 22, 32, 42, 52, 62, 82, 102, 1002, … @decimal 2.0, 22.0, 32.0, 42.0, 52.0, 62.0, 82.0, 102.0, 1002.0, …</pluralRule>
+ <pluralRule count="few">n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99 @integer 3, 4, 9, 23, 24, 29, 33, 34, 39, 43, 44, 49, 103, 1003, … @decimal 3.0, 4.0, 9.0, 23.0, 24.0, 29.0, 33.0, 34.0, 103.0, 1003.0, …</pluralRule>
+ <pluralRule count="many">n != 0 and n % 1000000 = 0 @integer 1000000, … @decimal 1000000.0, 1000000.00, 1000000.000, …</pluralRule>
+ <pluralRule count="other"> @integer 0, 5~8, 10~20, 100, 1000, 10000, 100000, … @decimal 0.0~0.9, 1.1~1.6, 10.0, 100.0, 1000.0, 10000.0, 100000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="ga">
+ <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
+ <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
+ <pluralRule count="few">n = 3..6 @integer 3~6 @decimal 3.0, 4.0, 5.0, 6.0, 3.00, 4.00, 5.00, 6.00, 3.000, 4.000, 5.000, 6.000, 3.0000, 4.0000, 5.0000, 6.0000</pluralRule>
+ <pluralRule count="many">n = 7..10 @integer 7~10 @decimal 7.0, 8.0, 9.0, 10.0, 7.00, 8.00, 9.00, 10.00, 7.000, 8.000, 9.000, 10.000, 7.0000, 8.0000, 9.0000, 10.0000</pluralRule>
+ <pluralRule count="other"> @integer 0, 11~25, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~0.9, 1.1~1.6, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="gv">
+ <pluralRule count="one">v = 0 and i % 10 = 1 @integer 1, 11, 21, 31, 41, 51, 61, 71, 101, 1001, …</pluralRule>
+ <pluralRule count="two">v = 0 and i % 10 = 2 @integer 2, 12, 22, 32, 42, 52, 62, 72, 102, 1002, …</pluralRule>
+ <pluralRule count="few">v = 0 and i % 100 = 0,20,40,60,80 @integer 0, 20, 40, 60, 80, 100, 120, 140, 1000, 10000, 100000, 1000000, …</pluralRule>
+ <pluralRule count="many">v != 0 @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ <pluralRule count="other"> @integer 3~10, 13~19, 23, 103, 1003, …</pluralRule>
+ </pluralRules>
+
+ <!-- 6: zero,one,two,few,many,other -->
+
+ <pluralRules locales="ar">
+ <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
+ <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
+ <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
+ <pluralRule count="few">n % 100 = 3..10 @integer 3~10, 103~110, 1003, … @decimal 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 103.0, 1003.0, …</pluralRule>
+ <pluralRule count="many">n % 100 = 11..99 @integer 11~26, 111, 1011, … @decimal 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 111.0, 1011.0, …</pluralRule>
+ <pluralRule count="other"> @integer 100~102, 200~202, 300~302, 400~402, 500~502, 600, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.1, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ <pluralRules locales="cy">
+ <pluralRule count="zero">n = 0 @integer 0 @decimal 0.0, 0.00, 0.000, 0.0000</pluralRule>
+ <pluralRule count="one">n = 1 @integer 1 @decimal 1.0, 1.00, 1.000, 1.0000</pluralRule>
+ <pluralRule count="two">n = 2 @integer 2 @decimal 2.0, 2.00, 2.000, 2.0000</pluralRule>
+ <pluralRule count="few">n = 3 @integer 3 @decimal 3.0, 3.00, 3.000, 3.0000</pluralRule>
+ <pluralRule count="many">n = 6 @integer 6 @decimal 6.0, 6.00, 6.000, 6.0000</pluralRule>
+ <pluralRule count="other"> @integer 4, 5, 7~20, 100, 1000, 10000, 100000, 1000000, … @decimal 0.1~0.9, 1.1~1.7, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …</pluralRule>
+ </pluralRules>
+ </plurals>
+</supplementalData>
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go
new file mode 100644
index 000000000..9d39053c2
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/codegen/xml.go
@@ -0,0 +1,143 @@
+package main
+
+import (
+ "encoding/xml"
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// SupplementalData is the top level struct of plural.xml
+type SupplementalData struct {
+ XMLName xml.Name `xml:"supplementalData"`
+ PluralGroups []PluralGroup `xml:"plurals>pluralRules"`
+}
+
+// PluralGroup is a group of locales with the same plural rules.
+type PluralGroup struct {
+ Locales string `xml:"locales,attr"`
+ PluralRules []PluralRule `xml:"pluralRule"`
+}
+
+// Name returns a unique name for this plural group.
+func (pg *PluralGroup) Name() string {
+ n := strings.Title(pg.Locales)
+ return strings.Replace(n, " ", "", -1)
+}
+
+// SplitLocales returns all the locales in the PluralGroup as a slice.
+func (pg *PluralGroup) SplitLocales() []string {
+ return strings.Split(pg.Locales, " ")
+}
+
+// PluralRule is the rule for a single plural form.
+type PluralRule struct {
+ Count string `xml:"count,attr"`
+ Rule string `xml:",innerxml"`
+}
+
+// CountTitle returns the title case of the PluralRule's count.
+func (pr *PluralRule) CountTitle() string {
+ return strings.Title(pr.Count)
+}
+
+// Condition returns the condition where the PluralRule applies.
+func (pr *PluralRule) Condition() string {
+ i := strings.Index(pr.Rule, "@")
+ return pr.Rule[:i]
+}
+
+// Examples returns the integer and decimal exmaples for the PLuralRule.
+func (pr *PluralRule) Examples() (integer []string, decimal []string) {
+ ex := strings.Replace(pr.Rule, ", …", "", -1)
+ ddelim := "@decimal"
+ if i := strings.Index(ex, ddelim); i > 0 {
+ dex := strings.TrimSpace(ex[i+len(ddelim):])
+ decimal = strings.Split(dex, ", ")
+ ex = ex[:i]
+ }
+ idelim := "@integer"
+ if i := strings.Index(ex, idelim); i > 0 {
+ iex := strings.TrimSpace(ex[i+len(idelim):])
+ integer = strings.Split(iex, ", ")
+ }
+ return integer, decimal
+}
+
+// IntegerExamples returns the integer exmaples for the PLuralRule.
+func (pr *PluralRule) IntegerExamples() []string {
+ integer, _ := pr.Examples()
+ return integer
+}
+
+// DecimalExamples returns the decimal exmaples for the PLuralRule.
+func (pr *PluralRule) DecimalExamples() []string {
+ _, decimal := pr.Examples()
+ return decimal
+}
+
+var relationRegexp = regexp.MustCompile("([niftvw])(?: % ([0-9]+))? (!=|=)(.*)")
+
+// GoCondition converts the XML condition to valid Go code.
+func (pr *PluralRule) GoCondition() string {
+ var ors []string
+ for _, and := range strings.Split(pr.Condition(), "or") {
+ var ands []string
+ for _, relation := range strings.Split(and, "and") {
+ parts := relationRegexp.FindStringSubmatch(relation)
+ if parts == nil {
+ continue
+ }
+ lvar, lmod, op, rhs := strings.Title(parts[1]), parts[2], parts[3], strings.TrimSpace(parts[4])
+ if op == "=" {
+ op = "=="
+ }
+ lvar = "ops." + lvar
+ var rhor []string
+ var rany []string
+ for _, rh := range strings.Split(rhs, ",") {
+ if parts := strings.Split(rh, ".."); len(parts) == 2 {
+ from, to := parts[0], parts[1]
+ if lvar == "ops.N" {
+ if lmod != "" {
+ rhor = append(rhor, fmt.Sprintf("ops.NmodInRange(%s, %s, %s)", lmod, from, to))
+ } else {
+ rhor = append(rhor, fmt.Sprintf("ops.NinRange(%s, %s)", from, to))
+ }
+ } else if lmod != "" {
+ rhor = append(rhor, fmt.Sprintf("intInRange(%s %% %s, %s, %s)", lvar, lmod, from, to))
+ } else {
+ rhor = append(rhor, fmt.Sprintf("intInRange(%s, %s, %s)", lvar, from, to))
+ }
+ } else {
+ rany = append(rany, rh)
+ }
+ }
+
+ if len(rany) > 0 {
+ rh := strings.Join(rany, ",")
+ if lvar == "ops.N" {
+ if lmod != "" {
+ rhor = append(rhor, fmt.Sprintf("ops.NmodEqualsAny(%s, %s)", lmod, rh))
+ } else {
+ rhor = append(rhor, fmt.Sprintf("ops.NequalsAny(%s)", rh))
+ }
+ } else if lmod != "" {
+ rhor = append(rhor, fmt.Sprintf("intEqualsAny(%s %% %s, %s)", lvar, lmod, rh))
+ } else {
+ rhor = append(rhor, fmt.Sprintf("intEqualsAny(%s, %s)", lvar, rh))
+ }
+ }
+ r := strings.Join(rhor, " || ")
+ if len(rhor) > 1 {
+ r = "(" + r + ")"
+ }
+ if op == "!=" {
+ r = "!" + r
+ }
+ ands = append(ands, r)
+ }
+ ors = append(ors, strings.Join(ands, " && "))
+ }
+ return strings.Join(ors, " ||\n")
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go
new file mode 100644
index 000000000..2949bfe4a
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/language_test.go
@@ -0,0 +1,85 @@
+package language
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestParse(t *testing.T) {
+ tests := []struct {
+ src string
+ lang []*Language
+ }{
+ {"en", []*Language{{"en", pluralSpecs["en"]}}},
+ {"en-US", []*Language{{"en-us", pluralSpecs["en"]}}},
+ {"en_US", []*Language{{"en-us", pluralSpecs["en"]}}},
+ {"en-GB", []*Language{{"en-gb", pluralSpecs["en"]}}},
+ {"zh-CN", []*Language{{"zh-cn", pluralSpecs["zh"]}}},
+ {"zh-TW", []*Language{{"zh-tw", pluralSpecs["zh"]}}},
+ {"pt-BR", []*Language{{"pt-br", pluralSpecs["pt"]}}},
+ {"pt_BR", []*Language{{"pt-br", pluralSpecs["pt"]}}},
+ {"pt-PT", []*Language{{"pt-pt", pluralSpecs["pt-pt"]}}},
+ {"pt_PT", []*Language{{"pt-pt", pluralSpecs["pt-pt"]}}},
+ {"zh-Hans-CN", []*Language{{"zh-hans-cn", pluralSpecs["zh"]}}},
+ {"zh-Hant-TW", []*Language{{"zh-hant-tw", pluralSpecs["zh"]}}},
+ {"en-US-en-US", []*Language{{"en-us-en-us", pluralSpecs["en"]}}},
+ {".en-US..en-US.", []*Language{{"en-us", pluralSpecs["en"]}}},
+ {
+ "it, xx-zz, xx-ZZ, zh, en-gb;q=0.8, en;q=0.7, es-ES;q=0.6, de-xx",
+ []*Language{
+ {"it", pluralSpecs["it"]},
+ {"zh", pluralSpecs["zh"]},
+ {"en-gb", pluralSpecs["en"]},
+ {"en", pluralSpecs["en"]},
+ {"es-es", pluralSpecs["es"]},
+ {"de-xx", pluralSpecs["de"]},
+ },
+ },
+ {
+ "it-qq,xx,xx-zz,xx-ZZ,zh,en-gb;q=0.8,en;q=0.7,es-ES;q=0.6,de-xx",
+ []*Language{
+ {"it-qq", pluralSpecs["it"]},
+ {"zh", pluralSpecs["zh"]},
+ {"en-gb", pluralSpecs["en"]},
+ {"en", pluralSpecs["en"]},
+ {"es-es", pluralSpecs["es"]},
+ {"de-xx", pluralSpecs["de"]},
+ },
+ },
+ {"en.json", []*Language{{"en", pluralSpecs["en"]}}},
+ {"en-US.json", []*Language{{"en-us", pluralSpecs["en"]}}},
+ {"en-us.json", []*Language{{"en-us", pluralSpecs["en"]}}},
+ {"en-xx.json", []*Language{{"en-xx", pluralSpecs["en"]}}},
+ {"xx-Yyen-US", nil},
+ {"en US", nil},
+ {"", nil},
+ {"-", nil},
+ {"_", nil},
+ {"-en", nil},
+ {"_en", nil},
+ {"-en-", nil},
+ {"_en_", nil},
+ {"xx", nil},
+ }
+ for _, test := range tests {
+ lang := Parse(test.src)
+ if !reflect.DeepEqual(lang, test.lang) {
+ t.Errorf("Parse(%q) = %s expected %s", test.src, lang, test.lang)
+ }
+ }
+}
+
+func TestMatchingTags(t *testing.T) {
+ tests := []struct {
+ lang *Language
+ matches []string
+ }{
+ {&Language{"zh-hans-cn", nil}, []string{"zh", "zh-hans", "zh-hans-cn"}},
+ {&Language{"foo", nil}, []string{"foo"}},
+ }
+ for _, test := range tests {
+ if actual := test.lang.MatchingTags(); !reflect.DeepEqual(test.matches, actual) {
+ t.Errorf("matchingTags(%q) = %q expected %q", test.lang.Tag, actual, test.matches)
+ }
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go
new file mode 100644
index 000000000..29030876a
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/operands_test.go
@@ -0,0 +1,45 @@
+package language
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestNewOperands(t *testing.T) {
+ tests := []struct {
+ input interface{}
+ ops *operands
+ err bool
+ }{
+ {int64(0), &operands{0.0, 0, 0, 0, 0, 0}, false},
+ {int64(1), &operands{1.0, 1, 0, 0, 0, 0}, false},
+ {"0", &operands{0.0, 0, 0, 0, 0, 0}, false},
+ {"1", &operands{1.0, 1, 0, 0, 0, 0}, false},
+ {"1.0", &operands{1.0, 1, 1, 0, 0, 0}, false},
+ {"1.00", &operands{1.0, 1, 2, 0, 0, 0}, false},
+ {"1.3", &operands{1.3, 1, 1, 1, 3, 3}, false},
+ {"1.30", &operands{1.3, 1, 2, 1, 30, 3}, false},
+ {"1.03", &operands{1.03, 1, 2, 2, 3, 3}, false},
+ {"1.230", &operands{1.23, 1, 3, 2, 230, 23}, false},
+ {"20.0230", &operands{20.023, 20, 4, 3, 230, 23}, false},
+ {20.0230, nil, true},
+ }
+ for _, test := range tests {
+ ops, err := newOperands(test.input)
+ if err != nil && !test.err {
+ t.Errorf("newOperands(%#v) unexpected error: %s", test.input, err)
+ } else if err == nil && test.err {
+ t.Errorf("newOperands(%#v) returned %#v; expected error", test.input, ops)
+ } else if !reflect.DeepEqual(ops, test.ops) {
+ t.Errorf("newOperands(%#v) returned %#v; expected %#v", test.input, ops, test.ops)
+ }
+ }
+}
+
+func BenchmarkNewOperand(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ if _, err := newOperands("1234.56780000"); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go
new file mode 100644
index 000000000..6336d29b2
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/plural_test.go
@@ -0,0 +1,28 @@
+package language
+
+import (
+ "testing"
+)
+
+func TestNewPlural(t *testing.T) {
+ tests := []struct {
+ src string
+ plural Plural
+ err bool
+ }{
+ {"zero", Zero, false},
+ {"one", One, false},
+ {"two", Two, false},
+ {"few", Few, false},
+ {"many", Many, false},
+ {"other", Other, false},
+ {"asdf", Invalid, true},
+ }
+ for _, test := range tests {
+ plural, err := NewPlural(test.src)
+ wrongErr := (err != nil && !test.err) || (err == nil && test.err)
+ if plural != test.plural || wrongErr {
+ t.Errorf("NewPlural(%#v) returned %#v,%#v; expected %#v", test.src, plural, err, test.plural)
+ }
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go
new file mode 100644
index 000000000..c8ec41fd4
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_gen_test.go
@@ -0,0 +1,645 @@
+package language
+
+// This file is generated by i18n/language/codegen/generate.sh
+
+import "testing"
+
+func TestBmBoDzIdIgIiInJaJboJvJwKdeKeaKmKoLktLoMsMyNqoRootSahSesSgThToViWoYoZh(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, Other, []string{"0~15", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"bm", "bo", "dz", "id", "ig", "ii", "in", "ja", "jbo", "jv", "jw", "kde", "kea", "km", "ko", "lkt", "lo", "ms", "my", "nqo", "root", "sah", "ses", "sg", "th", "to", "vi", "wo", "yo", "zh"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestAmAsBnFaGuHiKnMrZu(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0", "1"})
+ tests = appendDecimalTests(tests, One, []string{"0.0~1.0", "0.00~0.04"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"1.1~2.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"am", "as", "bn", "fa", "gu", "hi", "kn", "mr", "zu"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestFfFrHyKab(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0", "1"})
+ tests = appendDecimalTests(tests, One, []string{"0.0~1.5"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"2.0~3.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"ff", "fr", "hy", "kab"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestAstCaDeEnEtFiFyGlItJiNlSvSwUrYi(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"ast", "ca", "de", "en", "et", "fi", "fy", "gl", "it", "ji", "nl", "sv", "sw", "ur", "yi"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestSi(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0", "1"})
+ tests = appendDecimalTests(tests, One, []string{"0.0", "0.1", "1.0", "0.00", "0.01", "1.00", "0.000", "0.001", "1.000", "0.0000", "0.0001", "1.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.2~0.9", "1.1~1.8", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"si"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestAkBhGuwLnMgNsoPaTiWa(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0", "1"})
+ tests = appendDecimalTests(tests, One, []string{"0.0", "1.0", "0.00", "1.00", "0.000", "1.000", "0.0000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"ak", "bh", "guw", "ln", "mg", "nso", "pa", "ti", "wa"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestTzm(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0", "1", "11~24"})
+ tests = appendDecimalTests(tests, One, []string{"0.0", "1.0", "11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "19.0", "20.0", "21.0", "22.0", "23.0", "24.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~10", "100~106", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"tzm"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestPt(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0", "1"})
+ tests = appendDecimalTests(tests, One, []string{"0.0", "1.0", "0.00", "1.00", "0.000", "1.000", "0.0000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"pt"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestAfAsaAzBemBezBgBrxCeCggChrCkbDvEeElEoEsEuFoFurGswHaHawHuJgoJmcKaKajKcgKkKkjKlKsKsbKuKyLbLgMasMgoMlMnNahNbNdNeNnNnhNoNrNyNynOmOrOsPapPsRmRofRwkSaqSdhSehSnSoSqSsSsyStSyrTaTeTeoTigTkTnTrTsUgUzVeVoVunWaeXhXog(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"af", "asa", "az", "bem", "bez", "bg", "brx", "ce", "cgg", "chr", "ckb", "dv", "ee", "el", "eo", "es", "eu", "fo", "fur", "gsw", "ha", "haw", "hu", "jgo", "jmc", "ka", "kaj", "kcg", "kk", "kkj", "kl", "ks", "ksb", "ku", "ky", "lb", "lg", "mas", "mgo", "ml", "mn", "nah", "nb", "nd", "ne", "nn", "nnh", "no", "nr", "ny", "nyn", "om", "or", "os", "pap", "ps", "rm", "rof", "rwk", "saq", "sdh", "seh", "sn", "so", "sq", "ss", "ssy", "st", "syr", "ta", "te", "teo", "tig", "tk", "tn", "tr", "ts", "ug", "uz", "ve", "vo", "vun", "wae", "xh", "xog"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestPt_PT(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"pt_PT"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestDa(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"0.1~1.6"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0", "2.0~3.4", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"da"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestIs(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"0.1~1.6", "10.1", "100.1", "1000.1"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"is"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestMk(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "11", "21", "31", "41", "51", "61", "71", "101", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"0.1", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "2~10", "12~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0", "0.2~1.0", "1.2~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"mk"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestFilTl(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0~3", "5", "7", "8", "10~13", "15", "17", "18", "20", "21", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, One, []string{"0.0~0.3", "0.5", "0.7", "0.8", "1.0~1.3", "1.5", "1.7", "1.8", "2.0", "2.1", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"4", "6", "9", "14", "16", "19", "24", "26", "104", "1004"})
+ tests = appendDecimalTests(tests, Other, []string{"0.4", "0.6", "0.9", "1.4", "1.6", "1.9", "2.4", "2.6", "10.4", "100.4", "1000.4"})
+
+ locales := []string{"fil", "tl"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestLvPrg(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, Zero, []string{"0", "10~20", "30", "40", "50", "60", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Zero, []string{"0.0", "10.0", "11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"0.1", "1.0", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~9", "22~29", "102", "1002"})
+ tests = appendDecimalTests(tests, Other, []string{"0.2~0.9", "1.2~1.9", "10.2", "100.2", "1000.2"})
+
+ locales := []string{"lv", "prg"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestLag(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, Zero, []string{"0"})
+ tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"})
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"0.1~1.6"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"2.0~3.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"lag"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestKsh(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, Zero, []string{"0"})
+ tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"})
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"2~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"ksh"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestIuKwNaqSeSmaSmiSmjSmnSms(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2"})
+ tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "3~17", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"iu", "kw", "naq", "se", "sma", "smi", "smj", "smn", "sms"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestShi(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"0", "1"})
+ tests = appendDecimalTests(tests, One, []string{"0.0~1.0", "0.00~0.04"})
+
+ tests = appendIntegerTests(tests, Few, []string{"2~10"})
+ tests = appendDecimalTests(tests, Few, []string{"2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "2.00", "3.00", "4.00", "5.00", "6.00", "7.00", "8.00"})
+
+ tests = appendIntegerTests(tests, Other, []string{"11~26", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"1.1~1.9", "2.1~2.7", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"shi"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestMoRo(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+
+ tests = appendIntegerTests(tests, Few, []string{"0", "2~16", "101", "1001"})
+ tests = appendDecimalTests(tests, Few, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"20~35", "100", "1000", "10000", "100000", "1000000"})
+
+ locales := []string{"mo", "ro"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestBsHrShSr(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"0.1", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"})
+
+ tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"})
+ tests = appendDecimalTests(tests, Few, []string{"0.2~0.4", "1.2~1.4", "2.2~2.4", "3.2~3.4", "4.2~4.4", "5.2", "10.2", "100.2", "1000.2"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0", "0.5~1.0", "1.5~2.0", "2.5~2.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"bs", "hr", "sh", "sr"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestGd(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "11"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "11.0", "1.00", "11.00", "1.000", "11.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2", "12"})
+ tests = appendDecimalTests(tests, Two, []string{"2.0", "12.0", "2.00", "12.00", "2.000", "12.000", "2.0000"})
+
+ tests = appendIntegerTests(tests, Few, []string{"3~10", "13~19"})
+ tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "19.0", "3.00"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "20~34", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"gd"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestSl(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "101", "201", "301", "401", "501", "601", "701", "1001"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2", "102", "202", "302", "402", "502", "602", "702", "1002"})
+
+ tests = appendIntegerTests(tests, Few, []string{"3", "4", "103", "104", "203", "204", "303", "304", "403", "404", "503", "504", "603", "604", "703", "704", "1003"})
+ tests = appendDecimalTests(tests, Few, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"})
+
+ locales := []string{"sl"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestDsbHsb(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "101", "201", "301", "401", "501", "601", "701", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"0.1", "1.1", "2.1", "3.1", "4.1", "5.1", "6.1", "7.1", "10.1", "100.1", "1000.1"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2", "102", "202", "302", "402", "502", "602", "702", "1002"})
+ tests = appendDecimalTests(tests, Two, []string{"0.2", "1.2", "2.2", "3.2", "4.2", "5.2", "6.2", "7.2", "10.2", "100.2", "1000.2"})
+
+ tests = appendIntegerTests(tests, Few, []string{"3", "4", "103", "104", "203", "204", "303", "304", "403", "404", "503", "504", "603", "604", "703", "704", "1003"})
+ tests = appendDecimalTests(tests, Few, []string{"0.3", "0.4", "1.3", "1.4", "2.3", "2.4", "3.3", "3.4", "4.3", "4.4", "5.3", "5.4", "6.3", "6.4", "7.3", "7.4", "10.3", "100.3", "1000.3"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0", "0.5~1.0", "1.5~2.0", "2.5~2.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"dsb", "hsb"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestHeIw(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2"})
+
+ tests = appendIntegerTests(tests, Many, []string{"20", "30", "40", "50", "60", "70", "80", "90", "100", "1000", "10000", "100000", "1000000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "3~17", "101", "1001"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"he", "iw"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestCsSk(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+
+ tests = appendIntegerTests(tests, Few, []string{"2~4"})
+
+ tests = appendDecimalTests(tests, Many, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"})
+
+ locales := []string{"cs", "sk"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestPl(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+
+ tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"})
+
+ tests = appendIntegerTests(tests, Many, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"})
+
+ tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"pl"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestBe(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "21.0", "31.0", "41.0", "51.0", "61.0", "71.0", "81.0", "101.0", "1001.0"})
+
+ tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"})
+ tests = appendDecimalTests(tests, Few, []string{"2.0", "3.0", "4.0", "22.0", "23.0", "24.0", "32.0", "33.0", "102.0", "1002.0"})
+
+ tests = appendIntegerTests(tests, Many, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Many, []string{"0.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "11.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.1", "1000.1"})
+
+ locales := []string{"be"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestLt(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "21.0", "31.0", "41.0", "51.0", "61.0", "71.0", "81.0", "101.0", "1001.0"})
+
+ tests = appendIntegerTests(tests, Few, []string{"2~9", "22~29", "102", "1002"})
+ tests = appendDecimalTests(tests, Few, []string{"2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "22.0", "102.0", "1002.0"})
+
+ tests = appendDecimalTests(tests, Many, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.1", "1000.1"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "10~20", "30", "40", "50", "60", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0", "10.0", "11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"lt"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestMt(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Few, []string{"0", "2~10", "102~107", "1002"})
+ tests = appendDecimalTests(tests, Few, []string{"0.0", "2.0", "3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "10.0", "102.0", "1002.0"})
+
+ tests = appendIntegerTests(tests, Many, []string{"11~19", "111~117", "1011"})
+ tests = appendDecimalTests(tests, Many, []string{"11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "111.0", "1011.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"20~35", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"mt"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestRuUk(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"})
+
+ tests = appendIntegerTests(tests, Few, []string{"2~4", "22~24", "32~34", "42~44", "52~54", "62", "102", "1002"})
+
+ tests = appendIntegerTests(tests, Many, []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"})
+
+ tests = appendDecimalTests(tests, Other, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"ru", "uk"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestBr(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "21", "31", "41", "51", "61", "81", "101", "1001"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "21.0", "31.0", "41.0", "51.0", "61.0", "81.0", "101.0", "1001.0"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2", "22", "32", "42", "52", "62", "82", "102", "1002"})
+ tests = appendDecimalTests(tests, Two, []string{"2.0", "22.0", "32.0", "42.0", "52.0", "62.0", "82.0", "102.0", "1002.0"})
+
+ tests = appendIntegerTests(tests, Few, []string{"3", "4", "9", "23", "24", "29", "33", "34", "39", "43", "44", "49", "103", "1003"})
+ tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "9.0", "23.0", "24.0", "29.0", "33.0", "34.0", "103.0", "1003.0"})
+
+ tests = appendIntegerTests(tests, Many, []string{"1000000"})
+ tests = appendDecimalTests(tests, Many, []string{"1000000.0", "1000000.00", "1000000.000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "5~8", "10~20", "100", "1000", "10000", "100000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0"})
+
+ locales := []string{"br"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestGa(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2"})
+ tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"})
+
+ tests = appendIntegerTests(tests, Few, []string{"3~6"})
+ tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "5.0", "6.0", "3.00", "4.00", "5.00", "6.00", "3.000", "4.000", "5.000", "6.000", "3.0000", "4.0000", "5.0000", "6.0000"})
+
+ tests = appendIntegerTests(tests, Many, []string{"7~10"})
+ tests = appendDecimalTests(tests, Many, []string{"7.0", "8.0", "9.0", "10.0", "7.00", "8.00", "9.00", "10.00", "7.000", "8.000", "9.000", "10.000", "7.0000", "8.0000", "9.0000", "10.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"0", "11~25", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.0~0.9", "1.1~1.6", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"ga"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestGv(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, One, []string{"1", "11", "21", "31", "41", "51", "61", "71", "101", "1001"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2", "12", "22", "32", "42", "52", "62", "72", "102", "1002"})
+
+ tests = appendIntegerTests(tests, Few, []string{"0", "20", "40", "60", "80", "100", "120", "140", "1000", "10000", "100000", "1000000"})
+
+ tests = appendDecimalTests(tests, Many, []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"3~10", "13~19", "23", "103", "1003"})
+
+ locales := []string{"gv"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestAr(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, Zero, []string{"0"})
+ tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"})
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2"})
+ tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"})
+
+ tests = appendIntegerTests(tests, Few, []string{"3~10", "103~110", "1003"})
+ tests = appendDecimalTests(tests, Few, []string{"3.0", "4.0", "5.0", "6.0", "7.0", "8.0", "9.0", "10.0", "103.0", "1003.0"})
+
+ tests = appendIntegerTests(tests, Many, []string{"11~26", "111", "1011"})
+ tests = appendDecimalTests(tests, Many, []string{"11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "111.0", "1011.0"})
+
+ tests = appendIntegerTests(tests, Other, []string{"100~102", "200~202", "300~302", "400~402", "500~502", "600", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.1", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"ar"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
+
+func TestCy(t *testing.T) {
+ var tests []pluralTest
+
+ tests = appendIntegerTests(tests, Zero, []string{"0"})
+ tests = appendDecimalTests(tests, Zero, []string{"0.0", "0.00", "0.000", "0.0000"})
+
+ tests = appendIntegerTests(tests, One, []string{"1"})
+ tests = appendDecimalTests(tests, One, []string{"1.0", "1.00", "1.000", "1.0000"})
+
+ tests = appendIntegerTests(tests, Two, []string{"2"})
+ tests = appendDecimalTests(tests, Two, []string{"2.0", "2.00", "2.000", "2.0000"})
+
+ tests = appendIntegerTests(tests, Few, []string{"3"})
+ tests = appendDecimalTests(tests, Few, []string{"3.0", "3.00", "3.000", "3.0000"})
+
+ tests = appendIntegerTests(tests, Many, []string{"6"})
+ tests = appendDecimalTests(tests, Many, []string{"6.0", "6.00", "6.000", "6.0000"})
+
+ tests = appendIntegerTests(tests, Other, []string{"4", "5", "7~20", "100", "1000", "10000", "100000", "1000000"})
+ tests = appendDecimalTests(tests, Other, []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"})
+
+ locales := []string{"cy"}
+ for _, locale := range locales {
+ runTests(t, locale, tests)
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go
new file mode 100644
index 000000000..34931b7bb
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/language/pluralspec_test.go
@@ -0,0 +1,733 @@
+package language
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+const onePlusEpsilon = "1.00000000000000000000000000000001"
+
+func TestGetPluralSpec(t *testing.T) {
+ tests := []struct {
+ src string
+ spec *PluralSpec
+ }{
+ {"pl", pluralSpecs["pl"]},
+ {"en", pluralSpecs["en"]},
+ {"en-US", pluralSpecs["en"]},
+ {"en_US", pluralSpecs["en"]},
+ {"en-GB", pluralSpecs["en"]},
+ {"zh-CN", pluralSpecs["zh"]},
+ {"zh-TW", pluralSpecs["zh"]},
+ {"pt-BR", pluralSpecs["pt"]},
+ {"pt_BR", pluralSpecs["pt"]},
+ {"pt-PT", pluralSpecs["pt-pt"]},
+ {"pt_PT", pluralSpecs["pt-pt"]},
+ {"zh-Hans-CN", pluralSpecs["zh"]},
+ {"zh-Hant-TW", pluralSpecs["zh"]},
+ {"zh-CN", pluralSpecs["zh"]},
+ {"zh-TW", pluralSpecs["zh"]},
+ {"zh-Hans", pluralSpecs["zh"]},
+ {"zh-Hant", pluralSpecs["zh"]},
+ {"ko-KR", pluralSpecs["ko"]},
+ {"ko_KR", pluralSpecs["ko"]},
+ {"ko-KP", pluralSpecs["ko"]},
+ {"ko_KP", pluralSpecs["ko"]},
+ {"en-US-en-US", pluralSpecs["en"]},
+ {"th", pluralSpecs["th"]},
+ {"th-TH", pluralSpecs["th"]},
+ {"hr", pluralSpecs["hr"]},
+ {"bs", pluralSpecs["bs"]},
+ {"sr", pluralSpecs["sr"]},
+ {"ti", pluralSpecs["ti"]},
+ {"vi", pluralSpecs["vi"]},
+ {"vi-VN", pluralSpecs["vi"]},
+ {"mk", pluralSpecs["mk"]},
+ {"mk-MK", pluralSpecs["mk"]},
+ {"lv", pluralSpecs["lv"]},
+ {"lv-LV", pluralSpecs["lv"]},
+ {".en-US..en-US.", nil},
+ {"zh, en-gb;q=0.8, en;q=0.7", nil},
+ {"zh,en-gb;q=0.8,en;q=0.7", nil},
+ {"xx, en-gb;q=0.8, en;q=0.7", nil},
+ {"xx,en-gb;q=0.8,en;q=0.7", nil},
+ {"xx-YY,xx;q=0.8,en-US,en;q=0.8,de;q=0.6,nl;q=0.4", nil},
+ {"/foo/es/en.json", nil},
+ {"xx-Yyen-US", nil},
+ {"en US", nil},
+ {"", nil},
+ {"-", nil},
+ {"_", nil},
+ {".", nil},
+ {"-en", nil},
+ {"_en", nil},
+ {"-en-", nil},
+ {"_en_", nil},
+ {"xx", nil},
+ }
+ for _, test := range tests {
+ spec := getPluralSpec(test.src)
+ if spec != test.spec {
+ t.Errorf("getPluralSpec(%q) = %q expected %q", test.src, spec, test.spec)
+ }
+ }
+}
+
+type pluralTest struct {
+ num interface{}
+ plural Plural
+}
+
+func appendIntegerTests(tests []pluralTest, plural Plural, examples []string) []pluralTest {
+ for _, ex := range expandExamples(examples) {
+ i, err := strconv.ParseInt(ex, 10, 64)
+ if err != nil {
+ panic(err)
+ }
+ tests = append(tests, pluralTest{ex, plural}, pluralTest{i, plural})
+ }
+ return tests
+}
+
+func appendDecimalTests(tests []pluralTest, plural Plural, examples []string) []pluralTest {
+ for _, ex := range expandExamples(examples) {
+ tests = append(tests, pluralTest{ex, plural})
+ }
+ return tests
+}
+
+func expandExamples(examples []string) []string {
+ var expanded []string
+ for _, ex := range examples {
+ if parts := strings.Split(ex, "~"); len(parts) == 2 {
+ for ex := parts[0]; ; ex = increment(ex) {
+ expanded = append(expanded, ex)
+ if ex == parts[1] {
+ break
+ }
+ }
+ } else {
+ expanded = append(expanded, ex)
+ }
+ }
+ return expanded
+}
+
+func increment(dec string) string {
+ runes := []rune(dec)
+ carry := true
+ for i := len(runes) - 1; carry && i >= 0; i-- {
+ switch runes[i] {
+ case '.':
+ continue
+ case '9':
+ runes[i] = '0'
+ default:
+ runes[i]++
+ carry = false
+ }
+ }
+ if carry {
+ runes = append([]rune{'1'}, runes...)
+ }
+ return string(runes)
+}
+
+//
+// Below here are tests that were manually written before tests were automatically generated.
+// These are kept around as sanity checks for our code generation.
+//
+
+func TestArabic(t *testing.T) {
+ tests := []pluralTest{
+ {0, Zero},
+ {"0", Zero},
+ {"0.0", Zero},
+ {"0.00", Zero},
+ {1, One},
+ {"1", One},
+ {"1.0", One},
+ {"1.00", One},
+ {onePlusEpsilon, Other},
+ {2, Two},
+ {"2", Two},
+ {"2.0", Two},
+ {"2.00", Two},
+ {3, Few},
+ {"3", Few},
+ {"3.0", Few},
+ {"3.00", Few},
+ {10, Few},
+ {"10", Few},
+ {"10.0", Few},
+ {"10.00", Few},
+ {103, Few},
+ {"103", Few},
+ {"103.0", Few},
+ {"103.00", Few},
+ {110, Few},
+ {"110", Few},
+ {"110.0", Few},
+ {"110.00", Few},
+ {11, Many},
+ {"11", Many},
+ {"11.0", Many},
+ {"11.00", Many},
+ {99, Many},
+ {"99", Many},
+ {"99.0", Many},
+ {"99.00", Many},
+ {111, Many},
+ {"111", Many},
+ {"111.0", Many},
+ {"111.00", Many},
+ {199, Many},
+ {"199", Many},
+ {"199.0", Many},
+ {"199.00", Many},
+ {100, Other},
+ {"100", Other},
+ {"100.0", Other},
+ {"100.00", Other},
+ {102, Other},
+ {"102", Other},
+ {"102.0", Other},
+ {"102.00", Other},
+ {200, Other},
+ {"200", Other},
+ {"200.0", Other},
+ {"200.00", Other},
+ {202, Other},
+ {"202", Other},
+ {"202.0", Other},
+ {"202.00", Other},
+ }
+ tests = appendFloatTests(tests, 0.1, 0.9, Other)
+ tests = appendFloatTests(tests, 1.1, 1.9, Other)
+ tests = appendFloatTests(tests, 2.1, 2.9, Other)
+ tests = appendFloatTests(tests, 3.1, 3.9, Other)
+ tests = appendFloatTests(tests, 4.1, 4.9, Other)
+ runTests(t, "ar", tests)
+}
+
+func TestBelarusian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Many},
+ {1, One},
+ {2, Few},
+ {3, Few},
+ {4, Few},
+ {5, Many},
+ {19, Many},
+ {20, Many},
+ {21, One},
+ {11, Many},
+ {52, Few},
+ {101, One},
+ {"0.1", Other},
+ {"0.7", Other},
+ {"1.5", Other},
+ {"1.0", One},
+ {onePlusEpsilon, Other},
+ {"2.0", Few},
+ {"10.0", Many},
+ }
+ runTests(t, "be", tests)
+}
+
+func TestBurmese(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "my", tests)
+}
+
+func TestCatalan(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {"0", Other},
+ {1, One},
+ {"1", One},
+ {"1.0", Other},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ {"2", Other},
+ }
+ tests = appendIntTests(tests, 2, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "ca", tests)
+}
+
+func TestChinese(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "zh", tests)
+}
+
+func TestCzech(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {"0", Other},
+ {1, One},
+ {"1", One},
+ {onePlusEpsilon, Many},
+ {2, Few},
+ {"2", Few},
+ {3, Few},
+ {"3", Few},
+ {4, Few},
+ {"4", Few},
+ {5, Other},
+ {"5", Other},
+ }
+ tests = appendFloatTests(tests, 0, 10, Many)
+ runTests(t, "cs", tests)
+}
+
+func TestDanish(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {onePlusEpsilon, One},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.1, 1.9, One)
+ tests = appendFloatTests(tests, 2.0, 10.0, Other)
+ runTests(t, "da", tests)
+}
+
+func TestDutch(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 10.0, Other)
+ runTests(t, "nl", tests)
+}
+
+func TestEnglish(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 10.0, Other)
+ runTests(t, "en", tests)
+}
+
+func TestFrench(t *testing.T) {
+ tests := []pluralTest{
+ {0, One},
+ {1, One},
+ {onePlusEpsilon, One},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 1.9, One)
+ tests = appendFloatTests(tests, 2.0, 10.0, Other)
+ runTests(t, "fr", tests)
+}
+
+func TestGerman(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 10.0, Other)
+ runTests(t, "de", tests)
+}
+
+func TestIcelandic(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {2, Other},
+ {11, Other},
+ {21, One},
+ {111, Other},
+ {"0.0", Other},
+ {"0.1", One},
+ {"2.0", Other},
+ }
+ runTests(t, "is", tests)
+}
+
+func TestIndonesian(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "id", tests)
+}
+
+func TestItalian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 10.0, Other)
+ runTests(t, "it", tests)
+}
+
+func TestKorean(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "ko", tests)
+}
+
+func TestLatvian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Zero},
+ {"0", Zero},
+ {"0.1", One},
+ {1, One},
+ {"1", One},
+ {onePlusEpsilon, One},
+ {"10.0", Zero},
+ {"10.1", One},
+ {"10.2", Other},
+ {21, One},
+ }
+ tests = appendFloatTests(tests, 0.2, 0.9, Other)
+ tests = appendFloatTests(tests, 1.2, 1.9, Other)
+ tests = appendIntTests(tests, 2, 9, Other)
+ tests = appendIntTests(tests, 10, 20, Zero)
+ tests = appendIntTests(tests, 22, 29, Other)
+ runTests(t, "lv", tests)
+}
+
+func TestJapanese(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "ja", tests)
+}
+
+func TestLithuanian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {2, Few},
+ {3, Few},
+ {9, Few},
+ {10, Other},
+ {11, Other},
+ {"0.1", Many},
+ {"0.7", Many},
+ {"1.0", One},
+ {onePlusEpsilon, Many},
+ {"2.0", Few},
+ {"10.0", Other},
+ }
+ runTests(t, "lt", tests)
+}
+
+func TestMalay(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "ms", tests)
+}
+
+func TestPolish(t *testing.T) {
+ tests := []pluralTest{
+ {0, Many},
+ {1, One},
+ {2, Few},
+ {3, Few},
+ {4, Few},
+ {5, Many},
+ {19, Many},
+ {20, Many},
+ {10, Many},
+ {11, Many},
+ {52, Few},
+ {"0.1", Other},
+ {"0.7", Other},
+ {"1.5", Other},
+ {"1.0", Other},
+ {onePlusEpsilon, Other},
+ {"2.0", Other},
+ {"10.0", Other},
+ }
+ runTests(t, "pl", tests)
+}
+
+func TestPortuguese(t *testing.T) {
+ tests := []pluralTest{
+ {0, One},
+ {"0.0", One},
+ {1, One},
+ {"1.0", One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.1, 0.9, Other)
+ tests = appendFloatTests(tests, 1.1, 10.0, Other)
+ runTests(t, "pt", tests)
+}
+
+func TestMacedonian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {"1.1", One},
+ {"2.1", One},
+ {onePlusEpsilon, One},
+ {2, Other},
+ {"2.2", Other},
+ {11, One},
+ }
+ runTests(t, "mk", tests)
+}
+
+func TestPortugueseEuropean(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {"0.0", Other},
+ {"0.1", Other},
+ {"0.01", Other},
+ {1, One},
+ {"1", One},
+ {"1.1", Other},
+ {"1.01", Other},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 2.0, 10.0, Other)
+ runTests(t, "pt-pt", tests)
+}
+
+func TestRussian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Many},
+ {1, One},
+ {2, Few},
+ {3, Few},
+ {4, Few},
+ {5, Many},
+ {19, Many},
+ {20, Many},
+ {21, One},
+ {11, Many},
+ {52, Few},
+ {101, One},
+ {"0.1", Other},
+ {"0.7", Other},
+ {"1.5", Other},
+ {"1.0", Other},
+ {onePlusEpsilon, Other},
+ {"2.0", Other},
+ {"10.0", Other},
+ }
+ runTests(t, "ru", tests)
+}
+
+func TestSpanish(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {"1", One},
+ {"1.0", One},
+ {"1.00", One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 0.9, Other)
+ tests = appendFloatTests(tests, 1.1, 10.0, Other)
+ runTests(t, "es", tests)
+}
+
+func TestNorweigan(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {"1", One},
+ {"1.0", One},
+ {"1.00", One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 0.9, Other)
+ tests = appendFloatTests(tests, 1.1, 10.0, Other)
+ runTests(t, "no", tests)
+}
+
+func TestBulgarian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {2, Other},
+ {3, Other},
+ {9, Other},
+ {10, Other},
+ {11, Other},
+ {"0.1", Other},
+ {"0.7", Other},
+ {"1.0", One},
+ {"1.001", Other},
+ {onePlusEpsilon, Other},
+ {"1.1", Other},
+ {"2.0", Other},
+ {"10.0", Other},
+ }
+ runTests(t, "bg", tests)
+}
+
+func TestSwedish(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ }
+ tests = appendFloatTests(tests, 0.0, 10.0, Other)
+ runTests(t, "sv", tests)
+}
+
+func TestThai(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "th", tests)
+}
+
+func TestVietnamese(t *testing.T) {
+ tests := appendIntTests(nil, 0, 10, Other)
+ tests = appendFloatTests(tests, 0, 10, Other)
+ runTests(t, "vi", tests)
+}
+
+func TestTurkish(t *testing.T) {
+ tests := []pluralTest{
+ {0, Other},
+ {1, One},
+ {"1", One},
+ {"1.0", One},
+ {"1.00", One},
+ {"1.001", Other},
+ {"1.100", Other},
+ {"1.101", Other},
+ {onePlusEpsilon, Other},
+ {2, Other},
+ {"0.7", Other},
+ {"2.0", Other},
+ }
+ runTests(t, "tr", tests)
+}
+
+func TestUkrainian(t *testing.T) {
+ tests := []pluralTest{
+ {0, Many},
+ {1, One},
+ {2, Few},
+ {3, Few},
+ {4, Few},
+ {5, Many},
+ {19, Many},
+ {20, Many},
+ {21, One},
+ {11, Many},
+ {52, Few},
+ {101, One},
+ {"0.1", Other},
+ {"0.7", Other},
+ {"1.5", Other},
+ {"1.0", Other},
+ {onePlusEpsilon, Other},
+ {"2.0", Other},
+ {"10.0", Other},
+ }
+ runTests(t, "uk", tests)
+}
+
+func TestCroatian(t *testing.T) {
+ tests := makeCroatianBosnianSerbianTests()
+ runTests(t, "hr", tests)
+}
+
+func TestBosnian(t *testing.T) {
+ tests := makeCroatianBosnianSerbianTests()
+ runTests(t, "bs", tests)
+}
+
+func TestSerbian(t *testing.T) {
+ tests := makeCroatianBosnianSerbianTests()
+ runTests(t, "sr", tests)
+}
+
+func makeCroatianBosnianSerbianTests() []pluralTest {
+ return []pluralTest{
+ {1, One},
+ {"0.1", One},
+ {21, One},
+ {101, One},
+ {1001, One},
+ {51, One},
+ {"1.1", One},
+ {"5.1", One},
+ {"100.1", One},
+ {"1000.1", One},
+ {2, Few},
+ {"0.2", Few},
+ {22, Few},
+ {"1.2", Few},
+ {24, Few},
+ {"2.4", Few},
+ {102, Few},
+ {"100.2", Few},
+ {1002, Few},
+ {"1000.2", Few},
+ {5, Other},
+ {"0.5", Other},
+ {0, Other},
+ {100, Other},
+ {19, Other},
+ {"0.0", Other},
+ {"100.0", Other},
+ {"1000.0", Other},
+ }
+}
+
+func TestTigrinya(t *testing.T) {
+ tests := []pluralTest{
+ {0, One},
+ {1, One},
+ }
+ tests = appendIntTests(tests, 2, 10, Other)
+ tests = appendFloatTests(tests, 1.1, 10.0, Other)
+ runTests(t, "ti", tests)
+}
+
+func appendIntTests(tests []pluralTest, from, to int, p Plural) []pluralTest {
+ for i := from; i <= to; i++ {
+ tests = append(tests, pluralTest{i, p})
+ }
+ return tests
+}
+
+func appendFloatTests(tests []pluralTest, from, to float64, p Plural) []pluralTest {
+ stride := 0.1
+ format := "%.1f"
+ for f := from; f < to; f += stride {
+ tests = append(tests, pluralTest{fmt.Sprintf(format, f), p})
+ }
+ tests = append(tests, pluralTest{fmt.Sprintf(format, to), p})
+ return tests
+}
+
+func runTests(t *testing.T, pluralSpecID string, tests []pluralTest) {
+ pluralSpecID = normalizePluralSpecID(pluralSpecID)
+ if spec := pluralSpecs[pluralSpecID]; spec != nil {
+ for _, test := range tests {
+ if plural, err := spec.Plural(test.num); plural != test.plural {
+ t.Errorf("%s: PluralCategory(%#v) returned %s, %v; expected %s", pluralSpecID, test.num, plural, err, test.plural)
+ }
+ }
+ } else {
+ t.Errorf("could not find plural spec for locale %s", pluralSpecID)
+ }
+
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go
new file mode 100644
index 000000000..ea7de7fd9
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/plural_translation_test.go
@@ -0,0 +1,308 @@
+package translation
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/nicksnyder/go-i18n/i18n/language"
+)
+
+func mustTemplate(t *testing.T, src string) *template {
+ tmpl, err := newTemplate(src)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return tmpl
+}
+
+func pluralTranslationFixture(t *testing.T, id string, pluralCategories ...language.Plural) *pluralTranslation {
+ templates := make(map[language.Plural]*template, len(pluralCategories))
+ for _, pc := range pluralCategories {
+ templates[pc] = mustTemplate(t, string(pc))
+ }
+ return &pluralTranslation{id, templates}
+}
+
+func verifyDeepEqual(t *testing.T, actual, expected interface{}) {
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("\n%#v\nnot equal to expected value\n%#v", actual, expected)
+ }
+}
+
+func TestPluralTranslationMerge(t *testing.T) {
+ pt := pluralTranslationFixture(t, "id", language.One, language.Other)
+ oneTemplate, otherTemplate := pt.templates[language.One], pt.templates[language.Other]
+
+ pt.Merge(pluralTranslationFixture(t, "id"))
+ verifyDeepEqual(t, pt.templates, map[language.Plural]*template{
+ language.One: oneTemplate,
+ language.Other: otherTemplate,
+ })
+
+ pt2 := pluralTranslationFixture(t, "id", language.One, language.Two)
+ pt.Merge(pt2)
+ verifyDeepEqual(t, pt.templates, map[language.Plural]*template{
+ language.One: pt2.templates[language.One],
+ language.Two: pt2.templates[language.Two],
+ language.Other: otherTemplate,
+ })
+}
+
+/* Test implementations from old idea
+
+func TestCopy(t *testing.T) {
+ ls := &LocalizedString{
+ ID: "id",
+ Translation: testingTemplate(t, "translation {{.Hello}}"),
+ Translations: map[language.Plural]*template{
+ language.One: testingTemplate(t, "plural {{.One}}"),
+ language.Other: testingTemplate(t, "plural {{.Other}}"),
+ },
+ }
+
+ c := ls.Copy()
+ delete(c.Translations, language.One)
+ if _, ok := ls.Translations[language.One]; !ok {
+ t.Errorf("deleting plural translation from copy deleted it from the original")
+ }
+ c.Translations[language.Two] = testingTemplate(t, "plural {{.Two}}")
+ if _, ok := ls.Translations[language.Two]; ok {
+ t.Errorf("adding plural translation to copy added it to the original")
+ }
+}
+
+func TestNormalize(t *testing.T) {
+ oneTemplate := testingTemplate(t, "one {{.One}}")
+ ls := &LocalizedString{
+ Translation: testingTemplate(t, "single {{.Single}}"),
+ Translations: map[language.Plural]*template{
+ language.One: oneTemplate,
+ language.Two: testingTemplate(t, "two {{.Two}}"),
+ },
+ }
+ ls.Normalize(LanguageWithCode("en"))
+ if ls.Translation != nil {
+ t.Errorf("ls.Translation is %#v; expected nil", ls.Translation)
+ }
+ if actual := ls.Translations[language.Two]; actual != nil {
+ t.Errorf("ls.Translation[language.Two] is %#v; expected nil", actual)
+ }
+ if actual := ls.Translations[language.One]; actual != oneTemplate {
+ t.Errorf("ls.Translations[language.One] is %#v; expected %#v", actual, oneTemplate)
+ }
+ if _, ok := ls.Translations[language.Other]; !ok {
+ t.Errorf("ls.Translations[language.Other] shouldn't be empty")
+ }
+}
+
+func TestMergeTranslation(t *testing.T) {
+ ls := &LocalizedString{}
+
+ translation := testingTemplate(t, "one {{.Hello}}")
+ ls.Merge(&LocalizedString{
+ Translation: translation,
+ })
+ if ls.Translation != translation {
+ t.Errorf("expected %#v; got %#v", translation, ls.Translation)
+ }
+
+ ls.Merge(&LocalizedString{})
+ if ls.Translation != translation {
+ t.Errorf("expected %#v; got %#v", translation, ls.Translation)
+ }
+
+ translation = testingTemplate(t, "two {{.Hello}}")
+ ls.Merge(&LocalizedString{
+ Translation: translation,
+ })
+ if ls.Translation != translation {
+ t.Errorf("expected %#v; got %#v", translation, ls.Translation)
+ }
+}
+
+func TestMergeTranslations(t *testing.T) {
+ ls := &LocalizedString{}
+
+ oneTemplate := testingTemplate(t, "one {{.One}}")
+ otherTemplate := testingTemplate(t, "other {{.Other}}")
+ ls.Merge(&LocalizedString{
+ Translations: map[language.Plural]*template{
+ language.One: oneTemplate,
+ language.Other: otherTemplate,
+ },
+ })
+ if actual := ls.Translations[language.One]; actual != oneTemplate {
+ t.Errorf("ls.Translations[language.One] expected %#v; got %#v", oneTemplate, actual)
+ }
+ if actual := ls.Translations[language.Other]; actual != otherTemplate {
+ t.Errorf("ls.Translations[language.Other] expected %#v; got %#v", otherTemplate, actual)
+ }
+
+ ls.Merge(&LocalizedString{
+ Translations: map[language.Plural]*template{},
+ })
+ if actual := ls.Translations[language.One]; actual != oneTemplate {
+ t.Errorf("ls.Translations[language.One] expected %#v; got %#v", oneTemplate, actual)
+ }
+ if actual := ls.Translations[language.Other]; actual != otherTemplate {
+ t.Errorf("ls.Translations[language.Other] expected %#v; got %#v", otherTemplate, actual)
+ }
+
+ twoTemplate := testingTemplate(t, "two {{.Two}}")
+ otherTemplate = testingTemplate(t, "second other {{.Other}}")
+ ls.Merge(&LocalizedString{
+ Translations: map[language.Plural]*template{
+ language.Two: twoTemplate,
+ language.Other: otherTemplate,
+ },
+ })
+ if actual := ls.Translations[language.One]; actual != oneTemplate {
+ t.Errorf("ls.Translations[language.One] expected %#v; got %#v", oneTemplate, actual)
+ }
+ if actual := ls.Translations[language.Two]; actual != twoTemplate {
+ t.Errorf("ls.Translations[language.Two] expected %#v; got %#v", twoTemplate, actual)
+ }
+ if actual := ls.Translations[language.Other]; actual != otherTemplate {
+ t.Errorf("ls.Translations[language.Other] expected %#v; got %#v", otherTemplate, actual)
+ }
+}
+
+func TestMissingTranslations(t *testing.T) {
+ en := LanguageWithCode("en")
+
+ tests := []struct {
+ localizedString *LocalizedString
+ language *Language
+ expected bool
+ }{
+ {
+ &LocalizedString{},
+ en,
+ true,
+ },
+ {
+ &LocalizedString{Translation: testingTemplate(t, "single {{.Single}}")},
+ en,
+ false,
+ },
+ {
+ &LocalizedString{
+ Translation: testingTemplate(t, "single {{.Single}}"),
+ Translations: map[language.Plural]*template{
+ language.One: testingTemplate(t, "one {{.One}}"),
+ }},
+ en,
+ true,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.One: testingTemplate(t, "one {{.One}}"),
+ }},
+ en,
+ true,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.One: nil,
+ language.Other: nil,
+ }},
+ en,
+ true,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.One: testingTemplate(t, ""),
+ language.Other: testingTemplate(t, ""),
+ }},
+ en,
+ true,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.One: testingTemplate(t, "one {{.One}}"),
+ language.Other: testingTemplate(t, "other {{.Other}}"),
+ }},
+ en,
+ false,
+ },
+ }
+
+ for _, tt := range tests {
+ if actual := tt.localizedString.MissingTranslations(tt.language); actual != tt.expected {
+ t.Errorf("expected %t got %t for %s, %#v",
+ tt.expected, actual, tt.language.code, tt.localizedString)
+ }
+ }
+}
+
+func TestHasTranslations(t *testing.T) {
+ en := LanguageWithCode("en")
+
+ tests := []struct {
+ localizedString *LocalizedString
+ language *Language
+ expected bool
+ }{
+ {
+ &LocalizedString{},
+ en,
+ false,
+ },
+ {
+ &LocalizedString{Translation: testingTemplate(t, "single {{.Single}}")},
+ en,
+ true,
+ },
+ {
+ &LocalizedString{
+ Translation: testingTemplate(t, "single {{.Single}}"),
+ Translations: map[language.Plural]*template{}},
+ en,
+ false,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.One: testingTemplate(t, "one {{.One}}"),
+ }},
+ en,
+ true,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.Two: testingTemplate(t, "two {{.Two}}"),
+ }},
+ en,
+ false,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.One: nil,
+ }},
+ en,
+ false,
+ },
+ {
+ &LocalizedString{Translations: map[language.Plural]*template{
+ language.One: testingTemplate(t, ""),
+ }},
+ en,
+ false,
+ },
+ }
+
+ for _, tt := range tests {
+ if actual := tt.localizedString.HasTranslations(tt.language); actual != tt.expected {
+ t.Errorf("expected %t got %t for %s, %#v",
+ tt.expected, actual, tt.language.code, tt.localizedString)
+ }
+ }
+}
+
+func testingTemplate(t *testing.T, src string) *template {
+ tmpl, err := newTemplate(src)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return tmpl
+}
+*/
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go
new file mode 100644
index 000000000..73a923404
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/template_test.go
@@ -0,0 +1,146 @@
+package translation
+
+import (
+ "bytes"
+ "fmt"
+ //"launchpad.net/goyaml"
+ "testing"
+ gotemplate "text/template"
+)
+
+func TestNilTemplate(t *testing.T) {
+ expected := "hello"
+ tmpl := &template{
+ tmpl: nil,
+ src: expected,
+ }
+ if actual := tmpl.Execute(nil); actual != expected {
+ t.Errorf("Execute(nil) returned %s; expected %s", actual, expected)
+ }
+}
+
+func TestMarshalText(t *testing.T) {
+ tmpl := &template{
+ tmpl: gotemplate.Must(gotemplate.New("id").Parse("this is a {{.foo}} template")),
+ src: "boom",
+ }
+ expectedBuf := []byte(tmpl.src)
+ if buf, err := tmpl.MarshalText(); !bytes.Equal(buf, expectedBuf) || err != nil {
+ t.Errorf("MarshalText() returned %#v, %#v; expected %#v, nil", buf, err, expectedBuf)
+ }
+}
+
+func TestUnmarshalText(t *testing.T) {
+ tmpl := &template{}
+ tmpl.UnmarshalText([]byte("hello {{.World}}"))
+ result := tmpl.Execute(map[string]string{
+ "World": "world!",
+ })
+ expected := "hello world!"
+ if result != expected {
+ t.Errorf("expected %#v; got %#v", expected, result)
+ }
+}
+
+/*
+func TestYAMLMarshal(t *testing.T) {
+ src := "hello {{.World}}"
+ tmpl, err := newTemplate(src)
+ if err != nil {
+ t.Fatal(err)
+ }
+ buf, err := goyaml.Marshal(tmpl)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf, []byte(src)) {
+ t.Fatalf(`expected "%s"; got "%s"`, src, buf)
+ }
+}
+
+func TestYAMLUnmarshal(t *testing.T) {
+ buf := []byte(`Tmpl: "hello"`)
+
+ var out struct {
+ Tmpl *template
+ }
+ var foo map[string]string
+ if err := goyaml.Unmarshal(buf, &foo); err != nil {
+ t.Fatal(err)
+ }
+ if out.Tmpl == nil {
+ t.Fatalf("out.Tmpl was nil")
+ }
+ if out.Tmpl.tmpl == nil {
+ t.Fatalf("out.Tmpl.tmpl was nil")
+ }
+ if expected := "hello {{.World}}"; out.Tmpl.src != expected {
+ t.Fatalf("expected %s; got %s", expected, out.Tmpl.src)
+ }
+}
+
+func TestGetYAML(t *testing.T) {
+ src := "hello"
+ tmpl := &template{
+ tmpl: nil,
+ src: src,
+ }
+ if tag, value := tmpl.GetYAML(); tag != "" || value != src {
+ t.Errorf("GetYAML() returned (%#v, %#v); expected (%#v, %#v)", tag, value, "", src)
+ }
+}
+
+func TestSetYAML(t *testing.T) {
+ tmpl := &template{}
+ tmpl.SetYAML("tagDoesntMatter", "hello {{.World}}")
+ result := tmpl.Execute(map[string]string{
+ "World": "world!",
+ })
+ expected := "hello world!"
+ if result != expected {
+ t.Errorf("expected %#v; got %#v", expected, result)
+ }
+}
+*/
+
+func BenchmarkExecuteNilTemplate(b *testing.B) {
+ template := &template{src: "hello world"}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ template.Execute(nil)
+ }
+}
+
+func BenchmarkExecuteHelloWorldTemplate(b *testing.B) {
+ template, err := newTemplate("hello world")
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ template.Execute(nil)
+ }
+}
+
+// Executing a simple template like this is ~6x slower than Sprintf
+// but it is still only a few microseconds which should be sufficiently fast.
+// The benefit is that we have nice semantic tags in the translation.
+func BenchmarkExecuteHelloNameTemplate(b *testing.B) {
+ template, err := newTemplate("hello {{.Name}}")
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ template.Execute(map[string]string{
+ "Name": "Nick",
+ })
+ }
+}
+
+func BenchmarkSprintf(b *testing.B) {
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ fmt.Sprintf("hello %s", "nick")
+ }
+}
diff --git a/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go
new file mode 100644
index 000000000..7380d5a6f
--- /dev/null
+++ b/vendor/github.com/nicksnyder/go-i18n/i18n/translation/translation_test.go
@@ -0,0 +1,17 @@
+package translation
+
+import (
+ "sort"
+ "testing"
+)
+
+// Check this here to avoid unnecessary import of sort package.
+var _ = sort.Interface(make(SortableByID, 0, 0))
+
+func TestNewSingleTranslation(t *testing.T) {
+ t.Skipf("not implemented")
+}
+
+func TestNewPluralTranslation(t *testing.T) {
+ t.Skipf("not implemented")
+}
diff --git a/vendor/github.com/pborman/uuid/dce.go b/vendor/github.com/pborman/uuid/dce.go
index 50a0f2d09..50a0f2d09 100644..100755
--- a/vendor/github.com/pborman/uuid/dce.go
+++ b/vendor/github.com/pborman/uuid/dce.go
diff --git a/vendor/github.com/pborman/uuid/doc.go b/vendor/github.com/pborman/uuid/doc.go
index d8bd013e6..d8bd013e6 100644..100755
--- a/vendor/github.com/pborman/uuid/doc.go
+++ b/vendor/github.com/pborman/uuid/doc.go
diff --git a/vendor/github.com/pborman/uuid/json_test.go b/vendor/github.com/pborman/uuid/json_test.go
new file mode 100644
index 000000000..2866b8dc8
--- /dev/null
+++ b/vendor/github.com/pborman/uuid/json_test.go
@@ -0,0 +1,61 @@
+// Copyright 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package uuid
+
+import (
+ "encoding/json"
+ "reflect"
+ "testing"
+)
+
+var testUUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+
+func TestJSON(t *testing.T) {
+ type S struct {
+ ID1 UUID
+ ID2 UUID
+ }
+ s1 := S{ID1: testUUID}
+ data, err := json.Marshal(&s1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var s2 S
+ if err := json.Unmarshal(data, &s2); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(&s1, &s2) {
+ t.Errorf("got %#v, want %#v", s2, s1)
+ }
+}
+
+func BenchmarkUUID_MarshalJSON(b *testing.B) {
+ x := &struct {
+ UUID UUID `json:"uuid"`
+ }{}
+ x.UUID = Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if x.UUID == nil {
+ b.Fatal("invalid uuid")
+ }
+ for i := 0; i < b.N; i++ {
+ js, err := json.Marshal(x)
+ if err != nil {
+ b.Fatalf("marshal json: %#v (%v)", js, err)
+ }
+ }
+}
+
+func BenchmarkUUID_UnmarshalJSON(b *testing.B) {
+ js := []byte(`{"uuid":"f47ac10b-58cc-0372-8567-0e02b2c3d479"}`)
+ var x *struct {
+ UUID UUID `json:"uuid"`
+ }
+ for i := 0; i < b.N; i++ {
+ err := json.Unmarshal(js, &x)
+ if err != nil {
+ b.Fatalf("marshal json: %#v (%v)", js, err)
+ }
+ }
+}
diff --git a/vendor/github.com/pborman/uuid/node.go b/vendor/github.com/pborman/uuid/node.go
index 42d60da8f..42d60da8f 100644..100755
--- a/vendor/github.com/pborman/uuid/node.go
+++ b/vendor/github.com/pborman/uuid/node.go
diff --git a/vendor/github.com/pborman/uuid/seq_test.go b/vendor/github.com/pborman/uuid/seq_test.go
new file mode 100644
index 000000000..3b3d1430d
--- /dev/null
+++ b/vendor/github.com/pborman/uuid/seq_test.go
@@ -0,0 +1,66 @@
+// Copyright 2014 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package uuid
+
+import (
+ "flag"
+ "runtime"
+ "testing"
+ "time"
+)
+
+// This test is only run when --regressions is passed on the go test line.
+var regressions = flag.Bool("regressions", false, "run uuid regression tests")
+
+// TestClockSeqRace tests for a particular race condition of returning two
+// identical Version1 UUIDs. The duration of 1 minute was chosen as the race
+// condition, before being fixed, nearly always occured in under 30 seconds.
+func TestClockSeqRace(t *testing.T) {
+ if !*regressions {
+ t.Skip("skipping regression tests")
+ }
+ duration := time.Minute
+
+ done := make(chan struct{})
+ defer close(done)
+
+ ch := make(chan UUID, 10000)
+ ncpu := runtime.NumCPU()
+ switch ncpu {
+ case 0, 1:
+ // We can't run the test effectively.
+ t.Skip("skipping race test, only one CPU detected")
+ return
+ default:
+ runtime.GOMAXPROCS(ncpu)
+ }
+ for i := 0; i < ncpu; i++ {
+ go func() {
+ for {
+ select {
+ case <-done:
+ return
+ case ch <- NewUUID():
+ }
+ }
+ }()
+ }
+
+ uuids := make(map[string]bool)
+ cnt := 0
+ start := time.Now()
+ for u := range ch {
+ s := u.String()
+ if uuids[s] {
+ t.Errorf("duplicate uuid after %d in %v: %s", cnt, time.Since(start), s)
+ return
+ }
+ uuids[s] = true
+ if time.Since(start) > duration {
+ return
+ }
+ cnt++
+ }
+}
diff --git a/vendor/github.com/pborman/uuid/sql_test.go b/vendor/github.com/pborman/uuid/sql_test.go
new file mode 100644
index 000000000..103095156
--- /dev/null
+++ b/vendor/github.com/pborman/uuid/sql_test.go
@@ -0,0 +1,96 @@
+// Copyright 2015 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package uuid
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestScan(t *testing.T) {
+ var stringTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d479"
+ var byteTest []byte = Parse(stringTest)
+ var badTypeTest int = 6
+ var invalidTest string = "f47ac10b-58cc-0372-8567-0e02b2c3d4"
+
+ // sunny day tests
+
+ var uuid UUID
+ err := (&uuid).Scan(stringTest)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = (&uuid).Scan([]byte(stringTest))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = (&uuid).Scan(byteTest)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // bad type tests
+
+ err = (&uuid).Scan(badTypeTest)
+ if err == nil {
+ t.Error("int correctly parsed and shouldn't have")
+ }
+ if !strings.Contains(err.Error(), "unable to scan type") {
+ t.Error("attempting to parse an int returned an incorrect error message")
+ }
+
+ // invalid/incomplete uuids
+
+ err = (&uuid).Scan(invalidTest)
+ if err == nil {
+ t.Error("invalid uuid was parsed without error")
+ }
+ if !strings.Contains(err.Error(), "invalid UUID") {
+ t.Error("attempting to parse an invalid UUID returned an incorrect error message")
+ }
+
+ err = (&uuid).Scan(byteTest[:len(byteTest)-2])
+ if err == nil {
+ t.Error("invalid byte uuid was parsed without error")
+ }
+ if !strings.Contains(err.Error(), "invalid UUID") {
+ t.Error("attempting to parse an invalid byte UUID returned an incorrect error message")
+ }
+
+ // empty tests
+
+ uuid = nil
+ var emptySlice []byte
+ err = (&uuid).Scan(emptySlice)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if uuid != nil {
+ t.Error("UUID was not nil after scanning empty byte slice")
+ }
+
+ uuid = nil
+ var emptyString string
+ err = (&uuid).Scan(emptyString)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if uuid != nil {
+ t.Error("UUID was not nil after scanning empty string")
+ }
+}
+
+func TestValue(t *testing.T) {
+ stringTest := "f47ac10b-58cc-0372-8567-0e02b2c3d479"
+ uuid := Parse(stringTest)
+ val, _ := uuid.Value()
+ if val != stringTest {
+ t.Error("Value() did not return expected string")
+ }
+}
diff --git a/vendor/github.com/pborman/uuid/time.go b/vendor/github.com/pborman/uuid/time.go
index eedf24219..eedf24219 100644..100755
--- a/vendor/github.com/pborman/uuid/time.go
+++ b/vendor/github.com/pborman/uuid/time.go
diff --git a/vendor/github.com/pborman/uuid/uuid_test.go b/vendor/github.com/pborman/uuid/uuid_test.go
new file mode 100644
index 000000000..cb1cd5cf9
--- /dev/null
+++ b/vendor/github.com/pborman/uuid/uuid_test.go
@@ -0,0 +1,543 @@
+// Copyright 2011 Google Inc. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package uuid
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+ "time"
+)
+
+type test struct {
+ in string
+ version Version
+ variant Variant
+ isuuid bool
+}
+
+var tests = []test{
+ {"f47ac10b-58cc-0372-8567-0e02b2c3d479", 0, RFC4122, true},
+ {"f47ac10b-58cc-1372-8567-0e02b2c3d479", 1, RFC4122, true},
+ {"f47ac10b-58cc-2372-8567-0e02b2c3d479", 2, RFC4122, true},
+ {"f47ac10b-58cc-3372-8567-0e02b2c3d479", 3, RFC4122, true},
+ {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
+ {"f47ac10b-58cc-5372-8567-0e02b2c3d479", 5, RFC4122, true},
+ {"f47ac10b-58cc-6372-8567-0e02b2c3d479", 6, RFC4122, true},
+ {"f47ac10b-58cc-7372-8567-0e02b2c3d479", 7, RFC4122, true},
+ {"f47ac10b-58cc-8372-8567-0e02b2c3d479", 8, RFC4122, true},
+ {"f47ac10b-58cc-9372-8567-0e02b2c3d479", 9, RFC4122, true},
+ {"f47ac10b-58cc-a372-8567-0e02b2c3d479", 10, RFC4122, true},
+ {"f47ac10b-58cc-b372-8567-0e02b2c3d479", 11, RFC4122, true},
+ {"f47ac10b-58cc-c372-8567-0e02b2c3d479", 12, RFC4122, true},
+ {"f47ac10b-58cc-d372-8567-0e02b2c3d479", 13, RFC4122, true},
+ {"f47ac10b-58cc-e372-8567-0e02b2c3d479", 14, RFC4122, true},
+ {"f47ac10b-58cc-f372-8567-0e02b2c3d479", 15, RFC4122, true},
+
+ {"urn:uuid:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
+ {"URN:UUID:f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-0567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-1567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-2567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-3567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-4567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-5567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-6567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-7567-0e02b2c3d479", 4, Reserved, true},
+ {"f47ac10b-58cc-4372-8567-0e02b2c3d479", 4, RFC4122, true},
+ {"f47ac10b-58cc-4372-9567-0e02b2c3d479", 4, RFC4122, true},
+ {"f47ac10b-58cc-4372-a567-0e02b2c3d479", 4, RFC4122, true},
+ {"f47ac10b-58cc-4372-b567-0e02b2c3d479", 4, RFC4122, true},
+ {"f47ac10b-58cc-4372-c567-0e02b2c3d479", 4, Microsoft, true},
+ {"f47ac10b-58cc-4372-d567-0e02b2c3d479", 4, Microsoft, true},
+ {"f47ac10b-58cc-4372-e567-0e02b2c3d479", 4, Future, true},
+ {"f47ac10b-58cc-4372-f567-0e02b2c3d479", 4, Future, true},
+
+ {"f47ac10b158cc-5372-a567-0e02b2c3d479", 0, Invalid, false},
+ {"f47ac10b-58cc25372-a567-0e02b2c3d479", 0, Invalid, false},
+ {"f47ac10b-58cc-53723a567-0e02b2c3d479", 0, Invalid, false},
+ {"f47ac10b-58cc-5372-a56740e02b2c3d479", 0, Invalid, false},
+ {"f47ac10b-58cc-5372-a567-0e02-2c3d479", 0, Invalid, false},
+ {"g47ac10b-58cc-4372-a567-0e02b2c3d479", 0, Invalid, false},
+}
+
+var constants = []struct {
+ c interface{}
+ name string
+}{
+ {Person, "Person"},
+ {Group, "Group"},
+ {Org, "Org"},
+ {Invalid, "Invalid"},
+ {RFC4122, "RFC4122"},
+ {Reserved, "Reserved"},
+ {Microsoft, "Microsoft"},
+ {Future, "Future"},
+ {Domain(17), "Domain17"},
+ {Variant(42), "BadVariant42"},
+}
+
+func testTest(t *testing.T, in string, tt test) {
+ uuid := Parse(in)
+ if ok := (uuid != nil); ok != tt.isuuid {
+ t.Errorf("Parse(%s) got %v expected %v\b", in, ok, tt.isuuid)
+ }
+ if uuid == nil {
+ return
+ }
+
+ if v := uuid.Variant(); v != tt.variant {
+ t.Errorf("Variant(%s) got %d expected %d\b", in, v, tt.variant)
+ }
+ if v, _ := uuid.Version(); v != tt.version {
+ t.Errorf("Version(%s) got %d expected %d\b", in, v, tt.version)
+ }
+}
+
+func TestUUID(t *testing.T) {
+ for _, tt := range tests {
+ testTest(t, tt.in, tt)
+ testTest(t, strings.ToUpper(tt.in), tt)
+ }
+}
+
+func TestConstants(t *testing.T) {
+ for x, tt := range constants {
+ v, ok := tt.c.(fmt.Stringer)
+ if !ok {
+ t.Errorf("%x: %v: not a stringer", x, v)
+ } else if s := v.String(); s != tt.name {
+ v, _ := tt.c.(int)
+ t.Errorf("%x: Constant %T:%d gives %q, expected %q", x, tt.c, v, s, tt.name)
+ }
+ }
+}
+
+func TestRandomUUID(t *testing.T) {
+ m := make(map[string]bool)
+ for x := 1; x < 32; x++ {
+ uuid := NewRandom()
+ s := uuid.String()
+ if m[s] {
+ t.Errorf("NewRandom returned duplicated UUID %s", s)
+ }
+ m[s] = true
+ if v, _ := uuid.Version(); v != 4 {
+ t.Errorf("Random UUID of version %s", v)
+ }
+ if uuid.Variant() != RFC4122 {
+ t.Errorf("Random UUID is variant %d", uuid.Variant())
+ }
+ }
+}
+
+func TestNew(t *testing.T) {
+ m := make(map[string]bool)
+ for x := 1; x < 32; x++ {
+ s := New()
+ if m[s] {
+ t.Errorf("New returned duplicated UUID %s", s)
+ }
+ m[s] = true
+ uuid := Parse(s)
+ if uuid == nil {
+ t.Errorf("New returned %q which does not decode", s)
+ continue
+ }
+ if v, _ := uuid.Version(); v != 4 {
+ t.Errorf("Random UUID of version %s", v)
+ }
+ if uuid.Variant() != RFC4122 {
+ t.Errorf("Random UUID is variant %d", uuid.Variant())
+ }
+ }
+}
+
+func clockSeq(t *testing.T, uuid UUID) int {
+ seq, ok := uuid.ClockSequence()
+ if !ok {
+ t.Fatalf("%s: invalid clock sequence", uuid)
+ }
+ return seq
+}
+
+func TestClockSeq(t *testing.T) {
+ // Fake time.Now for this test to return a monotonically advancing time; restore it at end.
+ defer func(orig func() time.Time) { timeNow = orig }(timeNow)
+ monTime := time.Now()
+ timeNow = func() time.Time {
+ monTime = monTime.Add(1 * time.Second)
+ return monTime
+ }
+
+ SetClockSequence(-1)
+ uuid1 := NewUUID()
+ uuid2 := NewUUID()
+
+ if clockSeq(t, uuid1) != clockSeq(t, uuid2) {
+ t.Errorf("clock sequence %d != %d", clockSeq(t, uuid1), clockSeq(t, uuid2))
+ }
+
+ SetClockSequence(-1)
+ uuid2 = NewUUID()
+
+ // Just on the very off chance we generated the same sequence
+ // two times we try again.
+ if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
+ SetClockSequence(-1)
+ uuid2 = NewUUID()
+ }
+ if clockSeq(t, uuid1) == clockSeq(t, uuid2) {
+ t.Errorf("Duplicate clock sequence %d", clockSeq(t, uuid1))
+ }
+
+ SetClockSequence(0x1234)
+ uuid1 = NewUUID()
+ if seq := clockSeq(t, uuid1); seq != 0x1234 {
+ t.Errorf("%s: expected seq 0x1234 got 0x%04x", uuid1, seq)
+ }
+}
+
+func TestCoding(t *testing.T) {
+ text := "7d444840-9dc0-11d1-b245-5ffdce74fad2"
+ urn := "urn:uuid:7d444840-9dc0-11d1-b245-5ffdce74fad2"
+ data := UUID{
+ 0x7d, 0x44, 0x48, 0x40,
+ 0x9d, 0xc0,
+ 0x11, 0xd1,
+ 0xb2, 0x45,
+ 0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2,
+ }
+ if v := data.String(); v != text {
+ t.Errorf("%x: encoded to %s, expected %s", data, v, text)
+ }
+ if v := data.URN(); v != urn {
+ t.Errorf("%x: urn is %s, expected %s", data, v, urn)
+ }
+
+ uuid := Parse(text)
+ if !Equal(uuid, data) {
+ t.Errorf("%s: decoded to %s, expected %s", text, uuid, data)
+ }
+}
+
+func TestVersion1(t *testing.T) {
+ uuid1 := NewUUID()
+ uuid2 := NewUUID()
+
+ if Equal(uuid1, uuid2) {
+ t.Errorf("%s:duplicate uuid", uuid1)
+ }
+ if v, _ := uuid1.Version(); v != 1 {
+ t.Errorf("%s: version %s expected 1", uuid1, v)
+ }
+ if v, _ := uuid2.Version(); v != 1 {
+ t.Errorf("%s: version %s expected 1", uuid2, v)
+ }
+ n1 := uuid1.NodeID()
+ n2 := uuid2.NodeID()
+ if !bytes.Equal(n1, n2) {
+ t.Errorf("Different nodes %x != %x", n1, n2)
+ }
+ t1, ok := uuid1.Time()
+ if !ok {
+ t.Errorf("%s: invalid time", uuid1)
+ }
+ t2, ok := uuid2.Time()
+ if !ok {
+ t.Errorf("%s: invalid time", uuid2)
+ }
+ q1, ok := uuid1.ClockSequence()
+ if !ok {
+ t.Errorf("%s: invalid clock sequence", uuid1)
+ }
+ q2, ok := uuid2.ClockSequence()
+ if !ok {
+ t.Errorf("%s: invalid clock sequence", uuid2)
+ }
+
+ switch {
+ case t1 == t2 && q1 == q2:
+ t.Error("time stopped")
+ case t1 > t2 && q1 == q2:
+ t.Error("time reversed")
+ case t1 < t2 && q1 != q2:
+ t.Error("clock sequence chaned unexpectedly")
+ }
+}
+
+func TestNode(t *testing.T) {
+ // This test is mostly to make sure we don't leave nodeMu locked.
+ ifname = ""
+ if ni := NodeInterface(); ni != "" {
+ t.Errorf("NodeInterface got %q, want %q", ni, "")
+ }
+ if SetNodeInterface("xyzzy") {
+ t.Error("SetNodeInterface succeeded on a bad interface name")
+ }
+ if !SetNodeInterface("") {
+ t.Error("SetNodeInterface failed")
+ }
+ if ni := NodeInterface(); ni == "" {
+ t.Error("NodeInterface returned an empty string")
+ }
+
+ ni := NodeID()
+ if len(ni) != 6 {
+ t.Errorf("ni got %d bytes, want 6", len(ni))
+ }
+ hasData := false
+ for _, b := range ni {
+ if b != 0 {
+ hasData = true
+ }
+ }
+ if !hasData {
+ t.Error("nodeid is all zeros")
+ }
+
+ id := []byte{1, 2, 3, 4, 5, 6, 7, 8}
+ SetNodeID(id)
+ ni = NodeID()
+ if !bytes.Equal(ni, id[:6]) {
+ t.Errorf("got nodeid %v, want %v", ni, id[:6])
+ }
+
+ if ni := NodeInterface(); ni != "user" {
+ t.Errorf("got inteface %q, want %q", ni, "user")
+ }
+}
+
+func TestNodeAndTime(t *testing.T) {
+ // Time is February 5, 1998 12:30:23.136364800 AM GMT
+
+ uuid := Parse("7d444840-9dc0-11d1-b245-5ffdce74fad2")
+ node := []byte{0x5f, 0xfd, 0xce, 0x74, 0xfa, 0xd2}
+
+ ts, ok := uuid.Time()
+ if ok {
+ c := time.Unix(ts.UnixTime())
+ want := time.Date(1998, 2, 5, 0, 30, 23, 136364800, time.UTC)
+ if !c.Equal(want) {
+ t.Errorf("Got time %v, want %v", c, want)
+ }
+ } else {
+ t.Errorf("%s: bad time", uuid)
+ }
+ if !bytes.Equal(node, uuid.NodeID()) {
+ t.Errorf("Expected node %v got %v", node, uuid.NodeID())
+ }
+}
+
+func TestMD5(t *testing.T) {
+ uuid := NewMD5(NameSpace_DNS, []byte("python.org")).String()
+ want := "6fa459ea-ee8a-3ca4-894e-db77e160355e"
+ if uuid != want {
+ t.Errorf("MD5: got %q expected %q", uuid, want)
+ }
+}
+
+func TestSHA1(t *testing.T) {
+ uuid := NewSHA1(NameSpace_DNS, []byte("python.org")).String()
+ want := "886313e1-3b8a-5372-9b90-0c9aee199e5d"
+ if uuid != want {
+ t.Errorf("SHA1: got %q expected %q", uuid, want)
+ }
+}
+
+func TestNodeID(t *testing.T) {
+ nid := []byte{1, 2, 3, 4, 5, 6}
+ SetNodeInterface("")
+ s := NodeInterface()
+ if s == "" || s == "user" {
+ t.Errorf("NodeInterface %q after SetInteface", s)
+ }
+ node1 := NodeID()
+ if node1 == nil {
+ t.Error("NodeID nil after SetNodeInterface", s)
+ }
+ SetNodeID(nid)
+ s = NodeInterface()
+ if s != "user" {
+ t.Errorf("Expected NodeInterface %q got %q", "user", s)
+ }
+ node2 := NodeID()
+ if node2 == nil {
+ t.Error("NodeID nil after SetNodeID", s)
+ }
+ if bytes.Equal(node1, node2) {
+ t.Error("NodeID not changed after SetNodeID", s)
+ } else if !bytes.Equal(nid, node2) {
+ t.Errorf("NodeID is %x, expected %x", node2, nid)
+ }
+}
+
+func testDCE(t *testing.T, name string, uuid UUID, domain Domain, id uint32) {
+ if uuid == nil {
+ t.Errorf("%s failed", name)
+ return
+ }
+ if v, _ := uuid.Version(); v != 2 {
+ t.Errorf("%s: %s: expected version 2, got %s", name, uuid, v)
+ return
+ }
+ if v, ok := uuid.Domain(); !ok || v != domain {
+ if !ok {
+ t.Errorf("%s: %d: Domain failed", name, uuid)
+ } else {
+ t.Errorf("%s: %s: expected domain %d, got %d", name, uuid, domain, v)
+ }
+ }
+ if v, ok := uuid.Id(); !ok || v != id {
+ if !ok {
+ t.Errorf("%s: %d: Id failed", name, uuid)
+ } else {
+ t.Errorf("%s: %s: expected id %d, got %d", name, uuid, id, v)
+ }
+ }
+}
+
+func TestDCE(t *testing.T) {
+ testDCE(t, "NewDCESecurity", NewDCESecurity(42, 12345678), 42, 12345678)
+ testDCE(t, "NewDCEPerson", NewDCEPerson(), Person, uint32(os.Getuid()))
+ testDCE(t, "NewDCEGroup", NewDCEGroup(), Group, uint32(os.Getgid()))
+}
+
+type badRand struct{}
+
+func (r badRand) Read(buf []byte) (int, error) {
+ for i, _ := range buf {
+ buf[i] = byte(i)
+ }
+ return len(buf), nil
+}
+
+func TestBadRand(t *testing.T) {
+ SetRand(badRand{})
+ uuid1 := New()
+ uuid2 := New()
+ if uuid1 != uuid2 {
+ t.Errorf("execpted duplicates, got %q and %q", uuid1, uuid2)
+ }
+ SetRand(nil)
+ uuid1 = New()
+ uuid2 = New()
+ if uuid1 == uuid2 {
+ t.Errorf("unexecpted duplicates, got %q", uuid1)
+ }
+}
+
+func TestUUID_Array(t *testing.T) {
+ expect := Array{
+ 0xf4, 0x7a, 0xc1, 0x0b,
+ 0x58, 0xcc,
+ 0x03, 0x72,
+ 0x85, 0x67,
+ 0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
+ }
+ uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if uuid == nil {
+ t.Fatal("invalid uuid")
+ }
+ if uuid.Array() != expect {
+ t.Fatal("invalid array")
+ }
+}
+
+func TestArray_UUID(t *testing.T) {
+ array := Array{
+ 0xf4, 0x7a, 0xc1, 0x0b,
+ 0x58, 0xcc,
+ 0x03, 0x72,
+ 0x85, 0x67,
+ 0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
+ }
+ expect := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if expect == nil {
+ t.Fatal("invalid uuid")
+ }
+ if !bytes.Equal(array.UUID(), expect) {
+ t.Fatal("invalid uuid")
+ }
+}
+
+func BenchmarkParse(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if uuid == nil {
+ b.Fatal("invalid uuid")
+ }
+ }
+}
+
+func BenchmarkNew(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ New()
+ }
+}
+
+func BenchmarkUUID_String(b *testing.B) {
+ uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if uuid == nil {
+ b.Fatal("invalid uuid")
+ }
+ for i := 0; i < b.N; i++ {
+ if uuid.String() == "" {
+ b.Fatal("invalid uuid")
+ }
+ }
+}
+
+func BenchmarkUUID_URN(b *testing.B) {
+ uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if uuid == nil {
+ b.Fatal("invalid uuid")
+ }
+ for i := 0; i < b.N; i++ {
+ if uuid.URN() == "" {
+ b.Fatal("invalid uuid")
+ }
+ }
+}
+
+func BenchmarkUUID_Array(b *testing.B) {
+ expect := Array{
+ 0xf4, 0x7a, 0xc1, 0x0b,
+ 0x58, 0xcc,
+ 0x03, 0x72,
+ 0x85, 0x67,
+ 0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
+ }
+ uuid := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if uuid == nil {
+ b.Fatal("invalid uuid")
+ }
+ for i := 0; i < b.N; i++ {
+ if uuid.Array() != expect {
+ b.Fatal("invalid array")
+ }
+ }
+}
+
+func BenchmarkArray_UUID(b *testing.B) {
+ array := Array{
+ 0xf4, 0x7a, 0xc1, 0x0b,
+ 0x58, 0xcc,
+ 0x03, 0x72,
+ 0x85, 0x67,
+ 0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79,
+ }
+ expect := Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
+ if expect == nil {
+ b.Fatal("invalid uuid")
+ }
+ for i := 0; i < b.N; i++ {
+ if !bytes.Equal(array.UUID(), expect) {
+ b.Fatal("invalid uuid")
+ }
+ }
+}
diff --git a/vendor/github.com/rwcarlsen/goexif/.gitignore b/vendor/github.com/rwcarlsen/goexif/.gitignore
new file mode 100644
index 000000000..3866bbf31
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/.gitignore
@@ -0,0 +1,23 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+*.sw*
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
diff --git a/vendor/github.com/rwcarlsen/goexif/README.md b/vendor/github.com/rwcarlsen/goexif/README.md
new file mode 100644
index 000000000..8b815a0fd
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/README.md
@@ -0,0 +1,71 @@
+goexif
+======
+
+Provides decoding of basic exif and tiff encoded data. Still in alpha - no guarantees.
+Suggestions and pull requests are welcome. Functionality is split into two packages - "exif" and "tiff"
+The exif package depends on the tiff package.
+Documentation can be found at http://godoc.org/github.com/rwcarlsen/goexif
+
+Like goexif? - Bitcoin tips welcome: 17M7LFh3ETz4bz83VikB7xuGQskt8K5Lj4
+
+To install, in a terminal type:
+
+```
+go get github.com/rwcarlsen/goexif/exif
+```
+
+Or if you just want the tiff package:
+
+```
+go get github.com/rwcarlsen/goexif/tiff
+```
+
+Example usage:
+
+```go
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/mknote"
+)
+
+func ExampleDecode() {
+ fname := "sample1.jpg"
+
+ f, err := os.Open(fname)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Optionally register camera makenote data parsing - currently Nikon and
+ // Canon are supported.
+ exif.RegisterParsers(mknote.All...)
+
+ x, err := exif.Decode(f)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ camModel, _ := x.Get(exif.Model) // normally, don't ignore errors!
+ fmt.Println(camModel.StringVal())
+
+ focal, _ := x.Get(exif.FocalLength)
+ numer, denom, _ := focal.Rat2(0) // retrieve first (only) rat. value
+ fmt.Printf("%v/%v", numer, denom)
+
+ // Two convenience functions exist for date/time taken and GPS coords:
+ tm, _ := x.DateTime()
+ fmt.Println("Taken: ", tm)
+
+ lat, long, _ := x.LatLong()
+ fmt.Println("lat, long: ", lat, ", ", long)
+}
+```
+
+<!--golang-->
+[![githalytics.com alpha](https://cruel-carlota.pagodabox.com/5e166f74cdb82b999ccd84e3c4dc4348 "githalytics.com")](http://githalytics.com/rwcarlsen/goexif)
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/corrupt/huge_tag_exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/corrupt/huge_tag_exif.jpg
new file mode 100644
index 000000000..ffb31743d
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/corrupt/huge_tag_exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/corrupt/infinite_loop_exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/corrupt/infinite_loop_exif.jpg
new file mode 100644
index 000000000..6b0994713
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/corrupt/infinite_loop_exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/corrupt/max_uint32_exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/corrupt/max_uint32_exif.jpg
new file mode 100644
index 000000000..2a51b0ba0
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/corrupt/max_uint32_exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/example_test.go b/vendor/github.com/rwcarlsen/goexif/exif/example_test.go
new file mode 100644
index 000000000..45fd5d4ad
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/example_test.go
@@ -0,0 +1,42 @@
+package exif_test
+
+import (
+ "fmt"
+ "log"
+ "os"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/mknote"
+)
+
+func ExampleDecode() {
+ fname := "sample1.jpg"
+
+ f, err := os.Open(fname)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Optionally register camera makenote data parsing - currently Nikon and
+ // Canon are supported.
+ exif.RegisterParsers(mknote.All...)
+
+ x, err := exif.Decode(f)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ camModel, _ := x.Get(exif.Model) // normally, don't ignore errors!
+ fmt.Println(camModel.StringVal())
+
+ focal, _ := x.Get(exif.FocalLength)
+ numer, denom, _ := focal.Rat2(0) // retrieve first (only) rat. value
+ fmt.Printf("%v/%v", numer, denom)
+
+ // Two convenience functions exist for date/time taken and GPS coords:
+ tm, _ := x.DateTime()
+ fmt.Println("Taken: ", tm)
+
+ lat, long, _ := x.LatLong()
+ fmt.Println("lat, long: ", lat, ", ", long)
+}
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/exif_test.go b/vendor/github.com/rwcarlsen/goexif/exif/exif_test.go
new file mode 100644
index 000000000..c53f1ddda
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/exif_test.go
@@ -0,0 +1,202 @@
+package exif
+
+//go:generate go run regen_regress.go -- regress_expected_test.go
+//go:generate go fmt regress_expected_test.go
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/rwcarlsen/goexif/tiff"
+)
+
+var dataDir = flag.String("test_data_dir", ".", "Directory where the data files for testing are located")
+
+func TestDecode(t *testing.T) {
+ fpath := filepath.Join(*dataDir, "samples")
+ f, err := os.Open(fpath)
+ if err != nil {
+ t.Fatalf("Could not open sample directory '%s': %v", fpath, err)
+ }
+
+ names, err := f.Readdirnames(0)
+ if err != nil {
+ t.Fatalf("Could not read sample directory '%s': %v", fpath, err)
+ }
+
+ cnt := 0
+ for _, name := range names {
+ if !strings.HasSuffix(name, ".jpg") {
+ t.Logf("skipping non .jpg file %v", name)
+ continue
+ }
+ t.Logf("testing file %v", name)
+ f, err := os.Open(filepath.Join(fpath, name))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ x, err := Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ } else if x == nil {
+ t.Fatalf("No error and yet %v was not decoded", name)
+ }
+
+ t.Logf("checking pic %v", name)
+ x.Walk(&walker{name, t})
+ cnt++
+ }
+ if cnt != len(regressExpected) {
+ t.Errorf("Did not process enough samples, got %d, want %d", cnt, len(regressExpected))
+ }
+}
+
+type walker struct {
+ picName string
+ t *testing.T
+}
+
+func (w *walker) Walk(field FieldName, tag *tiff.Tag) error {
+ // this needs to be commented out when regenerating regress expected vals
+ pic := regressExpected[w.picName]
+ if pic == nil {
+ w.t.Errorf(" regression data not found")
+ return nil
+ }
+
+ exp, ok := pic[field]
+ if !ok {
+ w.t.Errorf(" regression data does not have field %v", field)
+ return nil
+ }
+
+ s := tag.String()
+ if tag.Count == 1 && s != "\"\"" {
+ s = fmt.Sprintf("[%s]", s)
+ }
+ got := tag.String()
+
+ if exp != got {
+ fmt.Println("s: ", s)
+ fmt.Printf("len(s)=%v\n", len(s))
+ w.t.Errorf(" field %v bad tag: expected '%s', got '%s'", field, exp, got)
+ }
+ return nil
+}
+
+func TestMarshal(t *testing.T) {
+ name := filepath.Join(*dataDir, "sample1.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ x, err := Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if x == nil {
+ t.Fatal("bad err")
+ }
+
+ b, err := x.MarshalJSON()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Logf("%s", b)
+}
+
+func testSingleParseDegreesString(t *testing.T, s string, w float64) {
+ g, err := parseTagDegreesString(s)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if math.Abs(w-g) > 1e-10 {
+ t.Errorf("Wrong parsing result %s: Want %.12f, got %.12f", s, w, g)
+ }
+}
+
+func TestParseTagDegreesString(t *testing.T) {
+ // semicolon as decimal mark
+ testSingleParseDegreesString(t, "52,00000,50,00000,34,01180", 52.842781055556) // comma as separator
+ testSingleParseDegreesString(t, "52,00000;50,00000;34,01180", 52.842781055556) // semicolon as separator
+
+ // point as decimal mark
+ testSingleParseDegreesString(t, "14.00000,44.00000,34.01180", 14.742781055556) // comma as separator
+ testSingleParseDegreesString(t, "14.00000;44.00000;34.01180", 14.742781055556) // semicolon as separator
+ testSingleParseDegreesString(t, "14.00000;44.00000,34.01180", 14.742781055556) // mixed separators
+
+ testSingleParseDegreesString(t, "-008.0,30.0,03.6", -8.501) // leading zeros
+
+ // no decimal places
+ testSingleParseDegreesString(t, "-10,15,54", -10.265)
+ testSingleParseDegreesString(t, "-10;15;54", -10.265)
+
+ // incorrect mix of comma and point as decimal mark
+ s := "-17,00000,15.00000,04.80000"
+ if _, err := parseTagDegreesString(s); err == nil {
+ t.Error("parseTagDegreesString: false positive for " + s)
+ }
+}
+
+// Make sure we error out early when a tag had a count of MaxUint32
+func TestMaxUint32CountError(t *testing.T) {
+ name := filepath.Join(*dataDir, "corrupt/max_uint32_exif.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ _, err = Decode(f)
+ if err == nil {
+ t.Fatal("no error on bad exif data")
+ }
+ if !strings.Contains(err.Error(), "invalid Count offset") {
+ t.Fatal("wrong error:", err.Error())
+ }
+}
+
+// Make sure we error out early with tag data sizes larger than the image file
+func TestHugeTagError(t *testing.T) {
+ name := filepath.Join(*dataDir, "corrupt/huge_tag_exif.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ _, err = Decode(f)
+ if err == nil {
+ t.Fatal("no error on bad exif data")
+ }
+ if !strings.Contains(err.Error(), "short read") {
+ t.Fatal("wrong error:", err.Error())
+ }
+}
+
+// Check for a 0-length tag value
+func TestZeroLengthTagError(t *testing.T) {
+ name := filepath.Join(*dataDir, "corrupt/infinite_loop_exif.jpg")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+ defer f.Close()
+
+ _, err = Decode(f)
+ if err == nil {
+ t.Fatal("no error on bad exif data")
+ }
+ if !strings.Contains(err.Error(), "zero length tag value") {
+ t.Fatal("wrong error:", err.Error())
+ }
+}
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/regress_expected_test.go b/vendor/github.com/rwcarlsen/goexif/exif/regress_expected_test.go
new file mode 100644
index 000000000..bf3998189
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/regress_expected_test.go
@@ -0,0 +1,2293 @@
+package exif
+
+var regressExpected = map[string]map[FieldName]string{
+ "2004-01-11-22-45-15-sep-2004-01-11-22-45-15a.jpg": map[FieldName]string{
+ PixelXDimension: `1600`,
+ InteroperabilityIFDPointer: `1009`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Samsung Techwin"`,
+ DateTimeOriginal: `"2004:01:11 22:45:15"`,
+ DateTimeDigitized: `"2004:01:11 22:45:15"`,
+ ImageDescription: `"SAMSUNG DIGITAL CAMERA "`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `2`,
+ Flash: `1`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `1039`,
+ MaxApertureValue: `"32/10"`,
+ ExposureProgram: `2`,
+ Software: `"M5011S-1031"`,
+ DateTime: `"2004:01:11 22:45:19"`,
+ FNumber: `"320/100"`,
+ ISOSpeedRatings: `150`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"2/1"`,
+ RelatedSoundFile: `""`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `251`,
+ ExposureTime: `"1000/30000"`,
+ LightSource: `0`,
+ FocalLength: `"82/11"`,
+ ColorSpace: `1`,
+ PixelYDimension: `1200`,
+ FileSource: `""`,
+ Model: `"U-CA 501"`,
+ ThumbJPEGInterchangeFormatLength: `3530`,
+ ExposureBiasValue: `"95/10"`,
+ },
+ "2006-08-03-16-29-38-sep-2006-08-03-16-29-38a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `4323`,
+ MaxApertureValue: `"95/32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/1500"`,
+ InteroperabilityIndex: `"R98"`,
+ FocalPlaneXResolution: `"2816000/225"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2006:08:03 16:29:38"`,
+ ShutterSpeedValue: `"338/32"`,
+ ApertureValue: `"95/32"`,
+ FocalLength: `"5800/1000"`,
+ FlashpixVersion: `"0100"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2006:08:03 16:29:38"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2824`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2006:08:03 16:29:38"`,
+ CompressedBitsPerPixel: `"5/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ PixelXDimension: `2816`,
+ Model: `"Canon PowerShot SD600"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `2112`,
+ FocalPlaneResolutionUnit: `2`,
+ DigitalZoomRatio: `"2816/2816"`,
+ Orientation: `6`,
+ XResolution: `"180/1"`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ FocalPlaneYResolution: `"2112000/169"`,
+ CustomRendered: `0`,
+ },
+ "2006-11-11-19-17-56-sep-2006-11-11-19-17-56a.jpg": map[FieldName]string{
+ FNumber: `"28/10"`,
+ ExposureProgram: `2`,
+ Software: `"E3200v1.1"`,
+ DateTime: `"2006:11:11 19:17:56"`,
+ ExposureTime: `"10/601"`,
+ ISOSpeedRatings: `50`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"4/1"`,
+ Saturation: `0`,
+ XResolution: `"300/1"`,
+ ExifIFDPointer: `284`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"58/10"`,
+ ColorSpace: `1`,
+ PixelYDimension: `1536`,
+ FileSource: `""`,
+ Model: `"E3200"`,
+ ThumbJPEGInterchangeFormatLength: `4546`,
+ DateTimeDigitized: `"2006:11:11 19:17:56"`,
+ PixelXDimension: `2048`,
+ InteroperabilityIFDPointer: `1026`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/100"`,
+ GainControl: `0`,
+ Make: `"NIKON"`,
+ DateTimeOriginal: `"2006:11:11 19:17:56"`,
+ InteroperabilityIndex: `"R98"`,
+ ImageDescription: `" "`,
+ Sharpness: `0`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `25`,
+ FocalLengthIn35mmFilm: `38`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ MaxApertureValue: `"30/10"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"300/1"`,
+ ThumbJPEGInterchangeFormat: `4596`,
+ CustomRendered: `1`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ UserComment: `" "`,
+ },
+ "2006-12-10-23-58-20-sep-2006-12-10-23-58-20a.jpg": map[FieldName]string{
+ Model: `"Canon PowerShot A80"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `1704`,
+ FocalPlaneResolutionUnit: `2`,
+ FocalPlaneYResolution: `"1704000/210"`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"2272/2272"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ ThumbJPEGInterchangeFormat: `2036`,
+ ThumbJPEGInterchangeFormatLength: `6465`,
+ MaxApertureValue: `"95/32"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/80"`,
+ FocalLength: `"250/32"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"2272000/280"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2006:12:10 23:58:20"`,
+ ShutterSpeedValue: `"202/32"`,
+ ApertureValue: `"95/32"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2006:12:10 23:58:20"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1844`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ UserComment: `""`,
+ PixelXDimension: `2272`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2006:12:10 23:58:20"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ },
+ "2006-12-17-07-09-14-sep-2006-12-17-07-09-14a.jpg": map[FieldName]string{
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `7063`,
+ ExposureBiasValue: `"0/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1536`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"PENTAX Corporation"`,
+ DateTimeDigitized: `"2006:12:17 07:09:14"`,
+ PixelXDimension: `2048`,
+ InteroperabilityIFDPointer: `31048`,
+ CustomRendered: `0`,
+ DateTime: `"2006:12:17 07:09:14"`,
+ ExposureProgram: `2`,
+ FocalLengthIn35mmFilm: `38`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `64`,
+ ExifVersion: `"0220"`,
+ CompressedBitsPerPixel: `"5725504/3145728"`,
+ Flash: `24`,
+ Model: `"PENTAX Optio S6"`,
+ ThumbJPEGInterchangeFormat: `31172`,
+ MaxApertureValue: `"27/10"`,
+ FocalLength: `"62/10"`,
+ ColorSpace: `1`,
+ DateTimeOriginal: `"2006:12:17 07:09:14"`,
+ MakerNote: `""`,
+ DigitalZoomRatio: `"100/100"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Software: `"Optio S6 Ver 1.00"`,
+ FNumber: `"270/100"`,
+ Sharpness: `0`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `5`,
+ SubjectDistanceRange: `2`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `586`,
+ ExposureTime: `"1/160"`,
+ },
+ "2006-12-21-15-55-26-sep-2006-12-21-15-55-26a.jpg": map[FieldName]string{
+ DateTimeDigitized: `"2006:12:21 15:55:26"`,
+ CompressedBitsPerPixel: `"8/1"`,
+ MeteringMode: `3`,
+ MakerNote: `""`,
+ PixelXDimension: `2592`,
+ Saturation: `0`,
+ ImageDescription: `" "`,
+ Model: `"DSC-W15"`,
+ ExposureBiasValue: `"-20/10"`,
+ PixelYDimension: `1944`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0220"`,
+ Flash: `79`,
+ CustomRendered: `0`,
+ ThumbJPEGInterchangeFormat: `2484`,
+ ThumbJPEGInterchangeFormatLength: `13571`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"48/16"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `256`,
+ ExposureTime: `"10/400"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ YResolution: `"72/1"`,
+ DateTime: `"2006:12:21 15:55:26"`,
+ LightSource: `0`,
+ FocalLength: `"79/10"`,
+ FlashpixVersion: `"0100"`,
+ Contrast: `0`,
+ Make: `"SONY"`,
+ DateTimeOriginal: `"2006:12:21 15:55:26"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2278`,
+ ExposureMode: `1`,
+ SceneCaptureType: `0`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ },
+ "2007-01-01-12-00-00-sep-2007-01-01-12-00-00a.jpg": map[FieldName]string{
+ MaxApertureValue: `"286/100"`,
+ ExposureIndex: `"200/1"`,
+ ThumbJPEGInterchangeFormat: `13848`,
+ ThumbJPEGInterchangeFormatLength: `3436`,
+ ExposureProgram: `2`,
+ ExposureTime: `"8942/1000000"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `340`,
+ ApertureValue: `"286/100"`,
+ LightSource: `0`,
+ FocalLength: `"60/10"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"480/1"`,
+ Software: `"KODAK EASYSHARE C713 ZOOM DIGITAL CAMERA"`,
+ ShutterSpeedValue: `"680/100"`,
+ InteroperabilityIFDPointer: `13816`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `36`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ DateTimeOriginal: `"2007:01:01 12:00:00"`,
+ ComponentsConfiguration: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ FNumber: `"270/100"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ PixelXDimension: `1280`,
+ SensingMethod: `2`,
+ GainControl: `2`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ DateTimeDigitized: `"2007:01:01 12:00:00"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ Model: `"KODAK EASYSHARE C713 ZOOM DIGITAL CAMERA"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `960`,
+ ExifVersion: `"0221"`,
+ Flash: `25`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/10"`,
+ Orientation: `1`,
+ XResolution: `"480/1"`,
+ ISOSpeedRatings: `200`,
+ },
+ "2007-01-17-21-49-44-sep-2007-01-17-21-49-44a.jpg": map[FieldName]string{
+ XResolution: `"180/1"`,
+ ISOSpeedRatings: `50`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ CustomRendered: `0`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `7024`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"297/100"`,
+ ThumbJPEGInterchangeFormat: `956`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `266`,
+ ExposureTime: `"1/30"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ Software: `"1.00.018PR "`,
+ DateTime: `"2007:01:17 21:49:44"`,
+ ShutterSpeedValue: `"491/100"`,
+ ApertureValue: `"33/10"`,
+ LightSource: `0`,
+ FocalLength: `"73/10"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"180/1"`,
+ DateTimeOriginal: `"2007:01:17 21:49:44"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `832`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Digital Camera "`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ FNumber: `"33/10"`,
+ MeteringMode: `2`,
+ MakerNote: `"6106789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456"`,
+ PixelXDimension: `2816`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2007:01:17 21:49:44"`,
+ Model: `"6MP-9Y8 "`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `2112`,
+ ImageDescription: `"Digital image "`,
+ },
+ "2007-02-02-18-13-29-sep-2007-02-02-18-13-29a.jpg": map[FieldName]string{
+ Software: `"Optio S5z Ver 1.00 "`,
+ FNumber: `"26/10"`,
+ Sharpness: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `586`,
+ ExposureTime: `"1/60"`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `5`,
+ SubjectDistanceRange: `2`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `8800`,
+ ExposureBiasValue: `"0/3"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1920`,
+ WhiteBalance: `0`,
+ Make: `"PENTAX Corporation "`,
+ DateTimeDigitized: `"2007:02:02 18:13:29"`,
+ PixelXDimension: `2560`,
+ InteroperabilityIFDPointer: `30974`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ DateTime: `"2007:02:02 18:13:29"`,
+ ExposureProgram: `2`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `200`,
+ ExifVersion: `"0220"`,
+ CompressedBitsPerPixel: `"27033600/4915200"`,
+ Flash: `25`,
+ FocalLengthIn35mmFilm: `35`,
+ Saturation: `0`,
+ Model: `"PENTAX Optio S5z "`,
+ ThumbJPEGInterchangeFormat: `31098`,
+ MaxApertureValue: `"28/10"`,
+ FocalLength: `"580/100"`,
+ ColorSpace: `1`,
+ DateTimeOriginal: `"2007:02:02 18:13:29"`,
+ MakerNote: `""`,
+ DigitalZoomRatio: `"0/0"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ },
+ "2007-05-02-17-02-21-sep-2007-05-02-17-02-21a.jpg": map[FieldName]string{
+ UserComment: `""`,
+ PixelXDimension: `1600`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2007:05:02 17:02:21"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ Model: `"Canon IXY DIGITAL 55"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `1200`,
+ FocalPlaneResolutionUnit: `2`,
+ FocalPlaneYResolution: `"1200000/168"`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"2592/2592"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ExifVersion: `"0220"`,
+ Flash: `9`,
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `6306`,
+ MaxApertureValue: `"107/32"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/60"`,
+ FocalLength: `"7109/1000"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"1600000/225"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2007:05:02 17:02:21"`,
+ ShutterSpeedValue: `"189/32"`,
+ ApertureValue: `"107/32"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2007:05:02 17:02:21"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2226`,
+ FNumber: `"32/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ },
+ "2007-05-12-08-19-07-sep-2007-05-12-08-19-07a.jpg": map[FieldName]string{
+ Model: `"EX-Z70 "`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `480`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/0"`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ExifVersion: `"0221"`,
+ Flash: `16`,
+ ThumbJPEGInterchangeFormat: `27422`,
+ ThumbJPEGInterchangeFormatLength: `8332`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"33/10"`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `282`,
+ ExposureTime: `"1/50"`,
+ FocalLength: `"630/100"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ Software: `"1.00 "`,
+ DateTime: `"2007:06:17 22:56:38"`,
+ LightSource: `0`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `38`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"CASIO COMPUTER CO.,LTD."`,
+ DateTimeOriginal: `"2007:05:12 08:19:07"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `27298`,
+ Sharpness: `0`,
+ FNumber: `"31/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ PixelXDimension: `640`,
+ GainControl: `2`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2007:06:17 22:56:38"`,
+ CompressedBitsPerPixel: `"252746/307200"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ },
+ "2007-05-26-04-49-45-sep-2007-05-26-04-49-45a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `4596`,
+ ThumbJPEGInterchangeFormatLength: `10120`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"34/10"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `284`,
+ ExposureTime: `"10/3486"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ YResolution: `"300/1"`,
+ Software: `"COOLPIX L3v1.2"`,
+ DateTime: `"2007:05:26 04:49:45"`,
+ LightSource: `0`,
+ FocalLength: `"63/10"`,
+ FlashpixVersion: `"0100"`,
+ Contrast: `0`,
+ Make: `"NIKON"`,
+ DateTimeOriginal: `"2007:05:26 04:49:45"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1026`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `38`,
+ SceneCaptureType: `2`,
+ FNumber: `"32/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2007:05:26 04:49:45"`,
+ CompressedBitsPerPixel: `"4/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `" "`,
+ PixelXDimension: `2592`,
+ GainControl: `0`,
+ SubjectDistanceRange: `0`,
+ ImageDescription: `" "`,
+ Model: `"COOLPIX L3"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `1944`,
+ Orientation: `1`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `50`,
+ ExifVersion: `"0220"`,
+ Flash: `24`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ },
+ "2007-05-30-14-28-01-sep-2007-05-30-14-28-01a.jpg": map[FieldName]string{
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `5`,
+ UserComment: `" "`,
+ GainControl: `1`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ ExifIFDPointer: `284`,
+ ExposureTime: `"10/40"`,
+ InteroperabilityIndex: `"R98"`,
+ Software: `"COOLPIX S6V1.0"`,
+ ImageDescription: `" "`,
+ Model: `"COOLPIX S6"`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `53`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1026`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ Make: `"NIKON"`,
+ Orientation: `1`,
+ Contrast: `0`,
+ FocalLengthIn35mmFilm: `35`,
+ SceneCaptureType: `0`,
+ FileSource: `""`,
+ FNumber: `"30/10"`,
+ ExposureProgram: `2`,
+ DateTimeDigitized: `"2007:05:30 14:28:01"`,
+ MakerNote: `""`,
+ PixelXDimension: `2816`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"58/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2112`,
+ YResolution: `"300/1"`,
+ DateTime: `"2007:05:30 14:28:01"`,
+ Flash: `16`,
+ ExposureMode: `0`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2007:05:30 14:28:01"`,
+ MaxApertureValue: `"32/10"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `4596`,
+ ThumbJPEGInterchangeFormatLength: `5274`,
+ },
+ "2007-06-06-16-15-25-sep-2007-06-06-16-15-25a.jpg": map[FieldName]string{
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2007:06:06 16:15:25"`,
+ Flash: `24`,
+ ExposureMode: `0`,
+ ThumbJPEGInterchangeFormat: `4596`,
+ ThumbJPEGInterchangeFormatLength: `5967`,
+ MaxApertureValue: `"30/10"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ExifIFDPointer: `284`,
+ ExposureTime: `"10/2870"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `5`,
+ UserComment: `" "`,
+ GainControl: `0`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ InteroperabilityIndex: `"R98"`,
+ ImageDescription: `" "`,
+ Model: `"E3700"`,
+ Software: `"E3700v1.2"`,
+ Make: `"NIKON"`,
+ Orientation: `1`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `50`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1026`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ FocalLengthIn35mmFilm: `35`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ FNumber: `"48/10"`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ DateTimeDigitized: `"2007:06:06 16:15:25"`,
+ MakerNote: `""`,
+ PixelXDimension: `2048`,
+ SceneType: `""`,
+ YResolution: `"300/1"`,
+ DateTime: `"2007:06:06 16:15:25"`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"54/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1536`,
+ },
+ "2007-06-26-10-13-04-sep-2007-06-26-10-13-04a.jpg": map[FieldName]string{
+ ColorSpace: `1`,
+ FileSource: `""`,
+ FNumber: `"3/1"`,
+ CompressedBitsPerPixel: `"6389872/3145728"`,
+ MeteringMode: `2`,
+ MakerNote: `""`,
+ PixelXDimension: `2048`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2007:06:26 10:13:04"`,
+ Model: `"DV"`,
+ Copyright: `"Copyright2004"`,
+ ExposureBiasValue: `"1/4"`,
+ PixelYDimension: `1536`,
+ ImageDescription: `"My beautiful picture"`,
+ XResolution: `"320/1"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0210"`,
+ Flash: `0`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `6292`,
+ ExposureProgram: `3`,
+ MaxApertureValue: `"3/1"`,
+ ExposureIndex: `"146/1"`,
+ ThumbJPEGInterchangeFormat: `1306`,
+ YCbCrPositioning: `2`,
+ ExposureTime: `"23697424/268435456"`,
+ ExifIFDPointer: `262`,
+ RelatedSoundFile: `"RelatedSound"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ Software: `"DVWare 1.0"`,
+ DateTime: `"2007:06:26 10:13:04"`,
+ ShutterSpeedValue: `"7/1"`,
+ ApertureValue: `"3/1"`,
+ LightSource: `0`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"384/1"`,
+ DateTimeOriginal: `"2007:06:26 10:13:04"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1170`,
+ Make: `"CEC"`,
+ },
+ "2007-07-13-17-02-30-sep-2007-07-13-17-02-30a.jpg": map[FieldName]string{
+ Software: `"Ver 1.00 "`,
+ DateTime: `"2007:07:13 17:02:30"`,
+ FNumber: `"48/10"`,
+ ExposureProgram: `2`,
+ RelatedSoundFile: `" "`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `266`,
+ ExposureTime: `"1/110"`,
+ ISOSpeedRatings: `64`,
+ ComponentsConfiguration: `""`,
+ ColorSpace: `1`,
+ PixelYDimension: `2736`,
+ FileSource: `""`,
+ Model: `"ViviCam X30 "`,
+ ThumbJPEGInterchangeFormatLength: `20544`,
+ ShutterSpeedValue: `"678/100"`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ DigitalZoomRatio: `"100/100"`,
+ GainControl: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Vivitar"`,
+ DateTimeOriginal: `"2007:07:13 17:02:30"`,
+ DateTimeDigitized: `"2007:07:13 17:02:30"`,
+ PixelXDimension: `3648`,
+ InteroperabilityIFDPointer: `1010`,
+ ImageDescription: `"Digital StillCamera"`,
+ Sharpness: `0`,
+ Flash: `0`,
+ FocalLengthIn35mmFilm: `35`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `2`,
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `1156`,
+ ApertureValue: `"45/10"`,
+ MaxApertureValue: `"30/10"`,
+ FlashpixVersion: `"0100"`,
+ MakerNote: `""`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ },
+ "2007-08-15-14-42-46-sep-2007-08-15-14-42-46a.jpg": map[FieldName]string{
+ Model: `"KODAK C663 ZOOM DIGITAL CAMERA"`,
+ ShutterSpeedValue: `"73/10"`,
+ DigitalZoomRatio: `"0/100"`,
+ FocalLengthIn35mmFilm: `66`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ Orientation: `1`,
+ XResolution: `"230/1"`,
+ CustomRendered: `0`,
+ ISOSpeedRatings: `80`,
+ ComponentsConfiguration: `""`,
+ FNumber: `"36/10"`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ PixelXDimension: `2832`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2007:08:15 14:42:46"`,
+ MakerNote: `""`,
+ FocalLength: `"110/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2128`,
+ YResolution: `"230/1"`,
+ ApertureValue: `"37/10"`,
+ ExposureBiasValue: `"0/3"`,
+ LightSource: `0`,
+ ExposureMode: `0`,
+ ExifVersion: `"0221"`,
+ DateTimeOriginal: `"2007:08:15 14:42:46"`,
+ Flash: `24`,
+ MaxApertureValue: `"37/10"`,
+ ColorSpace: `1`,
+ ExposureIndex: `"80/1"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `8472`,
+ ThumbJPEGInterchangeFormatLength: `3060`,
+ ExposureTime: `"1/160"`,
+ MeteringMode: `5`,
+ ExifIFDPointer: `320`,
+ GainControl: `0`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ },
+ "2007-08-24-02-40-42-sep-2007-08-24-02-40-42a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `2084`,
+ MaxApertureValue: `"147/32"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/400"`,
+ CompressedBitsPerPixel: `"5/1"`,
+ MeteringMode: `5`,
+ UserComment: `""`,
+ InteroperabilityIndex: `"R98"`,
+ Model: `"Canon PowerShot SD450"`,
+ ShutterSpeedValue: `"277/32"`,
+ FocalPlaneResolutionUnit: `2`,
+ DigitalZoomRatio: `"2592/2592"`,
+ Make: `"Canon"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `2206`,
+ FocalPlaneYResolution: `"1944000/168"`,
+ CustomRendered: `0`,
+ SceneCaptureType: `0`,
+ FNumber: `"100/10"`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2007:08:24 02:40:42"`,
+ MakerNote: `""`,
+ PixelXDimension: `2592`,
+ SensingMethod: `2`,
+ FocalPlaneXResolution: `"2592000/225"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2007:08:24 02:40:42"`,
+ ApertureValue: `"213/32"`,
+ ExposureBiasValue: `"0/3"`,
+ FocalLength: `"17400/1000"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1944`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2007:08:24 02:40:42"`,
+ Flash: `24`,
+ ExposureMode: `0`,
+ },
+ "2007-11-07-11-40-44-sep-2007-11-07-11-40-44a.jpg": map[FieldName]string{
+ YResolution: `"72/1"`,
+ Copyright: `" "`,
+ ThumbJPEGInterchangeFormat: `1306`,
+ ApertureValue: `"600/100"`,
+ MaxApertureValue: `"360/100"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ MakerNote: `""`,
+ SensingMethod: `2`,
+ CustomRendered: `1`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Software: `"Digital Camera FinePix Z1 Ver1.00"`,
+ DateTime: `"2007:11:07 11:40:44"`,
+ FNumber: `"800/100"`,
+ ExposureProgram: `2`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `294`,
+ ExposureTime: `"10/2000"`,
+ ISOSpeedRatings: `64`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"20/10"`,
+ PixelYDimension: `1944`,
+ Model: `"FinePix Z1 "`,
+ ThumbJPEGInterchangeFormatLength: `9900`,
+ ShutterSpeedValue: `"764/100"`,
+ ExposureBiasValue: `"0/100"`,
+ LightSource: `0`,
+ FocalLength: `"610/100"`,
+ ColorSpace: `1`,
+ FocalPlaneXResolution: `"4442/1"`,
+ FileSource: `""`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"FUJIFILM"`,
+ DateTimeOriginal: `"2007:11:07 11:40:44"`,
+ DateTimeDigitized: `"2007:11:07 11:40:44"`,
+ BrightnessValue: `"906/100"`,
+ PixelXDimension: `2592`,
+ InteroperabilityIFDPointer: `1158`,
+ SceneType: `""`,
+ FocalPlaneResolutionUnit: `3`,
+ Sharpness: `0`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `16`,
+ FocalPlaneYResolution: `"4442/1"`,
+ },
+ "2008-06-02-10-03-57-sep-2008-06-02-10-03-57a.jpg": map[FieldName]string{
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ FNumber: `"2800/1000"`,
+ CompressedBitsPerPixel: `"5896224/3145728"`,
+ MeteringMode: `4`,
+ MakerNote: `""`,
+ PixelXDimension: `2048`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2008:06:13 06:16:19"`,
+ Copyright: `"Copyright 2006"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `1536`,
+ Model: `"i533"`,
+ XResolution: `"288/3"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0220"`,
+ Flash: `65`,
+ DigitalZoomRatio: `"100/100"`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `5972`,
+ ExposureProgram: `7`,
+ MaxApertureValue: `"2970/1000"`,
+ ThumbJPEGInterchangeFormat: `3756`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `226`,
+ ExposureTime: `"10/600"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ Software: `"00.00.1240a"`,
+ DateTime: `"2008:06:13 06:16:19"`,
+ ShutterSpeedValue: `"5907/1000"`,
+ ApertureValue: `"2970/1000"`,
+ LightSource: `4`,
+ FocalLength: `"6200/1000"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"288/3"`,
+ DateTimeOriginal: `"2008:06:02 10:03:57"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `3620`,
+ ExposureMode: `0`,
+ Make: `"Polaroid"`,
+ },
+ "2008-06-06-13-29-29-sep-2008-06-06-13-29-29a.jpg": map[FieldName]string{
+ PixelXDimension: `1600`,
+ InteroperabilityIFDPointer: `3334`,
+ DigitalZoomRatio: `"3072/3072"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2008:06:06 13:29:29"`,
+ DateTimeDigitized: `"2008:06:06 13:29:29"`,
+ FocalPlaneResolutionUnit: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `16`,
+ FocalPlaneYResolution: `"1200000/169"`,
+ Orientation: `6`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ MaxApertureValue: `"116/32"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"180/1"`,
+ ThumbJPEGInterchangeFormat: `5108`,
+ ApertureValue: `"116/32"`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ SensingMethod: `2`,
+ DateTime: `"2008:06:06 13:29:29"`,
+ FNumber: `"35/10"`,
+ ISOSpeedRatings: `80`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"5/1"`,
+ XResolution: `"180/1"`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/320"`,
+ ExposureBiasValue: `"0/3"`,
+ FocalLength: `"8462/1000"`,
+ ColorSpace: `1`,
+ PixelYDimension: `1200`,
+ FocalPlaneXResolution: `"1600000/225"`,
+ Model: `"Canon DIGITAL IXUS 75"`,
+ ThumbJPEGInterchangeFormatLength: `6594`,
+ ShutterSpeedValue: `"266/32"`,
+ FileSource: `""`,
+ },
+ "2008-06-17-01-21-30-sep-2008-06-17-01-21-30a.jpg": map[FieldName]string{
+ MaxApertureValue: `"30/10"`,
+ ThumbJPEGInterchangeFormat: `1041`,
+ ThumbJPEGInterchangeFormatLength: `13506`,
+ ExposureProgram: `2`,
+ ExposureTime: `"10/326"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `253`,
+ LightSource: `0`,
+ FocalLength: `"645/100"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ Software: `"A520_CT019"`,
+ DateTime: `"2008:06:17 01:22:13"`,
+ InteroperabilityIFDPointer: `1011`,
+ Make: `"Polaroid"`,
+ DateTimeOriginal: `"2008:06:17 01:21:30"`,
+ ComponentsConfiguration: `""`,
+ FNumber: `"28/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ UserComment: `""`,
+ PixelXDimension: `2592`,
+ DateTimeDigitized: `"2008:06:17 01:21:30"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `2`,
+ PixelYDimension: `1944`,
+ ImageDescription: `"DCFC1247.JPG "`,
+ Model: `"5MP Digital Camera"`,
+ ExposureBiasValue: `"0/10"`,
+ ExifVersion: `"0220"`,
+ Flash: `0`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `100`,
+ },
+ "2008-09-02-17-43-48-sep-2008-09-02-17-43-48a.jpg": map[FieldName]string{
+ ImageDescription: `" "`,
+ Model: `"Z550a"`,
+ YResolution: `"72/1"`,
+ Software: `"R6GA004 prgCXC1250583_GENERIC_M 2.0"`,
+ DateTime: `"2008:09:02 17:43:48"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1024`,
+ Make: `"Sony Ericsson"`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2008:09:02 17:43:48"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `612`,
+ ThumbJPEGInterchangeFormat: `748`,
+ ThumbJPEGInterchangeFormatLength: `4641`,
+ ColorSpace: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `302`,
+ DateTimeDigitized: `"2008:09:02 17:43:48"`,
+ PixelXDimension: `1280`,
+ InteroperabilityIndex: `"R98"`,
+ },
+ "2009-03-26-09-23-20-sep-2009-03-26-09-23-20a.jpg": map[FieldName]string{
+ FocalLength: `"5800/1000"`,
+ ColorSpace: `1`,
+ PixelYDimension: `2304`,
+ FocalPlaneXResolution: `"3072000/225"`,
+ Model: `"Canon PowerShot SD750"`,
+ ThumbJPEGInterchangeFormatLength: `5513`,
+ ShutterSpeedValue: `"287/32"`,
+ ExposureBiasValue: `"0/3"`,
+ FileSource: `""`,
+ InteroperabilityIFDPointer: `3334`,
+ DigitalZoomRatio: `"3072/3072"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2009:03:26 09:23:20"`,
+ DateTimeDigitized: `"2009:03:26 09:23:20"`,
+ PixelXDimension: `3072`,
+ FocalPlaneResolutionUnit: `2`,
+ MeteringMode: `5`,
+ Flash: `24`,
+ FocalPlaneYResolution: `"2304000/169"`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifVersion: `"0220"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"180/1"`,
+ ThumbJPEGInterchangeFormat: `5108`,
+ ApertureValue: `"95/32"`,
+ MaxApertureValue: `"95/32"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ SensingMethod: `2`,
+ CustomRendered: `0`,
+ DateTime: `"2009:03:26 09:23:20"`,
+ FNumber: `"28/10"`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"5/1"`,
+ XResolution: `"180/1"`,
+ ExifIFDPointer: `196`,
+ ExposureTime: `"1/500"`,
+ ISOSpeedRatings: `160`,
+ },
+ "2009-04-11-03-01-38-sep-2009-04-11-03-01-38a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `33660`,
+ MaxApertureValue: `"30/10"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ YResolution: `"300/1"`,
+ UserComment: `" "`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ DateTime: `"2009:04:11 03:01:38"`,
+ FNumber: `"28/10"`,
+ ExposureProgram: `2`,
+ Software: `"COOLPIX L18 V1.1"`,
+ ExifIFDPointer: `230`,
+ ExposureTime: `"1/250"`,
+ ISOSpeedRatings: `227`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"4/1"`,
+ Saturation: `0`,
+ XResolution: `"300/1"`,
+ ThumbJPEGInterchangeFormatLength: `9697`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"5700/1000"`,
+ ColorSpace: `1`,
+ PixelYDimension: `2448`,
+ FileSource: `""`,
+ Model: `"COOLPIX L18"`,
+ DateTimeOriginal: `"2009:04:11 03:01:38"`,
+ DateTimeDigitized: `"2009:04:11 03:01:38"`,
+ PixelXDimension: `3264`,
+ InteroperabilityIFDPointer: `33536`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/100"`,
+ GainControl: `1`,
+ Make: `"NIKON"`,
+ InteroperabilityIndex: `"R98"`,
+ Sharpness: `1`,
+ ImageDescription: `" "`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `5`,
+ Flash: `24`,
+ FocalLengthIn35mmFilm: `35`,
+ SubjectDistanceRange: `0`,
+ Orientation: `1`,
+ },
+ "2009-04-23-07-21-35-sep-2009-04-23-07-21-35a.jpg": map[FieldName]string{
+ Sharpness: `0`,
+ MeteringMode: `5`,
+ Flash: `9`,
+ FocalLengthIn35mmFilm: `35`,
+ SubjectDistanceRange: `3`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifVersion: `"0220"`,
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `31176`,
+ MaxApertureValue: `"28/10"`,
+ FlashpixVersion: `"0100"`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Software: `"Optio S50 Ver 1.00"`,
+ DateTime: `"2009:04:23 07:21:35"`,
+ FNumber: `"26/10"`,
+ ComponentsConfiguration: `""`,
+ CompressedBitsPerPixel: `"13301888/4915200"`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `590`,
+ ExposureTime: `"1/40"`,
+ ISOSpeedRatings: `100`,
+ ColorSpace: `1`,
+ PixelYDimension: `1920`,
+ Model: `"PENTAX Optio S50"`,
+ ThumbJPEGInterchangeFormatLength: `6015`,
+ ExposureBiasValue: `"0/10"`,
+ FocalLength: `"58/10"`,
+ InteroperabilityIFDPointer: `31040`,
+ DigitalZoomRatio: `"0/100"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"PENTAX Corporation"`,
+ DateTimeOriginal: `"2009:04:23 07:21:35"`,
+ DateTimeDigitized: `"2009:04:23 07:21:35"`,
+ PixelXDimension: `2560`,
+ },
+ "2009-06-11-19-23-18-sep-2009-06-11-19-23-18a.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `606`,
+ ThumbJPEGInterchangeFormatLength: `7150`,
+ ExposureProgram: `1`,
+ ColorSpace: `65535`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `264`,
+ ExposureTime: `"1/4"`,
+ DateTimeDigitized: `"2009:06:11 19:23:18"`,
+ MeteringMode: `1`,
+ PixelXDimension: `1400`,
+ PixelYDimension: `2100`,
+ Model: `"Canon EOS DIGITAL REBEL XTi"`,
+ YResolution: `"3500000/10000"`,
+ Software: `"Adobe Photoshop CS3 Macintosh"`,
+ DateTime: `"2009:06:23 18:42:05"`,
+ ApertureValue: `"11257/1627"`,
+ ExposureBiasValue: `"0/1"`,
+ FocalLength: `"47/1"`,
+ Make: `"Canon"`,
+ Orientation: `1`,
+ XResolution: `"3500000/10000"`,
+ ISOSpeedRatings: `200`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2009:06:11 19:23:18"`,
+ Flash: `16`,
+ },
+ "2009-06-20-07-59-05-sep-2009-06-20-07-59-05a.jpg": map[FieldName]string{
+ DateTimeOriginal: `"2009:06:20 07:59:05"`,
+ Flash: `89`,
+ ExposureMode: `0`,
+ ExifVersion: `"0221"`,
+ ThumbJPEGInterchangeFormatLength: `4569`,
+ MaxApertureValue: `"36/10"`,
+ ColorSpace: `1`,
+ ExposureIndex: `"160/1"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `9032`,
+ ExposureTime: `"1/500"`,
+ MeteringMode: `5`,
+ GainControl: `2`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ InteroperabilityIndex: `"R98"`,
+ ExifIFDPointer: `514`,
+ ShutterSpeedValue: `"9/1"`,
+ Model: `"KODAK EASYSHARE Z710 ZOOM DIGITAL CAMERA"`,
+ Orientation: `1`,
+ XResolution: `"480/1"`,
+ ISOSpeedRatings: `160`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `8728`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/100"`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ FocalLengthIn35mmFilm: `337`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ FNumber: `"35/10"`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2009:06:20 07:59:05"`,
+ MakerNote: `""`,
+ PixelXDimension: `3072`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ ApertureValue: `"36/10"`,
+ ExposureBiasValue: `"0/3"`,
+ LightSource: `0`,
+ FocalLength: `"559/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2304`,
+ YResolution: `"480/1"`,
+ },
+ "2009-08-05-08-11-31-sep-2009-08-05-08-11-31a.jpg": map[FieldName]string{
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `100`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `1158`,
+ FocalPlaneYResolution: `"5292/1"`,
+ CustomRendered: `0`,
+ Make: `"FUJIFILM"`,
+ Orientation: `1`,
+ SceneCaptureType: `0`,
+ FileSource: `""`,
+ FNumber: `"400/100"`,
+ ExposureProgram: `2`,
+ DateTimeDigitized: `"2009:08:05 08:11:31"`,
+ MakerNote: `"FUJIFILM0130" !"#,012NORMAL d"`,
+ PixelXDimension: `2848`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ Copyright: `" "`,
+ ApertureValue: `"400/100"`,
+ ExposureBiasValue: `"0/100"`,
+ LightSource: `0`,
+ FocalLength: `"720/100"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ DateTime: `"2009:08:05 08:11:31"`,
+ PixelYDimension: `2136`,
+ FocalPlaneXResolution: `"5292/1"`,
+ Flash: `16`,
+ ExposureMode: `0`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2009:08:05 08:11:31"`,
+ MaxApertureValue: `"300/100"`,
+ ColorSpace: `1`,
+ WhiteBalance: `1`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `1306`,
+ ThumbJPEGInterchangeFormatLength: `8596`,
+ CompressedBitsPerPixel: `"20/10"`,
+ BrightnessValue: `"719/100"`,
+ MeteringMode: `5`,
+ SubjectDistanceRange: `0`,
+ InteroperabilityIndex: `"R98"`,
+ ExifIFDPointer: `294`,
+ ExposureTime: `"10/3000"`,
+ ShutterSpeedValue: `"820/100"`,
+ FocalPlaneResolutionUnit: `3`,
+ Model: `"FinePix E550 "`,
+ Software: `"Digital Camera FinePix E550 Ver1.00"`,
+ },
+ "2010-06-08-04-44-24-sep-2010-06-08-04-44-24a.jpg": map[FieldName]string{
+ CompressedBitsPerPixel: `"8/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ PixelXDimension: `2816`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2010:06:08 04:44:24"`,
+ Model: `"DSC-S600"`,
+ ExposureBiasValue: `"0/10"`,
+ PixelYDimension: `2112`,
+ ImageDescription: `" "`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `80`,
+ ExifVersion: `"0221"`,
+ Flash: `31`,
+ CustomRendered: `0`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormatLength: `4029`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"48/16"`,
+ ThumbJPEGInterchangeFormat: `6892`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `2314`,
+ ExposureTime: `"10/400"`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ DateTime: `"2010:06:08 04:44:24"`,
+ LightSource: `0`,
+ FocalLength: `"51/10"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"72/1"`,
+ DateTimeOriginal: `"2010:06:08 04:44:24"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `6640`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"SONY"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ FNumber: `"28/10"`,
+ },
+ "2010-06-20-20-07-39-sep-2010-06-20-20-07-39a.jpg": map[FieldName]string{
+ FocalPlaneYResolution: `"2736000/181"`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"3648/3648"`,
+ Orientation: `1`,
+ XResolution: `"4718592/65536"`,
+ ISOSpeedRatings: `800`,
+ ExifVersion: `"0220"`,
+ Flash: `16`,
+ ThumbJPEGInterchangeFormat: `3408`,
+ ThumbJPEGInterchangeFormatLength: `5126`,
+ MaxApertureValue: `"116/32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `302`,
+ ExposureTime: `"1/10"`,
+ FocalLength: `"9681/1000"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"3648000/241"`,
+ YResolution: `"4718592/65536"`,
+ Software: `"QuickTime 7.6.6"`,
+ DateTime: `"2010:10:31 22:39:25"`,
+ ShutterSpeedValue: `"106/32"`,
+ ApertureValue: `"116/32"`,
+ Make: `"Canon"`,
+ DateTimeOriginal: `"2010:06:20 20:07:39"`,
+ ComponentsConfiguration: `""`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ FNumber: `"35/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ PixelXDimension: `3648`,
+ SensingMethod: `2`,
+ DateTimeDigitized: `"2010:06:20 20:07:39"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ ImageDescription: `" "`,
+ Model: `"Canon PowerShot SD1200 IS"`,
+ ExposureBiasValue: `"0/3"`,
+ PixelYDimension: `2736`,
+ FocalPlaneResolutionUnit: `2`,
+ },
+ "2010-09-02-08-43-02-sep-2010-09-02-08-43-02a.jpg": map[FieldName]string{
+ DateTime: `"2010:09:02 08:43:02"`,
+ ExposureProgram: `5`,
+ ExifVersion: `"0221"`,
+ CompressedBitsPerPixel: `"1/1"`,
+ Flash: `65`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `800`,
+ MaxApertureValue: `"362/100"`,
+ LightSource: `0`,
+ FocalLength: `"210/10"`,
+ ColorSpace: `1`,
+ Model: `"FE370,X880,C575 "`,
+ ThumbJPEGInterchangeFormat: `9204`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/100"`,
+ SceneCaptureType: `3`,
+ GainControl: `2`,
+ Contrast: `0`,
+ DateTimeOriginal: `"2010:09:02 08:43:02"`,
+ MakerNote: `""`,
+ FNumber: `"53/10"`,
+ Sharpness: `0`,
+ ImageDescription: `"OLYMPUS DIGITAL CAMERA "`,
+ Software: `"Version 1.0 "`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `996`,
+ ExposureTime: `"10/500"`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `5`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ ExposureBiasValue: `"0/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2448`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `3562`,
+ UserComment: `" "`,
+ PixelXDimension: `3264`,
+ InteroperabilityIFDPointer: `1714`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"OLYMPUS IMAGING CORP. "`,
+ DateTimeDigitized: `"2010:09:02 08:43:02"`,
+ },
+ "2011-01-24-22-06-02-sep-2011-01-24-22-06-02a.jpg": map[FieldName]string{
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ ThumbJPEGInterchangeFormat: `25601`,
+ ThumbJPEGInterchangeFormatLength: `3385`,
+ ExifIFDPointer: `157`,
+ PixelXDimension: `1200`,
+ MakerNote: `""`,
+ DateTimeDigitized: `"2011:01:24 22:06:02"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ Software: `"V 12.40"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1600`,
+ Model: `"6350"`,
+ YResolution: `"300/1"`,
+ XResolution: `"300/1"`,
+ ExifVersion: `"0220"`,
+ ComponentsConfiguration: `""`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Nokia"`,
+ Orientation: `1`,
+ DigitalZoomRatio: `"1024/1024"`,
+ DateTimeOriginal: `"2011:01:24 22:06:02"`,
+ },
+ "2011-03-07-09-28-03-sep-2011-03-07-09-28-03a.jpg": map[FieldName]string{
+ Model: `"GU295"`,
+ Software: `"GU295-MSM1530032L-V10i-APR-22-2010-ATT-US"`,
+ Make: `"LG Elec."`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `538`,
+ CustomRendered: `1`,
+ DigitalZoomRatio: `"0/0"`,
+ Contrast: `0`,
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ DateTimeDigitized: `"2011:03:07 09:28:03"`,
+ PixelXDimension: `1280`,
+ SceneType: `""`,
+ YResolution: `"72/1"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `960`,
+ ExifVersion: `"0220"`,
+ DateTimeOriginal: `"2011:03:07 09:28:03"`,
+ ExposureMode: `0`,
+ ThumbJPEGInterchangeFormat: `662`,
+ ThumbJPEGInterchangeFormatLength: `9850`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ExifIFDPointer: `224`,
+ BrightnessValue: `"0/1024"`,
+ MeteringMode: `2`,
+ Saturation: `0`,
+ InteroperabilityIndex: `"R98"`,
+ },
+ "2011-05-07-13-02-49-sep-2011-05-07-13-02-49a.jpg": map[FieldName]string{
+ DateTimeOriginal: `"2011:05:07 13:02:49"`,
+ SceneType: `""`,
+ Contrast: `0`,
+ Software: `"M7500BSAAAAAAD3050"`,
+ GPSVersionID: `[2,2,0,0]`,
+ GPSLatitudeRef: `"N"`,
+ GPSAltitude: `"0/1"`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `218`,
+ GPSInfoIFDPointer: `502`,
+ ComponentsConfiguration: `""`,
+ GPSLongitudeRef: `"E"`,
+ GPSTimeStamp: `["19/1","3/1","43/1"]`,
+ GPSDateStamp: `"2011:05:07 "`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormatLength: `22806`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1536`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ GPSAltitudeRef: `0`,
+ Make: `"HTC"`,
+ DateTimeDigitized: `"2011:05:07 13:02:49"`,
+ PixelXDimension: `2048`,
+ InteroperabilityIFDPointer: `472`,
+ GPSLatitude: `["0/1","0/1","0/100"]`,
+ InteroperabilityIndex: `"R98"`,
+ GPSLongitude: `["0/1","0/1","0/100"]`,
+ XResolution: `"72/1"`,
+ ExifVersion: `"0220"`,
+ GPSProcessingMethod: `"ASCIIHYBRID-FIX"`,
+ Model: `"RAPH800"`,
+ ThumbJPEGInterchangeFormat: `920`,
+ ColorSpace: `1`,
+ GPSMapDatum: `"WGS-84"`,
+ },
+ "2011-08-07-19-22-57-sep-2011-08-07-19-22-57a.jpg": map[FieldName]string{
+ ResolutionUnit: `2`,
+ DateTimeDigitized: `"2011:08:07 19:22:57"`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ YResolution: `"300/1"`,
+ DateTime: `"2011:08:11 09:46:32"`,
+ ApertureValue: `"433985/100000"`,
+ ExposureBiasValue: `"2/6"`,
+ LightSource: `0`,
+ FocalLength: `"620/10"`,
+ ExifVersion: `"0221"`,
+ DateTimeOriginal: `"2011:08:07 19:22:57"`,
+ Flash: `7`,
+ ExposureMode: `0`,
+ ThumbJPEGInterchangeFormat: `802`,
+ ThumbJPEGInterchangeFormatLength: `9117`,
+ MaxApertureValue: `"43/10"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ExifIFDPointer: `186`,
+ ExposureTime: `"1/30"`,
+ MeteringMode: `2`,
+ GainControl: `1`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ Model: `"NIKON D200"`,
+ Software: `"Ver.1.00"`,
+ ShutterSpeedValue: `"4906891/1000000"`,
+ SubSecTimeOriginal: `"65"`,
+ SubSecTimeDigitized: `"65"`,
+ FocalLengthIn35mmFilm: `93`,
+ SceneCaptureType: `0`,
+ Make: `"NIKON CORPORATION"`,
+ XResolution: `"300/1"`,
+ ISOSpeedRatings: `400`,
+ CFAPattern: `""`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"1/1"`,
+ Contrast: `0`,
+ FNumber: `"45/10"`,
+ ExposureProgram: `3`,
+ SubjectDistance: `"63/100"`,
+ FileSource: `""`,
+ },
+ "2011-10-28-17-50-18-sep-2011-10-28-17-50-18a.jpg": map[FieldName]string{
+ SubSecTime: `"92"`,
+ CustomRendered: `0`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ UserComment: `""`,
+ DateTime: `"2011:11:08 07:27:55"`,
+ FNumber: `"4/1"`,
+ ExposureProgram: `2`,
+ SubSecTimeOriginal: `"92"`,
+ GPSVersionID: `[2,2,0,0]`,
+ Software: `"Adobe Photoshop CS4 Macintosh"`,
+ ExifIFDPointer: `364`,
+ ExposureTime: `"1/60"`,
+ ISOSpeedRatings: `800`,
+ ComponentsConfiguration: `""`,
+ XResolution: `"720000/10000"`,
+ ThumbJPEGInterchangeFormatLength: `6186`,
+ ShutterSpeedValue: `"393216/65536"`,
+ ExposureBiasValue: `"0/1"`,
+ FocalLength: `"34/1"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `864`,
+ FocalPlaneXResolution: `"5616000/1459"`,
+ Model: `"Canon EOS 5D Mark II"`,
+ DateTimeOriginal: `"2011:10:28 17:50:18"`,
+ DateTimeDigitized: `"2011:10:28 17:50:18"`,
+ PixelXDimension: `576`,
+ InteroperabilityIFDPointer: `1120`,
+ InteroperabilityIndex: `"R03"`,
+ Make: `"Canon"`,
+ FocalPlaneResolutionUnit: `2`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ GPSInfoIFDPointer: `1152`,
+ ExifVersion: `"0221"`,
+ MeteringMode: `5`,
+ Flash: `9`,
+ FocalPlaneYResolution: `"3744000/958"`,
+ Orientation: `1`,
+ ThumbJPEGInterchangeFormat: `1266`,
+ ApertureValue: `"262144/65536"`,
+ SubSecTimeDigitized: `"92"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `1`,
+ YResolution: `"720000/10000"`,
+ },
+ "2011-10-28-18-25-43-sep-2011-10-28-18-25-43.jpg": map[FieldName]string{
+ SubSecTimeOriginal: `"50"`,
+ DateTime: `"2011:10:28 18:25:43"`,
+ ISOSpeedRatings: `1250`,
+ ComponentsConfiguration: `""`,
+ Saturation: `0`,
+ XResolution: `"300/1"`,
+ ExposureTime: `"10/600"`,
+ ColorSpace: `1`,
+ ThumbJPEGInterchangeFormatLength: `3670`,
+ LightSource: `0`,
+ FocalLength: `"800/10"`,
+ CFAPattern: `""`,
+ DigitalZoomRatio: `"1/1"`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"NIKON CORPORATION"`,
+ DateTimeOriginal: `"2011:10:28 18:25:43"`,
+ InteroperabilityIFDPointer: `3604`,
+ Sharpness: `0`,
+ ExifVersion: `"0221"`,
+ MeteringMode: `5`,
+ Flash: `31`,
+ FocalLengthIn35mmFilm: `120`,
+ Orientation: `1`,
+ YCbCrPositioning: `2`,
+ SubSecTimeDigitized: `"50"`,
+ WhiteBalance: `0`,
+ ThumbJPEGInterchangeFormat: `3728`,
+ SensingMethod: `2`,
+ CustomRendered: `0`,
+ SubSecTime: `"50"`,
+ ExposureProgram: `0`,
+ Software: `"Ver.1.11 "`,
+ FNumber: `"56/10"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ ExifIFDPointer: `208`,
+ FileSource: `""`,
+ Model: `"NIKON D80"`,
+ ExposureBiasValue: `"0/6"`,
+ PixelYDimension: `537`,
+ GainControl: `2`,
+ DateTimeDigitized: `"2011:10:28 18:25:43"`,
+ PixelXDimension: `800`,
+ SceneType: `""`,
+ ImageUniqueID: `"7fa4f6d028df5f2fc1bad8102be81064"`,
+ SubjectDistanceRange: `0`,
+ ResolutionUnit: `2`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"300/1"`,
+ MaxApertureValue: `"50/10"`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ MakerNote: `""`,
+ UserComment: `"ASCII "`,
+ },
+ "2011-11-18-15-38-34-sep-Photo11181538.jpg": map[FieldName]string{
+ WhiteBalance: `0`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `642`,
+ FlashpixVersion: `"0100"`,
+ CustomRendered: `1`,
+ ExposureMode: `0`,
+ Contrast: `1`,
+ Software: `"M6290A-KPVMZL-2.6.0140T"`,
+ ExposureProgram: `2`,
+ Saturation: `0`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `204`,
+ ComponentsConfiguration: `""`,
+ PixelYDimension: `1200`,
+ FileSource: `""`,
+ Model: `"P2020"`,
+ ThumbJPEGInterchangeFormatLength: `12226`,
+ ColorSpace: `1`,
+ BrightnessValue: `"0/1024"`,
+ PixelXDimension: `1600`,
+ InteroperabilityIFDPointer: `518`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"0/0"`,
+ Make: `"PANTECH"`,
+ DateTimeOriginal: `"2011:11:18 15:38:34"`,
+ DateTimeDigitized: `"2011:11:18 15:38:34"`,
+ InteroperabilityIndex: `"R98"`,
+ Sharpness: `0`,
+ ExifVersion: `"0220"`,
+ MeteringMode: `2`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ },
+ "2012-06-02-10-12-28-sep-2012-06-02-10-12-28.jpg": map[FieldName]string{
+ YResolution: `"180/1"`,
+ Software: `"Ver.1.0 "`,
+ DateTime: `"2012:06:02 10:12:28"`,
+ LightSource: `0`,
+ FocalLength: `"50/10"`,
+ FlashpixVersion: `"0100"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ Make: `"Panasonic"`,
+ DateTimeOriginal: `"2012:06:02 10:12:28"`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `10506`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `28`,
+ FNumber: `"33/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ GainControl: `0`,
+ Saturation: `0`,
+ DateTimeDigitized: `"2012:06:02 10:12:28"`,
+ CompressedBitsPerPixel: `"4/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ PixelXDimension: `4608`,
+ SensingMethod: `2`,
+ Model: `"DMC-FH25"`,
+ ExposureBiasValue: `"0/100"`,
+ PixelYDimension: `3456`,
+ DigitalZoomRatio: `"0/10"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0230"`,
+ Flash: `16`,
+ CustomRendered: `0`,
+ ThumbJPEGInterchangeFormat: `11764`,
+ ThumbJPEGInterchangeFormatLength: `7486`,
+ ExposureProgram: `2`,
+ MaxApertureValue: `"441/128"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `636`,
+ ExposureTime: `"10/4000"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ },
+ "2012-09-21-22-07-34-sep-2012-09-21-22-07-34.jpg": map[FieldName]string{
+ ThumbJPEGInterchangeFormat: `5108`,
+ ThumbJPEGInterchangeFormatLength: `4855`,
+ MaxApertureValue: `"95/32"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ ExifIFDPointer: `240`,
+ ExposureTime: `"1/60"`,
+ CompressedBitsPerPixel: `"3/1"`,
+ MeteringMode: `5`,
+ UserComment: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ImageDescription: `" "`,
+ Model: `"Canon PowerShot SD940 IS"`,
+ ShutterSpeedValue: `"189/32"`,
+ FocalPlaneResolutionUnit: `2`,
+ CustomRendered: `0`,
+ Make: `"Canon"`,
+ Orientation: `1`,
+ XResolution: `"180/1"`,
+ ISOSpeedRatings: `500`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `3288`,
+ FocalPlaneYResolution: `"2448000/183"`,
+ DigitalZoomRatio: `"4000/4000"`,
+ SceneCaptureType: `2`,
+ FNumber: `"28/10"`,
+ FileSource: `""`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ DateTimeDigitized: `"2012:09:21 22:07:34"`,
+ MakerNote: `""`,
+ PixelXDimension: `3264`,
+ SensingMethod: `2`,
+ FocalPlaneXResolution: `"3264000/244"`,
+ YResolution: `"180/1"`,
+ DateTime: `"2012:09:21 22:07:34"`,
+ ApertureValue: `"95/32"`,
+ ExposureBiasValue: `"0/3"`,
+ FocalLength: `"5000/1000"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2448`,
+ ExifVersion: `"0221"`,
+ DateTimeOriginal: `"2012:09:21 22:07:34"`,
+ Flash: `25`,
+ ExposureMode: `0`,
+ },
+ "2012-12-19-21-38-40-sep-temple_square1.jpg": map[FieldName]string{
+ InteroperabilityIFDPointer: `322`,
+ GPSLatitude: `["40/1","46/1","1322/100"]`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"HTC"`,
+ DateTimeOriginal: `"2012:12:19 21:38:40"`,
+ DateTimeDigitized: `"2012:12:19 21:38:40"`,
+ PixelXDimension: `3264`,
+ GPSLatitudeRef: `"N"`,
+ GPSLongitude: `["111/1","53/1","2840/100"]`,
+ GPSLongitudeRef: `"W"`,
+ GPSProcessingMethod: `"ASCIIGPS"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ GPSInfoIFDPointer: `352`,
+ ExifVersion: `"0220"`,
+ GPSMapDatum: `"WGS-84"`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `696`,
+ FlashpixVersion: `"0100"`,
+ GPSAltitudeRef: `0`,
+ GPSVersionID: `[2,2,0]`,
+ GPSAltitude: `"1334/1"`,
+ GPSTimeStamp: `["4/1","38/1","40/1"]`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `136`,
+ ISOSpeedRatings: `801`,
+ ComponentsConfiguration: `""`,
+ PixelYDimension: `1952`,
+ GPSDateStamp: `"2012:12:20"`,
+ Model: `"ADR6400L"`,
+ ThumbJPEGInterchangeFormatLength: `38469`,
+ FocalLength: `"457/100"`,
+ ColorSpace: `1`,
+ },
+ "2012-12-21-11-15-19-sep-IMG_0001.jpg": map[FieldName]string{
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `360`,
+ ExposureTime: `"1/30"`,
+ InteroperabilityIndex: `"R98"`,
+ SubSecTimeDigitized: `"00"`,
+ FlashpixVersion: `"0100"`,
+ FocalPlaneXResolution: `"5184000/894"`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:12:21 11:15:19"`,
+ ShutterSpeedValue: `"327680/65536"`,
+ ApertureValue: `"286720/65536"`,
+ FocalLength: `"24/1"`,
+ LensModel: `"EF-S18-55mm f/3.5-5.6 IS II"`,
+ GPSVersionID: `[2,3,0,0]`,
+ InteroperabilityIFDPointer: `8806`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ Make: `"Canon"`,
+ GPSInfoIFDPointer: `9034`,
+ DateTimeOriginal: `"2012:12:21 11:15:19"`,
+ ComponentsConfiguration: `""`,
+ SubSecTime: `"00"`,
+ Artist: `""`,
+ FNumber: `"45/10"`,
+ ColorSpace: `1`,
+ WhiteBalance: `0`,
+ DateTimeDigitized: `"2012:12:21 11:15:19"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ UserComment: `""`,
+ PixelXDimension: `5184`,
+ FocalPlaneResolutionUnit: `2`,
+ Model: `"Canon EOS REBEL T4i"`,
+ Copyright: `""`,
+ ExposureBiasValue: `"0/1"`,
+ SubSecTimeOriginal: `"00"`,
+ PixelYDimension: `3456`,
+ FocalPlaneYResolution: `"3456000/597"`,
+ CustomRendered: `0`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ISOSpeedRatings: `1600`,
+ ExifVersion: `"0230"`,
+ Flash: `16`,
+ ThumbJPEGInterchangeFormat: `10924`,
+ ThumbJPEGInterchangeFormatLength: `14327`,
+ ExposureProgram: `0`,
+ },
+ "2013-02-05-23-12-09-sep-DSCI0001.jpg": map[FieldName]string{
+ ApertureValue: `"3072/1000"`,
+ ExposureBiasValue: `"0/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `1200`,
+ FileSource: `""`,
+ YResolution: `"288/3"`,
+ ThumbJPEGInterchangeFormatLength: `5863`,
+ ShutterSpeedValue: `"5907/1000"`,
+ WhiteBalance: `0`,
+ InteroperabilityIFDPointer: `4838`,
+ ExposureMode: `0`,
+ InteroperabilityIndex: `"R98"`,
+ Make: `"Polaroid"`,
+ DateTimeDigitized: `"2013:02:05 23:12:09"`,
+ PixelXDimension: `1600`,
+ DateTime: `"2013:02:05 23:12:09"`,
+ ExposureProgram: `2`,
+ CompressedBitsPerPixel: `"3766184/1920000"`,
+ Flash: `1`,
+ FocalLengthIn35mmFilm: `35`,
+ XResolution: `"288/3"`,
+ ISOSpeedRatings: `100`,
+ ExifVersion: `"0210"`,
+ MaxApertureValue: `"3072/1000"`,
+ LightSource: `0`,
+ FocalLength: `"5954/1000"`,
+ ColorSpace: `1`,
+ Model: `"Polaroid i532"`,
+ Copyright: `"Copyright 2005"`,
+ ThumbJPEGInterchangeFormat: `4974`,
+ SceneType: `""`,
+ DigitalZoomRatio: `"100/100"`,
+ SceneCaptureType: `0`,
+ DateTimeOriginal: `"2013:02:05 23:12:09"`,
+ MakerNote: `" BARCODE:A265KS008000; ZP:812; FP:124; AWB:235,679; PWB:476,304; PMF:12,11610; LV:493; LUM:3-8-9-8-1-11;20;26;19;10;A:1,F1:6,F2:18;ET:145, W:2, F:3 ;FV: 41FV: 36FV: 43FV: 223FV: 258FV: 9FV: 466FV: 216FP: 10FP: 8FP: 6FP: 6FP: 6FP: 0FP: 8FP: 8AFS: 110"`,
+ SensingMethod: `2`,
+ Sharpness: `0`,
+ ImageDescription: `""`,
+ Software: `" 1.0"`,
+ FNumber: `"28/10"`,
+ ExifIFDPointer: `240`,
+ ExposureTime: `"1/60"`,
+ ComponentsConfiguration: `""`,
+ MeteringMode: `3`,
+ Orientation: `1`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ },
+ "2099-08-12-19-59-29-sep-2099-08-12-19-59-29a.jpg": map[FieldName]string{
+ Model: `"NIKON D70s"`,
+ ExposureBiasValue: `"0/6"`,
+ SubSecTimeOriginal: `"00"`,
+ PixelYDimension: `2000`,
+ CFAPattern: `""`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"1/1"`,
+ Orientation: `1`,
+ XResolution: `"300/1"`,
+ ExifVersion: `"0221"`,
+ Flash: `31`,
+ ThumbJPEGInterchangeFormat: `28588`,
+ ThumbJPEGInterchangeFormatLength: `8886`,
+ ExposureProgram: `0`,
+ MaxApertureValue: `"36/10"`,
+ SceneType: `""`,
+ InteroperabilityIndex: `"R98"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `2`,
+ ExifIFDPointer: `216`,
+ ExposureTime: `"10/600"`,
+ FocalLength: `"180/10"`,
+ SubSecTimeDigitized: `"00"`,
+ FlashpixVersion: `"0100"`,
+ YResolution: `"300/1"`,
+ Software: `"Ver.1.00 "`,
+ DateTime: `"2099:08:12 19:59:29"`,
+ LightSource: `0`,
+ InteroperabilityIFDPointer: `28448`,
+ ExposureMode: `0`,
+ FocalLengthIn35mmFilm: `27`,
+ SceneCaptureType: `0`,
+ Make: `"NIKON CORPORATION"`,
+ DateTimeOriginal: `"2099:08:12 19:59:29"`,
+ ComponentsConfiguration: `""`,
+ SubSecTime: `"00"`,
+ Contrast: `1`,
+ Sharpness: `0`,
+ FNumber: `"35/10"`,
+ ColorSpace: `1`,
+ FileSource: `""`,
+ WhiteBalance: `0`,
+ UserComment: `"ASCII "`,
+ PixelXDimension: `3008`,
+ SensingMethod: `2`,
+ GainControl: `0`,
+ DateTimeDigitized: `"2099:08:12 19:59:29"`,
+ CompressedBitsPerPixel: `"2/1"`,
+ MeteringMode: `5`,
+ MakerNote: `""`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ },
+ "2216-11-15-11-46-51-sep-2216-11-15-11-46-51a.jpg": map[FieldName]string{
+ ExposureProgram: `2`,
+ FileSource: `""`,
+ FNumber: `"480/100"`,
+ YCbCrPositioning: `2`,
+ DateTimeDigitized: `"2216:11:15 11:46:51"`,
+ MakerNote: `""`,
+ PixelXDimension: `3296`,
+ SensingMethod: `2`,
+ SceneType: `""`,
+ ResolutionUnit: `2`,
+ ApertureValue: `"452/100"`,
+ ExposureBiasValue: `"0/10"`,
+ LightSource: `0`,
+ FocalLength: `"60/10"`,
+ FlashpixVersion: `"0100"`,
+ PixelYDimension: `2472`,
+ YResolution: `"480/1"`,
+ DateTimeOriginal: `"2216:11:15 11:46:51"`,
+ Flash: `24`,
+ ExposureMode: `0`,
+ ExifVersion: `"0221"`,
+ ThumbJPEGInterchangeFormatLength: `5175`,
+ MaxApertureValue: `"286/100"`,
+ ColorSpace: `1`,
+ ExposureIndex: `"80/1"`,
+ WhiteBalance: `0`,
+ Sharpness: `0`,
+ ThumbJPEGInterchangeFormat: `17818`,
+ ExposureTime: `"1016/1000000"`,
+ MeteringMode: `5`,
+ GainControl: `0`,
+ Saturation: `0`,
+ SubjectDistanceRange: `0`,
+ ExifIFDPointer: `2316`,
+ Software: `"KODAK EASYSHARE C813 ZOOM DIGITAL CAMERA"`,
+ ShutterSpeedValue: `"994/100"`,
+ Model: `"KODAK EASYSHARE C813 ZOOM DIGITAL CAMERA"`,
+ Orientation: `1`,
+ XResolution: `"480/1"`,
+ ISOSpeedRatings: `80`,
+ ComponentsConfiguration: `""`,
+ InteroperabilityIFDPointer: `17674`,
+ CustomRendered: `0`,
+ DigitalZoomRatio: `"0/10"`,
+ Make: `"EASTMAN KODAK COMPANY"`,
+ SceneCaptureType: `0`,
+ Contrast: `0`,
+ FocalLengthIn35mmFilm: `36`,
+ },
+ "FailedHash-NoDate-sep-remembory.jpg": map[FieldName]string{
+ Model: `"MFC-7840W"`,
+ YResolution: `"150/1"`,
+ Software: `"Apple Image Capture"`,
+ PixelYDimension: `1626`,
+ ExifIFDPointer: `192`,
+ PixelXDimension: `1232`,
+ Make: `"Brother"`,
+ Orientation: `1`,
+ XResolution: `"150/1"`,
+ ResolutionUnit: `2`,
+ },
+ "f1-exif.jpg": map[FieldName]string{
+ PixelXDimension: `0`,
+ Orientation: `1`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:02"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ },
+ "f2-exif.jpg": map[FieldName]string{
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `2`,
+ XResolution: `"72/1"`,
+ },
+ "f3-exif.jpg": map[FieldName]string{
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `3`,
+ XResolution: `"72/1"`,
+ },
+ "f4-exif.jpg": map[FieldName]string{
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `4`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ },
+ "f5-exif.jpg": map[FieldName]string{
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `5`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ },
+ "f6-exif.jpg": map[FieldName]string{
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `6`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ },
+ "f7-exif.jpg": map[FieldName]string{
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `7`,
+ XResolution: `"72/1"`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ },
+ "f8-exif.jpg": map[FieldName]string{
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ ExifIFDPointer: `134`,
+ ExifVersion: `"0210"`,
+ ComponentsConfiguration: `""`,
+ PixelXDimension: `0`,
+ Orientation: `8`,
+ XResolution: `"72/1"`,
+ FlashpixVersion: `"0100"`,
+ ColorSpace: `65535`,
+ PixelYDimension: `0`,
+ YResolution: `"72/1"`,
+ DateTime: `"2012:11:04 05:42:32"`,
+ },
+ "geodegrees_as_string.jpg": map[FieldName]string{
+ GPSAltitudeRef: `0`,
+ ThumbJPEGInterchangeFormat: `539`,
+ ThumbJPEGInterchangeFormatLength: `13132`,
+ WhiteBalance: `0`,
+ ExposureProgram: `0`,
+ Sharpness: `2`,
+ ExifIFDPointer: `114`,
+ ExposureTime: `"0/1024"`,
+ Saturation: `0`,
+ GPSLatitude: `"52,00000,50,00000,34,01180"`,
+ GPSTimeStamp: `"17,00000,8,00000,29,00000"`,
+ Model: `"HTC One_M8"`,
+ ApertureValue: `"2048/1024"`,
+ FocalLength: `"3072/1024"`,
+ GPSLatitudeRef: `"N"`,
+ GPSLongitude: `"11,00000,10,00000,58,28360"`,
+ GPSAltitude: `"0/1024"`,
+ GPSLongitudeRef: `"E"`,
+ GPSProcessingMethod: `"ASCII"`,
+ GPSInfoIFDPointer: `317`,
+ Make: `"HTC"`,
+ DateTimeOriginal: `"2014:04:26 19:09:19"`,
+ ISOSpeedRatings: `125`,
+ Contrast: `0`,
+ },
+ "has-lens-info.jpg": map[FieldName]string{
+ LensModel: `"iPhone 4S back camera 4.28mm f/2.4"`,
+ Model: `"iPhone 4S"`,
+ ThumbJPEGInterchangeFormatLength: `10875`,
+ ShutterSpeedValue: `"106906/10353"`,
+ FocalLength: `"107/25"`,
+ SubjectArea: `[1631,1223,881,881]`,
+ ColorSpace: `1`,
+ PixelYDimension: `2448`,
+ GPSLatitude: `["59/1","19/1","5717/100"]`,
+ Make: `"Apple"`,
+ DateTimeOriginal: `"2014:09:01 15:03:47"`,
+ DateTimeDigitized: `"2014:09:01 15:03:47"`,
+ BrightnessValue: `"3927/419"`,
+ PixelXDimension: `3264`,
+ SceneType: `""`,
+ LensMake: `"Apple"`,
+ GPSLatitudeRef: `"N"`,
+ GPSLongitude: `["18/1","3/1","5379/100"]`,
+ FocalLengthIn35mmFilm: `35`,
+ Orientation: `6`,
+ ResolutionUnit: `2`,
+ YCbCrPositioning: `1`,
+ GPSInfoIFDPointer: `948`,
+ ExifVersion: `"0221"`,
+ MeteringMode: `5`,
+ Flash: `16`,
+ GPSLongitudeRef: `"E"`,
+ YResolution: `"72/1"`,
+ ThumbJPEGInterchangeFormat: `1244`,
+ ApertureValue: `"4845/1918"`,
+ SubSecTimeDigitized: `"880"`,
+ FlashpixVersion: `"0100"`,
+ WhiteBalance: `0`,
+ GPSAltitudeRef: `0`,
+ MakerNote: `""`,
+ SensingMethod: `2`,
+ ExposureMode: `0`,
+ SceneCaptureType: `0`,
+ GPSImgDirection: `"18329/175"`,
+ Software: `"7.1.1"`,
+ DateTime: `"2014:09:01 15:03:47"`,
+ FNumber: `"12/5"`,
+ ExposureProgram: `2`,
+ SubSecTimeOriginal: `"880"`,
+ GPSImgDirectionRef: `"T"`,
+ XResolution: `"72/1"`,
+ ExifIFDPointer: `204`,
+ ExposureTime: `"1/1284"`,
+ ISOSpeedRatings: `50`,
+ ComponentsConfiguration: `""`,
+ GPSAltitude: `"29/1"`,
+ GPSTimeStamp: `["13/1","3/1","4279/100"]`,
+ },
+}
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2004-01-11-22-45-15-sep-2004-01-11-22-45-15a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2004-01-11-22-45-15-sep-2004-01-11-22-45-15a.jpg
new file mode 100644
index 000000000..6f3be2480
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2004-01-11-22-45-15-sep-2004-01-11-22-45-15a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-08-03-16-29-38-sep-2006-08-03-16-29-38a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-08-03-16-29-38-sep-2006-08-03-16-29-38a.jpg
new file mode 100644
index 000000000..39891df84
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-08-03-16-29-38-sep-2006-08-03-16-29-38a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-11-11-19-17-56-sep-2006-11-11-19-17-56a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-11-11-19-17-56-sep-2006-11-11-19-17-56a.jpg
new file mode 100644
index 000000000..4721e7542
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-11-11-19-17-56-sep-2006-11-11-19-17-56a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-10-23-58-20-sep-2006-12-10-23-58-20a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-10-23-58-20-sep-2006-12-10-23-58-20a.jpg
new file mode 100644
index 000000000..8c0997ea0
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-10-23-58-20-sep-2006-12-10-23-58-20a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-17-07-09-14-sep-2006-12-17-07-09-14a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-17-07-09-14-sep-2006-12-17-07-09-14a.jpg
new file mode 100644
index 000000000..1c6e7601d
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-17-07-09-14-sep-2006-12-17-07-09-14a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-21-15-55-26-sep-2006-12-21-15-55-26a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-21-15-55-26-sep-2006-12-21-15-55-26a.jpg
new file mode 100644
index 000000000..8aaf632be
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2006-12-21-15-55-26-sep-2006-12-21-15-55-26a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-01-12-00-00-sep-2007-01-01-12-00-00a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-01-12-00-00-sep-2007-01-01-12-00-00a.jpg
new file mode 100644
index 000000000..c44db32c1
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-01-12-00-00-sep-2007-01-01-12-00-00a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-17-21-49-44-sep-2007-01-17-21-49-44a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-17-21-49-44-sep-2007-01-17-21-49-44a.jpg
new file mode 100644
index 000000000..f025460d6
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-01-17-21-49-44-sep-2007-01-17-21-49-44a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-02-02-18-13-29-sep-2007-02-02-18-13-29a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-02-02-18-13-29-sep-2007-02-02-18-13-29a.jpg
new file mode 100644
index 000000000..3f1fbfbdf
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-02-02-18-13-29-sep-2007-02-02-18-13-29a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-02-17-02-21-sep-2007-05-02-17-02-21a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-02-17-02-21-sep-2007-05-02-17-02-21a.jpg
new file mode 100644
index 000000000..351935778
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-02-17-02-21-sep-2007-05-02-17-02-21a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-12-08-19-07-sep-2007-05-12-08-19-07a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-12-08-19-07-sep-2007-05-12-08-19-07a.jpg
new file mode 100644
index 000000000..175b60663
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-12-08-19-07-sep-2007-05-12-08-19-07a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-26-04-49-45-sep-2007-05-26-04-49-45a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-26-04-49-45-sep-2007-05-26-04-49-45a.jpg
new file mode 100644
index 000000000..90a6c92b0
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-26-04-49-45-sep-2007-05-26-04-49-45a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-30-14-28-01-sep-2007-05-30-14-28-01a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-30-14-28-01-sep-2007-05-30-14-28-01a.jpg
new file mode 100644
index 000000000..74f30c351
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-05-30-14-28-01-sep-2007-05-30-14-28-01a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-06-16-15-25-sep-2007-06-06-16-15-25a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-06-16-15-25-sep-2007-06-06-16-15-25a.jpg
new file mode 100644
index 000000000..0a025a0b8
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-06-16-15-25-sep-2007-06-06-16-15-25a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-26-10-13-04-sep-2007-06-26-10-13-04a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-26-10-13-04-sep-2007-06-26-10-13-04a.jpg
new file mode 100644
index 000000000..526cefafd
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-06-26-10-13-04-sep-2007-06-26-10-13-04a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-07-13-17-02-30-sep-2007-07-13-17-02-30a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-07-13-17-02-30-sep-2007-07-13-17-02-30a.jpg
new file mode 100644
index 000000000..c39e90fca
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-07-13-17-02-30-sep-2007-07-13-17-02-30a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-15-14-42-46-sep-2007-08-15-14-42-46a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-15-14-42-46-sep-2007-08-15-14-42-46a.jpg
new file mode 100644
index 000000000..81be2a200
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-15-14-42-46-sep-2007-08-15-14-42-46a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-24-02-40-42-sep-2007-08-24-02-40-42a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-24-02-40-42-sep-2007-08-24-02-40-42a.jpg
new file mode 100644
index 000000000..aa457643d
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-08-24-02-40-42-sep-2007-08-24-02-40-42a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-11-07-11-40-44-sep-2007-11-07-11-40-44a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-11-07-11-40-44-sep-2007-11-07-11-40-44a.jpg
new file mode 100644
index 000000000..916a2b6c3
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2007-11-07-11-40-44-sep-2007-11-07-11-40-44a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-02-10-03-57-sep-2008-06-02-10-03-57a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-02-10-03-57-sep-2008-06-02-10-03-57a.jpg
new file mode 100644
index 000000000..0aedf3003
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-02-10-03-57-sep-2008-06-02-10-03-57a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-06-13-29-29-sep-2008-06-06-13-29-29a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-06-13-29-29-sep-2008-06-06-13-29-29a.jpg
new file mode 100644
index 000000000..a291900e3
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-06-13-29-29-sep-2008-06-06-13-29-29a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-17-01-21-30-sep-2008-06-17-01-21-30a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-17-01-21-30-sep-2008-06-17-01-21-30a.jpg
new file mode 100644
index 000000000..805d1d0f0
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-06-17-01-21-30-sep-2008-06-17-01-21-30a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-09-02-17-43-48-sep-2008-09-02-17-43-48a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-09-02-17-43-48-sep-2008-09-02-17-43-48a.jpg
new file mode 100644
index 000000000..c866423c7
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2008-09-02-17-43-48-sep-2008-09-02-17-43-48a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-03-26-09-23-20-sep-2009-03-26-09-23-20a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-03-26-09-23-20-sep-2009-03-26-09-23-20a.jpg
new file mode 100644
index 000000000..761bf6488
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-03-26-09-23-20-sep-2009-03-26-09-23-20a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-11-03-01-38-sep-2009-04-11-03-01-38a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-11-03-01-38-sep-2009-04-11-03-01-38a.jpg
new file mode 100644
index 000000000..484fe3759
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-11-03-01-38-sep-2009-04-11-03-01-38a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-23-07-21-35-sep-2009-04-23-07-21-35a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-23-07-21-35-sep-2009-04-23-07-21-35a.jpg
new file mode 100644
index 000000000..f39db7d9a
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-04-23-07-21-35-sep-2009-04-23-07-21-35a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-11-19-23-18-sep-2009-06-11-19-23-18a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-11-19-23-18-sep-2009-06-11-19-23-18a.jpg
new file mode 100644
index 000000000..599764bf8
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-11-19-23-18-sep-2009-06-11-19-23-18a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-20-07-59-05-sep-2009-06-20-07-59-05a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-20-07-59-05-sep-2009-06-20-07-59-05a.jpg
new file mode 100644
index 000000000..8718269e9
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-06-20-07-59-05-sep-2009-06-20-07-59-05a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-08-05-08-11-31-sep-2009-08-05-08-11-31a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-08-05-08-11-31-sep-2009-08-05-08-11-31a.jpg
new file mode 100644
index 000000000..9598b2136
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2009-08-05-08-11-31-sep-2009-08-05-08-11-31a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-08-04-44-24-sep-2010-06-08-04-44-24a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-08-04-44-24-sep-2010-06-08-04-44-24a.jpg
new file mode 100644
index 000000000..33f7d9b20
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-08-04-44-24-sep-2010-06-08-04-44-24a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-20-20-07-39-sep-2010-06-20-20-07-39a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-20-20-07-39-sep-2010-06-20-20-07-39a.jpg
new file mode 100644
index 000000000..ec2faa1a9
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-06-20-20-07-39-sep-2010-06-20-20-07-39a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-09-02-08-43-02-sep-2010-09-02-08-43-02a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-09-02-08-43-02-sep-2010-09-02-08-43-02a.jpg
new file mode 100644
index 000000000..3b7f906db
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2010-09-02-08-43-02-sep-2010-09-02-08-43-02a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-01-24-22-06-02-sep-2011-01-24-22-06-02a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-01-24-22-06-02-sep-2011-01-24-22-06-02a.jpg
new file mode 100644
index 000000000..1a4af42d3
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-01-24-22-06-02-sep-2011-01-24-22-06-02a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-03-07-09-28-03-sep-2011-03-07-09-28-03a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-03-07-09-28-03-sep-2011-03-07-09-28-03a.jpg
new file mode 100644
index 000000000..42d347656
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-03-07-09-28-03-sep-2011-03-07-09-28-03a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-05-07-13-02-49-sep-2011-05-07-13-02-49a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-05-07-13-02-49-sep-2011-05-07-13-02-49a.jpg
new file mode 100644
index 000000000..7e84ec481
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-05-07-13-02-49-sep-2011-05-07-13-02-49a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-08-07-19-22-57-sep-2011-08-07-19-22-57a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-08-07-19-22-57-sep-2011-08-07-19-22-57a.jpg
new file mode 100644
index 000000000..16fad2ecb
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-08-07-19-22-57-sep-2011-08-07-19-22-57a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-17-50-18-sep-2011-10-28-17-50-18a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-17-50-18-sep-2011-10-28-17-50-18a.jpg
new file mode 100644
index 000000000..f6020a8c9
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-17-50-18-sep-2011-10-28-17-50-18a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-18-25-43-sep-2011-10-28-18-25-43.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-18-25-43-sep-2011-10-28-18-25-43.jpg
new file mode 100644
index 000000000..3aa541878
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-10-28-18-25-43-sep-2011-10-28-18-25-43.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-11-18-15-38-34-sep-Photo11181538.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-11-18-15-38-34-sep-Photo11181538.jpg
new file mode 100644
index 000000000..48ef933a2
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2011-11-18-15-38-34-sep-Photo11181538.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-06-02-10-12-28-sep-2012-06-02-10-12-28.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-06-02-10-12-28-sep-2012-06-02-10-12-28.jpg
new file mode 100644
index 000000000..f83270eee
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-06-02-10-12-28-sep-2012-06-02-10-12-28.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-09-21-22-07-34-sep-2012-09-21-22-07-34.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-09-21-22-07-34-sep-2012-09-21-22-07-34.jpg
new file mode 100644
index 000000000..5cdb55aac
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-09-21-22-07-34-sep-2012-09-21-22-07-34.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-19-21-38-40-sep-temple_square1.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-19-21-38-40-sep-temple_square1.jpg
new file mode 100644
index 000000000..4cc074f8e
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-19-21-38-40-sep-temple_square1.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-21-11-15-19-sep-IMG_0001.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-21-11-15-19-sep-IMG_0001.jpg
new file mode 100644
index 000000000..ba23c3c42
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2012-12-21-11-15-19-sep-IMG_0001.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2013-02-05-23-12-09-sep-DSCI0001.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2013-02-05-23-12-09-sep-DSCI0001.jpg
new file mode 100644
index 000000000..0396148af
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2013-02-05-23-12-09-sep-DSCI0001.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2099-08-12-19-59-29-sep-2099-08-12-19-59-29a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2099-08-12-19-59-29-sep-2099-08-12-19-59-29a.jpg
new file mode 100644
index 000000000..9729182b3
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2099-08-12-19-59-29-sep-2099-08-12-19-59-29a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/2216-11-15-11-46-51-sep-2216-11-15-11-46-51a.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/2216-11-15-11-46-51-sep-2216-11-15-11-46-51a.jpg
new file mode 100644
index 000000000..ae53a397a
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/2216-11-15-11-46-51-sep-2216-11-15-11-46-51a.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/FailedHash-NoDate-sep-remembory.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/FailedHash-NoDate-sep-remembory.jpg
new file mode 100644
index 000000000..9fb415124
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/FailedHash-NoDate-sep-remembory.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f1-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f1-exif.jpg
new file mode 100644
index 000000000..ff003e394
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f1-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f2-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f2-exif.jpg
new file mode 100644
index 000000000..7e0f170e3
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f2-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f3-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f3-exif.jpg
new file mode 100644
index 000000000..3ed7b16a7
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f3-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f4-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f4-exif.jpg
new file mode 100644
index 000000000..0e081f919
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f4-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f5-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f5-exif.jpg
new file mode 100644
index 000000000..e8d875479
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f5-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f6-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f6-exif.jpg
new file mode 100644
index 000000000..4e2c86415
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f6-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f7-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f7-exif.jpg
new file mode 100644
index 000000000..b5dddea44
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f7-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/f8-exif.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/f8-exif.jpg
new file mode 100644
index 000000000..fb050fc6d
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/f8-exif.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/geodegrees_as_string.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/geodegrees_as_string.jpg
new file mode 100644
index 000000000..280a70ec4
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/geodegrees_as_string.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exif/samples/has-lens-info.jpg b/vendor/github.com/rwcarlsen/goexif/exif/samples/has-lens-info.jpg
new file mode 100644
index 000000000..57757da33
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exif/samples/has-lens-info.jpg
Binary files differ
diff --git a/vendor/github.com/rwcarlsen/goexif/exifstat/main.go b/vendor/github.com/rwcarlsen/goexif/exifstat/main.go
new file mode 100644
index 000000000..0b383c9d5
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/exifstat/main.go
@@ -0,0 +1,60 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/mknote"
+ "github.com/rwcarlsen/goexif/tiff"
+)
+
+var mnote = flag.Bool("mknote", false, "try to parse makernote data")
+var thumb = flag.Bool("thumb", false, "dump thumbail data to stdout (for first listed image file)")
+
+func main() {
+ flag.Parse()
+ fnames := flag.Args()
+
+ if *mnote {
+ exif.RegisterParsers(mknote.All...)
+ }
+
+ for _, name := range fnames {
+ f, err := os.Open(name)
+ if err != nil {
+ log.Printf("err on %v: %v", name, err)
+ continue
+ }
+
+ x, err := exif.Decode(f)
+ if err != nil {
+ log.Printf("err on %v: %v", name, err)
+ continue
+ }
+
+ if *thumb {
+ data, err := x.JpegThumbnail()
+ if err != nil {
+ log.Fatal("no thumbnail present")
+ }
+ if _, err := os.Stdout.Write(data); err != nil {
+ log.Fatal(err)
+ }
+ return
+ }
+
+ fmt.Printf("\n---- Image '%v' ----\n", name)
+ x.Walk(Walker{})
+ }
+}
+
+type Walker struct{}
+
+func (_ Walker) Walk(name exif.FieldName, tag *tiff.Tag) error {
+ data, _ := tag.MarshalJSON()
+ fmt.Printf(" %v: %v\n", name, string(data))
+ return nil
+}
diff --git a/vendor/github.com/rwcarlsen/goexif/mknote/fields.go b/vendor/github.com/rwcarlsen/goexif/mknote/fields.go
new file mode 100644
index 000000000..e67d11c20
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/mknote/fields.go
@@ -0,0 +1,268 @@
+package mknote
+
+import "github.com/rwcarlsen/goexif/exif"
+
+// Useful resources used in creating these tables:
+// http://www.exiv2.org/makernote.html
+// http://www.exiv2.org/tags-canon.html
+// http://www.exiv2.org/tags-nikon.html
+
+// Known Maker Note fields
+const (
+ // common fields
+ ISOSpeed exif.FieldName = "ISOSpeed"
+ ColorMode = "ColorMode"
+ Quality = "Quality"
+ Sharpening = "Sharpening"
+ Focus = "Focus"
+ FlashSetting = "FlashSetting"
+ FlashDevice = "FlashDevice"
+ WhiteBalanceBias = "WhiteBalanceBias"
+ WB_RBLevels = "WB_RBLevels"
+ ProgramShift = "ProgramShift"
+ ExposureDiff = "ExposureDiff"
+ ISOSelection = "ISOSelection"
+ DataDump = "DataDump"
+ Preview = "Preview"
+ FlashComp = "FlashComp"
+ ISOSettings = "ISOSettings"
+ ImageBoundary = "ImageBoundary"
+ FlashExposureComp = "FlashExposureComp"
+ FlashBracketComp = "FlashBracketComp"
+ ExposureBracketComp = "ExposureBracketComp"
+ ImageProcessing = "ImageProcessing"
+ CropHiSpeed = "CropHiSpeed"
+ ExposureTuning = "ExposureTuning"
+ SerialNumber = "SerialNumber"
+ ImageAuthentication = "ImageAuthentication"
+ ActiveDLighting = "ActiveDLighting"
+ VignetteControl = "VignetteControl"
+ ImageAdjustment = "ImageAdjustment"
+ ToneComp = "ToneComp"
+ AuxiliaryLens = "AuxiliaryLens"
+ LensType = "LensType"
+ Lens = "Lens"
+ FocusDistance = "FocusDistance"
+ DigitalZoom = "DigitalZoom"
+ FlashMode = "FlashMode"
+ ShootingMode = "ShootingMode"
+ AutoBracketRelease = "AutoBracketRelease"
+ LensFStops = "LensFStops"
+ ContrastCurve = "ContrastCurve"
+ ColorHue = "ColorHue"
+ SceneMode = "SceneMode"
+ HueAdjustment = "HueAdjustment"
+ NEFCompression = "NEFCompression"
+ NoiseReduction = "NoiseReduction"
+ LinearizationTable = "LinearizationTable"
+ RawImageCenter = "RawImageCenter"
+ SensorPixelSize = "SensorPixelSize"
+ SceneAssist = "SceneAssist"
+ RetouchHistory = "RetouchHistory"
+ ImageDataSize = "ImageDataSize"
+ ImageCount = "ImageCount"
+ DeletedImageCount = "DeletedImageCount"
+ ShutterCount = "ShutterCount"
+ ImageOptimization = "ImageOptimization"
+ SaturationText = "SaturationText"
+ VariProgram = "VariProgram"
+ ImageStabilization = "ImageStabilization"
+ AFResponse = "AFResponse"
+ HighISONoiseReduction = "HighISONoiseReduction"
+ ToningEffect = "ToningEffect"
+ PrintIM = "PrintIM"
+ CaptureData = "CaptureData"
+ CaptureVersion = "CaptureVersion"
+ CaptureOffsets = "CaptureOffsets"
+ ScanIFD = "ScanIFD"
+ ICCProfile = "ICCProfile"
+ CaptureOutput = "CaptureOutput"
+ Panorama = "Panorama"
+ ImageType = "ImageType"
+ FirmwareVersion = "FirmwareVersion"
+ FileNumber = "FileNumber"
+ OwnerName = "OwnerName"
+ CameraInfo = "CameraInfo"
+ CustomFunctions = "CustomFunctions"
+ ModelID = "ModelID"
+ PictureInfo = "PictureInfo"
+ ThumbnailImageValidArea = "ThumbnailImageValidArea"
+ SerialNumberFormat = "SerialNumberFormat"
+ SuperMacro = "SuperMacro"
+ OriginalDecisionDataOffset = "OriginalDecisionDataOffset"
+ WhiteBalanceTable = "WhiteBalanceTable"
+ LensModel = "LensModel"
+ InternalSerialNumber = "InternalSerialNumber"
+ DustRemovalData = "DustRemovalData"
+ ProcessingInfo = "ProcessingInfo"
+ MeasuredColor = "MeasuredColor"
+ VRDOffset = "VRDOffset"
+ SensorInfo = "SensorInfo"
+ ColorData = "ColorData"
+
+ // Nikon-specific fields
+ Nikon_Version = "Nikon.Version"
+ Nikon_WhiteBalance = "Nikon.WhiteBalance"
+ Nikon_ColorSpace = "Nikon.ColorSpace"
+ Nikon_LightSource = "Nikon.LightSource"
+ Nikon_Saturation = "Nikon_Saturation"
+ Nikon_ShotInfo = "Nikon.ShotInfo" // A sub-IFD
+ Nikon_VRInfo = "Nikon.VRInfo" // A sub-IFD
+ Nikon_PictureControl = "Nikon.PictureControl" // A sub-IFD
+ Nikon_WorldTime = "Nikon.WorldTime" // A sub-IFD
+ Nikon_ISOInfo = "Nikon.ISOInfo" // A sub-IFD
+ Nikon_AFInfo = "Nikon.AFInfo" // A sub-IFD
+ Nikon_ColorBalance = "Nikon.ColorBalance" // A sub-IFD
+ Nikon_LensData = "Nikon.LensData" // A sub-IFD
+ Nikon_SerialNO = "Nikon.SerialNO" // usually starts with "NO="
+ Nikon_FlashInfo = "Nikon.FlashInfo" // A sub-IFD
+ Nikon_MultiExposure = "Nikon.MultiExposure" // A sub-IFD
+ Nikon_AFInfo2 = "Nikon.AFInfo2" // A sub-IFD
+ Nikon_FileInfo = "Nikon.FileInfo" // A sub-IFD
+ Nikon_AFTune = "Nikon.AFTune" // A sub-IFD
+ Nikon3_0x000a = "Nikon3.0x000a"
+ Nikon3_0x009b = "Nikon3.0x009b"
+ Nikon3_0x009f = "Nikon3.0x009f"
+ Nikon3_0x00a3 = "Nikon3.0x00a3"
+
+ // Canon-specific fiends
+ Canon_CameraSettings = "Canon.CameraSettings" // A sub-IFD
+ Canon_ShotInfo = "Canon.ShotInfo" // A sub-IFD
+ Canon_AFInfo = "Canon.AFInfo"
+ Canon_0x0000 = "Canon.0x0000"
+ Canon_0x0003 = "Canon.0x0003"
+ Canon_0x00b5 = "Canon.0x00b5"
+ Canon_0x00c0 = "Canon.0x00c0"
+ Canon_0x00c1 = "Canon.0x00c1"
+)
+
+var makerNoteCanonFields = map[uint16]exif.FieldName{
+ 0x0000: Canon_0x0000,
+ 0x0001: Canon_CameraSettings,
+ 0x0002: exif.FocalLength,
+ 0x0003: Canon_0x0003,
+ 0x0004: Canon_ShotInfo,
+ 0x0005: Panorama,
+ 0x0006: ImageType,
+ 0x0007: FirmwareVersion,
+ 0x0008: FileNumber,
+ 0x0009: OwnerName,
+ 0x000c: SerialNumber,
+ 0x000d: CameraInfo,
+ 0x000f: CustomFunctions,
+ 0x0010: ModelID,
+ 0x0012: PictureInfo,
+ 0x0013: ThumbnailImageValidArea,
+ 0x0015: SerialNumberFormat,
+ 0x001a: SuperMacro,
+ 0x0026: Canon_AFInfo,
+ 0x0083: OriginalDecisionDataOffset,
+ 0x00a4: WhiteBalanceTable,
+ 0x0095: LensModel,
+ 0x0096: InternalSerialNumber,
+ 0x0097: DustRemovalData,
+ 0x0099: CustomFunctions,
+ 0x00a0: ProcessingInfo,
+ 0x00aa: MeasuredColor,
+ 0x00b4: exif.ColorSpace,
+ 0x00b5: Canon_0x00b5,
+ 0x00c0: Canon_0x00c0,
+ 0x00c1: Canon_0x00c1,
+ 0x00d0: VRDOffset,
+ 0x00e0: SensorInfo,
+ 0x4001: ColorData,
+}
+
+// Nikon version 3 Maker Notes fields (used by E5400, SQ, D2H, D70, and newer)
+var makerNoteNikon3Fields = map[uint16]exif.FieldName{
+ 0x0001: Nikon_Version,
+ 0x0002: ISOSpeed,
+ 0x0003: ColorMode,
+ 0x0004: Quality,
+ 0x0005: Nikon_WhiteBalance,
+ 0x0006: Sharpening,
+ 0x0007: Focus,
+ 0x0008: FlashSetting,
+ 0x0009: FlashDevice,
+ 0x000a: Nikon3_0x000a,
+ 0x000b: WhiteBalanceBias,
+ 0x000c: WB_RBLevels,
+ 0x000d: ProgramShift,
+ 0x000e: ExposureDiff,
+ 0x000f: ISOSelection,
+ 0x0010: DataDump,
+ 0x0011: Preview,
+ 0x0012: FlashComp,
+ 0x0013: ISOSettings,
+ 0x0016: ImageBoundary,
+ 0x0017: FlashExposureComp,
+ 0x0018: FlashBracketComp,
+ 0x0019: ExposureBracketComp,
+ 0x001a: ImageProcessing,
+ 0x001b: CropHiSpeed,
+ 0x001c: ExposureTuning,
+ 0x001d: SerialNumber,
+ 0x001e: Nikon_ColorSpace,
+ 0x001f: Nikon_VRInfo,
+ 0x0020: ImageAuthentication,
+ 0x0022: ActiveDLighting,
+ 0x0023: Nikon_PictureControl,
+ 0x0024: Nikon_WorldTime,
+ 0x0025: Nikon_ISOInfo,
+ 0x002a: VignetteControl,
+ 0x0080: ImageAdjustment,
+ 0x0081: ToneComp,
+ 0x0082: AuxiliaryLens,
+ 0x0083: LensType,
+ 0x0084: Lens,
+ 0x0085: FocusDistance,
+ 0x0086: DigitalZoom,
+ 0x0087: FlashMode,
+ 0x0088: Nikon_AFInfo,
+ 0x0089: ShootingMode,
+ 0x008a: AutoBracketRelease,
+ 0x008b: LensFStops,
+ 0x008c: ContrastCurve,
+ 0x008d: ColorHue,
+ 0x008f: SceneMode,
+ 0x0090: Nikon_LightSource,
+ 0x0091: Nikon_ShotInfo,
+ 0x0092: HueAdjustment,
+ 0x0093: NEFCompression,
+ 0x0094: Nikon_Saturation,
+ 0x0095: NoiseReduction,
+ 0x0096: LinearizationTable,
+ 0x0097: Nikon_ColorBalance,
+ 0x0098: Nikon_LensData,
+ 0x0099: RawImageCenter,
+ 0x009a: SensorPixelSize,
+ 0x009b: Nikon3_0x009b,
+ 0x009c: SceneAssist,
+ 0x009e: RetouchHistory,
+ 0x009f: Nikon3_0x009f,
+ 0x00a0: Nikon_SerialNO,
+ 0x00a2: ImageDataSize,
+ 0x00a3: Nikon3_0x00a3,
+ 0x00a5: ImageCount,
+ 0x00a6: DeletedImageCount,
+ 0x00a7: ShutterCount,
+ 0x00a8: Nikon_FlashInfo,
+ 0x00a9: ImageOptimization,
+ 0x00aa: SaturationText,
+ 0x00ab: VariProgram,
+ 0x00ac: ImageStabilization,
+ 0x00ad: AFResponse,
+ 0x00b0: Nikon_MultiExposure,
+ 0x00b1: HighISONoiseReduction,
+ 0x00b3: ToningEffect,
+ 0x00b7: Nikon_AFInfo2,
+ 0x00b8: Nikon_FileInfo,
+ 0x00b9: Nikon_AFTune,
+ 0x0e00: PrintIM,
+ 0x0e01: CaptureData,
+ 0x0e09: CaptureVersion,
+ 0x0e0e: CaptureOffsets,
+ 0x0e10: ScanIFD,
+ 0x0e1d: ICCProfile,
+ 0x0e1e: CaptureOutput,
+}
diff --git a/vendor/github.com/rwcarlsen/goexif/mknote/mknote.go b/vendor/github.com/rwcarlsen/goexif/mknote/mknote.go
new file mode 100644
index 000000000..1e6021621
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/mknote/mknote.go
@@ -0,0 +1,70 @@
+// Package mknote provides makernote parsers that can be used with goexif/exif.
+package mknote
+
+import (
+ "bytes"
+
+ "github.com/rwcarlsen/goexif/exif"
+ "github.com/rwcarlsen/goexif/tiff"
+)
+
+var (
+ // Canon is an exif.Parser for canon makernote data.
+ Canon = &canon{}
+ // NikonV3 is an exif.Parser for nikon makernote data.
+ NikonV3 = &nikonV3{}
+ // All is a list of all available makernote parsers
+ All = []exif.Parser{Canon, NikonV3}
+)
+
+type canon struct{}
+
+// Parse decodes all Canon makernote data found in x and adds it to x.
+func (_ *canon) Parse(x *exif.Exif) error {
+ m, err := x.Get(exif.MakerNote)
+ if err != nil {
+ return nil
+ }
+
+ mk, err := x.Get(exif.Make)
+ if err != nil {
+ return nil
+ }
+
+ if val, err := mk.StringVal(); err != nil || val != "Canon" {
+ return nil
+ }
+
+ // Canon notes are a single IFD directory with no header.
+ // Reader offsets need to be w.r.t. the original tiff structure.
+ buf := bytes.NewReader(append(make([]byte, m.ValOffset), m.Val...))
+ buf.Seek(int64(m.ValOffset), 0)
+
+ mkNotesDir, _, err := tiff.DecodeDir(buf, x.Tiff.Order)
+ if err != nil {
+ return err
+ }
+ x.LoadTags(mkNotesDir, makerNoteCanonFields, false)
+ return nil
+}
+
+type nikonV3 struct{}
+
+// Parse decodes all Nikon makernote data found in x and adds it to x.
+func (_ *nikonV3) Parse(x *exif.Exif) error {
+ m, err := x.Get(exif.MakerNote)
+ if err != nil {
+ return nil
+ } else if bytes.Compare(m.Val[:6], []byte("Nikon\000")) != 0 {
+ return nil
+ }
+
+ // Nikon v3 maker note is a self-contained IFD (offsets are relative
+ // to the start of the maker note)
+ mkNotes, err := tiff.Decode(bytes.NewReader(m.Val[10:]))
+ if err != nil {
+ return err
+ }
+ x.LoadTags(mkNotes.Dirs[0], makerNoteNikon3Fields, false)
+ return nil
+}
diff --git a/vendor/github.com/rwcarlsen/goexif/tiff/tiff_test.go b/vendor/github.com/rwcarlsen/goexif/tiff/tiff_test.go
new file mode 100644
index 000000000..5db348dc8
--- /dev/null
+++ b/vendor/github.com/rwcarlsen/goexif/tiff/tiff_test.go
@@ -0,0 +1,235 @@
+package tiff
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "flag"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+var dataDir = flag.String("test_data_dir", ".", "Directory where the data files for testing are located")
+
+type input struct {
+ tgId string
+ tpe string
+ nVals string
+ offset string
+ val string
+}
+
+type output struct {
+ id uint16
+ typ DataType
+ count uint32
+ val []byte
+}
+
+type tagTest struct {
+ big input // big endian
+ little input // little endian
+ out output
+}
+
+///////////////////////////////////////////////
+//// Big endian Tests /////////////////////////
+///////////////////////////////////////////////
+var set1 = []tagTest{
+ //////////// string type //////////////
+ tagTest{
+ // {"TgId", "TYPE", "N-VALUES", "OFFSET--", "VAL..."},
+ input{"0003", "0002", "00000002", "11000000", ""},
+ input{"0300", "0200", "02000000", "11000000", ""},
+ output{0x0003, DataType(0x0002), 0x0002, []byte{0x11, 0x00}},
+ },
+ tagTest{
+ input{"0001", "0002", "00000006", "00000012", "111213141516"},
+ input{"0100", "0200", "06000000", "12000000", "111213141516"},
+ output{0x0001, DataType(0x0002), 0x0006, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}},
+ },
+ //////////// int (1-byte) type ////////////////
+ tagTest{
+ input{"0001", "0001", "00000001", "11000000", ""},
+ input{"0100", "0100", "01000000", "11000000", ""},
+ output{0x0001, DataType(0x0001), 0x0001, []byte{0x11}},
+ },
+ tagTest{
+ input{"0001", "0001", "00000005", "00000010", "1112131415"},
+ input{"0100", "0100", "05000000", "10000000", "1112131415"},
+ output{0x0001, DataType(0x0001), 0x0005, []byte{0x11, 0x12, 0x13, 0x14, 0x15}},
+ },
+ tagTest{
+ input{"0001", "0006", "00000001", "11000000", ""},
+ input{"0100", "0600", "01000000", "11000000", ""},
+ output{0x0001, DataType(0x0006), 0x0001, []byte{0x11}},
+ },
+ tagTest{
+ input{"0001", "0006", "00000005", "00000010", "1112131415"},
+ input{"0100", "0600", "05000000", "10000000", "1112131415"},
+ output{0x0001, DataType(0x0006), 0x0005, []byte{0x11, 0x12, 0x13, 0x14, 0x15}},
+ },
+ //////////// int (2-byte) types ////////////////
+ tagTest{
+ input{"0001", "0003", "00000002", "11111212", ""},
+ input{"0100", "0300", "02000000", "11111212", ""},
+ output{0x0001, DataType(0x0003), 0x0002, []byte{0x11, 0x11, 0x12, 0x12}},
+ },
+ tagTest{
+ input{"0001", "0003", "00000003", "00000010", "111213141516"},
+ input{"0100", "0300", "03000000", "10000000", "111213141516"},
+ output{0x0001, DataType(0x0003), 0x0003, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}},
+ },
+ tagTest{
+ input{"0001", "0008", "00000001", "11120000", ""},
+ input{"0100", "0800", "01000000", "11120000", ""},
+ output{0x0001, DataType(0x0008), 0x0001, []byte{0x11, 0x12}},
+ },
+ tagTest{
+ input{"0001", "0008", "00000003", "00000100", "111213141516"},
+ input{"0100", "0800", "03000000", "00100000", "111213141516"},
+ output{0x0001, DataType(0x0008), 0x0003, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}},
+ },
+ //////////// int (4-byte) types ////////////////
+ tagTest{
+ input{"0001", "0004", "00000001", "11121314", ""},
+ input{"0100", "0400", "01000000", "11121314", ""},
+ output{0x0001, DataType(0x0004), 0x0001, []byte{0x11, 0x12, 0x13, 0x14}},
+ },
+ tagTest{
+ input{"0001", "0004", "00000002", "00000010", "1112131415161718"},
+ input{"0100", "0400", "02000000", "10000000", "1112131415161718"},
+ output{0x0001, DataType(0x0004), 0x0002, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}},
+ },
+ tagTest{
+ input{"0001", "0009", "00000001", "11121314", ""},
+ input{"0100", "0900", "01000000", "11121314", ""},
+ output{0x0001, DataType(0x0009), 0x0001, []byte{0x11, 0x12, 0x13, 0x14}},
+ },
+ tagTest{
+ input{"0001", "0009", "00000002", "00000011", "1112131415161819"},
+ input{"0100", "0900", "02000000", "11000000", "1112131415161819"},
+ output{0x0001, DataType(0x0009), 0x0002, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19}},
+ },
+ //////////// rational types ////////////////////
+ tagTest{
+ input{"0001", "0005", "00000001", "00000010", "1112131415161718"},
+ input{"0100", "0500", "01000000", "10000000", "1112131415161718"},
+ output{0x0001, DataType(0x0005), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}},
+ },
+ tagTest{
+ input{"0001", "000A", "00000001", "00000011", "1112131415161819"},
+ input{"0100", "0A00", "01000000", "11000000", "1112131415161819"},
+ output{0x0001, DataType(0x000A), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19}},
+ },
+ //////////// float types ///////////////////////
+ tagTest{
+ input{"0001", "0005", "00000001", "00000010", "1112131415161718"},
+ input{"0100", "0500", "01000000", "10000000", "1112131415161718"},
+ output{0x0001, DataType(0x0005), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}},
+ },
+ tagTest{
+ input{"0101", "000A", "00000001", "00000011", "1112131415161819"},
+ input{"0101", "0A00", "01000000", "11000000", "1112131415161819"},
+ output{0x0101, DataType(0x000A), 0x0001, []byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x18, 0x19}},
+ },
+}
+
+func TestDecodeTag(t *testing.T) {
+ for i, tst := range set1 {
+ testSingle(t, binary.BigEndian, tst.big, tst.out, i)
+ testSingle(t, binary.LittleEndian, tst.little, tst.out, i)
+ }
+}
+
+func testSingle(t *testing.T, order binary.ByteOrder, in input, out output, i int) {
+ data := buildInput(in, order)
+ buf := bytes.NewReader(data)
+ tg, err := DecodeTag(buf, order)
+ if err != nil {
+ t.Errorf("(%v) tag %v%+v decode failed: %v", order, i, in, err)
+ return
+ }
+
+ if tg.Id != out.id {
+ t.Errorf("(%v) tag %v id decode: expected %v, got %v", order, i, out.id, tg.Id)
+ }
+ if tg.Type != out.typ {
+ t.Errorf("(%v) tag %v type decode: expected %v, got %v", order, i, out.typ, tg.Type)
+ }
+ if tg.Count != out.count {
+ t.Errorf("(%v) tag %v component count decode: expected %v, got %v", order, i, out.count, tg.Count)
+ }
+ if !bytes.Equal(tg.Val, out.val) {
+ t.Errorf("(%v) tag %v value decode: expected %v, got %v", order, i, out.val, tg.Val)
+ }
+}
+
+// buildInputBig creates a byte-slice based on big-endian ordered input
+func buildInput(in input, order binary.ByteOrder) []byte {
+ data := make([]byte, 0)
+ d, _ := hex.DecodeString(in.tgId)
+ data = append(data, d...)
+ d, _ = hex.DecodeString(in.tpe)
+ data = append(data, d...)
+ d, _ = hex.DecodeString(in.nVals)
+ data = append(data, d...)
+ d, _ = hex.DecodeString(in.offset)
+ data = append(data, d...)
+
+ if in.val != "" {
+ off := order.Uint32(d)
+ for i := 0; i < int(off)-12; i++ {
+ data = append(data, 0xFF)
+ }
+
+ d, _ = hex.DecodeString(in.val)
+ data = append(data, d...)
+ }
+
+ return data
+}
+
+func TestDecode(t *testing.T) {
+ name := filepath.Join(*dataDir, "sample1.tif")
+ f, err := os.Open(name)
+ if err != nil {
+ t.Fatalf("%v\n", err)
+ }
+
+ tif, err := Decode(f)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Log(tif)
+}
+
+func TestDecodeTag_blob(t *testing.T) {
+ buf := bytes.NewReader(data())
+ buf.Seek(10, 1)
+ tg, err := DecodeTag(buf, binary.LittleEndian)
+ if err != nil {
+ t.Fatalf("tag decode failed: %v", err)
+ }
+
+ t.Logf("tag: %v+\n", tg)
+ n, d, err := tg.Rat2(0)
+ if err != nil {
+ t.Fatalf("tag decoded wrong type: %v", err)
+ }
+ t.Logf("tag rat val: %v/%v\n", n, d)
+}
+
+func data() []byte {
+ s1 := "49492A000800000002001A0105000100"
+ s1 += "00002600000069870400010000001102"
+ s1 += "0000000000004800000001000000"
+
+ dat, err := hex.DecodeString(s1)
+ if err != nil {
+ panic("invalid string fixture")
+ }
+ return dat
+}
diff --git a/vendor/github.com/vaughan0/go-ini/ini_linux_test.go b/vendor/github.com/vaughan0/go-ini/ini_linux_test.go
new file mode 100644
index 000000000..38a6f0004
--- /dev/null
+++ b/vendor/github.com/vaughan0/go-ini/ini_linux_test.go
@@ -0,0 +1,43 @@
+package ini
+
+import (
+ "reflect"
+ "syscall"
+ "testing"
+)
+
+func TestLoadFile(t *testing.T) {
+ originalOpenFiles := numFilesOpen(t)
+
+ file, err := LoadFile("test.ini")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if originalOpenFiles != numFilesOpen(t) {
+ t.Error("test.ini not closed")
+ }
+
+ if !reflect.DeepEqual(file, File{"default": {"stuff": "things"}}) {
+ t.Error("file not read correctly")
+ }
+}
+
+func numFilesOpen(t *testing.T) (num uint64) {
+ var rlimit syscall.Rlimit
+ err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatal(err)
+ }
+ maxFds := int(rlimit.Cur)
+
+ var stat syscall.Stat_t
+ for i := 0; i < maxFds; i++ {
+ if syscall.Fstat(i, &stat) == nil {
+ num++
+ } else {
+ return
+ }
+ }
+ return
+}
diff --git a/vendor/github.com/vaughan0/go-ini/ini_test.go b/vendor/github.com/vaughan0/go-ini/ini_test.go
new file mode 100644
index 000000000..06a4d05ea
--- /dev/null
+++ b/vendor/github.com/vaughan0/go-ini/ini_test.go
@@ -0,0 +1,89 @@
+package ini
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+func TestLoad(t *testing.T) {
+ src := `
+ # Comments are ignored
+
+ herp = derp
+
+ [foo]
+ hello=world
+ whitespace should = not matter
+ ; sneaky semicolon-style comment
+ multiple = equals = signs
+
+ [bar]
+ this = that`
+
+ file, err := Load(strings.NewReader(src))
+ if err != nil {
+ t.Fatal(err)
+ }
+ check := func(section, key, expect string) {
+ if value, _ := file.Get(section, key); value != expect {
+ t.Errorf("Get(%q, %q): expected %q, got %q", section, key, expect, value)
+ }
+ }
+
+ check("", "herp", "derp")
+ check("foo", "hello", "world")
+ check("foo", "whitespace should", "not matter")
+ check("foo", "multiple", "equals = signs")
+ check("bar", "this", "that")
+}
+
+func TestSyntaxError(t *testing.T) {
+ src := `
+ # Line 2
+ [foo]
+ bar = baz
+ # Here's an error on line 6:
+ wut?
+ herp = derp`
+ _, err := Load(strings.NewReader(src))
+ t.Logf("%T: %v", err, err)
+ if err == nil {
+ t.Fatal("expected an error, got nil")
+ }
+ syntaxErr, ok := err.(ErrSyntax)
+ if !ok {
+ t.Fatal("expected an error of type ErrSyntax")
+ }
+ if syntaxErr.Line != 6 {
+ t.Fatal("incorrect line number")
+ }
+ if syntaxErr.Source != "wut?" {
+ t.Fatal("incorrect source")
+ }
+}
+
+func TestDefinedSectionBehaviour(t *testing.T) {
+ check := func(src string, expect File) {
+ file, err := Load(strings.NewReader(src))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(file, expect) {
+ t.Errorf("expected %v, got %v", expect, file)
+ }
+ }
+ // No sections for an empty file
+ check("", File{})
+ // Default section only if there are actually values for it
+ check("foo=bar", File{"": {"foo": "bar"}})
+ // User-defined sections should always be present, even if empty
+ check("[a]\n[b]\nfoo=bar", File{
+ "a": {},
+ "b": {"foo": "bar"},
+ })
+ check("foo=bar\n[a]\nthis=that", File{
+ "": {"foo": "bar"},
+ "a": {"this": "that"},
+ })
+}
diff --git a/vendor/golang.org/x/crypto/.gitattributes b/vendor/golang.org/x/crypto/.gitattributes
new file mode 100644
index 000000000..d2f212e5d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/.gitattributes
@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text
diff --git a/vendor/golang.org/x/crypto/.gitignore b/vendor/golang.org/x/crypto/.gitignore
new file mode 100644
index 000000000..8339fd61d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/.gitignore
@@ -0,0 +1,2 @@
+# Add no patterns to .hgignore except for files generated by the build.
+last-change
diff --git a/vendor/golang.org/x/crypto/AUTHORS b/vendor/golang.org/x/crypto/AUTHORS
new file mode 100644
index 000000000..15167cd74
--- /dev/null
+++ b/vendor/golang.org/x/crypto/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/vendor/golang.org/x/crypto/CONTRIBUTING.md b/vendor/golang.org/x/crypto/CONTRIBUTING.md
new file mode 100644
index 000000000..88dff59bc
--- /dev/null
+++ b/vendor/golang.org/x/crypto/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+
+## Filing issues
+
+When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
+
+1. What version of Go are you using (`go version`)?
+2. What operating system and processor architecture are you using?
+3. What did you do?
+4. What did you expect to see?
+5. What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+**We do not accept GitHub pull requests**
+(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.
+
diff --git a/vendor/golang.org/x/crypto/CONTRIBUTORS b/vendor/golang.org/x/crypto/CONTRIBUTORS
new file mode 100644
index 000000000..1c4577e96
--- /dev/null
+++ b/vendor/golang.org/x/crypto/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/vendor/golang.org/x/crypto/README b/vendor/golang.org/x/crypto/README
new file mode 100644
index 000000000..f1e0cbf94
--- /dev/null
+++ b/vendor/golang.org/x/crypto/README
@@ -0,0 +1,3 @@
+This repository holds supplementary Go cryptography libraries.
+
+To submit changes to this repository, see http://golang.org/doc/contribute.html.
diff --git a/vendor/golang.org/x/crypto/acme/internal/acme/acme.go b/vendor/golang.org/x/crypto/acme/internal/acme/acme.go
new file mode 100644
index 000000000..2732999f3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/internal/acme/acme.go
@@ -0,0 +1,473 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package acme provides an ACME client implementation.
+// See https://ietf-wg-acme.github.io/acme/ for details.
+//
+// This package is a work in progress and makes no API stability promises.
+package acme
+
+import (
+ "bytes"
+ "crypto/rsa"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "strconv"
+ "strings"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+// Client is an ACME client.
+type Client struct {
+ // HTTPClient optionally specifies an HTTP client to use
+ // instead of http.DefaultClient.
+ HTTPClient *http.Client
+
+ // Key is the account key used to register with a CA
+ // and sign requests.
+ Key *rsa.PrivateKey
+}
+
+// Discover performs ACME server discovery using the provided discovery endpoint URL.
+func (c *Client) Discover(url string) (*Directory, error) {
+ res, err := c.httpClient().Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return nil, responseError(res)
+ }
+ var v struct {
+ Reg string `json:"new-reg"`
+ Authz string `json:"new-authz"`
+ Cert string `json:"new-cert"`
+ Revoke string `json:"revoke-cert"`
+ Meta struct {
+ Terms string `json:"terms-of-service"`
+ Website string `json:"website"`
+ CAA []string `json:"caa-identities"`
+ }
+ }
+ if json.NewDecoder(res.Body).Decode(&v); err != nil {
+ return nil, err
+ }
+ return &Directory{
+ RegURL: v.Reg,
+ AuthzURL: v.Authz,
+ CertURL: v.Cert,
+ RevokeURL: v.Revoke,
+ Terms: v.Meta.Terms,
+ Website: v.Meta.Website,
+ CAA: v.Meta.CAA,
+ }, nil
+}
+
+// CreateCert requests a new certificate.
+// In the case where CA server does not provide the issued certificate in the response,
+// CreateCert will poll certURL using c.FetchCert, which will result in additional round-trips.
+// In such scenario the caller can cancel the polling with ctx.
+//
+// If the bundle is true, the returned value will also contain CA (the issuer) certificate.
+// The url argument is an Directory.CertURL value, typically obtained from c.Discover.
+// The csr is a DER encoded certificate signing request.
+func (c *Client) CreateCert(ctx context.Context, url string, csr []byte, exp time.Duration, bundle bool) (der [][]byte, certURL string, err error) {
+ req := struct {
+ Resource string `json:"resource"`
+ CSR string `json:"csr"`
+ NotBefore string `json:"notBefore,omitempty"`
+ NotAfter string `json:"notAfter,omitempty"`
+ }{
+ Resource: "new-cert",
+ CSR: base64.RawURLEncoding.EncodeToString(csr),
+ }
+ now := timeNow()
+ req.NotBefore = now.Format(time.RFC3339)
+ if exp > 0 {
+ req.NotAfter = now.Add(exp).Format(time.RFC3339)
+ }
+
+ res, err := c.postJWS(url, req)
+ if err != nil {
+ return nil, "", err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusCreated {
+ return nil, "", responseError(res)
+ }
+
+ curl := res.Header.Get("location") // cert permanent URL
+ if res.ContentLength == 0 {
+ // no cert in the body; poll until we get it
+ cert, err := c.FetchCert(ctx, curl, bundle)
+ return cert, curl, err
+ }
+ // slurp issued cert and ca, if requested
+ cert, err := responseCert(c.httpClient(), res, bundle)
+ return cert, curl, err
+}
+
+// FetchCert retrieves already issued certificate from the given url, in DER format.
+// It retries the request until the certificate is successfully retrieved,
+// context is cancelled by the caller or an error response is received.
+//
+// The returned value will also contain CA (the issuer) certificate if bundle == true.
+//
+// http.DefaultClient is used if client argument is nil.
+func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]byte, error) {
+ for {
+ res, err := c.httpClient().Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode == http.StatusOK {
+ return responseCert(c.httpClient(), res, bundle)
+ }
+ if res.StatusCode > 299 {
+ return nil, responseError(res)
+ }
+ d, err := retryAfter(res.Header.Get("retry-after"))
+ if err != nil {
+ d = 3 * time.Second
+ }
+ select {
+ case <-time.After(d):
+ // retry
+ case <-ctx.Done():
+ return nil, ctx.Err()
+ }
+ }
+}
+
+// Register creates a new account registration by following the "new-reg" flow.
+// It returns registered account. The a argument is not modified.
+//
+// The url argument is typically an Directory.RegURL obtained from c.Discover.
+func (c *Client) Register(url string, a *Account) (*Account, error) {
+ return c.doReg(url, "new-reg", a)
+}
+
+// GetReg retrieves an existing registration.
+// The url argument is an Account.URI, typically obtained from c.Register.
+func (c *Client) GetReg(url string) (*Account, error) {
+ a := &Account{URI: url}
+ return c.doReg(url, "reg", a)
+}
+
+// UpdateReg updates an existing registration.
+// It returns an updated account copy. The provided account is not modified.
+//
+// The url argument is an Account.URI, usually obtained with c.Register.
+func (c *Client) UpdateReg(url string, a *Account) (*Account, error) {
+ return c.doReg(url, "reg", a)
+}
+
+// Authorize performs the initial step in an authorization flow.
+// The caller will then need to choose from and perform a set of returned
+// challenges using c.Accept in order to successfully complete authorization.
+//
+// The url argument is an authz URL, usually obtained with c.Register.
+func (c *Client) Authorize(url, domain string) (*Authorization, error) {
+ type authzID struct {
+ Type string `json:"type"`
+ Value string `json:"value"`
+ }
+ req := struct {
+ Resource string `json:"resource"`
+ Identifier authzID `json:"identifier"`
+ }{
+ Resource: "new-authz",
+ Identifier: authzID{Type: "dns", Value: domain},
+ }
+ res, err := c.postJWS(url, req)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusCreated {
+ return nil, responseError(res)
+ }
+
+ var v wireAuthz
+ if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+ return nil, fmt.Errorf("Decode: %v", err)
+ }
+ if v.Status != StatusPending {
+ return nil, fmt.Errorf("Unexpected status: %s", v.Status)
+ }
+ return v.authorization(res.Header.Get("Location")), nil
+}
+
+// GetAuthz retrieves the current status of an authorization flow.
+//
+// A client typically polls an authz status using this method.
+func (c *Client) GetAuthz(url string) (*Authorization, error) {
+ res, err := c.httpClient().Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
+ return nil, responseError(res)
+ }
+ var v wireAuthz
+ if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+ return nil, fmt.Errorf("Decode: %v", err)
+ }
+ return v.authorization(url), nil
+}
+
+// GetChallenge retrieves the current status of an challenge.
+//
+// A client typically polls a challenge status using this method.
+func (c *Client) GetChallenge(url string) (*Challenge, error) {
+ res, err := c.httpClient().Get(url)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
+ return nil, responseError(res)
+ }
+ v := wireChallenge{URI: url}
+ if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+ return nil, fmt.Errorf("Decode: %v", err)
+ }
+ return v.challenge(), nil
+}
+
+// Accept informs the server that the client accepts one of its challenges
+// previously obtained with c.Authorize.
+//
+// The server will then perform the validation asynchronously.
+func (c *Client) Accept(chal *Challenge) (*Challenge, error) {
+ req := struct {
+ Resource string `json:"resource"`
+ Type string `json:"type"`
+ Auth string `json:"keyAuthorization"`
+ }{
+ Resource: "challenge",
+ Type: chal.Type,
+ Auth: keyAuth(&c.Key.PublicKey, chal.Token),
+ }
+ res, err := c.postJWS(chal.URI, req)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ // Note: the protocol specifies 200 as the expected response code, but
+ // letsencrypt seems to be returning 202.
+ if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusAccepted {
+ return nil, responseError(res)
+ }
+
+ var v wireChallenge
+ if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+ return nil, fmt.Errorf("Decode: %v", err)
+ }
+ return v.challenge(), nil
+}
+
+// HTTP01Handler creates a new handler which responds to a http-01 challenge.
+// The token argument is a Challenge.Token value.
+func (c *Client) HTTP01Handler(token string) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if !strings.HasSuffix(r.URL.Path, token) {
+ w.WriteHeader(http.StatusNotFound)
+ return
+ }
+ w.Header().Set("content-type", "text/plain")
+ w.Write([]byte(keyAuth(&c.Key.PublicKey, token)))
+ })
+}
+
+func (c *Client) httpClient() *http.Client {
+ if c.HTTPClient != nil {
+ return c.HTTPClient
+ }
+ return http.DefaultClient
+}
+
+// postJWS signs body and posts it to the provided url.
+// The body argument must be JSON-serializable.
+func (c *Client) postJWS(url string, body interface{}) (*http.Response, error) {
+ nonce, err := fetchNonce(c.httpClient(), url)
+ if err != nil {
+ return nil, err
+ }
+ b, err := jwsEncodeJSON(body, c.Key, nonce)
+ if err != nil {
+ return nil, err
+ }
+ req, err := http.NewRequest("POST", url, bytes.NewReader(b))
+ if err != nil {
+ return nil, err
+ }
+ return c.httpClient().Do(req)
+}
+
+// doReg sends all types of registration requests.
+// The type of request is identified by typ argument, which is a "resource"
+// in the ACME spec terms.
+//
+// A non-nil acct argument indicates whether the intention is to mutate data
+// of the Account. Only Contact and Agreement of its fields are used
+// in such cases.
+//
+// The fields of acct will be populate with the server response
+// and may be overwritten.
+func (c *Client) doReg(url string, typ string, acct *Account) (*Account, error) {
+ req := struct {
+ Resource string `json:"resource"`
+ Contact []string `json:"contact,omitempty"`
+ Agreement string `json:"agreement,omitempty"`
+ }{
+ Resource: typ,
+ }
+ if acct != nil {
+ req.Contact = acct.Contact
+ req.Agreement = acct.AgreedTerms
+ }
+ res, err := c.postJWS(url, req)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode < 200 || res.StatusCode > 299 {
+ return nil, responseError(res)
+ }
+
+ var v struct {
+ Contact []string
+ Agreement string
+ Authorizations string
+ Certificates string
+ }
+ if err := json.NewDecoder(res.Body).Decode(&v); err != nil {
+ return nil, fmt.Errorf("Decode: %v", err)
+ }
+ return &Account{
+ URI: res.Header.Get("Location"),
+ Contact: v.Contact,
+ AgreedTerms: v.Agreement,
+ CurrentTerms: linkHeader(res.Header, "terms-of-service"),
+ Authz: linkHeader(res.Header, "next"),
+ Authorizations: v.Authorizations,
+ Certificates: v.Certificates,
+ }, nil
+}
+
+func responseCert(client *http.Client, res *http.Response, bundle bool) ([][]byte, error) {
+ b, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ return nil, fmt.Errorf("ReadAll: %v", err)
+ }
+ cert := [][]byte{b}
+ if !bundle {
+ return cert, nil
+ }
+
+ // append ca cert
+ up := linkHeader(res.Header, "up")
+ if up == "" {
+ return nil, errors.New("rel=up link not found")
+ }
+ res, err = client.Get(up)
+ if err != nil {
+ return nil, err
+ }
+ defer res.Body.Close()
+ if res.StatusCode != http.StatusOK {
+ return nil, responseError(res)
+ }
+ b, err = ioutil.ReadAll(res.Body)
+ if err != nil {
+ return nil, err
+ }
+ return append(cert, b), nil
+}
+
+// responseError creates an error of Error type from resp.
+func responseError(resp *http.Response) error {
+ // don't care if ReadAll returns an error:
+ // json.Unmarshal will fail in that case anyway
+ b, _ := ioutil.ReadAll(resp.Body)
+ e := struct {
+ Status int
+ Type string
+ Detail string
+ }{
+ Status: resp.StatusCode,
+ }
+ if err := json.Unmarshal(b, &e); err != nil {
+ // this is not a regular error response:
+ // populate detail with anything we received,
+ // e.Status will already contain HTTP response code value
+ e.Detail = string(b)
+ if e.Detail == "" {
+ e.Detail = resp.Status
+ }
+ }
+ return &Error{
+ StatusCode: e.Status,
+ ProblemType: e.Type,
+ Detail: e.Detail,
+ Header: resp.Header,
+ }
+}
+
+func fetchNonce(client *http.Client, url string) (string, error) {
+ resp, err := client.Head(url)
+ if err != nil {
+ return "", nil
+ }
+ defer resp.Body.Close()
+ enc := resp.Header.Get("replay-nonce")
+ if enc == "" {
+ return "", errors.New("nonce not found")
+ }
+ return enc, nil
+}
+
+func linkHeader(h http.Header, rel string) string {
+ for _, v := range h["Link"] {
+ parts := strings.Split(v, ";")
+ for _, p := range parts {
+ p = strings.TrimSpace(p)
+ if !strings.HasPrefix(p, "rel=") {
+ continue
+ }
+ if v := strings.Trim(p[4:], `"`); v == rel {
+ return strings.Trim(parts[0], "<>")
+ }
+ }
+ }
+ return ""
+}
+
+func retryAfter(v string) (time.Duration, error) {
+ if i, err := strconv.Atoi(v); err == nil {
+ return time.Duration(i) * time.Second, nil
+ }
+ t, err := http.ParseTime(v)
+ if err != nil {
+ return 0, err
+ }
+ return t.Sub(timeNow()), nil
+}
+
+// keyAuth generates a key authorization string for a given token.
+func keyAuth(pub *rsa.PublicKey, token string) string {
+ return fmt.Sprintf("%s.%s", token, JWKThumbprint(pub))
+}
+
+// timeNow is useful for testing for fixed current time.
+var timeNow = time.Now
diff --git a/vendor/golang.org/x/crypto/acme/internal/acme/acme_test.go b/vendor/golang.org/x/crypto/acme/internal/acme/acme_test.go
new file mode 100644
index 000000000..f9d17c339
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/internal/acme/acme_test.go
@@ -0,0 +1,759 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+ "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "math/big"
+ "net/http"
+ "net/http/httptest"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+
+ "golang.org/x/net/context"
+)
+
+// Decodes a JWS-encoded request and unmarshals the decoded JSON into a provided
+// interface.
+func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
+ // Decode request
+ var req struct{ Payload string }
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ t.Fatal(err)
+ }
+ payload, err := base64.RawURLEncoding.DecodeString(req.Payload)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = json.Unmarshal(payload, v)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestDiscover(t *testing.T) {
+ const (
+ reg = "https://example.com/acme/new-reg"
+ authz = "https://example.com/acme/new-authz"
+ cert = "https://example.com/acme/new-cert"
+ revoke = "https://example.com/acme/revoke-cert"
+ )
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("content-type", "application/json")
+ fmt.Fprintf(w, `{
+ "new-reg": %q,
+ "new-authz": %q,
+ "new-cert": %q,
+ "revoke-cert": %q
+ }`, reg, authz, cert, revoke)
+ }))
+ defer ts.Close()
+ ep, err := (&Client{}).Discover(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if ep.RegURL != reg {
+ t.Errorf("RegURL = %q; want %q", ep.RegURL, reg)
+ }
+ if ep.AuthzURL != authz {
+ t.Errorf("authzURL = %q; want %q", ep.AuthzURL, authz)
+ }
+ if ep.CertURL != cert {
+ t.Errorf("certURL = %q; want %q", ep.CertURL, cert)
+ }
+ if ep.RevokeURL != revoke {
+ t.Errorf("revokeURL = %q; want %q", ep.RevokeURL, revoke)
+ }
+}
+
+func TestRegister(t *testing.T) {
+ contacts := []string{"mailto:admin@example.com"}
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "HEAD" {
+ w.Header().Set("replay-nonce", "test-nonce")
+ return
+ }
+ if r.Method != "POST" {
+ t.Errorf("r.Method = %q; want POST", r.Method)
+ }
+
+ var j struct {
+ Resource string
+ Contact []string
+ Agreement string
+ }
+ decodeJWSRequest(t, &j, r)
+
+ // Test request
+ if j.Resource != "new-reg" {
+ t.Errorf("j.Resource = %q; want new-reg", j.Resource)
+ }
+ if !reflect.DeepEqual(j.Contact, contacts) {
+ t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
+ }
+
+ w.Header().Set("Location", "https://ca.tld/acme/reg/1")
+ w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
+ w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
+ w.Header().Add("Link", `<https://ca.tld/acme/terms>;rel="terms-of-service"`)
+ w.WriteHeader(http.StatusCreated)
+ b, _ := json.Marshal(contacts)
+ fmt.Fprintf(w, `{
+ "key":%q,
+ "contact":%s
+ }`, testKeyThumbprint, b)
+ }))
+ defer ts.Close()
+
+ c := Client{Key: testKey}
+ a := &Account{Contact: contacts}
+ var err error
+ if a, err = c.Register(ts.URL, a); err != nil {
+ t.Fatal(err)
+ }
+ if a.URI != "https://ca.tld/acme/reg/1" {
+ t.Errorf("a.URI = %q; want https://ca.tld/acme/reg/1", a.URI)
+ }
+ if a.Authz != "https://ca.tld/acme/new-authz" {
+ t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
+ }
+ if a.CurrentTerms != "https://ca.tld/acme/terms" {
+ t.Errorf("a.CurrentTerms = %q; want https://ca.tld/acme/terms", a.CurrentTerms)
+ }
+ if !reflect.DeepEqual(a.Contact, contacts) {
+ t.Errorf("a.Contact = %v; want %v", a.Contact, contacts)
+ }
+}
+
+func TestUpdateReg(t *testing.T) {
+ const terms = "https://ca.tld/acme/terms"
+ contacts := []string{"mailto:admin@example.com"}
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "HEAD" {
+ w.Header().Set("replay-nonce", "test-nonce")
+ return
+ }
+ if r.Method != "POST" {
+ t.Errorf("r.Method = %q; want POST", r.Method)
+ }
+
+ var j struct {
+ Resource string
+ Contact []string
+ Agreement string
+ }
+ decodeJWSRequest(t, &j, r)
+
+ // Test request
+ if j.Resource != "reg" {
+ t.Errorf("j.Resource = %q; want reg", j.Resource)
+ }
+ if j.Agreement != terms {
+ t.Errorf("j.Agreement = %q; want %q", j.Agreement, terms)
+ }
+ if !reflect.DeepEqual(j.Contact, contacts) {
+ t.Errorf("j.Contact = %v; want %v", j.Contact, contacts)
+ }
+
+ w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
+ w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
+ w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, terms))
+ w.WriteHeader(http.StatusOK)
+ b, _ := json.Marshal(contacts)
+ fmt.Fprintf(w, `{
+ "key":%q,
+ "contact":%s,
+ "agreement":%q
+ }`, testKeyThumbprint, b, terms)
+ }))
+ defer ts.Close()
+
+ c := Client{Key: testKey}
+ a := &Account{Contact: contacts, AgreedTerms: terms}
+ var err error
+ if a, err = c.UpdateReg(ts.URL, a); err != nil {
+ t.Fatal(err)
+ }
+ if a.Authz != "https://ca.tld/acme/new-authz" {
+ t.Errorf("a.Authz = %q; want https://ca.tld/acme/new-authz", a.Authz)
+ }
+ if a.AgreedTerms != terms {
+ t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
+ }
+ if a.CurrentTerms != terms {
+ t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, terms)
+ }
+}
+
+func TestGetReg(t *testing.T) {
+ const terms = "https://ca.tld/acme/terms"
+ const newTerms = "https://ca.tld/acme/new-terms"
+ contacts := []string{"mailto:admin@example.com"}
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "HEAD" {
+ w.Header().Set("replay-nonce", "test-nonce")
+ return
+ }
+ if r.Method != "POST" {
+ t.Errorf("r.Method = %q; want POST", r.Method)
+ }
+
+ var j struct {
+ Resource string
+ Contact []string
+ Agreement string
+ }
+ decodeJWSRequest(t, &j, r)
+
+ // Test request
+ if j.Resource != "reg" {
+ t.Errorf("j.Resource = %q; want reg", j.Resource)
+ }
+ if len(j.Contact) != 0 {
+ t.Errorf("j.Contact = %v", j.Contact)
+ }
+ if j.Agreement != "" {
+ t.Errorf("j.Agreement = %q", j.Agreement)
+ }
+
+ w.Header().Set("Link", `<https://ca.tld/acme/new-authz>;rel="next"`)
+ w.Header().Add("Link", `<https://ca.tld/acme/recover-reg>;rel="recover"`)
+ w.Header().Add("Link", fmt.Sprintf(`<%s>;rel="terms-of-service"`, newTerms))
+ w.WriteHeader(http.StatusOK)
+ b, _ := json.Marshal(contacts)
+ fmt.Fprintf(w, `{
+ "key":%q,
+ "contact":%s,
+ "agreement":%q
+ }`, testKeyThumbprint, b, terms)
+ }))
+ defer ts.Close()
+
+ c := Client{Key: testKey}
+ a, err := c.GetReg(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if a.Authz != "https://ca.tld/acme/new-authz" {
+ t.Errorf("a.AuthzURL = %q; want https://ca.tld/acme/new-authz", a.Authz)
+ }
+ if a.AgreedTerms != terms {
+ t.Errorf("a.AgreedTerms = %q; want %q", a.AgreedTerms, terms)
+ }
+ if a.CurrentTerms != newTerms {
+ t.Errorf("a.CurrentTerms = %q; want %q", a.CurrentTerms, newTerms)
+ }
+}
+
+func TestAuthorize(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "HEAD" {
+ w.Header().Set("replay-nonce", "test-nonce")
+ return
+ }
+ if r.Method != "POST" {
+ t.Errorf("r.Method = %q; want POST", r.Method)
+ }
+
+ var j struct {
+ Resource string
+ Identifier struct {
+ Type string
+ Value string
+ }
+ }
+ decodeJWSRequest(t, &j, r)
+
+ // Test request
+ if j.Resource != "new-authz" {
+ t.Errorf("j.Resource = %q; want new-authz", j.Resource)
+ }
+ if j.Identifier.Type != "dns" {
+ t.Errorf("j.Identifier.Type = %q; want dns", j.Identifier.Type)
+ }
+ if j.Identifier.Value != "example.com" {
+ t.Errorf("j.Identifier.Value = %q; want example.com", j.Identifier.Value)
+ }
+
+ w.Header().Set("Location", "https://ca.tld/acme/auth/1")
+ w.WriteHeader(http.StatusCreated)
+ fmt.Fprintf(w, `{
+ "identifier": {"type":"dns","value":"example.com"},
+ "status":"pending",
+ "challenges":[
+ {
+ "type":"http-01",
+ "status":"pending",
+ "uri":"https://ca.tld/acme/challenge/publickey/id1",
+ "token":"token1"
+ },
+ {
+ "type":"tls-sni-01",
+ "status":"pending",
+ "uri":"https://ca.tld/acme/challenge/publickey/id2",
+ "token":"token2"
+ }
+ ],
+ "combinations":[[0],[1]]}`)
+ }))
+ defer ts.Close()
+
+ cl := Client{Key: testKey}
+ auth, err := cl.Authorize(ts.URL, "example.com")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if auth.URI != "https://ca.tld/acme/auth/1" {
+ t.Errorf("URI = %q; want https://ca.tld/acme/auth/1", auth.URI)
+ }
+ if auth.Status != "pending" {
+ t.Errorf("Status = %q; want pending", auth.Status)
+ }
+ if auth.Identifier.Type != "dns" {
+ t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
+ }
+ if auth.Identifier.Value != "example.com" {
+ t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
+ }
+
+ if n := len(auth.Challenges); n != 2 {
+ t.Fatalf("len(auth.Challenges) = %d; want 2", n)
+ }
+
+ c := auth.Challenges[0]
+ if c.Type != "http-01" {
+ t.Errorf("c.Type = %q; want http-01", c.Type)
+ }
+ if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+ t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
+ }
+ if c.Token != "token1" {
+ t.Errorf("c.Token = %q; want token1", c.Type)
+ }
+
+ c = auth.Challenges[1]
+ if c.Type != "tls-sni-01" {
+ t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
+ }
+ if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
+ t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
+ }
+ if c.Token != "token2" {
+ t.Errorf("c.Token = %q; want token2", c.Type)
+ }
+
+ combs := [][]int{{0}, {1}}
+ if !reflect.DeepEqual(auth.Combinations, combs) {
+ t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
+ }
+}
+
+func TestPollAuthz(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "GET" {
+ t.Errorf("r.Method = %q; want GET", r.Method)
+ }
+
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, `{
+ "identifier": {"type":"dns","value":"example.com"},
+ "status":"pending",
+ "challenges":[
+ {
+ "type":"http-01",
+ "status":"pending",
+ "uri":"https://ca.tld/acme/challenge/publickey/id1",
+ "token":"token1"
+ },
+ {
+ "type":"tls-sni-01",
+ "status":"pending",
+ "uri":"https://ca.tld/acme/challenge/publickey/id2",
+ "token":"token2"
+ }
+ ],
+ "combinations":[[0],[1]]}`)
+ }))
+ defer ts.Close()
+
+ cl := Client{Key: testKey}
+ auth, err := cl.GetAuthz(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if auth.Status != "pending" {
+ t.Errorf("Status = %q; want pending", auth.Status)
+ }
+ if auth.Identifier.Type != "dns" {
+ t.Errorf("Identifier.Type = %q; want dns", auth.Identifier.Type)
+ }
+ if auth.Identifier.Value != "example.com" {
+ t.Errorf("Identifier.Value = %q; want example.com", auth.Identifier.Value)
+ }
+
+ if n := len(auth.Challenges); n != 2 {
+ t.Fatalf("len(set.Challenges) = %d; want 2", n)
+ }
+
+ c := auth.Challenges[0]
+ if c.Type != "http-01" {
+ t.Errorf("c.Type = %q; want http-01", c.Type)
+ }
+ if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+ t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
+ }
+ if c.Token != "token1" {
+ t.Errorf("c.Token = %q; want token1", c.Type)
+ }
+
+ c = auth.Challenges[1]
+ if c.Type != "tls-sni-01" {
+ t.Errorf("c.Type = %q; want tls-sni-01", c.Type)
+ }
+ if c.URI != "https://ca.tld/acme/challenge/publickey/id2" {
+ t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id2", c.URI)
+ }
+ if c.Token != "token2" {
+ t.Errorf("c.Token = %q; want token2", c.Type)
+ }
+
+ combs := [][]int{{0}, {1}}
+ if !reflect.DeepEqual(auth.Combinations, combs) {
+ t.Errorf("auth.Combinations: %+v\nwant: %+v\n", auth.Combinations, combs)
+ }
+}
+
+func TestPollChallenge(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "GET" {
+ t.Errorf("r.Method = %q; want GET", r.Method)
+ }
+
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, `{
+ "type":"http-01",
+ "status":"pending",
+ "uri":"https://ca.tld/acme/challenge/publickey/id1",
+ "token":"token1"}`)
+ }))
+ defer ts.Close()
+
+ cl := Client{Key: testKey}
+ chall, err := cl.GetChallenge(ts.URL)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if chall.Status != "pending" {
+ t.Errorf("Status = %q; want pending", chall.Status)
+ }
+ if chall.Type != "http-01" {
+ t.Errorf("c.Type = %q; want http-01", chall.Type)
+ }
+ if chall.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+ t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", chall.URI)
+ }
+ if chall.Token != "token1" {
+ t.Errorf("c.Token = %q; want token1", chall.Type)
+ }
+}
+
+func TestAcceptChallenge(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "HEAD" {
+ w.Header().Set("replay-nonce", "test-nonce")
+ return
+ }
+ if r.Method != "POST" {
+ t.Errorf("r.Method = %q; want POST", r.Method)
+ }
+
+ var j struct {
+ Resource string
+ Type string
+ Auth string `json:"keyAuthorization"`
+ }
+ decodeJWSRequest(t, &j, r)
+
+ // Test request
+ if j.Resource != "challenge" {
+ t.Errorf(`resource = %q; want "challenge"`, j.Resource)
+ }
+ if j.Type != "http-01" {
+ t.Errorf(`type = %q; want "http-01"`, j.Type)
+ }
+ keyAuth := "token1." + testKeyThumbprint
+ if j.Auth != keyAuth {
+ t.Errorf(`keyAuthorization = %q; want %q`, j.Auth, keyAuth)
+ }
+
+ // Respond to request
+ w.WriteHeader(http.StatusAccepted)
+ fmt.Fprintf(w, `{
+ "type":"http-01",
+ "status":"pending",
+ "uri":"https://ca.tld/acme/challenge/publickey/id1",
+ "token":"token1",
+ "keyAuthorization":%q
+ }`, keyAuth)
+ }))
+ defer ts.Close()
+
+ cl := Client{Key: testKey}
+ c, err := cl.Accept(&Challenge{
+ URI: ts.URL,
+ Token: "token1",
+ Type: "http-01",
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if c.Type != "http-01" {
+ t.Errorf("c.Type = %q; want http-01", c.Type)
+ }
+ if c.URI != "https://ca.tld/acme/challenge/publickey/id1" {
+ t.Errorf("c.URI = %q; want https://ca.tld/acme/challenge/publickey/id1", c.URI)
+ }
+ if c.Token != "token1" {
+ t.Errorf("c.Token = %q; want token1", c.Type)
+ }
+}
+
+func TestNewCert(t *testing.T) {
+ notBefore := time.Now()
+ notAfter := notBefore.AddDate(0, 2, 0)
+ timeNow = func() time.Time { return notBefore }
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "HEAD" {
+ w.Header().Set("replay-nonce", "test-nonce")
+ return
+ }
+ if r.Method != "POST" {
+ t.Errorf("r.Method = %q; want POST", r.Method)
+ }
+
+ var j struct {
+ Resource string `json:"resource"`
+ CSR string `json:"csr"`
+ NotBefore string `json:"notBefore,omitempty"`
+ NotAfter string `json:"notAfter,omitempty"`
+ }
+ decodeJWSRequest(t, &j, r)
+
+ // Test request
+ if j.Resource != "new-cert" {
+ t.Errorf(`resource = %q; want "new-cert"`, j.Resource)
+ }
+ if j.NotBefore != notBefore.Format(time.RFC3339) {
+ t.Errorf(`notBefore = %q; wanted %q`, j.NotBefore, notBefore.Format(time.RFC3339))
+ }
+ if j.NotAfter != notAfter.Format(time.RFC3339) {
+ t.Errorf(`notAfter = %q; wanted %q`, j.NotAfter, notAfter.Format(time.RFC3339))
+ }
+
+ // Respond to request
+ template := x509.Certificate{
+ SerialNumber: big.NewInt(int64(1)),
+ Subject: pkix.Name{
+ Organization: []string{"goacme"},
+ },
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+
+ sampleCert, err := x509.CreateCertificate(rand.Reader, &template, &template, &testKey.PublicKey, testKey)
+ if err != nil {
+ t.Fatalf("Error creating certificate: %v", err)
+ }
+
+ w.Header().Set("Location", "https://ca.tld/acme/cert/1")
+ w.WriteHeader(http.StatusCreated)
+ w.Write(sampleCert)
+ }))
+ defer ts.Close()
+
+ csr := x509.CertificateRequest{
+ Version: 0,
+ Subject: pkix.Name{
+ CommonName: "example.com",
+ Organization: []string{"goacme"},
+ },
+ }
+ csrb, err := x509.CreateCertificateRequest(rand.Reader, &csr, testKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ c := Client{Key: testKey}
+ cert, certURL, err := c.CreateCert(context.Background(), ts.URL, csrb, notAfter.Sub(notBefore), false)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if cert == nil {
+ t.Errorf("cert is nil")
+ }
+ if certURL != "https://ca.tld/acme/cert/1" {
+ t.Errorf("certURL = %q; want https://ca.tld/acme/cert/1", certURL)
+ }
+}
+
+func TestFetchCert(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte{1})
+ }))
+ defer ts.Close()
+ res, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
+ if err != nil {
+ t.Fatalf("FetchCert: %v", err)
+ }
+ cert := [][]byte{{1}}
+ if !reflect.DeepEqual(res, cert) {
+ t.Errorf("res = %v; want %v", res, cert)
+ }
+}
+
+func TestFetchCertRetry(t *testing.T) {
+ var count int
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if count < 1 {
+ w.Header().Set("retry-after", "0")
+ w.WriteHeader(http.StatusAccepted)
+ count++
+ return
+ }
+ w.Write([]byte{1})
+ }))
+ defer ts.Close()
+ res, err := (&Client{}).FetchCert(context.Background(), ts.URL, false)
+ if err != nil {
+ t.Fatalf("FetchCert: %v", err)
+ }
+ cert := [][]byte{{1}}
+ if !reflect.DeepEqual(res, cert) {
+ t.Errorf("res = %v; want %v", res, cert)
+ }
+}
+
+func TestFetchCertCancel(t *testing.T) {
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("retry-after", "0")
+ w.WriteHeader(http.StatusAccepted)
+ }))
+ defer ts.Close()
+ ctx, cancel := context.WithCancel(context.Background())
+ done := make(chan struct{})
+ var err error
+ go func() {
+ _, err = (&Client{}).FetchCert(ctx, ts.URL, false)
+ close(done)
+ }()
+ cancel()
+ <-done
+ if err != context.Canceled {
+ t.Errorf("err = %v; want %v", err, context.Canceled)
+ }
+}
+
+func TestFetchNonce(t *testing.T) {
+ tests := []struct {
+ code int
+ nonce string
+ }{
+ {http.StatusOK, "nonce1"},
+ {http.StatusBadRequest, "nonce2"},
+ {http.StatusOK, ""},
+ }
+ var i int
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "HEAD" {
+ t.Errorf("%d: r.Method = %q; want HEAD", i, r.Method)
+ }
+ w.Header().Set("replay-nonce", tests[i].nonce)
+ w.WriteHeader(tests[i].code)
+ }))
+ defer ts.Close()
+ for ; i < len(tests); i++ {
+ test := tests[i]
+ n, err := fetchNonce(http.DefaultClient, ts.URL)
+ if n != test.nonce {
+ t.Errorf("%d: n=%q; want %q", i, n, test.nonce)
+ }
+ switch {
+ case err == nil && test.nonce == "":
+ t.Errorf("%d: n=%q, err=%v; want non-nil error", i, n, err)
+ case err != nil && test.nonce != "":
+ t.Errorf("%d: n=%q, err=%v; want %q", i, n, err, test.nonce)
+ }
+ }
+}
+
+func TestLinkHeader(t *testing.T) {
+ h := http.Header{"Link": {
+ `<https://example.com/acme/new-authz>;rel="next"`,
+ `<https://example.com/acme/recover-reg>; rel=recover`,
+ `<https://example.com/acme/terms>; foo=bar; rel="terms-of-service"`,
+ }}
+ tests := []struct{ in, out string }{
+ {"next", "https://example.com/acme/new-authz"},
+ {"recover", "https://example.com/acme/recover-reg"},
+ {"terms-of-service", "https://example.com/acme/terms"},
+ {"empty", ""},
+ }
+ for i, test := range tests {
+ if v := linkHeader(h, test.in); v != test.out {
+ t.Errorf("%d: parseLinkHeader(%q): %q; want %q", i, test.in, v, test.out)
+ }
+ }
+}
+
+func TestErrorResponse(t *testing.T) {
+ s := `{
+ "status": 400,
+ "type": "urn:acme:error:xxx",
+ "detail": "text"
+ }`
+ res := &http.Response{
+ StatusCode: 400,
+ Status: "400 Bad Request",
+ Body: ioutil.NopCloser(strings.NewReader(s)),
+ Header: http.Header{"X-Foo": {"bar"}},
+ }
+ err := responseError(res)
+ v, ok := err.(*Error)
+ if !ok {
+ t.Fatalf("err = %+v (%T); want *Error type", err, err)
+ }
+ if v.StatusCode != 400 {
+ t.Errorf("v.StatusCode = %v; want 400", v.StatusCode)
+ }
+ if v.ProblemType != "urn:acme:error:xxx" {
+ t.Errorf("v.ProblemType = %q; want urn:acme:error:xxx", v.ProblemType)
+ }
+ if v.Detail != "text" {
+ t.Errorf("v.Detail = %q; want text", v.Detail)
+ }
+ if !reflect.DeepEqual(v.Header, res.Header) {
+ t.Errorf("v.Header = %+v; want %+v", v.Header, res.Header)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/acme/internal/acme/jws.go b/vendor/golang.org/x/crypto/acme/internal/acme/jws.go
new file mode 100644
index 000000000..c27752977
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/internal/acme/jws.go
@@ -0,0 +1,67 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha256"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "math/big"
+)
+
+// jwsEncodeJSON signs claimset using provided key and a nonce.
+// The result is serialized in JSON format.
+// See https://tools.ietf.org/html/rfc7515#section-7.
+func jwsEncodeJSON(claimset interface{}, key *rsa.PrivateKey, nonce string) ([]byte, error) {
+ jwk := jwkEncode(&key.PublicKey)
+ phead := fmt.Sprintf(`{"alg":"RS256","jwk":%s,"nonce":%q}`, jwk, nonce)
+ phead = base64.RawURLEncoding.EncodeToString([]byte(phead))
+ cs, err := json.Marshal(claimset)
+ if err != nil {
+ return nil, err
+ }
+ payload := base64.RawURLEncoding.EncodeToString(cs)
+ h := sha256.New()
+ h.Write([]byte(phead + "." + payload))
+ sig, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
+ if err != nil {
+ return nil, err
+ }
+ enc := struct {
+ Protected string `json:"protected"`
+ Payload string `json:"payload"`
+ Sig string `json:"signature"`
+ }{
+ Protected: phead,
+ Payload: payload,
+ Sig: base64.RawURLEncoding.EncodeToString(sig),
+ }
+ return json.Marshal(&enc)
+}
+
+// jwkEncode encodes public part of an RSA key into a JWK.
+// The result is also suitable for creating a JWK thumbprint.
+func jwkEncode(pub *rsa.PublicKey) string {
+ n := pub.N
+ e := big.NewInt(int64(pub.E))
+ // fields order is important
+ // see https://tools.ietf.org/html/rfc7638#section-3.3 for details
+ return fmt.Sprintf(`{"e":"%s","kty":"RSA","n":"%s"}`,
+ base64.RawURLEncoding.EncodeToString(e.Bytes()),
+ base64.RawURLEncoding.EncodeToString(n.Bytes()),
+ )
+}
+
+// JWKThumbprint creates a JWK thumbprint out of pub
+// as specified in https://tools.ietf.org/html/rfc7638.
+func JWKThumbprint(pub *rsa.PublicKey) string {
+ jwk := jwkEncode(pub)
+ b := sha256.Sum256([]byte(jwk))
+ return base64.RawURLEncoding.EncodeToString(b[:])
+}
diff --git a/vendor/golang.org/x/crypto/acme/internal/acme/jws_test.go b/vendor/golang.org/x/crypto/acme/internal/acme/jws_test.go
new file mode 100644
index 000000000..7afd9507b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/internal/acme/jws_test.go
@@ -0,0 +1,139 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package acme
+
+import (
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/json"
+ "encoding/pem"
+ "math/big"
+ "testing"
+)
+
+const testKeyPEM = `
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA4xgZ3eRPkwoRvy7qeRUbmMDe0V+xH9eWLdu0iheeLlrmD2mq
+WXfP9IeSKApbn34g8TuAS9g5zhq8ELQ3kmjr+KV86GAMgI6VAcGlq3QrzpTCf/30
+Ab7+zawrfRaFONa1HwEzPY1KHnGVkxJc85gNkwYI9SY2RHXtvln3zs5wITNrdosq
+EXeaIkVYBEhbhNu54pp3kxo6TuWLi9e6pXeWetEwmlBwtWZlPoib2j3TxLBksKZf
+oyFyek380mHgJAumQ/I2fjj98/97mk3ihOY4AgVdCDj1z/GCoZkG5Rq7nbCGyosy
+KWyDX00Zs+nNqVhoLeIvXC4nnWdJMZ6rogxyQQIDAQABAoIBACIEZTOI1Kao9nmV
+9IeIsuaR1Y61b9neOF/MLmIVIZu+AAJFCMB4Iw11FV6sFodwpEyeZhx2WkpWVN+H
+r19eGiLX3zsL0DOdqBJoSIHDWCCMxgnYJ6nvS0nRxX3qVrBp8R2g12Ub+gNPbmFm
+ecf/eeERIVxfifd9VsyRu34eDEvcmKFuLYbElFcPh62xE3x12UZvV/sN7gXbawpP
+G+w255vbE5MoaKdnnO83cTFlcHvhn24M/78qP7Te5OAeelr1R89kYxQLpuGe4fbS
+zc6E3ym5Td6urDetGGrSY1Eu10/8sMusX+KNWkm+RsBRbkyKq72ks/qKpOxOa+c6
+9gm+Y8ECgYEA/iNUyg1ubRdH11p82l8KHtFC1DPE0V1gSZsX29TpM5jS4qv46K+s
+8Ym1zmrORM8x+cynfPx1VQZQ34EYeCMIX212ryJ+zDATl4NE0I4muMvSiH9vx6Xc
+7FmhNnaYzPsBL5Tm9nmtQuP09YEn8poiOJFiDs/4olnD5ogA5O4THGkCgYEA5MIL
+qWYBUuqbEWLRtMruUtpASclrBqNNsJEsMGbeqBJmoMxdHeSZckbLOrqm7GlMyNRJ
+Ne/5uWRGSzaMYuGmwsPpERzqEvYFnSrpjW5YtXZ+JtxFXNVfm9Z1gLLgvGpOUCIU
+RbpoDckDe1vgUuk3y5+DjZihs+rqIJ45XzXTzBkCgYBWuf3segruJZy5rEKhTv+o
+JqeUvRn0jNYYKFpLBeyTVBrbie6GkbUGNIWbrK05pC+c3K9nosvzuRUOQQL1tJbd
+4gA3oiD9U4bMFNr+BRTHyZ7OQBcIXdz3t1qhuHVKtnngIAN1p25uPlbRFUNpshnt
+jgeVoHlsBhApcs5DUc+pyQKBgDzeHPg/+g4z+nrPznjKnktRY1W+0El93kgi+J0Q
+YiJacxBKEGTJ1MKBb8X6sDurcRDm22wMpGfd9I5Cv2v4GsUsF7HD/cx5xdih+G73
+c4clNj/k0Ff5Nm1izPUno4C+0IOl7br39IPmfpSuR6wH/h6iHQDqIeybjxyKvT1G
+N0rRAoGBAKGD+4ZI/E1MoJ5CXB8cDDMHagbE3cq/DtmYzE2v1DFpQYu5I4PCm5c7
+EQeIP6dZtv8IMgtGIb91QX9pXvP0aznzQKwYIA8nZgoENCPfiMTPiEDT9e/0lObO
+9XWsXpbSTsRPj0sv1rB+UzBJ0PgjK4q2zOF0sNo7b1+6nlM3BWPx
+-----END RSA PRIVATE KEY-----
+`
+
+// This thumbprint is for the testKey defined above.
+const testKeyThumbprint = "6nicxzh6WETQlrvdchkz-U3e3DOQZ4heJKU63rfqMqQ"
+
+var testKey *rsa.PrivateKey
+
+func init() {
+ d, _ := pem.Decode([]byte(testKeyPEM))
+ if d == nil {
+ panic("no block found in testKeyPEM")
+ }
+ var err error
+ testKey, err = x509.ParsePKCS1PrivateKey(d.Bytes)
+ if err != nil {
+ panic(err.Error())
+ }
+}
+
+func TestJWSEncodeJSON(t *testing.T) {
+ claims := struct{ Msg string }{"Hello JWS"}
+ // JWS signed with testKey and "nonce" as the nonce value
+ // JSON-serialized JWS fields are split for easier testing
+ const (
+ // {"alg":"RS256","jwk":{"e":"AQAB","kty":"RSA","n":"..."},"nonce":"nonce"}
+ protected = "eyJhbGciOiJSUzI1NiIsImp3ayI6eyJlIjoiQVFBQiIsImt0eSI6" +
+ "IlJTQSIsIm4iOiI0eGdaM2VSUGt3b1J2eTdxZVJVYm1NRGUwVi14" +
+ "SDllV0xkdTBpaGVlTGxybUQybXFXWGZQOUllU0tBcGJuMzRnOFR1" +
+ "QVM5ZzV6aHE4RUxRM2ttanItS1Y4NkdBTWdJNlZBY0dscTNRcnpw" +
+ "VENmXzMwQWI3LXphd3JmUmFGT05hMUh3RXpQWTFLSG5HVmt4SmM4" +
+ "NWdOa3dZSTlTWTJSSFh0dmxuM3pzNXdJVE5yZG9zcUVYZWFJa1ZZ" +
+ "QkVoYmhOdTU0cHAza3hvNlR1V0xpOWU2cFhlV2V0RXdtbEJ3dFda" +
+ "bFBvaWIyajNUeExCa3NLWmZveUZ5ZWszODBtSGdKQXVtUV9JMmZq" +
+ "ajk4Xzk3bWszaWhPWTRBZ1ZkQ0RqMXpfR0NvWmtHNVJxN25iQ0d5" +
+ "b3N5S1d5RFgwMFpzLW5OcVZob0xlSXZYQzRubldkSk1aNnJvZ3h5" +
+ "UVEifSwibm9uY2UiOiJub25jZSJ9"
+ // {"Msg":"Hello JWS"}
+ payload = "eyJNc2ciOiJIZWxsbyBKV1MifQ"
+ signature = "eAGUikStX_UxyiFhxSLMyuyBcIB80GeBkFROCpap2sW3EmkU_ggF" +
+ "knaQzxrTfItICSAXsCLIquZ5BbrSWA_4vdEYrwWtdUj7NqFKjHRa" +
+ "zpLHcoR7r1rEHvkoP1xj49lS5fc3Wjjq8JUhffkhGbWZ8ZVkgPdC" +
+ "4tMBWiQDoth-x8jELP_3LYOB_ScUXi2mETBawLgOT2K8rA0Vbbmx" +
+ "hWNlOWuUf-8hL5YX4IOEwsS8JK_TrTq5Zc9My0zHJmaieqDV0UlP" +
+ "k0onFjPFkGm7MrPSgd0MqRG-4vSAg2O4hDo7rKv4n8POjjXlNQvM" +
+ "9IPLr8qZ7usYBKhEGwX3yq_eicAwBw"
+ )
+
+ b, err := jwsEncodeJSON(claims, testKey, "nonce")
+ if err != nil {
+ t.Fatal(err)
+ }
+ var jws struct{ Protected, Payload, Signature string }
+ if err := json.Unmarshal(b, &jws); err != nil {
+ t.Fatal(err)
+ }
+ if jws.Protected != protected {
+ t.Errorf("protected:\n%s\nwant:\n%s", jws.Protected, protected)
+ }
+ if jws.Payload != payload {
+ t.Errorf("payload:\n%s\nwant:\n%s", jws.Payload, payload)
+ }
+ if jws.Signature != signature {
+ t.Errorf("signature:\n%s\nwant:\n%s", jws.Signature, signature)
+ }
+}
+
+func TestJWKThumbprint(t *testing.T) {
+ // Key example from RFC 7638
+ const base64N = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAt" +
+ "VT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn6" +
+ "4tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FD" +
+ "W2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9" +
+ "1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINH" +
+ "aQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw"
+ const base64E = "AQAB"
+ const expected = "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs"
+
+ bytes, err := base64.RawURLEncoding.DecodeString(base64N)
+ if err != nil {
+ t.Fatalf("Error parsing example key N: %v", err)
+ }
+ n := new(big.Int).SetBytes(bytes)
+
+ bytes, err = base64.RawURLEncoding.DecodeString(base64E)
+ if err != nil {
+ t.Fatalf("Error parsing example key E: %v", err)
+ }
+ e := new(big.Int).SetBytes(bytes)
+
+ pub := &rsa.PublicKey{N: n, E: int(e.Uint64())}
+ th := JWKThumbprint(pub)
+ if th != expected {
+ t.Errorf("th = %q; want %q", th, expected)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/acme/internal/acme/types.go b/vendor/golang.org/x/crypto/acme/internal/acme/types.go
new file mode 100644
index 000000000..e64dc118c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/acme/internal/acme/types.go
@@ -0,0 +1,181 @@
+package acme
+
+import (
+ "fmt"
+ "net/http"
+)
+
+// ACME server response statuses used to describe Authorization and Challenge states.
+const (
+ StatusUnknown = "unknown"
+ StatusPending = "pending"
+ StatusProcessing = "processing"
+ StatusValid = "valid"
+ StatusInvalid = "invalid"
+ StatusRevoked = "revoked"
+)
+
+// Account is a user account. It is associated with a private key.
+type Account struct {
+ // URI is the account unique ID, which is also a URL used to retrieve
+ // account data from the CA.
+ URI string
+
+ // Contact is a slice of contact info used during registration.
+ Contact []string
+
+ // The terms user has agreed to.
+ // Zero value indicates that the user hasn't agreed yet.
+ AgreedTerms string
+
+ // Actual terms of a CA.
+ CurrentTerms string
+
+ // Authz is the authorization URL used to initiate a new authz flow.
+ Authz string
+
+ // Authorizations is a URI from which a list of authorizations
+ // granted to this account can be fetched via a GET request.
+ Authorizations string
+
+ // Certificates is a URI from which a list of certificates
+ // issued for this account can be fetched via a GET request.
+ Certificates string
+}
+
+// Directory is ACME server discovery data.
+type Directory struct {
+ // RegURL is an account endpoint URL, allowing for creating new
+ // and modifying existing accounts.
+ RegURL string
+
+ // AuthzURL is used to initiate Identifier Authorization flow.
+ AuthzURL string
+
+ // CertURL is a new certificate issuance endpoint URL.
+ CertURL string
+
+ // RevokeURL is used to initiate a certificate revocation flow.
+ RevokeURL string
+
+ // Term is a URI identifying the current terms of service.
+ Terms string
+
+ // Website is an HTTP or HTTPS URL locating a website
+ // providing more information about the ACME server.
+ Website string
+
+ // CAA consists of lowercase hostname elements, which the ACME server
+ // recognises as referring to itself for the purposes of CAA record validation
+ // as defined in RFC6844.
+ CAA []string
+}
+
+// Challenge encodes a returned CA challenge.
+type Challenge struct {
+ // Type is the challenge type, e.g. "http-01", "tls-sni-02", "dns-01".
+ Type string
+
+ // URI is where a challenge response can be posted to.
+ URI string
+
+ // Token is a random value that uniquely identifies the challenge.
+ Token string
+
+ // Status identifies the status of this challenge.
+ Status string
+}
+
+// Authorization encodes an authorization response.
+type Authorization struct {
+ // URI uniquely identifies a authorization.
+ URI string
+
+ // Status identifies the status of an authorization.
+ Status string
+
+ // Identifier is what the account is authorized to represent.
+ Identifier AuthzID
+
+ // Challenges that the client needs to fulfill in order to prove possession
+ // of the identifier (for pending authorizations).
+ // For final authorizations, the challenges that were used.
+ Challenges []*Challenge
+
+ // A collection of sets of challenges, each of which would be sufficient
+ // to prove possession of the identifier.
+ // Clients must complete a set of challenges that covers at least one set.
+ // Challenges are identified by their indices in the challenges array.
+ // If this field is empty, the client needs to complete all challenges.
+ Combinations [][]int
+}
+
+// AuthzID is an identifier that an account is authorized to represent.
+type AuthzID struct {
+ Type string // The type of identifier, e.g. "dns".
+ Value string // The identifier itself, e.g. "example.org".
+}
+
+// Error is an ACME error, defined in Problem Details for HTTP APIs doc
+// http://tools.ietf.org/html/draft-ietf-appsawg-http-problem.
+type Error struct {
+ // StatusCode is The HTTP status code generated by the origin server.
+ StatusCode int
+ // ProblemType is a URI reference that identifies the problem type,
+ // typically in a "urn:acme:error:xxx" form.
+ ProblemType string
+ // Detail is a human-readable explanation specific to this occurrence of the problem.
+ Detail string
+ // Header is the original server error response headers.
+ Header http.Header
+}
+
+func (e *Error) Error() string {
+ return fmt.Sprintf("%d %s: %s", e.StatusCode, e.ProblemType, e.Detail)
+}
+
+// wireAuthz is ACME JSON representation of Authorization objects.
+type wireAuthz struct {
+ Status string
+ Challenges []wireChallenge
+ Combinations [][]int
+ Identifier struct {
+ Type string
+ Value string
+ }
+}
+
+func (z *wireAuthz) authorization(uri string) *Authorization {
+ a := &Authorization{
+ URI: uri,
+ Status: z.Status,
+ Identifier: AuthzID{Type: z.Identifier.Type, Value: z.Identifier.Value},
+ Combinations: z.Combinations, // shallow copy
+ Challenges: make([]*Challenge, len(z.Challenges)),
+ }
+ for i, v := range z.Challenges {
+ a.Challenges[i] = v.challenge()
+ }
+ return a
+}
+
+// wireChallenge is ACME JSON challenge representation.
+type wireChallenge struct {
+ URI string `json:"uri"`
+ Type string
+ Token string
+ Status string
+}
+
+func (c *wireChallenge) challenge() *Challenge {
+ v := &Challenge{
+ URI: c.URI,
+ Type: c.Type,
+ Token: c.Token,
+ Status: c.Status,
+ }
+ if v.Status == "" {
+ v.Status = StatusPending
+ }
+ return v
+}
diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
index b8e18d744..f8b807f9c 100644
--- a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
+++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
@@ -4,7 +4,7 @@
// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
-package bcrypt
+package bcrypt // import "golang.org/x/crypto/bcrypt"
// The code is a port of Provos and Mazières's C implementation.
import (
diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
new file mode 100644
index 000000000..f08a6f5b2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt_test.go
@@ -0,0 +1,226 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bcrypt
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+)
+
+func TestBcryptingIsEasy(t *testing.T) {
+ pass := []byte("mypassword")
+ hp, err := GenerateFromPassword(pass, 0)
+ if err != nil {
+ t.Fatalf("GenerateFromPassword error: %s", err)
+ }
+
+ if CompareHashAndPassword(hp, pass) != nil {
+ t.Errorf("%v should hash %s correctly", hp, pass)
+ }
+
+ notPass := "notthepass"
+ err = CompareHashAndPassword(hp, []byte(notPass))
+ if err != ErrMismatchedHashAndPassword {
+ t.Errorf("%v and %s should be mismatched", hp, notPass)
+ }
+}
+
+func TestBcryptingIsCorrect(t *testing.T) {
+ pass := []byte("allmine")
+ salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
+ expectedHash := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
+
+ hash, err := bcrypt(pass, 10, salt)
+ if err != nil {
+ t.Fatalf("bcrypt blew up: %v", err)
+ }
+ if !bytes.HasSuffix(expectedHash, hash) {
+ t.Errorf("%v should be the suffix of %v", hash, expectedHash)
+ }
+
+ h, err := newFromHash(expectedHash)
+ if err != nil {
+ t.Errorf("Unable to parse %s: %v", string(expectedHash), err)
+ }
+
+ // This is not the safe way to compare these hashes. We do this only for
+ // testing clarity. Use bcrypt.CompareHashAndPassword()
+ if err == nil && !bytes.Equal(expectedHash, h.Hash()) {
+ t.Errorf("Parsed hash %v should equal %v", h.Hash(), expectedHash)
+ }
+}
+
+func TestVeryShortPasswords(t *testing.T) {
+ key := []byte("k")
+ salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
+ _, err := bcrypt(key, 10, salt)
+ if err != nil {
+ t.Errorf("One byte key resulted in error: %s", err)
+ }
+}
+
+func TestTooLongPasswordsWork(t *testing.T) {
+ salt := []byte("XajjQvNhvvRt5GSeFk1xFe")
+ // One byte over the usual 56 byte limit that blowfish has
+ tooLongPass := []byte("012345678901234567890123456789012345678901234567890123456")
+ tooLongExpected := []byte("$2a$10$XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C")
+ hash, err := bcrypt(tooLongPass, 10, salt)
+ if err != nil {
+ t.Fatalf("bcrypt blew up on long password: %v", err)
+ }
+ if !bytes.HasSuffix(tooLongExpected, hash) {
+ t.Errorf("%v should be the suffix of %v", hash, tooLongExpected)
+ }
+}
+
+type InvalidHashTest struct {
+ err error
+ hash []byte
+}
+
+var invalidTests = []InvalidHashTest{
+ {ErrHashTooShort, []byte("$2a$10$fooo")},
+ {ErrHashTooShort, []byte("$2a")},
+ {HashVersionTooNewError('3'), []byte("$3a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
+ {InvalidHashPrefixError('%'), []byte("%2a$10$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
+ {InvalidCostError(32), []byte("$2a$32$sssssssssssssssssssssshhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh")},
+}
+
+func TestInvalidHashErrors(t *testing.T) {
+ check := func(name string, expected, err error) {
+ if err == nil {
+ t.Errorf("%s: Should have returned an error", name)
+ }
+ if err != nil && err != expected {
+ t.Errorf("%s gave err %v but should have given %v", name, err, expected)
+ }
+ }
+ for _, iht := range invalidTests {
+ _, err := newFromHash(iht.hash)
+ check("newFromHash", iht.err, err)
+ err = CompareHashAndPassword(iht.hash, []byte("anything"))
+ check("CompareHashAndPassword", iht.err, err)
+ }
+}
+
+func TestUnpaddedBase64Encoding(t *testing.T) {
+ original := []byte{101, 201, 101, 75, 19, 227, 199, 20, 239, 236, 133, 32, 30, 109, 243, 30}
+ encodedOriginal := []byte("XajjQvNhvvRt5GSeFk1xFe")
+
+ encoded := base64Encode(original)
+
+ if !bytes.Equal(encodedOriginal, encoded) {
+ t.Errorf("Encoded %v should have equaled %v", encoded, encodedOriginal)
+ }
+
+ decoded, err := base64Decode(encodedOriginal)
+ if err != nil {
+ t.Fatalf("base64Decode blew up: %s", err)
+ }
+
+ if !bytes.Equal(decoded, original) {
+ t.Errorf("Decoded %v should have equaled %v", decoded, original)
+ }
+}
+
+func TestCost(t *testing.T) {
+ suffix := "XajjQvNhvvRt5GSeFk1xFe5l47dONXg781AmZtd869sO8zfsHuw7C"
+ for _, vers := range []string{"2a", "2"} {
+ for _, cost := range []int{4, 10} {
+ s := fmt.Sprintf("$%s$%02d$%s", vers, cost, suffix)
+ h := []byte(s)
+ actual, err := Cost(h)
+ if err != nil {
+ t.Errorf("Cost, error: %s", err)
+ continue
+ }
+ if actual != cost {
+ t.Errorf("Cost, expected: %d, actual: %d", cost, actual)
+ }
+ }
+ }
+ _, err := Cost([]byte("$a$a$" + suffix))
+ if err == nil {
+ t.Errorf("Cost, malformed but no error returned")
+ }
+}
+
+func TestCostValidationInHash(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ pass := []byte("mypassword")
+
+ for c := 0; c < MinCost; c++ {
+ p, _ := newFromPassword(pass, c)
+ if p.cost != DefaultCost {
+ t.Errorf("newFromPassword should default costs below %d to %d, but was %d", MinCost, DefaultCost, p.cost)
+ }
+ }
+
+ p, _ := newFromPassword(pass, 14)
+ if p.cost != 14 {
+ t.Errorf("newFromPassword should default cost to 14, but was %d", p.cost)
+ }
+
+ hp, _ := newFromHash(p.Hash())
+ if p.cost != hp.cost {
+ t.Errorf("newFromHash should maintain the cost at %d, but was %d", p.cost, hp.cost)
+ }
+
+ _, err := newFromPassword(pass, 32)
+ if err == nil {
+ t.Fatalf("newFromPassword: should return a cost error")
+ }
+ if err != InvalidCostError(32) {
+ t.Errorf("newFromPassword: should return cost error, got %#v", err)
+ }
+}
+
+func TestCostReturnsWithLeadingZeroes(t *testing.T) {
+ hp, _ := newFromPassword([]byte("abcdefgh"), 7)
+ cost := hp.Hash()[4:7]
+ expected := []byte("07$")
+
+ if !bytes.Equal(expected, cost) {
+ t.Errorf("single digit costs in hash should have leading zeros: was %v instead of %v", cost, expected)
+ }
+}
+
+func TestMinorNotRequired(t *testing.T) {
+ noMinorHash := []byte("$2$10$XajjQvNhvvRt5GSeFk1xFeyqRrsxkhBkUiQeg0dt.wU1qD4aFDcga")
+ h, err := newFromHash(noMinorHash)
+ if err != nil {
+ t.Fatalf("No minor hash blew up: %s", err)
+ }
+ if h.minor != 0 {
+ t.Errorf("Should leave minor version at 0, but was %d", h.minor)
+ }
+
+ if !bytes.Equal(noMinorHash, h.Hash()) {
+ t.Errorf("Should generate hash %v, but created %v", noMinorHash, h.Hash())
+ }
+}
+
+func BenchmarkEqual(b *testing.B) {
+ b.StopTimer()
+ passwd := []byte("somepasswordyoulike")
+ hash, _ := GenerateFromPassword(passwd, 10)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ CompareHashAndPassword(hash, passwd)
+ }
+}
+
+func BenchmarkGeneration(b *testing.B) {
+ b.StopTimer()
+ passwd := []byte("mylongpassword1234")
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ GenerateFromPassword(passwd, 10)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/blowfish/blowfish_test.go b/vendor/golang.org/x/crypto/blowfish/blowfish_test.go
new file mode 100644
index 000000000..7afa1fdf3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/blowfish/blowfish_test.go
@@ -0,0 +1,274 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+import "testing"
+
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+// Test vector values are from http://www.schneier.com/code/vectors.txt.
+var encryptTests = []CryptTest{
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+ {
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x51, 0x86, 0x6F, 0xD5, 0xB8, 0x5E, 0xCB, 0x8A}},
+ {
+ []byte{0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ []byte{0x7D, 0x85, 0x6F, 0x9A, 0x61, 0x30, 0x63, 0xF2}},
+ {
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x24, 0x66, 0xDD, 0x87, 0x8B, 0x96, 0x3C, 0x9D}},
+
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x61, 0xF9, 0xC3, 0x80, 0x22, 0x81, 0xB0, 0x96}},
+ {
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x7D, 0x0C, 0xC6, 0x30, 0xAF, 0xDA, 0x1E, 0xC7}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78}},
+ {
+ []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x0A, 0xCE, 0xAB, 0x0F, 0xC6, 0xA0, 0xA2, 0x8D}},
+ {
+ []byte{0x7C, 0xA1, 0x10, 0x45, 0x4A, 0x1A, 0x6E, 0x57},
+ []byte{0x01, 0xA1, 0xD6, 0xD0, 0x39, 0x77, 0x67, 0x42},
+ []byte{0x59, 0xC6, 0x82, 0x45, 0xEB, 0x05, 0x28, 0x2B}},
+ {
+ []byte{0x01, 0x31, 0xD9, 0x61, 0x9D, 0xC1, 0x37, 0x6E},
+ []byte{0x5C, 0xD5, 0x4C, 0xA8, 0x3D, 0xEF, 0x57, 0xDA},
+ []byte{0xB1, 0xB8, 0xCC, 0x0B, 0x25, 0x0F, 0x09, 0xA0}},
+ {
+ []byte{0x07, 0xA1, 0x13, 0x3E, 0x4A, 0x0B, 0x26, 0x86},
+ []byte{0x02, 0x48, 0xD4, 0x38, 0x06, 0xF6, 0x71, 0x72},
+ []byte{0x17, 0x30, 0xE5, 0x77, 0x8B, 0xEA, 0x1D, 0xA4}},
+ {
+ []byte{0x38, 0x49, 0x67, 0x4C, 0x26, 0x02, 0x31, 0x9E},
+ []byte{0x51, 0x45, 0x4B, 0x58, 0x2D, 0xDF, 0x44, 0x0A},
+ []byte{0xA2, 0x5E, 0x78, 0x56, 0xCF, 0x26, 0x51, 0xEB}},
+ {
+ []byte{0x04, 0xB9, 0x15, 0xBA, 0x43, 0xFE, 0xB5, 0xB6},
+ []byte{0x42, 0xFD, 0x44, 0x30, 0x59, 0x57, 0x7F, 0xA2},
+ []byte{0x35, 0x38, 0x82, 0xB1, 0x09, 0xCE, 0x8F, 0x1A}},
+ {
+ []byte{0x01, 0x13, 0xB9, 0x70, 0xFD, 0x34, 0xF2, 0xCE},
+ []byte{0x05, 0x9B, 0x5E, 0x08, 0x51, 0xCF, 0x14, 0x3A},
+ []byte{0x48, 0xF4, 0xD0, 0x88, 0x4C, 0x37, 0x99, 0x18}},
+ {
+ []byte{0x01, 0x70, 0xF1, 0x75, 0x46, 0x8F, 0xB5, 0xE6},
+ []byte{0x07, 0x56, 0xD8, 0xE0, 0x77, 0x47, 0x61, 0xD2},
+ []byte{0x43, 0x21, 0x93, 0xB7, 0x89, 0x51, 0xFC, 0x98}},
+ {
+ []byte{0x43, 0x29, 0x7F, 0xAD, 0x38, 0xE3, 0x73, 0xFE},
+ []byte{0x76, 0x25, 0x14, 0xB8, 0x29, 0xBF, 0x48, 0x6A},
+ []byte{0x13, 0xF0, 0x41, 0x54, 0xD6, 0x9D, 0x1A, 0xE5}},
+ {
+ []byte{0x07, 0xA7, 0x13, 0x70, 0x45, 0xDA, 0x2A, 0x16},
+ []byte{0x3B, 0xDD, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+ []byte{0x2E, 0xED, 0xDA, 0x93, 0xFF, 0xD3, 0x9C, 0x79}},
+ {
+ []byte{0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F},
+ []byte{0x26, 0x95, 0x5F, 0x68, 0x35, 0xAF, 0x60, 0x9A},
+ []byte{0xD8, 0x87, 0xE0, 0x39, 0x3C, 0x2D, 0xA6, 0xE3}},
+ {
+ []byte{0x37, 0xD0, 0x6B, 0xB5, 0x16, 0xCB, 0x75, 0x46},
+ []byte{0x16, 0x4D, 0x5E, 0x40, 0x4F, 0x27, 0x52, 0x32},
+ []byte{0x5F, 0x99, 0xD0, 0x4F, 0x5B, 0x16, 0x39, 0x69}},
+ {
+ []byte{0x1F, 0x08, 0x26, 0x0D, 0x1A, 0xC2, 0x46, 0x5E},
+ []byte{0x6B, 0x05, 0x6E, 0x18, 0x75, 0x9F, 0x5C, 0xCA},
+ []byte{0x4A, 0x05, 0x7A, 0x3B, 0x24, 0xD3, 0x97, 0x7B}},
+ {
+ []byte{0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76},
+ []byte{0x00, 0x4B, 0xD6, 0xEF, 0x09, 0x17, 0x60, 0x62},
+ []byte{0x45, 0x20, 0x31, 0xC1, 0xE4, 0xFA, 0xDA, 0x8E}},
+ {
+ []byte{0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xB0, 0x07},
+ []byte{0x48, 0x0D, 0x39, 0x00, 0x6E, 0xE7, 0x62, 0xF2},
+ []byte{0x75, 0x55, 0xAE, 0x39, 0xF5, 0x9B, 0x87, 0xBD}},
+ {
+ []byte{0x49, 0x79, 0x3E, 0xBC, 0x79, 0xB3, 0x25, 0x8F},
+ []byte{0x43, 0x75, 0x40, 0xC8, 0x69, 0x8F, 0x3C, 0xFA},
+ []byte{0x53, 0xC5, 0x5F, 0x9C, 0xB4, 0x9F, 0xC0, 0x19}},
+ {
+ []byte{0x4F, 0xB0, 0x5E, 0x15, 0x15, 0xAB, 0x73, 0xA7},
+ []byte{0x07, 0x2D, 0x43, 0xA0, 0x77, 0x07, 0x52, 0x92},
+ []byte{0x7A, 0x8E, 0x7B, 0xFA, 0x93, 0x7E, 0x89, 0xA3}},
+ {
+ []byte{0x49, 0xE9, 0x5D, 0x6D, 0x4C, 0xA2, 0x29, 0xBF},
+ []byte{0x02, 0xFE, 0x55, 0x77, 0x81, 0x17, 0xF1, 0x2A},
+ []byte{0xCF, 0x9C, 0x5D, 0x7A, 0x49, 0x86, 0xAD, 0xB5}},
+ {
+ []byte{0x01, 0x83, 0x10, 0xDC, 0x40, 0x9B, 0x26, 0xD6},
+ []byte{0x1D, 0x9D, 0x5C, 0x50, 0x18, 0xF7, 0x28, 0xC2},
+ []byte{0xD1, 0xAB, 0xB2, 0x90, 0x65, 0x8B, 0xC7, 0x78}},
+ {
+ []byte{0x1C, 0x58, 0x7F, 0x1C, 0x13, 0x92, 0x4F, 0xEF},
+ []byte{0x30, 0x55, 0x32, 0x28, 0x6D, 0x6F, 0x29, 0x5A},
+ []byte{0x55, 0xCB, 0x37, 0x74, 0xD1, 0x3E, 0xF2, 0x01}},
+ {
+ []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xFA, 0x34, 0xEC, 0x48, 0x47, 0xB2, 0x68, 0xB2}},
+ {
+ []byte{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE}},
+ {
+ []byte{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0xC3, 0x9E, 0x07, 0x2D, 0x9F, 0xAC, 0x63, 0x1D}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x01, 0x49, 0x33, 0xE0, 0xCD, 0xAF, 0xF6, 0xE4}},
+ {
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xF2, 0x1E, 0x9A, 0x77, 0xB7, 0x1C, 0x49, 0xBC}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x24, 0x59, 0x46, 0x88, 0x57, 0x54, 0x36, 0x9A}},
+ {
+ []byte{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ []byte{0x6B, 0x5C, 0x5A, 0x9C, 0x5D, 0x9E, 0x0A, 0x5A}},
+}
+
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ ct := make([]byte, len(tt.out))
+ c.Encrypt(ct, tt.in)
+ for j, v := range ct {
+ if v != tt.out[j] {
+ t.Errorf("Cipher.Encrypt, test vector #%d: cipher-text[%d] = %#x, expected %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ pt := make([]byte, len(tt.in))
+ c.Decrypt(pt, tt.out)
+ for j, v := range pt {
+ if v != tt.in[j] {
+ t.Errorf("Cipher.Decrypt, test vector #%d: plain-text[%d] = %#x, expected %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
+
+func TestSaltedCipherKeyLength(t *testing.T) {
+ if _, err := NewSaltedCipher(nil, []byte{'a'}); err != KeySizeError(0) {
+ t.Errorf("NewSaltedCipher with short key, gave error %#v, expected %#v", err, KeySizeError(0))
+ }
+
+ // A 57-byte key. One over the typical blowfish restriction.
+ key := []byte("012345678901234567890123456789012345678901234567890123456")
+ if _, err := NewSaltedCipher(key, []byte{'a'}); err != nil {
+ t.Errorf("NewSaltedCipher with long key, gave error %#v", err)
+ }
+}
+
+// Test vectors generated with Blowfish from OpenSSH.
+var saltedVectors = [][8]byte{
+ {0x0c, 0x82, 0x3b, 0x7b, 0x8d, 0x01, 0x4b, 0x7e},
+ {0xd1, 0xe1, 0x93, 0xf0, 0x70, 0xa6, 0xdb, 0x12},
+ {0xfc, 0x5e, 0xba, 0xde, 0xcb, 0xf8, 0x59, 0xad},
+ {0x8a, 0x0c, 0x76, 0xe7, 0xdd, 0x2c, 0xd3, 0xa8},
+ {0x2c, 0xcb, 0x7b, 0xee, 0xac, 0x7b, 0x7f, 0xf8},
+ {0xbb, 0xf6, 0x30, 0x6f, 0xe1, 0x5d, 0x62, 0xbf},
+ {0x97, 0x1e, 0xc1, 0x3d, 0x3d, 0xe0, 0x11, 0xe9},
+ {0x06, 0xd7, 0x4d, 0xb1, 0x80, 0xa3, 0xb1, 0x38},
+ {0x67, 0xa1, 0xa9, 0x75, 0x0e, 0x5b, 0xc6, 0xb4},
+ {0x51, 0x0f, 0x33, 0x0e, 0x4f, 0x67, 0xd2, 0x0c},
+ {0xf1, 0x73, 0x7e, 0xd8, 0x44, 0xea, 0xdb, 0xe5},
+ {0x14, 0x0e, 0x16, 0xce, 0x7f, 0x4a, 0x9c, 0x7b},
+ {0x4b, 0xfe, 0x43, 0xfd, 0xbf, 0x36, 0x04, 0x47},
+ {0xb1, 0xeb, 0x3e, 0x15, 0x36, 0xa7, 0xbb, 0xe2},
+ {0x6d, 0x0b, 0x41, 0xdd, 0x00, 0x98, 0x0b, 0x19},
+ {0xd3, 0xce, 0x45, 0xce, 0x1d, 0x56, 0xb7, 0xfc},
+ {0xd9, 0xf0, 0xfd, 0xda, 0xc0, 0x23, 0xb7, 0x93},
+ {0x4c, 0x6f, 0xa1, 0xe4, 0x0c, 0xa8, 0xca, 0x57},
+ {0xe6, 0x2f, 0x28, 0xa7, 0x0c, 0x94, 0x0d, 0x08},
+ {0x8f, 0xe3, 0xf0, 0xb6, 0x29, 0xe3, 0x44, 0x03},
+ {0xff, 0x98, 0xdd, 0x04, 0x45, 0xb4, 0x6d, 0x1f},
+ {0x9e, 0x45, 0x4d, 0x18, 0x40, 0x53, 0xdb, 0xef},
+ {0xb7, 0x3b, 0xef, 0x29, 0xbe, 0xa8, 0x13, 0x71},
+ {0x02, 0x54, 0x55, 0x41, 0x8e, 0x04, 0xfc, 0xad},
+ {0x6a, 0x0a, 0xee, 0x7c, 0x10, 0xd9, 0x19, 0xfe},
+ {0x0a, 0x22, 0xd9, 0x41, 0xcc, 0x23, 0x87, 0x13},
+ {0x6e, 0xff, 0x1f, 0xff, 0x36, 0x17, 0x9c, 0xbe},
+ {0x79, 0xad, 0xb7, 0x40, 0xf4, 0x9f, 0x51, 0xa6},
+ {0x97, 0x81, 0x99, 0xa4, 0xde, 0x9e, 0x9f, 0xb6},
+ {0x12, 0x19, 0x7a, 0x28, 0xd0, 0xdc, 0xcc, 0x92},
+ {0x81, 0xda, 0x60, 0x1e, 0x0e, 0xdd, 0x65, 0x56},
+ {0x7d, 0x76, 0x20, 0xb2, 0x73, 0xc9, 0x9e, 0xee},
+}
+
+func TestSaltedCipher(t *testing.T) {
+ var key, salt [32]byte
+ for i := range key {
+ key[i] = byte(i)
+ salt[i] = byte(i + 32)
+ }
+ for i, v := range saltedVectors {
+ c, err := NewSaltedCipher(key[:], salt[:i])
+ if err != nil {
+ t.Fatal(err)
+ }
+ var buf [8]byte
+ c.Encrypt(buf[:], buf[:])
+ if v != buf {
+ t.Errorf("%d: expected %x, got %x", i, v, buf)
+ }
+ }
+}
+
+func BenchmarkExpandKeyWithSalt(b *testing.B) {
+ key := make([]byte, 32)
+ salt := make([]byte, 16)
+ c, _ := NewCipher(key)
+ for i := 0; i < b.N; i++ {
+ expandKeyWithSalt(key, salt, c)
+ }
+}
+
+func BenchmarkExpandKey(b *testing.B) {
+ key := make([]byte, 32)
+ c, _ := NewCipher(key)
+ for i := 0; i < b.N; i++ {
+ ExpandKey(key, c)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/blowfish/cipher.go b/vendor/golang.org/x/crypto/blowfish/cipher.go
index 5019658a4..542984aa8 100644
--- a/vendor/golang.org/x/crypto/blowfish/cipher.go
+++ b/vendor/golang.org/x/crypto/blowfish/cipher.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
-package blowfish
+package blowfish // import "golang.org/x/crypto/blowfish"
// The code is a port of Bruce Schneier's C implementation.
// See http://www.schneier.com/blowfish.html.
diff --git a/vendor/golang.org/x/crypto/bn256/bn256.go b/vendor/golang.org/x/crypto/bn256/bn256.go
new file mode 100644
index 000000000..014f8b355
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/bn256.go
@@ -0,0 +1,404 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bn256 implements a particular bilinear group at the 128-bit security level.
+//
+// Bilinear groups are the basis of many of the new cryptographic protocols
+// that have been proposed over the past decade. They consist of a triplet of
+// groups (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ
+// (where gₓ is a generator of the respective group). That function is called
+// a pairing function.
+//
+// This package specifically implements the Optimal Ate pairing over a 256-bit
+// Barreto-Naehrig curve as described in
+// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible
+// with the implementation described in that paper.
+package bn256 // import "golang.org/x/crypto/bn256"
+
+import (
+ "crypto/rand"
+ "io"
+ "math/big"
+)
+
+// BUG(agl): this implementation is not constant time.
+// TODO(agl): keep GF(p²) elements in Mongomery form.
+
+// G1 is an abstract cyclic group. The zero value is suitable for use as the
+// output of an operation, but cannot be used as an input.
+type G1 struct {
+ p *curvePoint
+}
+
+// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r.
+func RandomG1(r io.Reader) (*big.Int, *G1, error) {
+ var k *big.Int
+ var err error
+
+ for {
+ k, err = rand.Int(r, Order)
+ if err != nil {
+ return nil, nil, err
+ }
+ if k.Sign() > 0 {
+ break
+ }
+ }
+
+ return k, new(G1).ScalarBaseMult(k), nil
+}
+
+func (g *G1) String() string {
+ return "bn256.G1" + g.p.String()
+}
+
+// ScalarBaseMult sets e to g*k where g is the generator of the group and
+// then returns e.
+func (e *G1) ScalarBaseMult(k *big.Int) *G1 {
+ if e.p == nil {
+ e.p = newCurvePoint(nil)
+ }
+ e.p.Mul(curveGen, k, new(bnPool))
+ return e
+}
+
+// ScalarMult sets e to a*k and then returns e.
+func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 {
+ if e.p == nil {
+ e.p = newCurvePoint(nil)
+ }
+ e.p.Mul(a.p, k, new(bnPool))
+ return e
+}
+
+// Add sets e to a+b and then returns e.
+// BUG(agl): this function is not complete: a==b fails.
+func (e *G1) Add(a, b *G1) *G1 {
+ if e.p == nil {
+ e.p = newCurvePoint(nil)
+ }
+ e.p.Add(a.p, b.p, new(bnPool))
+ return e
+}
+
+// Neg sets e to -a and then returns e.
+func (e *G1) Neg(a *G1) *G1 {
+ if e.p == nil {
+ e.p = newCurvePoint(nil)
+ }
+ e.p.Negative(a.p)
+ return e
+}
+
+// Marshal converts n to a byte slice.
+func (n *G1) Marshal() []byte {
+ n.p.MakeAffine(nil)
+
+ xBytes := new(big.Int).Mod(n.p.x, p).Bytes()
+ yBytes := new(big.Int).Mod(n.p.y, p).Bytes()
+
+ // Each value is a 256-bit number.
+ const numBytes = 256 / 8
+
+ ret := make([]byte, numBytes*2)
+ copy(ret[1*numBytes-len(xBytes):], xBytes)
+ copy(ret[2*numBytes-len(yBytes):], yBytes)
+
+ return ret
+}
+
+// Unmarshal sets e to the result of converting the output of Marshal back into
+// a group element and then returns e.
+func (e *G1) Unmarshal(m []byte) (*G1, bool) {
+ // Each value is a 256-bit number.
+ const numBytes = 256 / 8
+
+ if len(m) != 2*numBytes {
+ return nil, false
+ }
+
+ if e.p == nil {
+ e.p = newCurvePoint(nil)
+ }
+
+ e.p.x.SetBytes(m[0*numBytes : 1*numBytes])
+ e.p.y.SetBytes(m[1*numBytes : 2*numBytes])
+
+ if e.p.x.Sign() == 0 && e.p.y.Sign() == 0 {
+ // This is the point at infinity.
+ e.p.y.SetInt64(1)
+ e.p.z.SetInt64(0)
+ e.p.t.SetInt64(0)
+ } else {
+ e.p.z.SetInt64(1)
+ e.p.t.SetInt64(1)
+
+ if !e.p.IsOnCurve() {
+ return nil, false
+ }
+ }
+
+ return e, true
+}
+
+// G2 is an abstract cyclic group. The zero value is suitable for use as the
+// output of an operation, but cannot be used as an input.
+type G2 struct {
+ p *twistPoint
+}
+
+// RandomG1 returns x and g₂ˣ where x is a random, non-zero number read from r.
+func RandomG2(r io.Reader) (*big.Int, *G2, error) {
+ var k *big.Int
+ var err error
+
+ for {
+ k, err = rand.Int(r, Order)
+ if err != nil {
+ return nil, nil, err
+ }
+ if k.Sign() > 0 {
+ break
+ }
+ }
+
+ return k, new(G2).ScalarBaseMult(k), nil
+}
+
+func (g *G2) String() string {
+ return "bn256.G2" + g.p.String()
+}
+
+// ScalarBaseMult sets e to g*k where g is the generator of the group and
+// then returns out.
+func (e *G2) ScalarBaseMult(k *big.Int) *G2 {
+ if e.p == nil {
+ e.p = newTwistPoint(nil)
+ }
+ e.p.Mul(twistGen, k, new(bnPool))
+ return e
+}
+
+// ScalarMult sets e to a*k and then returns e.
+func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 {
+ if e.p == nil {
+ e.p = newTwistPoint(nil)
+ }
+ e.p.Mul(a.p, k, new(bnPool))
+ return e
+}
+
+// Add sets e to a+b and then returns e.
+// BUG(agl): this function is not complete: a==b fails.
+func (e *G2) Add(a, b *G2) *G2 {
+ if e.p == nil {
+ e.p = newTwistPoint(nil)
+ }
+ e.p.Add(a.p, b.p, new(bnPool))
+ return e
+}
+
+// Marshal converts n into a byte slice.
+func (n *G2) Marshal() []byte {
+ n.p.MakeAffine(nil)
+
+ xxBytes := new(big.Int).Mod(n.p.x.x, p).Bytes()
+ xyBytes := new(big.Int).Mod(n.p.x.y, p).Bytes()
+ yxBytes := new(big.Int).Mod(n.p.y.x, p).Bytes()
+ yyBytes := new(big.Int).Mod(n.p.y.y, p).Bytes()
+
+ // Each value is a 256-bit number.
+ const numBytes = 256 / 8
+
+ ret := make([]byte, numBytes*4)
+ copy(ret[1*numBytes-len(xxBytes):], xxBytes)
+ copy(ret[2*numBytes-len(xyBytes):], xyBytes)
+ copy(ret[3*numBytes-len(yxBytes):], yxBytes)
+ copy(ret[4*numBytes-len(yyBytes):], yyBytes)
+
+ return ret
+}
+
+// Unmarshal sets e to the result of converting the output of Marshal back into
+// a group element and then returns e.
+func (e *G2) Unmarshal(m []byte) (*G2, bool) {
+ // Each value is a 256-bit number.
+ const numBytes = 256 / 8
+
+ if len(m) != 4*numBytes {
+ return nil, false
+ }
+
+ if e.p == nil {
+ e.p = newTwistPoint(nil)
+ }
+
+ e.p.x.x.SetBytes(m[0*numBytes : 1*numBytes])
+ e.p.x.y.SetBytes(m[1*numBytes : 2*numBytes])
+ e.p.y.x.SetBytes(m[2*numBytes : 3*numBytes])
+ e.p.y.y.SetBytes(m[3*numBytes : 4*numBytes])
+
+ if e.p.x.x.Sign() == 0 &&
+ e.p.x.y.Sign() == 0 &&
+ e.p.y.x.Sign() == 0 &&
+ e.p.y.y.Sign() == 0 {
+ // This is the point at infinity.
+ e.p.y.SetOne()
+ e.p.z.SetZero()
+ e.p.t.SetZero()
+ } else {
+ e.p.z.SetOne()
+ e.p.t.SetOne()
+
+ if !e.p.IsOnCurve() {
+ return nil, false
+ }
+ }
+
+ return e, true
+}
+
+// GT is an abstract cyclic group. The zero value is suitable for use as the
+// output of an operation, but cannot be used as an input.
+type GT struct {
+ p *gfP12
+}
+
+func (g *GT) String() string {
+ return "bn256.GT" + g.p.String()
+}
+
+// ScalarMult sets e to a*k and then returns e.
+func (e *GT) ScalarMult(a *GT, k *big.Int) *GT {
+ if e.p == nil {
+ e.p = newGFp12(nil)
+ }
+ e.p.Exp(a.p, k, new(bnPool))
+ return e
+}
+
+// Add sets e to a+b and then returns e.
+func (e *GT) Add(a, b *GT) *GT {
+ if e.p == nil {
+ e.p = newGFp12(nil)
+ }
+ e.p.Mul(a.p, b.p, new(bnPool))
+ return e
+}
+
+// Neg sets e to -a and then returns e.
+func (e *GT) Neg(a *GT) *GT {
+ if e.p == nil {
+ e.p = newGFp12(nil)
+ }
+ e.p.Invert(a.p, new(bnPool))
+ return e
+}
+
+// Marshal converts n into a byte slice.
+func (n *GT) Marshal() []byte {
+ n.p.Minimal()
+
+ xxxBytes := n.p.x.x.x.Bytes()
+ xxyBytes := n.p.x.x.y.Bytes()
+ xyxBytes := n.p.x.y.x.Bytes()
+ xyyBytes := n.p.x.y.y.Bytes()
+ xzxBytes := n.p.x.z.x.Bytes()
+ xzyBytes := n.p.x.z.y.Bytes()
+ yxxBytes := n.p.y.x.x.Bytes()
+ yxyBytes := n.p.y.x.y.Bytes()
+ yyxBytes := n.p.y.y.x.Bytes()
+ yyyBytes := n.p.y.y.y.Bytes()
+ yzxBytes := n.p.y.z.x.Bytes()
+ yzyBytes := n.p.y.z.y.Bytes()
+
+ // Each value is a 256-bit number.
+ const numBytes = 256 / 8
+
+ ret := make([]byte, numBytes*12)
+ copy(ret[1*numBytes-len(xxxBytes):], xxxBytes)
+ copy(ret[2*numBytes-len(xxyBytes):], xxyBytes)
+ copy(ret[3*numBytes-len(xyxBytes):], xyxBytes)
+ copy(ret[4*numBytes-len(xyyBytes):], xyyBytes)
+ copy(ret[5*numBytes-len(xzxBytes):], xzxBytes)
+ copy(ret[6*numBytes-len(xzyBytes):], xzyBytes)
+ copy(ret[7*numBytes-len(yxxBytes):], yxxBytes)
+ copy(ret[8*numBytes-len(yxyBytes):], yxyBytes)
+ copy(ret[9*numBytes-len(yyxBytes):], yyxBytes)
+ copy(ret[10*numBytes-len(yyyBytes):], yyyBytes)
+ copy(ret[11*numBytes-len(yzxBytes):], yzxBytes)
+ copy(ret[12*numBytes-len(yzyBytes):], yzyBytes)
+
+ return ret
+}
+
+// Unmarshal sets e to the result of converting the output of Marshal back into
+// a group element and then returns e.
+func (e *GT) Unmarshal(m []byte) (*GT, bool) {
+ // Each value is a 256-bit number.
+ const numBytes = 256 / 8
+
+ if len(m) != 12*numBytes {
+ return nil, false
+ }
+
+ if e.p == nil {
+ e.p = newGFp12(nil)
+ }
+
+ e.p.x.x.x.SetBytes(m[0*numBytes : 1*numBytes])
+ e.p.x.x.y.SetBytes(m[1*numBytes : 2*numBytes])
+ e.p.x.y.x.SetBytes(m[2*numBytes : 3*numBytes])
+ e.p.x.y.y.SetBytes(m[3*numBytes : 4*numBytes])
+ e.p.x.z.x.SetBytes(m[4*numBytes : 5*numBytes])
+ e.p.x.z.y.SetBytes(m[5*numBytes : 6*numBytes])
+ e.p.y.x.x.SetBytes(m[6*numBytes : 7*numBytes])
+ e.p.y.x.y.SetBytes(m[7*numBytes : 8*numBytes])
+ e.p.y.y.x.SetBytes(m[8*numBytes : 9*numBytes])
+ e.p.y.y.y.SetBytes(m[9*numBytes : 10*numBytes])
+ e.p.y.z.x.SetBytes(m[10*numBytes : 11*numBytes])
+ e.p.y.z.y.SetBytes(m[11*numBytes : 12*numBytes])
+
+ return e, true
+}
+
+// Pair calculates an Optimal Ate pairing.
+func Pair(g1 *G1, g2 *G2) *GT {
+ return &GT{optimalAte(g2.p, g1.p, new(bnPool))}
+}
+
+// bnPool implements a tiny cache of *big.Int objects that's used to reduce the
+// number of allocations made during processing.
+type bnPool struct {
+ bns []*big.Int
+ count int
+}
+
+func (pool *bnPool) Get() *big.Int {
+ if pool == nil {
+ return new(big.Int)
+ }
+
+ pool.count++
+ l := len(pool.bns)
+ if l == 0 {
+ return new(big.Int)
+ }
+
+ bn := pool.bns[l-1]
+ pool.bns = pool.bns[:l-1]
+ return bn
+}
+
+func (pool *bnPool) Put(bn *big.Int) {
+ if pool == nil {
+ return
+ }
+ pool.bns = append(pool.bns, bn)
+ pool.count--
+}
+
+func (pool *bnPool) Count() int {
+ return pool.count
+}
diff --git a/vendor/golang.org/x/crypto/bn256/bn256_test.go b/vendor/golang.org/x/crypto/bn256/bn256_test.go
new file mode 100644
index 000000000..1cec3884e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/bn256_test.go
@@ -0,0 +1,304 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+ "bytes"
+ "crypto/rand"
+ "math/big"
+ "testing"
+)
+
+func TestGFp2Invert(t *testing.T) {
+ pool := new(bnPool)
+
+ a := newGFp2(pool)
+ a.x.SetString("23423492374", 10)
+ a.y.SetString("12934872398472394827398470", 10)
+
+ inv := newGFp2(pool)
+ inv.Invert(a, pool)
+
+ b := newGFp2(pool).Mul(inv, a, pool)
+ if b.x.Int64() != 0 || b.y.Int64() != 1 {
+ t.Fatalf("bad result for a^-1*a: %s %s", b.x, b.y)
+ }
+
+ a.Put(pool)
+ b.Put(pool)
+ inv.Put(pool)
+
+ if c := pool.Count(); c > 0 {
+ t.Errorf("Pool count non-zero: %d\n", c)
+ }
+}
+
+func isZero(n *big.Int) bool {
+ return new(big.Int).Mod(n, p).Int64() == 0
+}
+
+func isOne(n *big.Int) bool {
+ return new(big.Int).Mod(n, p).Int64() == 1
+}
+
+func TestGFp6Invert(t *testing.T) {
+ pool := new(bnPool)
+
+ a := newGFp6(pool)
+ a.x.x.SetString("239487238491", 10)
+ a.x.y.SetString("2356249827341", 10)
+ a.y.x.SetString("082659782", 10)
+ a.y.y.SetString("182703523765", 10)
+ a.z.x.SetString("978236549263", 10)
+ a.z.y.SetString("64893242", 10)
+
+ inv := newGFp6(pool)
+ inv.Invert(a, pool)
+
+ b := newGFp6(pool).Mul(inv, a, pool)
+ if !isZero(b.x.x) ||
+ !isZero(b.x.y) ||
+ !isZero(b.y.x) ||
+ !isZero(b.y.y) ||
+ !isZero(b.z.x) ||
+ !isOne(b.z.y) {
+ t.Fatalf("bad result for a^-1*a: %s", b)
+ }
+
+ a.Put(pool)
+ b.Put(pool)
+ inv.Put(pool)
+
+ if c := pool.Count(); c > 0 {
+ t.Errorf("Pool count non-zero: %d\n", c)
+ }
+}
+
+func TestGFp12Invert(t *testing.T) {
+ pool := new(bnPool)
+
+ a := newGFp12(pool)
+ a.x.x.x.SetString("239846234862342323958623", 10)
+ a.x.x.y.SetString("2359862352529835623", 10)
+ a.x.y.x.SetString("928836523", 10)
+ a.x.y.y.SetString("9856234", 10)
+ a.x.z.x.SetString("235635286", 10)
+ a.x.z.y.SetString("5628392833", 10)
+ a.y.x.x.SetString("252936598265329856238956532167968", 10)
+ a.y.x.y.SetString("23596239865236954178968", 10)
+ a.y.y.x.SetString("95421692834", 10)
+ a.y.y.y.SetString("236548", 10)
+ a.y.z.x.SetString("924523", 10)
+ a.y.z.y.SetString("12954623", 10)
+
+ inv := newGFp12(pool)
+ inv.Invert(a, pool)
+
+ b := newGFp12(pool).Mul(inv, a, pool)
+ if !isZero(b.x.x.x) ||
+ !isZero(b.x.x.y) ||
+ !isZero(b.x.y.x) ||
+ !isZero(b.x.y.y) ||
+ !isZero(b.x.z.x) ||
+ !isZero(b.x.z.y) ||
+ !isZero(b.y.x.x) ||
+ !isZero(b.y.x.y) ||
+ !isZero(b.y.y.x) ||
+ !isZero(b.y.y.y) ||
+ !isZero(b.y.z.x) ||
+ !isOne(b.y.z.y) {
+ t.Fatalf("bad result for a^-1*a: %s", b)
+ }
+
+ a.Put(pool)
+ b.Put(pool)
+ inv.Put(pool)
+
+ if c := pool.Count(); c > 0 {
+ t.Errorf("Pool count non-zero: %d\n", c)
+ }
+}
+
+func TestCurveImpl(t *testing.T) {
+ pool := new(bnPool)
+
+ g := &curvePoint{
+ pool.Get().SetInt64(1),
+ pool.Get().SetInt64(-2),
+ pool.Get().SetInt64(1),
+ pool.Get().SetInt64(0),
+ }
+
+ x := pool.Get().SetInt64(32498273234)
+ X := newCurvePoint(pool).Mul(g, x, pool)
+
+ y := pool.Get().SetInt64(98732423523)
+ Y := newCurvePoint(pool).Mul(g, y, pool)
+
+ s1 := newCurvePoint(pool).Mul(X, y, pool).MakeAffine(pool)
+ s2 := newCurvePoint(pool).Mul(Y, x, pool).MakeAffine(pool)
+
+ if s1.x.Cmp(s2.x) != 0 ||
+ s2.x.Cmp(s1.x) != 0 {
+ t.Errorf("DH points don't match: (%s, %s) (%s, %s)", s1.x, s1.y, s2.x, s2.y)
+ }
+
+ pool.Put(x)
+ X.Put(pool)
+ pool.Put(y)
+ Y.Put(pool)
+ s1.Put(pool)
+ s2.Put(pool)
+ g.Put(pool)
+
+ if c := pool.Count(); c > 0 {
+ t.Errorf("Pool count non-zero: %d\n", c)
+ }
+}
+
+func TestOrderG1(t *testing.T) {
+ g := new(G1).ScalarBaseMult(Order)
+ if !g.p.IsInfinity() {
+ t.Error("G1 has incorrect order")
+ }
+
+ one := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
+ g.Add(g, one)
+ g.p.MakeAffine(nil)
+ if g.p.x.Cmp(one.p.x) != 0 || g.p.y.Cmp(one.p.y) != 0 {
+ t.Errorf("1+0 != 1 in G1")
+ }
+}
+
+func TestOrderG2(t *testing.T) {
+ g := new(G2).ScalarBaseMult(Order)
+ if !g.p.IsInfinity() {
+ t.Error("G2 has incorrect order")
+ }
+
+ one := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
+ g.Add(g, one)
+ g.p.MakeAffine(nil)
+ if g.p.x.x.Cmp(one.p.x.x) != 0 ||
+ g.p.x.y.Cmp(one.p.x.y) != 0 ||
+ g.p.y.x.Cmp(one.p.y.x) != 0 ||
+ g.p.y.y.Cmp(one.p.y.y) != 0 {
+ t.Errorf("1+0 != 1 in G2")
+ }
+}
+
+func TestOrderGT(t *testing.T) {
+ gt := Pair(&G1{curveGen}, &G2{twistGen})
+ g := new(GT).ScalarMult(gt, Order)
+ if !g.p.IsOne() {
+ t.Error("GT has incorrect order")
+ }
+}
+
+func TestBilinearity(t *testing.T) {
+ for i := 0; i < 2; i++ {
+ a, p1, _ := RandomG1(rand.Reader)
+ b, p2, _ := RandomG2(rand.Reader)
+ e1 := Pair(p1, p2)
+
+ e2 := Pair(&G1{curveGen}, &G2{twistGen})
+ e2.ScalarMult(e2, a)
+ e2.ScalarMult(e2, b)
+
+ minusE2 := new(GT).Neg(e2)
+ e1.Add(e1, minusE2)
+
+ if !e1.p.IsOne() {
+ t.Fatalf("bad pairing result: %s", e1)
+ }
+ }
+}
+
+func TestG1Marshal(t *testing.T) {
+ g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1))
+ form := g.Marshal()
+ _, ok := new(G1).Unmarshal(form)
+ if !ok {
+ t.Fatalf("failed to unmarshal")
+ }
+
+ g.ScalarBaseMult(Order)
+ form = g.Marshal()
+ g2, ok := new(G1).Unmarshal(form)
+ if !ok {
+ t.Fatalf("failed to unmarshal ∞")
+ }
+ if !g2.p.IsInfinity() {
+ t.Fatalf("∞ unmarshaled incorrectly")
+ }
+}
+
+func TestG2Marshal(t *testing.T) {
+ g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1))
+ form := g.Marshal()
+ _, ok := new(G2).Unmarshal(form)
+ if !ok {
+ t.Fatalf("failed to unmarshal")
+ }
+
+ g.ScalarBaseMult(Order)
+ form = g.Marshal()
+ g2, ok := new(G2).Unmarshal(form)
+ if !ok {
+ t.Fatalf("failed to unmarshal ∞")
+ }
+ if !g2.p.IsInfinity() {
+ t.Fatalf("∞ unmarshaled incorrectly")
+ }
+}
+
+func TestG1Identity(t *testing.T) {
+ g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(0))
+ if !g.p.IsInfinity() {
+ t.Error("failure")
+ }
+}
+
+func TestG2Identity(t *testing.T) {
+ g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(0))
+ if !g.p.IsInfinity() {
+ t.Error("failure")
+ }
+}
+
+func TestTripartiteDiffieHellman(t *testing.T) {
+ a, _ := rand.Int(rand.Reader, Order)
+ b, _ := rand.Int(rand.Reader, Order)
+ c, _ := rand.Int(rand.Reader, Order)
+
+ pa, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(a).Marshal())
+ qa, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(a).Marshal())
+ pb, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(b).Marshal())
+ qb, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(b).Marshal())
+ pc, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(c).Marshal())
+ qc, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(c).Marshal())
+
+ k1 := Pair(pb, qc)
+ k1.ScalarMult(k1, a)
+ k1Bytes := k1.Marshal()
+
+ k2 := Pair(pc, qa)
+ k2.ScalarMult(k2, b)
+ k2Bytes := k2.Marshal()
+
+ k3 := Pair(pa, qb)
+ k3.ScalarMult(k3, c)
+ k3Bytes := k3.Marshal()
+
+ if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) {
+ t.Errorf("keys didn't agree")
+ }
+}
+
+func BenchmarkPairing(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Pair(&G1{curveGen}, &G2{twistGen})
+ }
+}
diff --git a/vendor/golang.org/x/crypto/bn256/constants.go b/vendor/golang.org/x/crypto/bn256/constants.go
new file mode 100644
index 000000000..08ccfdf3d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/constants.go
@@ -0,0 +1,44 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+ "math/big"
+)
+
+func bigFromBase10(s string) *big.Int {
+ n, _ := new(big.Int).SetString(s, 10)
+ return n
+}
+
+// u is the BN parameter that determines the prime: 1868033³.
+var u = bigFromBase10("6518589491078791937")
+
+// p is a prime over which we form a basic field: 36u⁴+36u³+24u³+6u+1.
+var p = bigFromBase10("65000549695646603732796438742359905742825358107623003571877145026864184071783")
+
+// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u³+6u+1.
+var Order = bigFromBase10("65000549695646603732796438742359905742570406053903786389881062969044166799969")
+
+// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+3.
+var xiToPMinus1Over6 = &gfP2{bigFromBase10("8669379979083712429711189836753509758585994370025260553045152614783263110636"), bigFromBase10("19998038925833620163537568958541907098007303196759855091367510456613536016040")}
+
+// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+3.
+var xiToPMinus1Over3 = &gfP2{bigFromBase10("26098034838977895781559542626833399156321265654106457577426020397262786167059"), bigFromBase10("15931493369629630809226283458085260090334794394361662678240713231519278691715")}
+
+// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+3.
+var xiToPMinus1Over2 = &gfP2{bigFromBase10("50997318142241922852281555961173165965672272825141804376761836765206060036244"), bigFromBase10("38665955945962842195025998234511023902832543644254935982879660597356748036009")}
+
+// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+3.
+var xiToPSquaredMinus1Over3 = bigFromBase10("65000549695646603727810655408050771481677621702948236658134783353303381437752")
+
+// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+3 (a cubic root of unity, mod p).
+var xiTo2PSquaredMinus2Over3 = bigFromBase10("4985783334309134261147736404674766913742361673560802634030")
+
+// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+3 (a cubic root of -1, mod p).
+var xiToPSquaredMinus1Over6 = bigFromBase10("65000549695646603727810655408050771481677621702948236658134783353303381437753")
+
+// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+3.
+var xiTo2PMinus2Over3 = &gfP2{bigFromBase10("19885131339612776214803633203834694332692106372356013117629940868870585019582"), bigFromBase10("21645619881471562101905880913352894726728173167203616652430647841922248593627")}
diff --git a/vendor/golang.org/x/crypto/bn256/curve.go b/vendor/golang.org/x/crypto/bn256/curve.go
new file mode 100644
index 000000000..55b7063f1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/curve.go
@@ -0,0 +1,278 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+ "math/big"
+)
+
+// curvePoint implements the elliptic curve y²=x³+3. Points are kept in
+// Jacobian form and t=z² when valid. G₁ is the set of points of this curve on
+// GF(p).
+type curvePoint struct {
+ x, y, z, t *big.Int
+}
+
+var curveB = new(big.Int).SetInt64(3)
+
+// curveGen is the generator of G₁.
+var curveGen = &curvePoint{
+ new(big.Int).SetInt64(1),
+ new(big.Int).SetInt64(-2),
+ new(big.Int).SetInt64(1),
+ new(big.Int).SetInt64(1),
+}
+
+func newCurvePoint(pool *bnPool) *curvePoint {
+ return &curvePoint{
+ pool.Get(),
+ pool.Get(),
+ pool.Get(),
+ pool.Get(),
+ }
+}
+
+func (c *curvePoint) String() string {
+ c.MakeAffine(new(bnPool))
+ return "(" + c.x.String() + ", " + c.y.String() + ")"
+}
+
+func (c *curvePoint) Put(pool *bnPool) {
+ pool.Put(c.x)
+ pool.Put(c.y)
+ pool.Put(c.z)
+ pool.Put(c.t)
+}
+
+func (c *curvePoint) Set(a *curvePoint) {
+ c.x.Set(a.x)
+ c.y.Set(a.y)
+ c.z.Set(a.z)
+ c.t.Set(a.t)
+}
+
+// IsOnCurve returns true iff c is on the curve where c must be in affine form.
+func (c *curvePoint) IsOnCurve() bool {
+ yy := new(big.Int).Mul(c.y, c.y)
+ xxx := new(big.Int).Mul(c.x, c.x)
+ xxx.Mul(xxx, c.x)
+ yy.Sub(yy, xxx)
+ yy.Sub(yy, curveB)
+ if yy.Sign() < 0 || yy.Cmp(p) >= 0 {
+ yy.Mod(yy, p)
+ }
+ return yy.Sign() == 0
+}
+
+func (c *curvePoint) SetInfinity() {
+ c.z.SetInt64(0)
+}
+
+func (c *curvePoint) IsInfinity() bool {
+ return c.z.Sign() == 0
+}
+
+func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) {
+ if a.IsInfinity() {
+ c.Set(b)
+ return
+ }
+ if b.IsInfinity() {
+ c.Set(a)
+ return
+ }
+
+ // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
+
+ // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2]
+ // by [u1:s1:z1·z2] and [u2:s2:z1·z2]
+ // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³
+ z1z1 := pool.Get().Mul(a.z, a.z)
+ z1z1.Mod(z1z1, p)
+ z2z2 := pool.Get().Mul(b.z, b.z)
+ z2z2.Mod(z2z2, p)
+ u1 := pool.Get().Mul(a.x, z2z2)
+ u1.Mod(u1, p)
+ u2 := pool.Get().Mul(b.x, z1z1)
+ u2.Mod(u2, p)
+
+ t := pool.Get().Mul(b.z, z2z2)
+ t.Mod(t, p)
+ s1 := pool.Get().Mul(a.y, t)
+ s1.Mod(s1, p)
+
+ t.Mul(a.z, z1z1)
+ t.Mod(t, p)
+ s2 := pool.Get().Mul(b.y, t)
+ s2.Mod(s2, p)
+
+ // Compute x = (2h)²(s²-u1-u2)
+ // where s = (s2-s1)/(u2-u1) is the slope of the line through
+ // (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below.
+ // This is also:
+ // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1)
+ // = r² - j - 2v
+ // with the notations below.
+ h := pool.Get().Sub(u2, u1)
+ xEqual := h.Sign() == 0
+
+ t.Add(h, h)
+ // i = 4h²
+ i := pool.Get().Mul(t, t)
+ i.Mod(i, p)
+ // j = 4h³
+ j := pool.Get().Mul(h, i)
+ j.Mod(j, p)
+
+ t.Sub(s2, s1)
+ yEqual := t.Sign() == 0
+ if xEqual && yEqual {
+ c.Double(a, pool)
+ return
+ }
+ r := pool.Get().Add(t, t)
+
+ v := pool.Get().Mul(u1, i)
+ v.Mod(v, p)
+
+ // t4 = 4(s2-s1)²
+ t4 := pool.Get().Mul(r, r)
+ t4.Mod(t4, p)
+ t.Add(v, v)
+ t6 := pool.Get().Sub(t4, j)
+ c.x.Sub(t6, t)
+
+ // Set y = -(2h)³(s1 + s*(x/4h²-u1))
+ // This is also
+ // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j
+ t.Sub(v, c.x) // t7
+ t4.Mul(s1, j) // t8
+ t4.Mod(t4, p)
+ t6.Add(t4, t4) // t9
+ t4.Mul(r, t) // t10
+ t4.Mod(t4, p)
+ c.y.Sub(t4, t6)
+
+ // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2
+ t.Add(a.z, b.z) // t11
+ t4.Mul(t, t) // t12
+ t4.Mod(t4, p)
+ t.Sub(t4, z1z1) // t13
+ t4.Sub(t, z2z2) // t14
+ c.z.Mul(t4, h)
+ c.z.Mod(c.z, p)
+
+ pool.Put(z1z1)
+ pool.Put(z2z2)
+ pool.Put(u1)
+ pool.Put(u2)
+ pool.Put(t)
+ pool.Put(s1)
+ pool.Put(s2)
+ pool.Put(h)
+ pool.Put(i)
+ pool.Put(j)
+ pool.Put(r)
+ pool.Put(v)
+ pool.Put(t4)
+ pool.Put(t6)
+}
+
+func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
+ A := pool.Get().Mul(a.x, a.x)
+ A.Mod(A, p)
+ B := pool.Get().Mul(a.y, a.y)
+ B.Mod(B, p)
+ C := pool.Get().Mul(B, B)
+ C.Mod(C, p)
+
+ t := pool.Get().Add(a.x, B)
+ t2 := pool.Get().Mul(t, t)
+ t2.Mod(t2, p)
+ t.Sub(t2, A)
+ t2.Sub(t, C)
+ d := pool.Get().Add(t2, t2)
+ t.Add(A, A)
+ e := pool.Get().Add(t, A)
+ f := pool.Get().Mul(e, e)
+ f.Mod(f, p)
+
+ t.Add(d, d)
+ c.x.Sub(f, t)
+
+ t.Add(C, C)
+ t2.Add(t, t)
+ t.Add(t2, t2)
+ c.y.Sub(d, c.x)
+ t2.Mul(e, c.y)
+ t2.Mod(t2, p)
+ c.y.Sub(t2, t)
+
+ t.Mul(a.y, a.z)
+ t.Mod(t, p)
+ c.z.Add(t, t)
+
+ pool.Put(A)
+ pool.Put(B)
+ pool.Put(C)
+ pool.Put(t)
+ pool.Put(t2)
+ pool.Put(d)
+ pool.Put(e)
+ pool.Put(f)
+}
+
+func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint {
+ sum := newCurvePoint(pool)
+ sum.SetInfinity()
+ t := newCurvePoint(pool)
+
+ for i := scalar.BitLen(); i >= 0; i-- {
+ t.Double(sum, pool)
+ if scalar.Bit(i) != 0 {
+ sum.Add(t, a, pool)
+ } else {
+ sum.Set(t)
+ }
+ }
+
+ c.Set(sum)
+ sum.Put(pool)
+ t.Put(pool)
+ return c
+}
+
+func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint {
+ if words := c.z.Bits(); len(words) == 1 && words[0] == 1 {
+ return c
+ }
+
+ zInv := pool.Get().ModInverse(c.z, p)
+ t := pool.Get().Mul(c.y, zInv)
+ t.Mod(t, p)
+ zInv2 := pool.Get().Mul(zInv, zInv)
+ zInv2.Mod(zInv2, p)
+ c.y.Mul(t, zInv2)
+ c.y.Mod(c.y, p)
+ t.Mul(c.x, zInv2)
+ t.Mod(t, p)
+ c.x.Set(t)
+ c.z.SetInt64(1)
+ c.t.SetInt64(1)
+
+ pool.Put(zInv)
+ pool.Put(t)
+ pool.Put(zInv2)
+
+ return c
+}
+
+func (c *curvePoint) Negative(a *curvePoint) {
+ c.x.Set(a.x)
+ c.y.Neg(a.y)
+ c.z.Set(a.z)
+ c.t.SetInt64(0)
+}
diff --git a/vendor/golang.org/x/crypto/bn256/example_test.go b/vendor/golang.org/x/crypto/bn256/example_test.go
new file mode 100644
index 000000000..b2d19807a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/example_test.go
@@ -0,0 +1,43 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+ "crypto/rand"
+)
+
+func ExamplePair() {
+ // This implements the tripartite Diffie-Hellman algorithm from "A One
+ // Round Protocol for Tripartite Diffie-Hellman", A. Joux.
+ // http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf
+
+ // Each of three parties, a, b and c, generate a private value.
+ a, _ := rand.Int(rand.Reader, Order)
+ b, _ := rand.Int(rand.Reader, Order)
+ c, _ := rand.Int(rand.Reader, Order)
+
+ // Then each party calculates g₁ and g₂ times their private value.
+ pa := new(G1).ScalarBaseMult(a)
+ qa := new(G2).ScalarBaseMult(a)
+
+ pb := new(G1).ScalarBaseMult(b)
+ qb := new(G2).ScalarBaseMult(b)
+
+ pc := new(G1).ScalarBaseMult(c)
+ qc := new(G2).ScalarBaseMult(c)
+
+ // Now each party exchanges its public values with the other two and
+ // all parties can calculate the shared key.
+ k1 := Pair(pb, qc)
+ k1.ScalarMult(k1, a)
+
+ k2 := Pair(pc, qa)
+ k2.ScalarMult(k2, b)
+
+ k3 := Pair(pa, qb)
+ k3.ScalarMult(k3, c)
+
+ // k1, k2 and k3 will all be equal.
+}
diff --git a/vendor/golang.org/x/crypto/bn256/gfp12.go b/vendor/golang.org/x/crypto/bn256/gfp12.go
new file mode 100644
index 000000000..f084eddf2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/gfp12.go
@@ -0,0 +1,200 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+// For details of the algorithms used, see "Multiplication and Squaring on
+// Pairing-Friendly Fields, Devegili et al.
+// http://eprint.iacr.org/2006/471.pdf.
+
+import (
+ "math/big"
+)
+
+// gfP12 implements the field of size p¹² as a quadratic extension of gfP6
+// where ω²=τ.
+type gfP12 struct {
+ x, y *gfP6 // value is xω + y
+}
+
+func newGFp12(pool *bnPool) *gfP12 {
+ return &gfP12{newGFp6(pool), newGFp6(pool)}
+}
+
+func (e *gfP12) String() string {
+ return "(" + e.x.String() + "," + e.y.String() + ")"
+}
+
+func (e *gfP12) Put(pool *bnPool) {
+ e.x.Put(pool)
+ e.y.Put(pool)
+}
+
+func (e *gfP12) Set(a *gfP12) *gfP12 {
+ e.x.Set(a.x)
+ e.y.Set(a.y)
+ return e
+}
+
+func (e *gfP12) SetZero() *gfP12 {
+ e.x.SetZero()
+ e.y.SetZero()
+ return e
+}
+
+func (e *gfP12) SetOne() *gfP12 {
+ e.x.SetZero()
+ e.y.SetOne()
+ return e
+}
+
+func (e *gfP12) Minimal() {
+ e.x.Minimal()
+ e.y.Minimal()
+}
+
+func (e *gfP12) IsZero() bool {
+ e.Minimal()
+ return e.x.IsZero() && e.y.IsZero()
+}
+
+func (e *gfP12) IsOne() bool {
+ e.Minimal()
+ return e.x.IsZero() && e.y.IsOne()
+}
+
+func (e *gfP12) Conjugate(a *gfP12) *gfP12 {
+ e.x.Negative(a.x)
+ e.y.Set(a.y)
+ return a
+}
+
+func (e *gfP12) Negative(a *gfP12) *gfP12 {
+ e.x.Negative(a.x)
+ e.y.Negative(a.y)
+ return e
+}
+
+// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p
+func (e *gfP12) Frobenius(a *gfP12, pool *bnPool) *gfP12 {
+ e.x.Frobenius(a.x, pool)
+ e.y.Frobenius(a.y, pool)
+ e.x.MulScalar(e.x, xiToPMinus1Over6, pool)
+ return e
+}
+
+// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p²
+func (e *gfP12) FrobeniusP2(a *gfP12, pool *bnPool) *gfP12 {
+ e.x.FrobeniusP2(a.x)
+ e.x.MulGFP(e.x, xiToPSquaredMinus1Over6)
+ e.y.FrobeniusP2(a.y)
+ return e
+}
+
+func (e *gfP12) Add(a, b *gfP12) *gfP12 {
+ e.x.Add(a.x, b.x)
+ e.y.Add(a.y, b.y)
+ return e
+}
+
+func (e *gfP12) Sub(a, b *gfP12) *gfP12 {
+ e.x.Sub(a.x, b.x)
+ e.y.Sub(a.y, b.y)
+ return e
+}
+
+func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 {
+ tx := newGFp6(pool)
+ tx.Mul(a.x, b.y, pool)
+ t := newGFp6(pool)
+ t.Mul(b.x, a.y, pool)
+ tx.Add(tx, t)
+
+ ty := newGFp6(pool)
+ ty.Mul(a.y, b.y, pool)
+ t.Mul(a.x, b.x, pool)
+ t.MulTau(t, pool)
+ e.y.Add(ty, t)
+ e.x.Set(tx)
+
+ tx.Put(pool)
+ ty.Put(pool)
+ t.Put(pool)
+ return e
+}
+
+func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
+ e.x.Mul(e.x, b, pool)
+ e.y.Mul(e.y, b, pool)
+ return e
+}
+
+func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
+ sum := newGFp12(pool)
+ sum.SetOne()
+ t := newGFp12(pool)
+
+ for i := power.BitLen() - 1; i >= 0; i-- {
+ t.Square(sum, pool)
+ if power.Bit(i) != 0 {
+ sum.Mul(t, a, pool)
+ } else {
+ sum.Set(t)
+ }
+ }
+
+ c.Set(sum)
+
+ sum.Put(pool)
+ t.Put(pool)
+
+ return c
+}
+
+func (e *gfP12) Square(a *gfP12, pool *bnPool) *gfP12 {
+ // Complex squaring algorithm
+ v0 := newGFp6(pool)
+ v0.Mul(a.x, a.y, pool)
+
+ t := newGFp6(pool)
+ t.MulTau(a.x, pool)
+ t.Add(a.y, t)
+ ty := newGFp6(pool)
+ ty.Add(a.x, a.y)
+ ty.Mul(ty, t, pool)
+ ty.Sub(ty, v0)
+ t.MulTau(v0, pool)
+ ty.Sub(ty, t)
+
+ e.y.Set(ty)
+ e.x.Double(v0)
+
+ v0.Put(pool)
+ t.Put(pool)
+ ty.Put(pool)
+
+ return e
+}
+
+func (e *gfP12) Invert(a *gfP12, pool *bnPool) *gfP12 {
+ // See "Implementing cryptographic pairings", M. Scott, section 3.2.
+ // ftp://136.206.11.249/pub/crypto/pairings.pdf
+ t1 := newGFp6(pool)
+ t2 := newGFp6(pool)
+
+ t1.Square(a.x, pool)
+ t2.Square(a.y, pool)
+ t1.MulTau(t1, pool)
+ t1.Sub(t2, t1)
+ t2.Invert(t1, pool)
+
+ e.x.Negative(a.x)
+ e.y.Set(a.y)
+ e.MulScalar(e, t2, pool)
+
+ t1.Put(pool)
+ t2.Put(pool)
+
+ return e
+}
diff --git a/vendor/golang.org/x/crypto/bn256/gfp2.go b/vendor/golang.org/x/crypto/bn256/gfp2.go
new file mode 100644
index 000000000..97f3f1f3f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/gfp2.go
@@ -0,0 +1,219 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+// For details of the algorithms used, see "Multiplication and Squaring on
+// Pairing-Friendly Fields, Devegili et al.
+// http://eprint.iacr.org/2006/471.pdf.
+
+import (
+ "math/big"
+)
+
+// gfP2 implements a field of size p² as a quadratic extension of the base
+// field where i²=-1.
+type gfP2 struct {
+ x, y *big.Int // value is xi+y.
+}
+
+func newGFp2(pool *bnPool) *gfP2 {
+ return &gfP2{pool.Get(), pool.Get()}
+}
+
+func (e *gfP2) String() string {
+ x := new(big.Int).Mod(e.x, p)
+ y := new(big.Int).Mod(e.y, p)
+ return "(" + x.String() + "," + y.String() + ")"
+}
+
+func (e *gfP2) Put(pool *bnPool) {
+ pool.Put(e.x)
+ pool.Put(e.y)
+}
+
+func (e *gfP2) Set(a *gfP2) *gfP2 {
+ e.x.Set(a.x)
+ e.y.Set(a.y)
+ return e
+}
+
+func (e *gfP2) SetZero() *gfP2 {
+ e.x.SetInt64(0)
+ e.y.SetInt64(0)
+ return e
+}
+
+func (e *gfP2) SetOne() *gfP2 {
+ e.x.SetInt64(0)
+ e.y.SetInt64(1)
+ return e
+}
+
+func (e *gfP2) Minimal() {
+ if e.x.Sign() < 0 || e.x.Cmp(p) >= 0 {
+ e.x.Mod(e.x, p)
+ }
+ if e.y.Sign() < 0 || e.y.Cmp(p) >= 0 {
+ e.y.Mod(e.y, p)
+ }
+}
+
+func (e *gfP2) IsZero() bool {
+ return e.x.Sign() == 0 && e.y.Sign() == 0
+}
+
+func (e *gfP2) IsOne() bool {
+ if e.x.Sign() != 0 {
+ return false
+ }
+ words := e.y.Bits()
+ return len(words) == 1 && words[0] == 1
+}
+
+func (e *gfP2) Conjugate(a *gfP2) *gfP2 {
+ e.y.Set(a.y)
+ e.x.Neg(a.x)
+ return e
+}
+
+func (e *gfP2) Negative(a *gfP2) *gfP2 {
+ e.x.Neg(a.x)
+ e.y.Neg(a.y)
+ return e
+}
+
+func (e *gfP2) Add(a, b *gfP2) *gfP2 {
+ e.x.Add(a.x, b.x)
+ e.y.Add(a.y, b.y)
+ return e
+}
+
+func (e *gfP2) Sub(a, b *gfP2) *gfP2 {
+ e.x.Sub(a.x, b.x)
+ e.y.Sub(a.y, b.y)
+ return e
+}
+
+func (e *gfP2) Double(a *gfP2) *gfP2 {
+ e.x.Lsh(a.x, 1)
+ e.y.Lsh(a.y, 1)
+ return e
+}
+
+func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
+ sum := newGFp2(pool)
+ sum.SetOne()
+ t := newGFp2(pool)
+
+ for i := power.BitLen() - 1; i >= 0; i-- {
+ t.Square(sum, pool)
+ if power.Bit(i) != 0 {
+ sum.Mul(t, a, pool)
+ } else {
+ sum.Set(t)
+ }
+ }
+
+ c.Set(sum)
+
+ sum.Put(pool)
+ t.Put(pool)
+
+ return c
+}
+
+// See "Multiplication and Squaring in Pairing-Friendly Fields",
+// http://eprint.iacr.org/2006/471.pdf
+func (e *gfP2) Mul(a, b *gfP2, pool *bnPool) *gfP2 {
+ tx := pool.Get().Mul(a.x, b.y)
+ t := pool.Get().Mul(b.x, a.y)
+ tx.Add(tx, t)
+ tx.Mod(tx, p)
+
+ ty := pool.Get().Mul(a.y, b.y)
+ t.Mul(a.x, b.x)
+ ty.Sub(ty, t)
+ e.y.Mod(ty, p)
+ e.x.Set(tx)
+
+ pool.Put(tx)
+ pool.Put(ty)
+ pool.Put(t)
+
+ return e
+}
+
+func (e *gfP2) MulScalar(a *gfP2, b *big.Int) *gfP2 {
+ e.x.Mul(a.x, b)
+ e.y.Mul(a.y, b)
+ return e
+}
+
+// MulXi sets e=ξa where ξ=i+3 and then returns e.
+func (e *gfP2) MulXi(a *gfP2, pool *bnPool) *gfP2 {
+ // (xi+y)(i+3) = (3x+y)i+(3y-x)
+ tx := pool.Get().Lsh(a.x, 1)
+ tx.Add(tx, a.x)
+ tx.Add(tx, a.y)
+
+ ty := pool.Get().Lsh(a.y, 1)
+ ty.Add(ty, a.y)
+ ty.Sub(ty, a.x)
+
+ e.x.Set(tx)
+ e.y.Set(ty)
+
+ pool.Put(tx)
+ pool.Put(ty)
+
+ return e
+}
+
+func (e *gfP2) Square(a *gfP2, pool *bnPool) *gfP2 {
+ // Complex squaring algorithm:
+ // (xi+b)² = (x+y)(y-x) + 2*i*x*y
+ t1 := pool.Get().Sub(a.y, a.x)
+ t2 := pool.Get().Add(a.x, a.y)
+ ty := pool.Get().Mul(t1, t2)
+ ty.Mod(ty, p)
+
+ t1.Mul(a.x, a.y)
+ t1.Lsh(t1, 1)
+
+ e.x.Mod(t1, p)
+ e.y.Set(ty)
+
+ pool.Put(t1)
+ pool.Put(t2)
+ pool.Put(ty)
+
+ return e
+}
+
+func (e *gfP2) Invert(a *gfP2, pool *bnPool) *gfP2 {
+ // See "Implementing cryptographic pairings", M. Scott, section 3.2.
+ // ftp://136.206.11.249/pub/crypto/pairings.pdf
+ t := pool.Get()
+ t.Mul(a.y, a.y)
+ t2 := pool.Get()
+ t2.Mul(a.x, a.x)
+ t.Add(t, t2)
+
+ inv := pool.Get()
+ inv.ModInverse(t, p)
+
+ e.x.Neg(a.x)
+ e.x.Mul(e.x, inv)
+ e.x.Mod(e.x, p)
+
+ e.y.Mul(a.y, inv)
+ e.y.Mod(e.y, p)
+
+ pool.Put(t)
+ pool.Put(t2)
+ pool.Put(inv)
+
+ return e
+}
diff --git a/vendor/golang.org/x/crypto/bn256/gfp6.go b/vendor/golang.org/x/crypto/bn256/gfp6.go
new file mode 100644
index 000000000..f98ae782c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/gfp6.go
@@ -0,0 +1,296 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+// For details of the algorithms used, see "Multiplication and Squaring on
+// Pairing-Friendly Fields, Devegili et al.
+// http://eprint.iacr.org/2006/471.pdf.
+
+import (
+ "math/big"
+)
+
+// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ
+// and ξ=i+3.
+type gfP6 struct {
+ x, y, z *gfP2 // value is xτ² + yτ + z
+}
+
+func newGFp6(pool *bnPool) *gfP6 {
+ return &gfP6{newGFp2(pool), newGFp2(pool), newGFp2(pool)}
+}
+
+func (e *gfP6) String() string {
+ return "(" + e.x.String() + "," + e.y.String() + "," + e.z.String() + ")"
+}
+
+func (e *gfP6) Put(pool *bnPool) {
+ e.x.Put(pool)
+ e.y.Put(pool)
+ e.z.Put(pool)
+}
+
+func (e *gfP6) Set(a *gfP6) *gfP6 {
+ e.x.Set(a.x)
+ e.y.Set(a.y)
+ e.z.Set(a.z)
+ return e
+}
+
+func (e *gfP6) SetZero() *gfP6 {
+ e.x.SetZero()
+ e.y.SetZero()
+ e.z.SetZero()
+ return e
+}
+
+func (e *gfP6) SetOne() *gfP6 {
+ e.x.SetZero()
+ e.y.SetZero()
+ e.z.SetOne()
+ return e
+}
+
+func (e *gfP6) Minimal() {
+ e.x.Minimal()
+ e.y.Minimal()
+ e.z.Minimal()
+}
+
+func (e *gfP6) IsZero() bool {
+ return e.x.IsZero() && e.y.IsZero() && e.z.IsZero()
+}
+
+func (e *gfP6) IsOne() bool {
+ return e.x.IsZero() && e.y.IsZero() && e.z.IsOne()
+}
+
+func (e *gfP6) Negative(a *gfP6) *gfP6 {
+ e.x.Negative(a.x)
+ e.y.Negative(a.y)
+ e.z.Negative(a.z)
+ return e
+}
+
+func (e *gfP6) Frobenius(a *gfP6, pool *bnPool) *gfP6 {
+ e.x.Conjugate(a.x)
+ e.y.Conjugate(a.y)
+ e.z.Conjugate(a.z)
+
+ e.x.Mul(e.x, xiTo2PMinus2Over3, pool)
+ e.y.Mul(e.y, xiToPMinus1Over3, pool)
+ return e
+}
+
+// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z
+func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 {
+ // τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3)
+ e.x.MulScalar(a.x, xiTo2PSquaredMinus2Over3)
+ // τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3)
+ e.y.MulScalar(a.y, xiToPSquaredMinus1Over3)
+ e.z.Set(a.z)
+ return e
+}
+
+func (e *gfP6) Add(a, b *gfP6) *gfP6 {
+ e.x.Add(a.x, b.x)
+ e.y.Add(a.y, b.y)
+ e.z.Add(a.z, b.z)
+ return e
+}
+
+func (e *gfP6) Sub(a, b *gfP6) *gfP6 {
+ e.x.Sub(a.x, b.x)
+ e.y.Sub(a.y, b.y)
+ e.z.Sub(a.z, b.z)
+ return e
+}
+
+func (e *gfP6) Double(a *gfP6) *gfP6 {
+ e.x.Double(a.x)
+ e.y.Double(a.y)
+ e.z.Double(a.z)
+ return e
+}
+
+func (e *gfP6) Mul(a, b *gfP6, pool *bnPool) *gfP6 {
+ // "Multiplication and Squaring on Pairing-Friendly Fields"
+ // Section 4, Karatsuba method.
+ // http://eprint.iacr.org/2006/471.pdf
+
+ v0 := newGFp2(pool)
+ v0.Mul(a.z, b.z, pool)
+ v1 := newGFp2(pool)
+ v1.Mul(a.y, b.y, pool)
+ v2 := newGFp2(pool)
+ v2.Mul(a.x, b.x, pool)
+
+ t0 := newGFp2(pool)
+ t0.Add(a.x, a.y)
+ t1 := newGFp2(pool)
+ t1.Add(b.x, b.y)
+ tz := newGFp2(pool)
+ tz.Mul(t0, t1, pool)
+
+ tz.Sub(tz, v1)
+ tz.Sub(tz, v2)
+ tz.MulXi(tz, pool)
+ tz.Add(tz, v0)
+
+ t0.Add(a.y, a.z)
+ t1.Add(b.y, b.z)
+ ty := newGFp2(pool)
+ ty.Mul(t0, t1, pool)
+ ty.Sub(ty, v0)
+ ty.Sub(ty, v1)
+ t0.MulXi(v2, pool)
+ ty.Add(ty, t0)
+
+ t0.Add(a.x, a.z)
+ t1.Add(b.x, b.z)
+ tx := newGFp2(pool)
+ tx.Mul(t0, t1, pool)
+ tx.Sub(tx, v0)
+ tx.Add(tx, v1)
+ tx.Sub(tx, v2)
+
+ e.x.Set(tx)
+ e.y.Set(ty)
+ e.z.Set(tz)
+
+ t0.Put(pool)
+ t1.Put(pool)
+ tx.Put(pool)
+ ty.Put(pool)
+ tz.Put(pool)
+ v0.Put(pool)
+ v1.Put(pool)
+ v2.Put(pool)
+ return e
+}
+
+func (e *gfP6) MulScalar(a *gfP6, b *gfP2, pool *bnPool) *gfP6 {
+ e.x.Mul(a.x, b, pool)
+ e.y.Mul(a.y, b, pool)
+ e.z.Mul(a.z, b, pool)
+ return e
+}
+
+func (e *gfP6) MulGFP(a *gfP6, b *big.Int) *gfP6 {
+ e.x.MulScalar(a.x, b)
+ e.y.MulScalar(a.y, b)
+ e.z.MulScalar(a.z, b)
+ return e
+}
+
+// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ
+func (e *gfP6) MulTau(a *gfP6, pool *bnPool) {
+ tz := newGFp2(pool)
+ tz.MulXi(a.x, pool)
+ ty := newGFp2(pool)
+ ty.Set(a.y)
+ e.y.Set(a.z)
+ e.x.Set(ty)
+ e.z.Set(tz)
+ tz.Put(pool)
+ ty.Put(pool)
+}
+
+func (e *gfP6) Square(a *gfP6, pool *bnPool) *gfP6 {
+ v0 := newGFp2(pool).Square(a.z, pool)
+ v1 := newGFp2(pool).Square(a.y, pool)
+ v2 := newGFp2(pool).Square(a.x, pool)
+
+ c0 := newGFp2(pool).Add(a.x, a.y)
+ c0.Square(c0, pool)
+ c0.Sub(c0, v1)
+ c0.Sub(c0, v2)
+ c0.MulXi(c0, pool)
+ c0.Add(c0, v0)
+
+ c1 := newGFp2(pool).Add(a.y, a.z)
+ c1.Square(c1, pool)
+ c1.Sub(c1, v0)
+ c1.Sub(c1, v1)
+ xiV2 := newGFp2(pool).MulXi(v2, pool)
+ c1.Add(c1, xiV2)
+
+ c2 := newGFp2(pool).Add(a.x, a.z)
+ c2.Square(c2, pool)
+ c2.Sub(c2, v0)
+ c2.Add(c2, v1)
+ c2.Sub(c2, v2)
+
+ e.x.Set(c2)
+ e.y.Set(c1)
+ e.z.Set(c0)
+
+ v0.Put(pool)
+ v1.Put(pool)
+ v2.Put(pool)
+ c0.Put(pool)
+ c1.Put(pool)
+ c2.Put(pool)
+ xiV2.Put(pool)
+
+ return e
+}
+
+func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
+ // See "Implementing cryptographic pairings", M. Scott, section 3.2.
+ // ftp://136.206.11.249/pub/crypto/pairings.pdf
+
+ // Here we can give a short explanation of how it works: let j be a cubic root of
+ // unity in GF(p²) so that 1+j+j²=0.
+ // Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
+ // = (xτ² + yτ + z)(Cτ²+Bτ+A)
+ // = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm).
+ //
+ // On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z)
+ // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy)
+ //
+ // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz)
+ t1 := newGFp2(pool)
+
+ A := newGFp2(pool)
+ A.Square(a.z, pool)
+ t1.Mul(a.x, a.y, pool)
+ t1.MulXi(t1, pool)
+ A.Sub(A, t1)
+
+ B := newGFp2(pool)
+ B.Square(a.x, pool)
+ B.MulXi(B, pool)
+ t1.Mul(a.y, a.z, pool)
+ B.Sub(B, t1)
+
+ C := newGFp2(pool)
+ C.Square(a.y, pool)
+ t1.Mul(a.x, a.z, pool)
+ C.Sub(C, t1)
+
+ F := newGFp2(pool)
+ F.Mul(C, a.y, pool)
+ F.MulXi(F, pool)
+ t1.Mul(A, a.z, pool)
+ F.Add(F, t1)
+ t1.Mul(B, a.x, pool)
+ t1.MulXi(t1, pool)
+ F.Add(F, t1)
+
+ F.Invert(F, pool)
+
+ e.x.Mul(C, F, pool)
+ e.y.Mul(B, F, pool)
+ e.z.Mul(A, F, pool)
+
+ t1.Put(pool)
+ A.Put(pool)
+ B.Put(pool)
+ C.Put(pool)
+ F.Put(pool)
+
+ return e
+}
diff --git a/vendor/golang.org/x/crypto/bn256/optate.go b/vendor/golang.org/x/crypto/bn256/optate.go
new file mode 100644
index 000000000..7ae0746eb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/optate.go
@@ -0,0 +1,395 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
+ // See the mixed addition algorithm from "Faster Computation of the
+ // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
+
+ B := newGFp2(pool).Mul(p.x, r.t, pool)
+
+ D := newGFp2(pool).Add(p.y, r.z)
+ D.Square(D, pool)
+ D.Sub(D, r2)
+ D.Sub(D, r.t)
+ D.Mul(D, r.t, pool)
+
+ H := newGFp2(pool).Sub(B, r.x)
+ I := newGFp2(pool).Square(H, pool)
+
+ E := newGFp2(pool).Add(I, I)
+ E.Add(E, E)
+
+ J := newGFp2(pool).Mul(H, E, pool)
+
+ L1 := newGFp2(pool).Sub(D, r.y)
+ L1.Sub(L1, r.y)
+
+ V := newGFp2(pool).Mul(r.x, E, pool)
+
+ rOut = newTwistPoint(pool)
+ rOut.x.Square(L1, pool)
+ rOut.x.Sub(rOut.x, J)
+ rOut.x.Sub(rOut.x, V)
+ rOut.x.Sub(rOut.x, V)
+
+ rOut.z.Add(r.z, H)
+ rOut.z.Square(rOut.z, pool)
+ rOut.z.Sub(rOut.z, r.t)
+ rOut.z.Sub(rOut.z, I)
+
+ t := newGFp2(pool).Sub(V, rOut.x)
+ t.Mul(t, L1, pool)
+ t2 := newGFp2(pool).Mul(r.y, J, pool)
+ t2.Add(t2, t2)
+ rOut.y.Sub(t, t2)
+
+ rOut.t.Square(rOut.z, pool)
+
+ t.Add(p.y, rOut.z)
+ t.Square(t, pool)
+ t.Sub(t, r2)
+ t.Sub(t, rOut.t)
+
+ t2.Mul(L1, p.x, pool)
+ t2.Add(t2, t2)
+ a = newGFp2(pool)
+ a.Sub(t2, t)
+
+ c = newGFp2(pool)
+ c.MulScalar(rOut.z, q.y)
+ c.Add(c, c)
+
+ b = newGFp2(pool)
+ b.SetZero()
+ b.Sub(b, L1)
+ b.MulScalar(b, q.x)
+ b.Add(b, b)
+
+ B.Put(pool)
+ D.Put(pool)
+ H.Put(pool)
+ I.Put(pool)
+ E.Put(pool)
+ J.Put(pool)
+ L1.Put(pool)
+ V.Put(pool)
+ t.Put(pool)
+ t2.Put(pool)
+
+ return
+}
+
+func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) {
+ // See the doubling algorithm for a=0 from "Faster Computation of the
+ // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf
+
+ A := newGFp2(pool).Square(r.x, pool)
+ B := newGFp2(pool).Square(r.y, pool)
+ C := newGFp2(pool).Square(B, pool)
+
+ D := newGFp2(pool).Add(r.x, B)
+ D.Square(D, pool)
+ D.Sub(D, A)
+ D.Sub(D, C)
+ D.Add(D, D)
+
+ E := newGFp2(pool).Add(A, A)
+ E.Add(E, A)
+
+ G := newGFp2(pool).Square(E, pool)
+
+ rOut = newTwistPoint(pool)
+ rOut.x.Sub(G, D)
+ rOut.x.Sub(rOut.x, D)
+
+ rOut.z.Add(r.y, r.z)
+ rOut.z.Square(rOut.z, pool)
+ rOut.z.Sub(rOut.z, B)
+ rOut.z.Sub(rOut.z, r.t)
+
+ rOut.y.Sub(D, rOut.x)
+ rOut.y.Mul(rOut.y, E, pool)
+ t := newGFp2(pool).Add(C, C)
+ t.Add(t, t)
+ t.Add(t, t)
+ rOut.y.Sub(rOut.y, t)
+
+ rOut.t.Square(rOut.z, pool)
+
+ t.Mul(E, r.t, pool)
+ t.Add(t, t)
+ b = newGFp2(pool)
+ b.SetZero()
+ b.Sub(b, t)
+ b.MulScalar(b, q.x)
+
+ a = newGFp2(pool)
+ a.Add(r.x, E)
+ a.Square(a, pool)
+ a.Sub(a, A)
+ a.Sub(a, G)
+ t.Add(B, B)
+ t.Add(t, t)
+ a.Sub(a, t)
+
+ c = newGFp2(pool)
+ c.Mul(rOut.z, r.t, pool)
+ c.Add(c, c)
+ c.MulScalar(c, q.y)
+
+ A.Put(pool)
+ B.Put(pool)
+ C.Put(pool)
+ D.Put(pool)
+ E.Put(pool)
+ G.Put(pool)
+ t.Put(pool)
+
+ return
+}
+
+func mulLine(ret *gfP12, a, b, c *gfP2, pool *bnPool) {
+ a2 := newGFp6(pool)
+ a2.x.SetZero()
+ a2.y.Set(a)
+ a2.z.Set(b)
+ a2.Mul(a2, ret.x, pool)
+ t3 := newGFp6(pool).MulScalar(ret.y, c, pool)
+
+ t := newGFp2(pool)
+ t.Add(b, c)
+ t2 := newGFp6(pool)
+ t2.x.SetZero()
+ t2.y.Set(a)
+ t2.z.Set(t)
+ ret.x.Add(ret.x, ret.y)
+
+ ret.y.Set(t3)
+
+ ret.x.Mul(ret.x, t2, pool)
+ ret.x.Sub(ret.x, a2)
+ ret.x.Sub(ret.x, ret.y)
+ a2.MulTau(a2, pool)
+ ret.y.Add(ret.y, a2)
+
+ a2.Put(pool)
+ t3.Put(pool)
+ t2.Put(pool)
+ t.Put(pool)
+}
+
+// sixuPlus2NAF is 6u+2 in non-adjacent form.
+var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 1, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 1}
+
+// miller implements the Miller loop for calculating the Optimal Ate pairing.
+// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf
+func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 {
+ ret := newGFp12(pool)
+ ret.SetOne()
+
+ aAffine := newTwistPoint(pool)
+ aAffine.Set(q)
+ aAffine.MakeAffine(pool)
+
+ bAffine := newCurvePoint(pool)
+ bAffine.Set(p)
+ bAffine.MakeAffine(pool)
+
+ minusA := newTwistPoint(pool)
+ minusA.Negative(aAffine, pool)
+
+ r := newTwistPoint(pool)
+ r.Set(aAffine)
+
+ r2 := newGFp2(pool)
+ r2.Square(aAffine.y, pool)
+
+ for i := len(sixuPlus2NAF) - 1; i > 0; i-- {
+ a, b, c, newR := lineFunctionDouble(r, bAffine, pool)
+ if i != len(sixuPlus2NAF)-1 {
+ ret.Square(ret, pool)
+ }
+
+ mulLine(ret, a, b, c, pool)
+ a.Put(pool)
+ b.Put(pool)
+ c.Put(pool)
+ r.Put(pool)
+ r = newR
+
+ switch sixuPlus2NAF[i-1] {
+ case 1:
+ a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2, pool)
+ case -1:
+ a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2, pool)
+ default:
+ continue
+ }
+
+ mulLine(ret, a, b, c, pool)
+ a.Put(pool)
+ b.Put(pool)
+ c.Put(pool)
+ r.Put(pool)
+ r = newR
+ }
+
+ // In order to calculate Q1 we have to convert q from the sextic twist
+ // to the full GF(p^12) group, apply the Frobenius there, and convert
+ // back.
+ //
+ // The twist isomorphism is (x', y') -> (xω², yω³). If we consider just
+ // x for a moment, then after applying the Frobenius, we have x̄ω^(2p)
+ // where x̄ is the conjugate of x. If we are going to apply the inverse
+ // isomorphism we need a value with a single coefficient of ω² so we
+ // rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of
+ // p, 2p-2 is a multiple of six. Therefore we can rewrite as
+ // x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the
+ // ω².
+ //
+ // A similar argument can be made for the y value.
+
+ q1 := newTwistPoint(pool)
+ q1.x.Conjugate(aAffine.x)
+ q1.x.Mul(q1.x, xiToPMinus1Over3, pool)
+ q1.y.Conjugate(aAffine.y)
+ q1.y.Mul(q1.y, xiToPMinus1Over2, pool)
+ q1.z.SetOne()
+ q1.t.SetOne()
+
+ // For Q2 we are applying the p² Frobenius. The two conjugations cancel
+ // out and we are left only with the factors from the isomorphism. In
+ // the case of x, we end up with a pure number which is why
+ // xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We
+ // ignore this to end up with -Q2.
+
+ minusQ2 := newTwistPoint(pool)
+ minusQ2.x.MulScalar(aAffine.x, xiToPSquaredMinus1Over3)
+ minusQ2.y.Set(aAffine.y)
+ minusQ2.z.SetOne()
+ minusQ2.t.SetOne()
+
+ r2.Square(q1.y, pool)
+ a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2, pool)
+ mulLine(ret, a, b, c, pool)
+ a.Put(pool)
+ b.Put(pool)
+ c.Put(pool)
+ r.Put(pool)
+ r = newR
+
+ r2.Square(minusQ2.y, pool)
+ a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2, pool)
+ mulLine(ret, a, b, c, pool)
+ a.Put(pool)
+ b.Put(pool)
+ c.Put(pool)
+ r.Put(pool)
+ r = newR
+
+ aAffine.Put(pool)
+ bAffine.Put(pool)
+ minusA.Put(pool)
+ r.Put(pool)
+ r2.Put(pool)
+
+ return ret
+}
+
+// finalExponentiation computes the (p¹²-1)/Order-th power of an element of
+// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from
+// http://cryptojedi.org/papers/dclxvi-20100714.pdf)
+func finalExponentiation(in *gfP12, pool *bnPool) *gfP12 {
+ t1 := newGFp12(pool)
+
+ // This is the p^6-Frobenius
+ t1.x.Negative(in.x)
+ t1.y.Set(in.y)
+
+ inv := newGFp12(pool)
+ inv.Invert(in, pool)
+ t1.Mul(t1, inv, pool)
+
+ t2 := newGFp12(pool).FrobeniusP2(t1, pool)
+ t1.Mul(t1, t2, pool)
+
+ fp := newGFp12(pool).Frobenius(t1, pool)
+ fp2 := newGFp12(pool).FrobeniusP2(t1, pool)
+ fp3 := newGFp12(pool).Frobenius(fp2, pool)
+
+ fu, fu2, fu3 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
+ fu.Exp(t1, u, pool)
+ fu2.Exp(fu, u, pool)
+ fu3.Exp(fu2, u, pool)
+
+ y3 := newGFp12(pool).Frobenius(fu, pool)
+ fu2p := newGFp12(pool).Frobenius(fu2, pool)
+ fu3p := newGFp12(pool).Frobenius(fu3, pool)
+ y2 := newGFp12(pool).FrobeniusP2(fu2, pool)
+
+ y0 := newGFp12(pool)
+ y0.Mul(fp, fp2, pool)
+ y0.Mul(y0, fp3, pool)
+
+ y1, y4, y5 := newGFp12(pool), newGFp12(pool), newGFp12(pool)
+ y1.Conjugate(t1)
+ y5.Conjugate(fu2)
+ y3.Conjugate(y3)
+ y4.Mul(fu, fu2p, pool)
+ y4.Conjugate(y4)
+
+ y6 := newGFp12(pool)
+ y6.Mul(fu3, fu3p, pool)
+ y6.Conjugate(y6)
+
+ t0 := newGFp12(pool)
+ t0.Square(y6, pool)
+ t0.Mul(t0, y4, pool)
+ t0.Mul(t0, y5, pool)
+ t1.Mul(y3, y5, pool)
+ t1.Mul(t1, t0, pool)
+ t0.Mul(t0, y2, pool)
+ t1.Square(t1, pool)
+ t1.Mul(t1, t0, pool)
+ t1.Square(t1, pool)
+ t0.Mul(t1, y1, pool)
+ t1.Mul(t1, y0, pool)
+ t0.Square(t0, pool)
+ t0.Mul(t0, t1, pool)
+
+ inv.Put(pool)
+ t1.Put(pool)
+ t2.Put(pool)
+ fp.Put(pool)
+ fp2.Put(pool)
+ fp3.Put(pool)
+ fu.Put(pool)
+ fu2.Put(pool)
+ fu3.Put(pool)
+ fu2p.Put(pool)
+ fu3p.Put(pool)
+ y0.Put(pool)
+ y1.Put(pool)
+ y2.Put(pool)
+ y3.Put(pool)
+ y4.Put(pool)
+ y5.Put(pool)
+ y6.Put(pool)
+
+ return t0
+}
+
+func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 {
+ e := miller(a, b, pool)
+ ret := finalExponentiation(e, pool)
+ e.Put(pool)
+
+ if a.IsInfinity() || b.IsInfinity() {
+ ret.SetOne()
+ }
+
+ return ret
+}
diff --git a/vendor/golang.org/x/crypto/bn256/twist.go b/vendor/golang.org/x/crypto/bn256/twist.go
new file mode 100644
index 000000000..4f8b3fede
--- /dev/null
+++ b/vendor/golang.org/x/crypto/bn256/twist.go
@@ -0,0 +1,249 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bn256
+
+import (
+ "math/big"
+)
+
+// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are
+// kept in Jacobian form and t=z² when valid. The group G₂ is the set of
+// n-torsion points of this curve over GF(p²) (where n = Order)
+type twistPoint struct {
+ x, y, z, t *gfP2
+}
+
+var twistB = &gfP2{
+ bigFromBase10("6500054969564660373279643874235990574282535810762300357187714502686418407178"),
+ bigFromBase10("45500384786952622612957507119651934019977750675336102500314001518804928850249"),
+}
+
+// twistGen is the generator of group G₂.
+var twistGen = &twistPoint{
+ &gfP2{
+ bigFromBase10("21167961636542580255011770066570541300993051739349375019639421053990175267184"),
+ bigFromBase10("64746500191241794695844075326670126197795977525365406531717464316923369116492"),
+ },
+ &gfP2{
+ bigFromBase10("20666913350058776956210519119118544732556678129809273996262322366050359951122"),
+ bigFromBase10("17778617556404439934652658462602675281523610326338642107814333856843981424549"),
+ },
+ &gfP2{
+ bigFromBase10("0"),
+ bigFromBase10("1"),
+ },
+ &gfP2{
+ bigFromBase10("0"),
+ bigFromBase10("1"),
+ },
+}
+
+func newTwistPoint(pool *bnPool) *twistPoint {
+ return &twistPoint{
+ newGFp2(pool),
+ newGFp2(pool),
+ newGFp2(pool),
+ newGFp2(pool),
+ }
+}
+
+func (c *twistPoint) String() string {
+ return "(" + c.x.String() + ", " + c.y.String() + ", " + c.z.String() + ")"
+}
+
+func (c *twistPoint) Put(pool *bnPool) {
+ c.x.Put(pool)
+ c.y.Put(pool)
+ c.z.Put(pool)
+ c.t.Put(pool)
+}
+
+func (c *twistPoint) Set(a *twistPoint) {
+ c.x.Set(a.x)
+ c.y.Set(a.y)
+ c.z.Set(a.z)
+ c.t.Set(a.t)
+}
+
+// IsOnCurve returns true iff c is on the curve where c must be in affine form.
+func (c *twistPoint) IsOnCurve() bool {
+ pool := new(bnPool)
+ yy := newGFp2(pool).Square(c.y, pool)
+ xxx := newGFp2(pool).Square(c.x, pool)
+ xxx.Mul(xxx, c.x, pool)
+ yy.Sub(yy, xxx)
+ yy.Sub(yy, twistB)
+ yy.Minimal()
+ return yy.x.Sign() == 0 && yy.y.Sign() == 0
+}
+
+func (c *twistPoint) SetInfinity() {
+ c.z.SetZero()
+}
+
+func (c *twistPoint) IsInfinity() bool {
+ return c.z.IsZero()
+}
+
+func (c *twistPoint) Add(a, b *twistPoint, pool *bnPool) {
+ // For additional comments, see the same function in curve.go.
+
+ if a.IsInfinity() {
+ c.Set(b)
+ return
+ }
+ if b.IsInfinity() {
+ c.Set(a)
+ return
+ }
+
+ // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
+ z1z1 := newGFp2(pool).Square(a.z, pool)
+ z2z2 := newGFp2(pool).Square(b.z, pool)
+ u1 := newGFp2(pool).Mul(a.x, z2z2, pool)
+ u2 := newGFp2(pool).Mul(b.x, z1z1, pool)
+
+ t := newGFp2(pool).Mul(b.z, z2z2, pool)
+ s1 := newGFp2(pool).Mul(a.y, t, pool)
+
+ t.Mul(a.z, z1z1, pool)
+ s2 := newGFp2(pool).Mul(b.y, t, pool)
+
+ h := newGFp2(pool).Sub(u2, u1)
+ xEqual := h.IsZero()
+
+ t.Add(h, h)
+ i := newGFp2(pool).Square(t, pool)
+ j := newGFp2(pool).Mul(h, i, pool)
+
+ t.Sub(s2, s1)
+ yEqual := t.IsZero()
+ if xEqual && yEqual {
+ c.Double(a, pool)
+ return
+ }
+ r := newGFp2(pool).Add(t, t)
+
+ v := newGFp2(pool).Mul(u1, i, pool)
+
+ t4 := newGFp2(pool).Square(r, pool)
+ t.Add(v, v)
+ t6 := newGFp2(pool).Sub(t4, j)
+ c.x.Sub(t6, t)
+
+ t.Sub(v, c.x) // t7
+ t4.Mul(s1, j, pool) // t8
+ t6.Add(t4, t4) // t9
+ t4.Mul(r, t, pool) // t10
+ c.y.Sub(t4, t6)
+
+ t.Add(a.z, b.z) // t11
+ t4.Square(t, pool) // t12
+ t.Sub(t4, z1z1) // t13
+ t4.Sub(t, z2z2) // t14
+ c.z.Mul(t4, h, pool)
+
+ z1z1.Put(pool)
+ z2z2.Put(pool)
+ u1.Put(pool)
+ u2.Put(pool)
+ t.Put(pool)
+ s1.Put(pool)
+ s2.Put(pool)
+ h.Put(pool)
+ i.Put(pool)
+ j.Put(pool)
+ r.Put(pool)
+ v.Put(pool)
+ t4.Put(pool)
+ t6.Put(pool)
+}
+
+func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
+ A := newGFp2(pool).Square(a.x, pool)
+ B := newGFp2(pool).Square(a.y, pool)
+ C := newGFp2(pool).Square(B, pool)
+
+ t := newGFp2(pool).Add(a.x, B)
+ t2 := newGFp2(pool).Square(t, pool)
+ t.Sub(t2, A)
+ t2.Sub(t, C)
+ d := newGFp2(pool).Add(t2, t2)
+ t.Add(A, A)
+ e := newGFp2(pool).Add(t, A)
+ f := newGFp2(pool).Square(e, pool)
+
+ t.Add(d, d)
+ c.x.Sub(f, t)
+
+ t.Add(C, C)
+ t2.Add(t, t)
+ t.Add(t2, t2)
+ c.y.Sub(d, c.x)
+ t2.Mul(e, c.y, pool)
+ c.y.Sub(t2, t)
+
+ t.Mul(a.y, a.z, pool)
+ c.z.Add(t, t)
+
+ A.Put(pool)
+ B.Put(pool)
+ C.Put(pool)
+ t.Put(pool)
+ t2.Put(pool)
+ d.Put(pool)
+ e.Put(pool)
+ f.Put(pool)
+}
+
+func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoint {
+ sum := newTwistPoint(pool)
+ sum.SetInfinity()
+ t := newTwistPoint(pool)
+
+ for i := scalar.BitLen(); i >= 0; i-- {
+ t.Double(sum, pool)
+ if scalar.Bit(i) != 0 {
+ sum.Add(t, a, pool)
+ } else {
+ sum.Set(t)
+ }
+ }
+
+ c.Set(sum)
+ sum.Put(pool)
+ t.Put(pool)
+ return c
+}
+
+func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint {
+ if c.z.IsOne() {
+ return c
+ }
+
+ zInv := newGFp2(pool).Invert(c.z, pool)
+ t := newGFp2(pool).Mul(c.y, zInv, pool)
+ zInv2 := newGFp2(pool).Square(zInv, pool)
+ c.y.Mul(t, zInv2, pool)
+ t.Mul(c.x, zInv2, pool)
+ c.x.Set(t)
+ c.z.SetOne()
+ c.t.SetOne()
+
+ zInv.Put(pool)
+ t.Put(pool)
+ zInv2.Put(pool)
+
+ return c
+}
+
+func (c *twistPoint) Negative(a *twistPoint, pool *bnPool) {
+ c.x.Set(a.x)
+ c.y.SetZero()
+ c.y.Sub(c.y, a.y)
+ c.z.Set(a.z)
+ c.t.SetZero()
+}
diff --git a/vendor/golang.org/x/crypto/cast5/cast5.go b/vendor/golang.org/x/crypto/cast5/cast5.go
new file mode 100644
index 000000000..0b4af37bd
--- /dev/null
+++ b/vendor/golang.org/x/crypto/cast5/cast5.go
@@ -0,0 +1,526 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cast5 implements CAST5, as defined in RFC 2144. CAST5 is a common
+// OpenPGP cipher.
+package cast5 // import "golang.org/x/crypto/cast5"
+
+import "errors"
+
+const BlockSize = 8
+const KeySize = 16
+
+type Cipher struct {
+ masking [16]uint32
+ rotate [16]uint8
+}
+
+func NewCipher(key []byte) (c *Cipher, err error) {
+ if len(key) != KeySize {
+ return nil, errors.New("CAST5: keys must be 16 bytes")
+ }
+
+ c = new(Cipher)
+ c.keySchedule(key)
+ return
+}
+
+func (c *Cipher) BlockSize() int {
+ return BlockSize
+}
+
+func (c *Cipher) Encrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+func (c *Cipher) Decrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+type keyScheduleA [4][7]uint8
+type keyScheduleB [4][5]uint8
+
+// keyScheduleRound contains the magic values for a round of the key schedule.
+// The keyScheduleA deals with the lines like:
+// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
+// Conceptually, both x and z are in the same array, x first. The first
+// element describes which word of this array gets written to and the
+// second, which word gets read. So, for the line above, it's "4, 0", because
+// it's writing to the first word of z, which, being after x, is word 4, and
+// reading from the first word of x: word 0.
+//
+// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
+// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
+// that it's z that we're indexing.
+//
+// keyScheduleB deals with lines like:
+// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
+// "K1" is ignored because key words are always written in order. So the five
+// elements are the S-box indexes. They use the same form as in keyScheduleA,
+// above.
+
+type keyScheduleRound struct{}
+type keySchedule []keyScheduleRound
+
+var schedule = []struct {
+ a keyScheduleA
+ b keyScheduleB
+}{
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
+ {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
+ {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
+ {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {3, 2, 0xc, 0xd, 8},
+ {1, 0, 0xe, 0xf, 0xd},
+ {7, 6, 8, 9, 3},
+ {5, 4, 0xa, 0xb, 7},
+ },
+ },
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
+ {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
+ {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
+ {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {8, 9, 7, 6, 3},
+ {0xa, 0xb, 5, 4, 7},
+ {0xc, 0xd, 3, 2, 8},
+ {0xe, 0xf, 1, 0, 0xd},
+ },
+ },
+}
+
+func (c *Cipher) keySchedule(in []byte) {
+ var t [8]uint32
+ var k [32]uint32
+
+ for i := 0; i < 4; i++ {
+ j := i * 4
+ t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
+ }
+
+ x := []byte{6, 7, 4, 5}
+ ki := 0
+
+ for half := 0; half < 2; half++ {
+ for _, round := range schedule {
+ for j := 0; j < 4; j++ {
+ var a [7]uint8
+ copy(a[:], round.a[j][:])
+ w := t[a[1]]
+ w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
+ w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
+ w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
+ w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
+ w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
+ t[a[0]] = w
+ }
+
+ for j := 0; j < 4; j++ {
+ var b [5]uint8
+ copy(b[:], round.b[j][:])
+ w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
+ w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
+ w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
+ w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
+ w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
+ k[ki] = w
+ ki++
+ }
+ }
+ }
+
+ for i := 0; i < 16; i++ {
+ c.masking[i] = k[i]
+ c.rotate[i] = uint8(k[16+i] & 0x1f)
+ }
+}
+
+// These are the three 'f' functions. See RFC 2144, section 2.2.
+func f1(d, m uint32, r uint8) uint32 {
+ t := m + d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
+}
+
+func f2(d, m uint32, r uint8) uint32 {
+ t := m ^ d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
+}
+
+func f3(d, m uint32, r uint8) uint32 {
+ t := m - d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
+}
+
+var sBox = [8][256]uint32{
+ {
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+ 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+ 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+ 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+ 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+ 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+ 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+ 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+ 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+ 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+ 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+ 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+ 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+ 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+ 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+ 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+ 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+ 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+ 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+ 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+ 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+ 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
+ },
+ {
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+ 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+ 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+ 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+ 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+ 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+ 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+ 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+ 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+ 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+ 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+ 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+ 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+ 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+ 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+ 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+ 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+ 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+ 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+ 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+ 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+ 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
+ },
+ {
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+ 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+ 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+ 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+ 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+ 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+ 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+ 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+ 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+ 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+ 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+ 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+ 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+ 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+ 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+ 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+ 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+ 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+ 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+ 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+ 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+ 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
+ },
+ {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+ 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+ 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+ 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+ 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+ 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+ 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+ 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+ 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+ 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+ 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+ 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+ 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+ 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+ 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+ 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+ 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+ 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+ 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+ 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+ 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+ 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
+ },
+ {
+ 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+ 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+ 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+ 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+ 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+ 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+ 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+ 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+ 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+ 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+ 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+ 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+ 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+ 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+ 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+ 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+ 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+ 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+ 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+ 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+ 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+ 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+ 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+ 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+ 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+ 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+ 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+ 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+ 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+ 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+ 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+ 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
+ },
+ {
+ 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+ 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+ 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+ 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+ 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+ 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+ 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+ 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+ 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+ 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+ 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+ 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+ 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+ 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+ 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+ 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+ 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+ 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+ 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+ 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+ 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+ 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+ 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+ 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+ 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+ 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+ 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+ 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+ 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+ 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+ 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+ 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
+ },
+ {
+ 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+ 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+ 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+ 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+ 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+ 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+ 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+ 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+ 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+ 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+ 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+ 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+ 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+ 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+ 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+ 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+ 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+ 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+ 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+ 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+ 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+ 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+ 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+ 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+ 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+ 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+ 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+ 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+ 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+ 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+ 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+ 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
+ },
+ {
+ 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+ 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+ 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+ 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+ 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+ 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+ 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+ 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+ 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+ 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+ 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+ 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+ 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+ 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+ 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+ 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+ 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+ 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+ 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+ 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+ 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+ 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+ 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+ 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+ 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+ 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+ 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+ 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+ 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+ 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+ 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+ 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
+ },
+}
diff --git a/vendor/golang.org/x/crypto/cast5/cast5_test.go b/vendor/golang.org/x/crypto/cast5/cast5_test.go
new file mode 100644
index 000000000..778b272a6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/cast5/cast5_test.go
@@ -0,0 +1,106 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cast5
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+// This test vector is taken from RFC 2144, App B.1.
+// Since the other two test vectors are for reduced-round variants, we can't
+// use them.
+var basicTests = []struct {
+ key, plainText, cipherText string
+}{
+ {
+ "0123456712345678234567893456789a",
+ "0123456789abcdef",
+ "238b4fe5847e44b2",
+ },
+}
+
+func TestBasic(t *testing.T) {
+ for i, test := range basicTests {
+ key, _ := hex.DecodeString(test.key)
+ plainText, _ := hex.DecodeString(test.plainText)
+ expected, _ := hex.DecodeString(test.cipherText)
+
+ c, err := NewCipher(key)
+ if err != nil {
+ t.Errorf("#%d: failed to create Cipher: %s", i, err)
+ continue
+ }
+ var cipherText [BlockSize]byte
+ c.Encrypt(cipherText[:], plainText)
+ if !bytes.Equal(cipherText[:], expected) {
+ t.Errorf("#%d: got:%x want:%x", i, cipherText, expected)
+ }
+
+ var plainTextAgain [BlockSize]byte
+ c.Decrypt(plainTextAgain[:], cipherText[:])
+ if !bytes.Equal(plainTextAgain[:], plainText) {
+ t.Errorf("#%d: got:%x want:%x", i, plainTextAgain, plainText)
+ }
+ }
+}
+
+// TestFull performs the test specified in RFC 2144, App B.2.
+// However, due to the length of time taken, it's disabled here and a more
+// limited version is included, below.
+func TestFull(t *testing.T) {
+ if testing.Short() {
+ // This is too slow for normal testing
+ return
+ }
+
+ a, b := iterate(1000000)
+
+ const expectedA = "eea9d0a249fd3ba6b3436fb89d6dca92"
+ const expectedB = "b2c95eb00c31ad7180ac05b8e83d696e"
+
+ if hex.EncodeToString(a) != expectedA {
+ t.Errorf("a: got:%x want:%s", a, expectedA)
+ }
+ if hex.EncodeToString(b) != expectedB {
+ t.Errorf("b: got:%x want:%s", b, expectedB)
+ }
+}
+
+func iterate(iterations int) ([]byte, []byte) {
+ const initValueHex = "0123456712345678234567893456789a"
+
+ initValue, _ := hex.DecodeString(initValueHex)
+
+ var a, b [16]byte
+ copy(a[:], initValue)
+ copy(b[:], initValue)
+
+ for i := 0; i < iterations; i++ {
+ c, _ := NewCipher(b[:])
+ c.Encrypt(a[:8], a[:8])
+ c.Encrypt(a[8:], a[8:])
+ c, _ = NewCipher(a[:])
+ c.Encrypt(b[:8], b[:8])
+ c.Encrypt(b[8:], b[8:])
+ }
+
+ return a[:], b[:]
+}
+
+func TestLimited(t *testing.T) {
+ a, b := iterate(1000)
+
+ const expectedA = "23f73b14b02a2ad7dfb9f2c35644798d"
+ const expectedB = "e5bf37eff14c456a40b21ce369370a9f"
+
+ if hex.EncodeToString(a) != expectedA {
+ t.Errorf("a: got:%x want:%s", a, expectedA)
+ }
+ if hex.EncodeToString(b) != expectedB {
+ t.Errorf("b: got:%x want:%s", b, expectedB)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/codereview.cfg b/vendor/golang.org/x/crypto/codereview.cfg
new file mode 100644
index 000000000..3f8b14b64
--- /dev/null
+++ b/vendor/golang.org/x/crypto/codereview.cfg
@@ -0,0 +1 @@
+issuerepo: golang/go
diff --git a/vendor/golang.org/x/crypto/curve25519/const_amd64.s b/vendor/golang.org/x/crypto/curve25519/const_amd64.s
new file mode 100644
index 000000000..797f9b051
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/const_amd64.s
@@ -0,0 +1,20 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF
+GLOBL ·REDMASK51(SB), 8, $8
+
+DATA ·_121666_213(SB)/8, $996687872
+GLOBL ·_121666_213(SB), 8, $8
+
+DATA ·_2P0(SB)/8, $0xFFFFFFFFFFFDA
+GLOBL ·_2P0(SB), 8, $8
+
+DATA ·_2P1234(SB)/8, $0xFFFFFFFFFFFFE
+GLOBL ·_2P1234(SB), 8, $8
diff --git a/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s b/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
new file mode 100644
index 000000000..45484d1b5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
@@ -0,0 +1,88 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+// func cswap(inout *[5]uint64, v uint64)
+TEXT ·cswap(SB),7,$0
+ MOVQ inout+0(FP),DI
+ MOVQ v+8(FP),SI
+
+ CMPQ SI,$1
+ MOVQ 0(DI),SI
+ MOVQ 80(DI),DX
+ MOVQ 8(DI),CX
+ MOVQ 88(DI),R8
+ MOVQ SI,R9
+ CMOVQEQ DX,SI
+ CMOVQEQ R9,DX
+ MOVQ CX,R9
+ CMOVQEQ R8,CX
+ CMOVQEQ R9,R8
+ MOVQ SI,0(DI)
+ MOVQ DX,80(DI)
+ MOVQ CX,8(DI)
+ MOVQ R8,88(DI)
+ MOVQ 16(DI),SI
+ MOVQ 96(DI),DX
+ MOVQ 24(DI),CX
+ MOVQ 104(DI),R8
+ MOVQ SI,R9
+ CMOVQEQ DX,SI
+ CMOVQEQ R9,DX
+ MOVQ CX,R9
+ CMOVQEQ R8,CX
+ CMOVQEQ R9,R8
+ MOVQ SI,16(DI)
+ MOVQ DX,96(DI)
+ MOVQ CX,24(DI)
+ MOVQ R8,104(DI)
+ MOVQ 32(DI),SI
+ MOVQ 112(DI),DX
+ MOVQ 40(DI),CX
+ MOVQ 120(DI),R8
+ MOVQ SI,R9
+ CMOVQEQ DX,SI
+ CMOVQEQ R9,DX
+ MOVQ CX,R9
+ CMOVQEQ R8,CX
+ CMOVQEQ R9,R8
+ MOVQ SI,32(DI)
+ MOVQ DX,112(DI)
+ MOVQ CX,40(DI)
+ MOVQ R8,120(DI)
+ MOVQ 48(DI),SI
+ MOVQ 128(DI),DX
+ MOVQ 56(DI),CX
+ MOVQ 136(DI),R8
+ MOVQ SI,R9
+ CMOVQEQ DX,SI
+ CMOVQEQ R9,DX
+ MOVQ CX,R9
+ CMOVQEQ R8,CX
+ CMOVQEQ R9,R8
+ MOVQ SI,48(DI)
+ MOVQ DX,128(DI)
+ MOVQ CX,56(DI)
+ MOVQ R8,136(DI)
+ MOVQ 64(DI),SI
+ MOVQ 144(DI),DX
+ MOVQ 72(DI),CX
+ MOVQ 152(DI),R8
+ MOVQ SI,R9
+ CMOVQEQ DX,SI
+ CMOVQEQ R9,DX
+ MOVQ CX,R9
+ CMOVQEQ R8,CX
+ CMOVQEQ R9,R8
+ MOVQ SI,64(DI)
+ MOVQ DX,144(DI)
+ MOVQ CX,72(DI)
+ MOVQ R8,152(DI)
+ MOVQ DI,AX
+ MOVQ SI,DX
+ RET
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go
new file mode 100644
index 000000000..6918c47fc
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go
@@ -0,0 +1,841 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// We have a implementation in amd64 assembly so this code is only run on
+// non-amd64 platforms. The amd64 assembly does not support gccgo.
+// +build !amd64 gccgo appengine
+
+package curve25519
+
+// This code is a port of the public domain, "ref10" implementation of
+// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
+
+// fieldElement represents an element of the field GF(2^255 - 19). An element
+// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+// context.
+type fieldElement [10]int32
+
+func feZero(fe *fieldElement) {
+ for i := range fe {
+ fe[i] = 0
+ }
+}
+
+func feOne(fe *fieldElement) {
+ feZero(fe)
+ fe[0] = 1
+}
+
+func feAdd(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] + b[i]
+ }
+}
+
+func feSub(dst, a, b *fieldElement) {
+ for i := range dst {
+ dst[i] = a[i] - b[i]
+ }
+}
+
+func feCopy(dst, src *fieldElement) {
+ for i := range dst {
+ dst[i] = src[i]
+ }
+}
+
+// feCSwap replaces (f,g) with (g,f) if b == 1; replaces (f,g) with (f,g) if b == 0.
+//
+// Preconditions: b in {0,1}.
+func feCSwap(f, g *fieldElement, b int32) {
+ var x fieldElement
+ b = -b
+ for i := range x {
+ x[i] = b & (f[i] ^ g[i])
+ }
+
+ for i := range f {
+ f[i] ^= x[i]
+ }
+ for i := range g {
+ g[i] ^= x[i]
+ }
+}
+
+// load3 reads a 24-bit, little-endian value from in.
+func load3(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ return r
+}
+
+// load4 reads a 32-bit, little-endian value from in.
+func load4(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ r |= int64(in[3]) << 24
+ return r
+}
+
+func feFromBytes(dst *fieldElement, src *[32]byte) {
+ h0 := load4(src[:])
+ h1 := load3(src[4:]) << 6
+ h2 := load3(src[7:]) << 5
+ h3 := load3(src[10:]) << 3
+ h4 := load3(src[13:]) << 2
+ h5 := load4(src[16:])
+ h6 := load3(src[20:]) << 7
+ h7 := load3(src[23:]) << 5
+ h8 := load3(src[26:]) << 4
+ h9 := load3(src[29:]) << 2
+
+ var carry [10]int64
+ carry[9] = (h9 + 1<<24) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + 1<<24) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + 1<<24) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + 1<<24) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + 1<<24) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + 1<<25) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + 1<<25) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + 1<<25) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + 1<<25) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + 1<<25) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ dst[0] = int32(h0)
+ dst[1] = int32(h1)
+ dst[2] = int32(h2)
+ dst[3] = int32(h3)
+ dst[4] = int32(h4)
+ dst[5] = int32(h5)
+ dst[6] = int32(h6)
+ dst[7] = int32(h7)
+ dst[8] = int32(h8)
+ dst[9] = int32(h9)
+}
+
+// feToBytes marshals h to s.
+// Preconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Write p=2^255-19; q=floor(h/p).
+// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+//
+// Proof:
+// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+//
+// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+// Then 0<y<1.
+//
+// Write r=h-pq.
+// Have 0<=r<=p-1=2^255-20.
+// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+//
+// Write x=r+19(2^-255)r+y.
+// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+//
+// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+func feToBytes(s *[32]byte, h *fieldElement) {
+ var carry [10]int32
+
+ q := (19*h[9] + (1 << 24)) >> 25
+ q = (h[0] + q) >> 26
+ q = (h[1] + q) >> 25
+ q = (h[2] + q) >> 26
+ q = (h[3] + q) >> 25
+ q = (h[4] + q) >> 26
+ q = (h[5] + q) >> 25
+ q = (h[6] + q) >> 26
+ q = (h[7] + q) >> 25
+ q = (h[8] + q) >> 26
+ q = (h[9] + q) >> 25
+
+ // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
+ h[0] += 19 * q
+ // Goal: Output h-2^255 q, which is between 0 and 2^255-20.
+
+ carry[0] = h[0] >> 26
+ h[1] += carry[0]
+ h[0] -= carry[0] << 26
+ carry[1] = h[1] >> 25
+ h[2] += carry[1]
+ h[1] -= carry[1] << 25
+ carry[2] = h[2] >> 26
+ h[3] += carry[2]
+ h[2] -= carry[2] << 26
+ carry[3] = h[3] >> 25
+ h[4] += carry[3]
+ h[3] -= carry[3] << 25
+ carry[4] = h[4] >> 26
+ h[5] += carry[4]
+ h[4] -= carry[4] << 26
+ carry[5] = h[5] >> 25
+ h[6] += carry[5]
+ h[5] -= carry[5] << 25
+ carry[6] = h[6] >> 26
+ h[7] += carry[6]
+ h[6] -= carry[6] << 26
+ carry[7] = h[7] >> 25
+ h[8] += carry[7]
+ h[7] -= carry[7] << 25
+ carry[8] = h[8] >> 26
+ h[9] += carry[8]
+ h[8] -= carry[8] << 26
+ carry[9] = h[9] >> 25
+ h[9] -= carry[9] << 25
+ // h10 = carry9
+
+ // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ // Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
+ // evidently 2^255 h10-2^255 q = 0.
+ // Goal: Output h[0]+...+2^230 h[9].
+
+ s[0] = byte(h[0] >> 0)
+ s[1] = byte(h[0] >> 8)
+ s[2] = byte(h[0] >> 16)
+ s[3] = byte((h[0] >> 24) | (h[1] << 2))
+ s[4] = byte(h[1] >> 6)
+ s[5] = byte(h[1] >> 14)
+ s[6] = byte((h[1] >> 22) | (h[2] << 3))
+ s[7] = byte(h[2] >> 5)
+ s[8] = byte(h[2] >> 13)
+ s[9] = byte((h[2] >> 21) | (h[3] << 5))
+ s[10] = byte(h[3] >> 3)
+ s[11] = byte(h[3] >> 11)
+ s[12] = byte((h[3] >> 19) | (h[4] << 6))
+ s[13] = byte(h[4] >> 2)
+ s[14] = byte(h[4] >> 10)
+ s[15] = byte(h[4] >> 18)
+ s[16] = byte(h[5] >> 0)
+ s[17] = byte(h[5] >> 8)
+ s[18] = byte(h[5] >> 16)
+ s[19] = byte((h[5] >> 24) | (h[6] << 1))
+ s[20] = byte(h[6] >> 7)
+ s[21] = byte(h[6] >> 15)
+ s[22] = byte((h[6] >> 23) | (h[7] << 3))
+ s[23] = byte(h[7] >> 5)
+ s[24] = byte(h[7] >> 13)
+ s[25] = byte((h[7] >> 21) | (h[8] << 4))
+ s[26] = byte(h[8] >> 4)
+ s[27] = byte(h[8] >> 12)
+ s[28] = byte((h[8] >> 20) | (h[9] << 6))
+ s[29] = byte(h[9] >> 2)
+ s[30] = byte(h[9] >> 10)
+ s[31] = byte(h[9] >> 18)
+}
+
+// feMul calculates h = f * g
+// Can overlap h with f or g.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Notes on implementation strategy:
+//
+// Using schoolbook multiplication.
+// Karatsuba would save a little in some cost models.
+//
+// Most multiplications by 2 and 19 are 32-bit precomputations;
+// cheaper than 64-bit postcomputations.
+//
+// There is one remaining multiplication by 19 in the carry chain;
+// one *19 precomputation can be merged into this,
+// but the resulting data flow is considerably less clean.
+//
+// There are 12 carries below.
+// 10 of them are 2-way parallelizable and vectorizable.
+// Can get away with 11 carries, but then data flow is much deeper.
+//
+// With tighter constraints on inputs can squeeze carries into int32.
+func feMul(h, f, g *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ g0 := g[0]
+ g1 := g[1]
+ g2 := g[2]
+ g3 := g[3]
+ g4 := g[4]
+ g5 := g[5]
+ g6 := g[6]
+ g7 := g[7]
+ g8 := g[8]
+ g9 := g[9]
+ g1_19 := 19 * g1 // 1.4*2^29
+ g2_19 := 19 * g2 // 1.4*2^30; still ok
+ g3_19 := 19 * g3
+ g4_19 := 19 * g4
+ g5_19 := 19 * g5
+ g6_19 := 19 * g6
+ g7_19 := 19 * g7
+ g8_19 := 19 * g8
+ g9_19 := 19 * g9
+ f1_2 := 2 * f1
+ f3_2 := 2 * f3
+ f5_2 := 2 * f5
+ f7_2 := 2 * f7
+ f9_2 := 2 * f9
+ f0g0 := int64(f0) * int64(g0)
+ f0g1 := int64(f0) * int64(g1)
+ f0g2 := int64(f0) * int64(g2)
+ f0g3 := int64(f0) * int64(g3)
+ f0g4 := int64(f0) * int64(g4)
+ f0g5 := int64(f0) * int64(g5)
+ f0g6 := int64(f0) * int64(g6)
+ f0g7 := int64(f0) * int64(g7)
+ f0g8 := int64(f0) * int64(g8)
+ f0g9 := int64(f0) * int64(g9)
+ f1g0 := int64(f1) * int64(g0)
+ f1g1_2 := int64(f1_2) * int64(g1)
+ f1g2 := int64(f1) * int64(g2)
+ f1g3_2 := int64(f1_2) * int64(g3)
+ f1g4 := int64(f1) * int64(g4)
+ f1g5_2 := int64(f1_2) * int64(g5)
+ f1g6 := int64(f1) * int64(g6)
+ f1g7_2 := int64(f1_2) * int64(g7)
+ f1g8 := int64(f1) * int64(g8)
+ f1g9_38 := int64(f1_2) * int64(g9_19)
+ f2g0 := int64(f2) * int64(g0)
+ f2g1 := int64(f2) * int64(g1)
+ f2g2 := int64(f2) * int64(g2)
+ f2g3 := int64(f2) * int64(g3)
+ f2g4 := int64(f2) * int64(g4)
+ f2g5 := int64(f2) * int64(g5)
+ f2g6 := int64(f2) * int64(g6)
+ f2g7 := int64(f2) * int64(g7)
+ f2g8_19 := int64(f2) * int64(g8_19)
+ f2g9_19 := int64(f2) * int64(g9_19)
+ f3g0 := int64(f3) * int64(g0)
+ f3g1_2 := int64(f3_2) * int64(g1)
+ f3g2 := int64(f3) * int64(g2)
+ f3g3_2 := int64(f3_2) * int64(g3)
+ f3g4 := int64(f3) * int64(g4)
+ f3g5_2 := int64(f3_2) * int64(g5)
+ f3g6 := int64(f3) * int64(g6)
+ f3g7_38 := int64(f3_2) * int64(g7_19)
+ f3g8_19 := int64(f3) * int64(g8_19)
+ f3g9_38 := int64(f3_2) * int64(g9_19)
+ f4g0 := int64(f4) * int64(g0)
+ f4g1 := int64(f4) * int64(g1)
+ f4g2 := int64(f4) * int64(g2)
+ f4g3 := int64(f4) * int64(g3)
+ f4g4 := int64(f4) * int64(g4)
+ f4g5 := int64(f4) * int64(g5)
+ f4g6_19 := int64(f4) * int64(g6_19)
+ f4g7_19 := int64(f4) * int64(g7_19)
+ f4g8_19 := int64(f4) * int64(g8_19)
+ f4g9_19 := int64(f4) * int64(g9_19)
+ f5g0 := int64(f5) * int64(g0)
+ f5g1_2 := int64(f5_2) * int64(g1)
+ f5g2 := int64(f5) * int64(g2)
+ f5g3_2 := int64(f5_2) * int64(g3)
+ f5g4 := int64(f5) * int64(g4)
+ f5g5_38 := int64(f5_2) * int64(g5_19)
+ f5g6_19 := int64(f5) * int64(g6_19)
+ f5g7_38 := int64(f5_2) * int64(g7_19)
+ f5g8_19 := int64(f5) * int64(g8_19)
+ f5g9_38 := int64(f5_2) * int64(g9_19)
+ f6g0 := int64(f6) * int64(g0)
+ f6g1 := int64(f6) * int64(g1)
+ f6g2 := int64(f6) * int64(g2)
+ f6g3 := int64(f6) * int64(g3)
+ f6g4_19 := int64(f6) * int64(g4_19)
+ f6g5_19 := int64(f6) * int64(g5_19)
+ f6g6_19 := int64(f6) * int64(g6_19)
+ f6g7_19 := int64(f6) * int64(g7_19)
+ f6g8_19 := int64(f6) * int64(g8_19)
+ f6g9_19 := int64(f6) * int64(g9_19)
+ f7g0 := int64(f7) * int64(g0)
+ f7g1_2 := int64(f7_2) * int64(g1)
+ f7g2 := int64(f7) * int64(g2)
+ f7g3_38 := int64(f7_2) * int64(g3_19)
+ f7g4_19 := int64(f7) * int64(g4_19)
+ f7g5_38 := int64(f7_2) * int64(g5_19)
+ f7g6_19 := int64(f7) * int64(g6_19)
+ f7g7_38 := int64(f7_2) * int64(g7_19)
+ f7g8_19 := int64(f7) * int64(g8_19)
+ f7g9_38 := int64(f7_2) * int64(g9_19)
+ f8g0 := int64(f8) * int64(g0)
+ f8g1 := int64(f8) * int64(g1)
+ f8g2_19 := int64(f8) * int64(g2_19)
+ f8g3_19 := int64(f8) * int64(g3_19)
+ f8g4_19 := int64(f8) * int64(g4_19)
+ f8g5_19 := int64(f8) * int64(g5_19)
+ f8g6_19 := int64(f8) * int64(g6_19)
+ f8g7_19 := int64(f8) * int64(g7_19)
+ f8g8_19 := int64(f8) * int64(g8_19)
+ f8g9_19 := int64(f8) * int64(g9_19)
+ f9g0 := int64(f9) * int64(g0)
+ f9g1_38 := int64(f9_2) * int64(g1_19)
+ f9g2_19 := int64(f9) * int64(g2_19)
+ f9g3_38 := int64(f9_2) * int64(g3_19)
+ f9g4_19 := int64(f9) * int64(g4_19)
+ f9g5_38 := int64(f9_2) * int64(g5_19)
+ f9g6_19 := int64(f9) * int64(g6_19)
+ f9g7_38 := int64(f9_2) * int64(g7_19)
+ f9g8_19 := int64(f9) * int64(g8_19)
+ f9g9_38 := int64(f9_2) * int64(g9_19)
+ h0 := f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38
+ h1 := f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19
+ h2 := f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38
+ h3 := f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19
+ h4 := f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38
+ h5 := f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19
+ h6 := f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38
+ h7 := f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19
+ h8 := f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38
+ h9 := f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0
+ var carry [10]int64
+
+ // |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+ // i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+ // |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+ // i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ // |h0| <= 2^25
+ // |h4| <= 2^25
+ // |h1| <= 1.51*2^58
+ // |h5| <= 1.51*2^58
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ // |h1| <= 2^24; from now on fits into int32
+ // |h5| <= 2^24; from now on fits into int32
+ // |h2| <= 1.21*2^59
+ // |h6| <= 1.21*2^59
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ // |h2| <= 2^25; from now on fits into int32 unchanged
+ // |h6| <= 2^25; from now on fits into int32 unchanged
+ // |h3| <= 1.51*2^58
+ // |h7| <= 1.51*2^58
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+ // |h3| <= 2^24; from now on fits into int32 unchanged
+ // |h7| <= 2^24; from now on fits into int32 unchanged
+ // |h4| <= 1.52*2^33
+ // |h8| <= 1.52*2^33
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+ // |h4| <= 2^25; from now on fits into int32 unchanged
+ // |h8| <= 2^25; from now on fits into int32 unchanged
+ // |h5| <= 1.01*2^24
+ // |h9| <= 1.51*2^58
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ // |h9| <= 2^24; from now on fits into int32 unchanged
+ // |h0| <= 1.8*2^37
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ // |h0| <= 2^25; from now on fits into int32 unchanged
+ // |h1| <= 1.01*2^24
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feSquare calculates h = f*f. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feSquare(h, f *fieldElement) {
+ f0 := f[0]
+ f1 := f[1]
+ f2 := f[2]
+ f3 := f[3]
+ f4 := f[4]
+ f5 := f[5]
+ f6 := f[6]
+ f7 := f[7]
+ f8 := f[8]
+ f9 := f[9]
+ f0_2 := 2 * f0
+ f1_2 := 2 * f1
+ f2_2 := 2 * f2
+ f3_2 := 2 * f3
+ f4_2 := 2 * f4
+ f5_2 := 2 * f5
+ f6_2 := 2 * f6
+ f7_2 := 2 * f7
+ f5_38 := 38 * f5 // 1.31*2^30
+ f6_19 := 19 * f6 // 1.31*2^30
+ f7_38 := 38 * f7 // 1.31*2^30
+ f8_19 := 19 * f8 // 1.31*2^30
+ f9_38 := 38 * f9 // 1.31*2^30
+ f0f0 := int64(f0) * int64(f0)
+ f0f1_2 := int64(f0_2) * int64(f1)
+ f0f2_2 := int64(f0_2) * int64(f2)
+ f0f3_2 := int64(f0_2) * int64(f3)
+ f0f4_2 := int64(f0_2) * int64(f4)
+ f0f5_2 := int64(f0_2) * int64(f5)
+ f0f6_2 := int64(f0_2) * int64(f6)
+ f0f7_2 := int64(f0_2) * int64(f7)
+ f0f8_2 := int64(f0_2) * int64(f8)
+ f0f9_2 := int64(f0_2) * int64(f9)
+ f1f1_2 := int64(f1_2) * int64(f1)
+ f1f2_2 := int64(f1_2) * int64(f2)
+ f1f3_4 := int64(f1_2) * int64(f3_2)
+ f1f4_2 := int64(f1_2) * int64(f4)
+ f1f5_4 := int64(f1_2) * int64(f5_2)
+ f1f6_2 := int64(f1_2) * int64(f6)
+ f1f7_4 := int64(f1_2) * int64(f7_2)
+ f1f8_2 := int64(f1_2) * int64(f8)
+ f1f9_76 := int64(f1_2) * int64(f9_38)
+ f2f2 := int64(f2) * int64(f2)
+ f2f3_2 := int64(f2_2) * int64(f3)
+ f2f4_2 := int64(f2_2) * int64(f4)
+ f2f5_2 := int64(f2_2) * int64(f5)
+ f2f6_2 := int64(f2_2) * int64(f6)
+ f2f7_2 := int64(f2_2) * int64(f7)
+ f2f8_38 := int64(f2_2) * int64(f8_19)
+ f2f9_38 := int64(f2) * int64(f9_38)
+ f3f3_2 := int64(f3_2) * int64(f3)
+ f3f4_2 := int64(f3_2) * int64(f4)
+ f3f5_4 := int64(f3_2) * int64(f5_2)
+ f3f6_2 := int64(f3_2) * int64(f6)
+ f3f7_76 := int64(f3_2) * int64(f7_38)
+ f3f8_38 := int64(f3_2) * int64(f8_19)
+ f3f9_76 := int64(f3_2) * int64(f9_38)
+ f4f4 := int64(f4) * int64(f4)
+ f4f5_2 := int64(f4_2) * int64(f5)
+ f4f6_38 := int64(f4_2) * int64(f6_19)
+ f4f7_38 := int64(f4) * int64(f7_38)
+ f4f8_38 := int64(f4_2) * int64(f8_19)
+ f4f9_38 := int64(f4) * int64(f9_38)
+ f5f5_38 := int64(f5) * int64(f5_38)
+ f5f6_38 := int64(f5_2) * int64(f6_19)
+ f5f7_76 := int64(f5_2) * int64(f7_38)
+ f5f8_38 := int64(f5_2) * int64(f8_19)
+ f5f9_76 := int64(f5_2) * int64(f9_38)
+ f6f6_19 := int64(f6) * int64(f6_19)
+ f6f7_38 := int64(f6) * int64(f7_38)
+ f6f8_38 := int64(f6_2) * int64(f8_19)
+ f6f9_38 := int64(f6) * int64(f9_38)
+ f7f7_38 := int64(f7) * int64(f7_38)
+ f7f8_38 := int64(f7_2) * int64(f8_19)
+ f7f9_76 := int64(f7_2) * int64(f9_38)
+ f8f8_19 := int64(f8) * int64(f8_19)
+ f8f9_38 := int64(f8) * int64(f9_38)
+ f9f9_38 := int64(f9) * int64(f9_38)
+ h0 := f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38
+ h1 := f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38
+ h2 := f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19
+ h3 := f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38
+ h4 := f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38
+ h5 := f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38
+ h6 := f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19
+ h7 := f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38
+ h8 := f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38
+ h9 := f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2
+ var carry [10]int64
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feMul121666 calculates h = f * 121666. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func feMul121666(h, f *fieldElement) {
+ h0 := int64(f[0]) * 121666
+ h1 := int64(f[1]) * 121666
+ h2 := int64(f[2]) * 121666
+ h3 := int64(f[3]) * 121666
+ h4 := int64(f[4]) * 121666
+ h5 := int64(f[5]) * 121666
+ h6 := int64(f[6]) * 121666
+ h7 := int64(f[7]) * 121666
+ h8 := int64(f[8]) * 121666
+ h9 := int64(f[9]) * 121666
+ var carry [10]int64
+
+ carry[9] = (h9 + (1 << 24)) >> 25
+ h0 += carry[9] * 19
+ h9 -= carry[9] << 25
+ carry[1] = (h1 + (1 << 24)) >> 25
+ h2 += carry[1]
+ h1 -= carry[1] << 25
+ carry[3] = (h3 + (1 << 24)) >> 25
+ h4 += carry[3]
+ h3 -= carry[3] << 25
+ carry[5] = (h5 + (1 << 24)) >> 25
+ h6 += carry[5]
+ h5 -= carry[5] << 25
+ carry[7] = (h7 + (1 << 24)) >> 25
+ h8 += carry[7]
+ h7 -= carry[7] << 25
+
+ carry[0] = (h0 + (1 << 25)) >> 26
+ h1 += carry[0]
+ h0 -= carry[0] << 26
+ carry[2] = (h2 + (1 << 25)) >> 26
+ h3 += carry[2]
+ h2 -= carry[2] << 26
+ carry[4] = (h4 + (1 << 25)) >> 26
+ h5 += carry[4]
+ h4 -= carry[4] << 26
+ carry[6] = (h6 + (1 << 25)) >> 26
+ h7 += carry[6]
+ h6 -= carry[6] << 26
+ carry[8] = (h8 + (1 << 25)) >> 26
+ h9 += carry[8]
+ h8 -= carry[8] << 26
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// feInvert sets out = z^-1.
+func feInvert(out, z *fieldElement) {
+ var t0, t1, t2, t3 fieldElement
+ var i int
+
+ feSquare(&t0, z)
+ for i = 1; i < 1; i++ {
+ feSquare(&t0, &t0)
+ }
+ feSquare(&t1, &t0)
+ for i = 1; i < 2; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(&t1, z, &t1)
+ feMul(&t0, &t0, &t1)
+ feSquare(&t2, &t0)
+ for i = 1; i < 1; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t1, &t2)
+ feSquare(&t2, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 20; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 10; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t2, &t1)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t2, &t2, &t1)
+ feSquare(&t3, &t2)
+ for i = 1; i < 100; i++ {
+ feSquare(&t3, &t3)
+ }
+ feMul(&t2, &t3, &t2)
+ feSquare(&t2, &t2)
+ for i = 1; i < 50; i++ {
+ feSquare(&t2, &t2)
+ }
+ feMul(&t1, &t2, &t1)
+ feSquare(&t1, &t1)
+ for i = 1; i < 5; i++ {
+ feSquare(&t1, &t1)
+ }
+ feMul(out, &t1, &t0)
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+
+ copy(e[:], in[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 fieldElement
+ feFromBytes(&x1, base)
+ feOne(&x2)
+ feCopy(&x3, &x1)
+ feOne(&z3)
+
+ swap := int32(0)
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int32(b)
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+ swap = int32(b)
+
+ feSub(&tmp0, &x3, &z3)
+ feSub(&tmp1, &x2, &z2)
+ feAdd(&x2, &x2, &z2)
+ feAdd(&z2, &x3, &z3)
+ feMul(&z3, &tmp0, &x2)
+ feMul(&z2, &z2, &tmp1)
+ feSquare(&tmp0, &tmp1)
+ feSquare(&tmp1, &x2)
+ feAdd(&x3, &z3, &z2)
+ feSub(&z2, &z3, &z2)
+ feMul(&x2, &tmp1, &tmp0)
+ feSub(&tmp1, &tmp1, &tmp0)
+ feSquare(&z2, &z2)
+ feMul121666(&z3, &tmp1)
+ feSquare(&x3, &x3)
+ feAdd(&tmp0, &tmp0, &z3)
+ feMul(&z3, &x1, &z2)
+ feMul(&z2, &tmp1, &tmp0)
+ }
+
+ feCSwap(&x2, &x3, swap)
+ feCSwap(&z2, &z3, swap)
+
+ feInvert(&z2, &z2)
+ feMul(&x2, &x2, &z2)
+ feToBytes(out, &x2)
+}
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519_test.go b/vendor/golang.org/x/crypto/curve25519/curve25519_test.go
new file mode 100644
index 000000000..14b0ee87c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519_test.go
@@ -0,0 +1,29 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package curve25519
+
+import (
+ "fmt"
+ "testing"
+)
+
+const expectedHex = "89161fde887b2b53de549af483940106ecc114d6982daa98256de23bdf77661a"
+
+func TestBaseScalarMult(t *testing.T) {
+ var a, b [32]byte
+ in := &a
+ out := &b
+ a[0] = 1
+
+ for i := 0; i < 200; i++ {
+ ScalarBaseMult(out, in)
+ in, out = out, in
+ }
+
+ result := fmt.Sprintf("%x", in[:])
+ if result != expectedHex {
+ t.Errorf("incorrect result: got %s, want %s", result, expectedHex)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/curve25519/doc.go b/vendor/golang.org/x/crypto/curve25519/doc.go
new file mode 100644
index 000000000..ebeea3c2d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/doc.go
@@ -0,0 +1,23 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package curve25519 provides an implementation of scalar multiplication on
+// the elliptic curve known as curve25519. See http://cr.yp.to/ecdh.html
+package curve25519 // import "golang.org/x/crypto/curve25519"
+
+// basePoint is the x coordinate of the generator of the curve.
+var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+// ScalarMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points and all values are in little-endian form.
+func ScalarMult(dst, in, base *[32]byte) {
+ scalarMult(dst, in, base)
+}
+
+// ScalarBaseMult sets dst to the product in*base where dst and base are the x
+// coordinates of group points, base is the standard generator and all values
+// are in little-endian form.
+func ScalarBaseMult(dst, in *[32]byte) {
+ ScalarMult(dst, in, &basePoint)
+}
diff --git a/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s b/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
new file mode 100644
index 000000000..37599fac0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
@@ -0,0 +1,94 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+// func freeze(inout *[5]uint64)
+TEXT ·freeze(SB),7,$96-8
+ MOVQ inout+0(FP), DI
+
+ MOVQ SP,R11
+ MOVQ $31,CX
+ NOTQ CX
+ ANDQ CX,SP
+ ADDQ $32,SP
+
+ MOVQ R11,0(SP)
+ MOVQ R12,8(SP)
+ MOVQ R13,16(SP)
+ MOVQ R14,24(SP)
+ MOVQ R15,32(SP)
+ MOVQ BX,40(SP)
+ MOVQ BP,48(SP)
+ MOVQ 0(DI),SI
+ MOVQ 8(DI),DX
+ MOVQ 16(DI),CX
+ MOVQ 24(DI),R8
+ MOVQ 32(DI),R9
+ MOVQ ·REDMASK51(SB),AX
+ MOVQ AX,R10
+ SUBQ $18,R10
+ MOVQ $3,R11
+REDUCELOOP:
+ MOVQ SI,R12
+ SHRQ $51,R12
+ ANDQ AX,SI
+ ADDQ R12,DX
+ MOVQ DX,R12
+ SHRQ $51,R12
+ ANDQ AX,DX
+ ADDQ R12,CX
+ MOVQ CX,R12
+ SHRQ $51,R12
+ ANDQ AX,CX
+ ADDQ R12,R8
+ MOVQ R8,R12
+ SHRQ $51,R12
+ ANDQ AX,R8
+ ADDQ R12,R9
+ MOVQ R9,R12
+ SHRQ $51,R12
+ ANDQ AX,R9
+ IMUL3Q $19,R12,R12
+ ADDQ R12,SI
+ SUBQ $1,R11
+ JA REDUCELOOP
+ MOVQ $1,R12
+ CMPQ R10,SI
+ CMOVQLT R11,R12
+ CMPQ AX,DX
+ CMOVQNE R11,R12
+ CMPQ AX,CX
+ CMOVQNE R11,R12
+ CMPQ AX,R8
+ CMOVQNE R11,R12
+ CMPQ AX,R9
+ CMOVQNE R11,R12
+ NEGQ R12
+ ANDQ R12,AX
+ ANDQ R12,R10
+ SUBQ R10,SI
+ SUBQ AX,DX
+ SUBQ AX,CX
+ SUBQ AX,R8
+ SUBQ AX,R9
+ MOVQ SI,0(DI)
+ MOVQ DX,8(DI)
+ MOVQ CX,16(DI)
+ MOVQ R8,24(DI)
+ MOVQ R9,32(DI)
+ MOVQ 0(SP),R11
+ MOVQ 8(SP),R12
+ MOVQ 16(SP),R13
+ MOVQ 24(SP),R14
+ MOVQ 32(SP),R15
+ MOVQ 40(SP),BX
+ MOVQ 48(SP),BP
+ MOVQ R11,SP
+ MOVQ DI,AX
+ MOVQ SI,DX
+ RET
diff --git a/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s b/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
new file mode 100644
index 000000000..3949f9cfa
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
@@ -0,0 +1,1398 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+// func ladderstep(inout *[5][5]uint64)
+TEXT ·ladderstep(SB),0,$384-8
+ MOVQ inout+0(FP),DI
+
+ MOVQ SP,R11
+ MOVQ $31,CX
+ NOTQ CX
+ ANDQ CX,SP
+ ADDQ $32,SP
+
+ MOVQ R11,0(SP)
+ MOVQ R12,8(SP)
+ MOVQ R13,16(SP)
+ MOVQ R14,24(SP)
+ MOVQ R15,32(SP)
+ MOVQ BX,40(SP)
+ MOVQ BP,48(SP)
+ MOVQ 40(DI),SI
+ MOVQ 48(DI),DX
+ MOVQ 56(DI),CX
+ MOVQ 64(DI),R8
+ MOVQ 72(DI),R9
+ MOVQ SI,AX
+ MOVQ DX,R10
+ MOVQ CX,R11
+ MOVQ R8,R12
+ MOVQ R9,R13
+ ADDQ ·_2P0(SB),AX
+ ADDQ ·_2P1234(SB),R10
+ ADDQ ·_2P1234(SB),R11
+ ADDQ ·_2P1234(SB),R12
+ ADDQ ·_2P1234(SB),R13
+ ADDQ 80(DI),SI
+ ADDQ 88(DI),DX
+ ADDQ 96(DI),CX
+ ADDQ 104(DI),R8
+ ADDQ 112(DI),R9
+ SUBQ 80(DI),AX
+ SUBQ 88(DI),R10
+ SUBQ 96(DI),R11
+ SUBQ 104(DI),R12
+ SUBQ 112(DI),R13
+ MOVQ SI,56(SP)
+ MOVQ DX,64(SP)
+ MOVQ CX,72(SP)
+ MOVQ R8,80(SP)
+ MOVQ R9,88(SP)
+ MOVQ AX,96(SP)
+ MOVQ R10,104(SP)
+ MOVQ R11,112(SP)
+ MOVQ R12,120(SP)
+ MOVQ R13,128(SP)
+ MOVQ 96(SP),AX
+ MULQ 96(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 96(SP),AX
+ SHLQ $1,AX
+ MULQ 104(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 96(SP),AX
+ SHLQ $1,AX
+ MULQ 112(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 96(SP),AX
+ SHLQ $1,AX
+ MULQ 120(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 96(SP),AX
+ SHLQ $1,AX
+ MULQ 128(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 104(SP),AX
+ MULQ 104(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 104(SP),AX
+ SHLQ $1,AX
+ MULQ 112(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 104(SP),AX
+ SHLQ $1,AX
+ MULQ 120(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 104(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 128(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 112(SP),AX
+ MULQ 112(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 112(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 120(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 112(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 128(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 120(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 120(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 120(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 128(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 128(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 128(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,136(SP)
+ MOVQ R8,144(SP)
+ MOVQ R9,152(SP)
+ MOVQ AX,160(SP)
+ MOVQ R10,168(SP)
+ MOVQ 56(SP),AX
+ MULQ 56(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 56(SP),AX
+ SHLQ $1,AX
+ MULQ 64(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 56(SP),AX
+ SHLQ $1,AX
+ MULQ 72(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 56(SP),AX
+ SHLQ $1,AX
+ MULQ 80(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 56(SP),AX
+ SHLQ $1,AX
+ MULQ 88(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 64(SP),AX
+ MULQ 64(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 64(SP),AX
+ SHLQ $1,AX
+ MULQ 72(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 64(SP),AX
+ SHLQ $1,AX
+ MULQ 80(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 64(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 88(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 72(SP),AX
+ MULQ 72(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 72(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 80(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 72(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 88(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 80(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 80(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 80(SP),DX
+ IMUL3Q $38,DX,AX
+ MULQ 88(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 88(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 88(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,176(SP)
+ MOVQ R8,184(SP)
+ MOVQ R9,192(SP)
+ MOVQ AX,200(SP)
+ MOVQ R10,208(SP)
+ MOVQ SI,SI
+ MOVQ R8,DX
+ MOVQ R9,CX
+ MOVQ AX,R8
+ MOVQ R10,R9
+ ADDQ ·_2P0(SB),SI
+ ADDQ ·_2P1234(SB),DX
+ ADDQ ·_2P1234(SB),CX
+ ADDQ ·_2P1234(SB),R8
+ ADDQ ·_2P1234(SB),R9
+ SUBQ 136(SP),SI
+ SUBQ 144(SP),DX
+ SUBQ 152(SP),CX
+ SUBQ 160(SP),R8
+ SUBQ 168(SP),R9
+ MOVQ SI,216(SP)
+ MOVQ DX,224(SP)
+ MOVQ CX,232(SP)
+ MOVQ R8,240(SP)
+ MOVQ R9,248(SP)
+ MOVQ 120(DI),SI
+ MOVQ 128(DI),DX
+ MOVQ 136(DI),CX
+ MOVQ 144(DI),R8
+ MOVQ 152(DI),R9
+ MOVQ SI,AX
+ MOVQ DX,R10
+ MOVQ CX,R11
+ MOVQ R8,R12
+ MOVQ R9,R13
+ ADDQ ·_2P0(SB),AX
+ ADDQ ·_2P1234(SB),R10
+ ADDQ ·_2P1234(SB),R11
+ ADDQ ·_2P1234(SB),R12
+ ADDQ ·_2P1234(SB),R13
+ ADDQ 160(DI),SI
+ ADDQ 168(DI),DX
+ ADDQ 176(DI),CX
+ ADDQ 184(DI),R8
+ ADDQ 192(DI),R9
+ SUBQ 160(DI),AX
+ SUBQ 168(DI),R10
+ SUBQ 176(DI),R11
+ SUBQ 184(DI),R12
+ SUBQ 192(DI),R13
+ MOVQ SI,256(SP)
+ MOVQ DX,264(SP)
+ MOVQ CX,272(SP)
+ MOVQ R8,280(SP)
+ MOVQ R9,288(SP)
+ MOVQ AX,296(SP)
+ MOVQ R10,304(SP)
+ MOVQ R11,312(SP)
+ MOVQ R12,320(SP)
+ MOVQ R13,328(SP)
+ MOVQ 280(SP),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,336(SP)
+ MULQ 112(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 288(SP),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,344(SP)
+ MULQ 104(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 256(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 256(SP),AX
+ MULQ 104(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 256(SP),AX
+ MULQ 112(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 256(SP),AX
+ MULQ 120(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 256(SP),AX
+ MULQ 128(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 264(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 264(SP),AX
+ MULQ 104(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 264(SP),AX
+ MULQ 112(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 264(SP),AX
+ MULQ 120(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 264(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 128(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 272(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 272(SP),AX
+ MULQ 104(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 272(SP),AX
+ MULQ 112(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 272(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 120(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 272(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 128(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 280(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 280(SP),AX
+ MULQ 104(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 336(SP),AX
+ MULQ 120(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 336(SP),AX
+ MULQ 128(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 288(SP),AX
+ MULQ 96(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 344(SP),AX
+ MULQ 112(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 344(SP),AX
+ MULQ 120(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 344(SP),AX
+ MULQ 128(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,96(SP)
+ MOVQ R8,104(SP)
+ MOVQ R9,112(SP)
+ MOVQ AX,120(SP)
+ MOVQ R10,128(SP)
+ MOVQ 320(SP),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,256(SP)
+ MULQ 72(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 328(SP),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,264(SP)
+ MULQ 64(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 296(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 296(SP),AX
+ MULQ 64(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 296(SP),AX
+ MULQ 72(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 296(SP),AX
+ MULQ 80(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 296(SP),AX
+ MULQ 88(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 304(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 304(SP),AX
+ MULQ 64(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 304(SP),AX
+ MULQ 72(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 304(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 304(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 88(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 312(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 312(SP),AX
+ MULQ 64(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 312(SP),AX
+ MULQ 72(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 312(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 80(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 312(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 88(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 320(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 320(SP),AX
+ MULQ 64(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 256(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 256(SP),AX
+ MULQ 88(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 328(SP),AX
+ MULQ 56(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 264(SP),AX
+ MULQ 72(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 264(SP),AX
+ MULQ 80(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 264(SP),AX
+ MULQ 88(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,DX
+ MOVQ R8,CX
+ MOVQ R9,R11
+ MOVQ AX,R12
+ MOVQ R10,R13
+ ADDQ ·_2P0(SB),DX
+ ADDQ ·_2P1234(SB),CX
+ ADDQ ·_2P1234(SB),R11
+ ADDQ ·_2P1234(SB),R12
+ ADDQ ·_2P1234(SB),R13
+ ADDQ 96(SP),SI
+ ADDQ 104(SP),R8
+ ADDQ 112(SP),R9
+ ADDQ 120(SP),AX
+ ADDQ 128(SP),R10
+ SUBQ 96(SP),DX
+ SUBQ 104(SP),CX
+ SUBQ 112(SP),R11
+ SUBQ 120(SP),R12
+ SUBQ 128(SP),R13
+ MOVQ SI,120(DI)
+ MOVQ R8,128(DI)
+ MOVQ R9,136(DI)
+ MOVQ AX,144(DI)
+ MOVQ R10,152(DI)
+ MOVQ DX,160(DI)
+ MOVQ CX,168(DI)
+ MOVQ R11,176(DI)
+ MOVQ R12,184(DI)
+ MOVQ R13,192(DI)
+ MOVQ 120(DI),AX
+ MULQ 120(DI)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 128(DI)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 136(DI)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 144(DI)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 120(DI),AX
+ SHLQ $1,AX
+ MULQ 152(DI)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 128(DI),AX
+ MULQ 128(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 128(DI),AX
+ SHLQ $1,AX
+ MULQ 136(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 128(DI),AX
+ SHLQ $1,AX
+ MULQ 144(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 128(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 136(DI),AX
+ MULQ 136(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 136(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 144(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 136(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 144(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 144(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 144(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 152(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 152(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,120(DI)
+ MOVQ R8,128(DI)
+ MOVQ R9,136(DI)
+ MOVQ AX,144(DI)
+ MOVQ R10,152(DI)
+ MOVQ 160(DI),AX
+ MULQ 160(DI)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 168(DI)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 176(DI)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 184(DI)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 160(DI),AX
+ SHLQ $1,AX
+ MULQ 192(DI)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 168(DI),AX
+ MULQ 168(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 168(DI),AX
+ SHLQ $1,AX
+ MULQ 176(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 168(DI),AX
+ SHLQ $1,AX
+ MULQ 184(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 168(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),AX
+ MULQ 176(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 176(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 184(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 184(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 184(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 184(DI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 192(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 192(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ ANDQ DX,SI
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ADDQ R10,CX
+ ANDQ DX,R8
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ADDQ R12,CX
+ ANDQ DX,R9
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ADDQ R14,CX
+ ANDQ DX,AX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,160(DI)
+ MOVQ R8,168(DI)
+ MOVQ R9,176(DI)
+ MOVQ AX,184(DI)
+ MOVQ R10,192(DI)
+ MOVQ 184(DI),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,56(SP)
+ MULQ 16(DI)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 192(DI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,64(SP)
+ MULQ 8(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 160(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 160(DI),AX
+ MULQ 8(DI)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 160(DI),AX
+ MULQ 16(DI)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 160(DI),AX
+ MULQ 24(DI)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 160(DI),AX
+ MULQ 32(DI)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 168(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 168(DI),AX
+ MULQ 8(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 168(DI),AX
+ MULQ 16(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 168(DI),AX
+ MULQ 24(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 168(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 176(DI),AX
+ MULQ 8(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 176(DI),AX
+ MULQ 16(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 176(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(DI)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 184(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 184(DI),AX
+ MULQ 8(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 56(SP),AX
+ MULQ 24(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 56(SP),AX
+ MULQ 32(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 192(DI),AX
+ MULQ 0(DI)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 64(SP),AX
+ MULQ 16(DI)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 64(SP),AX
+ MULQ 24(DI)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 64(SP),AX
+ MULQ 32(DI)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,160(DI)
+ MOVQ R8,168(DI)
+ MOVQ R9,176(DI)
+ MOVQ AX,184(DI)
+ MOVQ R10,192(DI)
+ MOVQ 200(SP),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,56(SP)
+ MULQ 152(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 208(SP),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,64(SP)
+ MULQ 144(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(SP),AX
+ MULQ 136(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 176(SP),AX
+ MULQ 144(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 176(SP),AX
+ MULQ 152(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 176(SP),AX
+ MULQ 160(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 176(SP),AX
+ MULQ 168(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 184(SP),AX
+ MULQ 136(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 184(SP),AX
+ MULQ 144(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 184(SP),AX
+ MULQ 152(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 184(SP),AX
+ MULQ 160(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 184(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 168(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 192(SP),AX
+ MULQ 136(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 192(SP),AX
+ MULQ 144(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 192(SP),AX
+ MULQ 152(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 192(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 160(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 192(SP),DX
+ IMUL3Q $19,DX,AX
+ MULQ 168(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 200(SP),AX
+ MULQ 136(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 200(SP),AX
+ MULQ 144(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 56(SP),AX
+ MULQ 160(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 56(SP),AX
+ MULQ 168(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 208(SP),AX
+ MULQ 136(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 64(SP),AX
+ MULQ 152(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 64(SP),AX
+ MULQ 160(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 64(SP),AX
+ MULQ 168(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,40(DI)
+ MOVQ R8,48(DI)
+ MOVQ R9,56(DI)
+ MOVQ AX,64(DI)
+ MOVQ R10,72(DI)
+ MOVQ 216(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 224(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,CX
+ MOVQ DX,R8
+ MOVQ 232(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,R8
+ MOVQ DX,R9
+ MOVQ 240(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,R9
+ MOVQ DX,R10
+ MOVQ 248(SP),AX
+ MULQ ·_121666_213(SB)
+ SHRQ $13,AX
+ ADDQ AX,R10
+ IMUL3Q $19,DX,DX
+ ADDQ DX,SI
+ ADDQ 136(SP),SI
+ ADDQ 144(SP),CX
+ ADDQ 152(SP),R8
+ ADDQ 160(SP),R9
+ ADDQ 168(SP),R10
+ MOVQ SI,80(DI)
+ MOVQ CX,88(DI)
+ MOVQ R8,96(DI)
+ MOVQ R9,104(DI)
+ MOVQ R10,112(DI)
+ MOVQ 104(DI),SI
+ IMUL3Q $19,SI,AX
+ MOVQ AX,56(SP)
+ MULQ 232(SP)
+ MOVQ AX,SI
+ MOVQ DX,CX
+ MOVQ 112(DI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,64(SP)
+ MULQ 224(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 80(DI),AX
+ MULQ 216(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 80(DI),AX
+ MULQ 224(SP)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 80(DI),AX
+ MULQ 232(SP)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 80(DI),AX
+ MULQ 240(SP)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 80(DI),AX
+ MULQ 248(SP)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 88(DI),AX
+ MULQ 216(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 88(DI),AX
+ MULQ 224(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 88(DI),AX
+ MULQ 232(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 88(DI),AX
+ MULQ 240(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 88(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 248(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 96(DI),AX
+ MULQ 216(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 96(DI),AX
+ MULQ 224(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 96(DI),AX
+ MULQ 232(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 96(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 240(SP)
+ ADDQ AX,SI
+ ADCQ DX,CX
+ MOVQ 96(DI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 248(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 104(DI),AX
+ MULQ 216(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 104(DI),AX
+ MULQ 224(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 56(SP),AX
+ MULQ 240(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 56(SP),AX
+ MULQ 248(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 112(DI),AX
+ MULQ 216(SP)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 64(SP),AX
+ MULQ 232(SP)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 64(SP),AX
+ MULQ 240(SP)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 64(SP),AX
+ MULQ 248(SP)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ ·REDMASK51(SB),DX
+ SHLQ $13,CX:SI
+ ANDQ DX,SI
+ SHLQ $13,R9:R8
+ ANDQ DX,R8
+ ADDQ CX,R8
+ SHLQ $13,R11:R10
+ ANDQ DX,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ DX,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ DX,R14
+ ADDQ R13,R14
+ IMUL3Q $19,R15,CX
+ ADDQ CX,SI
+ MOVQ SI,CX
+ SHRQ $51,CX
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $51,CX
+ ANDQ DX,SI
+ ADDQ R10,CX
+ MOVQ CX,R9
+ SHRQ $51,CX
+ ANDQ DX,R8
+ ADDQ R12,CX
+ MOVQ CX,AX
+ SHRQ $51,CX
+ ANDQ DX,R9
+ ADDQ R14,CX
+ MOVQ CX,R10
+ SHRQ $51,CX
+ ANDQ DX,AX
+ IMUL3Q $19,CX,CX
+ ADDQ CX,SI
+ ANDQ DX,R10
+ MOVQ SI,80(DI)
+ MOVQ R8,88(DI)
+ MOVQ R9,96(DI)
+ MOVQ AX,104(DI)
+ MOVQ R10,112(DI)
+ MOVQ 0(SP),R11
+ MOVQ 8(SP),R12
+ MOVQ 16(SP),R13
+ MOVQ 24(SP),R14
+ MOVQ 32(SP),R15
+ MOVQ 40(SP),BX
+ MOVQ 48(SP),BP
+ MOVQ R11,SP
+ MOVQ DI,AX
+ MOVQ SI,DX
+ RET
diff --git a/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go b/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
new file mode 100644
index 000000000..5822bd533
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/mont25519_amd64.go
@@ -0,0 +1,240 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package curve25519
+
+// These functions are implemented in the .s files. The names of the functions
+// in the rest of the file are also taken from the SUPERCOP sources to help
+// people following along.
+
+//go:noescape
+
+func cswap(inout *[5]uint64, v uint64)
+
+//go:noescape
+
+func ladderstep(inout *[5][5]uint64)
+
+//go:noescape
+
+func freeze(inout *[5]uint64)
+
+//go:noescape
+
+func mul(dest, a, b *[5]uint64)
+
+//go:noescape
+
+func square(out, in *[5]uint64)
+
+// mladder uses a Montgomery ladder to calculate (xr/zr) *= s.
+func mladder(xr, zr *[5]uint64, s *[32]byte) {
+ var work [5][5]uint64
+
+ work[0] = *xr
+ setint(&work[1], 1)
+ setint(&work[2], 0)
+ work[3] = *xr
+ setint(&work[4], 1)
+
+ j := uint(6)
+ var prevbit byte
+
+ for i := 31; i >= 0; i-- {
+ for j < 8 {
+ bit := ((*s)[i] >> j) & 1
+ swap := bit ^ prevbit
+ prevbit = bit
+ cswap(&work[1], uint64(swap))
+ ladderstep(&work)
+ j--
+ }
+ j = 7
+ }
+
+ *xr = work[1]
+ *zr = work[2]
+}
+
+func scalarMult(out, in, base *[32]byte) {
+ var e [32]byte
+ copy(e[:], (*in)[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var t, z [5]uint64
+ unpack(&t, base)
+ mladder(&t, &z, &e)
+ invert(&z, &z)
+ mul(&t, &t, &z)
+ pack(out, &t)
+}
+
+func setint(r *[5]uint64, v uint64) {
+ r[0] = v
+ r[1] = 0
+ r[2] = 0
+ r[3] = 0
+ r[4] = 0
+}
+
+// unpack sets r = x where r consists of 5, 51-bit limbs in little-endian
+// order.
+func unpack(r *[5]uint64, x *[32]byte) {
+ r[0] = uint64(x[0]) |
+ uint64(x[1])<<8 |
+ uint64(x[2])<<16 |
+ uint64(x[3])<<24 |
+ uint64(x[4])<<32 |
+ uint64(x[5])<<40 |
+ uint64(x[6]&7)<<48
+
+ r[1] = uint64(x[6])>>3 |
+ uint64(x[7])<<5 |
+ uint64(x[8])<<13 |
+ uint64(x[9])<<21 |
+ uint64(x[10])<<29 |
+ uint64(x[11])<<37 |
+ uint64(x[12]&63)<<45
+
+ r[2] = uint64(x[12])>>6 |
+ uint64(x[13])<<2 |
+ uint64(x[14])<<10 |
+ uint64(x[15])<<18 |
+ uint64(x[16])<<26 |
+ uint64(x[17])<<34 |
+ uint64(x[18])<<42 |
+ uint64(x[19]&1)<<50
+
+ r[3] = uint64(x[19])>>1 |
+ uint64(x[20])<<7 |
+ uint64(x[21])<<15 |
+ uint64(x[22])<<23 |
+ uint64(x[23])<<31 |
+ uint64(x[24])<<39 |
+ uint64(x[25]&15)<<47
+
+ r[4] = uint64(x[25])>>4 |
+ uint64(x[26])<<4 |
+ uint64(x[27])<<12 |
+ uint64(x[28])<<20 |
+ uint64(x[29])<<28 |
+ uint64(x[30])<<36 |
+ uint64(x[31]&127)<<44
+}
+
+// pack sets out = x where out is the usual, little-endian form of the 5,
+// 51-bit limbs in x.
+func pack(out *[32]byte, x *[5]uint64) {
+ t := *x
+ freeze(&t)
+
+ out[0] = byte(t[0])
+ out[1] = byte(t[0] >> 8)
+ out[2] = byte(t[0] >> 16)
+ out[3] = byte(t[0] >> 24)
+ out[4] = byte(t[0] >> 32)
+ out[5] = byte(t[0] >> 40)
+ out[6] = byte(t[0] >> 48)
+
+ out[6] ^= byte(t[1]<<3) & 0xf8
+ out[7] = byte(t[1] >> 5)
+ out[8] = byte(t[1] >> 13)
+ out[9] = byte(t[1] >> 21)
+ out[10] = byte(t[1] >> 29)
+ out[11] = byte(t[1] >> 37)
+ out[12] = byte(t[1] >> 45)
+
+ out[12] ^= byte(t[2]<<6) & 0xc0
+ out[13] = byte(t[2] >> 2)
+ out[14] = byte(t[2] >> 10)
+ out[15] = byte(t[2] >> 18)
+ out[16] = byte(t[2] >> 26)
+ out[17] = byte(t[2] >> 34)
+ out[18] = byte(t[2] >> 42)
+ out[19] = byte(t[2] >> 50)
+
+ out[19] ^= byte(t[3]<<1) & 0xfe
+ out[20] = byte(t[3] >> 7)
+ out[21] = byte(t[3] >> 15)
+ out[22] = byte(t[3] >> 23)
+ out[23] = byte(t[3] >> 31)
+ out[24] = byte(t[3] >> 39)
+ out[25] = byte(t[3] >> 47)
+
+ out[25] ^= byte(t[4]<<4) & 0xf0
+ out[26] = byte(t[4] >> 4)
+ out[27] = byte(t[4] >> 12)
+ out[28] = byte(t[4] >> 20)
+ out[29] = byte(t[4] >> 28)
+ out[30] = byte(t[4] >> 36)
+ out[31] = byte(t[4] >> 44)
+}
+
+// invert calculates r = x^-1 mod p using Fermat's little theorem.
+func invert(r *[5]uint64, x *[5]uint64) {
+ var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t [5]uint64
+
+ square(&z2, x) /* 2 */
+ square(&t, &z2) /* 4 */
+ square(&t, &t) /* 8 */
+ mul(&z9, &t, x) /* 9 */
+ mul(&z11, &z9, &z2) /* 11 */
+ square(&t, &z11) /* 22 */
+ mul(&z2_5_0, &t, &z9) /* 2^5 - 2^0 = 31 */
+
+ square(&t, &z2_5_0) /* 2^6 - 2^1 */
+ for i := 1; i < 5; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_10_0, &t, &z2_5_0) /* 2^10 - 2^0 */
+
+ square(&t, &z2_10_0) /* 2^11 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^20 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_20_0, &t, &z2_10_0) /* 2^20 - 2^0 */
+
+ square(&t, &z2_20_0) /* 2^21 - 2^1 */
+ for i := 1; i < 20; i++ { /* 2^40 - 2^20 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_20_0) /* 2^40 - 2^0 */
+
+ square(&t, &t) /* 2^41 - 2^1 */
+ for i := 1; i < 10; i++ { /* 2^50 - 2^10 */
+ square(&t, &t)
+ }
+ mul(&z2_50_0, &t, &z2_10_0) /* 2^50 - 2^0 */
+
+ square(&t, &z2_50_0) /* 2^51 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^100 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&z2_100_0, &t, &z2_50_0) /* 2^100 - 2^0 */
+
+ square(&t, &z2_100_0) /* 2^101 - 2^1 */
+ for i := 1; i < 100; i++ { /* 2^200 - 2^100 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_100_0) /* 2^200 - 2^0 */
+
+ square(&t, &t) /* 2^201 - 2^1 */
+ for i := 1; i < 50; i++ { /* 2^250 - 2^50 */
+ square(&t, &t)
+ }
+ mul(&t, &t, &z2_50_0) /* 2^250 - 2^0 */
+
+ square(&t, &t) /* 2^251 - 2^1 */
+ square(&t, &t) /* 2^252 - 2^2 */
+ square(&t, &t) /* 2^253 - 2^3 */
+
+ square(&t, &t) /* 2^254 - 2^4 */
+
+ square(&t, &t) /* 2^255 - 2^5 */
+ mul(r, &t, &z11) /* 2^255 - 21 */
+}
diff --git a/vendor/golang.org/x/crypto/curve25519/mul_amd64.s b/vendor/golang.org/x/crypto/curve25519/mul_amd64.s
new file mode 100644
index 000000000..e48d183ee
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/mul_amd64.s
@@ -0,0 +1,191 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+// func mul(dest, a, b *[5]uint64)
+TEXT ·mul(SB),0,$128-24
+ MOVQ dest+0(FP), DI
+ MOVQ a+8(FP), SI
+ MOVQ b+16(FP), DX
+
+ MOVQ SP,R11
+ MOVQ $31,CX
+ NOTQ CX
+ ANDQ CX,SP
+ ADDQ $32,SP
+
+ MOVQ R11,0(SP)
+ MOVQ R12,8(SP)
+ MOVQ R13,16(SP)
+ MOVQ R14,24(SP)
+ MOVQ R15,32(SP)
+ MOVQ BX,40(SP)
+ MOVQ BP,48(SP)
+ MOVQ DI,56(SP)
+ MOVQ DX,CX
+ MOVQ 24(SI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,64(SP)
+ MULQ 16(CX)
+ MOVQ AX,R8
+ MOVQ DX,R9
+ MOVQ 32(SI),DX
+ IMUL3Q $19,DX,AX
+ MOVQ AX,72(SP)
+ MULQ 8(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 0(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 0(SI),AX
+ MULQ 8(CX)
+ MOVQ AX,R10
+ MOVQ DX,R11
+ MOVQ 0(SI),AX
+ MULQ 16(CX)
+ MOVQ AX,R12
+ MOVQ DX,R13
+ MOVQ 0(SI),AX
+ MULQ 24(CX)
+ MOVQ AX,R14
+ MOVQ DX,R15
+ MOVQ 0(SI),AX
+ MULQ 32(CX)
+ MOVQ AX,BX
+ MOVQ DX,BP
+ MOVQ 8(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 8(SI),AX
+ MULQ 8(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 8(SI),AX
+ MULQ 16(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 8(SI),AX
+ MULQ 24(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 8(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 16(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 16(SI),AX
+ MULQ 8(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 16(SI),AX
+ MULQ 16(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 16(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(CX)
+ ADDQ AX,R8
+ ADCQ DX,R9
+ MOVQ 16(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 24(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ 24(SI),AX
+ MULQ 8(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 64(SP),AX
+ MULQ 24(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 64(SP),AX
+ MULQ 32(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 32(SI),AX
+ MULQ 0(CX)
+ ADDQ AX,BX
+ ADCQ DX,BP
+ MOVQ 72(SP),AX
+ MULQ 16(CX)
+ ADDQ AX,R10
+ ADCQ DX,R11
+ MOVQ 72(SP),AX
+ MULQ 24(CX)
+ ADDQ AX,R12
+ ADCQ DX,R13
+ MOVQ 72(SP),AX
+ MULQ 32(CX)
+ ADDQ AX,R14
+ ADCQ DX,R15
+ MOVQ ·REDMASK51(SB),SI
+ SHLQ $13,R9:R8
+ ANDQ SI,R8
+ SHLQ $13,R11:R10
+ ANDQ SI,R10
+ ADDQ R9,R10
+ SHLQ $13,R13:R12
+ ANDQ SI,R12
+ ADDQ R11,R12
+ SHLQ $13,R15:R14
+ ANDQ SI,R14
+ ADDQ R13,R14
+ SHLQ $13,BP:BX
+ ANDQ SI,BX
+ ADDQ R15,BX
+ IMUL3Q $19,BP,DX
+ ADDQ DX,R8
+ MOVQ R8,DX
+ SHRQ $51,DX
+ ADDQ R10,DX
+ MOVQ DX,CX
+ SHRQ $51,DX
+ ANDQ SI,R8
+ ADDQ R12,DX
+ MOVQ DX,R9
+ SHRQ $51,DX
+ ANDQ SI,CX
+ ADDQ R14,DX
+ MOVQ DX,AX
+ SHRQ $51,DX
+ ANDQ SI,R9
+ ADDQ BX,DX
+ MOVQ DX,R10
+ SHRQ $51,DX
+ ANDQ SI,AX
+ IMUL3Q $19,DX,DX
+ ADDQ DX,R8
+ ANDQ SI,R10
+ MOVQ R8,0(DI)
+ MOVQ CX,8(DI)
+ MOVQ R9,16(DI)
+ MOVQ AX,24(DI)
+ MOVQ R10,32(DI)
+ MOVQ 0(SP),R11
+ MOVQ 8(SP),R12
+ MOVQ 16(SP),R13
+ MOVQ 24(SP),R14
+ MOVQ 32(SP),R15
+ MOVQ 40(SP),BX
+ MOVQ 48(SP),BP
+ MOVQ R11,SP
+ MOVQ DI,AX
+ MOVQ SI,DX
+ RET
diff --git a/vendor/golang.org/x/crypto/curve25519/square_amd64.s b/vendor/golang.org/x/crypto/curve25519/square_amd64.s
new file mode 100644
index 000000000..78d1a50dd
--- /dev/null
+++ b/vendor/golang.org/x/crypto/curve25519/square_amd64.s
@@ -0,0 +1,153 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+// func square(out, in *[5]uint64)
+TEXT ·square(SB),7,$96-16
+ MOVQ out+0(FP), DI
+ MOVQ in+8(FP), SI
+
+ MOVQ SP,R11
+ MOVQ $31,CX
+ NOTQ CX
+ ANDQ CX,SP
+ ADDQ $32, SP
+
+ MOVQ R11,0(SP)
+ MOVQ R12,8(SP)
+ MOVQ R13,16(SP)
+ MOVQ R14,24(SP)
+ MOVQ R15,32(SP)
+ MOVQ BX,40(SP)
+ MOVQ BP,48(SP)
+ MOVQ 0(SI),AX
+ MULQ 0(SI)
+ MOVQ AX,CX
+ MOVQ DX,R8
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 8(SI)
+ MOVQ AX,R9
+ MOVQ DX,R10
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 16(SI)
+ MOVQ AX,R11
+ MOVQ DX,R12
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 24(SI)
+ MOVQ AX,R13
+ MOVQ DX,R14
+ MOVQ 0(SI),AX
+ SHLQ $1,AX
+ MULQ 32(SI)
+ MOVQ AX,R15
+ MOVQ DX,BX
+ MOVQ 8(SI),AX
+ MULQ 8(SI)
+ ADDQ AX,R11
+ ADCQ DX,R12
+ MOVQ 8(SI),AX
+ SHLQ $1,AX
+ MULQ 16(SI)
+ ADDQ AX,R13
+ ADCQ DX,R14
+ MOVQ 8(SI),AX
+ SHLQ $1,AX
+ MULQ 24(SI)
+ ADDQ AX,R15
+ ADCQ DX,BX
+ MOVQ 8(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,CX
+ ADCQ DX,R8
+ MOVQ 16(SI),AX
+ MULQ 16(SI)
+ ADDQ AX,R15
+ ADCQ DX,BX
+ MOVQ 16(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 24(SI)
+ ADDQ AX,CX
+ ADCQ DX,R8
+ MOVQ 16(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,R9
+ ADCQ DX,R10
+ MOVQ 24(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 24(SI)
+ ADDQ AX,R9
+ ADCQ DX,R10
+ MOVQ 24(SI),DX
+ IMUL3Q $38,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,R11
+ ADCQ DX,R12
+ MOVQ 32(SI),DX
+ IMUL3Q $19,DX,AX
+ MULQ 32(SI)
+ ADDQ AX,R13
+ ADCQ DX,R14
+ MOVQ ·REDMASK51(SB),SI
+ SHLQ $13,R8:CX
+ ANDQ SI,CX
+ SHLQ $13,R10:R9
+ ANDQ SI,R9
+ ADDQ R8,R9
+ SHLQ $13,R12:R11
+ ANDQ SI,R11
+ ADDQ R10,R11
+ SHLQ $13,R14:R13
+ ANDQ SI,R13
+ ADDQ R12,R13
+ SHLQ $13,BX:R15
+ ANDQ SI,R15
+ ADDQ R14,R15
+ IMUL3Q $19,BX,DX
+ ADDQ DX,CX
+ MOVQ CX,DX
+ SHRQ $51,DX
+ ADDQ R9,DX
+ ANDQ SI,CX
+ MOVQ DX,R8
+ SHRQ $51,DX
+ ADDQ R11,DX
+ ANDQ SI,R8
+ MOVQ DX,R9
+ SHRQ $51,DX
+ ADDQ R13,DX
+ ANDQ SI,R9
+ MOVQ DX,AX
+ SHRQ $51,DX
+ ADDQ R15,DX
+ ANDQ SI,AX
+ MOVQ DX,R10
+ SHRQ $51,DX
+ IMUL3Q $19,DX,DX
+ ADDQ DX,CX
+ ANDQ SI,R10
+ MOVQ CX,0(DI)
+ MOVQ R8,8(DI)
+ MOVQ R9,16(DI)
+ MOVQ AX,24(DI)
+ MOVQ R10,32(DI)
+ MOVQ 0(SP),R11
+ MOVQ 8(SP),R12
+ MOVQ 16(SP),R13
+ MOVQ 24(SP),R14
+ MOVQ 32(SP),R15
+ MOVQ 40(SP),BX
+ MOVQ 48(SP),BP
+ MOVQ R11,SP
+ MOVQ DI,AX
+ MOVQ SI,DX
+ RET
diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519.go b/vendor/golang.org/x/crypto/ed25519/ed25519.go
new file mode 100644
index 000000000..f1d95674a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ed25519/ed25519.go
@@ -0,0 +1,181 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ed25519 implements the Ed25519 signature algorithm. See
+// http://ed25519.cr.yp.to/.
+//
+// These functions are also compatible with the “Ed25519” function defined in
+// https://tools.ietf.org/html/draft-irtf-cfrg-eddsa-05.
+package ed25519
+
+// This code is a port of the public domain, “ref10” implementation of ed25519
+// from SUPERCOP.
+
+import (
+ "crypto"
+ cryptorand "crypto/rand"
+ "crypto/sha512"
+ "crypto/subtle"
+ "errors"
+ "io"
+ "strconv"
+
+ "golang.org/x/crypto/ed25519/internal/edwards25519"
+)
+
+const (
+ // PublicKeySize is the size, in bytes, of public keys as used in this package.
+ PublicKeySize = 32
+ // PrivateKeySize is the size, in bytes, of private keys as used in this package.
+ PrivateKeySize = 64
+ // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
+ SignatureSize = 64
+)
+
+// PublicKey is the type of Ed25519 public keys.
+type PublicKey []byte
+
+// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
+type PrivateKey []byte
+
+// Public returns the PublicKey corresponding to priv.
+func (priv PrivateKey) Public() crypto.PublicKey {
+ publicKey := make([]byte, PublicKeySize)
+ copy(publicKey, priv[32:])
+ return PublicKey(publicKey)
+}
+
+// Sign signs the given message with priv.
+// Ed25519 performs two passes over messages to be signed and therefore cannot
+// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
+// indicate the message hasn't been hashed. This can be achieved by passing
+// crypto.Hash(0) as the value for opts.
+func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
+ if opts.HashFunc() != crypto.Hash(0) {
+ return nil, errors.New("ed25519: cannot sign hashed message")
+ }
+
+ return Sign(priv, message), nil
+}
+
+// GenerateKey generates a public/private key pair using entropy from rand.
+// If rand is nil, crypto/rand.Reader will be used.
+func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
+ if rand == nil {
+ rand = cryptorand.Reader
+ }
+
+ privateKey = make([]byte, PrivateKeySize)
+ publicKey = make([]byte, PublicKeySize)
+ _, err = io.ReadFull(rand, privateKey[:32])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ digest := sha512.Sum512(privateKey[:32])
+ digest[0] &= 248
+ digest[31] &= 127
+ digest[31] |= 64
+
+ var A edwards25519.ExtendedGroupElement
+ var hBytes [32]byte
+ copy(hBytes[:], digest[:])
+ edwards25519.GeScalarMultBase(&A, &hBytes)
+ var publicKeyBytes [32]byte
+ A.ToBytes(&publicKeyBytes)
+
+ copy(privateKey[32:], publicKeyBytes[:])
+ copy(publicKey, publicKeyBytes[:])
+
+ return publicKey, privateKey, nil
+}
+
+// Sign signs the message with privateKey and returns a signature. It will
+// panic if len(privateKey) is not PrivateKeySize.
+func Sign(privateKey PrivateKey, message []byte) []byte {
+ if l := len(privateKey); l != PrivateKeySize {
+ panic("ed25519: bad private key length: " + strconv.Itoa(l))
+ }
+
+ h := sha512.New()
+ h.Write(privateKey[:32])
+
+ var digest1, messageDigest, hramDigest [64]byte
+ var expandedSecretKey [32]byte
+ h.Sum(digest1[:0])
+ copy(expandedSecretKey[:], digest1[:])
+ expandedSecretKey[0] &= 248
+ expandedSecretKey[31] &= 63
+ expandedSecretKey[31] |= 64
+
+ h.Reset()
+ h.Write(digest1[32:])
+ h.Write(message)
+ h.Sum(messageDigest[:0])
+
+ var messageDigestReduced [32]byte
+ edwards25519.ScReduce(&messageDigestReduced, &messageDigest)
+ var R edwards25519.ExtendedGroupElement
+ edwards25519.GeScalarMultBase(&R, &messageDigestReduced)
+
+ var encodedR [32]byte
+ R.ToBytes(&encodedR)
+
+ h.Reset()
+ h.Write(encodedR[:])
+ h.Write(privateKey[32:])
+ h.Write(message)
+ h.Sum(hramDigest[:0])
+ var hramDigestReduced [32]byte
+ edwards25519.ScReduce(&hramDigestReduced, &hramDigest)
+
+ var s [32]byte
+ edwards25519.ScMulAdd(&s, &hramDigestReduced, &expandedSecretKey, &messageDigestReduced)
+
+ signature := make([]byte, SignatureSize)
+ copy(signature[:], encodedR[:])
+ copy(signature[32:], s[:])
+
+ return signature
+}
+
+// Verify reports whether sig is a valid signature of message by publicKey. It
+// will panic if len(publicKey) is not PublicKeySize.
+func Verify(publicKey PublicKey, message, sig []byte) bool {
+ if l := len(publicKey); l != PublicKeySize {
+ panic("ed25519: bad public key length: " + strconv.Itoa(l))
+ }
+
+ if len(sig) != SignatureSize || sig[63]&224 != 0 {
+ return false
+ }
+
+ var A edwards25519.ExtendedGroupElement
+ var publicKeyBytes [32]byte
+ copy(publicKeyBytes[:], publicKey)
+ if !A.FromBytes(&publicKeyBytes) {
+ return false
+ }
+ edwards25519.FeNeg(&A.X, &A.X)
+ edwards25519.FeNeg(&A.T, &A.T)
+
+ h := sha512.New()
+ h.Write(sig[:32])
+ h.Write(publicKey[:])
+ h.Write(message)
+ var digest [64]byte
+ h.Sum(digest[:0])
+
+ var hReduced [32]byte
+ edwards25519.ScReduce(&hReduced, &digest)
+
+ var R edwards25519.ProjectiveGroupElement
+ var b [32]byte
+ copy(b[:], sig[32:])
+ edwards25519.GeDoubleScalarMultVartime(&R, &hReduced, &A, &b)
+
+ var checkR [32]byte
+ R.ToBytes(&checkR)
+ return subtle.ConstantTimeCompare(sig[:32], checkR[:]) == 1
+}
diff --git a/vendor/golang.org/x/crypto/ed25519/ed25519_test.go b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
new file mode 100644
index 000000000..638e5255d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ed25519/ed25519_test.go
@@ -0,0 +1,183 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ed25519
+
+import (
+ "bufio"
+ "bytes"
+ "compress/gzip"
+ "crypto"
+ "crypto/rand"
+ "encoding/hex"
+ "os"
+ "strings"
+ "testing"
+
+ "golang.org/x/crypto/ed25519/internal/edwards25519"
+)
+
+type zeroReader struct{}
+
+func (zeroReader) Read(buf []byte) (int, error) {
+ for i := range buf {
+ buf[i] = 0
+ }
+ return len(buf), nil
+}
+
+func TestUnmarshalMarshal(t *testing.T) {
+ pub, _, _ := GenerateKey(rand.Reader)
+
+ var A edwards25519.ExtendedGroupElement
+ var pubBytes [32]byte
+ copy(pubBytes[:], pub)
+ if !A.FromBytes(&pubBytes) {
+ t.Fatalf("ExtendedGroupElement.FromBytes failed")
+ }
+
+ var pub2 [32]byte
+ A.ToBytes(&pub2)
+
+ if pubBytes != pub2 {
+ t.Errorf("FromBytes(%v)->ToBytes does not round-trip, got %x\n", pubBytes, pub2)
+ }
+}
+
+func TestSignVerify(t *testing.T) {
+ var zero zeroReader
+ public, private, _ := GenerateKey(zero)
+
+ message := []byte("test message")
+ sig := Sign(private, message)
+ if !Verify(public, message, sig) {
+ t.Errorf("valid signature rejected")
+ }
+
+ wrongMessage := []byte("wrong message")
+ if Verify(public, wrongMessage, sig) {
+ t.Errorf("signature of different message accepted")
+ }
+}
+
+func TestCryptoSigner(t *testing.T) {
+ var zero zeroReader
+ public, private, _ := GenerateKey(zero)
+
+ signer := crypto.Signer(private)
+
+ publicInterface := signer.Public()
+ public2, ok := publicInterface.(PublicKey)
+ if !ok {
+ t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
+ }
+
+ if !bytes.Equal(public, public2) {
+ t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
+ }
+
+ message := []byte("message")
+ var noHash crypto.Hash
+ signature, err := signer.Sign(zero, message, noHash)
+ if err != nil {
+ t.Fatalf("error from Sign(): %s", err)
+ }
+
+ if !Verify(public, message, signature) {
+ t.Errorf("Verify failed on signature from Sign()")
+ }
+}
+
+func TestGolden(t *testing.T) {
+ // sign.input.gz is a selection of test cases from
+ // http://ed25519.cr.yp.to/python/sign.input
+ testDataZ, err := os.Open("testdata/sign.input.gz")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer testDataZ.Close()
+ testData, err := gzip.NewReader(testDataZ)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer testData.Close()
+
+ scanner := bufio.NewScanner(testData)
+ lineNo := 0
+
+ for scanner.Scan() {
+ lineNo++
+
+ line := scanner.Text()
+ parts := strings.Split(line, ":")
+ if len(parts) != 5 {
+ t.Fatalf("bad number of parts on line %d", lineNo)
+ }
+
+ privBytes, _ := hex.DecodeString(parts[0])
+ pubKey, _ := hex.DecodeString(parts[1])
+ msg, _ := hex.DecodeString(parts[2])
+ sig, _ := hex.DecodeString(parts[3])
+ // The signatures in the test vectors also include the message
+ // at the end, but we just want R and S.
+ sig = sig[:SignatureSize]
+
+ if l := len(pubKey); l != PublicKeySize {
+ t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
+ }
+
+ var priv [PrivateKeySize]byte
+ copy(priv[:], privBytes)
+ copy(priv[32:], pubKey)
+
+ sig2 := Sign(priv[:], msg)
+ if !bytes.Equal(sig, sig2[:]) {
+ t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
+ }
+
+ if !Verify(pubKey, msg, sig2) {
+ t.Errorf("signature failed to verify on line %d", lineNo)
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ t.Fatalf("error reading test data: %s", err)
+ }
+}
+
+func BenchmarkKeyGeneration(b *testing.B) {
+ var zero zeroReader
+ for i := 0; i < b.N; i++ {
+ if _, _, err := GenerateKey(zero); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkSigning(b *testing.B) {
+ var zero zeroReader
+ _, priv, err := GenerateKey(zero)
+ if err != nil {
+ b.Fatal(err)
+ }
+ message := []byte("Hello, world!")
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Sign(priv, message)
+ }
+}
+
+func BenchmarkVerification(b *testing.B) {
+ var zero zeroReader
+ pub, priv, err := GenerateKey(zero)
+ if err != nil {
+ b.Fatal(err)
+ }
+ message := []byte("Hello, world!")
+ signature := Sign(priv, message)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Verify(pub, message, signature)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
new file mode 100644
index 000000000..e39f086c1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
@@ -0,0 +1,1422 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+// These values are from the public domain, “ref10” implementation of ed25519
+// from SUPERCOP.
+
+// d is a constant in the Edwards curve equation.
+var d = FieldElement{
+ -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116,
+}
+
+// d2 is 2*d.
+var d2 = FieldElement{
+ -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199,
+}
+
+// SqrtM1 is the square-root of -1 in the field.
+var SqrtM1 = FieldElement{
+ -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482,
+}
+
+// A is a constant in the Montgomery-form of curve25519.
+var A = FieldElement{
+ 486662, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+}
+
+// bi contains precomputed multiples of the base-point. See the Ed25519 paper
+// for a discussion about how these values are used.
+var bi = [8]PreComputedGroupElement{
+ {
+ FieldElement{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
+ FieldElement{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
+ FieldElement{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546},
+ },
+ {
+ FieldElement{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
+ FieldElement{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
+ FieldElement{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357},
+ },
+ {
+ FieldElement{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
+ FieldElement{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
+ FieldElement{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942},
+ },
+ {
+ FieldElement{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
+ FieldElement{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
+ FieldElement{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300},
+ },
+ {
+ FieldElement{-22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877},
+ FieldElement{-6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951},
+ FieldElement{4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784},
+ },
+ {
+ FieldElement{-25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436},
+ FieldElement{25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918},
+ FieldElement{23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877},
+ },
+ {
+ FieldElement{-33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800},
+ FieldElement{-25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305},
+ FieldElement{-13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300},
+ },
+ {
+ FieldElement{-3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876},
+ FieldElement{-24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619},
+ FieldElement{-3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683},
+ },
+}
+
+// base contains precomputed multiples of the base-point. See the Ed25519 paper
+// for a discussion about how these values are used.
+var base = [32][8]PreComputedGroupElement{
+ {
+ {
+ FieldElement{25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605},
+ FieldElement{-12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378},
+ FieldElement{-8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546},
+ },
+ {
+ FieldElement{-12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303},
+ FieldElement{-21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081},
+ FieldElement{26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697},
+ },
+ {
+ FieldElement{15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024},
+ FieldElement{16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574},
+ FieldElement{30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357},
+ },
+ {
+ FieldElement{-17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540},
+ FieldElement{23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397},
+ FieldElement{7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325},
+ },
+ {
+ FieldElement{10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380},
+ FieldElement{4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306},
+ FieldElement{19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942},
+ },
+ {
+ FieldElement{-15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777},
+ FieldElement{-8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737},
+ FieldElement{-18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652},
+ },
+ {
+ FieldElement{5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766},
+ FieldElement{-30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701},
+ FieldElement{28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300},
+ },
+ {
+ FieldElement{14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726},
+ FieldElement{-7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955},
+ FieldElement{27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425},
+ },
+ },
+ {
+ {
+ FieldElement{-13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171},
+ FieldElement{27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510},
+ FieldElement{17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660},
+ },
+ {
+ FieldElement{-10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639},
+ FieldElement{29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963},
+ FieldElement{5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950},
+ },
+ {
+ FieldElement{-27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568},
+ FieldElement{12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335},
+ FieldElement{25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628},
+ },
+ {
+ FieldElement{-26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007},
+ FieldElement{-2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772},
+ FieldElement{-22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653},
+ },
+ {
+ FieldElement{2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567},
+ FieldElement{13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686},
+ FieldElement{21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372},
+ },
+ {
+ FieldElement{-13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887},
+ FieldElement{-23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954},
+ FieldElement{-29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953},
+ },
+ {
+ FieldElement{24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833},
+ FieldElement{-16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532},
+ FieldElement{-22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876},
+ },
+ {
+ FieldElement{2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268},
+ FieldElement{33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214},
+ FieldElement{1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038},
+ },
+ },
+ {
+ {
+ FieldElement{6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800},
+ FieldElement{4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645},
+ FieldElement{-4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664},
+ },
+ {
+ FieldElement{1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933},
+ FieldElement{-25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182},
+ FieldElement{-17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222},
+ },
+ {
+ FieldElement{-18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991},
+ FieldElement{20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880},
+ FieldElement{9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092},
+ },
+ {
+ FieldElement{-16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295},
+ FieldElement{19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788},
+ FieldElement{8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553},
+ },
+ {
+ FieldElement{-15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026},
+ FieldElement{11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347},
+ FieldElement{-18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033},
+ },
+ {
+ FieldElement{-23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395},
+ FieldElement{-27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278},
+ FieldElement{1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890},
+ },
+ {
+ FieldElement{32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995},
+ FieldElement{-30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596},
+ FieldElement{-11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891},
+ },
+ {
+ FieldElement{31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060},
+ FieldElement{11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608},
+ FieldElement{-20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606},
+ },
+ },
+ {
+ {
+ FieldElement{7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389},
+ FieldElement{-19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016},
+ FieldElement{-11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341},
+ },
+ {
+ FieldElement{-22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505},
+ FieldElement{14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553},
+ FieldElement{-28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655},
+ },
+ {
+ FieldElement{15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220},
+ FieldElement{12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631},
+ FieldElement{-4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099},
+ },
+ {
+ FieldElement{26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556},
+ FieldElement{14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749},
+ FieldElement{236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930},
+ },
+ {
+ FieldElement{1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391},
+ FieldElement{5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253},
+ FieldElement{20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066},
+ },
+ {
+ FieldElement{24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958},
+ FieldElement{-11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082},
+ FieldElement{-28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383},
+ },
+ {
+ FieldElement{-30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521},
+ FieldElement{-11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807},
+ FieldElement{23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948},
+ },
+ {
+ FieldElement{9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134},
+ FieldElement{-32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455},
+ FieldElement{27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629},
+ },
+ },
+ {
+ {
+ FieldElement{-8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069},
+ FieldElement{-32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746},
+ FieldElement{24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919},
+ },
+ {
+ FieldElement{11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837},
+ FieldElement{8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906},
+ FieldElement{-28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771},
+ },
+ {
+ FieldElement{-25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817},
+ FieldElement{10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098},
+ FieldElement{10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409},
+ },
+ {
+ FieldElement{-12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504},
+ FieldElement{-26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727},
+ FieldElement{28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420},
+ },
+ {
+ FieldElement{-32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003},
+ FieldElement{-1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605},
+ FieldElement{-30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384},
+ },
+ {
+ FieldElement{-26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701},
+ FieldElement{-23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683},
+ FieldElement{29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708},
+ },
+ {
+ FieldElement{-3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563},
+ FieldElement{-19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260},
+ FieldElement{-5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387},
+ },
+ {
+ FieldElement{-19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672},
+ FieldElement{23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686},
+ FieldElement{-24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665},
+ },
+ },
+ {
+ {
+ FieldElement{11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182},
+ FieldElement{-31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277},
+ FieldElement{14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628},
+ },
+ {
+ FieldElement{-4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474},
+ FieldElement{-26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539},
+ FieldElement{-25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822},
+ },
+ {
+ FieldElement{-10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970},
+ FieldElement{19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756},
+ FieldElement{-24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508},
+ },
+ {
+ FieldElement{-26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683},
+ FieldElement{-10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655},
+ FieldElement{-20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158},
+ },
+ {
+ FieldElement{-4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125},
+ FieldElement{-15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839},
+ FieldElement{-20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664},
+ },
+ {
+ FieldElement{27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294},
+ FieldElement{-18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899},
+ FieldElement{-11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070},
+ },
+ {
+ FieldElement{3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294},
+ FieldElement{-15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949},
+ FieldElement{-21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083},
+ },
+ {
+ FieldElement{31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420},
+ FieldElement{-5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940},
+ FieldElement{29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396},
+ },
+ },
+ {
+ {
+ FieldElement{-12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567},
+ FieldElement{20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127},
+ FieldElement{-16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294},
+ },
+ {
+ FieldElement{-12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887},
+ FieldElement{22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964},
+ FieldElement{16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195},
+ },
+ {
+ FieldElement{9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244},
+ FieldElement{24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999},
+ FieldElement{-1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762},
+ },
+ {
+ FieldElement{-18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274},
+ FieldElement{-33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236},
+ FieldElement{-16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605},
+ },
+ {
+ FieldElement{-13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761},
+ FieldElement{-22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884},
+ FieldElement{-6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482},
+ },
+ {
+ FieldElement{-24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638},
+ FieldElement{-11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490},
+ FieldElement{-32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170},
+ },
+ {
+ FieldElement{5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736},
+ FieldElement{10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124},
+ FieldElement{-17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392},
+ },
+ {
+ FieldElement{8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029},
+ FieldElement{6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048},
+ FieldElement{28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958},
+ },
+ },
+ {
+ {
+ FieldElement{24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593},
+ FieldElement{26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071},
+ FieldElement{-11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692},
+ },
+ {
+ FieldElement{11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687},
+ FieldElement{-160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441},
+ FieldElement{-20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001},
+ },
+ {
+ FieldElement{-938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460},
+ FieldElement{-19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007},
+ FieldElement{-21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762},
+ },
+ {
+ FieldElement{15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005},
+ FieldElement{-9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674},
+ FieldElement{4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035},
+ },
+ {
+ FieldElement{7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590},
+ FieldElement{-2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957},
+ FieldElement{-30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812},
+ },
+ {
+ FieldElement{33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740},
+ FieldElement{-18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122},
+ FieldElement{-27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158},
+ },
+ {
+ FieldElement{8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885},
+ FieldElement{26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140},
+ FieldElement{19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857},
+ },
+ {
+ FieldElement{801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155},
+ FieldElement{19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260},
+ FieldElement{19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483},
+ },
+ },
+ {
+ {
+ FieldElement{-3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677},
+ FieldElement{32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815},
+ FieldElement{22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751},
+ },
+ {
+ FieldElement{-16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203},
+ FieldElement{-11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208},
+ FieldElement{1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230},
+ },
+ {
+ FieldElement{16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850},
+ FieldElement{-21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389},
+ FieldElement{-9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968},
+ },
+ {
+ FieldElement{-11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689},
+ FieldElement{14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880},
+ FieldElement{5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304},
+ },
+ {
+ FieldElement{30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632},
+ FieldElement{-3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412},
+ FieldElement{20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566},
+ },
+ {
+ FieldElement{-20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038},
+ FieldElement{-26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232},
+ FieldElement{-1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943},
+ },
+ {
+ FieldElement{17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856},
+ FieldElement{23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738},
+ FieldElement{15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971},
+ },
+ {
+ FieldElement{-27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718},
+ FieldElement{-13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697},
+ FieldElement{-11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883},
+ },
+ },
+ {
+ {
+ FieldElement{5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912},
+ FieldElement{-26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358},
+ FieldElement{3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849},
+ },
+ {
+ FieldElement{29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307},
+ FieldElement{-14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977},
+ FieldElement{-6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335},
+ },
+ {
+ FieldElement{-29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644},
+ FieldElement{-22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616},
+ FieldElement{-27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735},
+ },
+ {
+ FieldElement{-21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099},
+ FieldElement{29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341},
+ FieldElement{-936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336},
+ },
+ {
+ FieldElement{-23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646},
+ FieldElement{31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425},
+ FieldElement{-17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388},
+ },
+ {
+ FieldElement{-31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743},
+ FieldElement{-16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822},
+ FieldElement{-8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462},
+ },
+ {
+ FieldElement{18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985},
+ FieldElement{9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702},
+ FieldElement{-22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797},
+ },
+ {
+ FieldElement{21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293},
+ FieldElement{27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100},
+ FieldElement{19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688},
+ },
+ },
+ {
+ {
+ FieldElement{12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186},
+ FieldElement{2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610},
+ FieldElement{-2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707},
+ },
+ {
+ FieldElement{7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220},
+ FieldElement{915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025},
+ FieldElement{32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044},
+ },
+ {
+ FieldElement{32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992},
+ FieldElement{-4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027},
+ FieldElement{21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197},
+ },
+ {
+ FieldElement{8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901},
+ FieldElement{31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952},
+ FieldElement{19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878},
+ },
+ {
+ FieldElement{-28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390},
+ FieldElement{32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730},
+ FieldElement{2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730},
+ },
+ {
+ FieldElement{-19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180},
+ FieldElement{-30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272},
+ FieldElement{-15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715},
+ },
+ {
+ FieldElement{-22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970},
+ FieldElement{-31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772},
+ FieldElement{-17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865},
+ },
+ {
+ FieldElement{15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750},
+ FieldElement{20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373},
+ FieldElement{32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348},
+ },
+ },
+ {
+ {
+ FieldElement{9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144},
+ FieldElement{-22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195},
+ FieldElement{5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086},
+ },
+ {
+ FieldElement{-13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684},
+ FieldElement{-8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518},
+ FieldElement{-2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233},
+ },
+ {
+ FieldElement{-5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793},
+ FieldElement{-2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794},
+ FieldElement{580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435},
+ },
+ {
+ FieldElement{23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921},
+ FieldElement{13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518},
+ FieldElement{2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563},
+ },
+ {
+ FieldElement{14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278},
+ FieldElement{-27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024},
+ FieldElement{4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030},
+ },
+ {
+ FieldElement{10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783},
+ FieldElement{27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717},
+ FieldElement{6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844},
+ },
+ {
+ FieldElement{14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333},
+ FieldElement{16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048},
+ FieldElement{22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760},
+ },
+ {
+ FieldElement{-4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760},
+ FieldElement{-15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757},
+ FieldElement{-2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112},
+ },
+ },
+ {
+ {
+ FieldElement{-19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468},
+ FieldElement{3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184},
+ FieldElement{10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289},
+ },
+ {
+ FieldElement{15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066},
+ FieldElement{24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882},
+ FieldElement{13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226},
+ },
+ {
+ FieldElement{16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101},
+ FieldElement{29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279},
+ FieldElement{-6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811},
+ },
+ {
+ FieldElement{27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709},
+ FieldElement{20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714},
+ FieldElement{-2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121},
+ },
+ {
+ FieldElement{9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464},
+ FieldElement{12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847},
+ FieldElement{13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400},
+ },
+ {
+ FieldElement{4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414},
+ FieldElement{-15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158},
+ FieldElement{17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045},
+ },
+ {
+ FieldElement{-461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415},
+ FieldElement{-5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459},
+ FieldElement{-31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079},
+ },
+ {
+ FieldElement{21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412},
+ FieldElement{-20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743},
+ FieldElement{-14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836},
+ },
+ },
+ {
+ {
+ FieldElement{12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022},
+ FieldElement{18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429},
+ FieldElement{-6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065},
+ },
+ {
+ FieldElement{30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861},
+ FieldElement{10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000},
+ FieldElement{-33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101},
+ },
+ {
+ FieldElement{32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815},
+ FieldElement{29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642},
+ FieldElement{10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966},
+ },
+ {
+ FieldElement{25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574},
+ FieldElement{-21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742},
+ FieldElement{-18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689},
+ },
+ {
+ FieldElement{12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020},
+ FieldElement{-10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772},
+ FieldElement{3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982},
+ },
+ {
+ FieldElement{-14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953},
+ FieldElement{-16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218},
+ FieldElement{-17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265},
+ },
+ {
+ FieldElement{29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073},
+ FieldElement{-3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325},
+ FieldElement{-11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798},
+ },
+ {
+ FieldElement{-4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870},
+ FieldElement{-7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863},
+ FieldElement{-13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927},
+ },
+ },
+ {
+ {
+ FieldElement{-2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267},
+ FieldElement{-9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663},
+ FieldElement{22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862},
+ },
+ {
+ FieldElement{-25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673},
+ FieldElement{15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943},
+ FieldElement{15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020},
+ },
+ {
+ FieldElement{-4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238},
+ FieldElement{11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064},
+ FieldElement{14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795},
+ },
+ {
+ FieldElement{15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052},
+ FieldElement{-10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904},
+ FieldElement{29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531},
+ },
+ {
+ FieldElement{-13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979},
+ FieldElement{-5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841},
+ FieldElement{10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431},
+ },
+ {
+ FieldElement{10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324},
+ FieldElement{-31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940},
+ FieldElement{10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320},
+ },
+ {
+ FieldElement{-15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184},
+ FieldElement{14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114},
+ FieldElement{30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878},
+ },
+ {
+ FieldElement{12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784},
+ FieldElement{-2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091},
+ FieldElement{-16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585},
+ },
+ },
+ {
+ {
+ FieldElement{-8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208},
+ FieldElement{10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864},
+ FieldElement{17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661},
+ },
+ {
+ FieldElement{7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233},
+ FieldElement{26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212},
+ FieldElement{-12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525},
+ },
+ {
+ FieldElement{-24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068},
+ FieldElement{9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397},
+ FieldElement{-8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988},
+ },
+ {
+ FieldElement{5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889},
+ FieldElement{32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038},
+ FieldElement{14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697},
+ },
+ {
+ FieldElement{20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875},
+ FieldElement{-25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905},
+ FieldElement{-25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656},
+ },
+ {
+ FieldElement{11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818},
+ FieldElement{27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714},
+ FieldElement{10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203},
+ },
+ {
+ FieldElement{20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931},
+ FieldElement{-30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024},
+ FieldElement{-23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084},
+ },
+ {
+ FieldElement{-1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204},
+ FieldElement{20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817},
+ FieldElement{27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667},
+ },
+ },
+ {
+ {
+ FieldElement{11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504},
+ FieldElement{-12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768},
+ FieldElement{-19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255},
+ },
+ {
+ FieldElement{6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790},
+ FieldElement{1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438},
+ FieldElement{-22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333},
+ },
+ {
+ FieldElement{17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971},
+ FieldElement{31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905},
+ FieldElement{29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409},
+ },
+ {
+ FieldElement{12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409},
+ FieldElement{6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499},
+ FieldElement{-8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363},
+ },
+ {
+ FieldElement{28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664},
+ FieldElement{-11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324},
+ FieldElement{-21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940},
+ },
+ {
+ FieldElement{13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990},
+ FieldElement{-17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914},
+ FieldElement{-25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290},
+ },
+ {
+ FieldElement{24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257},
+ FieldElement{-6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433},
+ FieldElement{-16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236},
+ },
+ {
+ FieldElement{-12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045},
+ FieldElement{11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093},
+ FieldElement{-1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347},
+ },
+ },
+ {
+ {
+ FieldElement{-28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191},
+ FieldElement{-15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507},
+ FieldElement{-12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906},
+ },
+ {
+ FieldElement{3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018},
+ FieldElement{-16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109},
+ FieldElement{-23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926},
+ },
+ {
+ FieldElement{-24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528},
+ FieldElement{8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625},
+ FieldElement{-32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286},
+ },
+ {
+ FieldElement{2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033},
+ FieldElement{27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866},
+ FieldElement{21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896},
+ },
+ {
+ FieldElement{30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075},
+ FieldElement{26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347},
+ FieldElement{-22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437},
+ },
+ {
+ FieldElement{-5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165},
+ FieldElement{-18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588},
+ FieldElement{-32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193},
+ },
+ {
+ FieldElement{-19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017},
+ FieldElement{-28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883},
+ FieldElement{21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961},
+ },
+ {
+ FieldElement{8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043},
+ FieldElement{29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663},
+ FieldElement{-20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362},
+ },
+ },
+ {
+ {
+ FieldElement{-33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860},
+ FieldElement{2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466},
+ FieldElement{-24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063},
+ },
+ {
+ FieldElement{-26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997},
+ FieldElement{-1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295},
+ FieldElement{-13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369},
+ },
+ {
+ FieldElement{9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385},
+ FieldElement{18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109},
+ FieldElement{2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906},
+ },
+ {
+ FieldElement{4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424},
+ FieldElement{-19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185},
+ FieldElement{7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962},
+ },
+ {
+ FieldElement{-7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325},
+ FieldElement{10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593},
+ FieldElement{696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404},
+ },
+ {
+ FieldElement{-11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644},
+ FieldElement{17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801},
+ FieldElement{26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804},
+ },
+ {
+ FieldElement{-31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884},
+ FieldElement{-586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577},
+ FieldElement{-9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849},
+ },
+ {
+ FieldElement{32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473},
+ FieldElement{-8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644},
+ FieldElement{-2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319},
+ },
+ },
+ {
+ {
+ FieldElement{-11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599},
+ FieldElement{-9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768},
+ FieldElement{-27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084},
+ },
+ {
+ FieldElement{-27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328},
+ FieldElement{-15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369},
+ FieldElement{20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920},
+ },
+ {
+ FieldElement{12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815},
+ FieldElement{-32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025},
+ FieldElement{-21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397},
+ },
+ {
+ FieldElement{-20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448},
+ FieldElement{6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981},
+ FieldElement{30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165},
+ },
+ {
+ FieldElement{32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501},
+ FieldElement{17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073},
+ FieldElement{-1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861},
+ },
+ {
+ FieldElement{14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845},
+ FieldElement{-1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211},
+ FieldElement{18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870},
+ },
+ {
+ FieldElement{10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096},
+ FieldElement{33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803},
+ FieldElement{-32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168},
+ },
+ {
+ FieldElement{30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965},
+ FieldElement{-14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505},
+ FieldElement{18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598},
+ },
+ },
+ {
+ {
+ FieldElement{5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782},
+ FieldElement{5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900},
+ FieldElement{-31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479},
+ },
+ {
+ FieldElement{-12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208},
+ FieldElement{8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232},
+ FieldElement{17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719},
+ },
+ {
+ FieldElement{16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271},
+ FieldElement{-4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326},
+ FieldElement{-8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132},
+ },
+ {
+ FieldElement{14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300},
+ FieldElement{8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570},
+ FieldElement{15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670},
+ },
+ {
+ FieldElement{-2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994},
+ FieldElement{-12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913},
+ FieldElement{31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317},
+ },
+ {
+ FieldElement{-25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730},
+ FieldElement{842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096},
+ FieldElement{-4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078},
+ },
+ {
+ FieldElement{-15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411},
+ FieldElement{-19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905},
+ FieldElement{-9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654},
+ },
+ {
+ FieldElement{-28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870},
+ FieldElement{-23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498},
+ FieldElement{12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579},
+ },
+ },
+ {
+ {
+ FieldElement{14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677},
+ FieldElement{10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647},
+ FieldElement{-2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743},
+ },
+ {
+ FieldElement{-25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468},
+ FieldElement{21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375},
+ FieldElement{-25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155},
+ },
+ {
+ FieldElement{6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725},
+ FieldElement{-12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612},
+ FieldElement{-10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943},
+ },
+ {
+ FieldElement{-30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944},
+ FieldElement{30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928},
+ FieldElement{9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406},
+ },
+ {
+ FieldElement{22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139},
+ FieldElement{-8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963},
+ FieldElement{-31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693},
+ },
+ {
+ FieldElement{1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734},
+ FieldElement{-448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680},
+ FieldElement{-24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410},
+ },
+ {
+ FieldElement{-9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931},
+ FieldElement{-16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654},
+ FieldElement{22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710},
+ },
+ {
+ FieldElement{29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180},
+ FieldElement{-26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684},
+ FieldElement{-10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895},
+ },
+ },
+ {
+ {
+ FieldElement{22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501},
+ FieldElement{-11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413},
+ FieldElement{6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880},
+ },
+ {
+ FieldElement{-8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874},
+ FieldElement{22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962},
+ FieldElement{-7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899},
+ },
+ {
+ FieldElement{21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152},
+ FieldElement{9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063},
+ FieldElement{7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080},
+ },
+ {
+ FieldElement{-9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146},
+ FieldElement{-17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183},
+ FieldElement{-19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133},
+ },
+ {
+ FieldElement{-32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421},
+ FieldElement{-3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622},
+ FieldElement{-4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197},
+ },
+ {
+ FieldElement{2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663},
+ FieldElement{31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753},
+ FieldElement{4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755},
+ },
+ {
+ FieldElement{-9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862},
+ FieldElement{-26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118},
+ FieldElement{26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171},
+ },
+ {
+ FieldElement{15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380},
+ FieldElement{16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824},
+ FieldElement{28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270},
+ },
+ },
+ {
+ {
+ FieldElement{-817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438},
+ FieldElement{-31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584},
+ FieldElement{-594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562},
+ },
+ {
+ FieldElement{30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471},
+ FieldElement{18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610},
+ FieldElement{19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269},
+ },
+ {
+ FieldElement{-30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650},
+ FieldElement{14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369},
+ FieldElement{19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461},
+ },
+ {
+ FieldElement{30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462},
+ FieldElement{-5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793},
+ FieldElement{-2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218},
+ },
+ {
+ FieldElement{-24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226},
+ FieldElement{18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019},
+ FieldElement{-15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037},
+ },
+ {
+ FieldElement{31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171},
+ FieldElement{-17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132},
+ FieldElement{-28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841},
+ },
+ {
+ FieldElement{21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181},
+ FieldElement{-33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210},
+ FieldElement{-1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040},
+ },
+ {
+ FieldElement{3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935},
+ FieldElement{24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105},
+ FieldElement{-28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814},
+ },
+ },
+ {
+ {
+ FieldElement{793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852},
+ FieldElement{5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581},
+ FieldElement{-4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646},
+ },
+ {
+ FieldElement{10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844},
+ FieldElement{10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025},
+ FieldElement{27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453},
+ },
+ {
+ FieldElement{-23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068},
+ FieldElement{4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192},
+ FieldElement{-17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921},
+ },
+ {
+ FieldElement{-9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259},
+ FieldElement{-12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426},
+ FieldElement{-5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072},
+ },
+ {
+ FieldElement{-17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305},
+ FieldElement{13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832},
+ FieldElement{28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943},
+ },
+ {
+ FieldElement{-16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011},
+ FieldElement{24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447},
+ FieldElement{17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494},
+ },
+ {
+ FieldElement{-28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245},
+ FieldElement{-20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859},
+ FieldElement{28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915},
+ },
+ {
+ FieldElement{16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707},
+ FieldElement{10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848},
+ FieldElement{-11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224},
+ },
+ },
+ {
+ {
+ FieldElement{-25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391},
+ FieldElement{15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215},
+ FieldElement{-23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101},
+ },
+ {
+ FieldElement{23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713},
+ FieldElement{21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849},
+ FieldElement{-7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930},
+ },
+ {
+ FieldElement{-29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940},
+ FieldElement{-21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031},
+ FieldElement{-17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404},
+ },
+ {
+ FieldElement{-25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243},
+ FieldElement{-23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116},
+ FieldElement{-24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525},
+ },
+ {
+ FieldElement{-23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509},
+ FieldElement{-10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883},
+ FieldElement{15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865},
+ },
+ {
+ FieldElement{-3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660},
+ FieldElement{4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273},
+ FieldElement{-28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138},
+ },
+ {
+ FieldElement{-25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560},
+ FieldElement{-10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135},
+ FieldElement{2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941},
+ },
+ {
+ FieldElement{-4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739},
+ FieldElement{18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756},
+ FieldElement{-30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819},
+ },
+ },
+ {
+ {
+ FieldElement{-6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347},
+ FieldElement{-27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028},
+ FieldElement{21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075},
+ },
+ {
+ FieldElement{16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799},
+ FieldElement{-2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609},
+ FieldElement{-25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817},
+ },
+ {
+ FieldElement{-23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989},
+ FieldElement{-30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523},
+ FieldElement{4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278},
+ },
+ {
+ FieldElement{31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045},
+ FieldElement{19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377},
+ FieldElement{24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480},
+ },
+ {
+ FieldElement{17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016},
+ FieldElement{510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426},
+ FieldElement{18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525},
+ },
+ {
+ FieldElement{13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396},
+ FieldElement{9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080},
+ FieldElement{12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892},
+ },
+ {
+ FieldElement{15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275},
+ FieldElement{11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074},
+ FieldElement{20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140},
+ },
+ {
+ FieldElement{-16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717},
+ FieldElement{-1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101},
+ FieldElement{24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127},
+ },
+ },
+ {
+ {
+ FieldElement{-12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632},
+ FieldElement{-26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415},
+ FieldElement{-31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160},
+ },
+ {
+ FieldElement{31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876},
+ FieldElement{22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625},
+ FieldElement{-15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478},
+ },
+ {
+ FieldElement{27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164},
+ FieldElement{26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595},
+ FieldElement{-7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248},
+ },
+ {
+ FieldElement{-16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858},
+ FieldElement{15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193},
+ FieldElement{8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184},
+ },
+ {
+ FieldElement{-18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942},
+ FieldElement{-1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635},
+ FieldElement{21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948},
+ },
+ {
+ FieldElement{11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935},
+ FieldElement{-25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415},
+ FieldElement{-15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416},
+ },
+ {
+ FieldElement{-7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018},
+ FieldElement{4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778},
+ FieldElement{366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659},
+ },
+ {
+ FieldElement{-24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385},
+ FieldElement{18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503},
+ FieldElement{476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329},
+ },
+ },
+ {
+ {
+ FieldElement{20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056},
+ FieldElement{-13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838},
+ FieldElement{24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948},
+ },
+ {
+ FieldElement{-3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691},
+ FieldElement{-15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118},
+ FieldElement{-23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517},
+ },
+ {
+ FieldElement{-20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269},
+ FieldElement{-6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904},
+ FieldElement{-23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589},
+ },
+ {
+ FieldElement{-28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193},
+ FieldElement{-7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910},
+ FieldElement{-30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930},
+ },
+ {
+ FieldElement{-7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667},
+ FieldElement{25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481},
+ FieldElement{-9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876},
+ },
+ {
+ FieldElement{22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640},
+ FieldElement{-8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278},
+ FieldElement{-21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112},
+ },
+ {
+ FieldElement{26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272},
+ FieldElement{17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012},
+ FieldElement{-10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221},
+ },
+ {
+ FieldElement{30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046},
+ FieldElement{13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345},
+ FieldElement{-19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310},
+ },
+ },
+ {
+ {
+ FieldElement{19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937},
+ FieldElement{31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636},
+ FieldElement{-9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008},
+ },
+ {
+ FieldElement{-2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429},
+ FieldElement{-15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576},
+ FieldElement{31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066},
+ },
+ {
+ FieldElement{-9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490},
+ FieldElement{-12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104},
+ FieldElement{33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053},
+ },
+ {
+ FieldElement{31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275},
+ FieldElement{-20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511},
+ FieldElement{22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095},
+ },
+ {
+ FieldElement{-28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439},
+ FieldElement{23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939},
+ FieldElement{-23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424},
+ },
+ {
+ FieldElement{2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310},
+ FieldElement{3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608},
+ FieldElement{-32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079},
+ },
+ {
+ FieldElement{-23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101},
+ FieldElement{21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418},
+ FieldElement{18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576},
+ },
+ {
+ FieldElement{30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356},
+ FieldElement{9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996},
+ FieldElement{-26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099},
+ },
+ },
+ {
+ {
+ FieldElement{-26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728},
+ FieldElement{-13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658},
+ FieldElement{-10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242},
+ },
+ {
+ FieldElement{-21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001},
+ FieldElement{-4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766},
+ FieldElement{18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373},
+ },
+ {
+ FieldElement{26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458},
+ FieldElement{-17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628},
+ FieldElement{-13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657},
+ },
+ {
+ FieldElement{-23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062},
+ FieldElement{25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616},
+ FieldElement{31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014},
+ },
+ {
+ FieldElement{24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383},
+ FieldElement{-25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814},
+ FieldElement{-20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718},
+ },
+ {
+ FieldElement{30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417},
+ FieldElement{2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222},
+ FieldElement{33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444},
+ },
+ {
+ FieldElement{-20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597},
+ FieldElement{23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970},
+ FieldElement{1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799},
+ },
+ {
+ FieldElement{-5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647},
+ FieldElement{13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511},
+ FieldElement{-29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032},
+ },
+ },
+ {
+ {
+ FieldElement{9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834},
+ FieldElement{-23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461},
+ FieldElement{29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062},
+ },
+ {
+ FieldElement{-25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516},
+ FieldElement{-20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547},
+ FieldElement{-24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240},
+ },
+ {
+ FieldElement{-17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038},
+ FieldElement{-33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741},
+ FieldElement{16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103},
+ },
+ {
+ FieldElement{-19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747},
+ FieldElement{-1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323},
+ FieldElement{31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016},
+ },
+ {
+ FieldElement{-14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373},
+ FieldElement{15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228},
+ FieldElement{-2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141},
+ },
+ {
+ FieldElement{16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399},
+ FieldElement{11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831},
+ FieldElement{-185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376},
+ },
+ {
+ FieldElement{-32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313},
+ FieldElement{-18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958},
+ FieldElement{-6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577},
+ },
+ {
+ FieldElement{-22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743},
+ FieldElement{29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684},
+ FieldElement{-20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476},
+ },
+ },
+}
diff --git a/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
new file mode 100644
index 000000000..5f8b99478
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
@@ -0,0 +1,1771 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+// This code is a port of the public domain, “ref10” implementation of ed25519
+// from SUPERCOP.
+
+// FieldElement represents an element of the field GF(2^255 - 19). An element
+// t, entries t[0]...t[9], represents the integer t[0]+2^26 t[1]+2^51 t[2]+2^77
+// t[3]+2^102 t[4]+...+2^230 t[9]. Bounds on each t[i] vary depending on
+// context.
+type FieldElement [10]int32
+
+var zero FieldElement
+
+func FeZero(fe *FieldElement) {
+ copy(fe[:], zero[:])
+}
+
+func FeOne(fe *FieldElement) {
+ FeZero(fe)
+ fe[0] = 1
+}
+
+func FeAdd(dst, a, b *FieldElement) {
+ dst[0] = a[0] + b[0]
+ dst[1] = a[1] + b[1]
+ dst[2] = a[2] + b[2]
+ dst[3] = a[3] + b[3]
+ dst[4] = a[4] + b[4]
+ dst[5] = a[5] + b[5]
+ dst[6] = a[6] + b[6]
+ dst[7] = a[7] + b[7]
+ dst[8] = a[8] + b[8]
+ dst[9] = a[9] + b[9]
+}
+
+func FeSub(dst, a, b *FieldElement) {
+ dst[0] = a[0] - b[0]
+ dst[1] = a[1] - b[1]
+ dst[2] = a[2] - b[2]
+ dst[3] = a[3] - b[3]
+ dst[4] = a[4] - b[4]
+ dst[5] = a[5] - b[5]
+ dst[6] = a[6] - b[6]
+ dst[7] = a[7] - b[7]
+ dst[8] = a[8] - b[8]
+ dst[9] = a[9] - b[9]
+}
+
+func FeCopy(dst, src *FieldElement) {
+ copy(dst[:], src[:])
+}
+
+// Replace (f,g) with (g,g) if b == 1;
+// replace (f,g) with (f,g) if b == 0.
+//
+// Preconditions: b in {0,1}.
+func FeCMove(f, g *FieldElement, b int32) {
+ b = -b
+ f[0] ^= b & (f[0] ^ g[0])
+ f[1] ^= b & (f[1] ^ g[1])
+ f[2] ^= b & (f[2] ^ g[2])
+ f[3] ^= b & (f[3] ^ g[3])
+ f[4] ^= b & (f[4] ^ g[4])
+ f[5] ^= b & (f[5] ^ g[5])
+ f[6] ^= b & (f[6] ^ g[6])
+ f[7] ^= b & (f[7] ^ g[7])
+ f[8] ^= b & (f[8] ^ g[8])
+ f[9] ^= b & (f[9] ^ g[9])
+}
+
+func load3(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ return r
+}
+
+func load4(in []byte) int64 {
+ var r int64
+ r = int64(in[0])
+ r |= int64(in[1]) << 8
+ r |= int64(in[2]) << 16
+ r |= int64(in[3]) << 24
+ return r
+}
+
+func FeFromBytes(dst *FieldElement, src *[32]byte) {
+ h0 := load4(src[:])
+ h1 := load3(src[4:]) << 6
+ h2 := load3(src[7:]) << 5
+ h3 := load3(src[10:]) << 3
+ h4 := load3(src[13:]) << 2
+ h5 := load4(src[16:])
+ h6 := load3(src[20:]) << 7
+ h7 := load3(src[23:]) << 5
+ h8 := load3(src[26:]) << 4
+ h9 := (load3(src[29:]) & 8388607) << 2
+
+ FeCombine(dst, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9)
+}
+
+// FeToBytes marshals h to s.
+// Preconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Write p=2^255-19; q=floor(h/p).
+// Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))).
+//
+// Proof:
+// Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4.
+// Also have |h-2^230 h9|<2^230 so |19 2^(-255)(h-2^230 h9)|<1/4.
+//
+// Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9).
+// Then 0<y<1.
+//
+// Write r=h-pq.
+// Have 0<=r<=p-1=2^255-20.
+// Thus 0<=r+19(2^-255)r<r+19(2^-255)2^255<=2^255-1.
+//
+// Write x=r+19(2^-255)r+y.
+// Then 0<x<2^255 so floor(2^(-255)x) = 0 so floor(q+2^(-255)x) = q.
+//
+// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
+// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
+func FeToBytes(s *[32]byte, h *FieldElement) {
+ var carry [10]int32
+
+ q := (19*h[9] + (1 << 24)) >> 25
+ q = (h[0] + q) >> 26
+ q = (h[1] + q) >> 25
+ q = (h[2] + q) >> 26
+ q = (h[3] + q) >> 25
+ q = (h[4] + q) >> 26
+ q = (h[5] + q) >> 25
+ q = (h[6] + q) >> 26
+ q = (h[7] + q) >> 25
+ q = (h[8] + q) >> 26
+ q = (h[9] + q) >> 25
+
+ // Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20.
+ h[0] += 19 * q
+ // Goal: Output h-2^255 q, which is between 0 and 2^255-20.
+
+ carry[0] = h[0] >> 26
+ h[1] += carry[0]
+ h[0] -= carry[0] << 26
+ carry[1] = h[1] >> 25
+ h[2] += carry[1]
+ h[1] -= carry[1] << 25
+ carry[2] = h[2] >> 26
+ h[3] += carry[2]
+ h[2] -= carry[2] << 26
+ carry[3] = h[3] >> 25
+ h[4] += carry[3]
+ h[3] -= carry[3] << 25
+ carry[4] = h[4] >> 26
+ h[5] += carry[4]
+ h[4] -= carry[4] << 26
+ carry[5] = h[5] >> 25
+ h[6] += carry[5]
+ h[5] -= carry[5] << 25
+ carry[6] = h[6] >> 26
+ h[7] += carry[6]
+ h[6] -= carry[6] << 26
+ carry[7] = h[7] >> 25
+ h[8] += carry[7]
+ h[7] -= carry[7] << 25
+ carry[8] = h[8] >> 26
+ h[9] += carry[8]
+ h[8] -= carry[8] << 26
+ carry[9] = h[9] >> 25
+ h[9] -= carry[9] << 25
+ // h10 = carry9
+
+ // Goal: Output h[0]+...+2^255 h10-2^255 q, which is between 0 and 2^255-20.
+ // Have h[0]+...+2^230 h[9] between 0 and 2^255-1;
+ // evidently 2^255 h10-2^255 q = 0.
+ // Goal: Output h[0]+...+2^230 h[9].
+
+ s[0] = byte(h[0] >> 0)
+ s[1] = byte(h[0] >> 8)
+ s[2] = byte(h[0] >> 16)
+ s[3] = byte((h[0] >> 24) | (h[1] << 2))
+ s[4] = byte(h[1] >> 6)
+ s[5] = byte(h[1] >> 14)
+ s[6] = byte((h[1] >> 22) | (h[2] << 3))
+ s[7] = byte(h[2] >> 5)
+ s[8] = byte(h[2] >> 13)
+ s[9] = byte((h[2] >> 21) | (h[3] << 5))
+ s[10] = byte(h[3] >> 3)
+ s[11] = byte(h[3] >> 11)
+ s[12] = byte((h[3] >> 19) | (h[4] << 6))
+ s[13] = byte(h[4] >> 2)
+ s[14] = byte(h[4] >> 10)
+ s[15] = byte(h[4] >> 18)
+ s[16] = byte(h[5] >> 0)
+ s[17] = byte(h[5] >> 8)
+ s[18] = byte(h[5] >> 16)
+ s[19] = byte((h[5] >> 24) | (h[6] << 1))
+ s[20] = byte(h[6] >> 7)
+ s[21] = byte(h[6] >> 15)
+ s[22] = byte((h[6] >> 23) | (h[7] << 3))
+ s[23] = byte(h[7] >> 5)
+ s[24] = byte(h[7] >> 13)
+ s[25] = byte((h[7] >> 21) | (h[8] << 4))
+ s[26] = byte(h[8] >> 4)
+ s[27] = byte(h[8] >> 12)
+ s[28] = byte((h[8] >> 20) | (h[9] << 6))
+ s[29] = byte(h[9] >> 2)
+ s[30] = byte(h[9] >> 10)
+ s[31] = byte(h[9] >> 18)
+}
+
+func FeIsNegative(f *FieldElement) byte {
+ var s [32]byte
+ FeToBytes(&s, f)
+ return s[0] & 1
+}
+
+func FeIsNonZero(f *FieldElement) int32 {
+ var s [32]byte
+ FeToBytes(&s, f)
+ var x uint8
+ for _, b := range s {
+ x |= b
+ }
+ x |= x >> 4
+ x |= x >> 2
+ x |= x >> 1
+ return int32(x & 1)
+}
+
+// FeNeg sets h = -f
+//
+// Preconditions:
+// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func FeNeg(h, f *FieldElement) {
+ h[0] = -f[0]
+ h[1] = -f[1]
+ h[2] = -f[2]
+ h[3] = -f[3]
+ h[4] = -f[4]
+ h[5] = -f[5]
+ h[6] = -f[6]
+ h[7] = -f[7]
+ h[8] = -f[8]
+ h[9] = -f[9]
+}
+
+func FeCombine(h *FieldElement, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) {
+ var c0, c1, c2, c3, c4, c5, c6, c7, c8, c9 int64
+
+ /*
+ |h0| <= (1.1*1.1*2^52*(1+19+19+19+19)+1.1*1.1*2^50*(38+38+38+38+38))
+ i.e. |h0| <= 1.2*2^59; narrower ranges for h2, h4, h6, h8
+ |h1| <= (1.1*1.1*2^51*(1+1+19+19+19+19+19+19+19+19))
+ i.e. |h1| <= 1.5*2^58; narrower ranges for h3, h5, h7, h9
+ */
+
+ c0 = (h0 + (1 << 25)) >> 26
+ h1 += c0
+ h0 -= c0 << 26
+ c4 = (h4 + (1 << 25)) >> 26
+ h5 += c4
+ h4 -= c4 << 26
+ /* |h0| <= 2^25 */
+ /* |h4| <= 2^25 */
+ /* |h1| <= 1.51*2^58 */
+ /* |h5| <= 1.51*2^58 */
+
+ c1 = (h1 + (1 << 24)) >> 25
+ h2 += c1
+ h1 -= c1 << 25
+ c5 = (h5 + (1 << 24)) >> 25
+ h6 += c5
+ h5 -= c5 << 25
+ /* |h1| <= 2^24; from now on fits into int32 */
+ /* |h5| <= 2^24; from now on fits into int32 */
+ /* |h2| <= 1.21*2^59 */
+ /* |h6| <= 1.21*2^59 */
+
+ c2 = (h2 + (1 << 25)) >> 26
+ h3 += c2
+ h2 -= c2 << 26
+ c6 = (h6 + (1 << 25)) >> 26
+ h7 += c6
+ h6 -= c6 << 26
+ /* |h2| <= 2^25; from now on fits into int32 unchanged */
+ /* |h6| <= 2^25; from now on fits into int32 unchanged */
+ /* |h3| <= 1.51*2^58 */
+ /* |h7| <= 1.51*2^58 */
+
+ c3 = (h3 + (1 << 24)) >> 25
+ h4 += c3
+ h3 -= c3 << 25
+ c7 = (h7 + (1 << 24)) >> 25
+ h8 += c7
+ h7 -= c7 << 25
+ /* |h3| <= 2^24; from now on fits into int32 unchanged */
+ /* |h7| <= 2^24; from now on fits into int32 unchanged */
+ /* |h4| <= 1.52*2^33 */
+ /* |h8| <= 1.52*2^33 */
+
+ c4 = (h4 + (1 << 25)) >> 26
+ h5 += c4
+ h4 -= c4 << 26
+ c8 = (h8 + (1 << 25)) >> 26
+ h9 += c8
+ h8 -= c8 << 26
+ /* |h4| <= 2^25; from now on fits into int32 unchanged */
+ /* |h8| <= 2^25; from now on fits into int32 unchanged */
+ /* |h5| <= 1.01*2^24 */
+ /* |h9| <= 1.51*2^58 */
+
+ c9 = (h9 + (1 << 24)) >> 25
+ h0 += c9 * 19
+ h9 -= c9 << 25
+ /* |h9| <= 2^24; from now on fits into int32 unchanged */
+ /* |h0| <= 1.8*2^37 */
+
+ c0 = (h0 + (1 << 25)) >> 26
+ h1 += c0
+ h0 -= c0 << 26
+ /* |h0| <= 2^25; from now on fits into int32 unchanged */
+ /* |h1| <= 1.01*2^24 */
+
+ h[0] = int32(h0)
+ h[1] = int32(h1)
+ h[2] = int32(h2)
+ h[3] = int32(h3)
+ h[4] = int32(h4)
+ h[5] = int32(h5)
+ h[6] = int32(h6)
+ h[7] = int32(h7)
+ h[8] = int32(h8)
+ h[9] = int32(h9)
+}
+
+// FeMul calculates h = f * g
+// Can overlap h with f or g.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+// |g| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+//
+// Notes on implementation strategy:
+//
+// Using schoolbook multiplication.
+// Karatsuba would save a little in some cost models.
+//
+// Most multiplications by 2 and 19 are 32-bit precomputations;
+// cheaper than 64-bit postcomputations.
+//
+// There is one remaining multiplication by 19 in the carry chain;
+// one *19 precomputation can be merged into this,
+// but the resulting data flow is considerably less clean.
+//
+// There are 12 carries below.
+// 10 of them are 2-way parallelizable and vectorizable.
+// Can get away with 11 carries, but then data flow is much deeper.
+//
+// With tighter constraints on inputs, can squeeze carries into int32.
+func FeMul(h, f, g *FieldElement) {
+ f0 := int64(f[0])
+ f1 := int64(f[1])
+ f2 := int64(f[2])
+ f3 := int64(f[3])
+ f4 := int64(f[4])
+ f5 := int64(f[5])
+ f6 := int64(f[6])
+ f7 := int64(f[7])
+ f8 := int64(f[8])
+ f9 := int64(f[9])
+
+ f1_2 := int64(2 * f[1])
+ f3_2 := int64(2 * f[3])
+ f5_2 := int64(2 * f[5])
+ f7_2 := int64(2 * f[7])
+ f9_2 := int64(2 * f[9])
+
+ g0 := int64(g[0])
+ g1 := int64(g[1])
+ g2 := int64(g[2])
+ g3 := int64(g[3])
+ g4 := int64(g[4])
+ g5 := int64(g[5])
+ g6 := int64(g[6])
+ g7 := int64(g[7])
+ g8 := int64(g[8])
+ g9 := int64(g[9])
+
+ g1_19 := int64(19 * g[1]) /* 1.4*2^29 */
+ g2_19 := int64(19 * g[2]) /* 1.4*2^30; still ok */
+ g3_19 := int64(19 * g[3])
+ g4_19 := int64(19 * g[4])
+ g5_19 := int64(19 * g[5])
+ g6_19 := int64(19 * g[6])
+ g7_19 := int64(19 * g[7])
+ g8_19 := int64(19 * g[8])
+ g9_19 := int64(19 * g[9])
+
+ h0 := f0*g0 + f1_2*g9_19 + f2*g8_19 + f3_2*g7_19 + f4*g6_19 + f5_2*g5_19 + f6*g4_19 + f7_2*g3_19 + f8*g2_19 + f9_2*g1_19
+ h1 := f0*g1 + f1*g0 + f2*g9_19 + f3*g8_19 + f4*g7_19 + f5*g6_19 + f6*g5_19 + f7*g4_19 + f8*g3_19 + f9*g2_19
+ h2 := f0*g2 + f1_2*g1 + f2*g0 + f3_2*g9_19 + f4*g8_19 + f5_2*g7_19 + f6*g6_19 + f7_2*g5_19 + f8*g4_19 + f9_2*g3_19
+ h3 := f0*g3 + f1*g2 + f2*g1 + f3*g0 + f4*g9_19 + f5*g8_19 + f6*g7_19 + f7*g6_19 + f8*g5_19 + f9*g4_19
+ h4 := f0*g4 + f1_2*g3 + f2*g2 + f3_2*g1 + f4*g0 + f5_2*g9_19 + f6*g8_19 + f7_2*g7_19 + f8*g6_19 + f9_2*g5_19
+ h5 := f0*g5 + f1*g4 + f2*g3 + f3*g2 + f4*g1 + f5*g0 + f6*g9_19 + f7*g8_19 + f8*g7_19 + f9*g6_19
+ h6 := f0*g6 + f1_2*g5 + f2*g4 + f3_2*g3 + f4*g2 + f5_2*g1 + f6*g0 + f7_2*g9_19 + f8*g8_19 + f9_2*g7_19
+ h7 := f0*g7 + f1*g6 + f2*g5 + f3*g4 + f4*g3 + f5*g2 + f6*g1 + f7*g0 + f8*g9_19 + f9*g8_19
+ h8 := f0*g8 + f1_2*g7 + f2*g6 + f3_2*g5 + f4*g4 + f5_2*g3 + f6*g2 + f7_2*g1 + f8*g0 + f9_2*g9_19
+ h9 := f0*g9 + f1*g8 + f2*g7 + f3*g6 + f4*g5 + f5*g4 + f6*g3 + f7*g2 + f8*g1 + f9*g0
+
+ FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9)
+}
+
+func feSquare(f *FieldElement) (h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 int64) {
+ f0 := int64(f[0])
+ f1 := int64(f[1])
+ f2 := int64(f[2])
+ f3 := int64(f[3])
+ f4 := int64(f[4])
+ f5 := int64(f[5])
+ f6 := int64(f[6])
+ f7 := int64(f[7])
+ f8 := int64(f[8])
+ f9 := int64(f[9])
+ f0_2 := int64(2 * f[0])
+ f1_2 := int64(2 * f[1])
+ f2_2 := int64(2 * f[2])
+ f3_2 := int64(2 * f[3])
+ f4_2 := int64(2 * f[4])
+ f5_2 := int64(2 * f[5])
+ f6_2 := int64(2 * f[6])
+ f7_2 := int64(2 * f[7])
+ f5_38 := 38 * f5 // 1.31*2^30
+ f6_19 := 19 * f6 // 1.31*2^30
+ f7_38 := 38 * f7 // 1.31*2^30
+ f8_19 := 19 * f8 // 1.31*2^30
+ f9_38 := 38 * f9 // 1.31*2^30
+
+ h0 = f0*f0 + f1_2*f9_38 + f2_2*f8_19 + f3_2*f7_38 + f4_2*f6_19 + f5*f5_38
+ h1 = f0_2*f1 + f2*f9_38 + f3_2*f8_19 + f4*f7_38 + f5_2*f6_19
+ h2 = f0_2*f2 + f1_2*f1 + f3_2*f9_38 + f4_2*f8_19 + f5_2*f7_38 + f6*f6_19
+ h3 = f0_2*f3 + f1_2*f2 + f4*f9_38 + f5_2*f8_19 + f6*f7_38
+ h4 = f0_2*f4 + f1_2*f3_2 + f2*f2 + f5_2*f9_38 + f6_2*f8_19 + f7*f7_38
+ h5 = f0_2*f5 + f1_2*f4 + f2_2*f3 + f6*f9_38 + f7_2*f8_19
+ h6 = f0_2*f6 + f1_2*f5_2 + f2_2*f4 + f3_2*f3 + f7_2*f9_38 + f8*f8_19
+ h7 = f0_2*f7 + f1_2*f6 + f2_2*f5 + f3_2*f4 + f8*f9_38
+ h8 = f0_2*f8 + f1_2*f7_2 + f2_2*f6 + f3_2*f5_2 + f4*f4 + f9*f9_38
+ h9 = f0_2*f9 + f1_2*f8 + f2_2*f7 + f3_2*f6 + f4_2*f5
+
+ return
+}
+
+// FeSquare calculates h = f*f. Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
+func FeSquare(h, f *FieldElement) {
+ h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f)
+ FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9)
+}
+
+// FeSquare2 sets h = 2 * f * f
+//
+// Can overlap h with f.
+//
+// Preconditions:
+// |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc.
+//
+// Postconditions:
+// |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc.
+// See fe_mul.c for discussion of implementation strategy.
+func FeSquare2(h, f *FieldElement) {
+ h0, h1, h2, h3, h4, h5, h6, h7, h8, h9 := feSquare(f)
+
+ h0 += h0
+ h1 += h1
+ h2 += h2
+ h3 += h3
+ h4 += h4
+ h5 += h5
+ h6 += h6
+ h7 += h7
+ h8 += h8
+ h9 += h9
+
+ FeCombine(h, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9)
+}
+
+func FeInvert(out, z *FieldElement) {
+ var t0, t1, t2, t3 FieldElement
+ var i int
+
+ FeSquare(&t0, z) // 2^1
+ FeSquare(&t1, &t0) // 2^2
+ for i = 1; i < 2; i++ { // 2^3
+ FeSquare(&t1, &t1)
+ }
+ FeMul(&t1, z, &t1) // 2^3 + 2^0
+ FeMul(&t0, &t0, &t1) // 2^3 + 2^1 + 2^0
+ FeSquare(&t2, &t0) // 2^4 + 2^2 + 2^1
+ FeMul(&t1, &t1, &t2) // 2^4 + 2^3 + 2^2 + 2^1 + 2^0
+ FeSquare(&t2, &t1) // 5,4,3,2,1
+ for i = 1; i < 5; i++ { // 9,8,7,6,5
+ FeSquare(&t2, &t2)
+ }
+ FeMul(&t1, &t2, &t1) // 9,8,7,6,5,4,3,2,1,0
+ FeSquare(&t2, &t1) // 10..1
+ for i = 1; i < 10; i++ { // 19..10
+ FeSquare(&t2, &t2)
+ }
+ FeMul(&t2, &t2, &t1) // 19..0
+ FeSquare(&t3, &t2) // 20..1
+ for i = 1; i < 20; i++ { // 39..20
+ FeSquare(&t3, &t3)
+ }
+ FeMul(&t2, &t3, &t2) // 39..0
+ FeSquare(&t2, &t2) // 40..1
+ for i = 1; i < 10; i++ { // 49..10
+ FeSquare(&t2, &t2)
+ }
+ FeMul(&t1, &t2, &t1) // 49..0
+ FeSquare(&t2, &t1) // 50..1
+ for i = 1; i < 50; i++ { // 99..50
+ FeSquare(&t2, &t2)
+ }
+ FeMul(&t2, &t2, &t1) // 99..0
+ FeSquare(&t3, &t2) // 100..1
+ for i = 1; i < 100; i++ { // 199..100
+ FeSquare(&t3, &t3)
+ }
+ FeMul(&t2, &t3, &t2) // 199..0
+ FeSquare(&t2, &t2) // 200..1
+ for i = 1; i < 50; i++ { // 249..50
+ FeSquare(&t2, &t2)
+ }
+ FeMul(&t1, &t2, &t1) // 249..0
+ FeSquare(&t1, &t1) // 250..1
+ for i = 1; i < 5; i++ { // 254..5
+ FeSquare(&t1, &t1)
+ }
+ FeMul(out, &t1, &t0) // 254..5,3,1,0
+}
+
+func fePow22523(out, z *FieldElement) {
+ var t0, t1, t2 FieldElement
+ var i int
+
+ FeSquare(&t0, z)
+ for i = 1; i < 1; i++ {
+ FeSquare(&t0, &t0)
+ }
+ FeSquare(&t1, &t0)
+ for i = 1; i < 2; i++ {
+ FeSquare(&t1, &t1)
+ }
+ FeMul(&t1, z, &t1)
+ FeMul(&t0, &t0, &t1)
+ FeSquare(&t0, &t0)
+ for i = 1; i < 1; i++ {
+ FeSquare(&t0, &t0)
+ }
+ FeMul(&t0, &t1, &t0)
+ FeSquare(&t1, &t0)
+ for i = 1; i < 5; i++ {
+ FeSquare(&t1, &t1)
+ }
+ FeMul(&t0, &t1, &t0)
+ FeSquare(&t1, &t0)
+ for i = 1; i < 10; i++ {
+ FeSquare(&t1, &t1)
+ }
+ FeMul(&t1, &t1, &t0)
+ FeSquare(&t2, &t1)
+ for i = 1; i < 20; i++ {
+ FeSquare(&t2, &t2)
+ }
+ FeMul(&t1, &t2, &t1)
+ FeSquare(&t1, &t1)
+ for i = 1; i < 10; i++ {
+ FeSquare(&t1, &t1)
+ }
+ FeMul(&t0, &t1, &t0)
+ FeSquare(&t1, &t0)
+ for i = 1; i < 50; i++ {
+ FeSquare(&t1, &t1)
+ }
+ FeMul(&t1, &t1, &t0)
+ FeSquare(&t2, &t1)
+ for i = 1; i < 100; i++ {
+ FeSquare(&t2, &t2)
+ }
+ FeMul(&t1, &t2, &t1)
+ FeSquare(&t1, &t1)
+ for i = 1; i < 50; i++ {
+ FeSquare(&t1, &t1)
+ }
+ FeMul(&t0, &t1, &t0)
+ FeSquare(&t0, &t0)
+ for i = 1; i < 2; i++ {
+ FeSquare(&t0, &t0)
+ }
+ FeMul(out, &t0, z)
+}
+
+// Group elements are members of the elliptic curve -x^2 + y^2 = 1 + d * x^2 *
+// y^2 where d = -121665/121666.
+//
+// Several representations are used:
+// ProjectiveGroupElement: (X:Y:Z) satisfying x=X/Z, y=Y/Z
+// ExtendedGroupElement: (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+// CompletedGroupElement: ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+// PreComputedGroupElement: (y+x,y-x,2dxy)
+
+type ProjectiveGroupElement struct {
+ X, Y, Z FieldElement
+}
+
+type ExtendedGroupElement struct {
+ X, Y, Z, T FieldElement
+}
+
+type CompletedGroupElement struct {
+ X, Y, Z, T FieldElement
+}
+
+type PreComputedGroupElement struct {
+ yPlusX, yMinusX, xy2d FieldElement
+}
+
+type CachedGroupElement struct {
+ yPlusX, yMinusX, Z, T2d FieldElement
+}
+
+func (p *ProjectiveGroupElement) Zero() {
+ FeZero(&p.X)
+ FeOne(&p.Y)
+ FeOne(&p.Z)
+}
+
+func (p *ProjectiveGroupElement) Double(r *CompletedGroupElement) {
+ var t0 FieldElement
+
+ FeSquare(&r.X, &p.X)
+ FeSquare(&r.Z, &p.Y)
+ FeSquare2(&r.T, &p.Z)
+ FeAdd(&r.Y, &p.X, &p.Y)
+ FeSquare(&t0, &r.Y)
+ FeAdd(&r.Y, &r.Z, &r.X)
+ FeSub(&r.Z, &r.Z, &r.X)
+ FeSub(&r.X, &t0, &r.Y)
+ FeSub(&r.T, &r.T, &r.Z)
+}
+
+func (p *ProjectiveGroupElement) ToBytes(s *[32]byte) {
+ var recip, x, y FieldElement
+
+ FeInvert(&recip, &p.Z)
+ FeMul(&x, &p.X, &recip)
+ FeMul(&y, &p.Y, &recip)
+ FeToBytes(s, &y)
+ s[31] ^= FeIsNegative(&x) << 7
+}
+
+func (p *ExtendedGroupElement) Zero() {
+ FeZero(&p.X)
+ FeOne(&p.Y)
+ FeOne(&p.Z)
+ FeZero(&p.T)
+}
+
+func (p *ExtendedGroupElement) Double(r *CompletedGroupElement) {
+ var q ProjectiveGroupElement
+ p.ToProjective(&q)
+ q.Double(r)
+}
+
+func (p *ExtendedGroupElement) ToCached(r *CachedGroupElement) {
+ FeAdd(&r.yPlusX, &p.Y, &p.X)
+ FeSub(&r.yMinusX, &p.Y, &p.X)
+ FeCopy(&r.Z, &p.Z)
+ FeMul(&r.T2d, &p.T, &d2)
+}
+
+func (p *ExtendedGroupElement) ToProjective(r *ProjectiveGroupElement) {
+ FeCopy(&r.X, &p.X)
+ FeCopy(&r.Y, &p.Y)
+ FeCopy(&r.Z, &p.Z)
+}
+
+func (p *ExtendedGroupElement) ToBytes(s *[32]byte) {
+ var recip, x, y FieldElement
+
+ FeInvert(&recip, &p.Z)
+ FeMul(&x, &p.X, &recip)
+ FeMul(&y, &p.Y, &recip)
+ FeToBytes(s, &y)
+ s[31] ^= FeIsNegative(&x) << 7
+}
+
+func (p *ExtendedGroupElement) FromBytes(s *[32]byte) bool {
+ var u, v, v3, vxx, check FieldElement
+
+ FeFromBytes(&p.Y, s)
+ FeOne(&p.Z)
+ FeSquare(&u, &p.Y)
+ FeMul(&v, &u, &d)
+ FeSub(&u, &u, &p.Z) // y = y^2-1
+ FeAdd(&v, &v, &p.Z) // v = dy^2+1
+
+ FeSquare(&v3, &v)
+ FeMul(&v3, &v3, &v) // v3 = v^3
+ FeSquare(&p.X, &v3)
+ FeMul(&p.X, &p.X, &v)
+ FeMul(&p.X, &p.X, &u) // x = uv^7
+
+ fePow22523(&p.X, &p.X) // x = (uv^7)^((q-5)/8)
+ FeMul(&p.X, &p.X, &v3)
+ FeMul(&p.X, &p.X, &u) // x = uv^3(uv^7)^((q-5)/8)
+
+ var tmpX, tmp2 [32]byte
+
+ FeSquare(&vxx, &p.X)
+ FeMul(&vxx, &vxx, &v)
+ FeSub(&check, &vxx, &u) // vx^2-u
+ if FeIsNonZero(&check) == 1 {
+ FeAdd(&check, &vxx, &u) // vx^2+u
+ if FeIsNonZero(&check) == 1 {
+ return false
+ }
+ FeMul(&p.X, &p.X, &SqrtM1)
+
+ FeToBytes(&tmpX, &p.X)
+ for i, v := range tmpX {
+ tmp2[31-i] = v
+ }
+ }
+
+ if FeIsNegative(&p.X) != (s[31] >> 7) {
+ FeNeg(&p.X, &p.X)
+ }
+
+ FeMul(&p.T, &p.X, &p.Y)
+ return true
+}
+
+func (p *CompletedGroupElement) ToProjective(r *ProjectiveGroupElement) {
+ FeMul(&r.X, &p.X, &p.T)
+ FeMul(&r.Y, &p.Y, &p.Z)
+ FeMul(&r.Z, &p.Z, &p.T)
+}
+
+func (p *CompletedGroupElement) ToExtended(r *ExtendedGroupElement) {
+ FeMul(&r.X, &p.X, &p.T)
+ FeMul(&r.Y, &p.Y, &p.Z)
+ FeMul(&r.Z, &p.Z, &p.T)
+ FeMul(&r.T, &p.X, &p.Y)
+}
+
+func (p *PreComputedGroupElement) Zero() {
+ FeOne(&p.yPlusX)
+ FeOne(&p.yMinusX)
+ FeZero(&p.xy2d)
+}
+
+func geAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) {
+ var t0 FieldElement
+
+ FeAdd(&r.X, &p.Y, &p.X)
+ FeSub(&r.Y, &p.Y, &p.X)
+ FeMul(&r.Z, &r.X, &q.yPlusX)
+ FeMul(&r.Y, &r.Y, &q.yMinusX)
+ FeMul(&r.T, &q.T2d, &p.T)
+ FeMul(&r.X, &p.Z, &q.Z)
+ FeAdd(&t0, &r.X, &r.X)
+ FeSub(&r.X, &r.Z, &r.Y)
+ FeAdd(&r.Y, &r.Z, &r.Y)
+ FeAdd(&r.Z, &t0, &r.T)
+ FeSub(&r.T, &t0, &r.T)
+}
+
+func geSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) {
+ var t0 FieldElement
+
+ FeAdd(&r.X, &p.Y, &p.X)
+ FeSub(&r.Y, &p.Y, &p.X)
+ FeMul(&r.Z, &r.X, &q.yMinusX)
+ FeMul(&r.Y, &r.Y, &q.yPlusX)
+ FeMul(&r.T, &q.T2d, &p.T)
+ FeMul(&r.X, &p.Z, &q.Z)
+ FeAdd(&t0, &r.X, &r.X)
+ FeSub(&r.X, &r.Z, &r.Y)
+ FeAdd(&r.Y, &r.Z, &r.Y)
+ FeSub(&r.Z, &t0, &r.T)
+ FeAdd(&r.T, &t0, &r.T)
+}
+
+func geMixedAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) {
+ var t0 FieldElement
+
+ FeAdd(&r.X, &p.Y, &p.X)
+ FeSub(&r.Y, &p.Y, &p.X)
+ FeMul(&r.Z, &r.X, &q.yPlusX)
+ FeMul(&r.Y, &r.Y, &q.yMinusX)
+ FeMul(&r.T, &q.xy2d, &p.T)
+ FeAdd(&t0, &p.Z, &p.Z)
+ FeSub(&r.X, &r.Z, &r.Y)
+ FeAdd(&r.Y, &r.Z, &r.Y)
+ FeAdd(&r.Z, &t0, &r.T)
+ FeSub(&r.T, &t0, &r.T)
+}
+
+func geMixedSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) {
+ var t0 FieldElement
+
+ FeAdd(&r.X, &p.Y, &p.X)
+ FeSub(&r.Y, &p.Y, &p.X)
+ FeMul(&r.Z, &r.X, &q.yMinusX)
+ FeMul(&r.Y, &r.Y, &q.yPlusX)
+ FeMul(&r.T, &q.xy2d, &p.T)
+ FeAdd(&t0, &p.Z, &p.Z)
+ FeSub(&r.X, &r.Z, &r.Y)
+ FeAdd(&r.Y, &r.Z, &r.Y)
+ FeSub(&r.Z, &t0, &r.T)
+ FeAdd(&r.T, &t0, &r.T)
+}
+
+func slide(r *[256]int8, a *[32]byte) {
+ for i := range r {
+ r[i] = int8(1 & (a[i>>3] >> uint(i&7)))
+ }
+
+ for i := range r {
+ if r[i] != 0 {
+ for b := 1; b <= 6 && i+b < 256; b++ {
+ if r[i+b] != 0 {
+ if r[i]+(r[i+b]<<uint(b)) <= 15 {
+ r[i] += r[i+b] << uint(b)
+ r[i+b] = 0
+ } else if r[i]-(r[i+b]<<uint(b)) >= -15 {
+ r[i] -= r[i+b] << uint(b)
+ for k := i + b; k < 256; k++ {
+ if r[k] == 0 {
+ r[k] = 1
+ break
+ }
+ r[k] = 0
+ }
+ } else {
+ break
+ }
+ }
+ }
+ }
+ }
+}
+
+// GeDoubleScalarMultVartime sets r = a*A + b*B
+// where a = a[0]+256*a[1]+...+256^31 a[31].
+// and b = b[0]+256*b[1]+...+256^31 b[31].
+// B is the Ed25519 base point (x,4/5) with x positive.
+func GeDoubleScalarMultVartime(r *ProjectiveGroupElement, a *[32]byte, A *ExtendedGroupElement, b *[32]byte) {
+ var aSlide, bSlide [256]int8
+ var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A
+ var t CompletedGroupElement
+ var u, A2 ExtendedGroupElement
+ var i int
+
+ slide(&aSlide, a)
+ slide(&bSlide, b)
+
+ A.ToCached(&Ai[0])
+ A.Double(&t)
+ t.ToExtended(&A2)
+
+ for i := 0; i < 7; i++ {
+ geAdd(&t, &A2, &Ai[i])
+ t.ToExtended(&u)
+ u.ToCached(&Ai[i+1])
+ }
+
+ r.Zero()
+
+ for i = 255; i >= 0; i-- {
+ if aSlide[i] != 0 || bSlide[i] != 0 {
+ break
+ }
+ }
+
+ for ; i >= 0; i-- {
+ r.Double(&t)
+
+ if aSlide[i] > 0 {
+ t.ToExtended(&u)
+ geAdd(&t, &u, &Ai[aSlide[i]/2])
+ } else if aSlide[i] < 0 {
+ t.ToExtended(&u)
+ geSub(&t, &u, &Ai[(-aSlide[i])/2])
+ }
+
+ if bSlide[i] > 0 {
+ t.ToExtended(&u)
+ geMixedAdd(&t, &u, &bi[bSlide[i]/2])
+ } else if bSlide[i] < 0 {
+ t.ToExtended(&u)
+ geMixedSub(&t, &u, &bi[(-bSlide[i])/2])
+ }
+
+ t.ToProjective(r)
+ }
+}
+
+// equal returns 1 if b == c and 0 otherwise, assuming that b and c are
+// non-negative.
+func equal(b, c int32) int32 {
+ x := uint32(b ^ c)
+ x--
+ return int32(x >> 31)
+}
+
+// negative returns 1 if b < 0 and 0 otherwise.
+func negative(b int32) int32 {
+ return (b >> 31) & 1
+}
+
+func PreComputedGroupElementCMove(t, u *PreComputedGroupElement, b int32) {
+ FeCMove(&t.yPlusX, &u.yPlusX, b)
+ FeCMove(&t.yMinusX, &u.yMinusX, b)
+ FeCMove(&t.xy2d, &u.xy2d, b)
+}
+
+func selectPoint(t *PreComputedGroupElement, pos int32, b int32) {
+ var minusT PreComputedGroupElement
+ bNegative := negative(b)
+ bAbs := b - (((-bNegative) & b) << 1)
+
+ t.Zero()
+ for i := int32(0); i < 8; i++ {
+ PreComputedGroupElementCMove(t, &base[pos][i], equal(bAbs, i+1))
+ }
+ FeCopy(&minusT.yPlusX, &t.yMinusX)
+ FeCopy(&minusT.yMinusX, &t.yPlusX)
+ FeNeg(&minusT.xy2d, &t.xy2d)
+ PreComputedGroupElementCMove(t, &minusT, bNegative)
+}
+
+// GeScalarMultBase computes h = a*B, where
+// a = a[0]+256*a[1]+...+256^31 a[31]
+// B is the Ed25519 base point (x,4/5) with x positive.
+//
+// Preconditions:
+// a[31] <= 127
+func GeScalarMultBase(h *ExtendedGroupElement, a *[32]byte) {
+ var e [64]int8
+
+ for i, v := range a {
+ e[2*i] = int8(v & 15)
+ e[2*i+1] = int8((v >> 4) & 15)
+ }
+
+ // each e[i] is between 0 and 15 and e[63] is between 0 and 7.
+
+ carry := int8(0)
+ for i := 0; i < 63; i++ {
+ e[i] += carry
+ carry = (e[i] + 8) >> 4
+ e[i] -= carry << 4
+ }
+ e[63] += carry
+ // each e[i] is between -8 and 8.
+
+ h.Zero()
+ var t PreComputedGroupElement
+ var r CompletedGroupElement
+ for i := int32(1); i < 64; i += 2 {
+ selectPoint(&t, i/2, int32(e[i]))
+ geMixedAdd(&r, h, &t)
+ r.ToExtended(h)
+ }
+
+ var s ProjectiveGroupElement
+
+ h.Double(&r)
+ r.ToProjective(&s)
+ s.Double(&r)
+ r.ToProjective(&s)
+ s.Double(&r)
+ r.ToProjective(&s)
+ s.Double(&r)
+ r.ToExtended(h)
+
+ for i := int32(0); i < 64; i += 2 {
+ selectPoint(&t, i/2, int32(e[i]))
+ geMixedAdd(&r, h, &t)
+ r.ToExtended(h)
+ }
+}
+
+// The scalars are GF(2^252 + 27742317777372353535851937790883648493).
+
+// Input:
+// a[0]+256*a[1]+...+256^31*a[31] = a
+// b[0]+256*b[1]+...+256^31*b[31] = b
+// c[0]+256*c[1]+...+256^31*c[31] = c
+//
+// Output:
+// s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
+// where l = 2^252 + 27742317777372353535851937790883648493.
+func ScMulAdd(s, a, b, c *[32]byte) {
+ a0 := 2097151 & load3(a[:])
+ a1 := 2097151 & (load4(a[2:]) >> 5)
+ a2 := 2097151 & (load3(a[5:]) >> 2)
+ a3 := 2097151 & (load4(a[7:]) >> 7)
+ a4 := 2097151 & (load4(a[10:]) >> 4)
+ a5 := 2097151 & (load3(a[13:]) >> 1)
+ a6 := 2097151 & (load4(a[15:]) >> 6)
+ a7 := 2097151 & (load3(a[18:]) >> 3)
+ a8 := 2097151 & load3(a[21:])
+ a9 := 2097151 & (load4(a[23:]) >> 5)
+ a10 := 2097151 & (load3(a[26:]) >> 2)
+ a11 := (load4(a[28:]) >> 7)
+ b0 := 2097151 & load3(b[:])
+ b1 := 2097151 & (load4(b[2:]) >> 5)
+ b2 := 2097151 & (load3(b[5:]) >> 2)
+ b3 := 2097151 & (load4(b[7:]) >> 7)
+ b4 := 2097151 & (load4(b[10:]) >> 4)
+ b5 := 2097151 & (load3(b[13:]) >> 1)
+ b6 := 2097151 & (load4(b[15:]) >> 6)
+ b7 := 2097151 & (load3(b[18:]) >> 3)
+ b8 := 2097151 & load3(b[21:])
+ b9 := 2097151 & (load4(b[23:]) >> 5)
+ b10 := 2097151 & (load3(b[26:]) >> 2)
+ b11 := (load4(b[28:]) >> 7)
+ c0 := 2097151 & load3(c[:])
+ c1 := 2097151 & (load4(c[2:]) >> 5)
+ c2 := 2097151 & (load3(c[5:]) >> 2)
+ c3 := 2097151 & (load4(c[7:]) >> 7)
+ c4 := 2097151 & (load4(c[10:]) >> 4)
+ c5 := 2097151 & (load3(c[13:]) >> 1)
+ c6 := 2097151 & (load4(c[15:]) >> 6)
+ c7 := 2097151 & (load3(c[18:]) >> 3)
+ c8 := 2097151 & load3(c[21:])
+ c9 := 2097151 & (load4(c[23:]) >> 5)
+ c10 := 2097151 & (load3(c[26:]) >> 2)
+ c11 := (load4(c[28:]) >> 7)
+ var carry [23]int64
+
+ s0 := c0 + a0*b0
+ s1 := c1 + a0*b1 + a1*b0
+ s2 := c2 + a0*b2 + a1*b1 + a2*b0
+ s3 := c3 + a0*b3 + a1*b2 + a2*b1 + a3*b0
+ s4 := c4 + a0*b4 + a1*b3 + a2*b2 + a3*b1 + a4*b0
+ s5 := c5 + a0*b5 + a1*b4 + a2*b3 + a3*b2 + a4*b1 + a5*b0
+ s6 := c6 + a0*b6 + a1*b5 + a2*b4 + a3*b3 + a4*b2 + a5*b1 + a6*b0
+ s7 := c7 + a0*b7 + a1*b6 + a2*b5 + a3*b4 + a4*b3 + a5*b2 + a6*b1 + a7*b0
+ s8 := c8 + a0*b8 + a1*b7 + a2*b6 + a3*b5 + a4*b4 + a5*b3 + a6*b2 + a7*b1 + a8*b0
+ s9 := c9 + a0*b9 + a1*b8 + a2*b7 + a3*b6 + a4*b5 + a5*b4 + a6*b3 + a7*b2 + a8*b1 + a9*b0
+ s10 := c10 + a0*b10 + a1*b9 + a2*b8 + a3*b7 + a4*b6 + a5*b5 + a6*b4 + a7*b3 + a8*b2 + a9*b1 + a10*b0
+ s11 := c11 + a0*b11 + a1*b10 + a2*b9 + a3*b8 + a4*b7 + a5*b6 + a6*b5 + a7*b4 + a8*b3 + a9*b2 + a10*b1 + a11*b0
+ s12 := a1*b11 + a2*b10 + a3*b9 + a4*b8 + a5*b7 + a6*b6 + a7*b5 + a8*b4 + a9*b3 + a10*b2 + a11*b1
+ s13 := a2*b11 + a3*b10 + a4*b9 + a5*b8 + a6*b7 + a7*b6 + a8*b5 + a9*b4 + a10*b3 + a11*b2
+ s14 := a3*b11 + a4*b10 + a5*b9 + a6*b8 + a7*b7 + a8*b6 + a9*b5 + a10*b4 + a11*b3
+ s15 := a4*b11 + a5*b10 + a6*b9 + a7*b8 + a8*b7 + a9*b6 + a10*b5 + a11*b4
+ s16 := a5*b11 + a6*b10 + a7*b9 + a8*b8 + a9*b7 + a10*b6 + a11*b5
+ s17 := a6*b11 + a7*b10 + a8*b9 + a9*b8 + a10*b7 + a11*b6
+ s18 := a7*b11 + a8*b10 + a9*b9 + a10*b8 + a11*b7
+ s19 := a8*b11 + a9*b10 + a10*b9 + a11*b8
+ s20 := a9*b11 + a10*b10 + a11*b9
+ s21 := a10*b11 + a11*b10
+ s22 := a11 * b11
+ s23 := int64(0)
+
+ carry[0] = (s0 + (1 << 20)) >> 21
+ s1 += carry[0]
+ s0 -= carry[0] << 21
+ carry[2] = (s2 + (1 << 20)) >> 21
+ s3 += carry[2]
+ s2 -= carry[2] << 21
+ carry[4] = (s4 + (1 << 20)) >> 21
+ s5 += carry[4]
+ s4 -= carry[4] << 21
+ carry[6] = (s6 + (1 << 20)) >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[8] = (s8 + (1 << 20)) >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[10] = (s10 + (1 << 20)) >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+ carry[12] = (s12 + (1 << 20)) >> 21
+ s13 += carry[12]
+ s12 -= carry[12] << 21
+ carry[14] = (s14 + (1 << 20)) >> 21
+ s15 += carry[14]
+ s14 -= carry[14] << 21
+ carry[16] = (s16 + (1 << 20)) >> 21
+ s17 += carry[16]
+ s16 -= carry[16] << 21
+ carry[18] = (s18 + (1 << 20)) >> 21
+ s19 += carry[18]
+ s18 -= carry[18] << 21
+ carry[20] = (s20 + (1 << 20)) >> 21
+ s21 += carry[20]
+ s20 -= carry[20] << 21
+ carry[22] = (s22 + (1 << 20)) >> 21
+ s23 += carry[22]
+ s22 -= carry[22] << 21
+
+ carry[1] = (s1 + (1 << 20)) >> 21
+ s2 += carry[1]
+ s1 -= carry[1] << 21
+ carry[3] = (s3 + (1 << 20)) >> 21
+ s4 += carry[3]
+ s3 -= carry[3] << 21
+ carry[5] = (s5 + (1 << 20)) >> 21
+ s6 += carry[5]
+ s5 -= carry[5] << 21
+ carry[7] = (s7 + (1 << 20)) >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[9] = (s9 + (1 << 20)) >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[11] = (s11 + (1 << 20)) >> 21
+ s12 += carry[11]
+ s11 -= carry[11] << 21
+ carry[13] = (s13 + (1 << 20)) >> 21
+ s14 += carry[13]
+ s13 -= carry[13] << 21
+ carry[15] = (s15 + (1 << 20)) >> 21
+ s16 += carry[15]
+ s15 -= carry[15] << 21
+ carry[17] = (s17 + (1 << 20)) >> 21
+ s18 += carry[17]
+ s17 -= carry[17] << 21
+ carry[19] = (s19 + (1 << 20)) >> 21
+ s20 += carry[19]
+ s19 -= carry[19] << 21
+ carry[21] = (s21 + (1 << 20)) >> 21
+ s22 += carry[21]
+ s21 -= carry[21] << 21
+
+ s11 += s23 * 666643
+ s12 += s23 * 470296
+ s13 += s23 * 654183
+ s14 -= s23 * 997805
+ s15 += s23 * 136657
+ s16 -= s23 * 683901
+ s23 = 0
+
+ s10 += s22 * 666643
+ s11 += s22 * 470296
+ s12 += s22 * 654183
+ s13 -= s22 * 997805
+ s14 += s22 * 136657
+ s15 -= s22 * 683901
+ s22 = 0
+
+ s9 += s21 * 666643
+ s10 += s21 * 470296
+ s11 += s21 * 654183
+ s12 -= s21 * 997805
+ s13 += s21 * 136657
+ s14 -= s21 * 683901
+ s21 = 0
+
+ s8 += s20 * 666643
+ s9 += s20 * 470296
+ s10 += s20 * 654183
+ s11 -= s20 * 997805
+ s12 += s20 * 136657
+ s13 -= s20 * 683901
+ s20 = 0
+
+ s7 += s19 * 666643
+ s8 += s19 * 470296
+ s9 += s19 * 654183
+ s10 -= s19 * 997805
+ s11 += s19 * 136657
+ s12 -= s19 * 683901
+ s19 = 0
+
+ s6 += s18 * 666643
+ s7 += s18 * 470296
+ s8 += s18 * 654183
+ s9 -= s18 * 997805
+ s10 += s18 * 136657
+ s11 -= s18 * 683901
+ s18 = 0
+
+ carry[6] = (s6 + (1 << 20)) >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[8] = (s8 + (1 << 20)) >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[10] = (s10 + (1 << 20)) >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+ carry[12] = (s12 + (1 << 20)) >> 21
+ s13 += carry[12]
+ s12 -= carry[12] << 21
+ carry[14] = (s14 + (1 << 20)) >> 21
+ s15 += carry[14]
+ s14 -= carry[14] << 21
+ carry[16] = (s16 + (1 << 20)) >> 21
+ s17 += carry[16]
+ s16 -= carry[16] << 21
+
+ carry[7] = (s7 + (1 << 20)) >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[9] = (s9 + (1 << 20)) >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[11] = (s11 + (1 << 20)) >> 21
+ s12 += carry[11]
+ s11 -= carry[11] << 21
+ carry[13] = (s13 + (1 << 20)) >> 21
+ s14 += carry[13]
+ s13 -= carry[13] << 21
+ carry[15] = (s15 + (1 << 20)) >> 21
+ s16 += carry[15]
+ s15 -= carry[15] << 21
+
+ s5 += s17 * 666643
+ s6 += s17 * 470296
+ s7 += s17 * 654183
+ s8 -= s17 * 997805
+ s9 += s17 * 136657
+ s10 -= s17 * 683901
+ s17 = 0
+
+ s4 += s16 * 666643
+ s5 += s16 * 470296
+ s6 += s16 * 654183
+ s7 -= s16 * 997805
+ s8 += s16 * 136657
+ s9 -= s16 * 683901
+ s16 = 0
+
+ s3 += s15 * 666643
+ s4 += s15 * 470296
+ s5 += s15 * 654183
+ s6 -= s15 * 997805
+ s7 += s15 * 136657
+ s8 -= s15 * 683901
+ s15 = 0
+
+ s2 += s14 * 666643
+ s3 += s14 * 470296
+ s4 += s14 * 654183
+ s5 -= s14 * 997805
+ s6 += s14 * 136657
+ s7 -= s14 * 683901
+ s14 = 0
+
+ s1 += s13 * 666643
+ s2 += s13 * 470296
+ s3 += s13 * 654183
+ s4 -= s13 * 997805
+ s5 += s13 * 136657
+ s6 -= s13 * 683901
+ s13 = 0
+
+ s0 += s12 * 666643
+ s1 += s12 * 470296
+ s2 += s12 * 654183
+ s3 -= s12 * 997805
+ s4 += s12 * 136657
+ s5 -= s12 * 683901
+ s12 = 0
+
+ carry[0] = (s0 + (1 << 20)) >> 21
+ s1 += carry[0]
+ s0 -= carry[0] << 21
+ carry[2] = (s2 + (1 << 20)) >> 21
+ s3 += carry[2]
+ s2 -= carry[2] << 21
+ carry[4] = (s4 + (1 << 20)) >> 21
+ s5 += carry[4]
+ s4 -= carry[4] << 21
+ carry[6] = (s6 + (1 << 20)) >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[8] = (s8 + (1 << 20)) >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[10] = (s10 + (1 << 20)) >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+
+ carry[1] = (s1 + (1 << 20)) >> 21
+ s2 += carry[1]
+ s1 -= carry[1] << 21
+ carry[3] = (s3 + (1 << 20)) >> 21
+ s4 += carry[3]
+ s3 -= carry[3] << 21
+ carry[5] = (s5 + (1 << 20)) >> 21
+ s6 += carry[5]
+ s5 -= carry[5] << 21
+ carry[7] = (s7 + (1 << 20)) >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[9] = (s9 + (1 << 20)) >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[11] = (s11 + (1 << 20)) >> 21
+ s12 += carry[11]
+ s11 -= carry[11] << 21
+
+ s0 += s12 * 666643
+ s1 += s12 * 470296
+ s2 += s12 * 654183
+ s3 -= s12 * 997805
+ s4 += s12 * 136657
+ s5 -= s12 * 683901
+ s12 = 0
+
+ carry[0] = s0 >> 21
+ s1 += carry[0]
+ s0 -= carry[0] << 21
+ carry[1] = s1 >> 21
+ s2 += carry[1]
+ s1 -= carry[1] << 21
+ carry[2] = s2 >> 21
+ s3 += carry[2]
+ s2 -= carry[2] << 21
+ carry[3] = s3 >> 21
+ s4 += carry[3]
+ s3 -= carry[3] << 21
+ carry[4] = s4 >> 21
+ s5 += carry[4]
+ s4 -= carry[4] << 21
+ carry[5] = s5 >> 21
+ s6 += carry[5]
+ s5 -= carry[5] << 21
+ carry[6] = s6 >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[7] = s7 >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[8] = s8 >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[9] = s9 >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[10] = s10 >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+ carry[11] = s11 >> 21
+ s12 += carry[11]
+ s11 -= carry[11] << 21
+
+ s0 += s12 * 666643
+ s1 += s12 * 470296
+ s2 += s12 * 654183
+ s3 -= s12 * 997805
+ s4 += s12 * 136657
+ s5 -= s12 * 683901
+ s12 = 0
+
+ carry[0] = s0 >> 21
+ s1 += carry[0]
+ s0 -= carry[0] << 21
+ carry[1] = s1 >> 21
+ s2 += carry[1]
+ s1 -= carry[1] << 21
+ carry[2] = s2 >> 21
+ s3 += carry[2]
+ s2 -= carry[2] << 21
+ carry[3] = s3 >> 21
+ s4 += carry[3]
+ s3 -= carry[3] << 21
+ carry[4] = s4 >> 21
+ s5 += carry[4]
+ s4 -= carry[4] << 21
+ carry[5] = s5 >> 21
+ s6 += carry[5]
+ s5 -= carry[5] << 21
+ carry[6] = s6 >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[7] = s7 >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[8] = s8 >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[9] = s9 >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[10] = s10 >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+
+ s[0] = byte(s0 >> 0)
+ s[1] = byte(s0 >> 8)
+ s[2] = byte((s0 >> 16) | (s1 << 5))
+ s[3] = byte(s1 >> 3)
+ s[4] = byte(s1 >> 11)
+ s[5] = byte((s1 >> 19) | (s2 << 2))
+ s[6] = byte(s2 >> 6)
+ s[7] = byte((s2 >> 14) | (s3 << 7))
+ s[8] = byte(s3 >> 1)
+ s[9] = byte(s3 >> 9)
+ s[10] = byte((s3 >> 17) | (s4 << 4))
+ s[11] = byte(s4 >> 4)
+ s[12] = byte(s4 >> 12)
+ s[13] = byte((s4 >> 20) | (s5 << 1))
+ s[14] = byte(s5 >> 7)
+ s[15] = byte((s5 >> 15) | (s6 << 6))
+ s[16] = byte(s6 >> 2)
+ s[17] = byte(s6 >> 10)
+ s[18] = byte((s6 >> 18) | (s7 << 3))
+ s[19] = byte(s7 >> 5)
+ s[20] = byte(s7 >> 13)
+ s[21] = byte(s8 >> 0)
+ s[22] = byte(s8 >> 8)
+ s[23] = byte((s8 >> 16) | (s9 << 5))
+ s[24] = byte(s9 >> 3)
+ s[25] = byte(s9 >> 11)
+ s[26] = byte((s9 >> 19) | (s10 << 2))
+ s[27] = byte(s10 >> 6)
+ s[28] = byte((s10 >> 14) | (s11 << 7))
+ s[29] = byte(s11 >> 1)
+ s[30] = byte(s11 >> 9)
+ s[31] = byte(s11 >> 17)
+}
+
+// Input:
+// s[0]+256*s[1]+...+256^63*s[63] = s
+//
+// Output:
+// s[0]+256*s[1]+...+256^31*s[31] = s mod l
+// where l = 2^252 + 27742317777372353535851937790883648493.
+func ScReduce(out *[32]byte, s *[64]byte) {
+ s0 := 2097151 & load3(s[:])
+ s1 := 2097151 & (load4(s[2:]) >> 5)
+ s2 := 2097151 & (load3(s[5:]) >> 2)
+ s3 := 2097151 & (load4(s[7:]) >> 7)
+ s4 := 2097151 & (load4(s[10:]) >> 4)
+ s5 := 2097151 & (load3(s[13:]) >> 1)
+ s6 := 2097151 & (load4(s[15:]) >> 6)
+ s7 := 2097151 & (load3(s[18:]) >> 3)
+ s8 := 2097151 & load3(s[21:])
+ s9 := 2097151 & (load4(s[23:]) >> 5)
+ s10 := 2097151 & (load3(s[26:]) >> 2)
+ s11 := 2097151 & (load4(s[28:]) >> 7)
+ s12 := 2097151 & (load4(s[31:]) >> 4)
+ s13 := 2097151 & (load3(s[34:]) >> 1)
+ s14 := 2097151 & (load4(s[36:]) >> 6)
+ s15 := 2097151 & (load3(s[39:]) >> 3)
+ s16 := 2097151 & load3(s[42:])
+ s17 := 2097151 & (load4(s[44:]) >> 5)
+ s18 := 2097151 & (load3(s[47:]) >> 2)
+ s19 := 2097151 & (load4(s[49:]) >> 7)
+ s20 := 2097151 & (load4(s[52:]) >> 4)
+ s21 := 2097151 & (load3(s[55:]) >> 1)
+ s22 := 2097151 & (load4(s[57:]) >> 6)
+ s23 := (load4(s[60:]) >> 3)
+
+ s11 += s23 * 666643
+ s12 += s23 * 470296
+ s13 += s23 * 654183
+ s14 -= s23 * 997805
+ s15 += s23 * 136657
+ s16 -= s23 * 683901
+ s23 = 0
+
+ s10 += s22 * 666643
+ s11 += s22 * 470296
+ s12 += s22 * 654183
+ s13 -= s22 * 997805
+ s14 += s22 * 136657
+ s15 -= s22 * 683901
+ s22 = 0
+
+ s9 += s21 * 666643
+ s10 += s21 * 470296
+ s11 += s21 * 654183
+ s12 -= s21 * 997805
+ s13 += s21 * 136657
+ s14 -= s21 * 683901
+ s21 = 0
+
+ s8 += s20 * 666643
+ s9 += s20 * 470296
+ s10 += s20 * 654183
+ s11 -= s20 * 997805
+ s12 += s20 * 136657
+ s13 -= s20 * 683901
+ s20 = 0
+
+ s7 += s19 * 666643
+ s8 += s19 * 470296
+ s9 += s19 * 654183
+ s10 -= s19 * 997805
+ s11 += s19 * 136657
+ s12 -= s19 * 683901
+ s19 = 0
+
+ s6 += s18 * 666643
+ s7 += s18 * 470296
+ s8 += s18 * 654183
+ s9 -= s18 * 997805
+ s10 += s18 * 136657
+ s11 -= s18 * 683901
+ s18 = 0
+
+ var carry [17]int64
+
+ carry[6] = (s6 + (1 << 20)) >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[8] = (s8 + (1 << 20)) >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[10] = (s10 + (1 << 20)) >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+ carry[12] = (s12 + (1 << 20)) >> 21
+ s13 += carry[12]
+ s12 -= carry[12] << 21
+ carry[14] = (s14 + (1 << 20)) >> 21
+ s15 += carry[14]
+ s14 -= carry[14] << 21
+ carry[16] = (s16 + (1 << 20)) >> 21
+ s17 += carry[16]
+ s16 -= carry[16] << 21
+
+ carry[7] = (s7 + (1 << 20)) >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[9] = (s9 + (1 << 20)) >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[11] = (s11 + (1 << 20)) >> 21
+ s12 += carry[11]
+ s11 -= carry[11] << 21
+ carry[13] = (s13 + (1 << 20)) >> 21
+ s14 += carry[13]
+ s13 -= carry[13] << 21
+ carry[15] = (s15 + (1 << 20)) >> 21
+ s16 += carry[15]
+ s15 -= carry[15] << 21
+
+ s5 += s17 * 666643
+ s6 += s17 * 470296
+ s7 += s17 * 654183
+ s8 -= s17 * 997805
+ s9 += s17 * 136657
+ s10 -= s17 * 683901
+ s17 = 0
+
+ s4 += s16 * 666643
+ s5 += s16 * 470296
+ s6 += s16 * 654183
+ s7 -= s16 * 997805
+ s8 += s16 * 136657
+ s9 -= s16 * 683901
+ s16 = 0
+
+ s3 += s15 * 666643
+ s4 += s15 * 470296
+ s5 += s15 * 654183
+ s6 -= s15 * 997805
+ s7 += s15 * 136657
+ s8 -= s15 * 683901
+ s15 = 0
+
+ s2 += s14 * 666643
+ s3 += s14 * 470296
+ s4 += s14 * 654183
+ s5 -= s14 * 997805
+ s6 += s14 * 136657
+ s7 -= s14 * 683901
+ s14 = 0
+
+ s1 += s13 * 666643
+ s2 += s13 * 470296
+ s3 += s13 * 654183
+ s4 -= s13 * 997805
+ s5 += s13 * 136657
+ s6 -= s13 * 683901
+ s13 = 0
+
+ s0 += s12 * 666643
+ s1 += s12 * 470296
+ s2 += s12 * 654183
+ s3 -= s12 * 997805
+ s4 += s12 * 136657
+ s5 -= s12 * 683901
+ s12 = 0
+
+ carry[0] = (s0 + (1 << 20)) >> 21
+ s1 += carry[0]
+ s0 -= carry[0] << 21
+ carry[2] = (s2 + (1 << 20)) >> 21
+ s3 += carry[2]
+ s2 -= carry[2] << 21
+ carry[4] = (s4 + (1 << 20)) >> 21
+ s5 += carry[4]
+ s4 -= carry[4] << 21
+ carry[6] = (s6 + (1 << 20)) >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[8] = (s8 + (1 << 20)) >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[10] = (s10 + (1 << 20)) >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+
+ carry[1] = (s1 + (1 << 20)) >> 21
+ s2 += carry[1]
+ s1 -= carry[1] << 21
+ carry[3] = (s3 + (1 << 20)) >> 21
+ s4 += carry[3]
+ s3 -= carry[3] << 21
+ carry[5] = (s5 + (1 << 20)) >> 21
+ s6 += carry[5]
+ s5 -= carry[5] << 21
+ carry[7] = (s7 + (1 << 20)) >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[9] = (s9 + (1 << 20)) >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[11] = (s11 + (1 << 20)) >> 21
+ s12 += carry[11]
+ s11 -= carry[11] << 21
+
+ s0 += s12 * 666643
+ s1 += s12 * 470296
+ s2 += s12 * 654183
+ s3 -= s12 * 997805
+ s4 += s12 * 136657
+ s5 -= s12 * 683901
+ s12 = 0
+
+ carry[0] = s0 >> 21
+ s1 += carry[0]
+ s0 -= carry[0] << 21
+ carry[1] = s1 >> 21
+ s2 += carry[1]
+ s1 -= carry[1] << 21
+ carry[2] = s2 >> 21
+ s3 += carry[2]
+ s2 -= carry[2] << 21
+ carry[3] = s3 >> 21
+ s4 += carry[3]
+ s3 -= carry[3] << 21
+ carry[4] = s4 >> 21
+ s5 += carry[4]
+ s4 -= carry[4] << 21
+ carry[5] = s5 >> 21
+ s6 += carry[5]
+ s5 -= carry[5] << 21
+ carry[6] = s6 >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[7] = s7 >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[8] = s8 >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[9] = s9 >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[10] = s10 >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+ carry[11] = s11 >> 21
+ s12 += carry[11]
+ s11 -= carry[11] << 21
+
+ s0 += s12 * 666643
+ s1 += s12 * 470296
+ s2 += s12 * 654183
+ s3 -= s12 * 997805
+ s4 += s12 * 136657
+ s5 -= s12 * 683901
+ s12 = 0
+
+ carry[0] = s0 >> 21
+ s1 += carry[0]
+ s0 -= carry[0] << 21
+ carry[1] = s1 >> 21
+ s2 += carry[1]
+ s1 -= carry[1] << 21
+ carry[2] = s2 >> 21
+ s3 += carry[2]
+ s2 -= carry[2] << 21
+ carry[3] = s3 >> 21
+ s4 += carry[3]
+ s3 -= carry[3] << 21
+ carry[4] = s4 >> 21
+ s5 += carry[4]
+ s4 -= carry[4] << 21
+ carry[5] = s5 >> 21
+ s6 += carry[5]
+ s5 -= carry[5] << 21
+ carry[6] = s6 >> 21
+ s7 += carry[6]
+ s6 -= carry[6] << 21
+ carry[7] = s7 >> 21
+ s8 += carry[7]
+ s7 -= carry[7] << 21
+ carry[8] = s8 >> 21
+ s9 += carry[8]
+ s8 -= carry[8] << 21
+ carry[9] = s9 >> 21
+ s10 += carry[9]
+ s9 -= carry[9] << 21
+ carry[10] = s10 >> 21
+ s11 += carry[10]
+ s10 -= carry[10] << 21
+
+ out[0] = byte(s0 >> 0)
+ out[1] = byte(s0 >> 8)
+ out[2] = byte((s0 >> 16) | (s1 << 5))
+ out[3] = byte(s1 >> 3)
+ out[4] = byte(s1 >> 11)
+ out[5] = byte((s1 >> 19) | (s2 << 2))
+ out[6] = byte(s2 >> 6)
+ out[7] = byte((s2 >> 14) | (s3 << 7))
+ out[8] = byte(s3 >> 1)
+ out[9] = byte(s3 >> 9)
+ out[10] = byte((s3 >> 17) | (s4 << 4))
+ out[11] = byte(s4 >> 4)
+ out[12] = byte(s4 >> 12)
+ out[13] = byte((s4 >> 20) | (s5 << 1))
+ out[14] = byte(s5 >> 7)
+ out[15] = byte((s5 >> 15) | (s6 << 6))
+ out[16] = byte(s6 >> 2)
+ out[17] = byte(s6 >> 10)
+ out[18] = byte((s6 >> 18) | (s7 << 3))
+ out[19] = byte(s7 >> 5)
+ out[20] = byte(s7 >> 13)
+ out[21] = byte(s8 >> 0)
+ out[22] = byte(s8 >> 8)
+ out[23] = byte((s8 >> 16) | (s9 << 5))
+ out[24] = byte(s9 >> 3)
+ out[25] = byte(s9 >> 11)
+ out[26] = byte((s9 >> 19) | (s10 << 2))
+ out[27] = byte(s10 >> 6)
+ out[28] = byte((s10 >> 14) | (s11 << 7))
+ out[29] = byte(s11 >> 1)
+ out[30] = byte(s11 >> 9)
+ out[31] = byte(s11 >> 17)
+}
diff --git a/vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gz b/vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gz
new file mode 100644
index 000000000..41030690c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ed25519/testdata/sign.input.gz
Binary files differ
diff --git a/vendor/golang.org/x/crypto/hkdf/example_test.go b/vendor/golang.org/x/crypto/hkdf/example_test.go
new file mode 100644
index 000000000..df8439512
--- /dev/null
+++ b/vendor/golang.org/x/crypto/hkdf/example_test.go
@@ -0,0 +1,61 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hkdf_test
+
+import (
+ "bytes"
+ "crypto/rand"
+ "crypto/sha256"
+ "fmt"
+ "golang.org/x/crypto/hkdf"
+ "io"
+)
+
+// Usage example that expands one master key into three other cryptographically
+// secure keys.
+func Example_usage() {
+ // Underlying hash function to use
+ hash := sha256.New
+
+ // Cryptographically secure master key.
+ master := []byte{0x00, 0x01, 0x02, 0x03} // i.e. NOT this.
+
+ // Non secret salt, optional (can be nil)
+ // Recommended: hash-length sized random
+ salt := make([]byte, hash().Size())
+ n, err := io.ReadFull(rand.Reader, salt)
+ if n != len(salt) || err != nil {
+ fmt.Println("error:", err)
+ return
+ }
+
+ // Non secret context specific info, optional (can be nil).
+ // Note, independent from the master key.
+ info := []byte{0x03, 0x14, 0x15, 0x92, 0x65}
+
+ // Create the key derivation function
+ hkdf := hkdf.New(hash, master, salt, info)
+
+ // Generate the required keys
+ keys := make([][]byte, 3)
+ for i := 0; i < len(keys); i++ {
+ keys[i] = make([]byte, 24)
+ n, err := io.ReadFull(hkdf, keys[i])
+ if n != len(keys[i]) || err != nil {
+ fmt.Println("error:", err)
+ return
+ }
+ }
+
+ // Keys should contain 192 bit random keys
+ for i := 1; i <= len(keys); i++ {
+ fmt.Printf("Key #%d: %v\n", i, !bytes.Equal(keys[i-1], make([]byte, 24)))
+ }
+
+ // Output:
+ // Key #1: true
+ // Key #2: true
+ // Key #3: true
+}
diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go
new file mode 100644
index 000000000..5bc246355
--- /dev/null
+++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go
@@ -0,0 +1,75 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation
+// Function (HKDF) as defined in RFC 5869.
+//
+// HKDF is a cryptographic key derivation function (KDF) with the goal of
+// expanding limited input keying material into one or more cryptographically
+// strong secret keys.
+//
+// RFC 5869: https://tools.ietf.org/html/rfc5869
+package hkdf // import "golang.org/x/crypto/hkdf"
+
+import (
+ "crypto/hmac"
+ "errors"
+ "hash"
+ "io"
+)
+
+type hkdf struct {
+ expander hash.Hash
+ size int
+
+ info []byte
+ counter byte
+
+ prev []byte
+ cache []byte
+}
+
+func (f *hkdf) Read(p []byte) (int, error) {
+ // Check whether enough data can be generated
+ need := len(p)
+ remains := len(f.cache) + int(255-f.counter+1)*f.size
+ if remains < need {
+ return 0, errors.New("hkdf: entropy limit reached")
+ }
+ // Read from the cache, if enough data is present
+ n := copy(p, f.cache)
+ p = p[n:]
+
+ // Fill the buffer
+ for len(p) > 0 {
+ f.expander.Reset()
+ f.expander.Write(f.prev)
+ f.expander.Write(f.info)
+ f.expander.Write([]byte{f.counter})
+ f.prev = f.expander.Sum(f.prev[:0])
+ f.counter++
+
+ // Copy the new batch into p
+ f.cache = f.prev
+ n = copy(p, f.cache)
+ p = p[n:]
+ }
+ // Save leftovers for next run
+ f.cache = f.cache[n:]
+
+ return need, nil
+}
+
+// New returns a new HKDF using the given hash, the secret keying material to expand
+// and optional salt and info fields.
+func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader {
+ if salt == nil {
+ salt = make([]byte, hash().Size())
+ }
+ extractor := hmac.New(hash, salt)
+ extractor.Write(secret)
+ prk := extractor.Sum(nil)
+
+ return &hkdf{hmac.New(hash, prk), extractor.Size(), info, 1, nil, nil}
+}
diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf_test.go b/vendor/golang.org/x/crypto/hkdf/hkdf_test.go
new file mode 100644
index 000000000..cee659bcd
--- /dev/null
+++ b/vendor/golang.org/x/crypto/hkdf/hkdf_test.go
@@ -0,0 +1,370 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+package hkdf
+
+import (
+ "bytes"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "hash"
+ "io"
+ "testing"
+)
+
+type hkdfTest struct {
+ hash func() hash.Hash
+ master []byte
+ salt []byte
+ info []byte
+ out []byte
+}
+
+var hkdfTests = []hkdfTest{
+ // Tests from RFC 5869
+ {
+ sha256.New,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ },
+ []byte{
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9,
+ },
+ []byte{
+ 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+ 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+ 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+ 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+ 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+ 0x58, 0x65,
+ },
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ },
+ []byte{
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ },
+ []byte{
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ },
+ []byte{
+ 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1,
+ 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
+ 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
+ 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
+ 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72,
+ 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+ 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
+ 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
+ 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
+ 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
+ 0x1d, 0x87,
+ },
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ []byte{},
+ []byte{},
+ []byte{
+ 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f,
+ 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31,
+ 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e,
+ 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d,
+ 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a,
+ 0x96, 0xc8,
+ },
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b,
+ },
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ },
+ []byte{
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9,
+ },
+ []byte{
+ 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69,
+ 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81,
+ 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15,
+ 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2,
+ 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3,
+ 0xf8, 0x96,
+ },
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ },
+ []byte{
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ },
+ []byte{
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ },
+ []byte{
+ 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7,
+ 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb,
+ 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19,
+ 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe,
+ 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3,
+ 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c,
+ 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed,
+ 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e,
+ 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43,
+ 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52,
+ 0xd3, 0xb4,
+ },
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ []byte{},
+ []byte{},
+ []byte{
+ 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61,
+ 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06,
+ 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06,
+ 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0,
+ 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3,
+ 0x49, 0x18,
+ },
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ },
+ nil,
+ []byte{},
+ []byte{
+ 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3,
+ 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a,
+ 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23,
+ 0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5,
+ 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac,
+ 0xfc, 0x48,
+ },
+ },
+}
+
+func TestHKDF(t *testing.T) {
+ for i, tt := range hkdfTests {
+ hkdf := New(tt.hash, tt.master, tt.salt, tt.info)
+ out := make([]byte, len(tt.out))
+
+ n, err := io.ReadFull(hkdf, out)
+ if n != len(tt.out) || err != nil {
+ t.Errorf("test %d: not enough output bytes: %d.", i, n)
+ }
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("test %d: incorrect output: have %v, need %v.", i, out, tt.out)
+ }
+ }
+}
+
+func TestHKDFMultiRead(t *testing.T) {
+ for i, tt := range hkdfTests {
+ hkdf := New(tt.hash, tt.master, tt.salt, tt.info)
+ out := make([]byte, len(tt.out))
+
+ for b := 0; b < len(tt.out); b++ {
+ n, err := io.ReadFull(hkdf, out[b:b+1])
+ if n != 1 || err != nil {
+ t.Errorf("test %d.%d: not enough output bytes: have %d, need %d .", i, b, n, len(tt.out))
+ }
+ }
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("test %d: incorrect output: have %v, need %v.", i, out, tt.out)
+ }
+ }
+}
+
+func TestHKDFLimit(t *testing.T) {
+ hash := sha1.New
+ master := []byte{0x00, 0x01, 0x02, 0x03}
+ info := []byte{}
+
+ hkdf := New(hash, master, nil, info)
+ limit := hash().Size() * 255
+ out := make([]byte, limit)
+
+ // The maximum output bytes should be extractable
+ n, err := io.ReadFull(hkdf, out)
+ if n != limit || err != nil {
+ t.Errorf("not enough output bytes: %d, %v.", n, err)
+ }
+
+ // Reading one more should fail
+ n, err = io.ReadFull(hkdf, make([]byte, 1))
+ if n > 0 || err == nil {
+ t.Errorf("key expansion overflowed: n = %d, err = %v", n, err)
+ }
+}
+
+func Benchmark16ByteMD5Single(b *testing.B) {
+ benchmarkHKDFSingle(md5.New, 16, b)
+}
+
+func Benchmark20ByteSHA1Single(b *testing.B) {
+ benchmarkHKDFSingle(sha1.New, 20, b)
+}
+
+func Benchmark32ByteSHA256Single(b *testing.B) {
+ benchmarkHKDFSingle(sha256.New, 32, b)
+}
+
+func Benchmark64ByteSHA512Single(b *testing.B) {
+ benchmarkHKDFSingle(sha512.New, 64, b)
+}
+
+func Benchmark8ByteMD5Stream(b *testing.B) {
+ benchmarkHKDFStream(md5.New, 8, b)
+}
+
+func Benchmark16ByteMD5Stream(b *testing.B) {
+ benchmarkHKDFStream(md5.New, 16, b)
+}
+
+func Benchmark8ByteSHA1Stream(b *testing.B) {
+ benchmarkHKDFStream(sha1.New, 8, b)
+}
+
+func Benchmark20ByteSHA1Stream(b *testing.B) {
+ benchmarkHKDFStream(sha1.New, 20, b)
+}
+
+func Benchmark8ByteSHA256Stream(b *testing.B) {
+ benchmarkHKDFStream(sha256.New, 8, b)
+}
+
+func Benchmark32ByteSHA256Stream(b *testing.B) {
+ benchmarkHKDFStream(sha256.New, 32, b)
+}
+
+func Benchmark8ByteSHA512Stream(b *testing.B) {
+ benchmarkHKDFStream(sha512.New, 8, b)
+}
+
+func Benchmark64ByteSHA512Stream(b *testing.B) {
+ benchmarkHKDFStream(sha512.New, 64, b)
+}
+
+func benchmarkHKDFSingle(hasher func() hash.Hash, block int, b *testing.B) {
+ master := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
+ salt := []byte{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}
+ info := []byte{0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}
+ out := make([]byte, block)
+
+ b.SetBytes(int64(block))
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ hkdf := New(hasher, master, salt, info)
+ io.ReadFull(hkdf, out)
+ }
+}
+
+func benchmarkHKDFStream(hasher func() hash.Hash, block int, b *testing.B) {
+ master := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}
+ salt := []byte{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17}
+ info := []byte{0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27}
+ out := make([]byte, block)
+
+ b.SetBytes(int64(block))
+ b.ResetTimer()
+
+ hkdf := New(hasher, master, salt, info)
+ for i := 0; i < b.N; i++ {
+ _, err := io.ReadFull(hkdf, out)
+ if err != nil {
+ hkdf = New(hasher, master, salt, info)
+ i--
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/md4/md4.go b/vendor/golang.org/x/crypto/md4/md4.go
new file mode 100644
index 000000000..6d9ba9e5f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/md4/md4.go
@@ -0,0 +1,118 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package md4 implements the MD4 hash algorithm as defined in RFC 1320.
+package md4 // import "golang.org/x/crypto/md4"
+
+import (
+ "crypto"
+ "hash"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.MD4, New)
+}
+
+// The size of an MD4 checksum in bytes.
+const Size = 16
+
+// The blocksize of MD4 in bytes.
+const BlockSize = 64
+
+const (
+ _Chunk = 64
+ _Init0 = 0x67452301
+ _Init1 = 0xEFCDAB89
+ _Init2 = 0x98BADCFE
+ _Init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [4]uint32
+ x [_Chunk]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.s[0] = _Init0
+ d.s[1] = _Init1
+ d.s[2] = _Init2
+ d.s[3] = _Init3
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the MD4 checksum.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > _Chunk-d.nx {
+ n = _Chunk - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == _Chunk {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum(in []byte) []byte {
+ // Make a copy of d0, so that caller can keep writing and summing.
+ d := new(digest)
+ *d = *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ len := d.len
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if len%64 < 56 {
+ d.Write(tmp[0 : 56-len%64])
+ } else {
+ d.Write(tmp[0 : 64+56-len%64])
+ }
+
+ // Length in bits.
+ len <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(len >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ for _, s := range d.s {
+ in = append(in, byte(s>>0))
+ in = append(in, byte(s>>8))
+ in = append(in, byte(s>>16))
+ in = append(in, byte(s>>24))
+ }
+ return in
+}
diff --git a/vendor/golang.org/x/crypto/md4/md4_test.go b/vendor/golang.org/x/crypto/md4/md4_test.go
new file mode 100644
index 000000000..b56edd787
--- /dev/null
+++ b/vendor/golang.org/x/crypto/md4/md4_test.go
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package md4
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type md4Test struct {
+ out string
+ in string
+}
+
+var golden = []md4Test{
+ {"31d6cfe0d16ae931b73c59d7e0c089c0", ""},
+ {"bde52cb31de33e46245e05fbdbd6fb24", "a"},
+ {"ec388dd78999dfc7cf4632465693b6bf", "ab"},
+ {"a448017aaf21d8525fc10ae87aa6729d", "abc"},
+ {"41decd8f579255c5200f86a4bb3ba740", "abcd"},
+ {"9803f4a34e8eb14f96adba49064a0c41", "abcde"},
+ {"804e7f1c2586e50b49ac65db5b645131", "abcdef"},
+ {"752f4adfe53d1da0241b5bc216d098fc", "abcdefg"},
+ {"ad9daf8d49d81988590a6f0e745d15dd", "abcdefgh"},
+ {"1e4e28b05464316b56402b3815ed2dfd", "abcdefghi"},
+ {"dc959c6f5d6f9e04e4380777cc964b3d", "abcdefghij"},
+ {"1b5701e265778898ef7de5623bbe7cc0", "Discard medicine more than two years old."},
+ {"d7f087e090fe7ad4a01cb59dacc9a572", "He who has a shady past knows that nice guys finish last."},
+ {"a6f8fd6df617c72837592fc3570595c9", "I wouldn't marry him with a ten foot pole."},
+ {"c92a84a9526da8abc240c05d6b1a1ce0", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"f6013160c4dcb00847069fee3bb09803", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"2c3bb64f50b9107ed57640fe94bec09f", "Nepal premier won't resign."},
+ {"45b7d8a32c7806f2f7f897332774d6e4", "For every action there is an equal and opposite government program."},
+ {"b5b4f9026b175c62d7654bdc3a1cd438", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"caf44e80f2c20ce19b5ba1cab766e7bd", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"191fae6707f496aa54a6bce9f2ecf74d", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"9ddc753e7a4ccee6081cd1b45b23a834", "size: a.out: bad magic"},
+ {"8d050f55b1cadb9323474564be08a521", "The major problem is with sendmail. -Mark Horton"},
+ {"ad6e2587f74c3e3cc19146f6127fa2e3", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"1d616d60a5fabe85589c3f1566ca7fca", "If the enemy is within range, then so are you."},
+ {"aec3326a4f496a2ced65a1963f84577f", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"77b4fd762d6b9245e61c50bf6ebf118b", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"e8f48c726bae5e516f6ddb1a4fe62438", "C is as portable as Stonehedge!!"},
+ {"a3a84366e7219e887423b01f9be7166e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"a6b7aa35157e984ef5d9b7f32e5fbb52", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"75661f0545955f8f9abeeb17845f3fd6", "How can you write a big system without C++? -Paul Glick"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum(nil))
+ if s != g.out {
+ t.Fatalf("md4[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/md4/md4block.go b/vendor/golang.org/x/crypto/md4/md4block.go
new file mode 100644
index 000000000..3fed475f3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/md4/md4block.go
@@ -0,0 +1,89 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// MD4 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package md4
+
+var shift1 = []uint{3, 7, 11, 19}
+var shift2 = []uint{3, 5, 9, 13}
+var shift3 = []uint{3, 9, 11, 15}
+
+var xIndex2 = []uint{0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15}
+var xIndex3 = []uint{0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}
+
+func _Block(dig *digest, p []byte) int {
+ a := dig.s[0]
+ b := dig.s[1]
+ c := dig.s[2]
+ d := dig.s[3]
+ n := 0
+ var X [16]uint32
+ for len(p) >= _Chunk {
+ aa, bb, cc, dd := a, b, c, d
+
+ j := 0
+ for i := 0; i < 16; i++ {
+ X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // If this needs to be made faster in the future,
+ // the usual trick is to unroll each of these
+ // loops by a factor of 4; that lets you replace
+ // the shift[] lookups with constants and,
+ // with suitable variable renaming in each
+ // unrolled body, delete the a, b, c, d = d, a, b, c
+ // (or you can let the optimizer do the renaming).
+ //
+ // The index variables are uint so that % by a power
+ // of two can be optimized easily by a compiler.
+
+ // Round 1.
+ for i := uint(0); i < 16; i++ {
+ x := i
+ s := shift1[i%4]
+ f := ((c ^ d) & b) ^ d
+ a += f + X[x]
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 2.
+ for i := uint(0); i < 16; i++ {
+ x := xIndex2[i]
+ s := shift2[i%4]
+ g := (b & c) | (b & d) | (c & d)
+ a += g + X[x] + 0x5a827999
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ // Round 3.
+ for i := uint(0); i < 16; i++ {
+ x := xIndex3[i]
+ s := shift3[i%4]
+ h := b ^ c ^ d
+ a += h + X[x] + 0x6ed9eba1
+ a = a<<s | a>>(32-s)
+ a, b, c, d = d, a, b, c
+ }
+
+ a += aa
+ b += bb
+ c += cc
+ d += dd
+
+ p = p[_Chunk:]
+ n += _Chunk
+ }
+
+ dig.s[0] = a
+ dig.s[1] = b
+ dig.s[2] = c
+ dig.s[3] = d
+ return n
+}
diff --git a/vendor/golang.org/x/crypto/nacl/box/box.go b/vendor/golang.org/x/crypto/nacl/box/box.go
new file mode 100644
index 000000000..ca48a6dbf
--- /dev/null
+++ b/vendor/golang.org/x/crypto/nacl/box/box.go
@@ -0,0 +1,85 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package box authenticates and encrypts messages using public-key cryptography.
+
+Box uses Curve25519, XSalsa20 and Poly1305 to encrypt and authenticate
+messages. The length of messages is not hidden.
+
+It is the caller's responsibility to ensure the uniqueness of nonces—for
+example, by using nonce 1 for the first message, nonce 2 for the second
+message, etc. Nonces are long enough that randomly generated nonces have
+negligible risk of collision.
+
+This package is interoperable with NaCl: http://nacl.cr.yp.to/box.html.
+*/
+package box // import "golang.org/x/crypto/nacl/box"
+
+import (
+ "golang.org/x/crypto/curve25519"
+ "golang.org/x/crypto/nacl/secretbox"
+ "golang.org/x/crypto/salsa20/salsa"
+ "io"
+)
+
+// Overhead is the number of bytes of overhead when boxing a message.
+const Overhead = secretbox.Overhead
+
+// GenerateKey generates a new public/private key pair suitable for use with
+// Seal and Open.
+func GenerateKey(rand io.Reader) (publicKey, privateKey *[32]byte, err error) {
+ publicKey = new([32]byte)
+ privateKey = new([32]byte)
+ _, err = io.ReadFull(rand, privateKey[:])
+ if err != nil {
+ publicKey = nil
+ privateKey = nil
+ return
+ }
+
+ curve25519.ScalarBaseMult(publicKey, privateKey)
+ return
+}
+
+var zeros [16]byte
+
+// Precompute calculates the shared key between peersPublicKey and privateKey
+// and writes it to sharedKey. The shared key can be used with
+// OpenAfterPrecomputation and SealAfterPrecomputation to speed up processing
+// when using the same pair of keys repeatedly.
+func Precompute(sharedKey, peersPublicKey, privateKey *[32]byte) {
+ curve25519.ScalarMult(sharedKey, privateKey, peersPublicKey)
+ salsa.HSalsa20(sharedKey, &zeros, sharedKey, &salsa.Sigma)
+}
+
+// Seal appends an encrypted and authenticated copy of message to out, which
+// will be Overhead bytes longer than the original and must not overlap. The
+// nonce must be unique for each distinct message for a given pair of keys.
+func Seal(out, message []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) []byte {
+ var sharedKey [32]byte
+ Precompute(&sharedKey, peersPublicKey, privateKey)
+ return secretbox.Seal(out, message, nonce, &sharedKey)
+}
+
+// SealAfterPrecomputation performs the same actions as Seal, but takes a
+// shared key as generated by Precompute.
+func SealAfterPrecomputation(out, message []byte, nonce *[24]byte, sharedKey *[32]byte) []byte {
+ return secretbox.Seal(out, message, nonce, sharedKey)
+}
+
+// Open authenticates and decrypts a box produced by Seal and appends the
+// message to out, which must not overlap box. The output will be Overhead
+// bytes smaller than box.
+func Open(out, box []byte, nonce *[24]byte, peersPublicKey, privateKey *[32]byte) ([]byte, bool) {
+ var sharedKey [32]byte
+ Precompute(&sharedKey, peersPublicKey, privateKey)
+ return secretbox.Open(out, box, nonce, &sharedKey)
+}
+
+// OpenAfterPrecomputation performs the same actions as Open, but takes a
+// shared key as generated by Precompute.
+func OpenAfterPrecomputation(out, box []byte, nonce *[24]byte, sharedKey *[32]byte) ([]byte, bool) {
+ return secretbox.Open(out, box, nonce, sharedKey)
+}
diff --git a/vendor/golang.org/x/crypto/nacl/box/box_test.go b/vendor/golang.org/x/crypto/nacl/box/box_test.go
new file mode 100644
index 000000000..481ade28a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/nacl/box/box_test.go
@@ -0,0 +1,78 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package box
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/hex"
+ "testing"
+
+ "golang.org/x/crypto/curve25519"
+)
+
+func TestSealOpen(t *testing.T) {
+ publicKey1, privateKey1, _ := GenerateKey(rand.Reader)
+ publicKey2, privateKey2, _ := GenerateKey(rand.Reader)
+
+ if *privateKey1 == *privateKey2 {
+ t.Fatalf("private keys are equal!")
+ }
+ if *publicKey1 == *publicKey2 {
+ t.Fatalf("public keys are equal!")
+ }
+ message := []byte("test message")
+ var nonce [24]byte
+
+ box := Seal(nil, message, &nonce, publicKey1, privateKey2)
+ opened, ok := Open(nil, box, &nonce, publicKey2, privateKey1)
+ if !ok {
+ t.Fatalf("failed to open box")
+ }
+
+ if !bytes.Equal(opened, message) {
+ t.Fatalf("got %x, want %x", opened, message)
+ }
+
+ for i := range box {
+ box[i] ^= 0x40
+ _, ok := Open(nil, box, &nonce, publicKey2, privateKey1)
+ if ok {
+ t.Fatalf("opened box with byte %d corrupted", i)
+ }
+ box[i] ^= 0x40
+ }
+}
+
+func TestBox(t *testing.T) {
+ var privateKey1, privateKey2 [32]byte
+ for i := range privateKey1[:] {
+ privateKey1[i] = 1
+ }
+ for i := range privateKey2[:] {
+ privateKey2[i] = 2
+ }
+
+ var publicKey1 [32]byte
+ curve25519.ScalarBaseMult(&publicKey1, &privateKey1)
+ var message [64]byte
+ for i := range message[:] {
+ message[i] = 3
+ }
+
+ var nonce [24]byte
+ for i := range nonce[:] {
+ nonce[i] = 4
+ }
+
+ box := Seal(nil, message[:], &nonce, &publicKey1, &privateKey2)
+
+ // expected was generated using the C implementation of NaCl.
+ expected, _ := hex.DecodeString("78ea30b19d2341ebbdba54180f821eec265cf86312549bea8a37652a8bb94f07b78a73ed1708085e6ddd0e943bbdeb8755079a37eb31d86163ce241164a47629c0539f330b4914cd135b3855bc2a2dfc")
+
+ if !bytes.Equal(box, expected) {
+ t.Fatalf("box didn't match, got\n%x\n, expected\n%x", box, expected)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go
new file mode 100644
index 000000000..dbf31bbf4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox.go
@@ -0,0 +1,149 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package secretbox encrypts and authenticates small messages.
+
+Secretbox uses XSalsa20 and Poly1305 to encrypt and authenticate messages with
+secret-key cryptography. The length of messages is not hidden.
+
+It is the caller's responsibility to ensure the uniqueness of nonces—for
+example, by using nonce 1 for the first message, nonce 2 for the second
+message, etc. Nonces are long enough that randomly generated nonces have
+negligible risk of collision.
+
+This package is interoperable with NaCl: http://nacl.cr.yp.to/secretbox.html.
+*/
+package secretbox // import "golang.org/x/crypto/nacl/secretbox"
+
+import (
+ "golang.org/x/crypto/poly1305"
+ "golang.org/x/crypto/salsa20/salsa"
+)
+
+// Overhead is the number of bytes of overhead when boxing a message.
+const Overhead = poly1305.TagSize
+
+// setup produces a sub-key and Salsa20 counter given a nonce and key.
+func setup(subKey *[32]byte, counter *[16]byte, nonce *[24]byte, key *[32]byte) {
+ // We use XSalsa20 for encryption so first we need to generate a
+ // key and nonce with HSalsa20.
+ var hNonce [16]byte
+ copy(hNonce[:], nonce[:])
+ salsa.HSalsa20(subKey, &hNonce, key, &salsa.Sigma)
+
+ // The final 8 bytes of the original nonce form the new nonce.
+ copy(counter[:], nonce[16:])
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// Seal appends an encrypted and authenticated copy of message to out, which
+// must not overlap message. The key and nonce pair must be unique for each
+// distinct message and the output will be Overhead bytes longer than message.
+func Seal(out, message []byte, nonce *[24]byte, key *[32]byte) []byte {
+ var subKey [32]byte
+ var counter [16]byte
+ setup(&subKey, &counter, nonce, key)
+
+ // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
+ // Salsa20 works with 64-byte blocks, we also generate 32 bytes of
+ // keystream as a side effect.
+ var firstBlock [64]byte
+ salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey)
+
+ var poly1305Key [32]byte
+ copy(poly1305Key[:], firstBlock[:])
+
+ ret, out := sliceForAppend(out, len(message)+poly1305.TagSize)
+
+ // We XOR up to 32 bytes of message with the keystream generated from
+ // the first block.
+ firstMessageBlock := message
+ if len(firstMessageBlock) > 32 {
+ firstMessageBlock = firstMessageBlock[:32]
+ }
+
+ tagOut := out
+ out = out[poly1305.TagSize:]
+ for i, x := range firstMessageBlock {
+ out[i] = firstBlock[32+i] ^ x
+ }
+ message = message[len(firstMessageBlock):]
+ ciphertext := out
+ out = out[len(firstMessageBlock):]
+
+ // Now encrypt the rest.
+ counter[8] = 1
+ salsa.XORKeyStream(out, message, &counter, &subKey)
+
+ var tag [poly1305.TagSize]byte
+ poly1305.Sum(&tag, ciphertext, &poly1305Key)
+ copy(tagOut, tag[:])
+
+ return ret
+}
+
+// Open authenticates and decrypts a box produced by Seal and appends the
+// message to out, which must not overlap box. The output will be Overhead
+// bytes smaller than box.
+func Open(out []byte, box []byte, nonce *[24]byte, key *[32]byte) ([]byte, bool) {
+ if len(box) < Overhead {
+ return nil, false
+ }
+
+ var subKey [32]byte
+ var counter [16]byte
+ setup(&subKey, &counter, nonce, key)
+
+ // The Poly1305 key is generated by encrypting 32 bytes of zeros. Since
+ // Salsa20 works with 64-byte blocks, we also generate 32 bytes of
+ // keystream as a side effect.
+ var firstBlock [64]byte
+ salsa.XORKeyStream(firstBlock[:], firstBlock[:], &counter, &subKey)
+
+ var poly1305Key [32]byte
+ copy(poly1305Key[:], firstBlock[:])
+ var tag [poly1305.TagSize]byte
+ copy(tag[:], box)
+
+ if !poly1305.Verify(&tag, box[poly1305.TagSize:], &poly1305Key) {
+ return nil, false
+ }
+
+ ret, out := sliceForAppend(out, len(box)-Overhead)
+
+ // We XOR up to 32 bytes of box with the keystream generated from
+ // the first block.
+ box = box[Overhead:]
+ firstMessageBlock := box
+ if len(firstMessageBlock) > 32 {
+ firstMessageBlock = firstMessageBlock[:32]
+ }
+ for i, x := range firstMessageBlock {
+ out[i] = firstBlock[32+i] ^ x
+ }
+
+ box = box[len(firstMessageBlock):]
+ out = out[len(firstMessageBlock):]
+
+ // Now decrypt the rest.
+ counter[8] = 1
+ salsa.XORKeyStream(out, box, &counter, &subKey)
+
+ return ret, true
+}
diff --git a/vendor/golang.org/x/crypto/nacl/secretbox/secretbox_test.go b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox_test.go
new file mode 100644
index 000000000..664dc1521
--- /dev/null
+++ b/vendor/golang.org/x/crypto/nacl/secretbox/secretbox_test.go
@@ -0,0 +1,91 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package secretbox
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/hex"
+ "testing"
+)
+
+func TestSealOpen(t *testing.T) {
+ var key [32]byte
+ var nonce [24]byte
+
+ rand.Reader.Read(key[:])
+ rand.Reader.Read(nonce[:])
+
+ var box, opened []byte
+
+ for msgLen := 0; msgLen < 128; msgLen += 17 {
+ message := make([]byte, msgLen)
+ rand.Reader.Read(message)
+
+ box = Seal(box[:0], message, &nonce, &key)
+ var ok bool
+ opened, ok = Open(opened[:0], box, &nonce, &key)
+ if !ok {
+ t.Errorf("%d: failed to open box", msgLen)
+ continue
+ }
+
+ if !bytes.Equal(opened, message) {
+ t.Errorf("%d: got %x, expected %x", msgLen, opened, message)
+ continue
+ }
+ }
+
+ for i := range box {
+ box[i] ^= 0x20
+ _, ok := Open(opened[:0], box, &nonce, &key)
+ if ok {
+ t.Errorf("box was opened after corrupting byte %d", i)
+ }
+ box[i] ^= 0x20
+ }
+}
+
+func TestSecretBox(t *testing.T) {
+ var key [32]byte
+ var nonce [24]byte
+ var message [64]byte
+
+ for i := range key[:] {
+ key[i] = 1
+ }
+ for i := range nonce[:] {
+ nonce[i] = 2
+ }
+ for i := range message[:] {
+ message[i] = 3
+ }
+
+ box := Seal(nil, message[:], &nonce, &key)
+ // expected was generated using the C implementation of NaCl.
+ expected, _ := hex.DecodeString("8442bc313f4626f1359e3b50122b6ce6fe66ddfe7d39d14e637eb4fd5b45beadab55198df6ab5368439792a23c87db70acb6156dc5ef957ac04f6276cf6093b84be77ff0849cc33e34b7254d5a8f65ad")
+
+ if !bytes.Equal(box, expected) {
+ t.Fatalf("box didn't match, got\n%x\n, expected\n%x", box, expected)
+ }
+}
+
+func TestAppend(t *testing.T) {
+ var key [32]byte
+ var nonce [24]byte
+ var message [8]byte
+
+ out := make([]byte, 4)
+ box := Seal(out, message[:], &nonce, &key)
+ if !bytes.Equal(box[:4], out[:4]) {
+ t.Fatalf("Seal didn't correctly append")
+ }
+
+ out = make([]byte, 4, 100)
+ box = Seal(out, message[:], &nonce, &key)
+ if !bytes.Equal(box[:4], out[:4]) {
+ t.Fatalf("Seal didn't correctly append with sufficient capacity.")
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ocsp/ocsp.go b/vendor/golang.org/x/crypto/ocsp/ocsp.go
new file mode 100644
index 000000000..6bfbd5da9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ocsp/ocsp.go
@@ -0,0 +1,673 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ocsp parses OCSP responses as specified in RFC 2560. OCSP responses
+// are signed messages attesting to the validity of a certificate for a small
+// period of time. This is used to manage revocation for X.509 certificates.
+package ocsp // import "golang.org/x/crypto/ocsp"
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+ "math/big"
+ "strconv"
+ "time"
+)
+
+var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
+
+// ResponseStatus contains the result of an OCSP request. See
+// https://tools.ietf.org/html/rfc6960#section-2.3
+type ResponseStatus int
+
+const (
+ Success ResponseStatus = 0
+ Malformed ResponseStatus = 1
+ InternalError ResponseStatus = 2
+ TryLater ResponseStatus = 3
+ // Status code four is ununsed in OCSP. See
+ // https://tools.ietf.org/html/rfc6960#section-4.2.1
+ SignatureRequired ResponseStatus = 5
+ Unauthorized ResponseStatus = 6
+)
+
+func (r ResponseStatus) String() string {
+ switch r {
+ case Success:
+ return "success"
+ case Malformed:
+ return "malformed"
+ case InternalError:
+ return "internal error"
+ case TryLater:
+ return "try later"
+ case SignatureRequired:
+ return "signature required"
+ case Unauthorized:
+ return "unauthorized"
+ default:
+ return "unknown OCSP status: " + strconv.Itoa(int(r))
+ }
+}
+
+// ResponseError is an error that may be returned by ParseResponse to indicate
+// that the response itself is an error, not just that its indicating that a
+// certificate is revoked, unknown, etc.
+type ResponseError struct {
+ Status ResponseStatus
+}
+
+func (r ResponseError) Error() string {
+ return "ocsp: error from server: " + r.Status.String()
+}
+
+// These are internal structures that reflect the ASN.1 structure of an OCSP
+// response. See RFC 2560, section 4.2.
+
+type certID struct {
+ HashAlgorithm pkix.AlgorithmIdentifier
+ NameHash []byte
+ IssuerKeyHash []byte
+ SerialNumber *big.Int
+}
+
+// https://tools.ietf.org/html/rfc2560#section-4.1.1
+type ocspRequest struct {
+ TBSRequest tbsRequest
+}
+
+type tbsRequest struct {
+ Version int `asn1:"explicit,tag:0,default:0,optional"`
+ RequestorName pkix.RDNSequence `asn1:"explicit,tag:1,optional"`
+ RequestList []request
+}
+
+type request struct {
+ Cert certID
+}
+
+type responseASN1 struct {
+ Status asn1.Enumerated
+ Response responseBytes `asn1:"explicit,tag:0,optional"`
+}
+
+type responseBytes struct {
+ ResponseType asn1.ObjectIdentifier
+ Response []byte
+}
+
+type basicResponse struct {
+ TBSResponseData responseData
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ Signature asn1.BitString
+ Certificates []asn1.RawValue `asn1:"explicit,tag:0,optional"`
+}
+
+type responseData struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,default:1,explicit,tag:0"`
+ RawResponderName asn1.RawValue `asn1:"optional,explicit,tag:1"`
+ KeyHash []byte `asn1:"optional,explicit,tag:2"`
+ ProducedAt time.Time `asn1:"generalized"`
+ Responses []singleResponse
+}
+
+type singleResponse struct {
+ CertID certID
+ Good asn1.Flag `asn1:"tag:0,optional"`
+ Revoked revokedInfo `asn1:"tag:1,optional"`
+ Unknown asn1.Flag `asn1:"tag:2,optional"`
+ ThisUpdate time.Time `asn1:"generalized"`
+ NextUpdate time.Time `asn1:"generalized,explicit,tag:0,optional"`
+ SingleExtensions []pkix.Extension `asn1:"explicit,tag:1,optional"`
+}
+
+type revokedInfo struct {
+ RevocationTime time.Time `asn1:"generalized"`
+ Reason asn1.Enumerated `asn1:"explicit,tag:0,optional"`
+}
+
+var (
+ oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
+ oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
+ oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
+ oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
+ oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
+ oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+ oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
+ oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
+ oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
+ oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
+ oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
+ oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
+)
+
+var hashOIDs = map[crypto.Hash]asn1.ObjectIdentifier{
+ crypto.SHA1: asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}),
+ crypto.SHA256: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1}),
+ crypto.SHA384: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 2}),
+ crypto.SHA512: asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 3}),
+}
+
+// TODO(rlb): This is also from crypto/x509, so same comment as AGL's below
+var signatureAlgorithmDetails = []struct {
+ algo x509.SignatureAlgorithm
+ oid asn1.ObjectIdentifier
+ pubKeyAlgo x509.PublicKeyAlgorithm
+ hash crypto.Hash
+}{
+ {x509.MD2WithRSA, oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
+ {x509.MD5WithRSA, oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
+ {x509.SHA1WithRSA, oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
+ {x509.SHA256WithRSA, oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
+ {x509.SHA384WithRSA, oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
+ {x509.SHA512WithRSA, oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
+ {x509.DSAWithSHA1, oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
+ {x509.DSAWithSHA256, oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
+ {x509.ECDSAWithSHA1, oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
+ {x509.ECDSAWithSHA256, oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
+ {x509.ECDSAWithSHA384, oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
+ {x509.ECDSAWithSHA512, oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
+}
+
+// TODO(rlb): This is also from crypto/x509, so same comment as AGL's below
+func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+ var pubType x509.PublicKeyAlgorithm
+
+ switch pub := pub.(type) {
+ case *rsa.PublicKey:
+ pubType = x509.RSA
+ hashFunc = crypto.SHA256
+ sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+ sigAlgo.Parameters = asn1.RawValue{
+ Tag: 5,
+ }
+
+ case *ecdsa.PublicKey:
+ pubType = x509.ECDSA
+
+ switch pub.Curve {
+ case elliptic.P224(), elliptic.P256():
+ hashFunc = crypto.SHA256
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+ case elliptic.P384():
+ hashFunc = crypto.SHA384
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+ case elliptic.P521():
+ hashFunc = crypto.SHA512
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+ default:
+ err = errors.New("x509: unknown elliptic curve")
+ }
+
+ default:
+ err = errors.New("x509: only RSA and ECDSA keys supported")
+ }
+
+ if err != nil {
+ return
+ }
+
+ if requestedSigAlgo == 0 {
+ return
+ }
+
+ found := false
+ for _, details := range signatureAlgorithmDetails {
+ if details.algo == requestedSigAlgo {
+ if details.pubKeyAlgo != pubType {
+ err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
+ return
+ }
+ sigAlgo.Algorithm, hashFunc = details.oid, details.hash
+ if hashFunc == 0 {
+ err = errors.New("x509: cannot sign with hash function requested")
+ return
+ }
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ err = errors.New("x509: unknown SignatureAlgorithm")
+ }
+
+ return
+}
+
+// TODO(agl): this is taken from crypto/x509 and so should probably be exported
+// from crypto/x509 or crypto/x509/pkix.
+func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) x509.SignatureAlgorithm {
+ for _, details := range signatureAlgorithmDetails {
+ if oid.Equal(details.oid) {
+ return details.algo
+ }
+ }
+ return x509.UnknownSignatureAlgorithm
+}
+
+// TODO(rlb): This is not taken from crypto/x509, but it's of the same general form.
+func getHashAlgorithmFromOID(target asn1.ObjectIdentifier) crypto.Hash {
+ for hash, oid := range hashOIDs {
+ if oid.Equal(target) {
+ return hash
+ }
+ }
+ return crypto.Hash(0)
+}
+
+// This is the exposed reflection of the internal OCSP structures.
+
+// The status values that can be expressed in OCSP. See RFC 6960.
+const (
+ // Good means that the certificate is valid.
+ Good = iota
+ // Revoked means that the certificate has been deliberately revoked.
+ Revoked
+ // Unknown means that the OCSP responder doesn't know about the certificate.
+ Unknown
+ // ServerFailed is unused and was never used (see
+ // https://go-review.googlesource.com/#/c/18944). ParseResponse will
+ // return a ResponseError when an error response is parsed.
+ ServerFailed
+)
+
+// The enumerated reasons for revoking a certificate. See RFC 5280.
+const (
+ Unspecified = iota
+ KeyCompromise = iota
+ CACompromise = iota
+ AffiliationChanged = iota
+ Superseded = iota
+ CessationOfOperation = iota
+ CertificateHold = iota
+ _ = iota
+ RemoveFromCRL = iota
+ PrivilegeWithdrawn = iota
+ AACompromise = iota
+)
+
+// Request represents an OCSP request. See RFC 6960.
+type Request struct {
+ HashAlgorithm crypto.Hash
+ IssuerNameHash []byte
+ IssuerKeyHash []byte
+ SerialNumber *big.Int
+}
+
+// Response represents an OCSP response containing a single SingleResponse. See
+// RFC 6960.
+type Response struct {
+ // Status is one of {Good, Revoked, Unknown}
+ Status int
+ SerialNumber *big.Int
+ ProducedAt, ThisUpdate, NextUpdate, RevokedAt time.Time
+ RevocationReason int
+ Certificate *x509.Certificate
+ // TBSResponseData contains the raw bytes of the signed response. If
+ // Certificate is nil then this can be used to verify Signature.
+ TBSResponseData []byte
+ Signature []byte
+ SignatureAlgorithm x509.SignatureAlgorithm
+
+ // Extensions contains raw X.509 extensions from the singleExtensions field
+ // of the OCSP response. When parsing certificates, this can be used to
+ // extract non-critical extensions that are not parsed by this package. When
+ // marshaling OCSP responses, the Extensions field is ignored, see
+ // ExtraExtensions.
+ Extensions []pkix.Extension
+
+ // ExtraExtensions contains extensions to be copied, raw, into any marshaled
+ // OCSP response (in the singleExtensions field). Values override any
+ // extensions that would otherwise be produced based on the other fields. The
+ // ExtraExtensions field is not populated when parsing certificates, see
+ // Extensions.
+ ExtraExtensions []pkix.Extension
+}
+
+// These are pre-serialized error responses for the various non-success codes
+// defined by OCSP. The Unauthorized code in particular can be used by an OCSP
+// responder that supports only pre-signed responses as a response to requests
+// for certificates with unknown status. See RFC 5019.
+var (
+ MalformedRequestErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x01}
+ InternalErrorErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x02}
+ TryLaterErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x03}
+ SigRequredErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x05}
+ UnauthorizedErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x06}
+)
+
+// CheckSignatureFrom checks that the signature in resp is a valid signature
+// from issuer. This should only be used if resp.Certificate is nil. Otherwise,
+// the OCSP response contained an intermediate certificate that created the
+// signature. That signature is checked by ParseResponse and only
+// resp.Certificate remains to be validated.
+func (resp *Response) CheckSignatureFrom(issuer *x509.Certificate) error {
+ return issuer.CheckSignature(resp.SignatureAlgorithm, resp.TBSResponseData, resp.Signature)
+}
+
+// ParseError results from an invalid OCSP response.
+type ParseError string
+
+func (p ParseError) Error() string {
+ return string(p)
+}
+
+// ParseRequest parses an OCSP request in DER form. It only supports
+// requests for a single certificate. Signed requests are not supported.
+// If a request includes a signature, it will result in a ParseError.
+func ParseRequest(bytes []byte) (*Request, error) {
+ var req ocspRequest
+ rest, err := asn1.Unmarshal(bytes, &req)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, ParseError("trailing data in OCSP request")
+ }
+
+ if len(req.TBSRequest.RequestList) == 0 {
+ return nil, ParseError("OCSP request contains no request body")
+ }
+ innerRequest := req.TBSRequest.RequestList[0]
+
+ hashFunc := getHashAlgorithmFromOID(innerRequest.Cert.HashAlgorithm.Algorithm)
+ if hashFunc == crypto.Hash(0) {
+ return nil, ParseError("OCSP request uses unknown hash function")
+ }
+
+ return &Request{
+ HashAlgorithm: hashFunc,
+ IssuerNameHash: innerRequest.Cert.NameHash,
+ IssuerKeyHash: innerRequest.Cert.IssuerKeyHash,
+ SerialNumber: innerRequest.Cert.SerialNumber,
+ }, nil
+}
+
+// ParseResponse parses an OCSP response in DER form. It only supports
+// responses for a single certificate. If the response contains a certificate
+// then the signature over the response is checked. If issuer is not nil then
+// it will be used to validate the signature or embedded certificate.
+//
+// Invalid signatures or parse failures will result in a ParseError. Error
+// responses will result in a ResponseError.
+func ParseResponse(bytes []byte, issuer *x509.Certificate) (*Response, error) {
+ var resp responseASN1
+ rest, err := asn1.Unmarshal(bytes, &resp)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, ParseError("trailing data in OCSP response")
+ }
+
+ if status := ResponseStatus(resp.Status); status != Success {
+ return nil, ResponseError{status}
+ }
+
+ if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
+ return nil, ParseError("bad OCSP response type")
+ }
+
+ var basicResp basicResponse
+ rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(basicResp.Certificates) > 1 {
+ return nil, ParseError("OCSP response contains bad number of certificates")
+ }
+
+ if len(basicResp.TBSResponseData.Responses) != 1 {
+ return nil, ParseError("OCSP response contains bad number of responses")
+ }
+
+ ret := &Response{
+ TBSResponseData: basicResp.TBSResponseData.Raw,
+ Signature: basicResp.Signature.RightAlign(),
+ SignatureAlgorithm: getSignatureAlgorithmFromOID(basicResp.SignatureAlgorithm.Algorithm),
+ }
+
+ if len(basicResp.Certificates) > 0 {
+ ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := ret.CheckSignatureFrom(ret.Certificate); err != nil {
+ return nil, ParseError("bad OCSP signature")
+ }
+
+ if issuer != nil {
+ if err := issuer.CheckSignature(ret.Certificate.SignatureAlgorithm, ret.Certificate.RawTBSCertificate, ret.Certificate.Signature); err != nil {
+ return nil, ParseError("bad signature on embedded certificate")
+ }
+ }
+ } else if issuer != nil {
+ if err := ret.CheckSignatureFrom(issuer); err != nil {
+ return nil, ParseError("bad OCSP signature")
+ }
+ }
+
+ r := basicResp.TBSResponseData.Responses[0]
+
+ for _, ext := range r.SingleExtensions {
+ if ext.Critical {
+ return nil, ParseError("unsupported critical extension")
+ }
+ }
+ ret.Extensions = r.SingleExtensions
+
+ ret.SerialNumber = r.CertID.SerialNumber
+
+ switch {
+ case bool(r.Good):
+ ret.Status = Good
+ case bool(r.Unknown):
+ ret.Status = Unknown
+ default:
+ ret.Status = Revoked
+ ret.RevokedAt = r.Revoked.RevocationTime
+ ret.RevocationReason = int(r.Revoked.Reason)
+ }
+
+ ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
+ ret.ThisUpdate = r.ThisUpdate
+ ret.NextUpdate = r.NextUpdate
+
+ return ret, nil
+}
+
+// RequestOptions contains options for constructing OCSP requests.
+type RequestOptions struct {
+ // Hash contains the hash function that should be used when
+ // constructing the OCSP request. If zero, SHA-1 will be used.
+ Hash crypto.Hash
+}
+
+func (opts *RequestOptions) hash() crypto.Hash {
+ if opts == nil || opts.Hash == 0 {
+ // SHA-1 is nearly universally used in OCSP.
+ return crypto.SHA1
+ }
+ return opts.Hash
+}
+
+// CreateRequest returns a DER-encoded, OCSP request for the status of cert. If
+// opts is nil then sensible defaults are used.
+func CreateRequest(cert, issuer *x509.Certificate, opts *RequestOptions) ([]byte, error) {
+ hashFunc := opts.hash()
+
+ // OCSP seems to be the only place where these raw hash identifiers are
+ // used. I took the following from
+ // http://msdn.microsoft.com/en-us/library/ff635603.aspx
+ var hashOID asn1.ObjectIdentifier
+ hashOID, ok := hashOIDs[hashFunc]
+ if !ok {
+ return nil, x509.ErrUnsupportedAlgorithm
+ }
+
+ if !hashFunc.Available() {
+ return nil, x509.ErrUnsupportedAlgorithm
+ }
+ h := opts.hash().New()
+
+ var publicKeyInfo struct {
+ Algorithm pkix.AlgorithmIdentifier
+ PublicKey asn1.BitString
+ }
+ if _, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo); err != nil {
+ return nil, err
+ }
+
+ h.Write(publicKeyInfo.PublicKey.RightAlign())
+ issuerKeyHash := h.Sum(nil)
+
+ h.Reset()
+ h.Write(issuer.RawSubject)
+ issuerNameHash := h.Sum(nil)
+
+ return asn1.Marshal(ocspRequest{
+ tbsRequest{
+ Version: 0,
+ RequestList: []request{
+ {
+ Cert: certID{
+ pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */},
+ },
+ issuerNameHash,
+ issuerKeyHash,
+ cert.SerialNumber,
+ },
+ },
+ },
+ },
+ })
+}
+
+// CreateResponse returns a DER-encoded OCSP response with the specified contents.
+// The fields in the response are populated as follows:
+//
+// The responder cert is used to populate the ResponderName field, and the certificate
+// itself is provided alongside the OCSP response signature.
+//
+// The issuer cert is used to puplate the IssuerNameHash and IssuerKeyHash fields.
+// (SHA-1 is used for the hash function; this is not configurable.)
+//
+// The template is used to populate the SerialNumber, RevocationStatus, RevokedAt,
+// RevocationReason, ThisUpdate, and NextUpdate fields.
+//
+// The ProducedAt date is automatically set to the current date, to the nearest minute.
+func CreateResponse(issuer, responderCert *x509.Certificate, template Response, priv crypto.Signer) ([]byte, error) {
+ var publicKeyInfo struct {
+ Algorithm pkix.AlgorithmIdentifier
+ PublicKey asn1.BitString
+ }
+ if _, err := asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo); err != nil {
+ return nil, err
+ }
+
+ h := sha1.New()
+ h.Write(publicKeyInfo.PublicKey.RightAlign())
+ issuerKeyHash := h.Sum(nil)
+
+ h.Reset()
+ h.Write(issuer.RawSubject)
+ issuerNameHash := h.Sum(nil)
+
+ innerResponse := singleResponse{
+ CertID: certID{
+ HashAlgorithm: pkix.AlgorithmIdentifier{
+ Algorithm: hashOIDs[crypto.SHA1],
+ Parameters: asn1.RawValue{Tag: 5 /* ASN.1 NULL */},
+ },
+ NameHash: issuerNameHash,
+ IssuerKeyHash: issuerKeyHash,
+ SerialNumber: template.SerialNumber,
+ },
+ ThisUpdate: template.ThisUpdate.UTC(),
+ NextUpdate: template.NextUpdate.UTC(),
+ SingleExtensions: template.ExtraExtensions,
+ }
+
+ switch template.Status {
+ case Good:
+ innerResponse.Good = true
+ case Unknown:
+ innerResponse.Unknown = true
+ case Revoked:
+ innerResponse.Revoked = revokedInfo{
+ RevocationTime: template.RevokedAt.UTC(),
+ Reason: asn1.Enumerated(template.RevocationReason),
+ }
+ }
+
+ responderName := asn1.RawValue{
+ Class: 2, // context-specific
+ Tag: 1, // explicit tag
+ IsCompound: true,
+ Bytes: responderCert.RawSubject,
+ }
+ tbsResponseData := responseData{
+ Version: 0,
+ RawResponderName: responderName,
+ ProducedAt: time.Now().Truncate(time.Minute).UTC(),
+ Responses: []singleResponse{innerResponse},
+ }
+
+ tbsResponseDataDER, err := asn1.Marshal(tbsResponseData)
+ if err != nil {
+ return nil, err
+ }
+
+ hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+
+ responseHash := hashFunc.New()
+ responseHash.Write(tbsResponseDataDER)
+ signature, err := priv.Sign(rand.Reader, responseHash.Sum(nil), hashFunc)
+ if err != nil {
+ return nil, err
+ }
+
+ response := basicResponse{
+ TBSResponseData: tbsResponseData,
+ SignatureAlgorithm: signatureAlgorithm,
+ Signature: asn1.BitString{
+ Bytes: signature,
+ BitLength: 8 * len(signature),
+ },
+ }
+ if template.Certificate != nil {
+ response.Certificates = []asn1.RawValue{
+ asn1.RawValue{FullBytes: template.Certificate.Raw},
+ }
+ }
+ responseDER, err := asn1.Marshal(response)
+ if err != nil {
+ return nil, err
+ }
+
+ return asn1.Marshal(responseASN1{
+ Status: asn1.Enumerated(Success),
+ Response: responseBytes{
+ ResponseType: idPKIXOCSPBasic,
+ Response: responseDER,
+ },
+ })
+}
diff --git a/vendor/golang.org/x/crypto/ocsp/ocsp_test.go b/vendor/golang.org/x/crypto/ocsp/ocsp_test.go
new file mode 100644
index 000000000..338684973
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ocsp/ocsp_test.go
@@ -0,0 +1,584 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ocsp
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/sha1"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/hex"
+ "math/big"
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestOCSPDecode(t *testing.T) {
+ responseBytes, _ := hex.DecodeString(ocspResponseHex)
+ resp, err := ParseResponse(responseBytes, nil)
+ if err != nil {
+ t.Error(err)
+ }
+
+ expected := Response{
+ Status: Good,
+ SerialNumber: big.NewInt(0x1d0fa),
+ RevocationReason: Unspecified,
+ ThisUpdate: time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC),
+ NextUpdate: time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC),
+ }
+
+ if !reflect.DeepEqual(resp.ThisUpdate, expected.ThisUpdate) {
+ t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
+ }
+
+ if !reflect.DeepEqual(resp.NextUpdate, expected.NextUpdate) {
+ t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
+ }
+
+ if resp.Status != expected.Status {
+ t.Errorf("resp.Status: got %d, want %d", resp.Status, expected.Status)
+ }
+
+ if resp.SerialNumber.Cmp(expected.SerialNumber) != 0 {
+ t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, expected.SerialNumber)
+ }
+
+ if resp.RevocationReason != expected.RevocationReason {
+ t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
+ }
+}
+
+func TestOCSPDecodeWithoutCert(t *testing.T) {
+ responseBytes, _ := hex.DecodeString(ocspResponseWithoutCertHex)
+ _, err := ParseResponse(responseBytes, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestOCSPDecodeWithExtensions(t *testing.T) {
+ responseBytes, _ := hex.DecodeString(ocspResponseWithCriticalExtensionHex)
+ _, err := ParseResponse(responseBytes, nil)
+ if err == nil {
+ t.Error(err)
+ }
+
+ responseBytes, _ = hex.DecodeString(ocspResponseWithExtensionHex)
+ response, err := ParseResponse(responseBytes, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(response.Extensions) != 1 {
+ t.Errorf("len(response.Extensions): got %v, want %v", len(response.Extensions), 1)
+ }
+
+ extensionBytes := response.Extensions[0].Value
+ expectedBytes, _ := hex.DecodeString(ocspExtensionValueHex)
+ if !bytes.Equal(extensionBytes, expectedBytes) {
+ t.Errorf("response.Extensions[0]: got %x, want %x", extensionBytes, expectedBytes)
+ }
+}
+
+func TestOCSPSignature(t *testing.T) {
+ issuerCert, _ := hex.DecodeString(startComHex)
+ issuer, err := x509.ParseCertificate(issuerCert)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ response, _ := hex.DecodeString(ocspResponseHex)
+ if _, err := ParseResponse(response, issuer); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestOCSPRequest(t *testing.T) {
+ leafCert, _ := hex.DecodeString(leafCertHex)
+ cert, err := x509.ParseCertificate(leafCert)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ issuerCert, _ := hex.DecodeString(issuerCertHex)
+ issuer, err := x509.ParseCertificate(issuerCert)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ request, err := CreateRequest(cert, issuer, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ expectedBytes, _ := hex.DecodeString(ocspRequestHex)
+ if !bytes.Equal(request, expectedBytes) {
+ t.Errorf("request: got %x, wanted %x", request, expectedBytes)
+ }
+
+ decodedRequest, err := ParseRequest(expectedBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if decodedRequest.HashAlgorithm != crypto.SHA1 {
+ t.Errorf("request.HashAlgorithm: got %v, want %v", decodedRequest.HashAlgorithm, crypto.SHA1)
+ }
+
+ var publicKeyInfo struct {
+ Algorithm pkix.AlgorithmIdentifier
+ PublicKey asn1.BitString
+ }
+ _, err = asn1.Unmarshal(issuer.RawSubjectPublicKeyInfo, &publicKeyInfo)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ h := sha1.New()
+ h.Write(publicKeyInfo.PublicKey.RightAlign())
+ issuerKeyHash := h.Sum(nil)
+
+ h.Reset()
+ h.Write(issuer.RawSubject)
+ issuerNameHash := h.Sum(nil)
+
+ if got := decodedRequest.IssuerKeyHash; !bytes.Equal(got, issuerKeyHash) {
+ t.Errorf("request.IssuerKeyHash: got %x, want %x", got, issuerKeyHash)
+ }
+
+ if got := decodedRequest.IssuerNameHash; !bytes.Equal(got, issuerNameHash) {
+ t.Errorf("request.IssuerKeyHash: got %x, want %x", got, issuerNameHash)
+ }
+
+ if got := decodedRequest.SerialNumber; got.Cmp(cert.SerialNumber) != 0 {
+ t.Errorf("request.SerialNumber: got %x, want %x", got, cert.SerialNumber)
+ }
+}
+
+func TestOCSPResponse(t *testing.T) {
+ leafCert, _ := hex.DecodeString(leafCertHex)
+ leaf, err := x509.ParseCertificate(leafCert)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ issuerCert, _ := hex.DecodeString(issuerCertHex)
+ issuer, err := x509.ParseCertificate(issuerCert)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ responderCert, _ := hex.DecodeString(responderCertHex)
+ responder, err := x509.ParseCertificate(responderCert)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ responderPrivateKeyDER, _ := hex.DecodeString(responderPrivateKeyHex)
+ responderPrivateKey, err := x509.ParsePKCS1PrivateKey(responderPrivateKeyDER)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ extensionBytes, _ := hex.DecodeString(ocspExtensionValueHex)
+ extensions := []pkix.Extension{
+ pkix.Extension{
+ Id: ocspExtensionOID,
+ Critical: false,
+ Value: extensionBytes,
+ },
+ }
+
+ producedAt := time.Now().Truncate(time.Minute)
+ thisUpdate := time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC)
+ nextUpdate := time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC)
+ template := Response{
+ Status: Revoked,
+ SerialNumber: leaf.SerialNumber,
+ ThisUpdate: thisUpdate,
+ NextUpdate: nextUpdate,
+ RevokedAt: thisUpdate,
+ RevocationReason: KeyCompromise,
+ Certificate: responder,
+ ExtraExtensions: extensions,
+ }
+
+ responseBytes, err := CreateResponse(issuer, responder, template, responderPrivateKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err := ParseResponse(responseBytes, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !reflect.DeepEqual(resp.ThisUpdate, template.ThisUpdate) {
+ t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, template.ThisUpdate)
+ }
+
+ if !reflect.DeepEqual(resp.NextUpdate, template.NextUpdate) {
+ t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, template.NextUpdate)
+ }
+
+ if !reflect.DeepEqual(resp.RevokedAt, template.RevokedAt) {
+ t.Errorf("resp.RevokedAt: got %d, want %d", resp.RevokedAt, template.RevokedAt)
+ }
+
+ if !reflect.DeepEqual(resp.Extensions, template.ExtraExtensions) {
+ t.Errorf("resp.Extensions: got %v, want %v", resp.Extensions, template.ExtraExtensions)
+ }
+
+ if !resp.ProducedAt.Equal(producedAt) {
+ t.Errorf("resp.ProducedAt: got %d, want %d", resp.ProducedAt, producedAt)
+ }
+
+ if resp.Status != template.Status {
+ t.Errorf("resp.Status: got %d, want %d", resp.Status, template.Status)
+ }
+
+ if resp.SerialNumber.Cmp(template.SerialNumber) != 0 {
+ t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, template.SerialNumber)
+ }
+
+ if resp.RevocationReason != template.RevocationReason {
+ t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, template.RevocationReason)
+ }
+}
+
+func TestErrorResponse(t *testing.T) {
+ responseBytes, _ := hex.DecodeString(errorResponseHex)
+ _, err := ParseResponse(responseBytes, nil)
+
+ respErr, ok := err.(ResponseError)
+ if !ok {
+ t.Fatalf("expected ResponseError from ParseResponse but got %#v", err)
+ }
+ if respErr.Status != Malformed {
+ t.Fatalf("expected Malformed status from ParseResponse but got %d", respErr.Status)
+ }
+}
+
+// This OCSP response was taken from Thawte's public OCSP responder.
+// To recreate:
+// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
+// Copy and paste the first certificate into /tmp/cert.crt and the second into
+// /tmp/intermediate.crt
+// $ openssl ocsp -issuer /tmp/intermediate.crt -cert /tmp/cert.crt -url http://ocsp.thawte.com -resp_text -respout /tmp/ocsp.der
+// Then hex encode the result:
+// $ python -c 'print file("/tmp/ocsp.der", "r").read().encode("hex")'
+
+const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048206a23082069e3081" +
+ "c9a14e304c310b300906035504061302494c31163014060355040a130d5374617274436f" +
+ "6d204c74642e312530230603550403131c5374617274436f6d20436c6173732031204f43" +
+ "5350205369676e6572180f32303130303730373137333531375a30663064303c30090605" +
+ "2b0e03021a050004146568874f40750f016a3475625e1f5c93e5a26d580414eb4234d098" +
+ "b0ab9ff41b6b08f7cc642eef0e2c45020301d0fa8000180f323031303037303731353031" +
+ "30355aa011180f32303130303730373138333531375a300d06092a864886f70d01010505" +
+ "000382010100ab557ff070d1d7cebbb5f0ec91a15c3fed22eb2e1b8244f1b84545f013a4" +
+ "fb46214c5e3fbfbebb8a56acc2b9db19f68fd3c3201046b3824d5ba689f99864328710cb" +
+ "467195eb37d84f539e49f859316b32964dc3e47e36814ce94d6c56dd02733b1d0802f7ff" +
+ "4eebdbbd2927dcf580f16cbc290f91e81b53cb365e7223f1d6e20a88ea064104875e0145" +
+ "672b20fc14829d51ca122f5f5d77d3ad6c83889c55c7dc43680ba2fe3cef8b05dbcabdc0" +
+ "d3e09aaf9725597f8c858c2fa38c0d6aed2e6318194420dd1a1137445d13e1c97ab47896" +
+ "17a4e08925f46f867b72e3a4dc1f08cb870b2b0717f7207faa0ac512e628a029aba7457a" +
+ "e63dcf3281e2162d9349a08204ba308204b6308204b23082039aa003020102020101300d" +
+ "06092a864886f70d010105050030818c310b300906035504061302494c31163014060355" +
+ "040a130d5374617274436f6d204c74642e312b3029060355040b13225365637572652044" +
+ "69676974616c204365727469666963617465205369676e696e6731383036060355040313" +
+ "2f5374617274436f6d20436c6173732031205072696d61727920496e7465726d65646961" +
+ "746520536572766572204341301e170d3037313032353030323330365a170d3132313032" +
+ "333030323330365a304c310b300906035504061302494c31163014060355040a130d5374" +
+ "617274436f6d204c74642e312530230603550403131c5374617274436f6d20436c617373" +
+ "2031204f435350205369676e657230820122300d06092a864886f70d0101010500038201" +
+ "0f003082010a0282010100b9561b4c45318717178084e96e178df2255e18ed8d8ecc7c2b" +
+ "7b51a6c1c2e6bf0aa3603066f132fe10ae97b50e99fa24b83fc53dd2777496387d14e1c3" +
+ "a9b6a4933e2ac12413d085570a95b8147414a0bc007c7bcf222446ef7f1a156d7ea1c577" +
+ "fc5f0facdfd42eb0f5974990cb2f5cefebceef4d1bdc7ae5c1075c5a99a93171f2b0845b" +
+ "4ff0864e973fcfe32f9d7511ff87a3e943410c90a4493a306b6944359340a9ca96f02b66" +
+ "ce67f028df2980a6aaee8d5d5d452b8b0eb93f923cc1e23fcccbdbe7ffcb114d08fa7a6a" +
+ "3c404f825d1a0e715935cf623a8c7b59670014ed0622f6089a9447a7a19010f7fe58f841" +
+ "29a2765ea367824d1c3bb2fda308530203010001a382015c30820158300c0603551d1301" +
+ "01ff04023000300b0603551d0f0404030203a8301e0603551d250417301506082b060105" +
+ "0507030906092b0601050507300105301d0603551d0e0416041445e0a36695414c5dd449" +
+ "bc00e33cdcdbd2343e173081a80603551d230481a030819d8014eb4234d098b0ab9ff41b" +
+ "6b08f7cc642eef0e2c45a18181a47f307d310b300906035504061302494c311630140603" +
+ "55040a130d5374617274436f6d204c74642e312b3029060355040b132253656375726520" +
+ "4469676974616c204365727469666963617465205369676e696e67312930270603550403" +
+ "13205374617274436f6d2043657274696669636174696f6e20417574686f726974798201" +
+ "0a30230603551d12041c301a8618687474703a2f2f7777772e737461727473736c2e636f" +
+ "6d2f302c06096086480186f842010d041f161d5374617274436f6d205265766f63617469" +
+ "6f6e20417574686f72697479300d06092a864886f70d01010505000382010100182d2215" +
+ "8f0fc0291324fa8574c49bb8ff2835085adcbf7b7fc4191c397ab6951328253fffe1e5ec" +
+ "2a7da0d50fca1a404e6968481366939e666c0a6209073eca57973e2fefa9ed1718e8176f" +
+ "1d85527ff522c08db702e3b2b180f1cbff05d98128252cf0f450f7dd2772f4188047f19d" +
+ "c85317366f94bc52d60f453a550af58e308aaab00ced33040b62bf37f5b1ab2a4f7f0f80" +
+ "f763bf4d707bc8841d7ad9385ee2a4244469260b6f2bf085977af9074796048ecc2f9d48" +
+ "a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
+ "6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"
+
+const startComHex = "308206343082041ca003020102020118300d06092a864886f70d0101050500307d310b30" +
+ "0906035504061302494c31163014060355040a130d5374617274436f6d204c74642e312b" +
+ "3029060355040b1322536563757265204469676974616c20436572746966696361746520" +
+ "5369676e696e6731293027060355040313205374617274436f6d20436572746966696361" +
+ "74696f6e20417574686f72697479301e170d3037313032343230353431375a170d313731" +
+ "3032343230353431375a30818c310b300906035504061302494c31163014060355040a13" +
+ "0d5374617274436f6d204c74642e312b3029060355040b13225365637572652044696769" +
+ "74616c204365727469666963617465205369676e696e67313830360603550403132f5374" +
+ "617274436f6d20436c6173732031205072696d61727920496e7465726d65646961746520" +
+ "53657276657220434130820122300d06092a864886f70d01010105000382010f00308201" +
+ "0a0282010100b689c6acef09527807ac9263d0f44418188480561f91aee187fa3250b4d3" +
+ "4706f0e6075f700e10f71dc0ce103634855a0f92ac83c6ac58523fba38e8fce7a724e240" +
+ "a60876c0926e9e2a6d4d3f6e61200adb59ded27d63b33e46fefa215118d7cd30a6ed076e" +
+ "3b7087b4f9faebee823c056f92f7a4dc0a301e9373fe07cad75f809d225852ae06da8b87" +
+ "2369b0e42ad8ea83d2bdf371db705a280faf5a387045123f304dcd3baf17e50fcba0a95d" +
+ "48aab16150cb34cd3c5cc30be810c08c9bf0030362feb26c3e720eee1c432ac9480e5739" +
+ "c43121c810c12c87fe5495521f523c31129b7fe7c0a0a559d5e28f3ef0d5a8e1d77031a9" +
+ "c4b3cfaf6d532f06f4a70203010001a38201ad308201a9300f0603551d130101ff040530" +
+ "030101ff300e0603551d0f0101ff040403020106301d0603551d0e04160414eb4234d098" +
+ "b0ab9ff41b6b08f7cc642eef0e2c45301f0603551d230418301680144e0bef1aa4405ba5" +
+ "17698730ca346843d041aef2306606082b06010505070101045a3058302706082b060105" +
+ "05073001861b687474703a2f2f6f6373702e737461727473736c2e636f6d2f6361302d06" +
+ "082b060105050730028621687474703a2f2f7777772e737461727473736c2e636f6d2f73" +
+ "667363612e637274305b0603551d1f045430523027a025a0238621687474703a2f2f7777" +
+ "772e737461727473736c2e636f6d2f73667363612e63726c3027a025a023862168747470" +
+ "3a2f2f63726c2e737461727473736c2e636f6d2f73667363612e63726c3081800603551d" +
+ "20047930773075060b2b0601040181b5370102013066302e06082b060105050702011622" +
+ "687474703a2f2f7777772e737461727473736c2e636f6d2f706f6c6963792e7064663034" +
+ "06082b060105050702011628687474703a2f2f7777772e737461727473736c2e636f6d2f" +
+ "696e7465726d6564696174652e706466300d06092a864886f70d01010505000382020100" +
+ "2109493ea5886ee00b8b48da314d8ff75657a2e1d36257e9b556f38545753be5501f048b" +
+ "e6a05a3ee700ae85d0fbff200364cbad02e1c69172f8a34dd6dee8cc3fa18aa2e37c37a7" +
+ "c64f8f35d6f4d66e067bdd21d9cf56ffcb302249fe8904f385e5aaf1e71fe875904dddf9" +
+ "46f74234f745580c110d84b0c6da5d3ef9019ee7e1da5595be741c7bfc4d144fac7e5547" +
+ "7d7bf4a50d491e95e8f712c1ccff76a62547d0f37535be97b75816ebaa5c786fec5330af" +
+ "ea044dcca902e3f0b60412f630b1113d904e5664d7dc3c435f7339ef4baf87ebf6fe6888" +
+ "4472ead207c669b0c1a18bef1749d761b145485f3b2021e95bb2ccf4d7e931f50b15613b" +
+ "7a94e3ebd9bc7f94ae6ae3626296a8647cb887f399327e92a252bebbf865cfc9f230fc8b" +
+ "c1c2a696d75f89e15c3480f58f47072fb491bfb1a27e5f4b5ad05b9f248605515a690365" +
+ "434971c5e06f94346bf61bd8a9b04c7e53eb8f48dfca33b548fa364a1a53a6330cd089cd" +
+ "4915cd89313c90c072d7654b52358a461144b93d8e2865a63e799e5c084429adb035112e" +
+ "214eb8d2e7103e5d8483b3c3c2e4d2c6fd094b7409ddf1b3d3193e800da20b19f038e7c5" +
+ "c2afe223db61e29d5c6e2089492e236ab262c145b49faf8ba7f1223bf87de290d07a19fb" +
+ "4a4ce3d27d5f4a8303ed27d6239e6b8db459a2d9ef6c8229dd75193c3f4c108defbb7527" +
+ "d2ae83a7a8ce5ba7"
+
+const ocspResponseWithoutCertHex = "308201d40a0100a08201cd308201c906092b0601050507300101048201ba3082" +
+ "01b630819fa2160414884451ff502a695e2d88f421bad90cf2cecbea7c180f3230313330" +
+ "3631383037323434335a30743072304a300906052b0e03021a0500041448b60d38238df8" +
+ "456e4ee5843ea394111802979f0414884451ff502a695e2d88f421bad90cf2cecbea7c02" +
+ "1100f78b13b946fc9635d8ab49de9d2148218000180f3230313330363138303732343433" +
+ "5aa011180f32303133303632323037323434335a300d06092a864886f70d010105050003" +
+ "82010100103e18b3d297a5e7a6c07a4fc52ac46a15c0eba96f3be17f0ffe84de5b8c8e05" +
+ "5a8f577586a849dc4abd6440eb6fedde4622451e2823c1cbf3558b4e8184959c9fe96eff" +
+ "8bc5f95866c58c6d087519faabfdae37e11d9874f1bc0db292208f645dd848185e4dd38b" +
+ "6a8547dfa7b74d514a8470015719064d35476b95bebb03d4d2845c5ca15202d2784878f2" +
+ "0f904c24f09736f044609e9c271381713400e563023d212db422236440c6f377bbf24b2b" +
+ "9e7dec8698e36a8df68b7592ad3489fb2937afb90eb85d2aa96b81c94c25057dbd4759d9" +
+ "20a1a65c7f0b6427a224b3c98edd96b9b61f706099951188b0289555ad30a216fb774651" +
+ "5a35fca2e054dfa8"
+
+// PKIX nonce extension
+var ocspExtensionOID = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 2}
+var ocspExtensionValueHex = "0403000000"
+
+const ocspResponseWithCriticalExtensionHex = "308204fe0a0100a08204f7308204f306092b0601050507300101048204e4308204e03081" +
+ "dba003020100a11b3019311730150603550403130e4f43535020526573706f6e64657218" +
+ "0f32303136303130343137303130305a3081a53081a23049300906052b0e03021a050004" +
+ "14c0fe0278fc99188891b3f212e9c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b21317" +
+ "7e6f8d157cd4f60210017f77deb3bcbb235d44ccc7dba62e72a116180f32303130303730" +
+ "373135303130355aa0030a0101180f32303130303730373135303130355aa011180f3230" +
+ "3130303730373138333531375aa1193017301506092b06010505073001020101ff040504" +
+ "03000000300d06092a864886f70d01010b0500038201010031c730ca60a7a0d92d8e4010" +
+ "911b469de95b4d27e89de6537552436237967694f76f701cf6b45c932bd308bca4a8d092" +
+ "5c604ba94796903091d9e6c000178e72c1f0a24a277dd262835af5d17d3f9d7869606c9f" +
+ "e7c8e708a41645699895beee38bfa63bb46296683761c5d1d65439b8ab868dc3017c9eeb" +
+ "b70b82dbf3a31c55b457d48bb9e82b335ed49f445042eaf606b06a3e0639824924c89c63" +
+ "eccddfe85e6694314138b2536f5e15e07085d0f6e26d4b2f8244bab0d70de07283ac6384" +
+ "a0501fc3dea7cf0adfd4c7f34871080900e252ddc403e3f0265f2a704af905d3727504ed" +
+ "28f3214a219d898a022463c78439799ca81c8cbafdbcec34ea937cd6a08202ea308202e6" +
+ "308202e2308201caa003020102020101300d06092a864886f70d01010b05003019311730" +
+ "150603550403130e4f43535020526573706f6e646572301e170d31353031333031353530" +
+ "33335a170d3136303133303135353033335a3019311730150603550403130e4f43535020" +
+ "526573706f6e64657230820122300d06092a864886f70d01010105000382010f00308201" +
+ "0a0282010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef1099f0f6616e" +
+ "c5265b56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df1701dc6ccfbc" +
+ "bec75a70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074ffde8a99d5b72" +
+ "3350f0a112076614b12ef79c78991b119453445acf2416ab0046b540db14c9fc0f27b898" +
+ "9ad0f63aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa77e7332971c7d" +
+ "285b6a04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f1290bafd97e6" +
+ "55b1049a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb96222b12ace31" +
+ "a77dcf920334dc94581b0203010001a3353033300e0603551d0f0101ff04040302078030" +
+ "130603551d25040c300a06082b06010505070309300c0603551d130101ff04023000300d" +
+ "06092a864886f70d01010b05000382010100718012761b5063e18f0dc44644d8e6ab8612" +
+ "31c15fd5357805425d82aec1de85bf6d3e30fce205e3e3b8b795bbe52e40a439286d2288" +
+ "9064f4aeeb150359b9425f1da51b3a5c939018555d13ac42c565a0603786a919328f3267" +
+ "09dce52c22ad958ecb7873b9771d1148b1c4be2efe80ba868919fc9f68b6090c2f33c156" +
+ "d67156e42766a50b5d51e79637b7e58af74c2a951b1e642fa7741fec982cc937de37eff5" +
+ "9e2005d5939bfc031589ca143e6e8ab83f40ee08cc20a6b4a95a318352c28d18528dcaf9" +
+ "66705de17afa19d6e8ae91ddf33179d16ebb6ac2c69cae8373d408ebf8c55308be6c04d9" +
+ "3a25439a94299a65a709756c7a3e568be049d5c38839"
+
+const ocspResponseWithExtensionHex = "308204fb0a0100a08204f4308204f006092b0601050507300101048204e1308204dd3081" +
+ "d8a003020100a11b3019311730150603550403130e4f43535020526573706f6e64657218" +
+ "0f32303136303130343136353930305a3081a230819f3049300906052b0e03021a050004" +
+ "14c0fe0278fc99188891b3f212e9c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b21317" +
+ "7e6f8d157cd4f60210017f77deb3bcbb235d44ccc7dba62e72a116180f32303130303730" +
+ "373135303130355aa0030a0101180f32303130303730373135303130355aa011180f3230" +
+ "3130303730373138333531375aa1163014301206092b0601050507300102040504030000" +
+ "00300d06092a864886f70d01010b05000382010100c09a33e0b2324c852421bb83f85ac9" +
+ "9113f5426012bd2d2279a8166e9241d18a33c870894250622ffc7ed0c4601b16d624f90b" +
+ "779265442cdb6868cf40ab304ab4b66e7315ed02cf663b1601d1d4751772b31bc299db23" +
+ "9aebac78ed6797c06ed815a7a8d18d63cfbb609cafb47ec2e89e37db255216eb09307848" +
+ "d01be0a3e943653c78212b96ff524b74c9ec456b17cdfb950cc97645c577b2e09ff41dde" +
+ "b03afb3adaa381cc0f7c1d95663ef22a0f72f2c45613ae8e2b2d1efc96e8463c7d1d8a1d" +
+ "7e3b35df8fe73a301fc3f804b942b2b3afa337ff105fc1462b7b1c1d75eb4566c8665e59" +
+ "f80393b0adbf8004ff6c3327ed34f007cb4a3348a7d55e06e3a08202ea308202e6308202" +
+ "e2308201caa003020102020101300d06092a864886f70d01010b05003019311730150603" +
+ "550403130e4f43535020526573706f6e646572301e170d3135303133303135353033335a" +
+ "170d3136303133303135353033335a3019311730150603550403130e4f43535020526573" +
+ "706f6e64657230820122300d06092a864886f70d01010105000382010f003082010a0282" +
+ "010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef1099f0f6616ec5265b" +
+ "56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df1701dc6ccfbcbec75a" +
+ "70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074ffde8a99d5b723350f0" +
+ "a112076614b12ef79c78991b119453445acf2416ab0046b540db14c9fc0f27b8989ad0f6" +
+ "3aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa77e7332971c7d285b6a" +
+ "04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f1290bafd97e655b104" +
+ "9a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb96222b12ace31a77dcf" +
+ "920334dc94581b0203010001a3353033300e0603551d0f0101ff04040302078030130603" +
+ "551d25040c300a06082b06010505070309300c0603551d130101ff04023000300d06092a" +
+ "864886f70d01010b05000382010100718012761b5063e18f0dc44644d8e6ab861231c15f" +
+ "d5357805425d82aec1de85bf6d3e30fce205e3e3b8b795bbe52e40a439286d22889064f4" +
+ "aeeb150359b9425f1da51b3a5c939018555d13ac42c565a0603786a919328f326709dce5" +
+ "2c22ad958ecb7873b9771d1148b1c4be2efe80ba868919fc9f68b6090c2f33c156d67156" +
+ "e42766a50b5d51e79637b7e58af74c2a951b1e642fa7741fec982cc937de37eff59e2005" +
+ "d5939bfc031589ca143e6e8ab83f40ee08cc20a6b4a95a318352c28d18528dcaf966705d" +
+ "e17afa19d6e8ae91ddf33179d16ebb6ac2c69cae8373d408ebf8c55308be6c04d93a2543" +
+ "9a94299a65a709756c7a3e568be049d5c38839"
+
+const ocspRequestHex = "3051304f304d304b3049300906052b0e03021a05000414c0fe0278fc99188891b3f212e9" +
+ "c7e1b21ab7bfc004140dfc1df0a9e0f01ce7f2b213177e6f8d157cd4f60210017f77deb3" +
+ "bcbb235d44ccc7dba62e72"
+
+const leafCertHex = "308203c830820331a0030201020210017f77deb3bcbb235d44ccc7dba62e72300d06092a" +
+ "864886f70d01010505003081ba311f301d060355040a1316566572695369676e20547275" +
+ "7374204e6574776f726b31173015060355040b130e566572695369676e2c20496e632e31" +
+ "333031060355040b132a566572695369676e20496e7465726e6174696f6e616c20536572" +
+ "766572204341202d20436c617373203331493047060355040b13407777772e7665726973" +
+ "69676e2e636f6d2f43505320496e636f72702e6279205265662e204c494142494c495459" +
+ "204c54442e286329393720566572695369676e301e170d3132303632313030303030305a" +
+ "170d3133313233313233353935395a3068310b3009060355040613025553311330110603" +
+ "550408130a43616c69666f726e6961311230100603550407130950616c6f20416c746f31" +
+ "173015060355040a130e46616365626f6f6b2c20496e632e311730150603550403140e2a" +
+ "2e66616365626f6f6b2e636f6d30819f300d06092a864886f70d010101050003818d0030" +
+ "818902818100ae94b171e2deccc1693e051063240102e0689ae83c39b6b3e74b97d48d7b" +
+ "23689100b0b496ee62f0e6d356bcf4aa0f50643402f5d1766aa972835a7564723f39bbef" +
+ "5290ded9bcdbf9d3d55dfad23aa03dc604c54d29cf1d4b3bdbd1a809cfae47b44c7eae17" +
+ "c5109bee24a9cf4a8d911bb0fd0415ae4c3f430aa12a557e2ae10203010001a382011e30" +
+ "82011a30090603551d130402300030440603551d20043d303b3039060b6086480186f845" +
+ "01071703302a302806082b06010505070201161c68747470733a2f2f7777772e76657269" +
+ "7369676e2e636f6d2f727061303c0603551d1f043530333031a02fa02d862b687474703a" +
+ "2f2f535652496e746c2d63726c2e766572697369676e2e636f6d2f535652496e746c2e63" +
+ "726c301d0603551d250416301406082b0601050507030106082b06010505070302300b06" +
+ "03551d0f0404030205a0303406082b0601050507010104283026302406082b0601050507" +
+ "30018618687474703a2f2f6f6373702e766572697369676e2e636f6d30270603551d1104" +
+ "20301e820e2a2e66616365626f6f6b2e636f6d820c66616365626f6f6b2e636f6d300d06" +
+ "092a864886f70d0101050500038181005b6c2b75f8ed30aa51aad36aba595e555141951f" +
+ "81a53b447910ac1f76ff78fc2781616b58f3122afc1c87010425e9ed43df1a7ba6498060" +
+ "67e2688af03db58c7df4ee03309a6afc247ccb134dc33e54c6bc1d5133a532a73273b1d7" +
+ "9cadc08e7e1a83116d34523340b0305427a21742827c98916698ee7eaf8c3bdd71700817"
+
+const issuerCertHex = "30820383308202eca003020102021046fcebbab4d02f0f926098233f93078f300d06092a" +
+ "864886f70d0101050500305f310b300906035504061302555331173015060355040a130e" +
+ "566572695369676e2c20496e632e31373035060355040b132e436c617373203320507562" +
+ "6c6963205072696d6172792043657274696669636174696f6e20417574686f7269747930" +
+ "1e170d3937303431373030303030305a170d3136313032343233353935395a3081ba311f" +
+ "301d060355040a1316566572695369676e205472757374204e6574776f726b3117301506" +
+ "0355040b130e566572695369676e2c20496e632e31333031060355040b132a5665726953" +
+ "69676e20496e7465726e6174696f6e616c20536572766572204341202d20436c61737320" +
+ "3331493047060355040b13407777772e766572697369676e2e636f6d2f43505320496e63" +
+ "6f72702e6279205265662e204c494142494c495459204c54442e28632939372056657269" +
+ "5369676e30819f300d06092a864886f70d010101050003818d0030818902818100d88280" +
+ "e8d619027d1f85183925a2652be1bfd405d3bce6363baaf04c6c5bb6e7aa3c734555b2f1" +
+ "bdea9742ed9a340a15d4a95cf54025ddd907c132b2756cc4cabba3fe56277143aa63f530" +
+ "3e9328e5faf1093bf3b74d4e39f75c495ab8c11dd3b28afe70309542cbfe2b518b5a3c3a" +
+ "f9224f90b202a7539c4f34e7ab04b27b6f0203010001a381e33081e0300f0603551d1304" +
+ "0830060101ff02010030440603551d20043d303b3039060b6086480186f8450107010130" +
+ "2a302806082b06010505070201161c68747470733a2f2f7777772e766572697369676e2e" +
+ "636f6d2f43505330340603551d25042d302b06082b0601050507030106082b0601050507" +
+ "030206096086480186f8420401060a6086480186f845010801300b0603551d0f04040302" +
+ "0106301106096086480186f842010104040302010630310603551d1f042a30283026a024" +
+ "a0228620687474703a2f2f63726c2e766572697369676e2e636f6d2f706361332e63726c" +
+ "300d06092a864886f70d010105050003818100408e4997968a73dd8e4def3e61b7caa062" +
+ "adf40e0abb753de26ed82cc7bff4b98c369bcaa2d09c724639f6a682036511c4bcbf2da6" +
+ "f5d93b0ab598fab378b91ef22b4c62d5fdb27a1ddf33fd73f9a5d82d8c2aead1fcb028b6" +
+ "e94948134b838a1b487b24f738de6f4154b8ab576b06dfc7a2d4a9f6f136628088f28b75" +
+ "d68071"
+
+// Key and certificate for the OCSP responder were not taken from the Thawte
+// responder, since CreateResponse requires that we have the private key.
+// Instead, they were generated randomly.
+const responderPrivateKeyHex = "308204a40201000282010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef" +
+ "1099f0f6616ec5265b56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df" +
+ "1701dc6ccfbcbec75a70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074f" +
+ "fde8a99d5b723350f0a112076614b12ef79c78991b119453445acf2416ab0046b540db14" +
+ "c9fc0f27b8989ad0f63aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa7" +
+ "7e7332971c7d285b6a04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f" +
+ "1290bafd97e655b1049a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb9" +
+ "6222b12ace31a77dcf920334dc94581b02030100010282010100bcf0b93d7238bda329a8" +
+ "72e7149f61bcb37c154330ccb3f42a85c9002c2e2bdea039d77d8581cd19bed94078794e" +
+ "56293d601547fc4bf6a2f9002fe5772b92b21b254403b403585e3130cc99ccf08f0ef81a" +
+ "575b38f597ba4660448b54f44bfbb97072b5a2bf043bfeca828cf7741d13698e3f38162b" +
+ "679faa646b82abd9a72c5c7d722c5fc577a76d2c2daac588accad18516d1bbad10b0dfa2" +
+ "05cfe246b59e28608a43942e1b71b0c80498075121de5b900d727c31c42c78cf1db5c0aa" +
+ "5b491e10ea4ed5c0962aaf2ae025dd81fa4ce490d9d6b4a4465411d8e542fc88617e5695" +
+ "1aa4fc8ea166f2b4d0eb89ef17f2b206bd5f1014bf8fe0e71fe62f2cccf102818100f2dc" +
+ "ddf878d553286daad68bac4070a82ffec3dc4666a2750f47879eec913f91836f1d976b60" +
+ "daf9356e078446dafab5bd2e489e5d64f8572ba24a4ba4f3729b5e106c4dd831cc2497a7" +
+ "e6c7507df05cb64aeb1bbc81c1e340d58b5964cf39cff84ea30c29ec5d3f005ee1362698" +
+ "07395037955955655292c3e85f6187fa1f9502818100f4a33c102630840705f8c778a47b" +
+ "87e8da31e68809af981ac5e5999cf1551685d761cdf0d6520361b99aebd5777a940fa64d" +
+ "327c09fa63746fbb3247ec73a86edf115f1fe5c83598db803881ade71c33c6e956118345" +
+ "497b98b5e07bb5be75971465ec78f2f9467e1b74956ca9d4c7c3e314e742a72d8b33889c" +
+ "6c093a466cef0281801d3df0d02124766dd0be98349b19eb36a508c4e679e793ba0a8bef" +
+ "4d786888c1e9947078b1ea28938716677b4ad8c5052af12eb73ac194915264a913709a0b" +
+ "7b9f98d4a18edd781a13d49899f91c20dbd8eb2e61d991ba19b5cdc08893f5cb9d39e5a6" +
+ "0629ea16d426244673b1b3ee72bd30e41fac8395acac40077403de5efd028180050731dd" +
+ "d71b1a2b96c8d538ba90bb6b62c8b1c74c03aae9a9f59d21a7a82b0d572ef06fa9c807bf" +
+ "c373d6b30d809c7871df96510c577421d9860c7383fda0919ece19996b3ca13562159193" +
+ "c0c246471e287f975e8e57034e5136aaf44254e2650def3d51292474c515b1588969112e" +
+ "0a85cc77073e9d64d2c2fc497844284b02818100d71d63eabf416cf677401ebf965f8314" +
+ "120b568a57dd3bd9116c629c40dc0c6948bab3a13cc544c31c7da40e76132ef5dd3f7534" +
+ "45a635930c74326ae3df0edd1bfb1523e3aa259873ac7cf1ac31151ec8f37b528c275622" +
+ "48f99b8bed59fd4da2576aa6ee20d93a684900bf907e80c66d6e2261ae15e55284b4ed9d" +
+ "6bdaa059"
+
+const responderCertHex = "308202e2308201caa003020102020101300d06092a864886f70d01010b05003019311730" +
+ "150603550403130e4f43535020526573706f6e646572301e170d31353031333031353530" +
+ "33335a170d3136303133303135353033335a3019311730150603550403130e4f43535020" +
+ "526573706f6e64657230820122300d06092a864886f70d01010105000382010f00308201" +
+ "0a0282010100e8155f2d3e6f2e8d14c62a788bd462f9f844e7a6977c83ef1099f0f6616e" +
+ "c5265b56f356e62c5400f0b06a2e7945a82752c636df32a895152d6074df1701dc6ccfbc" +
+ "bec75a70bd2b55ae2be7e6cad3b5fd4cd5b7790ab401a436d3f5f346074ffde8a99d5b72" +
+ "3350f0a112076614b12ef79c78991b119453445acf2416ab0046b540db14c9fc0f27b898" +
+ "9ad0f63aa4b8aefc91aa8a72160c36307c60fec78a93d3fddf4259902aa77e7332971c7d" +
+ "285b6a04f648993c6922a3e9da9adf5f81508c3228791843e5d49f24db2f1290bafd97e6" +
+ "55b1049a199f652cd603c4fafa330c390b0da78fbbc67e8fa021cbd74eb96222b12ace31" +
+ "a77dcf920334dc94581b0203010001a3353033300e0603551d0f0101ff04040302078030" +
+ "130603551d25040c300a06082b06010505070309300c0603551d130101ff04023000300d" +
+ "06092a864886f70d01010b05000382010100718012761b5063e18f0dc44644d8e6ab8612" +
+ "31c15fd5357805425d82aec1de85bf6d3e30fce205e3e3b8b795bbe52e40a439286d2288" +
+ "9064f4aeeb150359b9425f1da51b3a5c939018555d13ac42c565a0603786a919328f3267" +
+ "09dce52c22ad958ecb7873b9771d1148b1c4be2efe80ba868919fc9f68b6090c2f33c156" +
+ "d67156e42766a50b5d51e79637b7e58af74c2a951b1e642fa7741fec982cc937de37eff5" +
+ "9e2005d5939bfc031589ca143e6e8ab83f40ee08cc20a6b4a95a318352c28d18528dcaf9" +
+ "66705de17afa19d6e8ae91ddf33179d16ebb6ac2c69cae8373d408ebf8c55308be6c04d9" +
+ "3a25439a94299a65a709756c7a3e568be049d5c38839"
+
+const errorResponseHex = "30030a0101"
diff --git a/vendor/golang.org/x/crypto/openpgp/armor/armor.go b/vendor/golang.org/x/crypto/openpgp/armor/armor.go
new file mode 100644
index 000000000..592d18643
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/armor/armor.go
@@ -0,0 +1,219 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package armor implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
+// very similar to PEM except that it has an additional CRC checksum.
+package armor // import "golang.org/x/crypto/openpgp/armor"
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/base64"
+ "golang.org/x/crypto/openpgp/errors"
+ "io"
+)
+
+// A Block represents an OpenPGP armored structure.
+//
+// The encoded form is:
+// -----BEGIN Type-----
+// Headers
+//
+// base64-encoded Bytes
+// '=' base64 encoded checksum
+// -----END Type-----
+// where Headers is a possibly empty sequence of Key: Value lines.
+//
+// Since the armored data can be very large, this package presents a streaming
+// interface.
+type Block struct {
+ Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
+ Header map[string]string // Optional headers.
+ Body io.Reader // A Reader from which the contents can be read
+ lReader lineReader
+ oReader openpgpReader
+}
+
+var ArmorCorrupt error = errors.StructuralError("armor invalid")
+
+const crc24Init = 0xb704ce
+const crc24Poly = 0x1864cfb
+const crc24Mask = 0xffffff
+
+// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
+func crc24(crc uint32, d []byte) uint32 {
+ for _, b := range d {
+ crc ^= uint32(b) << 16
+ for i := 0; i < 8; i++ {
+ crc <<= 1
+ if crc&0x1000000 != 0 {
+ crc ^= crc24Poly
+ }
+ }
+ }
+ return crc
+}
+
+var armorStart = []byte("-----BEGIN ")
+var armorEnd = []byte("-----END ")
+var armorEndOfLine = []byte("-----")
+
+// lineReader wraps a line based reader. It watches for the end of an armor
+// block and records the expected CRC value.
+type lineReader struct {
+ in *bufio.Reader
+ buf []byte
+ eof bool
+ crc uint32
+}
+
+func (l *lineReader) Read(p []byte) (n int, err error) {
+ if l.eof {
+ return 0, io.EOF
+ }
+
+ if len(l.buf) > 0 {
+ n = copy(p, l.buf)
+ l.buf = l.buf[n:]
+ return
+ }
+
+ line, isPrefix, err := l.in.ReadLine()
+ if err != nil {
+ return
+ }
+ if isPrefix {
+ return 0, ArmorCorrupt
+ }
+
+ if len(line) == 5 && line[0] == '=' {
+ // This is the checksum line
+ var expectedBytes [3]byte
+ var m int
+ m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
+ if m != 3 || err != nil {
+ return
+ }
+ l.crc = uint32(expectedBytes[0])<<16 |
+ uint32(expectedBytes[1])<<8 |
+ uint32(expectedBytes[2])
+
+ line, _, err = l.in.ReadLine()
+ if err != nil && err != io.EOF {
+ return
+ }
+ if !bytes.HasPrefix(line, armorEnd) {
+ return 0, ArmorCorrupt
+ }
+
+ l.eof = true
+ return 0, io.EOF
+ }
+
+ if len(line) > 96 {
+ return 0, ArmorCorrupt
+ }
+
+ n = copy(p, line)
+ bytesToSave := len(line) - n
+ if bytesToSave > 0 {
+ if cap(l.buf) < bytesToSave {
+ l.buf = make([]byte, 0, bytesToSave)
+ }
+ l.buf = l.buf[0:bytesToSave]
+ copy(l.buf, line[n:])
+ }
+
+ return
+}
+
+// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
+// a running CRC of the resulting data and checks the CRC against the value
+// found by the lineReader at EOF.
+type openpgpReader struct {
+ lReader *lineReader
+ b64Reader io.Reader
+ currentCRC uint32
+}
+
+func (r *openpgpReader) Read(p []byte) (n int, err error) {
+ n, err = r.b64Reader.Read(p)
+ r.currentCRC = crc24(r.currentCRC, p[:n])
+
+ if err == io.EOF {
+ if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
+ return 0, ArmorCorrupt
+ }
+ }
+
+ return
+}
+
+// Decode reads a PGP armored block from the given Reader. It will ignore
+// leading garbage. If it doesn't find a block, it will return nil, io.EOF. The
+// given Reader is not usable after calling this function: an arbitrary amount
+// of data may have been read past the end of the block.
+func Decode(in io.Reader) (p *Block, err error) {
+ r := bufio.NewReaderSize(in, 100)
+ var line []byte
+ ignoreNext := false
+
+TryNextBlock:
+ p = nil
+
+ // Skip leading garbage
+ for {
+ ignoreThis := ignoreNext
+ line, ignoreNext, err = r.ReadLine()
+ if err != nil {
+ return
+ }
+ if ignoreNext || ignoreThis {
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
+ break
+ }
+ }
+
+ p = new(Block)
+ p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
+ p.Header = make(map[string]string)
+ nextIsContinuation := false
+ var lastKey string
+
+ // Read headers
+ for {
+ isContinuation := nextIsContinuation
+ line, nextIsContinuation, err = r.ReadLine()
+ if err != nil {
+ p = nil
+ return
+ }
+ if isContinuation {
+ p.Header[lastKey] += string(line)
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 {
+ break
+ }
+
+ i := bytes.Index(line, []byte(": "))
+ if i == -1 {
+ goto TryNextBlock
+ }
+ lastKey = string(line[:i])
+ p.Header[lastKey] = string(line[i+2:])
+ }
+
+ p.lReader.in = r
+ p.oReader.currentCRC = crc24Init
+ p.oReader.lReader = &p.lReader
+ p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
+ p.Body = &p.oReader
+
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/armor/armor_test.go b/vendor/golang.org/x/crypto/openpgp/armor/armor_test.go
new file mode 100644
index 000000000..9334e94e9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/armor/armor_test.go
@@ -0,0 +1,95 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "bytes"
+ "hash/adler32"
+ "io/ioutil"
+ "testing"
+)
+
+func TestDecodeEncode(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorExample1))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ }
+ expectedType := "PGP SIGNATURE"
+ if result.Type != expectedType {
+ t.Errorf("result.Type: got:%s want:%s", result.Type, expectedType)
+ }
+ if len(result.Header) != 1 {
+ t.Errorf("len(result.Header): got:%d want:1", len(result.Header))
+ }
+ v, ok := result.Header["Version"]
+ if !ok || v != "GnuPG v1.4.10 (GNU/Linux)" {
+ t.Errorf("result.Header: got:%#v", result.Header)
+ }
+
+ contents, err := ioutil.ReadAll(result.Body)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if adler32.Checksum(contents) != 0x27b144be {
+ t.Errorf("contents: got: %x", contents)
+ }
+
+ buf = bytes.NewBuffer(nil)
+ w, err := Encode(buf, result.Type, result.Header)
+ if err != nil {
+ t.Error(err)
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ t.Error(err)
+ }
+ w.Close()
+
+ if !bytes.Equal(buf.Bytes(), []byte(armorExample1)) {
+ t.Errorf("got: %s\nwant: %s", string(buf.Bytes()), armorExample1)
+ }
+}
+
+func TestLongHeader(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorLongLine))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ value, ok := result.Header["Version"]
+ if !ok {
+ t.Errorf("missing Version header")
+ }
+ if value != longValueExpected {
+ t.Errorf("got: %s want: %s", value, longValueExpected)
+ }
+}
+
+const armorExample1 = `-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+iJwEAAECAAYFAk1Fv/0ACgkQo01+GMIMMbsYTwQAiAw+QAaNfY6WBdplZ/uMAccm
+4g+81QPmTSGHnetSb6WBiY13kVzK4HQiZH8JSkmmroMLuGeJwsRTEL4wbjRyUKEt
+p1xwUZDECs234F1xiG5enc5SGlRtP7foLBz9lOsjx+LEcA4sTl5/2eZR9zyFZqWW
+TxRjs+fJCIFuo71xb1g=
+=/teI
+-----END PGP SIGNATURE-----`
+
+const armorLongLine = `-----BEGIN PGP SIGNATURE-----
+Version: 0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz
+
+iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
+kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
+cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
+byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
+WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
+okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
+=wfQG
+-----END PGP SIGNATURE-----`
+
+const longValueExpected = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
diff --git a/vendor/golang.org/x/crypto/openpgp/armor/encode.go b/vendor/golang.org/x/crypto/openpgp/armor/encode.go
new file mode 100644
index 000000000..6f07582c3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/armor/encode.go
@@ -0,0 +1,160 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "encoding/base64"
+ "io"
+)
+
+var armorHeaderSep = []byte(": ")
+var blockEnd = []byte("\n=")
+var newline = []byte("\n")
+var armorEndOfLineOut = []byte("-----\n")
+
+// writeSlices writes its arguments to the given Writer.
+func writeSlices(out io.Writer, slices ...[]byte) (err error) {
+ for _, s := range slices {
+ _, err = out.Write(s)
+ if err != nil {
+ return err
+ }
+ }
+ return
+}
+
+// lineBreaker breaks data across several lines, all of the same byte length
+// (except possibly the last). Lines are broken with a single '\n'.
+type lineBreaker struct {
+ lineLength int
+ line []byte
+ used int
+ out io.Writer
+ haveWritten bool
+}
+
+func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
+ return &lineBreaker{
+ lineLength: lineLength,
+ line: make([]byte, lineLength),
+ used: 0,
+ out: out,
+ }
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err error) {
+ n = len(b)
+
+ if n == 0 {
+ return
+ }
+
+ if l.used == 0 && l.haveWritten {
+ _, err = l.out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+ }
+
+ if l.used+len(b) < l.lineLength {
+ l.used += copy(l.line[l.used:], b)
+ return
+ }
+
+ l.haveWritten = true
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ excess := l.lineLength - l.used
+ l.used = 0
+
+ _, err = l.out.Write(b[0:excess])
+ if err != nil {
+ return
+ }
+
+ _, err = l.Write(b[excess:])
+ return
+}
+
+func (l *lineBreaker) Close() (err error) {
+ if l.used > 0 {
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+// encoding keeps track of a running CRC24 over the data which has been written
+// to it and outputs a OpenPGP checksum when closed, followed by an armor
+// trailer.
+//
+// It's built into a stack of io.Writers:
+// encoding -> base64 encoder -> lineBreaker -> out
+type encoding struct {
+ out io.Writer
+ breaker *lineBreaker
+ b64 io.WriteCloser
+ crc uint32
+ blockType []byte
+}
+
+func (e *encoding) Write(data []byte) (n int, err error) {
+ e.crc = crc24(e.crc, data)
+ return e.b64.Write(data)
+}
+
+func (e *encoding) Close() (err error) {
+ err = e.b64.Close()
+ if err != nil {
+ return
+ }
+ e.breaker.Close()
+
+ var checksumBytes [3]byte
+ checksumBytes[0] = byte(e.crc >> 16)
+ checksumBytes[1] = byte(e.crc >> 8)
+ checksumBytes[2] = byte(e.crc)
+
+ var b64ChecksumBytes [4]byte
+ base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
+
+ return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
+}
+
+// Encode returns a WriteCloser which will encode the data written to it in
+// OpenPGP armor.
+func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err error) {
+ bType := []byte(blockType)
+ err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
+ if err != nil {
+ return
+ }
+
+ for k, v := range headers {
+ err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
+ if err != nil {
+ return
+ }
+ }
+
+ _, err = out.Write(newline)
+ if err != nil {
+ return
+ }
+
+ e := &encoding{
+ out: out,
+ breaker: newLineBreaker(out, 64),
+ crc: crc24Init,
+ blockType: bType,
+ }
+ e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
+ return e, nil
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/canonical_text.go b/vendor/golang.org/x/crypto/openpgp/canonical_text.go
new file mode 100644
index 000000000..e601e389f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/canonical_text.go
@@ -0,0 +1,59 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import "hash"
+
+// NewCanonicalTextHash reformats text written to it into the canonical
+// form and then applies the hash h. See RFC 4880, section 5.2.1.
+func NewCanonicalTextHash(h hash.Hash) hash.Hash {
+ return &canonicalTextHash{h, 0}
+}
+
+type canonicalTextHash struct {
+ h hash.Hash
+ s int
+}
+
+var newline = []byte{'\r', '\n'}
+
+func (cth *canonicalTextHash) Write(buf []byte) (int, error) {
+ start := 0
+
+ for i, c := range buf {
+ switch cth.s {
+ case 0:
+ if c == '\r' {
+ cth.s = 1
+ } else if c == '\n' {
+ cth.h.Write(buf[start:i])
+ cth.h.Write(newline)
+ start = i + 1
+ }
+ case 1:
+ cth.s = 0
+ }
+ }
+
+ cth.h.Write(buf[start:])
+ return len(buf), nil
+}
+
+func (cth *canonicalTextHash) Sum(in []byte) []byte {
+ return cth.h.Sum(in)
+}
+
+func (cth *canonicalTextHash) Reset() {
+ cth.h.Reset()
+ cth.s = 0
+}
+
+func (cth *canonicalTextHash) Size() int {
+ return cth.h.Size()
+}
+
+func (cth *canonicalTextHash) BlockSize() int {
+ return cth.h.BlockSize()
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/canonical_text_test.go b/vendor/golang.org/x/crypto/openpgp/canonical_text_test.go
new file mode 100644
index 000000000..8f3ba2a88
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/canonical_text_test.go
@@ -0,0 +1,52 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "bytes"
+ "testing"
+)
+
+type recordingHash struct {
+ buf *bytes.Buffer
+}
+
+func (r recordingHash) Write(b []byte) (n int, err error) {
+ return r.buf.Write(b)
+}
+
+func (r recordingHash) Sum(in []byte) []byte {
+ return append(in, r.buf.Bytes()...)
+}
+
+func (r recordingHash) Reset() {
+ panic("shouldn't be called")
+}
+
+func (r recordingHash) Size() int {
+ panic("shouldn't be called")
+}
+
+func (r recordingHash) BlockSize() int {
+ panic("shouldn't be called")
+}
+
+func testCanonicalText(t *testing.T, input, expected string) {
+ r := recordingHash{bytes.NewBuffer(nil)}
+ c := NewCanonicalTextHash(r)
+ c.Write([]byte(input))
+ result := c.Sum(nil)
+ if expected != string(result) {
+ t.Errorf("input: %x got: %x want: %x", input, result, expected)
+ }
+}
+
+func TestCanonicalText(t *testing.T) {
+ testCanonicalText(t, "foo\n", "foo\r\n")
+ testCanonicalText(t, "foo", "foo")
+ testCanonicalText(t, "foo\r\n", "foo\r\n")
+ testCanonicalText(t, "foo\r\nbar", "foo\r\nbar")
+ testCanonicalText(t, "foo\r\nbar\n\n", "foo\r\nbar\r\n\r\n")
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
new file mode 100644
index 000000000..def4cabaf
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign.go
@@ -0,0 +1,376 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package clearsign generates and processes OpenPGP, clear-signed data. See
+// RFC 4880, section 7.
+//
+// Clearsigned messages are cryptographically signed, but the contents of the
+// message are kept in plaintext so that it can be read without special tools.
+package clearsign // import "golang.org/x/crypto/openpgp/clearsign"
+
+import (
+ "bufio"
+ "bytes"
+ "crypto"
+ "hash"
+ "io"
+ "net/textproto"
+ "strconv"
+
+ "golang.org/x/crypto/openpgp/armor"
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/packet"
+)
+
+// A Block represents a clearsigned message. A signature on a Block can
+// be checked by passing Bytes into openpgp.CheckDetachedSignature.
+type Block struct {
+ Headers textproto.MIMEHeader // Optional message headers
+ Plaintext []byte // The original message text
+ Bytes []byte // The signed message
+ ArmoredSignature *armor.Block // The signature block
+}
+
+// start is the marker which denotes the beginning of a clearsigned message.
+var start = []byte("\n-----BEGIN PGP SIGNED MESSAGE-----")
+
+// dashEscape is prefixed to any lines that begin with a hyphen so that they
+// can't be confused with endText.
+var dashEscape = []byte("- ")
+
+// endText is a marker which denotes the end of the message and the start of
+// an armored signature.
+var endText = []byte("-----BEGIN PGP SIGNATURE-----")
+
+// end is a marker which denotes the end of the armored signature.
+var end = []byte("\n-----END PGP SIGNATURE-----")
+
+var crlf = []byte("\r\n")
+var lf = byte('\n')
+
+// getLine returns the first \r\n or \n delineated line from the given byte
+// array. The line does not include the \r\n or \n. The remainder of the byte
+// array (also not including the new line bytes) is also returned and this will
+// always be smaller than the original argument.
+func getLine(data []byte) (line, rest []byte) {
+ i := bytes.Index(data, []byte{'\n'})
+ var j int
+ if i < 0 {
+ i = len(data)
+ j = i
+ } else {
+ j = i + 1
+ if i > 0 && data[i-1] == '\r' {
+ i--
+ }
+ }
+ return data[0:i], data[j:]
+}
+
+// Decode finds the first clearsigned message in data and returns it, as well
+// as the suffix of data which remains after the message.
+func Decode(data []byte) (b *Block, rest []byte) {
+ // start begins with a newline. However, at the very beginning of
+ // the byte array, we'll accept the start string without it.
+ rest = data
+ if bytes.HasPrefix(data, start[1:]) {
+ rest = rest[len(start)-1:]
+ } else if i := bytes.Index(data, start); i >= 0 {
+ rest = rest[i+len(start):]
+ } else {
+ return nil, data
+ }
+
+ // Consume the start line.
+ _, rest = getLine(rest)
+
+ var line []byte
+ b = &Block{
+ Headers: make(textproto.MIMEHeader),
+ }
+
+ // Next come a series of header lines.
+ for {
+ // This loop terminates because getLine's second result is
+ // always smaller than its argument.
+ if len(rest) == 0 {
+ return nil, data
+ }
+ // An empty line marks the end of the headers.
+ if line, rest = getLine(rest); len(line) == 0 {
+ break
+ }
+
+ i := bytes.Index(line, []byte{':'})
+ if i == -1 {
+ return nil, data
+ }
+
+ key, val := line[0:i], line[i+1:]
+ key = bytes.TrimSpace(key)
+ val = bytes.TrimSpace(val)
+ b.Headers.Add(string(key), string(val))
+ }
+
+ firstLine := true
+ for {
+ start := rest
+
+ line, rest = getLine(rest)
+ if len(line) == 0 && len(rest) == 0 {
+ // No armored data was found, so this isn't a complete message.
+ return nil, data
+ }
+ if bytes.Equal(line, endText) {
+ // Back up to the start of the line because armor expects to see the
+ // header line.
+ rest = start
+ break
+ }
+
+ // The final CRLF isn't included in the hash so we don't write it until
+ // we've seen the next line.
+ if firstLine {
+ firstLine = false
+ } else {
+ b.Bytes = append(b.Bytes, crlf...)
+ }
+
+ if bytes.HasPrefix(line, dashEscape) {
+ line = line[2:]
+ }
+ line = bytes.TrimRight(line, " \t")
+ b.Bytes = append(b.Bytes, line...)
+
+ b.Plaintext = append(b.Plaintext, line...)
+ b.Plaintext = append(b.Plaintext, lf)
+ }
+
+ // We want to find the extent of the armored data (including any newlines at
+ // the end).
+ i := bytes.Index(rest, end)
+ if i == -1 {
+ return nil, data
+ }
+ i += len(end)
+ for i < len(rest) && (rest[i] == '\r' || rest[i] == '\n') {
+ i++
+ }
+ armored := rest[:i]
+ rest = rest[i:]
+
+ var err error
+ b.ArmoredSignature, err = armor.Decode(bytes.NewBuffer(armored))
+ if err != nil {
+ return nil, data
+ }
+
+ return b, rest
+}
+
+// A dashEscaper is an io.WriteCloser which processes the body of a clear-signed
+// message. The clear-signed message is written to buffered and a hash, suitable
+// for signing, is maintained in h.
+//
+// When closed, an armored signature is created and written to complete the
+// message.
+type dashEscaper struct {
+ buffered *bufio.Writer
+ h hash.Hash
+ hashType crypto.Hash
+
+ atBeginningOfLine bool
+ isFirstLine bool
+
+ whitespace []byte
+ byteBuf []byte // a one byte buffer to save allocations
+
+ privateKey *packet.PrivateKey
+ config *packet.Config
+}
+
+func (d *dashEscaper) Write(data []byte) (n int, err error) {
+ for _, b := range data {
+ d.byteBuf[0] = b
+
+ if d.atBeginningOfLine {
+ // The final CRLF isn't included in the hash so we have to wait
+ // until this point (the start of the next line) before writing it.
+ if !d.isFirstLine {
+ d.h.Write(crlf)
+ }
+ d.isFirstLine = false
+ }
+
+ // Any whitespace at the end of the line has to be removed so we
+ // buffer it until we find out whether there's more on this line.
+ if b == ' ' || b == '\t' || b == '\r' {
+ d.whitespace = append(d.whitespace, b)
+ d.atBeginningOfLine = false
+ continue
+ }
+
+ if d.atBeginningOfLine {
+ // At the beginning of a line, hyphens have to be escaped.
+ if b == '-' {
+ // The signature isn't calculated over the dash-escaped text so
+ // the escape is only written to buffered.
+ if _, err = d.buffered.Write(dashEscape); err != nil {
+ return
+ }
+ d.h.Write(d.byteBuf)
+ d.atBeginningOfLine = false
+ } else if b == '\n' {
+ // Nothing to do because we delay writing CRLF to the hash.
+ } else {
+ d.h.Write(d.byteBuf)
+ d.atBeginningOfLine = false
+ }
+ if err = d.buffered.WriteByte(b); err != nil {
+ return
+ }
+ } else {
+ if b == '\n' {
+ // We got a raw \n. Drop any trailing whitespace and write a
+ // CRLF.
+ d.whitespace = d.whitespace[:0]
+ // We delay writing CRLF to the hash until the start of the
+ // next line.
+ if err = d.buffered.WriteByte(b); err != nil {
+ return
+ }
+ d.atBeginningOfLine = true
+ } else {
+ // Any buffered whitespace wasn't at the end of the line so
+ // we need to write it out.
+ if len(d.whitespace) > 0 {
+ d.h.Write(d.whitespace)
+ if _, err = d.buffered.Write(d.whitespace); err != nil {
+ return
+ }
+ d.whitespace = d.whitespace[:0]
+ }
+ d.h.Write(d.byteBuf)
+ if err = d.buffered.WriteByte(b); err != nil {
+ return
+ }
+ }
+ }
+ }
+
+ n = len(data)
+ return
+}
+
+func (d *dashEscaper) Close() (err error) {
+ if !d.atBeginningOfLine {
+ if err = d.buffered.WriteByte(lf); err != nil {
+ return
+ }
+ }
+ sig := new(packet.Signature)
+ sig.SigType = packet.SigTypeText
+ sig.PubKeyAlgo = d.privateKey.PubKeyAlgo
+ sig.Hash = d.hashType
+ sig.CreationTime = d.config.Now()
+ sig.IssuerKeyId = &d.privateKey.KeyId
+
+ if err = sig.Sign(d.h, d.privateKey, d.config); err != nil {
+ return
+ }
+
+ out, err := armor.Encode(d.buffered, "PGP SIGNATURE", nil)
+ if err != nil {
+ return
+ }
+
+ if err = sig.Serialize(out); err != nil {
+ return
+ }
+ if err = out.Close(); err != nil {
+ return
+ }
+ if err = d.buffered.Flush(); err != nil {
+ return
+ }
+ return
+}
+
+// Encode returns a WriteCloser which will clear-sign a message with privateKey
+// and write it to w. If config is nil, sensible defaults are used.
+func Encode(w io.Writer, privateKey *packet.PrivateKey, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ if privateKey.Encrypted {
+ return nil, errors.InvalidArgumentError("signing key is encrypted")
+ }
+
+ hashType := config.Hash()
+ name := nameOfHash(hashType)
+ if len(name) == 0 {
+ return nil, errors.UnsupportedError("unknown hash type: " + strconv.Itoa(int(hashType)))
+ }
+
+ if !hashType.Available() {
+ return nil, errors.UnsupportedError("unsupported hash type: " + strconv.Itoa(int(hashType)))
+ }
+ h := hashType.New()
+
+ buffered := bufio.NewWriter(w)
+ // start has a \n at the beginning that we don't want here.
+ if _, err = buffered.Write(start[1:]); err != nil {
+ return
+ }
+ if err = buffered.WriteByte(lf); err != nil {
+ return
+ }
+ if _, err = buffered.WriteString("Hash: "); err != nil {
+ return
+ }
+ if _, err = buffered.WriteString(name); err != nil {
+ return
+ }
+ if err = buffered.WriteByte(lf); err != nil {
+ return
+ }
+ if err = buffered.WriteByte(lf); err != nil {
+ return
+ }
+
+ plaintext = &dashEscaper{
+ buffered: buffered,
+ h: h,
+ hashType: hashType,
+
+ atBeginningOfLine: true,
+ isFirstLine: true,
+
+ byteBuf: make([]byte, 1),
+
+ privateKey: privateKey,
+ config: config,
+ }
+
+ return
+}
+
+// nameOfHash returns the OpenPGP name for the given hash, or the empty string
+// if the name isn't known. See RFC 4880, section 9.4.
+func nameOfHash(h crypto.Hash) string {
+ switch h {
+ case crypto.MD5:
+ return "MD5"
+ case crypto.SHA1:
+ return "SHA1"
+ case crypto.RIPEMD160:
+ return "RIPEMD160"
+ case crypto.SHA224:
+ return "SHA224"
+ case crypto.SHA256:
+ return "SHA256"
+ case crypto.SHA384:
+ return "SHA384"
+ case crypto.SHA512:
+ return "SHA512"
+ }
+ return ""
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
new file mode 100644
index 000000000..2c0948078
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/clearsign/clearsign_test.go
@@ -0,0 +1,210 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package clearsign
+
+import (
+ "bytes"
+ "golang.org/x/crypto/openpgp"
+ "testing"
+)
+
+func testParse(t *testing.T, input []byte, expected, expectedPlaintext string) {
+ b, rest := Decode(input)
+ if b == nil {
+ t.Fatal("failed to decode clearsign message")
+ }
+ if !bytes.Equal(rest, []byte("trailing")) {
+ t.Errorf("unexpected remaining bytes returned: %s", string(rest))
+ }
+ if b.ArmoredSignature.Type != "PGP SIGNATURE" {
+ t.Errorf("bad armor type, got:%s, want:PGP SIGNATURE", b.ArmoredSignature.Type)
+ }
+ if !bytes.Equal(b.Bytes, []byte(expected)) {
+ t.Errorf("bad body, got:%x want:%x", b.Bytes, expected)
+ }
+
+ if !bytes.Equal(b.Plaintext, []byte(expectedPlaintext)) {
+ t.Errorf("bad plaintext, got:%x want:%x", b.Plaintext, expectedPlaintext)
+ }
+
+ keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(signingKey))
+ if err != nil {
+ t.Errorf("failed to parse public key: %s", err)
+ }
+
+ if _, err := openpgp.CheckDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body); err != nil {
+ t.Errorf("failed to check signature: %s", err)
+ }
+}
+
+func TestParse(t *testing.T) {
+ testParse(t, clearsignInput, "Hello world\r\nline 2", "Hello world\nline 2\n")
+ testParse(t, clearsignInput2, "\r\n\r\n(This message has a couple of blank lines at the start and end.)\r\n\r\n", "\n\n(This message has a couple of blank lines at the start and end.)\n\n\n")
+}
+
+func TestParseInvalid(t *testing.T) {
+ if b, _ := Decode(clearsignInput3); b != nil {
+ t.Fatal("decoded a bad clearsigned message without any error")
+ }
+}
+
+func TestParseWithNoNewlineAtEnd(t *testing.T) {
+ input := clearsignInput
+ input = input[:len(input)-len("trailing")-1]
+ b, rest := Decode(input)
+ if b == nil {
+ t.Fatal("failed to decode clearsign message")
+ }
+ if len(rest) > 0 {
+ t.Errorf("unexpected remaining bytes returned: %s", string(rest))
+ }
+}
+
+var signingTests = []struct {
+ in, signed, plaintext string
+}{
+ {"", "", ""},
+ {"a", "a", "a\n"},
+ {"a\n", "a", "a\n"},
+ {"-a\n", "-a", "-a\n"},
+ {"--a\nb", "--a\r\nb", "--a\nb\n"},
+ // leading whitespace
+ {" a\n", " a", " a\n"},
+ {" a\n", " a", " a\n"},
+ // trailing whitespace (should be stripped)
+ {"a \n", "a", "a\n"},
+ {"a ", "a", "a\n"},
+ // whitespace-only lines (should be stripped)
+ {" \n", "", "\n"},
+ {" ", "", "\n"},
+ {"a\n \n \nb\n", "a\r\n\r\n\r\nb", "a\n\n\nb\n"},
+}
+
+func TestSigning(t *testing.T) {
+ keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(signingKey))
+ if err != nil {
+ t.Errorf("failed to parse public key: %s", err)
+ }
+
+ for i, test := range signingTests {
+ var buf bytes.Buffer
+
+ plaintext, err := Encode(&buf, keyring[0].PrivateKey, nil)
+ if err != nil {
+ t.Errorf("#%d: error from Encode: %s", i, err)
+ continue
+ }
+ if _, err := plaintext.Write([]byte(test.in)); err != nil {
+ t.Errorf("#%d: error from Write: %s", i, err)
+ continue
+ }
+ if err := plaintext.Close(); err != nil {
+ t.Fatalf("#%d: error from Close: %s", i, err)
+ continue
+ }
+
+ b, _ := Decode(buf.Bytes())
+ if b == nil {
+ t.Errorf("#%d: failed to decode clearsign message", i)
+ continue
+ }
+ if !bytes.Equal(b.Bytes, []byte(test.signed)) {
+ t.Errorf("#%d: bad result, got:%x, want:%x", i, b.Bytes, test.signed)
+ continue
+ }
+ if !bytes.Equal(b.Plaintext, []byte(test.plaintext)) {
+ t.Errorf("#%d: bad result, got:%x, want:%x", i, b.Plaintext, test.plaintext)
+ continue
+ }
+
+ if _, err := openpgp.CheckDetachedSignature(keyring, bytes.NewBuffer(b.Bytes), b.ArmoredSignature.Body); err != nil {
+ t.Errorf("#%d: failed to check signature: %s", i, err)
+ }
+ }
+}
+
+var clearsignInput = []byte(`
+;lasjlkfdsa
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+Hello world
+line 2
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+iJwEAQECAAYFAk8kMuEACgkQO9o98PRieSpMsAQAhmY/vwmNpflrPgmfWsYhk5O8
+pjnBUzZwqTDoDeINjZEoPDSpQAHGhjFjgaDx/Gj4fAl0dM4D0wuUEBb6QOrwflog
+2A2k9kfSOMOtk0IH/H5VuFN1Mie9L/erYXjTQIptv9t9J7NoRBMU0QOOaFU0JaO9
+MyTpno24AjIAGb+mH1U=
+=hIJ6
+-----END PGP SIGNATURE-----
+trailing`)
+
+var clearsignInput2 = []byte(`
+asdlfkjasdlkfjsadf
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA256
+
+
+
+(This message has a couple of blank lines at the start and end.)
+
+
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.11 (GNU/Linux)
+
+iJwEAQEIAAYFAlPpSREACgkQO9o98PRieSpZTAP+M8QUoCt/7Rf3YbXPcdzIL32v
+pt1I+cMNeopzfLy0u4ioEFi8s5VkwpL1AFmirvgViCwlf82inoRxzZRiW05JQ5LI
+ESEzeCoy2LIdRCQ2hcrG8pIUPzUO4TqO5D/dMbdHwNH4h5nNmGJUAEG6FpURlPm+
+qZg6BaTvOxepqOxnhVU=
+=e+C6
+-----END PGP SIGNATURE-----
+
+trailing`)
+
+var clearsignInput3 = []byte(`
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA256
+
+(This message was truncated.)
+`)
+
+var signingKey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
+idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
+vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
+AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
+0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
+IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
+VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
+gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
+TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
+q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
+dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
+CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
+ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
+eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
+AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
+bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
+/UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
+A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
+TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
+lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
+rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
+oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
+QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
+nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
+AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
+BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
+AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
+VrM0m72/jnpKo04=
+=zNCn
+-----END PGP PRIVATE KEY BLOCK-----
+`
diff --git a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
new file mode 100644
index 000000000..73f4fe378
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
@@ -0,0 +1,122 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elgamal implements ElGamal encryption, suitable for OpenPGP,
+// as specified in "A Public-Key Cryptosystem and a Signature Scheme Based on
+// Discrete Logarithms," IEEE Transactions on Information Theory, v. IT-31,
+// n. 4, 1985, pp. 469-472.
+//
+// This form of ElGamal embeds PKCS#1 v1.5 padding, which may make it
+// unsuitable for other protocols. RSA should be used in preference in any
+// case.
+package elgamal // import "golang.org/x/crypto/openpgp/elgamal"
+
+import (
+ "crypto/rand"
+ "crypto/subtle"
+ "errors"
+ "io"
+ "math/big"
+)
+
+// PublicKey represents an ElGamal public key.
+type PublicKey struct {
+ G, P, Y *big.Int
+}
+
+// PrivateKey represents an ElGamal private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+// Encrypt encrypts the given message to the given public key. The result is a
+// pair of integers. Errors can result from reading random, or because msg is
+// too large to be encrypted to the public key.
+func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
+ pLen := (pub.P.BitLen() + 7) / 8
+ if len(msg) > pLen-11 {
+ err = errors.New("elgamal: message too long")
+ return
+ }
+
+ // EM = 0x02 || PS || 0x00 || M
+ em := make([]byte, pLen-1)
+ em[0] = 2
+ ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err = nonZeroRandomBytes(ps, random)
+ if err != nil {
+ return
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ m := new(big.Int).SetBytes(em)
+
+ k, err := rand.Int(random, pub.P)
+ if err != nil {
+ return
+ }
+
+ c1 = new(big.Int).Exp(pub.G, k, pub.P)
+ s := new(big.Int).Exp(pub.Y, k, pub.P)
+ c2 = s.Mul(s, m)
+ c2.Mod(c2, pub.P)
+
+ return
+}
+
+// Decrypt takes two integers, resulting from an ElGamal encryption, and
+// returns the plaintext of the message. An error can result only if the
+// ciphertext is invalid. Users should keep in mind that this is a padding
+// oracle and thus, if exposed to an adaptive chosen ciphertext attack, can
+// be used to break the cryptosystem. See ``Chosen Ciphertext Attacks
+// Against Protocols Based on the RSA Encryption Standard PKCS #1'', Daniel
+// Bleichenbacher, Advances in Cryptology (Crypto '98),
+func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
+ s := new(big.Int).Exp(c1, priv.X, priv.P)
+ s.ModInverse(s, priv.P)
+ s.Mul(s, c2)
+ s.Mod(s, priv.P)
+ em := s.Bytes()
+
+ firstByteIsTwo := subtle.ConstantTimeByteEq(em[0], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ var lookingForIndex, index int
+ lookingForIndex = 1
+
+ for i := 1; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ if firstByteIsTwo != 1 || lookingForIndex != 0 || index < 9 {
+ return nil, errors.New("elgamal: decryption error")
+ }
+ return em[index+1:], nil
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, rand io.Reader) (err error) {
+ _, err = io.ReadFull(rand, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(rand, s[i:i+1])
+ if err != nil {
+ return
+ }
+ }
+ }
+
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal_test.go b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal_test.go
new file mode 100644
index 000000000..c4f99f5c4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal_test.go
@@ -0,0 +1,49 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elgamal
+
+import (
+ "bytes"
+ "crypto/rand"
+ "math/big"
+ "testing"
+)
+
+// This is the 1024-bit MODP group from RFC 5114, section 2.1:
+const primeHex = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371"
+
+const generatorHex = "A4D1CBD5C3FD34126765A442EFB99905F8104DD258AC507FD6406CFF14266D31266FEA1E5C41564B777E690F5504F213160217B4B01B886A5E91547F9E2749F4D7FBD7D3B9A92EE1909D0D2263F80A76A6A24C087A091F531DBF0A0169B6A28AD662A4D18E73AFA32D779D5918D08BC8858F4DCEF97C2A24855E6EEB22B3B2E5"
+
+func fromHex(hex string) *big.Int {
+ n, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("failed to parse hex number")
+ }
+ return n
+}
+
+func TestEncryptDecrypt(t *testing.T) {
+ priv := &PrivateKey{
+ PublicKey: PublicKey{
+ G: fromHex(generatorHex),
+ P: fromHex(primeHex),
+ },
+ X: fromHex("42"),
+ }
+ priv.Y = new(big.Int).Exp(priv.G, priv.X, priv.P)
+
+ message := []byte("hello world")
+ c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ }
+ message2, err := Decrypt(priv, c1, c2)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ }
+ if !bytes.Equal(message2, message) {
+ t.Errorf("decryption failed, got: %x, want: %x", message2, message)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/errors/errors.go b/vendor/golang.org/x/crypto/openpgp/errors/errors.go
new file mode 100644
index 000000000..eb0550b2d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/errors/errors.go
@@ -0,0 +1,72 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package errors contains common error types for the OpenPGP packages.
+package errors // import "golang.org/x/crypto/openpgp/errors"
+
+import (
+ "strconv"
+)
+
+// A StructuralError is returned when OpenPGP data is found to be syntactically
+// invalid.
+type StructuralError string
+
+func (s StructuralError) Error() string {
+ return "openpgp: invalid data: " + string(s)
+}
+
+// UnsupportedError indicates that, although the OpenPGP data is valid, it
+// makes use of currently unimplemented features.
+type UnsupportedError string
+
+func (s UnsupportedError) Error() string {
+ return "openpgp: unsupported feature: " + string(s)
+}
+
+// InvalidArgumentError indicates that the caller is in error and passed an
+// incorrect value.
+type InvalidArgumentError string
+
+func (i InvalidArgumentError) Error() string {
+ return "openpgp: invalid argument: " + string(i)
+}
+
+// SignatureError indicates that a syntactically valid signature failed to
+// validate.
+type SignatureError string
+
+func (b SignatureError) Error() string {
+ return "openpgp: invalid signature: " + string(b)
+}
+
+type keyIncorrectError int
+
+func (ki keyIncorrectError) Error() string {
+ return "openpgp: incorrect key"
+}
+
+var ErrKeyIncorrect error = keyIncorrectError(0)
+
+type unknownIssuerError int
+
+func (unknownIssuerError) Error() string {
+ return "openpgp: signature made by unknown entity"
+}
+
+var ErrUnknownIssuer error = unknownIssuerError(0)
+
+type keyRevokedError int
+
+func (keyRevokedError) Error() string {
+ return "openpgp: signature made by revoked key"
+}
+
+var ErrKeyRevoked error = keyRevokedError(0)
+
+type UnknownPacketTypeError uint8
+
+func (upte UnknownPacketTypeError) Error() string {
+ return "openpgp: unknown packet type: " + strconv.Itoa(int(upte))
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/keys.go b/vendor/golang.org/x/crypto/openpgp/keys.go
new file mode 100644
index 000000000..bfe326031
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/keys.go
@@ -0,0 +1,633 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "crypto/rsa"
+ "io"
+ "time"
+
+ "golang.org/x/crypto/openpgp/armor"
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/packet"
+)
+
+// PublicKeyType is the armor type for a PGP public key.
+var PublicKeyType = "PGP PUBLIC KEY BLOCK"
+
+// PrivateKeyType is the armor type for a PGP private key.
+var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
+
+// An Entity represents the components of an OpenPGP key: a primary public key
+// (which must be a signing key), one or more identities claimed by that key,
+// and zero or more subkeys, which may be encryption keys.
+type Entity struct {
+ PrimaryKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ Identities map[string]*Identity // indexed by Identity.Name
+ Revocations []*packet.Signature
+ Subkeys []Subkey
+}
+
+// An Identity represents an identity claimed by an Entity and zero or more
+// assertions by other entities about that claim.
+type Identity struct {
+ Name string // by convention, has the form "Full Name (comment) <email@example.com>"
+ UserId *packet.UserId
+ SelfSignature *packet.Signature
+ Signatures []*packet.Signature
+}
+
+// A Subkey is an additional public key in an Entity. Subkeys can be used for
+// encryption.
+type Subkey struct {
+ PublicKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ Sig *packet.Signature
+}
+
+// A Key identifies a specific public key in an Entity. This is either the
+// Entity's primary key or a subkey.
+type Key struct {
+ Entity *Entity
+ PublicKey *packet.PublicKey
+ PrivateKey *packet.PrivateKey
+ SelfSignature *packet.Signature
+}
+
+// A KeyRing provides access to public and private keys.
+type KeyRing interface {
+ // KeysById returns the set of keys that have the given key id.
+ KeysById(id uint64) []Key
+ // KeysByIdAndUsage returns the set of keys with the given id
+ // that also meet the key usage given by requiredUsage.
+ // The requiredUsage is expressed as the bitwise-OR of
+ // packet.KeyFlag* values.
+ KeysByIdUsage(id uint64, requiredUsage byte) []Key
+ // DecryptionKeys returns all private keys that are valid for
+ // decryption.
+ DecryptionKeys() []Key
+}
+
+// primaryIdentity returns the Identity marked as primary or the first identity
+// if none are so marked.
+func (e *Entity) primaryIdentity() *Identity {
+ var firstIdentity *Identity
+ for _, ident := range e.Identities {
+ if firstIdentity == nil {
+ firstIdentity = ident
+ }
+ if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
+ return ident
+ }
+ }
+ return firstIdentity
+}
+
+// encryptionKey returns the best candidate Key for encrypting a message to the
+// given Entity.
+func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
+ candidateSubkey := -1
+
+ // Iterate the keys to find the newest key
+ var maxTime time.Time
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid &&
+ subkey.Sig.FlagEncryptCommunications &&
+ subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
+ !subkey.Sig.KeyExpired(now) &&
+ (maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
+ candidateSubkey = i
+ maxTime = subkey.Sig.CreationTime
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
+ }
+
+ // If we don't have any candidate subkeys for encryption and
+ // the primary key doesn't have any usage metadata then we
+ // assume that the primary key is ok. Or, if the primary key is
+ // marked as ok to encrypt to, then we can obviously use it.
+ i := e.primaryIdentity()
+ if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
+ e.PrimaryKey.PubKeyAlgo.CanEncrypt() &&
+ !i.SelfSignature.KeyExpired(now) {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
+ }
+
+ // This Entity appears to be signing only.
+ return Key{}, false
+}
+
+// signingKey return the best candidate Key for signing a message with this
+// Entity.
+func (e *Entity) signingKey(now time.Time) (Key, bool) {
+ candidateSubkey := -1
+
+ for i, subkey := range e.Subkeys {
+ if subkey.Sig.FlagsValid &&
+ subkey.Sig.FlagSign &&
+ subkey.PublicKey.PubKeyAlgo.CanSign() &&
+ !subkey.Sig.KeyExpired(now) {
+ candidateSubkey = i
+ break
+ }
+ }
+
+ if candidateSubkey != -1 {
+ subkey := e.Subkeys[candidateSubkey]
+ return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
+ }
+
+ // If we have no candidate subkey then we assume that it's ok to sign
+ // with the primary key.
+ i := e.primaryIdentity()
+ if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign &&
+ !i.SelfSignature.KeyExpired(now) {
+ return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
+ }
+
+ return Key{}, false
+}
+
+// An EntityList contains one or more Entities.
+type EntityList []*Entity
+
+// KeysById returns the set of keys that have the given key id.
+func (el EntityList) KeysById(id uint64) (keys []Key) {
+ for _, e := range el {
+ if e.PrimaryKey.KeyId == id {
+ var selfSig *packet.Signature
+ for _, ident := range e.Identities {
+ if selfSig == nil {
+ selfSig = ident.SelfSignature
+ } else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
+ selfSig = ident.SelfSignature
+ break
+ }
+ }
+ keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig})
+ }
+
+ for _, subKey := range e.Subkeys {
+ if subKey.PublicKey.KeyId == id {
+ keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
+ }
+ }
+ }
+ return
+}
+
+// KeysByIdAndUsage returns the set of keys with the given id that also meet
+// the key usage given by requiredUsage. The requiredUsage is expressed as
+// the bitwise-OR of packet.KeyFlag* values.
+func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
+ for _, key := range el.KeysById(id) {
+ if len(key.Entity.Revocations) > 0 {
+ continue
+ }
+
+ if key.SelfSignature.RevocationReason != nil {
+ continue
+ }
+
+ if key.SelfSignature.FlagsValid && requiredUsage != 0 {
+ var usage byte
+ if key.SelfSignature.FlagCertify {
+ usage |= packet.KeyFlagCertify
+ }
+ if key.SelfSignature.FlagSign {
+ usage |= packet.KeyFlagSign
+ }
+ if key.SelfSignature.FlagEncryptCommunications {
+ usage |= packet.KeyFlagEncryptCommunications
+ }
+ if key.SelfSignature.FlagEncryptStorage {
+ usage |= packet.KeyFlagEncryptStorage
+ }
+ if usage&requiredUsage != requiredUsage {
+ continue
+ }
+ }
+
+ keys = append(keys, key)
+ }
+ return
+}
+
+// DecryptionKeys returns all private keys that are valid for decryption.
+func (el EntityList) DecryptionKeys() (keys []Key) {
+ for _, e := range el {
+ for _, subKey := range e.Subkeys {
+ if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
+ keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
+ }
+ }
+ }
+ return
+}
+
+// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
+func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
+ block, err := armor.Decode(r)
+ if err == io.EOF {
+ return nil, errors.InvalidArgumentError("no armored data found")
+ }
+ if err != nil {
+ return nil, err
+ }
+ if block.Type != PublicKeyType && block.Type != PrivateKeyType {
+ return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
+ }
+
+ return ReadKeyRing(block.Body)
+}
+
+// ReadKeyRing reads one or more public/private keys. Unsupported keys are
+// ignored as long as at least a single valid key is found.
+func ReadKeyRing(r io.Reader) (el EntityList, err error) {
+ packets := packet.NewReader(r)
+ var lastUnsupportedError error
+
+ for {
+ var e *Entity
+ e, err = ReadEntity(packets)
+ if err != nil {
+ // TODO: warn about skipped unsupported/unreadable keys
+ if _, ok := err.(errors.UnsupportedError); ok {
+ lastUnsupportedError = err
+ err = readToNextPublicKey(packets)
+ } else if _, ok := err.(errors.StructuralError); ok {
+ // Skip unreadable, badly-formatted keys
+ lastUnsupportedError = err
+ err = readToNextPublicKey(packets)
+ }
+ if err == io.EOF {
+ err = nil
+ break
+ }
+ if err != nil {
+ el = nil
+ break
+ }
+ } else {
+ el = append(el, e)
+ }
+ }
+
+ if len(el) == 0 && err == nil {
+ err = lastUnsupportedError
+ }
+ return
+}
+
+// readToNextPublicKey reads packets until the start of the entity and leaves
+// the first packet of the new entity in the Reader.
+func readToNextPublicKey(packets *packet.Reader) (err error) {
+ var p packet.Packet
+ for {
+ p, err = packets.Next()
+ if err == io.EOF {
+ return
+ } else if err != nil {
+ if _, ok := err.(errors.UnsupportedError); ok {
+ err = nil
+ continue
+ }
+ return
+ }
+
+ if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
+ packets.Unread(p)
+ return
+ }
+ }
+
+ panic("unreachable")
+}
+
+// ReadEntity reads an entity (public key, identities, subkeys etc) from the
+// given Reader.
+func ReadEntity(packets *packet.Reader) (*Entity, error) {
+ e := new(Entity)
+ e.Identities = make(map[string]*Identity)
+
+ p, err := packets.Next()
+ if err != nil {
+ return nil, err
+ }
+
+ var ok bool
+ if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
+ if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
+ packets.Unread(p)
+ return nil, errors.StructuralError("first packet was not a public/private key")
+ } else {
+ e.PrimaryKey = &e.PrivateKey.PublicKey
+ }
+ }
+
+ if !e.PrimaryKey.PubKeyAlgo.CanSign() {
+ return nil, errors.StructuralError("primary key cannot be used for signatures")
+ }
+
+ var current *Identity
+ var revocations []*packet.Signature
+EachPacket:
+ for {
+ p, err := packets.Next()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return nil, err
+ }
+
+ switch pkt := p.(type) {
+ case *packet.UserId:
+ current = new(Identity)
+ current.Name = pkt.Id
+ current.UserId = pkt
+ e.Identities[pkt.Id] = current
+
+ for {
+ p, err = packets.Next()
+ if err == io.EOF {
+ return nil, io.ErrUnexpectedEOF
+ } else if err != nil {
+ return nil, err
+ }
+
+ sig, ok := p.(*packet.Signature)
+ if !ok {
+ return nil, errors.StructuralError("user ID packet not followed by self-signature")
+ }
+
+ if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
+ if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil {
+ return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error())
+ }
+ current.SelfSignature = sig
+ break
+ }
+ current.Signatures = append(current.Signatures, sig)
+ }
+ case *packet.Signature:
+ if pkt.SigType == packet.SigTypeKeyRevocation {
+ revocations = append(revocations, pkt)
+ } else if pkt.SigType == packet.SigTypeDirectSignature {
+ // TODO: RFC4880 5.2.1 permits signatures
+ // directly on keys (eg. to bind additional
+ // revocation keys).
+ } else if current == nil {
+ return nil, errors.StructuralError("signature packet found before user id packet")
+ } else {
+ current.Signatures = append(current.Signatures, pkt)
+ }
+ case *packet.PrivateKey:
+ if pkt.IsSubkey == false {
+ packets.Unread(p)
+ break EachPacket
+ }
+ err = addSubkey(e, packets, &pkt.PublicKey, pkt)
+ if err != nil {
+ return nil, err
+ }
+ case *packet.PublicKey:
+ if pkt.IsSubkey == false {
+ packets.Unread(p)
+ break EachPacket
+ }
+ err = addSubkey(e, packets, pkt, nil)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ // we ignore unknown packets
+ }
+ }
+
+ if len(e.Identities) == 0 {
+ return nil, errors.StructuralError("entity without any identities")
+ }
+
+ for _, revocation := range revocations {
+ err = e.PrimaryKey.VerifyRevocationSignature(revocation)
+ if err == nil {
+ e.Revocations = append(e.Revocations, revocation)
+ } else {
+ // TODO: RFC 4880 5.2.3.15 defines revocation keys.
+ return nil, errors.StructuralError("revocation signature signed by alternate key")
+ }
+ }
+
+ return e, nil
+}
+
+func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
+ var subKey Subkey
+ subKey.PublicKey = pub
+ subKey.PrivateKey = priv
+ p, err := packets.Next()
+ if err == io.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return errors.StructuralError("subkey signature invalid: " + err.Error())
+ }
+ var ok bool
+ subKey.Sig, ok = p.(*packet.Signature)
+ if !ok {
+ return errors.StructuralError("subkey packet not followed by signature")
+ }
+ if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation {
+ return errors.StructuralError("subkey signature with wrong type")
+ }
+ err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig)
+ if err != nil {
+ return errors.StructuralError("subkey signature invalid: " + err.Error())
+ }
+ e.Subkeys = append(e.Subkeys, subKey)
+ return nil
+}
+
+const defaultRSAKeyBits = 2048
+
+// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
+// single identity composed of the given full name, comment and email, any of
+// which may be empty but must not contain any of "()<>\x00".
+// If config is nil, sensible defaults will be used.
+func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
+ currentTime := config.Now()
+
+ bits := defaultRSAKeyBits
+ if config != nil && config.RSABits != 0 {
+ bits = config.RSABits
+ }
+
+ uid := packet.NewUserId(name, comment, email)
+ if uid == nil {
+ return nil, errors.InvalidArgumentError("user id field contained invalid characters")
+ }
+ signingPriv, err := rsa.GenerateKey(config.Random(), bits)
+ if err != nil {
+ return nil, err
+ }
+ encryptingPriv, err := rsa.GenerateKey(config.Random(), bits)
+ if err != nil {
+ return nil, err
+ }
+
+ e := &Entity{
+ PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey),
+ PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv),
+ Identities: make(map[string]*Identity),
+ }
+ isPrimaryId := true
+ e.Identities[uid.Id] = &Identity{
+ Name: uid.Name,
+ UserId: uid,
+ SelfSignature: &packet.Signature{
+ CreationTime: currentTime,
+ SigType: packet.SigTypePositiveCert,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: config.Hash(),
+ IsPrimaryId: &isPrimaryId,
+ FlagsValid: true,
+ FlagSign: true,
+ FlagCertify: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+
+ e.Subkeys = make([]Subkey, 1)
+ e.Subkeys[0] = Subkey{
+ PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
+ PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv),
+ Sig: &packet.Signature{
+ CreationTime: currentTime,
+ SigType: packet.SigTypeSubkeyBinding,
+ PubKeyAlgo: packet.PubKeyAlgoRSA,
+ Hash: config.Hash(),
+ FlagsValid: true,
+ FlagEncryptStorage: true,
+ FlagEncryptCommunications: true,
+ IssuerKeyId: &e.PrimaryKey.KeyId,
+ },
+ }
+ e.Subkeys[0].PublicKey.IsSubkey = true
+ e.Subkeys[0].PrivateKey.IsSubkey = true
+
+ return e, nil
+}
+
+// SerializePrivate serializes an Entity, including private key material, to
+// the given Writer. For now, it must only be used on an Entity returned from
+// NewEntity.
+// If config is nil, sensible defaults will be used.
+func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
+ err = e.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config)
+ if err != nil {
+ return
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PrivateKey.Serialize(w)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
+ if err != nil {
+ return
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return
+ }
+ }
+ return nil
+}
+
+// Serialize writes the public part of the given Entity to w. (No private
+// key material will be output).
+func (e *Entity) Serialize(w io.Writer) error {
+ err := e.PrimaryKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, ident := range e.Identities {
+ err = ident.UserId.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = ident.SelfSignature.Serialize(w)
+ if err != nil {
+ return err
+ }
+ for _, sig := range ident.Signatures {
+ err = sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ for _, subkey := range e.Subkeys {
+ err = subkey.PublicKey.Serialize(w)
+ if err != nil {
+ return err
+ }
+ err = subkey.Sig.Serialize(w)
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// SignIdentity adds a signature to e, from signer, attesting that identity is
+// associated with e. The provided identity must already be an element of
+// e.Identities and the private key of signer must have been decrypted if
+// necessary.
+// If config is nil, sensible defaults will be used.
+func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error {
+ if signer.PrivateKey == nil {
+ return errors.InvalidArgumentError("signing Entity must have a private key")
+ }
+ if signer.PrivateKey.Encrypted {
+ return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
+ }
+ ident, ok := e.Identities[identity]
+ if !ok {
+ return errors.InvalidArgumentError("given identity string not found in Entity")
+ }
+
+ sig := &packet.Signature{
+ SigType: packet.SigTypeGenericCert,
+ PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
+ Hash: config.Hash(),
+ CreationTime: config.Now(),
+ IssuerKeyId: &signer.PrivateKey.KeyId,
+ }
+ if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil {
+ return err
+ }
+ ident.Signatures = append(ident.Signatures, sig)
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/keys_test.go b/vendor/golang.org/x/crypto/openpgp/keys_test.go
new file mode 100644
index 000000000..d5e2056bb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/keys_test.go
@@ -0,0 +1,370 @@
+package openpgp
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+ "time"
+
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/packet"
+)
+
+func TestKeyExpiry(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(expiringKeyHex))
+ entity := kring[0]
+
+ const timeFormat = "2006-01-02"
+ time1, _ := time.Parse(timeFormat, "2013-07-01")
+
+ // The expiringKeyHex key is structured as:
+ //
+ // pub 1024R/5E237D8C created: 2013-07-01 expires: 2013-07-31 usage: SC
+ // sub 1024R/1ABB25A0 created: 2013-07-01 23:11:07 +0200 CEST expires: 2013-07-08 usage: E
+ // sub 1024R/96A672F5 created: 2013-07-01 23:11:23 +0200 CEST expires: 2013-07-31 usage: E
+ //
+ // So this should select the newest, non-expired encryption key.
+ key, _ := entity.encryptionKey(time1)
+ if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" {
+ t.Errorf("Expected key 1ABB25A0 at time %s, but got key %s", time1.Format(timeFormat), id)
+ }
+
+ // Once the first encryption subkey has expired, the second should be
+ // selected.
+ time2, _ := time.Parse(timeFormat, "2013-07-09")
+ key, _ = entity.encryptionKey(time2)
+ if id := key.PublicKey.KeyIdShortString(); id != "96A672F5" {
+ t.Errorf("Expected key 96A672F5 at time %s, but got key %s", time2.Format(timeFormat), id)
+ }
+
+ // Once all the keys have expired, nothing should be returned.
+ time3, _ := time.Parse(timeFormat, "2013-08-01")
+ if key, ok := entity.encryptionKey(time3); ok {
+ t.Errorf("Expected no key at time %s, but got key %s", time3.Format(timeFormat), key.PublicKey.KeyIdShortString())
+ }
+}
+
+func TestMissingCrossSignature(t *testing.T) {
+ // This public key has a signing subkey, but the subkey does not
+ // contain a cross-signature.
+ keys, err := ReadArmoredKeyRing(bytes.NewBufferString(missingCrossSignatureKey))
+ if len(keys) != 0 {
+ t.Errorf("Accepted key with missing cross signature")
+ }
+ if err == nil {
+ t.Fatal("Failed to detect error in keyring with missing cross signature")
+ }
+ structural, ok := err.(errors.StructuralError)
+ if !ok {
+ t.Fatalf("Unexpected class of error: %T. Wanted StructuralError", err)
+ }
+ const expectedMsg = "signing subkey is missing cross-signature"
+ if !strings.Contains(string(structural), expectedMsg) {
+ t.Fatalf("Unexpected error: %q. Expected it to contain %q", err, expectedMsg)
+ }
+}
+
+func TestInvalidCrossSignature(t *testing.T) {
+ // This public key has a signing subkey, and the subkey has an
+ // embedded cross-signature. However, the cross-signature does
+ // not correctly validate over the primary and subkey.
+ keys, err := ReadArmoredKeyRing(bytes.NewBufferString(invalidCrossSignatureKey))
+ if len(keys) != 0 {
+ t.Errorf("Accepted key with invalid cross signature")
+ }
+ if err == nil {
+ t.Fatal("Failed to detect error in keyring with an invalid cross signature")
+ }
+ structural, ok := err.(errors.StructuralError)
+ if !ok {
+ t.Fatalf("Unexpected class of error: %T. Wanted StructuralError", err)
+ }
+ const expectedMsg = "subkey signature invalid"
+ if !strings.Contains(string(structural), expectedMsg) {
+ t.Fatalf("Unexpected error: %q. Expected it to contain %q", err, expectedMsg)
+ }
+}
+
+func TestGoodCrossSignature(t *testing.T) {
+ // This public key has a signing subkey, and the subkey has an
+ // embedded cross-signature which correctly validates over the
+ // primary and subkey.
+ keys, err := ReadArmoredKeyRing(bytes.NewBufferString(goodCrossSignatureKey))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(keys) != 1 {
+ t.Errorf("Failed to accept key with good cross signature, %d", len(keys))
+ }
+ if len(keys[0].Subkeys) != 1 {
+ t.Errorf("Failed to accept good subkey, %d", len(keys[0].Subkeys))
+ }
+}
+
+// TestExternallyRevokableKey attempts to load and parse a key with a third party revocation permission.
+func TestExternallyRevocableKey(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(subkeyUsageHex))
+
+ // The 0xA42704B92866382A key can be revoked by 0xBE3893CB843D0FE70C
+ // according to this signature that appears within the key:
+ // :signature packet: algo 1, keyid A42704B92866382A
+ // version 4, created 1396409682, md5len 0, sigclass 0x1f
+ // digest algo 2, begin of digest a9 84
+ // hashed subpkt 2 len 4 (sig created 2014-04-02)
+ // hashed subpkt 12 len 22 (revocation key: c=80 a=1 f=CE094AA433F7040BB2DDF0BE3893CB843D0FE70C)
+ // hashed subpkt 7 len 1 (not revocable)
+ // subpkt 16 len 8 (issuer key ID A42704B92866382A)
+ // data: [1024 bits]
+
+ id := uint64(0xA42704B92866382A)
+ keys := kring.KeysById(id)
+ if len(keys) != 1 {
+ t.Errorf("Expected to find key id %X, but got %d matches", id, len(keys))
+ }
+}
+
+func TestKeyRevocation(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(revokedKeyHex))
+
+ // revokedKeyHex contains these keys:
+ // pub 1024R/9A34F7C0 2014-03-25 [revoked: 2014-03-25]
+ // sub 1024R/1BA3CD60 2014-03-25 [revoked: 2014-03-25]
+ ids := []uint64{0xA401D9F09A34F7C0, 0x5CD3BE0A1BA3CD60}
+
+ for _, id := range ids {
+ keys := kring.KeysById(id)
+ if len(keys) != 1 {
+ t.Errorf("Expected KeysById to find revoked key %X, but got %d matches", id, len(keys))
+ }
+ keys = kring.KeysByIdUsage(id, 0)
+ if len(keys) != 0 {
+ t.Errorf("Expected KeysByIdUsage to filter out revoked key %X, but got %d matches", id, len(keys))
+ }
+ }
+}
+
+func TestSubkeyRevocation(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(revokedSubkeyHex))
+
+ // revokedSubkeyHex contains these keys:
+ // pub 1024R/4EF7E4BECCDE97F0 2014-03-25
+ // sub 1024R/D63636E2B96AE423 2014-03-25
+ // sub 1024D/DBCE4EE19529437F 2014-03-25
+ // sub 1024R/677815E371C2FD23 2014-03-25 [revoked: 2014-03-25]
+ validKeys := []uint64{0x4EF7E4BECCDE97F0, 0xD63636E2B96AE423, 0xDBCE4EE19529437F}
+ revokedKey := uint64(0x677815E371C2FD23)
+
+ for _, id := range validKeys {
+ keys := kring.KeysById(id)
+ if len(keys) != 1 {
+ t.Errorf("Expected KeysById to find key %X, but got %d matches", id, len(keys))
+ }
+ keys = kring.KeysByIdUsage(id, 0)
+ if len(keys) != 1 {
+ t.Errorf("Expected KeysByIdUsage to find key %X, but got %d matches", id, len(keys))
+ }
+ }
+
+ keys := kring.KeysById(revokedKey)
+ if len(keys) != 1 {
+ t.Errorf("Expected KeysById to find key %X, but got %d matches", revokedKey, len(keys))
+ }
+
+ keys = kring.KeysByIdUsage(revokedKey, 0)
+ if len(keys) != 0 {
+ t.Errorf("Expected KeysByIdUsage to filter out revoked key %X, but got %d matches", revokedKey, len(keys))
+ }
+}
+
+func TestKeyUsage(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(subkeyUsageHex))
+
+ // subkeyUsageHex contains these keys:
+ // pub 1024R/2866382A created: 2014-04-01 expires: never usage: SC
+ // sub 1024R/936C9153 created: 2014-04-01 expires: never usage: E
+ // sub 1024R/64D5F5BB created: 2014-04-02 expires: never usage: E
+ // sub 1024D/BC0BA992 created: 2014-04-02 expires: never usage: S
+ certifiers := []uint64{0xA42704B92866382A}
+ signers := []uint64{0xA42704B92866382A, 0x42CE2C64BC0BA992}
+ encrypters := []uint64{0x09C0C7D9936C9153, 0xC104E98664D5F5BB}
+
+ for _, id := range certifiers {
+ keys := kring.KeysByIdUsage(id, packet.KeyFlagCertify)
+ if len(keys) == 1 {
+ if keys[0].PublicKey.KeyId != id {
+ t.Errorf("Expected to find certifier key id %X, but got %X", id, keys[0].PublicKey.KeyId)
+ }
+ } else {
+ t.Errorf("Expected one match for certifier key id %X, but got %d matches", id, len(keys))
+ }
+ }
+
+ for _, id := range signers {
+ keys := kring.KeysByIdUsage(id, packet.KeyFlagSign)
+ if len(keys) == 1 {
+ if keys[0].PublicKey.KeyId != id {
+ t.Errorf("Expected to find signing key id %X, but got %X", id, keys[0].PublicKey.KeyId)
+ }
+ } else {
+ t.Errorf("Expected one match for signing key id %X, but got %d matches", id, len(keys))
+ }
+
+ // This keyring contains no encryption keys that are also good for signing.
+ keys = kring.KeysByIdUsage(id, packet.KeyFlagEncryptStorage|packet.KeyFlagEncryptCommunications)
+ if len(keys) != 0 {
+ t.Errorf("Unexpected match for encryption key id %X", id)
+ }
+ }
+
+ for _, id := range encrypters {
+ keys := kring.KeysByIdUsage(id, packet.KeyFlagEncryptStorage|packet.KeyFlagEncryptCommunications)
+ if len(keys) == 1 {
+ if keys[0].PublicKey.KeyId != id {
+ t.Errorf("Expected to find encryption key id %X, but got %X", id, keys[0].PublicKey.KeyId)
+ }
+ } else {
+ t.Errorf("Expected one match for encryption key id %X, but got %d matches", id, len(keys))
+ }
+
+ // This keyring contains no encryption keys that are also good for signing.
+ keys = kring.KeysByIdUsage(id, packet.KeyFlagSign)
+ if len(keys) != 0 {
+ t.Errorf("Unexpected match for signing key id %X", id)
+ }
+ }
+}
+
+func TestIdVerification(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := kring[1].PrivateKey.Decrypt([]byte("passphrase")); err != nil {
+ t.Fatal(err)
+ }
+
+ const identity = "Test Key 1 (RSA)"
+ if err := kring[0].SignIdentity(identity, kring[1], nil); err != nil {
+ t.Fatal(err)
+ }
+
+ ident, ok := kring[0].Identities[identity]
+ if !ok {
+ t.Fatal("identity missing from key after signing")
+ }
+
+ checked := false
+ for _, sig := range ident.Signatures {
+ if sig.IssuerKeyId == nil || *sig.IssuerKeyId != kring[1].PrimaryKey.KeyId {
+ continue
+ }
+
+ if err := kring[1].PrimaryKey.VerifyUserIdSignature(identity, kring[0].PrimaryKey, sig); err != nil {
+ t.Fatalf("error verifying new identity signature: %s", err)
+ }
+ checked = true
+ break
+ }
+
+ if !checked {
+ t.Fatal("didn't find identity signature in Entity")
+ }
+}
+
+const expiringKeyHex = "988d0451d1ec5d010400ba3385721f2dc3f4ab096b2ee867ab77213f0a27a8538441c35d2fa225b08798a1439a66a5150e6bdc3f40f5d28d588c712394c632b6299f77db8c0d48d37903fb72ebd794d61be6aa774688839e5fdecfe06b2684cc115d240c98c66cb1ef22ae84e3aa0c2b0c28665c1e7d4d044e7f270706193f5223c8d44e0d70b7b8da830011010001b40f4578706972792074657374206b657988be041301020028050251d1ec5d021b03050900278d00060b090807030206150802090a0b0416020301021e01021780000a091072589ad75e237d8c033503fd10506d72837834eb7f994117740723adc39227104b0d326a1161871c0b415d25b4aedef946ca77ea4c05af9c22b32cf98be86ab890111fced1ee3f75e87b7cc3c00dc63bbc85dfab91c0dc2ad9de2c4d13a34659333a85c6acc1a669c5e1d6cecb0cf1e56c10e72d855ae177ddc9e766f9b2dda57ccbb75f57156438bbdb4e42b88d0451d1ec5d0104009c64906559866c5cb61578f5846a94fcee142a489c9b41e67b12bb54cfe86eb9bc8566460f9a720cb00d6526fbccfd4f552071a8e3f7744b1882d01036d811ee5a3fb91a1c568055758f43ba5d2c6a9676b012f3a1a89e47bbf624f1ad571b208f3cc6224eb378f1645dd3d47584463f9eadeacfd1ce6f813064fbfdcc4b5a53001101000188a504180102000f021b0c050251d1f06b050900093e89000a091072589ad75e237d8c20e00400ab8310a41461425b37889c4da28129b5fae6084fafbc0a47dd1adc74a264c6e9c9cc125f40462ee1433072a58384daef88c961c390ed06426a81b464a53194c4e291ddd7e2e2ba3efced01537d713bd111f48437bde2363446200995e8e0d4e528dda377fd1e8f8ede9c8e2198b393bd86852ce7457a7e3daf74d510461a5b77b88d0451d1ece8010400b3a519f83ab0010307e83bca895170acce8964a044190a2b368892f7a244758d9fc193482648acb1fb9780d28cc22d171931f38bb40279389fc9bf2110876d4f3db4fcfb13f22f7083877fe56592b3b65251312c36f83ffcb6d313c6a17f197dd471f0712aad15a8537b435a92471ba2e5b0c72a6c72536c3b567c558d7b6051001101000188a504180102000f021b0c050251d1f07b050900279091000a091072589ad75e237d8ce69e03fe286026afacf7c97ee20673864d4459a2240b5655219950643c7dba0ac384b1d4359c67805b21d98211f7b09c2a0ccf6410c8c04d4ff4a51293725d8d6570d9d8bb0e10c07d22357caeb49626df99c180be02d77d1fe8ed25e7a54481237646083a9f89a11566cd20b9e995b1487c5f9e02aeb434f3a1897cd416dd0a87861838da3e9e"
+const subkeyUsageHex = "988d04533a52bc010400d26af43085558f65b9e7dbc90cb9238015259aed5e954637adcfa2181548b2d0b60c65f1f42ec5081cbf1bc0a8aa4900acfb77070837c58f26012fbce297d70afe96e759ad63531f0037538e70dbf8e384569b9720d99d8eb39d8d0a2947233ed242436cb6ac7dfe74123354b3d0119b5c235d3dd9c9d6c004f8ffaf67ad8583001101000188b7041f010200210502533b8552170c8001ce094aa433f7040bb2ddf0be3893cb843d0fe70c020700000a0910a42704b92866382aa98404009d63d916a27543da4221c60087c33f1c44bec9998c5438018ed370cca4962876c748e94b73eb39c58eb698063f3fd6346d58dd2a11c0247934c4a9d71f24754f7468f96fb24c3e791dd2392b62f626148ad724189498cbf993db2df7c0cdc2d677c35da0f16cb16c9ce7c33b4de65a4a91b1d21a130ae9cc26067718910ef8e2b417556d627261203c756d627261407379642e65642e61753e88b80413010200220502533a52bc021b03060b090807030206150802090a0b0416020301021e01021780000a0910a42704b92866382a47840400c0c2bd04f5fca586de408b395b3c280a278259c93eaaa8b79a53b97003f8ed502a8a00446dd9947fb462677e4fcac0dac2f0701847d15130aadb6cd9e0705ea0cf5f92f129136c7be21a718d46c8e641eb7f044f2adae573e11ae423a0a9ca51324f03a8a2f34b91fa40c3cc764bee4dccadedb54c768ba0469b683ea53f1c29b88d04533a52bc01040099c92a5d6f8b744224da27bc2369127c35269b58bec179de6bbc038f749344222f85a31933224f26b70243c4e4b2d242f0c4777eaef7b5502f9dad6d8bf3aaeb471210674b74de2d7078af497d55f5cdad97c7bedfbc1b41e8065a97c9c3d344b21fc81d27723af8e374bc595da26ea242dccb6ae497be26eea57e563ed517e90011010001889f0418010200090502533a52bc021b0c000a0910a42704b92866382afa1403ff70284c2de8a043ff51d8d29772602fa98009b7861c540535f874f2c230af8caf5638151a636b21f8255003997ccd29747fdd06777bb24f9593bd7d98a3e887689bf902f999915fcc94625ae487e5d13e6616f89090ebc4fdc7eb5cad8943e4056995bb61c6af37f8043016876a958ec7ebf39c43d20d53b7f546cfa83e8d2604b88d04533b8283010400c0b529316dbdf58b4c54461e7e669dc11c09eb7f73819f178ccd4177b9182b91d138605fcf1e463262fabefa73f94a52b5e15d1904635541c7ea540f07050ce0fb51b73e6f88644cec86e91107c957a114f69554548a85295d2b70bd0b203992f76eb5d493d86d9eabcaa7ef3fc7db7e458438db3fcdb0ca1cc97c638439a9170011010001889f0418010200090502533b8283021b0c000a0910a42704b92866382adc6d0400cfff6258485a21675adb7a811c3e19ebca18851533f75a7ba317950b9997fda8d1a4c8c76505c08c04b6c2cc31dc704d33da36a21273f2b388a1a706f7c3378b66d887197a525936ed9a69acb57fe7f718133da85ec742001c5d1864e9c6c8ea1b94f1c3759cebfd93b18606066c063a63be86085b7e37bdbc65f9a915bf084bb901a204533b85cd110400aed3d2c52af2b38b5b67904b0ef73d6dd7aef86adb770e2b153cd22489654dcc91730892087bb9856ae2d9f7ed1eb48f214243fe86bfe87b349ebd7c30e630e49c07b21fdabf78b7a95c8b7f969e97e3d33f2e074c63552ba64a2ded7badc05ce0ea2be6d53485f6900c7860c7aa76560376ce963d7271b9b54638a4028b573f00a0d8854bfcdb04986141568046202192263b9b67350400aaa1049dbc7943141ef590a70dcb028d730371d92ea4863de715f7f0f16d168bd3dc266c2450457d46dcbbf0b071547e5fbee7700a820c3750b236335d8d5848adb3c0da010e998908dfd93d961480084f3aea20b247034f8988eccb5546efaa35a92d0451df3aaf1aee5aa36a4c4d462c760ecd9cebcabfbe1412b1f21450f203fd126687cd486496e971a87fd9e1a8a765fe654baa219a6871ab97768596ab05c26c1aeea8f1a2c72395a58dbc12ef9640d2b95784e974a4d2d5a9b17c25fedacfe551bda52602de8f6d2e48443f5dd1a2a2a8e6a5e70ecdb88cd6e766ad9745c7ee91d78cc55c3d06536b49c3fee6c3d0b6ff0fb2bf13a314f57c953b8f4d93bf88e70418010200090502533b85cd021b0200520910a42704b92866382a47200419110200060502533b85cd000a091042ce2c64bc0ba99214b2009e26b26852c8b13b10c35768e40e78fbbb48bd084100a0c79d9ea0844fa5853dd3c85ff3ecae6f2c9dd6c557aa04008bbbc964cd65b9b8299d4ebf31f41cc7264b8cf33a00e82c5af022331fac79efc9563a822497ba012953cefe2629f1242fcdcb911dbb2315985bab060bfd58261ace3c654bdbbe2e8ed27a46e836490145c86dc7bae15c011f7e1ffc33730109b9338cd9f483e7cef3d2f396aab5bd80efb6646d7e778270ee99d934d187dd98"
+const revokedKeyHex = "988d045331ce82010400c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be10011010001889f04200102000905025331d0e3021d03000a0910a401d9f09a34f7c042aa040086631196405b7e6af71026b88e98012eab44aa9849f6ef3fa930c7c9f23deaedba9db1538830f8652fb7648ec3fcade8dbcbf9eaf428e83c6cbcc272201bfe2fbb90d41963397a7c0637a1a9d9448ce695d9790db2dc95433ad7be19eb3de72dacf1d6db82c3644c13eae2a3d072b99bb341debba012c5ce4006a7d34a1f4b94b444526567205265766f6b657220283c52656727732022424d204261726973746122204b657920262530305c303e5c29203c72656740626d626172697374612e636f2e61753e88b704130102002205025331ce82021b03060b090807030206150802090a0b0416020301021e01021780000a0910a401d9f09a34f7c0019c03f75edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56889c04100102000605025331cfb5000a0910fe9645554e8266b64b4303fc084075396674fb6f778d302ac07cef6bc0b5d07b66b2004c44aef711cbac79617ef06d836b4957522d8772dd94bf41a2f4ac8b1ee6d70c57503f837445a74765a076d07b829b8111fc2a918423ddb817ead7ca2a613ef0bfb9c6b3562aec6c3cf3c75ef3031d81d95f6563e4cdcc9960bcb386c5d757b104fcca5fe11fc709df884604101102000605025331cfe7000a09107b15a67f0b3ddc0317f6009e360beea58f29c1d963a22b962b80788c3fa6c84e009d148cfde6b351469b8eae91187eff07ad9d08fcaab88d045331ce820104009f25e20a42b904f3fa555530fe5c46737cf7bd076c35a2a0d22b11f7e0b61a69320b768f4a80fe13980ce380d1cfc4a0cd8fbe2d2e2ef85416668b77208baa65bf973fe8e500e78cc310d7c8705cdb34328bf80e24f0385fce5845c33bc7943cf6b11b02348a23da0bf6428e57c05135f2dc6bd7c1ce325d666d5a5fd2fd5e410011010001889f04180102000905025331ce82021b0c000a0910a401d9f09a34f7c0418003fe34feafcbeaef348a800a0d908a7a6809cc7304017d820f70f0474d5e23cb17e38b67dc6dca282c6ca00961f4ec9edf2738d0f087b1d81e4871ef08e1798010863afb4eac4c44a376cb343be929c5be66a78cfd4456ae9ec6a99d97f4e1c3ff3583351db2147a65c0acef5c003fb544ab3a2e2dc4d43646f58b811a6c3a369d1f"
+const revokedSubkeyHex = "988d04533121f6010400aefc803a3e4bb1a61c86e8a86d2726c6a43e0079e9f2713f1fa017e9854c83877f4aced8e331d675c67ea83ddab80aacbfa0b9040bb12d96f5a3d6be09455e2a76546cbd21677537db941cab710216b6d24ec277ee0bd65b910f416737ed120f6b93a9d3b306245c8cfd8394606fdb462e5cf43c551438d2864506c63367fc890011010001b41d416c696365203c616c69636540626d626172697374612e636f2e61753e88bb041301020025021b03060b090807030206150802090a0b0416020301021e01021780050253312798021901000a09104ef7e4beccde97f015a803ff5448437780f63263b0df8442a995e7f76c221351a51edd06f2063d8166cf3157aada4923dfc44aa0f2a6a4da5cf83b7fe722ba8ab416c976e77c6b5682e7f1069026673bd0de56ba06fd5d7a9f177607f277d9b55ff940a638c3e68525c67517e2b3d976899b93ca267f705b3e5efad7d61220e96b618a4497eab8d04403d23f8846041011020006050253312910000a09107b15a67f0b3ddc03d96e009f50b6365d86c4be5d5e9d0ea42d5e56f5794c617700a0ab274e19c2827780016d23417ce89e0a2c0d987d889c04100102000605025331cf7a000a0910a401d9f09a34f7c0ee970400aca292f213041c9f3b3fc49148cbda9d84afee6183c8dd6c5ff2600b29482db5fecd4303797be1ee6d544a20a858080fec43412061c9a71fae4039fd58013b4ae341273e6c66ad4c7cdd9e68245bedb260562e7b166f2461a1032f2b38c0e0e5715fb3d1656979e052b55ca827a76f872b78a9fdae64bc298170bfcebedc1271b41a416c696365203c616c696365407379646973702e6f722e61753e88b804130102002205025331278b021b03060b090807030206150802090a0b0416020301021e01021780000a09104ef7e4beccde97f06a7003fa03c3af68d272ebc1fa08aa72a03b02189c26496a2833d90450801c4e42c5b5f51ad96ce2d2c9cef4b7c02a6a2fcf1412d6a2d486098eb762f5010a201819c17fd2888aec8eda20c65a3b75744de7ee5cc8ac7bfc470cbe3cb982720405a27a3c6a8c229cfe36905f881b02ed5680f6a8f05866efb9d6c5844897e631deb949ca8846041011020006050253312910000a09107b15a67f0b3ddc0347bc009f7fa35db59147469eb6f2c5aaf6428accb138b22800a0caa2f5f0874bacc5909c652a57a31beda65eddd5889c04100102000605025331cf7a000a0910a401d9f09a34f7c0316403ff46f2a5c101256627f16384d34a38fb47a6c88ba60506843e532d91614339fccae5f884a5741e7582ffaf292ba38ee10a270a05f139bde3814b6a077e8cd2db0f105ebea2a83af70d385f13b507fac2ad93ff79d84950328bb86f3074745a8b7f9b64990fb142e2a12976e27e8d09a28dc5621f957ac49091116da410ac3cbde1b88d04533121f6010400cbd785b56905e4192e2fb62a720727d43c4fa487821203cf72138b884b78b701093243e1d8c92a0248a6c0203a5a88693da34af357499abacaf4b3309c640797d03093870a323b4b6f37865f6eaa2838148a67df4735d43a90ca87942554cdf1c4a751b1e75f9fd4ce4e97e278d6c1c7ed59d33441df7d084f3f02beb68896c70011010001889f0418010200090502533121f6021b0c000a09104ef7e4beccde97f0b98b03fc0a5ccf6a372995835a2f5da33b282a7d612c0ab2a97f59cf9fff73e9110981aac2858c41399afa29624a7fd8a0add11654e3d882c0fd199e161bdad65e5e2548f7b68a437ea64293db1246e3011cbb94dc1bcdeaf0f2539bd88ff16d95547144d97cead6a8c5927660a91e6db0d16eb36b7b49a3525b54d1644e65599b032b7eb901a204533127a0110400bd3edaa09eff9809c4edc2c2a0ebe52e53c50a19c1e49ab78e6167bf61473bb08f2050d78a5cbbc6ed66aff7b42cd503f16b4a0b99fa1609681fca9b7ce2bbb1a5b3864d6cdda4d7ef7849d156d534dea30fb0efb9e4cf8959a2b2ce623905882d5430b995a15c3b9fe92906086788b891002924f94abe139b42cbbfaaabe42f00a0b65dc1a1ad27d798adbcb5b5ad02d2688c89477b03ff4eebb6f7b15a73b96a96bed201c0e5e4ea27e4c6e2dd1005b94d4b90137a5b1cf5e01c6226c070c4cc999938101578877ee76d296b9aab8246d57049caacf489e80a3f40589cade790a020b1ac146d6f7a6241184b8c7fcde680eae3188f5dcbe846d7f7bdad34f6fcfca08413e19c1d5df83fc7c7c627d493492e009c2f52a80400a2fe82de87136fd2e8845888c4431b032ba29d9a29a804277e31002a8201fb8591a3e55c7a0d0881496caf8b9fb07544a5a4879291d0dc026a0ea9e5bd88eb4aa4947bbd694b25012e208a250d65ddc6f1eea59d3aed3b4ec15fcab85e2afaa23a40ab1ef9ce3e11e1bc1c34a0e758e7aa64deb8739276df0af7d4121f834a9b88e70418010200090502533127a0021b02005209104ef7e4beccde97f047200419110200060502533127a0000a0910dbce4ee19529437fe045009c0b32f5ead48ee8a7e98fac0dea3d3e6c0e2c552500a0ad71fadc5007cfaf842d9b7db3335a8cdad15d3d1a6404009b08e2c68fe8f3b45c1bb72a4b3278cdf3012aa0f229883ad74aa1f6000bb90b18301b2f85372ca5d6b9bf478d235b733b1b197d19ccca48e9daf8e890cb64546b4ce1b178faccfff07003c172a2d4f5ebaba9f57153955f3f61a9b80a4f5cb959908f8b211b03b7026a8a82fc612bfedd3794969bcf458c4ce92be215a1176ab88d045331d144010400a5063000c5aaf34953c1aa3bfc95045b3aab9882b9a8027fecfe2142dc6b47ba8aca667399990244d513dd0504716908c17d92c65e74219e004f7b83fc125e575dd58efec3ab6dd22e3580106998523dea42ec75bf9aa111734c82df54630bebdff20fe981cfc36c76f865eb1c2fb62c9e85bc3a6e5015a361a2eb1c8431578d0011010001889f04280102000905025331d433021d03000a09104ef7e4beccde97f02e5503ff5e0630d1b65291f4882b6d40a29da4616bb5088717d469fbcc3648b8276de04a04988b1f1b9f3e18f52265c1f8b6c85861691c1a6b8a3a25a1809a0b32ad330aec5667cb4262f4450649184e8113849b05e5ad06a316ea80c001e8e71838190339a6e48bbde30647bcf245134b9a97fa875c1d83a9862cae87ffd7e2c4ce3a1b89013d04180102000905025331d144021b0200a809104ef7e4beccde97f09d2004190102000605025331d144000a0910677815e371c2fd23522203fe22ab62b8e7a151383cea3edd3a12995693911426f8ccf125e1f6426388c0010f88d9ca7da2224aee8d1c12135998640c5e1813d55a93df472faae75bef858457248db41b4505827590aeccf6f9eb646da7f980655dd3050c6897feddddaca90676dee856d66db8923477d251712bb9b3186b4d0114daf7d6b59272b53218dd1da94a03ff64006fcbe71211e5daecd9961fba66cdb6de3f914882c58ba5beddeba7dcb950c1156d7fba18c19ea880dccc800eae335deec34e3b84ac75ffa24864f782f87815cda1c0f634b3dd2fa67cea30811d21723d21d9551fa12ccbcfa62b6d3a15d01307b99925707992556d50065505b090aadb8579083a20fe65bd2a270da9b011"
+const missingCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Charset: UTF-8
+
+mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY
+ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG
+zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54
+QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ
+QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo
+9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu
+Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/
+dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R
+JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL
+ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew
+RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW
+/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu
+yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAJcXQeP+NmuciE99YcJoffxv
+2gVLU4ZXBNHEaP0mgaJ1+tmMD089vUQAcyGRvw8jfsNsVZQIOAuRxY94aHQhIRHR
+bUzBN28ofo/AJJtfx62C15xt6fDKRV6HXYqAiygrHIpEoRLyiN69iScUsjIJeyFL
+C8wa72e8pSL6dkHoaV1N9ZH/xmrJ+k0vsgkQaAh9CzYufncDxcwkoP+aOlGtX1gP
+WwWoIbz0JwLEMPHBWvDDXQcQPQTYQyj+LGC9U6f9VZHN25E94subM1MjuT9OhN9Y
+MLfWaaIc5WyhLFyQKW2Upofn9wSFi8ubyBnv640Dfd0rVmaWv7LNTZpoZ/GbJAMA
+EQEAAYkBHwQYAQIACQUCU5ygeQIbAgAKCRDt1A0FCB6SP0zCB/sEzaVR38vpx+OQ
+MMynCBJrakiqDmUZv9xtplY7zsHSQjpd6xGflbU2n+iX99Q+nav0ETQZifNUEd4N
+1ljDGQejcTyKD6Pkg6wBL3x9/RJye7Zszazm4+toJXZ8xJ3800+BtaPoI39akYJm
++ijzbskvN0v/j5GOFJwQO0pPRAFtdHqRs9Kf4YanxhedB4dIUblzlIJuKsxFit6N
+lgGRblagG3Vv2eBszbxzPbJjHCgVLR3RmrVezKOsZjr/2i7X+xLWIR0uD3IN1qOW
+CXQxLBizEEmSNVNxsp7KPGTLnqO3bPtqFirxS9PJLIMPTPLNBY7ZYuPNTMqVIUWF
+4artDmrG
+=7FfJ
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const invalidCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQENBFMYynYBCACVOZ3/e8Bm2b9KH9QyIlHGo/i1bnkpqsgXj8tpJ2MIUOnXMMAY
+ztW7kKFLCmgVdLIC0vSoLA4yhaLcMojznh/2CcUglZeb6Ao8Gtelr//Rd5DRfPpG
+zqcfUo+m+eO1co2Orabw0tZDfGpg5p3AYl0hmxhUyYSc/xUq93xL1UJzBFgYXY54
+QsM8dgeQgFseSk/YvdP5SMx1ev+eraUyiiUtWzWrWC1TdyRa5p4UZg6Rkoppf+WJ
+QrW6BWrhAtqATHc8ozV7uJjeONjUEq24roRc/OFZdmQQGK6yrzKnnbA6MdHhqpdo
+9kWDcXYb7pSE63Lc+OBa5X2GUVvXJLS/3nrtABEBAAG0F2ludmFsaWQtc2lnbmlu
+Zy1zdWJrZXlziQEoBBMBAgASBQJTnKB5AhsBAgsHAhUIAh4BAAoJEO3UDQUIHpI/
+dN4H/idX4FQ1LIZCnpHS/oxoWQWfpRgdKAEM0qCqjMgiipJeEwSQbqjTCynuh5/R
+JlODDz85ABR06aoF4l5ebGLQWFCYifPnJZ/Yf5OYcMGtb7dIbqxWVFL9iLMO/oDL
+ioI3dotjPui5e+2hI9pVH1UHB/bZ/GvMGo6Zg0XxLPolKQODMVjpjLAQ0YJ3spew
+RAmOGre6tIvbDsMBnm8qREt7a07cBJ6XK7xjxYaZHQBiHVxyEWDa6gyANONx8duW
+/fhQ/zDTnyVM/ik6VO0Ty9BhPpcEYLFwh5c1ilFari1ta3e6qKo6ZGa9YMk/REhu
+yBHd9nTkI+0CiQUmbckUiVjDKKe5AQ0EUxjKdgEIAIINDqlj7X6jYKc6DjwrOkjQ
+UIRWbQQar0LwmNilehmt70g5DCL1SYm9q4LcgJJ2Nhxj0/5qqsYib50OSWMcKeEe
+iRXpXzv1ObpcQtI5ithp0gR53YPXBib80t3bUzomQ5UyZqAAHzMp3BKC54/vUrSK
+FeRaxDzNLrCeyI00+LHNUtwghAqHvdNcsIf8VRumK8oTm3RmDh0TyjASWYbrt9c8
+R1Um3zuoACOVy+mEIgIzsfHq0u7dwYwJB5+KeM7ZLx+HGIYdUYzHuUE1sLwVoELh
++SHIGHI1HDicOjzqgajShuIjj5hZTyQySVprrsLKiXS6NEwHAP20+XjayJ/R3tEA
+EQEAAYkCPgQYAQIBKAUCU5ygeQIbAsBdIAQZAQIABgUCU5ygeQAKCRCpVlnFZmhO
+52RJB/9uD1MSa0wjY6tHOIgquZcP3bHBvHmrHNMw9HR2wRCMO91ZkhrpdS3ZHtgb
+u3/55etj0FdvDo1tb8P8FGSVtO5Vcwf5APM8sbbqoi8L951Q3i7qt847lfhu6sMl
+w0LWFvPTOLHrliZHItPRjOltS1WAWfr2jUYhsU9ytaDAJmvf9DujxEOsN5G1YJep
+54JCKVCkM/y585Zcnn+yxk/XwqoNQ0/iJUT9qRrZWvoeasxhl1PQcwihCwss44A+
+YXaAt3hbk+6LEQuZoYS73yR3WHj+42tfm7YxRGeubXfgCEz/brETEWXMh4pe0vCL
+bfWrmfSPq2rDegYcAybxRQz0lF8PAAoJEO3UDQUIHpI/exkH/0vQfdHA8g/N4T6E
+i6b1CUVBAkvtdJpCATZjWPhXmShOw62gkDw306vHPilL4SCvEEi4KzG72zkp6VsB
+DSRcpxCwT4mHue+duiy53/aRMtSJ+vDfiV1Vhq+3sWAck/yUtfDU9/u4eFaiNok1
+8/Gd7reyuZt5CiJnpdPpjCwelK21l2w7sHAnJF55ITXdOxI8oG3BRKufz0z5lyDY
+s2tXYmhhQIggdgelN8LbcMhWs/PBbtUr6uZlNJG2lW1yscD4aI529VjwJlCeo745
+U7pO4eF05VViUJ2mmfoivL3tkhoTUWhx8xs8xCUcCg8DoEoSIhxtOmoTPR22Z9BL
+6LCg2mg=
+=Dhm4
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const goodCrossSignatureKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mI0EVUqeVwEEAMufHRrMPWK3gyvi0O0tABCs/oON9zV9KDZlr1a1M91ShCSFwCPo
+7r80PxdWVWcj0V5h50/CJYtpN3eE/mUIgW2z1uDYQF1OzrQ8ubrksfsJvpAhENom
+lTQEppv9mV8qhcM278teb7TX0pgrUHLYF5CfPdp1L957JLLXoQR/lwLVABEBAAG0
+E2dvb2Qtc2lnbmluZy1zdWJrZXmIuAQTAQIAIgUCVUqeVwIbAwYLCQgHAwIGFQgC
+CQoLBBYCAwECHgECF4AACgkQNRjL95IRWP69XQQAlH6+eyXJN4DZTLX78KGjHrsw
+6FCvxxClEPtPUjcJy/1KCRQmtLAt9PbbA78dvgzjDeZMZqRAwdjyJhjyg/fkU2OH
+7wq4ktjUu+dLcOBb+BFMEY+YjKZhf6EJuVfxoTVr5f82XNPbYHfTho9/OABKH6kv
+X70PaKZhbwnwij8Nts65AaIEVUqftREEAJ3WxZfqAX0bTDbQPf2CMT2IVMGDfhK7
+GyubOZgDFFjwUJQvHNvsrbeGLZ0xOBumLINyPO1amIfTgJNm1iiWFWfmnHReGcDl
+y5mpYG60Mb79Whdcer7CMm3AqYh/dW4g6IB02NwZMKoUHo3PXmFLxMKXnWyJ0clw
+R0LI/Qn509yXAKDh1SO20rqrBM+EAP2c5bfI98kyNwQAi3buu94qo3RR1ZbvfxgW
+CKXDVm6N99jdZGNK7FbRifXqzJJDLcXZKLnstnC4Sd3uyfyf1uFhmDLIQRryn5m+
+LBYHfDBPN3kdm7bsZDDq9GbTHiFZUfm/tChVKXWxkhpAmHhU/tH6GGzNSMXuIWSO
+aOz3Rqq0ED4NXyNKjdF9MiwD/i83S0ZBc0LmJYt4Z10jtH2B6tYdqnAK29uQaadx
+yZCX2scE09UIm32/w7pV77CKr1Cp/4OzAXS1tmFzQ+bX7DR+Gl8t4wxr57VeEMvl
+BGw4Vjh3X8//m3xynxycQU18Q1zJ6PkiMyPw2owZ/nss3hpSRKFJsxMLhW3fKmKr
+Ey2KiOcEGAECAAkFAlVKn7UCGwIAUgkQNRjL95IRWP5HIAQZEQIABgUCVUqftQAK
+CRD98VjDN10SqkWrAKDTpEY8D8HC02E/KVC5YUI01B30wgCgurpILm20kXEDCeHp
+C5pygfXw1DJrhAP+NyPJ4um/bU1I+rXaHHJYroYJs8YSweiNcwiHDQn0Engh/mVZ
+SqLHvbKh2dL/RXymC3+rjPvQf5cup9bPxNMa6WagdYBNAfzWGtkVISeaQW+cTEp/
+MtgVijRGXR/lGLGETPg2X3Afwn9N9bLMBkBprKgbBqU7lpaoPupxT61bL70=
+=vtbN
+-----END PGP PUBLIC KEY BLOCK-----`
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/compressed.go b/vendor/golang.org/x/crypto/openpgp/packet/compressed.go
new file mode 100644
index 000000000..e8f0b5caa
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/compressed.go
@@ -0,0 +1,123 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "compress/bzip2"
+ "compress/flate"
+ "compress/zlib"
+ "golang.org/x/crypto/openpgp/errors"
+ "io"
+ "strconv"
+)
+
+// Compressed represents a compressed OpenPGP packet. The decompressed contents
+// will contain more OpenPGP packets. See RFC 4880, section 5.6.
+type Compressed struct {
+ Body io.Reader
+}
+
+const (
+ NoCompression = flate.NoCompression
+ BestSpeed = flate.BestSpeed
+ BestCompression = flate.BestCompression
+ DefaultCompression = flate.DefaultCompression
+)
+
+// CompressionConfig contains compressor configuration settings.
+type CompressionConfig struct {
+ // Level is the compression level to use. It must be set to
+ // between -1 and 9, with -1 causing the compressor to use the
+ // default compression level, 0 causing the compressor to use
+ // no compression and 1 to 9 representing increasing (better,
+ // slower) compression levels. If Level is less than -1 or
+ // more then 9, a non-nil error will be returned during
+ // encryption. See the constants above for convenient common
+ // settings for Level.
+ Level int
+}
+
+func (c *Compressed) parse(r io.Reader) error {
+ var buf [1]byte
+ _, err := readFull(r, buf[:])
+ if err != nil {
+ return err
+ }
+
+ switch buf[0] {
+ case 1:
+ c.Body = flate.NewReader(r)
+ case 2:
+ c.Body, err = zlib.NewReader(r)
+ case 3:
+ c.Body = bzip2.NewReader(r)
+ default:
+ err = errors.UnsupportedError("unknown compression algorithm: " + strconv.Itoa(int(buf[0])))
+ }
+
+ return err
+}
+
+// compressedWriterCloser represents the serialized compression stream
+// header and the compressor. Its Close() method ensures that both the
+// compressor and serialized stream header are closed. Its Write()
+// method writes to the compressor.
+type compressedWriteCloser struct {
+ sh io.Closer // Stream Header
+ c io.WriteCloser // Compressor
+}
+
+func (cwc compressedWriteCloser) Write(p []byte) (int, error) {
+ return cwc.c.Write(p)
+}
+
+func (cwc compressedWriteCloser) Close() (err error) {
+ err = cwc.c.Close()
+ if err != nil {
+ return err
+ }
+
+ return cwc.sh.Close()
+}
+
+// SerializeCompressed serializes a compressed data packet to w and
+// returns a WriteCloser to which the literal data packets themselves
+// can be written and which MUST be closed on completion. If cc is
+// nil, sensible defaults will be used to configure the compression
+// algorithm.
+func SerializeCompressed(w io.WriteCloser, algo CompressionAlgo, cc *CompressionConfig) (literaldata io.WriteCloser, err error) {
+ compressed, err := serializeStreamHeader(w, packetTypeCompressed)
+ if err != nil {
+ return
+ }
+
+ _, err = compressed.Write([]byte{uint8(algo)})
+ if err != nil {
+ return
+ }
+
+ level := DefaultCompression
+ if cc != nil {
+ level = cc.Level
+ }
+
+ var compressor io.WriteCloser
+ switch algo {
+ case CompressionZIP:
+ compressor, err = flate.NewWriter(compressed, level)
+ case CompressionZLIB:
+ compressor, err = zlib.NewWriterLevel(compressed, level)
+ default:
+ s := strconv.Itoa(int(algo))
+ err = errors.UnsupportedError("Unsupported compression algorithm: " + s)
+ }
+ if err != nil {
+ return
+ }
+
+ literaldata = compressedWriteCloser{compressed, compressor}
+
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/compressed_test.go b/vendor/golang.org/x/crypto/openpgp/packet/compressed_test.go
new file mode 100644
index 000000000..cb2d70bd4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/compressed_test.go
@@ -0,0 +1,41 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+func TestCompressed(t *testing.T) {
+ packet, err := Read(readerFromHex(compressedHex))
+ if err != nil {
+ t.Errorf("failed to read Compressed: %s", err)
+ return
+ }
+
+ c, ok := packet.(*Compressed)
+ if !ok {
+ t.Error("didn't find Compressed packet")
+ return
+ }
+
+ contents, err := ioutil.ReadAll(c.Body)
+ if err != nil && err != io.EOF {
+ t.Error(err)
+ return
+ }
+
+ expected, _ := hex.DecodeString(compressedExpectedHex)
+ if !bytes.Equal(expected, contents) {
+ t.Errorf("got:%x want:%x", contents, expected)
+ }
+}
+
+const compressedHex = "a3013b2d90c4e02b72e25f727e5e496a5e49b11e1700"
+const compressedExpectedHex = "cb1062004d14c8fe636f6e74656e74732e0a"
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/config.go b/vendor/golang.org/x/crypto/openpgp/packet/config.go
new file mode 100644
index 000000000..c76eecc96
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/config.go
@@ -0,0 +1,91 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "crypto/rand"
+ "io"
+ "time"
+)
+
+// Config collects a number of parameters along with sensible defaults.
+// A nil *Config is valid and results in all default values.
+type Config struct {
+ // Rand provides the source of entropy.
+ // If nil, the crypto/rand Reader is used.
+ Rand io.Reader
+ // DefaultHash is the default hash function to be used.
+ // If zero, SHA-256 is used.
+ DefaultHash crypto.Hash
+ // DefaultCipher is the cipher to be used.
+ // If zero, AES-128 is used.
+ DefaultCipher CipherFunction
+ // Time returns the current time as the number of seconds since the
+ // epoch. If Time is nil, time.Now is used.
+ Time func() time.Time
+ // DefaultCompressionAlgo is the compression algorithm to be
+ // applied to the plaintext before encryption. If zero, no
+ // compression is done.
+ DefaultCompressionAlgo CompressionAlgo
+ // CompressionConfig configures the compression settings.
+ CompressionConfig *CompressionConfig
+ // S2KCount is only used for symmetric encryption. It
+ // determines the strength of the passphrase stretching when
+ // the said passphrase is hashed to produce a key. S2KCount
+ // should be between 1024 and 65011712, inclusive. If Config
+ // is nil or S2KCount is 0, the value 65536 used. Not all
+ // values in the above range can be represented. S2KCount will
+ // be rounded up to the next representable value if it cannot
+ // be encoded exactly. When set, it is strongly encrouraged to
+ // use a value that is at least 65536. See RFC 4880 Section
+ // 3.7.1.3.
+ S2KCount int
+ // RSABits is the number of bits in new RSA keys made with NewEntity.
+ // If zero, then 2048 bit keys are created.
+ RSABits int
+}
+
+func (c *Config) Random() io.Reader {
+ if c == nil || c.Rand == nil {
+ return rand.Reader
+ }
+ return c.Rand
+}
+
+func (c *Config) Hash() crypto.Hash {
+ if c == nil || uint(c.DefaultHash) == 0 {
+ return crypto.SHA256
+ }
+ return c.DefaultHash
+}
+
+func (c *Config) Cipher() CipherFunction {
+ if c == nil || uint8(c.DefaultCipher) == 0 {
+ return CipherAES128
+ }
+ return c.DefaultCipher
+}
+
+func (c *Config) Now() time.Time {
+ if c == nil || c.Time == nil {
+ return time.Now()
+ }
+ return c.Time()
+}
+
+func (c *Config) Compression() CompressionAlgo {
+ if c == nil {
+ return CompressionNone
+ }
+ return c.DefaultCompressionAlgo
+}
+
+func (c *Config) PasswordHashIterations() int {
+ if c == nil || c.S2KCount == 0 {
+ return 0
+ }
+ return c.S2KCount
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go
new file mode 100644
index 000000000..266840d05
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key.go
@@ -0,0 +1,199 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto/rsa"
+ "encoding/binary"
+ "io"
+ "math/big"
+ "strconv"
+
+ "golang.org/x/crypto/openpgp/elgamal"
+ "golang.org/x/crypto/openpgp/errors"
+)
+
+const encryptedKeyVersion = 3
+
+// EncryptedKey represents a public-key encrypted session key. See RFC 4880,
+// section 5.1.
+type EncryptedKey struct {
+ KeyId uint64
+ Algo PublicKeyAlgorithm
+ CipherFunc CipherFunction // only valid after a successful Decrypt
+ Key []byte // only valid after a successful Decrypt
+
+ encryptedMPI1, encryptedMPI2 parsedMPI
+}
+
+func (e *EncryptedKey) parse(r io.Reader) (err error) {
+ var buf [10]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ if buf[0] != encryptedKeyVersion {
+ return errors.UnsupportedError("unknown EncryptedKey version " + strconv.Itoa(int(buf[0])))
+ }
+ e.KeyId = binary.BigEndian.Uint64(buf[1:9])
+ e.Algo = PublicKeyAlgorithm(buf[9])
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
+ case PubKeyAlgoElGamal:
+ e.encryptedMPI1.bytes, e.encryptedMPI1.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ e.encryptedMPI2.bytes, e.encryptedMPI2.bitLength, err = readMPI(r)
+ }
+ _, err = consumeAll(r)
+ return
+}
+
+func checksumKeyMaterial(key []byte) uint16 {
+ var checksum uint16
+ for _, v := range key {
+ checksum += uint16(v)
+ }
+ return checksum
+}
+
+// Decrypt decrypts an encrypted session key with the given private key. The
+// private key must have been decrypted first.
+// If config is nil, sensible defaults will be used.
+func (e *EncryptedKey) Decrypt(priv *PrivateKey, config *Config) error {
+ var err error
+ var b []byte
+
+ // TODO(agl): use session key decryption routines here to avoid
+ // padding oracle attacks.
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ b, err = rsa.DecryptPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), e.encryptedMPI1.bytes)
+ case PubKeyAlgoElGamal:
+ c1 := new(big.Int).SetBytes(e.encryptedMPI1.bytes)
+ c2 := new(big.Int).SetBytes(e.encryptedMPI2.bytes)
+ b, err = elgamal.Decrypt(priv.PrivateKey.(*elgamal.PrivateKey), c1, c2)
+ default:
+ err = errors.InvalidArgumentError("cannot decrypted encrypted session key with private key of type " + strconv.Itoa(int(priv.PubKeyAlgo)))
+ }
+
+ if err != nil {
+ return err
+ }
+
+ e.CipherFunc = CipherFunction(b[0])
+ e.Key = b[1 : len(b)-2]
+ expectedChecksum := uint16(b[len(b)-2])<<8 | uint16(b[len(b)-1])
+ checksum := checksumKeyMaterial(e.Key)
+ if checksum != expectedChecksum {
+ return errors.StructuralError("EncryptedKey checksum incorrect")
+ }
+
+ return nil
+}
+
+// Serialize writes the encrypted key packet, e, to w.
+func (e *EncryptedKey) Serialize(w io.Writer) error {
+ var mpiLen int
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ mpiLen = 2 + len(e.encryptedMPI1.bytes)
+ case PubKeyAlgoElGamal:
+ mpiLen = 2 + len(e.encryptedMPI1.bytes) + 2 + len(e.encryptedMPI2.bytes)
+ default:
+ return errors.InvalidArgumentError("don't know how to serialize encrypted key type " + strconv.Itoa(int(e.Algo)))
+ }
+
+ serializeHeader(w, packetTypeEncryptedKey, 1 /* version */ +8 /* key id */ +1 /* algo */ +mpiLen)
+
+ w.Write([]byte{encryptedKeyVersion})
+ binary.Write(w, binary.BigEndian, e.KeyId)
+ w.Write([]byte{byte(e.Algo)})
+
+ switch e.Algo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ writeMPIs(w, e.encryptedMPI1)
+ case PubKeyAlgoElGamal:
+ writeMPIs(w, e.encryptedMPI1, e.encryptedMPI2)
+ default:
+ panic("internal error")
+ }
+
+ return nil
+}
+
+// SerializeEncryptedKey serializes an encrypted key packet to w that contains
+// key, encrypted to pub.
+// If config is nil, sensible defaults will be used.
+func SerializeEncryptedKey(w io.Writer, pub *PublicKey, cipherFunc CipherFunction, key []byte, config *Config) error {
+ var buf [10]byte
+ buf[0] = encryptedKeyVersion
+ binary.BigEndian.PutUint64(buf[1:9], pub.KeyId)
+ buf[9] = byte(pub.PubKeyAlgo)
+
+ keyBlock := make([]byte, 1 /* cipher type */ +len(key)+2 /* checksum */)
+ keyBlock[0] = byte(cipherFunc)
+ copy(keyBlock[1:], key)
+ checksum := checksumKeyMaterial(key)
+ keyBlock[1+len(key)] = byte(checksum >> 8)
+ keyBlock[1+len(key)+1] = byte(checksum)
+
+ switch pub.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly:
+ return serializeEncryptedKeyRSA(w, config.Random(), buf, pub.PublicKey.(*rsa.PublicKey), keyBlock)
+ case PubKeyAlgoElGamal:
+ return serializeEncryptedKeyElGamal(w, config.Random(), buf, pub.PublicKey.(*elgamal.PublicKey), keyBlock)
+ case PubKeyAlgoDSA, PubKeyAlgoRSASignOnly:
+ return errors.InvalidArgumentError("cannot encrypt to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+ }
+
+ return errors.UnsupportedError("encrypting a key to public key of type " + strconv.Itoa(int(pub.PubKeyAlgo)))
+}
+
+func serializeEncryptedKeyRSA(w io.Writer, rand io.Reader, header [10]byte, pub *rsa.PublicKey, keyBlock []byte) error {
+ cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)
+ if err != nil {
+ return errors.InvalidArgumentError("RSA encryption failed: " + err.Error())
+ }
+
+ packetLen := 10 /* header length */ + 2 /* mpi size */ + len(cipherText)
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ return writeMPI(w, 8*uint16(len(cipherText)), cipherText)
+}
+
+func serializeEncryptedKeyElGamal(w io.Writer, rand io.Reader, header [10]byte, pub *elgamal.PublicKey, keyBlock []byte) error {
+ c1, c2, err := elgamal.Encrypt(rand, pub, keyBlock)
+ if err != nil {
+ return errors.InvalidArgumentError("ElGamal encryption failed: " + err.Error())
+ }
+
+ packetLen := 10 /* header length */
+ packetLen += 2 /* mpi size */ + (c1.BitLen()+7)/8
+ packetLen += 2 /* mpi size */ + (c2.BitLen()+7)/8
+
+ err = serializeHeader(w, packetTypeEncryptedKey, packetLen)
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(header[:])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, c1)
+ if err != nil {
+ return err
+ }
+ return writeBig(w, c2)
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go
new file mode 100644
index 000000000..fee14cf3c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/encrypted_key_test.go
@@ -0,0 +1,146 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/rsa"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "testing"
+)
+
+func bigFromBase10(s string) *big.Int {
+ b, ok := new(big.Int).SetString(s, 10)
+ if !ok {
+ panic("bigFromBase10 failed")
+ }
+ return b
+}
+
+var encryptedKeyPub = rsa.PublicKey{
+ E: 65537,
+ N: bigFromBase10("115804063926007623305902631768113868327816898845124614648849934718568541074358183759250136204762053879858102352159854352727097033322663029387610959884180306668628526686121021235757016368038585212410610742029286439607686208110250133174279811431933746643015923132833417396844716207301518956640020862630546868823"),
+}
+
+var encryptedKeyRSAPriv = &rsa.PrivateKey{
+ PublicKey: encryptedKeyPub,
+ D: bigFromBase10("32355588668219869544751561565313228297765464314098552250409557267371233892496951383426602439009993875125222579159850054973310859166139474359774543943714622292329487391199285040721944491839695981199720170366763547754915493640685849961780092241140181198779299712578774460837139360803883139311171713302987058393"),
+}
+
+var encryptedKeyPriv = &PrivateKey{
+ PublicKey: PublicKey{
+ PubKeyAlgo: PubKeyAlgoRSA,
+ },
+ PrivateKey: encryptedKeyRSAPriv,
+}
+
+func TestDecryptingEncryptedKey(t *testing.T) {
+ const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+ const expectedKeyHex = "d930363f7e0308c333b9618617ea728963d8df993665ae7be1092d4926fd864b"
+
+ p, err := Read(readerFromHex(encryptedKeyHex))
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+ return
+ }
+
+ if ek.KeyId != 0x2a67d68660df41c7 || ek.Algo != PubKeyAlgoRSA {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ err = ek.Decrypt(encryptedKeyPriv, nil)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ if ek.CipherFunc != CipherAES256 {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ keyHex := fmt.Sprintf("%x", ek.Key)
+ if keyHex != expectedKeyHex {
+ t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
+ }
+}
+
+func TestEncryptingEncryptedKey(t *testing.T) {
+ key := []byte{1, 2, 3, 4}
+ const expectedKeyHex = "01020304"
+ const keyId = 42
+
+ pub := &PublicKey{
+ PublicKey: &encryptedKeyPub,
+ KeyId: keyId,
+ PubKeyAlgo: PubKeyAlgoRSAEncryptOnly,
+ }
+
+ buf := new(bytes.Buffer)
+ err := SerializeEncryptedKey(buf, pub, CipherAES128, key, nil)
+ if err != nil {
+ t.Errorf("error writing encrypted key packet: %s", err)
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Errorf("didn't parse an EncryptedKey, got %#v", p)
+ return
+ }
+
+ if ek.KeyId != keyId || ek.Algo != PubKeyAlgoRSAEncryptOnly {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ err = ek.Decrypt(encryptedKeyPriv, nil)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ if ek.CipherFunc != CipherAES128 {
+ t.Errorf("unexpected EncryptedKey contents: %#v", ek)
+ return
+ }
+
+ keyHex := fmt.Sprintf("%x", ek.Key)
+ if keyHex != expectedKeyHex {
+ t.Errorf("bad key, got %s want %x", keyHex, expectedKeyHex)
+ }
+}
+
+func TestSerializingEncryptedKey(t *testing.T) {
+ const encryptedKeyHex = "c18c032a67d68660df41c70104005789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8"
+
+ p, err := Read(readerFromHex(encryptedKeyHex))
+ if err != nil {
+ t.Fatalf("error from Read: %s", err)
+ }
+ ek, ok := p.(*EncryptedKey)
+ if !ok {
+ t.Fatalf("didn't parse an EncryptedKey, got %#v", p)
+ }
+
+ var buf bytes.Buffer
+ ek.Serialize(&buf)
+
+ if bufHex := hex.EncodeToString(buf.Bytes()); bufHex != encryptedKeyHex {
+ t.Fatalf("serialization of encrypted key differed from original. Original was %s, but reserialized as %s", encryptedKeyHex, bufHex)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/literal.go b/vendor/golang.org/x/crypto/openpgp/packet/literal.go
new file mode 100644
index 000000000..1a9ec6e51
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/literal.go
@@ -0,0 +1,89 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "encoding/binary"
+ "io"
+)
+
+// LiteralData represents an encrypted file. See RFC 4880, section 5.9.
+type LiteralData struct {
+ IsBinary bool
+ FileName string
+ Time uint32 // Unix epoch time. Either creation time or modification time. 0 means undefined.
+ Body io.Reader
+}
+
+// ForEyesOnly returns whether the contents of the LiteralData have been marked
+// as especially sensitive.
+func (l *LiteralData) ForEyesOnly() bool {
+ return l.FileName == "_CONSOLE"
+}
+
+func (l *LiteralData) parse(r io.Reader) (err error) {
+ var buf [256]byte
+
+ _, err = readFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+
+ l.IsBinary = buf[0] == 'b'
+ fileNameLen := int(buf[1])
+
+ _, err = readFull(r, buf[:fileNameLen])
+ if err != nil {
+ return
+ }
+
+ l.FileName = string(buf[:fileNameLen])
+
+ _, err = readFull(r, buf[:4])
+ if err != nil {
+ return
+ }
+
+ l.Time = binary.BigEndian.Uint32(buf[:4])
+ l.Body = r
+ return
+}
+
+// SerializeLiteral serializes a literal data packet to w and returns a
+// WriteCloser to which the data itself can be written and which MUST be closed
+// on completion. The fileName is truncated to 255 bytes.
+func SerializeLiteral(w io.WriteCloser, isBinary bool, fileName string, time uint32) (plaintext io.WriteCloser, err error) {
+ var buf [4]byte
+ buf[0] = 't'
+ if isBinary {
+ buf[0] = 'b'
+ }
+ if len(fileName) > 255 {
+ fileName = fileName[:255]
+ }
+ buf[1] = byte(len(fileName))
+
+ inner, err := serializeStreamHeader(w, packetTypeLiteralData)
+ if err != nil {
+ return
+ }
+
+ _, err = inner.Write(buf[:2])
+ if err != nil {
+ return
+ }
+ _, err = inner.Write([]byte(fileName))
+ if err != nil {
+ return
+ }
+ binary.BigEndian.PutUint32(buf[:], time)
+ _, err = inner.Write(buf[:])
+ if err != nil {
+ return
+ }
+
+ plaintext = inner
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go b/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go
new file mode 100644
index 000000000..ce2a33a54
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go
@@ -0,0 +1,143 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
+
+package packet
+
+import (
+ "crypto/cipher"
+)
+
+type ocfbEncrypter struct {
+ b cipher.Block
+ fre []byte
+ outUsed int
+}
+
+// An OCFBResyncOption determines if the "resynchronization step" of OCFB is
+// performed.
+type OCFBResyncOption bool
+
+const (
+ OCFBResync OCFBResyncOption = true
+ OCFBNoResync OCFBResyncOption = false
+)
+
+// NewOCFBEncrypter returns a cipher.Stream which encrypts data with OpenPGP's
+// cipher feedback mode using the given cipher.Block, and an initial amount of
+// ciphertext. randData must be random bytes and be the same length as the
+// cipher.Block's block size. Resync determines if the "resynchronization step"
+// from RFC 4880, 13.9 step 7 is performed. Different parts of OpenPGP vary on
+// this point.
+func NewOCFBEncrypter(block cipher.Block, randData []byte, resync OCFBResyncOption) (cipher.Stream, []byte) {
+ blockSize := block.BlockSize()
+ if len(randData) != blockSize {
+ return nil, nil
+ }
+
+ x := &ocfbEncrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefix := make([]byte, blockSize+2)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefix[i] = randData[i] ^ x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
+ prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
+
+ if resync {
+ block.Encrypt(x.fre, prefix[2:])
+ } else {
+ x.fre[0] = prefix[blockSize]
+ x.fre[1] = prefix[blockSize+1]
+ x.outUsed = 2
+ }
+ return x, prefix
+}
+
+func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ x.fre[x.outUsed] ^= src[i]
+ dst[i] = x.fre[x.outUsed]
+ x.outUsed++
+ }
+}
+
+type ocfbDecrypter struct {
+ b cipher.Block
+ fre []byte
+ outUsed int
+}
+
+// NewOCFBDecrypter returns a cipher.Stream which decrypts data with OpenPGP's
+// cipher feedback mode using the given cipher.Block. Prefix must be the first
+// blockSize + 2 bytes of the ciphertext, where blockSize is the cipher.Block's
+// block size. If an incorrect key is detected then nil is returned. On
+// successful exit, blockSize+2 bytes of decrypted data are written into
+// prefix. Resync determines if the "resynchronization step" from RFC 4880,
+// 13.9 step 7 is performed. Different parts of OpenPGP vary on this point.
+func NewOCFBDecrypter(block cipher.Block, prefix []byte, resync OCFBResyncOption) cipher.Stream {
+ blockSize := block.BlockSize()
+ if len(prefix) != blockSize+2 {
+ return nil
+ }
+
+ x := &ocfbDecrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefixCopy := make([]byte, len(prefix))
+ copy(prefixCopy, prefix)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefixCopy[i] ^= x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefixCopy[blockSize] ^= x.fre[0]
+ prefixCopy[blockSize+1] ^= x.fre[1]
+
+ if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
+ prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
+ return nil
+ }
+
+ if resync {
+ block.Encrypt(x.fre, prefix[2:])
+ } else {
+ x.fre[0] = prefix[blockSize]
+ x.fre[1] = prefix[blockSize+1]
+ x.outUsed = 2
+ }
+ copy(prefix, prefixCopy)
+ return x
+}
+
+func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ c := src[i]
+ dst[i] = x.fre[x.outUsed] ^ src[i]
+ x.fre[x.outUsed] = c
+ x.outUsed++
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/ocfb_test.go b/vendor/golang.org/x/crypto/openpgp/packet/ocfb_test.go
new file mode 100644
index 000000000..91022c042
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/ocfb_test.go
@@ -0,0 +1,46 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/rand"
+ "testing"
+)
+
+var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
+
+func testOCFB(t *testing.T, resync OCFBResyncOption) {
+ block, err := aes.NewCipher(commonKey128)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ plaintext := []byte("this is the plaintext, which is long enough to span several blocks.")
+ randData := make([]byte, block.BlockSize())
+ rand.Reader.Read(randData)
+ ocfb, prefix := NewOCFBEncrypter(block, randData, resync)
+ ciphertext := make([]byte, len(plaintext))
+ ocfb.XORKeyStream(ciphertext, plaintext)
+
+ ocfbdec := NewOCFBDecrypter(block, prefix, resync)
+ if ocfbdec == nil {
+ t.Errorf("NewOCFBDecrypter failed (resync: %t)", resync)
+ return
+ }
+ plaintextCopy := make([]byte, len(plaintext))
+ ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("got: %x, want: %x (resync: %t)", plaintextCopy, plaintext, resync)
+ }
+}
+
+func TestOCFB(t *testing.T) {
+ testOCFB(t, OCFBNoResync)
+ testOCFB(t, OCFBResync)
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go b/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go
new file mode 100644
index 000000000..171350339
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/one_pass_signature.go
@@ -0,0 +1,73 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "encoding/binary"
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/s2k"
+ "io"
+ "strconv"
+)
+
+// OnePassSignature represents a one-pass signature packet. See RFC 4880,
+// section 5.4.
+type OnePassSignature struct {
+ SigType SignatureType
+ Hash crypto.Hash
+ PubKeyAlgo PublicKeyAlgorithm
+ KeyId uint64
+ IsLast bool
+}
+
+const onePassSignatureVersion = 3
+
+func (ops *OnePassSignature) parse(r io.Reader) (err error) {
+ var buf [13]byte
+
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ if buf[0] != onePassSignatureVersion {
+ err = errors.UnsupportedError("one-pass-signature packet version " + strconv.Itoa(int(buf[0])))
+ }
+
+ var ok bool
+ ops.Hash, ok = s2k.HashIdToHash(buf[2])
+ if !ok {
+ return errors.UnsupportedError("hash function: " + strconv.Itoa(int(buf[2])))
+ }
+
+ ops.SigType = SignatureType(buf[1])
+ ops.PubKeyAlgo = PublicKeyAlgorithm(buf[3])
+ ops.KeyId = binary.BigEndian.Uint64(buf[4:12])
+ ops.IsLast = buf[12] != 0
+ return
+}
+
+// Serialize marshals the given OnePassSignature to w.
+func (ops *OnePassSignature) Serialize(w io.Writer) error {
+ var buf [13]byte
+ buf[0] = onePassSignatureVersion
+ buf[1] = uint8(ops.SigType)
+ var ok bool
+ buf[2], ok = s2k.HashToHashId(ops.Hash)
+ if !ok {
+ return errors.UnsupportedError("hash type: " + strconv.Itoa(int(ops.Hash)))
+ }
+ buf[3] = uint8(ops.PubKeyAlgo)
+ binary.BigEndian.PutUint64(buf[4:12], ops.KeyId)
+ if ops.IsLast {
+ buf[12] = 1
+ }
+
+ if err := serializeHeader(w, packetTypeOnePassSignature, len(buf)); err != nil {
+ return err
+ }
+ _, err := w.Write(buf[:])
+ return err
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/opaque.go b/vendor/golang.org/x/crypto/openpgp/packet/opaque.go
new file mode 100644
index 000000000..456d807f2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/opaque.go
@@ -0,0 +1,162 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+
+ "golang.org/x/crypto/openpgp/errors"
+)
+
+// OpaquePacket represents an OpenPGP packet as raw, unparsed data. This is
+// useful for splitting and storing the original packet contents separately,
+// handling unsupported packet types or accessing parts of the packet not yet
+// implemented by this package.
+type OpaquePacket struct {
+ // Packet type
+ Tag uint8
+ // Reason why the packet was parsed opaquely
+ Reason error
+ // Binary contents of the packet data
+ Contents []byte
+}
+
+func (op *OpaquePacket) parse(r io.Reader) (err error) {
+ op.Contents, err = ioutil.ReadAll(r)
+ return
+}
+
+// Serialize marshals the packet to a writer in its original form, including
+// the packet header.
+func (op *OpaquePacket) Serialize(w io.Writer) (err error) {
+ err = serializeHeader(w, packetType(op.Tag), len(op.Contents))
+ if err == nil {
+ _, err = w.Write(op.Contents)
+ }
+ return
+}
+
+// Parse attempts to parse the opaque contents into a structure supported by
+// this package. If the packet is not known then the result will be another
+// OpaquePacket.
+func (op *OpaquePacket) Parse() (p Packet, err error) {
+ hdr := bytes.NewBuffer(nil)
+ err = serializeHeader(hdr, packetType(op.Tag), len(op.Contents))
+ if err != nil {
+ op.Reason = err
+ return op, err
+ }
+ p, err = Read(io.MultiReader(hdr, bytes.NewBuffer(op.Contents)))
+ if err != nil {
+ op.Reason = err
+ p = op
+ }
+ return
+}
+
+// OpaqueReader reads OpaquePackets from an io.Reader.
+type OpaqueReader struct {
+ r io.Reader
+}
+
+func NewOpaqueReader(r io.Reader) *OpaqueReader {
+ return &OpaqueReader{r: r}
+}
+
+// Read the next OpaquePacket.
+func (or *OpaqueReader) Next() (op *OpaquePacket, err error) {
+ tag, _, contents, err := readHeader(or.r)
+ if err != nil {
+ return
+ }
+ op = &OpaquePacket{Tag: uint8(tag), Reason: err}
+ err = op.parse(contents)
+ if err != nil {
+ consumeAll(contents)
+ }
+ return
+}
+
+// OpaqueSubpacket represents an unparsed OpenPGP subpacket,
+// as found in signature and user attribute packets.
+type OpaqueSubpacket struct {
+ SubType uint8
+ Contents []byte
+}
+
+// OpaqueSubpackets extracts opaque, unparsed OpenPGP subpackets from
+// their byte representation.
+func OpaqueSubpackets(contents []byte) (result []*OpaqueSubpacket, err error) {
+ var (
+ subHeaderLen int
+ subPacket *OpaqueSubpacket
+ )
+ for len(contents) > 0 {
+ subHeaderLen, subPacket, err = nextSubpacket(contents)
+ if err != nil {
+ break
+ }
+ result = append(result, subPacket)
+ contents = contents[subHeaderLen+len(subPacket.Contents):]
+ }
+ return
+}
+
+func nextSubpacket(contents []byte) (subHeaderLen int, subPacket *OpaqueSubpacket, err error) {
+ // RFC 4880, section 5.2.3.1
+ var subLen uint32
+ if len(contents) < 1 {
+ goto Truncated
+ }
+ subPacket = &OpaqueSubpacket{}
+ switch {
+ case contents[0] < 192:
+ subHeaderLen = 2 // 1 length byte, 1 subtype byte
+ if len(contents) < subHeaderLen {
+ goto Truncated
+ }
+ subLen = uint32(contents[0])
+ contents = contents[1:]
+ case contents[0] < 255:
+ subHeaderLen = 3 // 2 length bytes, 1 subtype
+ if len(contents) < subHeaderLen {
+ goto Truncated
+ }
+ subLen = uint32(contents[0]-192)<<8 + uint32(contents[1]) + 192
+ contents = contents[2:]
+ default:
+ subHeaderLen = 6 // 5 length bytes, 1 subtype
+ if len(contents) < subHeaderLen {
+ goto Truncated
+ }
+ subLen = uint32(contents[1])<<24 |
+ uint32(contents[2])<<16 |
+ uint32(contents[3])<<8 |
+ uint32(contents[4])
+ contents = contents[5:]
+ }
+ if subLen > uint32(len(contents)) || subLen == 0 {
+ goto Truncated
+ }
+ subPacket.SubType = contents[0]
+ subPacket.Contents = contents[1:subLen]
+ return
+Truncated:
+ err = errors.StructuralError("subpacket truncated")
+ return
+}
+
+func (osp *OpaqueSubpacket) Serialize(w io.Writer) (err error) {
+ buf := make([]byte, 6)
+ n := serializeSubpacketLength(buf, len(osp.Contents)+1)
+ buf[n] = osp.SubType
+ if _, err = w.Write(buf[:n+1]); err != nil {
+ return
+ }
+ _, err = w.Write(osp.Contents)
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/opaque_test.go b/vendor/golang.org/x/crypto/openpgp/packet/opaque_test.go
new file mode 100644
index 000000000..f27bbfe09
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/opaque_test.go
@@ -0,0 +1,67 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "io"
+ "testing"
+)
+
+// Test packet.Read error handling in OpaquePacket.Parse,
+// which attempts to re-read an OpaquePacket as a supported
+// Packet type.
+func TestOpaqueParseReason(t *testing.T) {
+ buf, err := hex.DecodeString(UnsupportedKeyHex)
+ if err != nil {
+ t.Fatal(err)
+ }
+ or := NewOpaqueReader(bytes.NewBuffer(buf))
+ count := 0
+ badPackets := 0
+ var uid *UserId
+ for {
+ op, err := or.Next()
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ t.Errorf("#%d: opaque read error: %v", count, err)
+ break
+ }
+ // try to parse opaque packet
+ p, err := op.Parse()
+ switch pkt := p.(type) {
+ case *UserId:
+ uid = pkt
+ case *OpaquePacket:
+ // If an OpaquePacket can't re-parse, packet.Read
+ // certainly had its reasons.
+ if pkt.Reason == nil {
+ t.Errorf("#%d: opaque packet, no reason", count)
+ } else {
+ badPackets++
+ }
+ }
+ count++
+ }
+
+ const expectedBad = 3
+ // Test post-conditions, make sure we actually parsed packets as expected.
+ if badPackets != expectedBad {
+ t.Errorf("unexpected # unparseable packets: %d (want %d)", badPackets, expectedBad)
+ }
+ if uid == nil {
+ t.Errorf("failed to find expected UID in unsupported keyring")
+ } else if uid.Id != "Armin M. Warda <warda@nephilim.ruhr.de>" {
+ t.Errorf("unexpected UID: %v", uid.Id)
+ }
+}
+
+// This key material has public key and signature packet versions modified to
+// an unsupported value (1), so that trying to parse the OpaquePacket to
+// a typed packet will get an error. It also contains a GnuPG trust packet.
+// (Created with: od -An -t x1 pubring.gpg | xargs | sed 's/ //g')
+const UnsupportedKeyHex = `988d012e7a18a20000010400d6ac00d92b89c1f4396c243abb9b76d2e9673ad63483291fed88e22b82e255e441c078c6abbbf7d2d195e50b62eeaa915b85b0ec20c225ce2c64c167cacb6e711daf2e45da4a8356a059b8160e3b3628ac0dd8437b31f06d53d6e8ea4214d4a26406a6b63e1001406ef23e0bb3069fac9a99a91f77dfafd5de0f188a5da5e3c9000511b42741726d696e204d2e205761726461203c7761726461406e657068696c696d2e727568722e64653e8900950105102e8936c705d1eb399e58489901013f0e03ff5a0c4f421e34fcfa388129166420c08cd76987bcdec6f01bd0271459a85cc22048820dd4e44ac2c7d23908d540f54facf1b36b0d9c20488781ce9dca856531e76e2e846826e9951338020a03a09b57aa5faa82e9267458bd76105399885ac35af7dc1cbb6aaed7c39e1039f3b5beda2c0e916bd38560509bab81235d1a0ead83b0020000`
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go
new file mode 100644
index 000000000..e2bde1111
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go
@@ -0,0 +1,539 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package packet implements parsing and serialization of OpenPGP packets, as
+// specified in RFC 4880.
+package packet // import "golang.org/x/crypto/openpgp/packet"
+
+import (
+ "bufio"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "golang.org/x/crypto/cast5"
+ "golang.org/x/crypto/openpgp/errors"
+ "io"
+ "math/big"
+)
+
+// readFull is the same as io.ReadFull except that reading zero bytes returns
+// ErrUnexpectedEOF rather than EOF.
+func readFull(r io.Reader, buf []byte) (n int, err error) {
+ n, err = io.ReadFull(r, buf)
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// readLength reads an OpenPGP length from r. See RFC 4880, section 4.2.2.
+func readLength(r io.Reader) (length int64, isPartial bool, err error) {
+ var buf [4]byte
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ switch {
+ case buf[0] < 192:
+ length = int64(buf[0])
+ case buf[0] < 224:
+ length = int64(buf[0]-192) << 8
+ _, err = readFull(r, buf[0:1])
+ if err != nil {
+ return
+ }
+ length += int64(buf[0]) + 192
+ case buf[0] < 255:
+ length = int64(1) << (buf[0] & 0x1f)
+ isPartial = true
+ default:
+ _, err = readFull(r, buf[0:4])
+ if err != nil {
+ return
+ }
+ length = int64(buf[0])<<24 |
+ int64(buf[1])<<16 |
+ int64(buf[2])<<8 |
+ int64(buf[3])
+ }
+ return
+}
+
+// partialLengthReader wraps an io.Reader and handles OpenPGP partial lengths.
+// The continuation lengths are parsed and removed from the stream and EOF is
+// returned at the end of the packet. See RFC 4880, section 4.2.2.4.
+type partialLengthReader struct {
+ r io.Reader
+ remaining int64
+ isPartial bool
+}
+
+func (r *partialLengthReader) Read(p []byte) (n int, err error) {
+ for r.remaining == 0 {
+ if !r.isPartial {
+ return 0, io.EOF
+ }
+ r.remaining, r.isPartial, err = readLength(r.r)
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ toRead := int64(len(p))
+ if toRead > r.remaining {
+ toRead = r.remaining
+ }
+
+ n, err = r.r.Read(p[:int(toRead)])
+ r.remaining -= int64(n)
+ if n < int(toRead) && err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// partialLengthWriter writes a stream of data using OpenPGP partial lengths.
+// See RFC 4880, section 4.2.2.4.
+type partialLengthWriter struct {
+ w io.WriteCloser
+ lengthByte [1]byte
+}
+
+func (w *partialLengthWriter) Write(p []byte) (n int, err error) {
+ for len(p) > 0 {
+ for power := uint(14); power < 32; power-- {
+ l := 1 << power
+ if len(p) >= l {
+ w.lengthByte[0] = 224 + uint8(power)
+ _, err = w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return
+ }
+ var m int
+ m, err = w.w.Write(p[:l])
+ n += m
+ if err != nil {
+ return
+ }
+ p = p[l:]
+ break
+ }
+ }
+ }
+ return
+}
+
+func (w *partialLengthWriter) Close() error {
+ w.lengthByte[0] = 0
+ _, err := w.w.Write(w.lengthByte[:])
+ if err != nil {
+ return err
+ }
+ return w.w.Close()
+}
+
+// A spanReader is an io.LimitReader, but it returns ErrUnexpectedEOF if the
+// underlying Reader returns EOF before the limit has been reached.
+type spanReader struct {
+ r io.Reader
+ n int64
+}
+
+func (l *spanReader) Read(p []byte) (n int, err error) {
+ if l.n <= 0 {
+ return 0, io.EOF
+ }
+ if int64(len(p)) > l.n {
+ p = p[0:l.n]
+ }
+ n, err = l.r.Read(p)
+ l.n -= int64(n)
+ if l.n > 0 && err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return
+}
+
+// readHeader parses a packet header and returns an io.Reader which will return
+// the contents of the packet. See RFC 4880, section 4.2.
+func readHeader(r io.Reader) (tag packetType, length int64, contents io.Reader, err error) {
+ var buf [4]byte
+ _, err = io.ReadFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ if buf[0]&0x80 == 0 {
+ err = errors.StructuralError("tag byte does not have MSB set")
+ return
+ }
+ if buf[0]&0x40 == 0 {
+ // Old format packet
+ tag = packetType((buf[0] & 0x3f) >> 2)
+ lengthType := buf[0] & 3
+ if lengthType == 3 {
+ length = -1
+ contents = r
+ return
+ }
+ lengthBytes := 1 << lengthType
+ _, err = readFull(r, buf[0:lengthBytes])
+ if err != nil {
+ return
+ }
+ for i := 0; i < lengthBytes; i++ {
+ length <<= 8
+ length |= int64(buf[i])
+ }
+ contents = &spanReader{r, length}
+ return
+ }
+
+ // New format packet
+ tag = packetType(buf[0] & 0x3f)
+ length, isPartial, err := readLength(r)
+ if err != nil {
+ return
+ }
+ if isPartial {
+ contents = &partialLengthReader{
+ remaining: length,
+ isPartial: true,
+ r: r,
+ }
+ length = -1
+ } else {
+ contents = &spanReader{r, length}
+ }
+ return
+}
+
+// serializeHeader writes an OpenPGP packet header to w. See RFC 4880, section
+// 4.2.
+func serializeHeader(w io.Writer, ptype packetType, length int) (err error) {
+ var buf [6]byte
+ var n int
+
+ buf[0] = 0x80 | 0x40 | byte(ptype)
+ if length < 192 {
+ buf[1] = byte(length)
+ n = 2
+ } else if length < 8384 {
+ length -= 192
+ buf[1] = 192 + byte(length>>8)
+ buf[2] = byte(length)
+ n = 3
+ } else {
+ buf[1] = 255
+ buf[2] = byte(length >> 24)
+ buf[3] = byte(length >> 16)
+ buf[4] = byte(length >> 8)
+ buf[5] = byte(length)
+ n = 6
+ }
+
+ _, err = w.Write(buf[:n])
+ return
+}
+
+// serializeStreamHeader writes an OpenPGP packet header to w where the
+// length of the packet is unknown. It returns a io.WriteCloser which can be
+// used to write the contents of the packet. See RFC 4880, section 4.2.
+func serializeStreamHeader(w io.WriteCloser, ptype packetType) (out io.WriteCloser, err error) {
+ var buf [1]byte
+ buf[0] = 0x80 | 0x40 | byte(ptype)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ out = &partialLengthWriter{w: w}
+ return
+}
+
+// Packet represents an OpenPGP packet. Users are expected to try casting
+// instances of this interface to specific packet types.
+type Packet interface {
+ parse(io.Reader) error
+}
+
+// consumeAll reads from the given Reader until error, returning the number of
+// bytes read.
+func consumeAll(r io.Reader) (n int64, err error) {
+ var m int
+ var buf [1024]byte
+
+ for {
+ m, err = r.Read(buf[:])
+ n += int64(m)
+ if err == io.EOF {
+ err = nil
+ return
+ }
+ if err != nil {
+ return
+ }
+ }
+
+ panic("unreachable")
+}
+
+// packetType represents the numeric ids of the different OpenPGP packet types. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-2
+type packetType uint8
+
+const (
+ packetTypeEncryptedKey packetType = 1
+ packetTypeSignature packetType = 2
+ packetTypeSymmetricKeyEncrypted packetType = 3
+ packetTypeOnePassSignature packetType = 4
+ packetTypePrivateKey packetType = 5
+ packetTypePublicKey packetType = 6
+ packetTypePrivateSubkey packetType = 7
+ packetTypeCompressed packetType = 8
+ packetTypeSymmetricallyEncrypted packetType = 9
+ packetTypeLiteralData packetType = 11
+ packetTypeUserId packetType = 13
+ packetTypePublicSubkey packetType = 14
+ packetTypeUserAttribute packetType = 17
+ packetTypeSymmetricallyEncryptedMDC packetType = 18
+)
+
+// peekVersion detects the version of a public key packet about to
+// be read. A bufio.Reader at the original position of the io.Reader
+// is returned.
+func peekVersion(r io.Reader) (bufr *bufio.Reader, ver byte, err error) {
+ bufr = bufio.NewReader(r)
+ var verBuf []byte
+ if verBuf, err = bufr.Peek(1); err != nil {
+ return
+ }
+ ver = verBuf[0]
+ return
+}
+
+// Read reads a single OpenPGP packet from the given io.Reader. If there is an
+// error parsing a packet, the whole packet is consumed from the input.
+func Read(r io.Reader) (p Packet, err error) {
+ tag, _, contents, err := readHeader(r)
+ if err != nil {
+ return
+ }
+
+ switch tag {
+ case packetTypeEncryptedKey:
+ p = new(EncryptedKey)
+ case packetTypeSignature:
+ var version byte
+ // Detect signature version
+ if contents, version, err = peekVersion(contents); err != nil {
+ return
+ }
+ if version < 4 {
+ p = new(SignatureV3)
+ } else {
+ p = new(Signature)
+ }
+ case packetTypeSymmetricKeyEncrypted:
+ p = new(SymmetricKeyEncrypted)
+ case packetTypeOnePassSignature:
+ p = new(OnePassSignature)
+ case packetTypePrivateKey, packetTypePrivateSubkey:
+ pk := new(PrivateKey)
+ if tag == packetTypePrivateSubkey {
+ pk.IsSubkey = true
+ }
+ p = pk
+ case packetTypePublicKey, packetTypePublicSubkey:
+ var version byte
+ if contents, version, err = peekVersion(contents); err != nil {
+ return
+ }
+ isSubkey := tag == packetTypePublicSubkey
+ if version < 4 {
+ p = &PublicKeyV3{IsSubkey: isSubkey}
+ } else {
+ p = &PublicKey{IsSubkey: isSubkey}
+ }
+ case packetTypeCompressed:
+ p = new(Compressed)
+ case packetTypeSymmetricallyEncrypted:
+ p = new(SymmetricallyEncrypted)
+ case packetTypeLiteralData:
+ p = new(LiteralData)
+ case packetTypeUserId:
+ p = new(UserId)
+ case packetTypeUserAttribute:
+ p = new(UserAttribute)
+ case packetTypeSymmetricallyEncryptedMDC:
+ se := new(SymmetricallyEncrypted)
+ se.MDC = true
+ p = se
+ default:
+ err = errors.UnknownPacketTypeError(tag)
+ }
+ if p != nil {
+ err = p.parse(contents)
+ }
+ if err != nil {
+ consumeAll(contents)
+ }
+ return
+}
+
+// SignatureType represents the different semantic meanings of an OpenPGP
+// signature. See RFC 4880, section 5.2.1.
+type SignatureType uint8
+
+const (
+ SigTypeBinary SignatureType = 0
+ SigTypeText = 1
+ SigTypeGenericCert = 0x10
+ SigTypePersonaCert = 0x11
+ SigTypeCasualCert = 0x12
+ SigTypePositiveCert = 0x13
+ SigTypeSubkeyBinding = 0x18
+ SigTypePrimaryKeyBinding = 0x19
+ SigTypeDirectSignature = 0x1F
+ SigTypeKeyRevocation = 0x20
+ SigTypeSubkeyRevocation = 0x28
+)
+
+// PublicKeyAlgorithm represents the different public key system specified for
+// OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-12
+type PublicKeyAlgorithm uint8
+
+const (
+ PubKeyAlgoRSA PublicKeyAlgorithm = 1
+ PubKeyAlgoRSAEncryptOnly PublicKeyAlgorithm = 2
+ PubKeyAlgoRSASignOnly PublicKeyAlgorithm = 3
+ PubKeyAlgoElGamal PublicKeyAlgorithm = 16
+ PubKeyAlgoDSA PublicKeyAlgorithm = 17
+ // RFC 6637, Section 5.
+ PubKeyAlgoECDH PublicKeyAlgorithm = 18
+ PubKeyAlgoECDSA PublicKeyAlgorithm = 19
+)
+
+// CanEncrypt returns true if it's possible to encrypt a message to a public
+// key of the given type.
+func (pka PublicKeyAlgorithm) CanEncrypt() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoElGamal:
+ return true
+ }
+ return false
+}
+
+// CanSign returns true if it's possible for a public key of the given type to
+// sign a message.
+func (pka PublicKeyAlgorithm) CanSign() bool {
+ switch pka {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA:
+ return true
+ }
+ return false
+}
+
+// CipherFunction represents the different block ciphers specified for OpenPGP. See
+// http://www.iana.org/assignments/pgp-parameters/pgp-parameters.xhtml#pgp-parameters-13
+type CipherFunction uint8
+
+const (
+ Cipher3DES CipherFunction = 2
+ CipherCAST5 CipherFunction = 3
+ CipherAES128 CipherFunction = 7
+ CipherAES192 CipherFunction = 8
+ CipherAES256 CipherFunction = 9
+)
+
+// KeySize returns the key size, in bytes, of cipher.
+func (cipher CipherFunction) KeySize() int {
+ switch cipher {
+ case Cipher3DES:
+ return 24
+ case CipherCAST5:
+ return cast5.KeySize
+ case CipherAES128:
+ return 16
+ case CipherAES192:
+ return 24
+ case CipherAES256:
+ return 32
+ }
+ return 0
+}
+
+// blockSize returns the block size, in bytes, of cipher.
+func (cipher CipherFunction) blockSize() int {
+ switch cipher {
+ case Cipher3DES:
+ return des.BlockSize
+ case CipherCAST5:
+ return 8
+ case CipherAES128, CipherAES192, CipherAES256:
+ return 16
+ }
+ return 0
+}
+
+// new returns a fresh instance of the given cipher.
+func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
+ switch cipher {
+ case Cipher3DES:
+ block, _ = des.NewTripleDESCipher(key)
+ case CipherCAST5:
+ block, _ = cast5.NewCipher(key)
+ case CipherAES128, CipherAES192, CipherAES256:
+ block, _ = aes.NewCipher(key)
+ }
+ return
+}
+
+// readMPI reads a big integer from r. The bit length returned is the bit
+// length that was specified in r. This is preserved so that the integer can be
+// reserialized exactly.
+func readMPI(r io.Reader) (mpi []byte, bitLength uint16, err error) {
+ var buf [2]byte
+ _, err = readFull(r, buf[0:])
+ if err != nil {
+ return
+ }
+ bitLength = uint16(buf[0])<<8 | uint16(buf[1])
+ numBytes := (int(bitLength) + 7) / 8
+ mpi = make([]byte, numBytes)
+ _, err = readFull(r, mpi)
+ return
+}
+
+// mpiLength returns the length of the given *big.Int when serialized as an
+// MPI.
+func mpiLength(n *big.Int) (mpiLengthInBytes int) {
+ mpiLengthInBytes = 2 /* MPI length */
+ mpiLengthInBytes += (n.BitLen() + 7) / 8
+ return
+}
+
+// writeMPI serializes a big integer to w.
+func writeMPI(w io.Writer, bitLength uint16, mpiBytes []byte) (err error) {
+ _, err = w.Write([]byte{byte(bitLength >> 8), byte(bitLength)})
+ if err == nil {
+ _, err = w.Write(mpiBytes)
+ }
+ return
+}
+
+// writeBig serializes a *big.Int to w.
+func writeBig(w io.Writer, i *big.Int) error {
+ return writeMPI(w, uint16(i.BitLen()), i.Bytes())
+}
+
+// CompressionAlgo Represents the different compression algorithms
+// supported by OpenPGP (except for BZIP2, which is not currently
+// supported). See Section 9.3 of RFC 4880.
+type CompressionAlgo uint8
+
+const (
+ CompressionNone CompressionAlgo = 0
+ CompressionZIP CompressionAlgo = 1
+ CompressionZLIB CompressionAlgo = 2
+)
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet_test.go b/vendor/golang.org/x/crypto/openpgp/packet/packet_test.go
new file mode 100644
index 000000000..1dab5c3d5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/packet_test.go
@@ -0,0 +1,255 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+ "golang.org/x/crypto/openpgp/errors"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+func TestReadFull(t *testing.T) {
+ var out [4]byte
+
+ b := bytes.NewBufferString("foo")
+ n, err := readFull(b, out[:3])
+ if n != 3 || err != nil {
+ t.Errorf("full read failed n:%d err:%s", n, err)
+ }
+
+ b = bytes.NewBufferString("foo")
+ n, err = readFull(b, out[:4])
+ if n != 3 || err != io.ErrUnexpectedEOF {
+ t.Errorf("partial read failed n:%d err:%s", n, err)
+ }
+
+ b = bytes.NewBuffer(nil)
+ n, err = readFull(b, out[:3])
+ if n != 0 || err != io.ErrUnexpectedEOF {
+ t.Errorf("empty read failed n:%d err:%s", n, err)
+ }
+}
+
+func readerFromHex(s string) io.Reader {
+ data, err := hex.DecodeString(s)
+ if err != nil {
+ panic("readerFromHex: bad input")
+ }
+ return bytes.NewBuffer(data)
+}
+
+var readLengthTests = []struct {
+ hexInput string
+ length int64
+ isPartial bool
+ err error
+}{
+ {"", 0, false, io.ErrUnexpectedEOF},
+ {"1f", 31, false, nil},
+ {"c0", 0, false, io.ErrUnexpectedEOF},
+ {"c101", 256 + 1 + 192, false, nil},
+ {"e0", 1, true, nil},
+ {"e1", 2, true, nil},
+ {"e2", 4, true, nil},
+ {"ff", 0, false, io.ErrUnexpectedEOF},
+ {"ff00", 0, false, io.ErrUnexpectedEOF},
+ {"ff0000", 0, false, io.ErrUnexpectedEOF},
+ {"ff000000", 0, false, io.ErrUnexpectedEOF},
+ {"ff00000000", 0, false, nil},
+ {"ff01020304", 16909060, false, nil},
+}
+
+func TestReadLength(t *testing.T) {
+ for i, test := range readLengthTests {
+ length, isPartial, err := readLength(readerFromHex(test.hexInput))
+ if test.err != nil {
+ if err != test.err {
+ t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("%d: unexpected error: %s", i, err)
+ continue
+ }
+ if length != test.length || isPartial != test.isPartial {
+ t.Errorf("%d: bad result got:(%d,%t) want:(%d,%t)", i, length, isPartial, test.length, test.isPartial)
+ }
+ }
+}
+
+var partialLengthReaderTests = []struct {
+ hexInput string
+ err error
+ hexOutput string
+}{
+ {"e0", io.ErrUnexpectedEOF, ""},
+ {"e001", io.ErrUnexpectedEOF, ""},
+ {"e0010102", nil, "0102"},
+ {"ff00000000", nil, ""},
+ {"e10102e1030400", nil, "01020304"},
+ {"e101", io.ErrUnexpectedEOF, ""},
+}
+
+func TestPartialLengthReader(t *testing.T) {
+ for i, test := range partialLengthReaderTests {
+ r := &partialLengthReader{readerFromHex(test.hexInput), 0, true}
+ out, err := ioutil.ReadAll(r)
+ if test.err != nil {
+ if err != test.err {
+ t.Errorf("%d: expected different error got:%s want:%s", i, err, test.err)
+ }
+ continue
+ }
+ if err != nil {
+ t.Errorf("%d: unexpected error: %s", i, err)
+ continue
+ }
+
+ got := fmt.Sprintf("%x", out)
+ if got != test.hexOutput {
+ t.Errorf("%d: got:%s want:%s", i, test.hexOutput, got)
+ }
+ }
+}
+
+var readHeaderTests = []struct {
+ hexInput string
+ structuralError bool
+ unexpectedEOF bool
+ tag int
+ length int64
+ hexOutput string
+}{
+ {"", false, false, 0, 0, ""},
+ {"7f", true, false, 0, 0, ""},
+
+ // Old format headers
+ {"80", false, true, 0, 0, ""},
+ {"8001", false, true, 0, 1, ""},
+ {"800102", false, false, 0, 1, "02"},
+ {"81000102", false, false, 0, 1, "02"},
+ {"820000000102", false, false, 0, 1, "02"},
+ {"860000000102", false, false, 1, 1, "02"},
+ {"83010203", false, false, 0, -1, "010203"},
+
+ // New format headers
+ {"c0", false, true, 0, 0, ""},
+ {"c000", false, false, 0, 0, ""},
+ {"c00102", false, false, 0, 1, "02"},
+ {"c0020203", false, false, 0, 2, "0203"},
+ {"c00202", false, true, 0, 2, ""},
+ {"c3020203", false, false, 3, 2, "0203"},
+}
+
+func TestReadHeader(t *testing.T) {
+ for i, test := range readHeaderTests {
+ tag, length, contents, err := readHeader(readerFromHex(test.hexInput))
+ if test.structuralError {
+ if _, ok := err.(errors.StructuralError); ok {
+ continue
+ }
+ t.Errorf("%d: expected StructuralError, got:%s", i, err)
+ continue
+ }
+ if err != nil {
+ if len(test.hexInput) == 0 && err == io.EOF {
+ continue
+ }
+ if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
+ t.Errorf("%d: unexpected error from readHeader: %s", i, err)
+ }
+ continue
+ }
+ if int(tag) != test.tag || length != test.length {
+ t.Errorf("%d: got:(%d,%d) want:(%d,%d)", i, int(tag), length, test.tag, test.length)
+ continue
+ }
+
+ body, err := ioutil.ReadAll(contents)
+ if err != nil {
+ if !test.unexpectedEOF || err != io.ErrUnexpectedEOF {
+ t.Errorf("%d: unexpected error from contents: %s", i, err)
+ }
+ continue
+ }
+ if test.unexpectedEOF {
+ t.Errorf("%d: expected ErrUnexpectedEOF from contents but got no error", i)
+ continue
+ }
+ got := fmt.Sprintf("%x", body)
+ if got != test.hexOutput {
+ t.Errorf("%d: got:%s want:%s", i, got, test.hexOutput)
+ }
+ }
+}
+
+func TestSerializeHeader(t *testing.T) {
+ tag := packetTypePublicKey
+ lengths := []int{0, 1, 2, 64, 192, 193, 8000, 8384, 8385, 10000}
+
+ for _, length := range lengths {
+ buf := bytes.NewBuffer(nil)
+ serializeHeader(buf, tag, length)
+ tag2, length2, _, err := readHeader(buf)
+ if err != nil {
+ t.Errorf("length %d, err: %s", length, err)
+ }
+ if tag2 != tag {
+ t.Errorf("length %d, tag incorrect (got %d, want %d)", length, tag2, tag)
+ }
+ if int(length2) != length {
+ t.Errorf("length %d, length incorrect (got %d)", length, length2)
+ }
+ }
+}
+
+func TestPartialLengths(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ w := new(partialLengthWriter)
+ w.w = noOpCloser{buf}
+
+ const maxChunkSize = 64
+
+ var b [maxChunkSize]byte
+ var n uint8
+ for l := 1; l <= maxChunkSize; l++ {
+ for i := 0; i < l; i++ {
+ b[i] = n
+ n++
+ }
+ m, err := w.Write(b[:l])
+ if m != l {
+ t.Errorf("short write got: %d want: %d", m, l)
+ }
+ if err != nil {
+ t.Errorf("error from write: %s", err)
+ }
+ }
+ w.Close()
+
+ want := (maxChunkSize * (maxChunkSize + 1)) / 2
+ copyBuf := bytes.NewBuffer(nil)
+ r := &partialLengthReader{buf, 0, true}
+ m, err := io.Copy(copyBuf, r)
+ if m != int64(want) {
+ t.Errorf("short copy got: %d want: %d", m, want)
+ }
+ if err != nil {
+ t.Errorf("error from copy: %s", err)
+ }
+
+ copyBytes := copyBuf.Bytes()
+ for i := 0; i < want; i++ {
+ if copyBytes[i] != uint8(i) {
+ t.Errorf("bad pattern in copy at %d", i)
+ break
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go
new file mode 100644
index 000000000..545846ba8
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key.go
@@ -0,0 +1,362 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "crypto/sha1"
+ "io"
+ "io/ioutil"
+ "math/big"
+ "strconv"
+ "time"
+
+ "golang.org/x/crypto/openpgp/elgamal"
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/s2k"
+)
+
+// PrivateKey represents a possibly encrypted private key. See RFC 4880,
+// section 5.5.3.
+type PrivateKey struct {
+ PublicKey
+ Encrypted bool // if true then the private key is unavailable until Decrypt has been called.
+ encryptedData []byte
+ cipher CipherFunction
+ s2k func(out, in []byte)
+ PrivateKey interface{} // An *rsa.PrivateKey or *dsa.PrivateKey.
+ sha1Checksum bool
+ iv []byte
+}
+
+func NewRSAPrivateKey(currentTime time.Time, priv *rsa.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewRSAPublicKey(currentTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewDSAPrivateKey(currentTime time.Time, priv *dsa.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewDSAPublicKey(currentTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewElGamalPrivateKey(currentTime time.Time, priv *elgamal.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewElGamalPublicKey(currentTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func NewECDSAPrivateKey(currentTime time.Time, priv *ecdsa.PrivateKey) *PrivateKey {
+ pk := new(PrivateKey)
+ pk.PublicKey = *NewECDSAPublicKey(currentTime, &priv.PublicKey)
+ pk.PrivateKey = priv
+ return pk
+}
+
+func (pk *PrivateKey) parse(r io.Reader) (err error) {
+ err = (&pk.PublicKey).parse(r)
+ if err != nil {
+ return
+ }
+ var buf [1]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+
+ s2kType := buf[0]
+
+ switch s2kType {
+ case 0:
+ pk.s2k = nil
+ pk.Encrypted = false
+ case 254, 255:
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ pk.cipher = CipherFunction(buf[0])
+ pk.Encrypted = true
+ pk.s2k, err = s2k.Parse(r)
+ if err != nil {
+ return
+ }
+ if s2kType == 254 {
+ pk.sha1Checksum = true
+ }
+ default:
+ return errors.UnsupportedError("deprecated s2k function in private key")
+ }
+
+ if pk.Encrypted {
+ blockSize := pk.cipher.blockSize()
+ if blockSize == 0 {
+ return errors.UnsupportedError("unsupported cipher in private key: " + strconv.Itoa(int(pk.cipher)))
+ }
+ pk.iv = make([]byte, blockSize)
+ _, err = readFull(r, pk.iv)
+ if err != nil {
+ return
+ }
+ }
+
+ pk.encryptedData, err = ioutil.ReadAll(r)
+ if err != nil {
+ return
+ }
+
+ if !pk.Encrypted {
+ return pk.parsePrivateKey(pk.encryptedData)
+ }
+
+ return
+}
+
+func mod64kHash(d []byte) uint16 {
+ var h uint16
+ for _, b := range d {
+ h += uint16(b)
+ }
+ return h
+}
+
+func (pk *PrivateKey) Serialize(w io.Writer) (err error) {
+ // TODO(agl): support encrypted private keys
+ buf := bytes.NewBuffer(nil)
+ err = pk.PublicKey.serializeWithoutHeaders(buf)
+ if err != nil {
+ return
+ }
+ buf.WriteByte(0 /* no encryption */)
+
+ privateKeyBuf := bytes.NewBuffer(nil)
+
+ switch priv := pk.PrivateKey.(type) {
+ case *rsa.PrivateKey:
+ err = serializeRSAPrivateKey(privateKeyBuf, priv)
+ case *dsa.PrivateKey:
+ err = serializeDSAPrivateKey(privateKeyBuf, priv)
+ case *elgamal.PrivateKey:
+ err = serializeElGamalPrivateKey(privateKeyBuf, priv)
+ case *ecdsa.PrivateKey:
+ err = serializeECDSAPrivateKey(privateKeyBuf, priv)
+ default:
+ err = errors.InvalidArgumentError("unknown private key type")
+ }
+ if err != nil {
+ return
+ }
+
+ ptype := packetTypePrivateKey
+ contents := buf.Bytes()
+ privateKeyBytes := privateKeyBuf.Bytes()
+ if pk.IsSubkey {
+ ptype = packetTypePrivateSubkey
+ }
+ err = serializeHeader(w, ptype, len(contents)+len(privateKeyBytes)+2)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(privateKeyBytes)
+ if err != nil {
+ return
+ }
+
+ checksum := mod64kHash(privateKeyBytes)
+ var checksumBytes [2]byte
+ checksumBytes[0] = byte(checksum >> 8)
+ checksumBytes[1] = byte(checksum)
+ _, err = w.Write(checksumBytes[:])
+
+ return
+}
+
+func serializeRSAPrivateKey(w io.Writer, priv *rsa.PrivateKey) error {
+ err := writeBig(w, priv.D)
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[1])
+ if err != nil {
+ return err
+ }
+ err = writeBig(w, priv.Primes[0])
+ if err != nil {
+ return err
+ }
+ return writeBig(w, priv.Precomputed.Qinv)
+}
+
+func serializeDSAPrivateKey(w io.Writer, priv *dsa.PrivateKey) error {
+ return writeBig(w, priv.X)
+}
+
+func serializeElGamalPrivateKey(w io.Writer, priv *elgamal.PrivateKey) error {
+ return writeBig(w, priv.X)
+}
+
+func serializeECDSAPrivateKey(w io.Writer, priv *ecdsa.PrivateKey) error {
+ return writeBig(w, priv.D)
+}
+
+// Decrypt decrypts an encrypted private key using a passphrase.
+func (pk *PrivateKey) Decrypt(passphrase []byte) error {
+ if !pk.Encrypted {
+ return nil
+ }
+
+ key := make([]byte, pk.cipher.KeySize())
+ pk.s2k(key, passphrase)
+ block := pk.cipher.new(key)
+ cfb := cipher.NewCFBDecrypter(block, pk.iv)
+
+ data := make([]byte, len(pk.encryptedData))
+ cfb.XORKeyStream(data, pk.encryptedData)
+
+ if pk.sha1Checksum {
+ if len(data) < sha1.Size {
+ return errors.StructuralError("truncated private key data")
+ }
+ h := sha1.New()
+ h.Write(data[:len(data)-sha1.Size])
+ sum := h.Sum(nil)
+ if !bytes.Equal(sum, data[len(data)-sha1.Size:]) {
+ return errors.StructuralError("private key checksum failure")
+ }
+ data = data[:len(data)-sha1.Size]
+ } else {
+ if len(data) < 2 {
+ return errors.StructuralError("truncated private key data")
+ }
+ var sum uint16
+ for i := 0; i < len(data)-2; i++ {
+ sum += uint16(data[i])
+ }
+ if data[len(data)-2] != uint8(sum>>8) ||
+ data[len(data)-1] != uint8(sum) {
+ return errors.StructuralError("private key checksum failure")
+ }
+ data = data[:len(data)-2]
+ }
+
+ return pk.parsePrivateKey(data)
+}
+
+func (pk *PrivateKey) parsePrivateKey(data []byte) (err error) {
+ switch pk.PublicKey.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoRSAEncryptOnly:
+ return pk.parseRSAPrivateKey(data)
+ case PubKeyAlgoDSA:
+ return pk.parseDSAPrivateKey(data)
+ case PubKeyAlgoElGamal:
+ return pk.parseElGamalPrivateKey(data)
+ case PubKeyAlgoECDSA:
+ return pk.parseECDSAPrivateKey(data)
+ }
+ panic("impossible")
+}
+
+func (pk *PrivateKey) parseRSAPrivateKey(data []byte) (err error) {
+ rsaPub := pk.PublicKey.PublicKey.(*rsa.PublicKey)
+ rsaPriv := new(rsa.PrivateKey)
+ rsaPriv.PublicKey = *rsaPub
+
+ buf := bytes.NewBuffer(data)
+ d, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+ p, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+ q, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ rsaPriv.D = new(big.Int).SetBytes(d)
+ rsaPriv.Primes = make([]*big.Int, 2)
+ rsaPriv.Primes[0] = new(big.Int).SetBytes(p)
+ rsaPriv.Primes[1] = new(big.Int).SetBytes(q)
+ if err := rsaPriv.Validate(); err != nil {
+ return err
+ }
+ rsaPriv.Precompute()
+ pk.PrivateKey = rsaPriv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
+
+func (pk *PrivateKey) parseDSAPrivateKey(data []byte) (err error) {
+ dsaPub := pk.PublicKey.PublicKey.(*dsa.PublicKey)
+ dsaPriv := new(dsa.PrivateKey)
+ dsaPriv.PublicKey = *dsaPub
+
+ buf := bytes.NewBuffer(data)
+ x, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ dsaPriv.X = new(big.Int).SetBytes(x)
+ pk.PrivateKey = dsaPriv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
+
+func (pk *PrivateKey) parseElGamalPrivateKey(data []byte) (err error) {
+ pub := pk.PublicKey.PublicKey.(*elgamal.PublicKey)
+ priv := new(elgamal.PrivateKey)
+ priv.PublicKey = *pub
+
+ buf := bytes.NewBuffer(data)
+ x, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ priv.X = new(big.Int).SetBytes(x)
+ pk.PrivateKey = priv
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
+
+func (pk *PrivateKey) parseECDSAPrivateKey(data []byte) (err error) {
+ ecdsaPub := pk.PublicKey.PublicKey.(*ecdsa.PublicKey)
+
+ buf := bytes.NewBuffer(data)
+ d, _, err := readMPI(buf)
+ if err != nil {
+ return
+ }
+
+ pk.PrivateKey = &ecdsa.PrivateKey{
+ PublicKey: *ecdsaPub,
+ D: new(big.Int).SetBytes(d),
+ }
+ pk.Encrypted = false
+ pk.encryptedData = nil
+
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go b/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go
new file mode 100644
index 000000000..81d3961de
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/private_key_test.go
@@ -0,0 +1,126 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "hash"
+ "testing"
+ "time"
+)
+
+var privateKeyTests = []struct {
+ privateKeyHex string
+ creationTime time.Time
+}{
+ {
+ privKeyRSAHex,
+ time.Unix(0x4cc349a8, 0),
+ },
+ {
+ privKeyElGamalHex,
+ time.Unix(0x4df9ee1a, 0),
+ },
+}
+
+func TestPrivateKeyRead(t *testing.T) {
+ for i, test := range privateKeyTests {
+ packet, err := Read(readerFromHex(test.privateKeyHex))
+ if err != nil {
+ t.Errorf("#%d: failed to parse: %s", i, err)
+ continue
+ }
+
+ privKey := packet.(*PrivateKey)
+
+ if !privKey.Encrypted {
+ t.Errorf("#%d: private key isn't encrypted", i)
+ continue
+ }
+
+ err = privKey.Decrypt([]byte("wrong password"))
+ if err == nil {
+ t.Errorf("#%d: decrypted with incorrect key", i)
+ continue
+ }
+
+ err = privKey.Decrypt([]byte("testing"))
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt: %s", i, err)
+ continue
+ }
+
+ if !privKey.CreationTime.Equal(test.creationTime) || privKey.Encrypted {
+ t.Errorf("#%d: bad result, got: %#v", i, privKey)
+ }
+ }
+}
+
+func populateHash(hashFunc crypto.Hash, msg []byte) (hash.Hash, error) {
+ h := hashFunc.New()
+ if _, err := h.Write(msg); err != nil {
+ return nil, err
+ }
+ return h, nil
+}
+
+func TestECDSAPrivateKey(t *testing.T) {
+ ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var buf bytes.Buffer
+ if err := NewECDSAPrivateKey(time.Now(), ecdsaPriv).Serialize(&buf); err != nil {
+ t.Fatal(err)
+ }
+
+ p, err := Read(&buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ priv, ok := p.(*PrivateKey)
+ if !ok {
+ t.Fatal("didn't parse private key")
+ }
+
+ sig := &Signature{
+ PubKeyAlgo: PubKeyAlgoECDSA,
+ Hash: crypto.SHA256,
+ }
+ msg := []byte("Hello World!")
+
+ h, err := populateHash(sig.Hash, msg)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := sig.Sign(h, priv, nil); err != nil {
+ t.Fatal(err)
+ }
+
+ if h, err = populateHash(sig.Hash, msg); err != nil {
+ t.Fatal(err)
+ }
+ if err := priv.VerifySignature(h, sig); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestIssue11505(t *testing.T) {
+ // parsing a rsa private key with p or q == 1 used to panic due to a divide by zero
+ _, _ = Read(readerFromHex("9c3004303030300100000011303030000000000000010130303030303030303030303030303030303030303030303030303030303030303030303030303030303030"))
+}
+
+// Generated with `gpg --export-secret-keys "Test Key 2"`
+const privKeyRSAHex = "9501fe044cc349a8010400b70ca0010e98c090008d45d1ee8f9113bd5861fd57b88bacb7c68658747663f1e1a3b5a98f32fda6472373c024b97359cd2efc88ff60f77751adfbf6af5e615e6a1408cfad8bf0cea30b0d5f53aa27ad59089ba9b15b7ebc2777a25d7b436144027e3bcd203909f147d0e332b240cf63d3395f5dfe0df0a6c04e8655af7eacdf0011010001fe0303024a252e7d475fd445607de39a265472aa74a9320ba2dac395faa687e9e0336aeb7e9a7397e511b5afd9dc84557c80ac0f3d4d7bfec5ae16f20d41c8c84a04552a33870b930420e230e179564f6d19bb153145e76c33ae993886c388832b0fa042ddda7f133924f3854481533e0ede31d51278c0519b29abc3bf53da673e13e3e1214b52413d179d7f66deee35cac8eacb060f78379d70ef4af8607e68131ff529439668fc39c9ce6dfef8a5ac234d234802cbfb749a26107db26406213ae5c06d4673253a3cbee1fcbae58d6ab77e38d6e2c0e7c6317c48e054edadb5a40d0d48acb44643d998139a8a66bb820be1f3f80185bc777d14b5954b60effe2448a036d565c6bc0b915fcea518acdd20ab07bc1529f561c58cd044f723109b93f6fd99f876ff891d64306b5d08f48bab59f38695e9109c4dec34013ba3153488ce070268381ba923ee1eb77125b36afcb4347ec3478c8f2735b06ef17351d872e577fa95d0c397c88c71b59629a36aec"
+
+// Generated by `gpg --export-secret-keys` followed by a manual extraction of
+// the ElGamal subkey from the packets.
+const privKeyElGamalHex = "9d0157044df9ee1a100400eb8e136a58ec39b582629cdadf830bc64e0a94ed8103ca8bb247b27b11b46d1d25297ef4bcc3071785ba0c0bedfe89eabc5287fcc0edf81ab5896c1c8e4b20d27d79813c7aede75320b33eaeeaa586edc00fd1036c10133e6ba0ff277245d0d59d04b2b3421b7244aca5f4a8d870c6f1c1fbff9e1c26699a860b9504f35ca1d700030503fd1ededd3b840795be6d9ccbe3c51ee42e2f39233c432b831ddd9c4e72b7025a819317e47bf94f9ee316d7273b05d5fcf2999c3a681f519b1234bbfa6d359b4752bd9c3f77d6b6456cde152464763414ca130f4e91d91041432f90620fec0e6d6b5116076c2985d5aeaae13be492b9b329efcaf7ee25120159a0a30cd976b42d7afe030302dae7eb80db744d4960c4df930d57e87fe81412eaace9f900e6c839817a614ddb75ba6603b9417c33ea7b6c93967dfa2bcff3fa3c74a5ce2c962db65b03aece14c96cbd0038fc"
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go
new file mode 100644
index 000000000..c769933ce
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key.go
@@ -0,0 +1,750 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+ "encoding/binary"
+ "fmt"
+ "hash"
+ "io"
+ "math/big"
+ "strconv"
+ "time"
+
+ "golang.org/x/crypto/openpgp/elgamal"
+ "golang.org/x/crypto/openpgp/errors"
+)
+
+var (
+ // NIST curve P-256
+ oidCurveP256 []byte = []byte{0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07}
+ // NIST curve P-384
+ oidCurveP384 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x22}
+ // NIST curve P-521
+ oidCurveP521 []byte = []byte{0x2B, 0x81, 0x04, 0x00, 0x23}
+)
+
+const maxOIDLength = 8
+
+// ecdsaKey stores the algorithm-specific fields for ECDSA keys.
+// as defined in RFC 6637, Section 9.
+type ecdsaKey struct {
+ // oid contains the OID byte sequence identifying the elliptic curve used
+ oid []byte
+ // p contains the elliptic curve point that represents the public key
+ p parsedMPI
+}
+
+// parseOID reads the OID for the curve as defined in RFC 6637, Section 9.
+func parseOID(r io.Reader) (oid []byte, err error) {
+ buf := make([]byte, maxOIDLength)
+ if _, err = readFull(r, buf[:1]); err != nil {
+ return
+ }
+ oidLen := buf[0]
+ if int(oidLen) > len(buf) {
+ err = errors.UnsupportedError("invalid oid length: " + strconv.Itoa(int(oidLen)))
+ return
+ }
+ oid = buf[:oidLen]
+ _, err = readFull(r, oid)
+ return
+}
+
+func (f *ecdsaKey) parse(r io.Reader) (err error) {
+ if f.oid, err = parseOID(r); err != nil {
+ return err
+ }
+ f.p.bytes, f.p.bitLength, err = readMPI(r)
+ return
+}
+
+func (f *ecdsaKey) serialize(w io.Writer) (err error) {
+ buf := make([]byte, maxOIDLength+1)
+ buf[0] = byte(len(f.oid))
+ copy(buf[1:], f.oid)
+ if _, err = w.Write(buf[:len(f.oid)+1]); err != nil {
+ return
+ }
+ return writeMPIs(w, f.p)
+}
+
+func (f *ecdsaKey) newECDSA() (*ecdsa.PublicKey, error) {
+ var c elliptic.Curve
+ if bytes.Equal(f.oid, oidCurveP256) {
+ c = elliptic.P256()
+ } else if bytes.Equal(f.oid, oidCurveP384) {
+ c = elliptic.P384()
+ } else if bytes.Equal(f.oid, oidCurveP521) {
+ c = elliptic.P521()
+ } else {
+ return nil, errors.UnsupportedError(fmt.Sprintf("unsupported oid: %x", f.oid))
+ }
+ x, y := elliptic.Unmarshal(c, f.p.bytes)
+ if x == nil {
+ return nil, errors.UnsupportedError("failed to parse EC point")
+ }
+ return &ecdsa.PublicKey{Curve: c, X: x, Y: y}, nil
+}
+
+func (f *ecdsaKey) byteLen() int {
+ return 1 + len(f.oid) + 2 + len(f.p.bytes)
+}
+
+type kdfHashFunction byte
+type kdfAlgorithm byte
+
+// ecdhKdf stores key derivation function parameters
+// used for ECDH encryption. See RFC 6637, Section 9.
+type ecdhKdf struct {
+ KdfHash kdfHashFunction
+ KdfAlgo kdfAlgorithm
+}
+
+func (f *ecdhKdf) parse(r io.Reader) (err error) {
+ buf := make([]byte, 1)
+ if _, err = readFull(r, buf); err != nil {
+ return
+ }
+ kdfLen := int(buf[0])
+ if kdfLen < 3 {
+ return errors.UnsupportedError("Unsupported ECDH KDF length: " + strconv.Itoa(kdfLen))
+ }
+ buf = make([]byte, kdfLen)
+ if _, err = readFull(r, buf); err != nil {
+ return
+ }
+ reserved := int(buf[0])
+ f.KdfHash = kdfHashFunction(buf[1])
+ f.KdfAlgo = kdfAlgorithm(buf[2])
+ if reserved != 0x01 {
+ return errors.UnsupportedError("Unsupported KDF reserved field: " + strconv.Itoa(reserved))
+ }
+ return
+}
+
+func (f *ecdhKdf) serialize(w io.Writer) (err error) {
+ buf := make([]byte, 4)
+ // See RFC 6637, Section 9, Algorithm-Specific Fields for ECDH keys.
+ buf[0] = byte(0x03) // Length of the following fields
+ buf[1] = byte(0x01) // Reserved for future extensions, must be 1 for now
+ buf[2] = byte(f.KdfHash)
+ buf[3] = byte(f.KdfAlgo)
+ _, err = w.Write(buf[:])
+ return
+}
+
+func (f *ecdhKdf) byteLen() int {
+ return 4
+}
+
+// PublicKey represents an OpenPGP public key. See RFC 4880, section 5.5.2.
+type PublicKey struct {
+ CreationTime time.Time
+ PubKeyAlgo PublicKeyAlgorithm
+ PublicKey interface{} // *rsa.PublicKey, *dsa.PublicKey or *ecdsa.PublicKey
+ Fingerprint [20]byte
+ KeyId uint64
+ IsSubkey bool
+
+ n, e, p, q, g, y parsedMPI
+
+ // RFC 6637 fields
+ ec *ecdsaKey
+ ecdh *ecdhKdf
+}
+
+// signingKey provides a convenient abstraction over signature verification
+// for v3 and v4 public keys.
+type signingKey interface {
+ SerializeSignaturePrefix(io.Writer)
+ serializeWithoutHeaders(io.Writer) error
+}
+
+func fromBig(n *big.Int) parsedMPI {
+ return parsedMPI{
+ bytes: n.Bytes(),
+ bitLength: uint16(n.BitLen()),
+ }
+}
+
+// NewRSAPublicKey returns a PublicKey that wraps the given rsa.PublicKey.
+func NewRSAPublicKey(creationTime time.Time, pub *rsa.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoRSA,
+ PublicKey: pub,
+ n: fromBig(pub.N),
+ e: fromBig(big.NewInt(int64(pub.E))),
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
+// NewDSAPublicKey returns a PublicKey that wraps the given dsa.PublicKey.
+func NewDSAPublicKey(creationTime time.Time, pub *dsa.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoDSA,
+ PublicKey: pub,
+ p: fromBig(pub.P),
+ q: fromBig(pub.Q),
+ g: fromBig(pub.G),
+ y: fromBig(pub.Y),
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
+// NewElGamalPublicKey returns a PublicKey that wraps the given elgamal.PublicKey.
+func NewElGamalPublicKey(creationTime time.Time, pub *elgamal.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoElGamal,
+ PublicKey: pub,
+ p: fromBig(pub.P),
+ g: fromBig(pub.G),
+ y: fromBig(pub.Y),
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
+func NewECDSAPublicKey(creationTime time.Time, pub *ecdsa.PublicKey) *PublicKey {
+ pk := &PublicKey{
+ CreationTime: creationTime,
+ PubKeyAlgo: PubKeyAlgoECDSA,
+ PublicKey: pub,
+ ec: new(ecdsaKey),
+ }
+
+ switch pub.Curve {
+ case elliptic.P256():
+ pk.ec.oid = oidCurveP256
+ case elliptic.P384():
+ pk.ec.oid = oidCurveP384
+ case elliptic.P521():
+ pk.ec.oid = oidCurveP521
+ default:
+ panic("unknown elliptic curve")
+ }
+
+ pk.ec.p.bytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
+ pk.ec.p.bitLength = uint16(8 * len(pk.ec.p.bytes))
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
+func (pk *PublicKey) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.5.2
+ var buf [6]byte
+ _, err = readFull(r, buf[:])
+ if err != nil {
+ return
+ }
+ if buf[0] != 4 {
+ return errors.UnsupportedError("public key version")
+ }
+ pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
+ pk.PubKeyAlgo = PublicKeyAlgorithm(buf[5])
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ err = pk.parseRSA(r)
+ case PubKeyAlgoDSA:
+ err = pk.parseDSA(r)
+ case PubKeyAlgoElGamal:
+ err = pk.parseElGamal(r)
+ case PubKeyAlgoECDSA:
+ pk.ec = new(ecdsaKey)
+ if err = pk.ec.parse(r); err != nil {
+ return err
+ }
+ pk.PublicKey, err = pk.ec.newECDSA()
+ case PubKeyAlgoECDH:
+ pk.ec = new(ecdsaKey)
+ if err = pk.ec.parse(r); err != nil {
+ return
+ }
+ pk.ecdh = new(ecdhKdf)
+ if err = pk.ecdh.parse(r); err != nil {
+ return
+ }
+ // The ECDH key is stored in an ecdsa.PublicKey for convenience.
+ pk.PublicKey, err = pk.ec.newECDSA()
+ default:
+ err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
+ }
+ if err != nil {
+ return
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return
+}
+
+func (pk *PublicKey) setFingerPrintAndKeyId() {
+ // RFC 4880, section 12.2
+ fingerPrint := sha1.New()
+ pk.SerializeSignaturePrefix(fingerPrint)
+ pk.serializeWithoutHeaders(fingerPrint)
+ copy(pk.Fingerprint[:], fingerPrint.Sum(nil))
+ pk.KeyId = binary.BigEndian.Uint64(pk.Fingerprint[12:20])
+}
+
+// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseRSA(r io.Reader) (err error) {
+ pk.n.bytes, pk.n.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.e.bytes, pk.e.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ if len(pk.e.bytes) > 3 {
+ err = errors.UnsupportedError("large public exponent")
+ return
+ }
+ rsa := &rsa.PublicKey{
+ N: new(big.Int).SetBytes(pk.n.bytes),
+ E: 0,
+ }
+ for i := 0; i < len(pk.e.bytes); i++ {
+ rsa.E <<= 8
+ rsa.E |= int(pk.e.bytes[i])
+ }
+ pk.PublicKey = rsa
+ return
+}
+
+// parseDSA parses DSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKey) parseDSA(r io.Reader) (err error) {
+ pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.q.bytes, pk.q.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ dsa := new(dsa.PublicKey)
+ dsa.P = new(big.Int).SetBytes(pk.p.bytes)
+ dsa.Q = new(big.Int).SetBytes(pk.q.bytes)
+ dsa.G = new(big.Int).SetBytes(pk.g.bytes)
+ dsa.Y = new(big.Int).SetBytes(pk.y.bytes)
+ pk.PublicKey = dsa
+ return
+}
+
+// parseElGamal parses ElGamal public key material from the given Reader. See
+// RFC 4880, section 5.5.2.
+func (pk *PublicKey) parseElGamal(r io.Reader) (err error) {
+ pk.p.bytes, pk.p.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.g.bytes, pk.g.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+ pk.y.bytes, pk.y.bitLength, err = readMPI(r)
+ if err != nil {
+ return
+ }
+
+ elgamal := new(elgamal.PublicKey)
+ elgamal.P = new(big.Int).SetBytes(pk.p.bytes)
+ elgamal.G = new(big.Int).SetBytes(pk.g.bytes)
+ elgamal.Y = new(big.Int).SetBytes(pk.y.bytes)
+ pk.PublicKey = elgamal
+ return
+}
+
+// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
+// The prefix is used when calculating a signature over this public key. See
+// RFC 4880, section 5.2.4.
+func (pk *PublicKey) SerializeSignaturePrefix(h io.Writer) {
+ var pLength uint16
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ pLength += 2 + uint16(len(pk.n.bytes))
+ pLength += 2 + uint16(len(pk.e.bytes))
+ case PubKeyAlgoDSA:
+ pLength += 2 + uint16(len(pk.p.bytes))
+ pLength += 2 + uint16(len(pk.q.bytes))
+ pLength += 2 + uint16(len(pk.g.bytes))
+ pLength += 2 + uint16(len(pk.y.bytes))
+ case PubKeyAlgoElGamal:
+ pLength += 2 + uint16(len(pk.p.bytes))
+ pLength += 2 + uint16(len(pk.g.bytes))
+ pLength += 2 + uint16(len(pk.y.bytes))
+ case PubKeyAlgoECDSA:
+ pLength += uint16(pk.ec.byteLen())
+ case PubKeyAlgoECDH:
+ pLength += uint16(pk.ec.byteLen())
+ pLength += uint16(pk.ecdh.byteLen())
+ default:
+ panic("unknown public key algorithm")
+ }
+ pLength += 6
+ h.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
+ return
+}
+
+func (pk *PublicKey) Serialize(w io.Writer) (err error) {
+ length := 6 // 6 byte header
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ length += 2 + len(pk.n.bytes)
+ length += 2 + len(pk.e.bytes)
+ case PubKeyAlgoDSA:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.q.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ case PubKeyAlgoElGamal:
+ length += 2 + len(pk.p.bytes)
+ length += 2 + len(pk.g.bytes)
+ length += 2 + len(pk.y.bytes)
+ case PubKeyAlgoECDSA:
+ length += pk.ec.byteLen()
+ case PubKeyAlgoECDH:
+ length += pk.ec.byteLen()
+ length += pk.ecdh.byteLen()
+ default:
+ panic("unknown public key algorithm")
+ }
+
+ packetType := packetTypePublicKey
+ if pk.IsSubkey {
+ packetType = packetTypePublicSubkey
+ }
+ err = serializeHeader(w, packetType, length)
+ if err != nil {
+ return
+ }
+ return pk.serializeWithoutHeaders(w)
+}
+
+// serializeWithoutHeaders marshals the PublicKey to w in the form of an
+// OpenPGP public key packet, not including the packet header.
+func (pk *PublicKey) serializeWithoutHeaders(w io.Writer) (err error) {
+ var buf [6]byte
+ buf[0] = 4
+ t := uint32(pk.CreationTime.Unix())
+ buf[1] = byte(t >> 24)
+ buf[2] = byte(t >> 16)
+ buf[3] = byte(t >> 8)
+ buf[4] = byte(t)
+ buf[5] = byte(pk.PubKeyAlgo)
+
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ return writeMPIs(w, pk.n, pk.e)
+ case PubKeyAlgoDSA:
+ return writeMPIs(w, pk.p, pk.q, pk.g, pk.y)
+ case PubKeyAlgoElGamal:
+ return writeMPIs(w, pk.p, pk.g, pk.y)
+ case PubKeyAlgoECDSA:
+ return pk.ec.serialize(w)
+ case PubKeyAlgoECDH:
+ if err = pk.ec.serialize(w); err != nil {
+ return
+ }
+ return pk.ecdh.serialize(w)
+ }
+ return errors.InvalidArgumentError("bad public-key algorithm")
+}
+
+// CanSign returns true iff this public key can generate signatures
+func (pk *PublicKey) CanSign() bool {
+ return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly && pk.PubKeyAlgo != PubKeyAlgoElGamal
+}
+
+// VerifySignature returns nil iff sig is a valid signature, made by this
+// public key, of the data hashed into signed. signed is mutated by this call.
+func (pk *PublicKey) VerifySignature(signed hash.Hash, sig *Signature) (err error) {
+ if !pk.CanSign() {
+ return errors.InvalidArgumentError("public key cannot generate signatures")
+ }
+
+ signed.Write(sig.HashSuffix)
+ hashBytes := signed.Sum(nil)
+
+ if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
+ return errors.SignatureError("hash tag doesn't match")
+ }
+
+ if pk.PubKeyAlgo != sig.PubKeyAlgo {
+ return errors.InvalidArgumentError("public key and signature use different algorithms")
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ rsaPublicKey, _ := pk.PublicKey.(*rsa.PublicKey)
+ err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes)
+ if err != nil {
+ return errors.SignatureError("RSA verification failure")
+ }
+ return nil
+ case PubKeyAlgoDSA:
+ dsaPublicKey, _ := pk.PublicKey.(*dsa.PublicKey)
+ // Need to truncate hashBytes to match FIPS 186-3 section 4.6.
+ subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
+ if len(hashBytes) > subgroupSize {
+ hashBytes = hashBytes[:subgroupSize]
+ }
+ if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
+ return errors.SignatureError("DSA verification failure")
+ }
+ return nil
+ case PubKeyAlgoECDSA:
+ ecdsaPublicKey := pk.PublicKey.(*ecdsa.PublicKey)
+ if !ecdsa.Verify(ecdsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.ECDSASigR.bytes), new(big.Int).SetBytes(sig.ECDSASigS.bytes)) {
+ return errors.SignatureError("ECDSA verification failure")
+ }
+ return nil
+ default:
+ return errors.SignatureError("Unsupported public key algorithm used in signature")
+ }
+ panic("unreachable")
+}
+
+// VerifySignatureV3 returns nil iff sig is a valid signature, made by this
+// public key, of the data hashed into signed. signed is mutated by this call.
+func (pk *PublicKey) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) {
+ if !pk.CanSign() {
+ return errors.InvalidArgumentError("public key cannot generate signatures")
+ }
+
+ suffix := make([]byte, 5)
+ suffix[0] = byte(sig.SigType)
+ binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix()))
+ signed.Write(suffix)
+ hashBytes := signed.Sum(nil)
+
+ if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
+ return errors.SignatureError("hash tag doesn't match")
+ }
+
+ if pk.PubKeyAlgo != sig.PubKeyAlgo {
+ return errors.InvalidArgumentError("public key and signature use different algorithms")
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ rsaPublicKey := pk.PublicKey.(*rsa.PublicKey)
+ if err = rsa.VerifyPKCS1v15(rsaPublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil {
+ return errors.SignatureError("RSA verification failure")
+ }
+ return
+ case PubKeyAlgoDSA:
+ dsaPublicKey := pk.PublicKey.(*dsa.PublicKey)
+ // Need to truncate hashBytes to match FIPS 186-3 section 4.6.
+ subgroupSize := (dsaPublicKey.Q.BitLen() + 7) / 8
+ if len(hashBytes) > subgroupSize {
+ hashBytes = hashBytes[:subgroupSize]
+ }
+ if !dsa.Verify(dsaPublicKey, hashBytes, new(big.Int).SetBytes(sig.DSASigR.bytes), new(big.Int).SetBytes(sig.DSASigS.bytes)) {
+ return errors.SignatureError("DSA verification failure")
+ }
+ return nil
+ default:
+ panic("shouldn't happen")
+ }
+ panic("unreachable")
+}
+
+// keySignatureHash returns a Hash of the message that needs to be signed for
+// pk to assert a subkey relationship to signed.
+func keySignatureHash(pk, signed signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
+ if !hashFunc.Available() {
+ return nil, errors.UnsupportedError("hash function")
+ }
+ h = hashFunc.New()
+
+ // RFC 4880, section 5.2.4
+ pk.SerializeSignaturePrefix(h)
+ pk.serializeWithoutHeaders(h)
+ signed.SerializeSignaturePrefix(h)
+ signed.serializeWithoutHeaders(h)
+ return
+}
+
+// VerifyKeySignature returns nil iff sig is a valid signature, made by this
+// public key, of signed.
+func (pk *PublicKey) VerifyKeySignature(signed *PublicKey, sig *Signature) error {
+ h, err := keySignatureHash(pk, signed, sig.Hash)
+ if err != nil {
+ return err
+ }
+ if err = pk.VerifySignature(h, sig); err != nil {
+ return err
+ }
+
+ if sig.FlagSign {
+ // Signing subkeys must be cross-signed. See
+ // https://www.gnupg.org/faq/subkey-cross-certify.html.
+ if sig.EmbeddedSignature == nil {
+ return errors.StructuralError("signing subkey is missing cross-signature")
+ }
+ // Verify the cross-signature. This is calculated over the same
+ // data as the main signature, so we cannot just recursively
+ // call signed.VerifyKeySignature(...)
+ if h, err = keySignatureHash(pk, signed, sig.EmbeddedSignature.Hash); err != nil {
+ return errors.StructuralError("error while hashing for cross-signature: " + err.Error())
+ }
+ if err := signed.VerifySignature(h, sig.EmbeddedSignature); err != nil {
+ return errors.StructuralError("error while verifying cross-signature: " + err.Error())
+ }
+ }
+
+ return nil
+}
+
+func keyRevocationHash(pk signingKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
+ if !hashFunc.Available() {
+ return nil, errors.UnsupportedError("hash function")
+ }
+ h = hashFunc.New()
+
+ // RFC 4880, section 5.2.4
+ pk.SerializeSignaturePrefix(h)
+ pk.serializeWithoutHeaders(h)
+
+ return
+}
+
+// VerifyRevocationSignature returns nil iff sig is a valid signature, made by this
+// public key.
+func (pk *PublicKey) VerifyRevocationSignature(sig *Signature) (err error) {
+ h, err := keyRevocationHash(pk, sig.Hash)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignature(h, sig)
+}
+
+// userIdSignatureHash returns a Hash of the message that needs to be signed
+// to assert that pk is a valid key for id.
+func userIdSignatureHash(id string, pk *PublicKey, hashFunc crypto.Hash) (h hash.Hash, err error) {
+ if !hashFunc.Available() {
+ return nil, errors.UnsupportedError("hash function")
+ }
+ h = hashFunc.New()
+
+ // RFC 4880, section 5.2.4
+ pk.SerializeSignaturePrefix(h)
+ pk.serializeWithoutHeaders(h)
+
+ var buf [5]byte
+ buf[0] = 0xb4
+ buf[1] = byte(len(id) >> 24)
+ buf[2] = byte(len(id) >> 16)
+ buf[3] = byte(len(id) >> 8)
+ buf[4] = byte(len(id))
+ h.Write(buf[:])
+ h.Write([]byte(id))
+
+ return
+}
+
+// VerifyUserIdSignature returns nil iff sig is a valid signature, made by this
+// public key, that id is the identity of pub.
+func (pk *PublicKey) VerifyUserIdSignature(id string, pub *PublicKey, sig *Signature) (err error) {
+ h, err := userIdSignatureHash(id, pub, sig.Hash)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignature(h, sig)
+}
+
+// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this
+// public key, that id is the identity of pub.
+func (pk *PublicKey) VerifyUserIdSignatureV3(id string, pub *PublicKey, sig *SignatureV3) (err error) {
+ h, err := userIdSignatureV3Hash(id, pub, sig.Hash)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignatureV3(h, sig)
+}
+
+// KeyIdString returns the public key's fingerprint in capital hex
+// (e.g. "6C7EE1B8621CC013").
+func (pk *PublicKey) KeyIdString() string {
+ return fmt.Sprintf("%X", pk.Fingerprint[12:20])
+}
+
+// KeyIdShortString returns the short form of public key's fingerprint
+// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
+func (pk *PublicKey) KeyIdShortString() string {
+ return fmt.Sprintf("%X", pk.Fingerprint[16:20])
+}
+
+// A parsedMPI is used to store the contents of a big integer, along with the
+// bit length that was specified in the original input. This allows the MPI to
+// be reserialized exactly.
+type parsedMPI struct {
+ bytes []byte
+ bitLength uint16
+}
+
+// writeMPIs is a utility function for serializing several big integers to the
+// given Writer.
+func writeMPIs(w io.Writer, mpis ...parsedMPI) (err error) {
+ for _, mpi := range mpis {
+ err = writeMPI(w, mpi.bitLength, mpi.bytes)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// BitLength returns the bit length for the given public key.
+func (pk *PublicKey) BitLength() (bitLength uint16, err error) {
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ bitLength = pk.n.bitLength
+ case PubKeyAlgoDSA:
+ bitLength = pk.p.bitLength
+ case PubKeyAlgoElGamal:
+ bitLength = pk.p.bitLength
+ default:
+ err = errors.InvalidArgumentError("bad public-key algorithm")
+ }
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go
new file mode 100644
index 000000000..7ad7d9185
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key_test.go
@@ -0,0 +1,202 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+ "time"
+)
+
+var pubKeyTests = []struct {
+ hexData string
+ hexFingerprint string
+ creationTime time.Time
+ pubKeyAlgo PublicKeyAlgorithm
+ keyId uint64
+ keyIdString string
+ keyIdShort string
+}{
+ {rsaPkDataHex, rsaFingerprintHex, time.Unix(0x4d3c5c10, 0), PubKeyAlgoRSA, 0xa34d7e18c20c31bb, "A34D7E18C20C31BB", "C20C31BB"},
+ {dsaPkDataHex, dsaFingerprintHex, time.Unix(0x4d432f89, 0), PubKeyAlgoDSA, 0x8e8fbe54062f19ed, "8E8FBE54062F19ED", "062F19ED"},
+ {ecdsaPkDataHex, ecdsaFingerprintHex, time.Unix(0x5071c294, 0), PubKeyAlgoECDSA, 0x43fe956c542ca00b, "43FE956C542CA00B", "542CA00B"},
+}
+
+func TestPublicKeyRead(t *testing.T) {
+ for i, test := range pubKeyTests {
+ packet, err := Read(readerFromHex(test.hexData))
+ if err != nil {
+ t.Errorf("#%d: Read error: %s", i, err)
+ continue
+ }
+ pk, ok := packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse, got: %#v", i, packet)
+ continue
+ }
+ if pk.PubKeyAlgo != test.pubKeyAlgo {
+ t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
+ }
+ if !pk.CreationTime.Equal(test.creationTime) {
+ t.Errorf("#%d: bad creation time got:%v want:%v", i, pk.CreationTime, test.creationTime)
+ }
+ expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
+ if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
+ t.Errorf("#%d: bad fingerprint got:%x want:%x", i, pk.Fingerprint[:], expectedFingerprint)
+ }
+ if pk.KeyId != test.keyId {
+ t.Errorf("#%d: bad keyid got:%x want:%x", i, pk.KeyId, test.keyId)
+ }
+ if g, e := pk.KeyIdString(), test.keyIdString; g != e {
+ t.Errorf("#%d: bad KeyIdString got:%q want:%q", i, g, e)
+ }
+ if g, e := pk.KeyIdShortString(), test.keyIdShort; g != e {
+ t.Errorf("#%d: bad KeyIdShortString got:%q want:%q", i, g, e)
+ }
+ }
+}
+
+func TestPublicKeySerialize(t *testing.T) {
+ for i, test := range pubKeyTests {
+ packet, err := Read(readerFromHex(test.hexData))
+ if err != nil {
+ t.Errorf("#%d: Read error: %s", i, err)
+ continue
+ }
+ pk, ok := packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse, got: %#v", i, packet)
+ continue
+ }
+ serializeBuf := bytes.NewBuffer(nil)
+ err = pk.Serialize(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: failed to serialize: %s", i, err)
+ continue
+ }
+
+ packet, err = Read(serializeBuf)
+ if err != nil {
+ t.Errorf("#%d: Read error (from serialized data): %s", i, err)
+ continue
+ }
+ pk, ok = packet.(*PublicKey)
+ if !ok {
+ t.Errorf("#%d: failed to parse serialized data, got: %#v", i, packet)
+ continue
+ }
+ }
+}
+
+func TestEcc384Serialize(t *testing.T) {
+ r := readerFromHex(ecc384PubHex)
+ var w bytes.Buffer
+ for i := 0; i < 2; i++ {
+ // Public key
+ p, err := Read(r)
+ if err != nil {
+ t.Error(err)
+ }
+ pubkey := p.(*PublicKey)
+ if !bytes.Equal(pubkey.ec.oid, []byte{0x2b, 0x81, 0x04, 0x00, 0x22}) {
+ t.Errorf("Unexpected pubkey OID: %x", pubkey.ec.oid)
+ }
+ if !bytes.Equal(pubkey.ec.p.bytes[:5], []byte{0x04, 0xf6, 0xb8, 0xc5, 0xac}) {
+ t.Errorf("Unexpected pubkey P[:5]: %x", pubkey.ec.p.bytes)
+ }
+ if pubkey.KeyId != 0x098033880F54719F {
+ t.Errorf("Unexpected pubkey ID: %x", pubkey.KeyId)
+ }
+ err = pubkey.Serialize(&w)
+ if err != nil {
+ t.Error(err)
+ }
+ // User ID
+ p, err = Read(r)
+ if err != nil {
+ t.Error(err)
+ }
+ uid := p.(*UserId)
+ if uid.Id != "ec_dsa_dh_384 <openpgp@brainhub.org>" {
+ t.Error("Unexpected UID:", uid.Id)
+ }
+ err = uid.Serialize(&w)
+ if err != nil {
+ t.Error(err)
+ }
+ // User ID Sig
+ p, err = Read(r)
+ if err != nil {
+ t.Error(err)
+ }
+ uidSig := p.(*Signature)
+ err = pubkey.VerifyUserIdSignature(uid.Id, pubkey, uidSig)
+ if err != nil {
+ t.Error(err, ": UID")
+ }
+ err = uidSig.Serialize(&w)
+ if err != nil {
+ t.Error(err)
+ }
+ // Subkey
+ p, err = Read(r)
+ if err != nil {
+ t.Error(err)
+ }
+ subkey := p.(*PublicKey)
+ if !bytes.Equal(subkey.ec.oid, []byte{0x2b, 0x81, 0x04, 0x00, 0x22}) {
+ t.Errorf("Unexpected subkey OID: %x", subkey.ec.oid)
+ }
+ if !bytes.Equal(subkey.ec.p.bytes[:5], []byte{0x04, 0x2f, 0xaa, 0x84, 0x02}) {
+ t.Errorf("Unexpected subkey P[:5]: %x", subkey.ec.p.bytes)
+ }
+ if subkey.ecdh.KdfHash != 0x09 {
+ t.Error("Expected KDF hash function SHA384 (0x09), got", subkey.ecdh.KdfHash)
+ }
+ if subkey.ecdh.KdfAlgo != 0x09 {
+ t.Error("Expected KDF symmetric alg AES256 (0x09), got", subkey.ecdh.KdfAlgo)
+ }
+ if subkey.KeyId != 0xAA8B938F9A201946 {
+ t.Errorf("Unexpected subkey ID: %x", subkey.KeyId)
+ }
+ err = subkey.Serialize(&w)
+ if err != nil {
+ t.Error(err)
+ }
+ // Subkey Sig
+ p, err = Read(r)
+ if err != nil {
+ t.Error(err)
+ }
+ subkeySig := p.(*Signature)
+ err = pubkey.VerifyKeySignature(subkey, subkeySig)
+ if err != nil {
+ t.Error(err)
+ }
+ err = subkeySig.Serialize(&w)
+ if err != nil {
+ t.Error(err)
+ }
+ // Now read back what we've written again
+ r = bytes.NewBuffer(w.Bytes())
+ w.Reset()
+ }
+}
+
+const rsaFingerprintHex = "5fb74b1d03b1e3cb31bc2f8aa34d7e18c20c31bb"
+
+const rsaPkDataHex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001"
+
+const dsaFingerprintHex = "eece4c094db002103714c63c8e8fbe54062f19ed"
+
+const dsaPkDataHex = "9901a2044d432f89110400cd581334f0d7a1e1bdc8b9d6d8c0baf68793632735d2bb0903224cbaa1dfbf35a60ee7a13b92643421e1eb41aa8d79bea19a115a677f6b8ba3c7818ce53a6c2a24a1608bd8b8d6e55c5090cbde09dd26e356267465ae25e69ec8bdd57c7bbb2623e4d73336f73a0a9098f7f16da2e25252130fd694c0e8070c55a812a423ae7f00a0ebf50e70c2f19c3520a551bd4b08d30f23530d3d03ff7d0bf4a53a64a09dc5e6e6e35854b7d70c882b0c60293401958b1bd9e40abec3ea05ba87cf64899299d4bd6aa7f459c201d3fbbd6c82004bdc5e8a9eb8082d12054cc90fa9d4ec251a843236a588bf49552441817436c4f43326966fe85447d4e6d0acf8fa1ef0f014730770603ad7634c3088dc52501c237328417c31c89ed70400b2f1a98b0bf42f11fefc430704bebbaa41d9f355600c3facee1e490f64208e0e094ea55e3a598a219a58500bf78ac677b670a14f4e47e9cf8eab4f368cc1ddcaa18cc59309d4cc62dd4f680e73e6cc3e1ce87a84d0925efbcb26c575c093fc42eecf45135fabf6403a25c2016e1774c0484e440a18319072c617cc97ac0a3bb0"
+
+const ecdsaFingerprintHex = "9892270b38b8980b05c8d56d43fe956c542ca00b"
+
+const ecdsaPkDataHex = "9893045071c29413052b8104002304230401f4867769cedfa52c325018896245443968e52e51d0c2df8d939949cb5b330f2921711fbee1c9b9dddb95d15cb0255e99badeddda7cc23d9ddcaacbc290969b9f24019375d61c2e4e3b36953a28d8b2bc95f78c3f1d592fb24499be348656a7b17e3963187b4361afe497bc5f9f81213f04069f8e1fb9e6a6290ae295ca1a92b894396cb4"
+
+// Source: https://sites.google.com/site/brainhub/pgpecckeys#TOC-ECC-NIST-P-384-key
+const ecc384PubHex = `99006f044d53059213052b81040022030304f6b8c5aced5b84ef9f4a209db2e4a9dfb70d28cb8c10ecd57674a9fa5a67389942b62d5e51367df4c7bfd3f8e500feecf07ed265a621a8ebbbe53e947ec78c677eba143bd1533c2b350e1c29f82313e1e1108eba063be1e64b10e6950e799c2db42465635f6473615f64685f333834203c6f70656e70677040627261696e6875622e6f72673e8900cb04101309005305024d530592301480000000002000077072656665727265642d656d61696c2d656e636f64696e67407067702e636f6d7067706d696d65040b090807021901051b03000000021602051e010000000415090a08000a0910098033880f54719fca2b0180aa37350968bd5f115afd8ce7bc7b103822152dbff06d0afcda835329510905b98cb469ba208faab87c7412b799e7b633017f58364ea480e8a1a3f253a0c5f22c446e8be9a9fce6210136ee30811abbd49139de28b5bdf8dc36d06ae748579e9ff503b90073044d53059212052b810400220303042faa84024a20b6735c4897efa5bfb41bf85b7eefeab5ca0cb9ffc8ea04a46acb25534a577694f9e25340a4ab5223a9dd1eda530c8aa2e6718db10d7e672558c7736fe09369ea5739a2a3554bf16d41faa50562f11c6d39bbd5dffb6b9a9ec9180301090989008404181309000c05024d530592051b0c000000000a0910098033880f54719f80970180eee7a6d8fcee41ee4f9289df17f9bcf9d955dca25c583b94336f3a2b2d4986dc5cf417b8d2dc86f741a9e1a6d236c0e3017d1c76575458a0cfb93ae8a2b274fcc65ceecd7a91eec83656ba13219969f06945b48c56bd04152c3a0553c5f2f4bd1267`
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go
new file mode 100644
index 000000000..26337f5aa
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3.go
@@ -0,0 +1,280 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "crypto/md5"
+ "crypto/rsa"
+ "encoding/binary"
+ "fmt"
+ "hash"
+ "io"
+ "math/big"
+ "strconv"
+ "time"
+
+ "golang.org/x/crypto/openpgp/errors"
+)
+
+// PublicKeyV3 represents older, version 3 public keys. These keys are less secure and
+// should not be used for signing or encrypting. They are supported here only for
+// parsing version 3 key material and validating signatures.
+// See RFC 4880, section 5.5.2.
+type PublicKeyV3 struct {
+ CreationTime time.Time
+ DaysToExpire uint16
+ PubKeyAlgo PublicKeyAlgorithm
+ PublicKey *rsa.PublicKey
+ Fingerprint [16]byte
+ KeyId uint64
+ IsSubkey bool
+
+ n, e parsedMPI
+}
+
+// newRSAPublicKeyV3 returns a PublicKey that wraps the given rsa.PublicKey.
+// Included here for testing purposes only. RFC 4880, section 5.5.2:
+// "an implementation MUST NOT generate a V3 key, but MAY accept it."
+func newRSAPublicKeyV3(creationTime time.Time, pub *rsa.PublicKey) *PublicKeyV3 {
+ pk := &PublicKeyV3{
+ CreationTime: creationTime,
+ PublicKey: pub,
+ n: fromBig(pub.N),
+ e: fromBig(big.NewInt(int64(pub.E))),
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return pk
+}
+
+func (pk *PublicKeyV3) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.5.2
+ var buf [8]byte
+ if _, err = readFull(r, buf[:]); err != nil {
+ return
+ }
+ if buf[0] < 2 || buf[0] > 3 {
+ return errors.UnsupportedError("public key version")
+ }
+ pk.CreationTime = time.Unix(int64(uint32(buf[1])<<24|uint32(buf[2])<<16|uint32(buf[3])<<8|uint32(buf[4])), 0)
+ pk.DaysToExpire = binary.BigEndian.Uint16(buf[5:7])
+ pk.PubKeyAlgo = PublicKeyAlgorithm(buf[7])
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ err = pk.parseRSA(r)
+ default:
+ err = errors.UnsupportedError("public key type: " + strconv.Itoa(int(pk.PubKeyAlgo)))
+ }
+ if err != nil {
+ return
+ }
+
+ pk.setFingerPrintAndKeyId()
+ return
+}
+
+func (pk *PublicKeyV3) setFingerPrintAndKeyId() {
+ // RFC 4880, section 12.2
+ fingerPrint := md5.New()
+ fingerPrint.Write(pk.n.bytes)
+ fingerPrint.Write(pk.e.bytes)
+ fingerPrint.Sum(pk.Fingerprint[:0])
+ pk.KeyId = binary.BigEndian.Uint64(pk.n.bytes[len(pk.n.bytes)-8:])
+}
+
+// parseRSA parses RSA public key material from the given Reader. See RFC 4880,
+// section 5.5.2.
+func (pk *PublicKeyV3) parseRSA(r io.Reader) (err error) {
+ if pk.n.bytes, pk.n.bitLength, err = readMPI(r); err != nil {
+ return
+ }
+ if pk.e.bytes, pk.e.bitLength, err = readMPI(r); err != nil {
+ return
+ }
+
+ // RFC 4880 Section 12.2 requires the low 8 bytes of the
+ // modulus to form the key id.
+ if len(pk.n.bytes) < 8 {
+ return errors.StructuralError("v3 public key modulus is too short")
+ }
+ if len(pk.e.bytes) > 3 {
+ err = errors.UnsupportedError("large public exponent")
+ return
+ }
+ rsa := &rsa.PublicKey{N: new(big.Int).SetBytes(pk.n.bytes)}
+ for i := 0; i < len(pk.e.bytes); i++ {
+ rsa.E <<= 8
+ rsa.E |= int(pk.e.bytes[i])
+ }
+ pk.PublicKey = rsa
+ return
+}
+
+// SerializeSignaturePrefix writes the prefix for this public key to the given Writer.
+// The prefix is used when calculating a signature over this public key. See
+// RFC 4880, section 5.2.4.
+func (pk *PublicKeyV3) SerializeSignaturePrefix(w io.Writer) {
+ var pLength uint16
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ pLength += 2 + uint16(len(pk.n.bytes))
+ pLength += 2 + uint16(len(pk.e.bytes))
+ default:
+ panic("unknown public key algorithm")
+ }
+ pLength += 6
+ w.Write([]byte{0x99, byte(pLength >> 8), byte(pLength)})
+ return
+}
+
+func (pk *PublicKeyV3) Serialize(w io.Writer) (err error) {
+ length := 8 // 8 byte header
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ length += 2 + len(pk.n.bytes)
+ length += 2 + len(pk.e.bytes)
+ default:
+ panic("unknown public key algorithm")
+ }
+
+ packetType := packetTypePublicKey
+ if pk.IsSubkey {
+ packetType = packetTypePublicSubkey
+ }
+ if err = serializeHeader(w, packetType, length); err != nil {
+ return
+ }
+ return pk.serializeWithoutHeaders(w)
+}
+
+// serializeWithoutHeaders marshals the PublicKey to w in the form of an
+// OpenPGP public key packet, not including the packet header.
+func (pk *PublicKeyV3) serializeWithoutHeaders(w io.Writer) (err error) {
+ var buf [8]byte
+ // Version 3
+ buf[0] = 3
+ // Creation time
+ t := uint32(pk.CreationTime.Unix())
+ buf[1] = byte(t >> 24)
+ buf[2] = byte(t >> 16)
+ buf[3] = byte(t >> 8)
+ buf[4] = byte(t)
+ // Days to expire
+ buf[5] = byte(pk.DaysToExpire >> 8)
+ buf[6] = byte(pk.DaysToExpire)
+ // Public key algorithm
+ buf[7] = byte(pk.PubKeyAlgo)
+
+ if _, err = w.Write(buf[:]); err != nil {
+ return
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ return writeMPIs(w, pk.n, pk.e)
+ }
+ return errors.InvalidArgumentError("bad public-key algorithm")
+}
+
+// CanSign returns true iff this public key can generate signatures
+func (pk *PublicKeyV3) CanSign() bool {
+ return pk.PubKeyAlgo != PubKeyAlgoRSAEncryptOnly
+}
+
+// VerifySignatureV3 returns nil iff sig is a valid signature, made by this
+// public key, of the data hashed into signed. signed is mutated by this call.
+func (pk *PublicKeyV3) VerifySignatureV3(signed hash.Hash, sig *SignatureV3) (err error) {
+ if !pk.CanSign() {
+ return errors.InvalidArgumentError("public key cannot generate signatures")
+ }
+
+ suffix := make([]byte, 5)
+ suffix[0] = byte(sig.SigType)
+ binary.BigEndian.PutUint32(suffix[1:], uint32(sig.CreationTime.Unix()))
+ signed.Write(suffix)
+ hashBytes := signed.Sum(nil)
+
+ if hashBytes[0] != sig.HashTag[0] || hashBytes[1] != sig.HashTag[1] {
+ return errors.SignatureError("hash tag doesn't match")
+ }
+
+ if pk.PubKeyAlgo != sig.PubKeyAlgo {
+ return errors.InvalidArgumentError("public key and signature use different algorithms")
+ }
+
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ if err = rsa.VerifyPKCS1v15(pk.PublicKey, sig.Hash, hashBytes, sig.RSASignature.bytes); err != nil {
+ return errors.SignatureError("RSA verification failure")
+ }
+ return
+ default:
+ // V3 public keys only support RSA.
+ panic("shouldn't happen")
+ }
+ panic("unreachable")
+}
+
+// VerifyUserIdSignatureV3 returns nil iff sig is a valid signature, made by this
+// public key, that id is the identity of pub.
+func (pk *PublicKeyV3) VerifyUserIdSignatureV3(id string, pub *PublicKeyV3, sig *SignatureV3) (err error) {
+ h, err := userIdSignatureV3Hash(id, pk, sig.Hash)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignatureV3(h, sig)
+}
+
+// VerifyKeySignatureV3 returns nil iff sig is a valid signature, made by this
+// public key, of signed.
+func (pk *PublicKeyV3) VerifyKeySignatureV3(signed *PublicKeyV3, sig *SignatureV3) (err error) {
+ h, err := keySignatureHash(pk, signed, sig.Hash)
+ if err != nil {
+ return err
+ }
+ return pk.VerifySignatureV3(h, sig)
+}
+
+// userIdSignatureV3Hash returns a Hash of the message that needs to be signed
+// to assert that pk is a valid key for id.
+func userIdSignatureV3Hash(id string, pk signingKey, hfn crypto.Hash) (h hash.Hash, err error) {
+ if !hfn.Available() {
+ return nil, errors.UnsupportedError("hash function")
+ }
+ h = hfn.New()
+
+ // RFC 4880, section 5.2.4
+ pk.SerializeSignaturePrefix(h)
+ pk.serializeWithoutHeaders(h)
+
+ h.Write([]byte(id))
+
+ return
+}
+
+// KeyIdString returns the public key's fingerprint in capital hex
+// (e.g. "6C7EE1B8621CC013").
+func (pk *PublicKeyV3) KeyIdString() string {
+ return fmt.Sprintf("%X", pk.KeyId)
+}
+
+// KeyIdShortString returns the short form of public key's fingerprint
+// in capital hex, as shown by gpg --list-keys (e.g. "621CC013").
+func (pk *PublicKeyV3) KeyIdShortString() string {
+ return fmt.Sprintf("%X", pk.KeyId&0xFFFFFFFF)
+}
+
+// BitLength returns the bit length for the given public key.
+func (pk *PublicKeyV3) BitLength() (bitLength uint16, err error) {
+ switch pk.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSAEncryptOnly, PubKeyAlgoRSASignOnly:
+ bitLength = pk.n.bitLength
+ default:
+ err = errors.InvalidArgumentError("bad public-key algorithm")
+ }
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3_test.go b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3_test.go
new file mode 100644
index 000000000..e06405904
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/public_key_v3_test.go
@@ -0,0 +1,82 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+ "time"
+)
+
+var pubKeyV3Test = struct {
+ hexFingerprint string
+ creationTime time.Time
+ pubKeyAlgo PublicKeyAlgorithm
+ keyId uint64
+ keyIdString string
+ keyIdShort string
+}{
+ "103BECF5BD1E837C89D19E98487767F7",
+ time.Unix(779753634, 0),
+ PubKeyAlgoRSA,
+ 0xDE0F188A5DA5E3C9,
+ "DE0F188A5DA5E3C9",
+ "5DA5E3C9"}
+
+func TestPublicKeyV3Read(t *testing.T) {
+ i, test := 0, pubKeyV3Test
+ packet, err := Read(v3KeyReader(t))
+ if err != nil {
+ t.Fatalf("#%d: Read error: %s", i, err)
+ }
+ pk, ok := packet.(*PublicKeyV3)
+ if !ok {
+ t.Fatalf("#%d: failed to parse, got: %#v", i, packet)
+ }
+ if pk.PubKeyAlgo != test.pubKeyAlgo {
+ t.Errorf("#%d: bad public key algorithm got:%x want:%x", i, pk.PubKeyAlgo, test.pubKeyAlgo)
+ }
+ if !pk.CreationTime.Equal(test.creationTime) {
+ t.Errorf("#%d: bad creation time got:%v want:%v", i, pk.CreationTime, test.creationTime)
+ }
+ expectedFingerprint, _ := hex.DecodeString(test.hexFingerprint)
+ if !bytes.Equal(expectedFingerprint, pk.Fingerprint[:]) {
+ t.Errorf("#%d: bad fingerprint got:%x want:%x", i, pk.Fingerprint[:], expectedFingerprint)
+ }
+ if pk.KeyId != test.keyId {
+ t.Errorf("#%d: bad keyid got:%x want:%x", i, pk.KeyId, test.keyId)
+ }
+ if g, e := pk.KeyIdString(), test.keyIdString; g != e {
+ t.Errorf("#%d: bad KeyIdString got:%q want:%q", i, g, e)
+ }
+ if g, e := pk.KeyIdShortString(), test.keyIdShort; g != e {
+ t.Errorf("#%d: bad KeyIdShortString got:%q want:%q", i, g, e)
+ }
+}
+
+func TestPublicKeyV3Serialize(t *testing.T) {
+ //for i, test := range pubKeyV3Tests {
+ i := 0
+ packet, err := Read(v3KeyReader(t))
+ if err != nil {
+ t.Fatalf("#%d: Read error: %s", i, err)
+ }
+ pk, ok := packet.(*PublicKeyV3)
+ if !ok {
+ t.Fatalf("#%d: failed to parse, got: %#v", i, packet)
+ }
+ var serializeBuf bytes.Buffer
+ if err = pk.Serialize(&serializeBuf); err != nil {
+ t.Fatalf("#%d: failed to serialize: %s", i, err)
+ }
+
+ if packet, err = Read(bytes.NewBuffer(serializeBuf.Bytes())); err != nil {
+ t.Fatalf("#%d: Read error (from serialized data): %s", i, err)
+ }
+ if pk, ok = packet.(*PublicKeyV3); !ok {
+ t.Fatalf("#%d: failed to parse serialized data, got: %#v", i, packet)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/reader.go b/vendor/golang.org/x/crypto/openpgp/packet/reader.go
new file mode 100644
index 000000000..34bc7c613
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/reader.go
@@ -0,0 +1,76 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "golang.org/x/crypto/openpgp/errors"
+ "io"
+)
+
+// Reader reads packets from an io.Reader and allows packets to be 'unread' so
+// that they result from the next call to Next.
+type Reader struct {
+ q []Packet
+ readers []io.Reader
+}
+
+// New io.Readers are pushed when a compressed or encrypted packet is processed
+// and recursively treated as a new source of packets. However, a carefully
+// crafted packet can trigger an infinite recursive sequence of packets. See
+// http://mumble.net/~campbell/misc/pgp-quine
+// https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2013-4402
+// This constant limits the number of recursive packets that may be pushed.
+const maxReaders = 32
+
+// Next returns the most recently unread Packet, or reads another packet from
+// the top-most io.Reader. Unknown packet types are skipped.
+func (r *Reader) Next() (p Packet, err error) {
+ if len(r.q) > 0 {
+ p = r.q[len(r.q)-1]
+ r.q = r.q[:len(r.q)-1]
+ return
+ }
+
+ for len(r.readers) > 0 {
+ p, err = Read(r.readers[len(r.readers)-1])
+ if err == nil {
+ return
+ }
+ if err == io.EOF {
+ r.readers = r.readers[:len(r.readers)-1]
+ continue
+ }
+ if _, ok := err.(errors.UnknownPacketTypeError); !ok {
+ return nil, err
+ }
+ }
+
+ return nil, io.EOF
+}
+
+// Push causes the Reader to start reading from a new io.Reader. When an EOF
+// error is seen from the new io.Reader, it is popped and the Reader continues
+// to read from the next most recent io.Reader. Push returns a StructuralError
+// if pushing the reader would exceed the maximum recursion level, otherwise it
+// returns nil.
+func (r *Reader) Push(reader io.Reader) (err error) {
+ if len(r.readers) >= maxReaders {
+ return errors.StructuralError("too many layers of packets")
+ }
+ r.readers = append(r.readers, reader)
+ return nil
+}
+
+// Unread causes the given Packet to be returned from the next call to Next.
+func (r *Reader) Unread(p Packet) {
+ r.q = append(r.q, p)
+}
+
+func NewReader(r io.Reader) *Reader {
+ return &Reader{
+ q: nil,
+ readers: []io.Reader{r},
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature.go b/vendor/golang.org/x/crypto/openpgp/packet/signature.go
new file mode 100644
index 000000000..4368f6b9e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/signature.go
@@ -0,0 +1,706 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "encoding/binary"
+ "hash"
+ "io"
+ "strconv"
+ "time"
+
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/s2k"
+)
+
+const (
+ // See RFC 4880, section 5.2.3.21 for details.
+ KeyFlagCertify = 1 << iota
+ KeyFlagSign
+ KeyFlagEncryptCommunications
+ KeyFlagEncryptStorage
+)
+
+// Signature represents a signature. See RFC 4880, section 5.2.
+type Signature struct {
+ SigType SignatureType
+ PubKeyAlgo PublicKeyAlgorithm
+ Hash crypto.Hash
+
+ // HashSuffix is extra data that is hashed in after the signed data.
+ HashSuffix []byte
+ // HashTag contains the first two bytes of the hash for fast rejection
+ // of bad signed data.
+ HashTag [2]byte
+ CreationTime time.Time
+
+ RSASignature parsedMPI
+ DSASigR, DSASigS parsedMPI
+ ECDSASigR, ECDSASigS parsedMPI
+
+ // rawSubpackets contains the unparsed subpackets, in order.
+ rawSubpackets []outputSubpacket
+
+ // The following are optional so are nil when not included in the
+ // signature.
+
+ SigLifetimeSecs, KeyLifetimeSecs *uint32
+ PreferredSymmetric, PreferredHash, PreferredCompression []uint8
+ IssuerKeyId *uint64
+ IsPrimaryId *bool
+
+ // FlagsValid is set if any flags were given. See RFC 4880, section
+ // 5.2.3.21 for details.
+ FlagsValid bool
+ FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool
+
+ // RevocationReason is set if this signature has been revoked.
+ // See RFC 4880, section 5.2.3.23 for details.
+ RevocationReason *uint8
+ RevocationReasonText string
+
+ // MDC is set if this signature has a feature packet that indicates
+ // support for MDC subpackets.
+ MDC bool
+
+ // EmbeddedSignature, if non-nil, is a signature of the parent key, by
+ // this key. This prevents an attacker from claiming another's signing
+ // subkey as their own.
+ EmbeddedSignature *Signature
+
+ outSubpackets []outputSubpacket
+}
+
+func (sig *Signature) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.2.3
+ var buf [5]byte
+ _, err = readFull(r, buf[:1])
+ if err != nil {
+ return
+ }
+ if buf[0] != 4 {
+ err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
+ return
+ }
+
+ _, err = readFull(r, buf[:5])
+ if err != nil {
+ return
+ }
+ sig.SigType = SignatureType(buf[0])
+ sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA:
+ default:
+ err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ return
+ }
+
+ var ok bool
+ sig.Hash, ok = s2k.HashIdToHash(buf[2])
+ if !ok {
+ return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
+ }
+
+ hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4])
+ l := 6 + hashedSubpacketsLength
+ sig.HashSuffix = make([]byte, l+6)
+ sig.HashSuffix[0] = 4
+ copy(sig.HashSuffix[1:], buf[:5])
+ hashedSubpackets := sig.HashSuffix[6:l]
+ _, err = readFull(r, hashedSubpackets)
+ if err != nil {
+ return
+ }
+ // See RFC 4880, section 5.2.4
+ trailer := sig.HashSuffix[l:]
+ trailer[0] = 4
+ trailer[1] = 0xff
+ trailer[2] = uint8(l >> 24)
+ trailer[3] = uint8(l >> 16)
+ trailer[4] = uint8(l >> 8)
+ trailer[5] = uint8(l)
+
+ err = parseSignatureSubpackets(sig, hashedSubpackets, true)
+ if err != nil {
+ return
+ }
+
+ _, err = readFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+ unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1])
+ unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
+ _, err = readFull(r, unhashedSubpackets)
+ if err != nil {
+ return
+ }
+ err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
+ if err != nil {
+ return
+ }
+
+ _, err = readFull(r, sig.HashTag[:2])
+ if err != nil {
+ return
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
+ case PubKeyAlgoDSA:
+ sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
+ if err == nil {
+ sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
+ }
+ case PubKeyAlgoECDSA:
+ sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r)
+ if err == nil {
+ sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r)
+ }
+ default:
+ panic("unreachable")
+ }
+ return
+}
+
+// parseSignatureSubpackets parses subpackets of the main signature packet. See
+// RFC 4880, section 5.2.3.1.
+func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) {
+ for len(subpackets) > 0 {
+ subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
+ if err != nil {
+ return
+ }
+ }
+
+ if sig.CreationTime.IsZero() {
+ err = errors.StructuralError("no creation time in signature")
+ }
+
+ return
+}
+
+type signatureSubpacketType uint8
+
+const (
+ creationTimeSubpacket signatureSubpacketType = 2
+ signatureExpirationSubpacket signatureSubpacketType = 3
+ keyExpirationSubpacket signatureSubpacketType = 9
+ prefSymmetricAlgosSubpacket signatureSubpacketType = 11
+ issuerSubpacket signatureSubpacketType = 16
+ prefHashAlgosSubpacket signatureSubpacketType = 21
+ prefCompressionSubpacket signatureSubpacketType = 22
+ primaryUserIdSubpacket signatureSubpacketType = 25
+ keyFlagsSubpacket signatureSubpacketType = 27
+ reasonForRevocationSubpacket signatureSubpacketType = 29
+ featuresSubpacket signatureSubpacketType = 30
+ embeddedSignatureSubpacket signatureSubpacketType = 32
+)
+
+// parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
+func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) {
+ // RFC 4880, section 5.2.3.1
+ var (
+ length uint32
+ packetType signatureSubpacketType
+ isCritical bool
+ )
+ switch {
+ case subpacket[0] < 192:
+ length = uint32(subpacket[0])
+ subpacket = subpacket[1:]
+ case subpacket[0] < 255:
+ if len(subpacket) < 2 {
+ goto Truncated
+ }
+ length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
+ subpacket = subpacket[2:]
+ default:
+ if len(subpacket) < 5 {
+ goto Truncated
+ }
+ length = uint32(subpacket[1])<<24 |
+ uint32(subpacket[2])<<16 |
+ uint32(subpacket[3])<<8 |
+ uint32(subpacket[4])
+ subpacket = subpacket[5:]
+ }
+ if length > uint32(len(subpacket)) {
+ goto Truncated
+ }
+ rest = subpacket[length:]
+ subpacket = subpacket[:length]
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("zero length signature subpacket")
+ return
+ }
+ packetType = signatureSubpacketType(subpacket[0] & 0x7f)
+ isCritical = subpacket[0]&0x80 == 0x80
+ subpacket = subpacket[1:]
+ sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
+ switch packetType {
+ case creationTimeSubpacket:
+ if !isHashed {
+ err = errors.StructuralError("signature creation time in non-hashed area")
+ return
+ }
+ if len(subpacket) != 4 {
+ err = errors.StructuralError("signature creation time not four bytes")
+ return
+ }
+ t := binary.BigEndian.Uint32(subpacket)
+ sig.CreationTime = time.Unix(int64(t), 0)
+ case signatureExpirationSubpacket:
+ // Signature expiration time, section 5.2.3.10
+ if !isHashed {
+ return
+ }
+ if len(subpacket) != 4 {
+ err = errors.StructuralError("expiration subpacket with bad length")
+ return
+ }
+ sig.SigLifetimeSecs = new(uint32)
+ *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+ case keyExpirationSubpacket:
+ // Key expiration time, section 5.2.3.6
+ if !isHashed {
+ return
+ }
+ if len(subpacket) != 4 {
+ err = errors.StructuralError("key expiration subpacket with bad length")
+ return
+ }
+ sig.KeyLifetimeSecs = new(uint32)
+ *sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
+ case prefSymmetricAlgosSubpacket:
+ // Preferred symmetric algorithms, section 5.2.3.7
+ if !isHashed {
+ return
+ }
+ sig.PreferredSymmetric = make([]byte, len(subpacket))
+ copy(sig.PreferredSymmetric, subpacket)
+ case issuerSubpacket:
+ // Issuer, section 5.2.3.5
+ if len(subpacket) != 8 {
+ err = errors.StructuralError("issuer subpacket with bad length")
+ return
+ }
+ sig.IssuerKeyId = new(uint64)
+ *sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
+ case prefHashAlgosSubpacket:
+ // Preferred hash algorithms, section 5.2.3.8
+ if !isHashed {
+ return
+ }
+ sig.PreferredHash = make([]byte, len(subpacket))
+ copy(sig.PreferredHash, subpacket)
+ case prefCompressionSubpacket:
+ // Preferred compression algorithms, section 5.2.3.9
+ if !isHashed {
+ return
+ }
+ sig.PreferredCompression = make([]byte, len(subpacket))
+ copy(sig.PreferredCompression, subpacket)
+ case primaryUserIdSubpacket:
+ // Primary User ID, section 5.2.3.19
+ if !isHashed {
+ return
+ }
+ if len(subpacket) != 1 {
+ err = errors.StructuralError("primary user id subpacket with bad length")
+ return
+ }
+ sig.IsPrimaryId = new(bool)
+ if subpacket[0] > 0 {
+ *sig.IsPrimaryId = true
+ }
+ case keyFlagsSubpacket:
+ // Key flags, section 5.2.3.21
+ if !isHashed {
+ return
+ }
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("empty key flags subpacket")
+ return
+ }
+ sig.FlagsValid = true
+ if subpacket[0]&KeyFlagCertify != 0 {
+ sig.FlagCertify = true
+ }
+ if subpacket[0]&KeyFlagSign != 0 {
+ sig.FlagSign = true
+ }
+ if subpacket[0]&KeyFlagEncryptCommunications != 0 {
+ sig.FlagEncryptCommunications = true
+ }
+ if subpacket[0]&KeyFlagEncryptStorage != 0 {
+ sig.FlagEncryptStorage = true
+ }
+ case reasonForRevocationSubpacket:
+ // Reason For Revocation, section 5.2.3.23
+ if !isHashed {
+ return
+ }
+ if len(subpacket) == 0 {
+ err = errors.StructuralError("empty revocation reason subpacket")
+ return
+ }
+ sig.RevocationReason = new(uint8)
+ *sig.RevocationReason = subpacket[0]
+ sig.RevocationReasonText = string(subpacket[1:])
+ case featuresSubpacket:
+ // Features subpacket, section 5.2.3.24 specifies a very general
+ // mechanism for OpenPGP implementations to signal support for new
+ // features. In practice, the subpacket is used exclusively to
+ // indicate support for MDC-protected encryption.
+ sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1
+ case embeddedSignatureSubpacket:
+ // Only usage is in signatures that cross-certify
+ // signing subkeys. section 5.2.3.26 describes the
+ // format, with its usage described in section 11.1
+ if sig.EmbeddedSignature != nil {
+ err = errors.StructuralError("Cannot have multiple embedded signatures")
+ return
+ }
+ sig.EmbeddedSignature = new(Signature)
+ // Embedded signatures are required to be v4 signatures see
+ // section 12.1. However, we only parse v4 signatures in this
+ // file anyway.
+ if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil {
+ return nil, err
+ }
+ if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding {
+ return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType)))
+ }
+ default:
+ if isCritical {
+ err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
+ return
+ }
+ }
+ return
+
+Truncated:
+ err = errors.StructuralError("signature subpacket truncated")
+ return
+}
+
+// subpacketLengthLength returns the length, in bytes, of an encoded length value.
+func subpacketLengthLength(length int) int {
+ if length < 192 {
+ return 1
+ }
+ if length < 16320 {
+ return 2
+ }
+ return 5
+}
+
+// serializeSubpacketLength marshals the given length into to.
+func serializeSubpacketLength(to []byte, length int) int {
+ // RFC 4880, Section 4.2.2.
+ if length < 192 {
+ to[0] = byte(length)
+ return 1
+ }
+ if length < 16320 {
+ length -= 192
+ to[0] = byte((length >> 8) + 192)
+ to[1] = byte(length)
+ return 2
+ }
+ to[0] = 255
+ to[1] = byte(length >> 24)
+ to[2] = byte(length >> 16)
+ to[3] = byte(length >> 8)
+ to[4] = byte(length)
+ return 5
+}
+
+// subpacketsLength returns the serialized length, in bytes, of the given
+// subpackets.
+func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
+ for _, subpacket := range subpackets {
+ if subpacket.hashed == hashed {
+ length += subpacketLengthLength(len(subpacket.contents) + 1)
+ length += 1 // type byte
+ length += len(subpacket.contents)
+ }
+ }
+ return
+}
+
+// serializeSubpackets marshals the given subpackets into to.
+func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
+ for _, subpacket := range subpackets {
+ if subpacket.hashed == hashed {
+ n := serializeSubpacketLength(to, len(subpacket.contents)+1)
+ to[n] = byte(subpacket.subpacketType)
+ to = to[1+n:]
+ n = copy(to, subpacket.contents)
+ to = to[n:]
+ }
+ }
+ return
+}
+
+// KeyExpired returns whether sig is a self-signature of a key that has
+// expired.
+func (sig *Signature) KeyExpired(currentTime time.Time) bool {
+ if sig.KeyLifetimeSecs == nil {
+ return false
+ }
+ expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second)
+ return currentTime.After(expiry)
+}
+
+// buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
+func (sig *Signature) buildHashSuffix() (err error) {
+ hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
+
+ var ok bool
+ l := 6 + hashedSubpacketsLen
+ sig.HashSuffix = make([]byte, l+6)
+ sig.HashSuffix[0] = 4
+ sig.HashSuffix[1] = uint8(sig.SigType)
+ sig.HashSuffix[2] = uint8(sig.PubKeyAlgo)
+ sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
+ if !ok {
+ sig.HashSuffix = nil
+ return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
+ }
+ sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
+ sig.HashSuffix[5] = byte(hashedSubpacketsLen)
+ serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
+ trailer := sig.HashSuffix[l:]
+ trailer[0] = 4
+ trailer[1] = 0xff
+ trailer[2] = byte(l >> 24)
+ trailer[3] = byte(l >> 16)
+ trailer[4] = byte(l >> 8)
+ trailer[5] = byte(l)
+ return
+}
+
+func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) {
+ err = sig.buildHashSuffix()
+ if err != nil {
+ return
+ }
+
+ h.Write(sig.HashSuffix)
+ digest = h.Sum(nil)
+ copy(sig.HashTag[:], digest)
+ return
+}
+
+// Sign signs a message with a private key. The hash, h, must contain
+// the hash of the message to be signed and will be mutated by this function.
+// On success, the signature is stored in sig. Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) {
+ sig.outSubpackets = sig.buildSubpackets()
+ digest, err := sig.signPrepareHash(h)
+ if err != nil {
+ return
+ }
+
+ switch priv.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
+ sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
+ case PubKeyAlgoDSA:
+ dsaPriv := priv.PrivateKey.(*dsa.PrivateKey)
+
+ // Need to truncate hashBytes to match FIPS 186-3 section 4.6.
+ subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8
+ if len(digest) > subgroupSize {
+ digest = digest[:subgroupSize]
+ }
+ r, s, err := dsa.Sign(config.Random(), dsaPriv, digest)
+ if err == nil {
+ sig.DSASigR.bytes = r.Bytes()
+ sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
+ sig.DSASigS.bytes = s.Bytes()
+ sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
+ }
+ case PubKeyAlgoECDSA:
+ r, s, err := ecdsa.Sign(config.Random(), priv.PrivateKey.(*ecdsa.PrivateKey), digest)
+ if err == nil {
+ sig.ECDSASigR = fromBig(r)
+ sig.ECDSASigS = fromBig(s)
+ }
+ default:
+ err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ }
+
+ return
+}
+
+// SignUserId computes a signature from priv, asserting that pub is a valid
+// key for the identity id. On success, the signature is stored in sig. Call
+// Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error {
+ h, err := userIdSignatureHash(id, pub, sig.Hash)
+ if err != nil {
+ return nil
+ }
+ return sig.Sign(h, priv, config)
+}
+
+// SignKey computes a signature from priv, asserting that pub is a subkey. On
+// success, the signature is stored in sig. Call Serialize to write it out.
+// If config is nil, sensible defaults will be used.
+func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error {
+ h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash)
+ if err != nil {
+ return err
+ }
+ return sig.Sign(h, priv, config)
+}
+
+// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
+// called first.
+func (sig *Signature) Serialize(w io.Writer) (err error) {
+ if len(sig.outSubpackets) == 0 {
+ sig.outSubpackets = sig.rawSubpackets
+ }
+ if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil {
+ return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
+ }
+
+ sigLength := 0
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sigLength = 2 + len(sig.RSASignature.bytes)
+ case PubKeyAlgoDSA:
+ sigLength = 2 + len(sig.DSASigR.bytes)
+ sigLength += 2 + len(sig.DSASigS.bytes)
+ case PubKeyAlgoECDSA:
+ sigLength = 2 + len(sig.ECDSASigR.bytes)
+ sigLength += 2 + len(sig.ECDSASigS.bytes)
+ default:
+ panic("impossible")
+ }
+
+ unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
+ length := len(sig.HashSuffix) - 6 /* trailer not included */ +
+ 2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
+ 2 /* hash tag */ + sigLength
+ err = serializeHeader(w, packetTypeSignature, length)
+ if err != nil {
+ return
+ }
+
+ _, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6])
+ if err != nil {
+ return
+ }
+
+ unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
+ unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
+ unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
+ serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
+
+ _, err = w.Write(unhashedSubpackets)
+ if err != nil {
+ return
+ }
+ _, err = w.Write(sig.HashTag[:])
+ if err != nil {
+ return
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ err = writeMPIs(w, sig.RSASignature)
+ case PubKeyAlgoDSA:
+ err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
+ case PubKeyAlgoECDSA:
+ err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS)
+ default:
+ panic("impossible")
+ }
+ return
+}
+
+// outputSubpacket represents a subpacket to be marshaled.
+type outputSubpacket struct {
+ hashed bool // true if this subpacket is in the hashed area.
+ subpacketType signatureSubpacketType
+ isCritical bool
+ contents []byte
+}
+
+func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
+ creationTime := make([]byte, 4)
+ binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
+ subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
+
+ if sig.IssuerKeyId != nil {
+ keyId := make([]byte, 8)
+ binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
+ subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
+ }
+
+ if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 {
+ sigLifetime := make([]byte, 4)
+ binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs)
+ subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime})
+ }
+
+ // Key flags may only appear in self-signatures or certification signatures.
+
+ if sig.FlagsValid {
+ var flags byte
+ if sig.FlagCertify {
+ flags |= KeyFlagCertify
+ }
+ if sig.FlagSign {
+ flags |= KeyFlagSign
+ }
+ if sig.FlagEncryptCommunications {
+ flags |= KeyFlagEncryptCommunications
+ }
+ if sig.FlagEncryptStorage {
+ flags |= KeyFlagEncryptStorage
+ }
+ subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}})
+ }
+
+ // The following subpackets may only appear in self-signatures
+
+ if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 {
+ keyLifetime := make([]byte, 4)
+ binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs)
+ subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime})
+ }
+
+ if sig.IsPrimaryId != nil && *sig.IsPrimaryId {
+ subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}})
+ }
+
+ if len(sig.PreferredSymmetric) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric})
+ }
+
+ if len(sig.PreferredHash) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash})
+ }
+
+ if len(sig.PreferredCompression) > 0 {
+ subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression})
+ }
+
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature_test.go b/vendor/golang.org/x/crypto/openpgp/packet/signature_test.go
new file mode 100644
index 000000000..c1bbde8b0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/signature_test.go
@@ -0,0 +1,42 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "encoding/hex"
+ "testing"
+)
+
+func TestSignatureRead(t *testing.T) {
+ packet, err := Read(readerFromHex(signatureDataHex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ sig, ok := packet.(*Signature)
+ if !ok || sig.SigType != SigTypeBinary || sig.PubKeyAlgo != PubKeyAlgoRSA || sig.Hash != crypto.SHA1 {
+ t.Errorf("failed to parse, got: %#v", packet)
+ }
+}
+
+func TestSignatureReserialize(t *testing.T) {
+ packet, _ := Read(readerFromHex(signatureDataHex))
+ sig := packet.(*Signature)
+ out := new(bytes.Buffer)
+ err := sig.Serialize(out)
+ if err != nil {
+ t.Errorf("error reserializing: %s", err)
+ return
+ }
+
+ expected, _ := hex.DecodeString(signatureDataHex)
+ if !bytes.Equal(expected, out.Bytes()) {
+ t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
+ }
+}
+
+const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e"
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go b/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go
new file mode 100644
index 000000000..6edff8893
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/signature_v3.go
@@ -0,0 +1,146 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "strconv"
+ "time"
+
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/s2k"
+)
+
+// SignatureV3 represents older version 3 signatures. These signatures are less secure
+// than version 4 and should not be used to create new signatures. They are included
+// here for backwards compatibility to read and validate with older key material.
+// See RFC 4880, section 5.2.2.
+type SignatureV3 struct {
+ SigType SignatureType
+ CreationTime time.Time
+ IssuerKeyId uint64
+ PubKeyAlgo PublicKeyAlgorithm
+ Hash crypto.Hash
+ HashTag [2]byte
+
+ RSASignature parsedMPI
+ DSASigR, DSASigS parsedMPI
+}
+
+func (sig *SignatureV3) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.2.2
+ var buf [8]byte
+ if _, err = readFull(r, buf[:1]); err != nil {
+ return
+ }
+ if buf[0] < 2 || buf[0] > 3 {
+ err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
+ return
+ }
+ if _, err = readFull(r, buf[:1]); err != nil {
+ return
+ }
+ if buf[0] != 5 {
+ err = errors.UnsupportedError(
+ "invalid hashed material length " + strconv.Itoa(int(buf[0])))
+ return
+ }
+
+ // Read hashed material: signature type + creation time
+ if _, err = readFull(r, buf[:5]); err != nil {
+ return
+ }
+ sig.SigType = SignatureType(buf[0])
+ t := binary.BigEndian.Uint32(buf[1:5])
+ sig.CreationTime = time.Unix(int64(t), 0)
+
+ // Eight-octet Key ID of signer.
+ if _, err = readFull(r, buf[:8]); err != nil {
+ return
+ }
+ sig.IssuerKeyId = binary.BigEndian.Uint64(buf[:])
+
+ // Public-key and hash algorithm
+ if _, err = readFull(r, buf[:2]); err != nil {
+ return
+ }
+ sig.PubKeyAlgo = PublicKeyAlgorithm(buf[0])
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA:
+ default:
+ err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
+ return
+ }
+ var ok bool
+ if sig.Hash, ok = s2k.HashIdToHash(buf[1]); !ok {
+ return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
+ }
+
+ // Two-octet field holding left 16 bits of signed hash value.
+ if _, err = readFull(r, sig.HashTag[:2]); err != nil {
+ return
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
+ case PubKeyAlgoDSA:
+ if sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r); err != nil {
+ return
+ }
+ sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
+ default:
+ panic("unreachable")
+ }
+ return
+}
+
+// Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
+// called first.
+func (sig *SignatureV3) Serialize(w io.Writer) (err error) {
+ buf := make([]byte, 8)
+
+ // Write the sig type and creation time
+ buf[0] = byte(sig.SigType)
+ binary.BigEndian.PutUint32(buf[1:5], uint32(sig.CreationTime.Unix()))
+ if _, err = w.Write(buf[:5]); err != nil {
+ return
+ }
+
+ // Write the issuer long key ID
+ binary.BigEndian.PutUint64(buf[:8], sig.IssuerKeyId)
+ if _, err = w.Write(buf[:8]); err != nil {
+ return
+ }
+
+ // Write public key algorithm, hash ID, and hash value
+ buf[0] = byte(sig.PubKeyAlgo)
+ hashId, ok := s2k.HashToHashId(sig.Hash)
+ if !ok {
+ return errors.UnsupportedError(fmt.Sprintf("hash function %v", sig.Hash))
+ }
+ buf[1] = hashId
+ copy(buf[2:4], sig.HashTag[:])
+ if _, err = w.Write(buf[:4]); err != nil {
+ return
+ }
+
+ if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil {
+ return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
+ }
+
+ switch sig.PubKeyAlgo {
+ case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
+ err = writeMPIs(w, sig.RSASignature)
+ case PubKeyAlgoDSA:
+ err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
+ default:
+ panic("impossible")
+ }
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/signature_v3_test.go b/vendor/golang.org/x/crypto/openpgp/packet/signature_v3_test.go
new file mode 100644
index 000000000..ad7b62ac1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/signature_v3_test.go
@@ -0,0 +1,92 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "testing"
+
+ "golang.org/x/crypto/openpgp/armor"
+)
+
+func TestSignatureV3Read(t *testing.T) {
+ r := v3KeyReader(t)
+ Read(r) // Skip public key
+ Read(r) // Skip uid
+ packet, err := Read(r) // Signature
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ sig, ok := packet.(*SignatureV3)
+ if !ok || sig.SigType != SigTypeGenericCert || sig.PubKeyAlgo != PubKeyAlgoRSA || sig.Hash != crypto.MD5 {
+ t.Errorf("failed to parse, got: %#v", packet)
+ }
+}
+
+func TestSignatureV3Reserialize(t *testing.T) {
+ r := v3KeyReader(t)
+ Read(r) // Skip public key
+ Read(r) // Skip uid
+ packet, err := Read(r)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ sig := packet.(*SignatureV3)
+ out := new(bytes.Buffer)
+ if err = sig.Serialize(out); err != nil {
+ t.Errorf("error reserializing: %s", err)
+ return
+ }
+ expected, err := ioutil.ReadAll(v3KeyReader(t))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ expected = expected[4+141+4+39:] // See pgpdump offsets below, this is where the sig starts
+ if !bytes.Equal(expected, out.Bytes()) {
+ t.Errorf("output doesn't match input (got vs expected):\n%s\n%s", hex.Dump(out.Bytes()), hex.Dump(expected))
+ }
+}
+
+func v3KeyReader(t *testing.T) io.Reader {
+ armorBlock, err := armor.Decode(bytes.NewBufferString(keySigV3Armor))
+ if err != nil {
+ t.Fatalf("armor Decode failed: %v", err)
+ }
+ return armorBlock.Body
+}
+
+// keySigV3Armor is some V3 public key I found in an SKS dump.
+// Old: Public Key Packet(tag 6)(141 bytes)
+// Ver 4 - new
+// Public key creation time - Fri Sep 16 17:13:54 CDT 1994
+// Pub alg - unknown(pub 0)
+// Unknown public key(pub 0)
+// Old: User ID Packet(tag 13)(39 bytes)
+// User ID - Armin M. Warda <warda@nephilim.ruhr.de>
+// Old: Signature Packet(tag 2)(149 bytes)
+// Ver 4 - new
+// Sig type - unknown(05)
+// Pub alg - ElGamal Encrypt-Only(pub 16)
+// Hash alg - unknown(hash 46)
+// Hashed Sub: unknown(sub 81, critical)(1988 bytes)
+const keySigV3Armor = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: SKS 1.0.10
+
+mI0CLnoYogAAAQQA1qwA2SuJwfQ5bCQ6u5t20ulnOtY0gykf7YjiK4LiVeRBwHjGq7v30tGV
+5Qti7qqRW4Ww7CDCJc4sZMFnystucR2vLkXaSoNWoFm4Fg47NiisDdhDezHwbVPW6OpCFNSi
+ZAamtj4QAUBu8j4LswafrJqZqR9336/V3g8Yil2l48kABRG0J0FybWluIE0uIFdhcmRhIDx3
+YXJkYUBuZXBoaWxpbS5ydWhyLmRlPoiVAgUQLok2xwXR6zmeWEiZAQE/DgP/WgxPQh40/Po4
+gSkWZCDAjNdph7zexvAb0CcUWahcwiBIgg3U5ErCx9I5CNVA9U+s8bNrDZwgSIeBzp3KhWUx
+524uhGgm6ZUTOAIKA6CbV6pfqoLpJnRYvXYQU5mIWsNa99wcu2qu18OeEDnztb7aLA6Ra9OF
+YFCbq4EjXRoOrYM=
+=LPjs
+-----END PGP PUBLIC KEY BLOCK-----`
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go
new file mode 100644
index 000000000..4b1105b6f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted.go
@@ -0,0 +1,155 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "io"
+ "strconv"
+
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/s2k"
+)
+
+// This is the largest session key that we'll support. Since no 512-bit cipher
+// has even been seriously used, this is comfortably large.
+const maxSessionKeySizeInBytes = 64
+
+// SymmetricKeyEncrypted represents a passphrase protected session key. See RFC
+// 4880, section 5.3.
+type SymmetricKeyEncrypted struct {
+ CipherFunc CipherFunction
+ s2k func(out, in []byte)
+ encryptedKey []byte
+}
+
+const symmetricKeyEncryptedVersion = 4
+
+func (ske *SymmetricKeyEncrypted) parse(r io.Reader) error {
+ // RFC 4880, section 5.3.
+ var buf [2]byte
+ if _, err := readFull(r, buf[:]); err != nil {
+ return err
+ }
+ if buf[0] != symmetricKeyEncryptedVersion {
+ return errors.UnsupportedError("SymmetricKeyEncrypted version")
+ }
+ ske.CipherFunc = CipherFunction(buf[1])
+
+ if ske.CipherFunc.KeySize() == 0 {
+ return errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(buf[1])))
+ }
+
+ var err error
+ ske.s2k, err = s2k.Parse(r)
+ if err != nil {
+ return err
+ }
+
+ encryptedKey := make([]byte, maxSessionKeySizeInBytes)
+ // The session key may follow. We just have to try and read to find
+ // out. If it exists then we limit it to maxSessionKeySizeInBytes.
+ n, err := readFull(r, encryptedKey)
+ if err != nil && err != io.ErrUnexpectedEOF {
+ return err
+ }
+
+ if n != 0 {
+ if n == maxSessionKeySizeInBytes {
+ return errors.UnsupportedError("oversized encrypted session key")
+ }
+ ske.encryptedKey = encryptedKey[:n]
+ }
+
+ return nil
+}
+
+// Decrypt attempts to decrypt an encrypted session key and returns the key and
+// the cipher to use when decrypting a subsequent Symmetrically Encrypted Data
+// packet.
+func (ske *SymmetricKeyEncrypted) Decrypt(passphrase []byte) ([]byte, CipherFunction, error) {
+ key := make([]byte, ske.CipherFunc.KeySize())
+ ske.s2k(key, passphrase)
+
+ if len(ske.encryptedKey) == 0 {
+ return key, ske.CipherFunc, nil
+ }
+
+ // the IV is all zeros
+ iv := make([]byte, ske.CipherFunc.blockSize())
+ c := cipher.NewCFBDecrypter(ske.CipherFunc.new(key), iv)
+ plaintextKey := make([]byte, len(ske.encryptedKey))
+ c.XORKeyStream(plaintextKey, ske.encryptedKey)
+ cipherFunc := CipherFunction(plaintextKey[0])
+ if cipherFunc.blockSize() == 0 {
+ return nil, ske.CipherFunc, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+ }
+ plaintextKey = plaintextKey[1:]
+ if l := len(plaintextKey); l == 0 || l%cipherFunc.blockSize() != 0 {
+ return nil, cipherFunc, errors.StructuralError("length of decrypted key not a multiple of block size")
+ }
+
+ return plaintextKey, cipherFunc, nil
+}
+
+// SerializeSymmetricKeyEncrypted serializes a symmetric key packet to w. The
+// packet contains a random session key, encrypted by a key derived from the
+// given passphrase. The session key is returned and must be passed to
+// SerializeSymmetricallyEncrypted.
+// If config is nil, sensible defaults will be used.
+func SerializeSymmetricKeyEncrypted(w io.Writer, passphrase []byte, config *Config) (key []byte, err error) {
+ cipherFunc := config.Cipher()
+ keySize := cipherFunc.KeySize()
+ if keySize == 0 {
+ return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(cipherFunc)))
+ }
+
+ s2kBuf := new(bytes.Buffer)
+ keyEncryptingKey := make([]byte, keySize)
+ // s2k.Serialize salts and stretches the passphrase, and writes the
+ // resulting key to keyEncryptingKey and the s2k descriptor to s2kBuf.
+ err = s2k.Serialize(s2kBuf, keyEncryptingKey, config.Random(), passphrase, &s2k.Config{Hash: config.Hash(), S2KCount: config.PasswordHashIterations()})
+ if err != nil {
+ return
+ }
+ s2kBytes := s2kBuf.Bytes()
+
+ packetLength := 2 /* header */ + len(s2kBytes) + 1 /* cipher type */ + keySize
+ err = serializeHeader(w, packetTypeSymmetricKeyEncrypted, packetLength)
+ if err != nil {
+ return
+ }
+
+ var buf [2]byte
+ buf[0] = symmetricKeyEncryptedVersion
+ buf[1] = byte(cipherFunc)
+ _, err = w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ _, err = w.Write(s2kBytes)
+ if err != nil {
+ return
+ }
+
+ sessionKey := make([]byte, keySize)
+ _, err = io.ReadFull(config.Random(), sessionKey)
+ if err != nil {
+ return
+ }
+ iv := make([]byte, cipherFunc.blockSize())
+ c := cipher.NewCFBEncrypter(cipherFunc.new(keyEncryptingKey), iv)
+ encryptedCipherAndKey := make([]byte, keySize+1)
+ c.XORKeyStream(encryptedCipherAndKey, buf[1:])
+ c.XORKeyStream(encryptedCipherAndKey[1:], sessionKey)
+ _, err = w.Write(encryptedCipherAndKey)
+ if err != nil {
+ return
+ }
+
+ key = sessionKey
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted_test.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted_test.go
new file mode 100644
index 000000000..19538df77
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/symmetric_key_encrypted_test.go
@@ -0,0 +1,103 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+func TestSymmetricKeyEncrypted(t *testing.T) {
+ buf := readerFromHex(symmetricallyEncryptedHex)
+ packet, err := Read(buf)
+ if err != nil {
+ t.Errorf("failed to read SymmetricKeyEncrypted: %s", err)
+ return
+ }
+ ske, ok := packet.(*SymmetricKeyEncrypted)
+ if !ok {
+ t.Error("didn't find SymmetricKeyEncrypted packet")
+ return
+ }
+ key, cipherFunc, err := ske.Decrypt([]byte("password"))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ packet, err = Read(buf)
+ if err != nil {
+ t.Errorf("failed to read SymmetricallyEncrypted: %s", err)
+ return
+ }
+ se, ok := packet.(*SymmetricallyEncrypted)
+ if !ok {
+ t.Error("didn't find SymmetricallyEncrypted packet")
+ return
+ }
+ r, err := se.Decrypt(cipherFunc, key)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ contents, err := ioutil.ReadAll(r)
+ if err != nil && err != io.EOF {
+ t.Error(err)
+ return
+ }
+
+ expectedContents, _ := hex.DecodeString(symmetricallyEncryptedContentsHex)
+ if !bytes.Equal(expectedContents, contents) {
+ t.Errorf("bad contents got:%x want:%x", contents, expectedContents)
+ }
+}
+
+const symmetricallyEncryptedHex = "8c0d04030302371a0b38d884f02060c91cf97c9973b8e58e028e9501708ccfe618fb92afef7fa2d80ddadd93cf"
+const symmetricallyEncryptedContentsHex = "cb1062004d14c4df636f6e74656e74732e0a"
+
+func TestSerializeSymmetricKeyEncrypted(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ passphrase := []byte("testing")
+ const cipherFunc = CipherAES128
+ config := &Config{
+ DefaultCipher: cipherFunc,
+ }
+
+ key, err := SerializeSymmetricKeyEncrypted(buf, passphrase, config)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ ske, ok := p.(*SymmetricKeyEncrypted)
+ if !ok {
+ t.Errorf("parsed a different packet type: %#v", p)
+ return
+ }
+
+ if ske.CipherFunc != config.DefaultCipher {
+ t.Errorf("SKE cipher function is %d (expected %d)", ske.CipherFunc, config.DefaultCipher)
+ }
+ parsedKey, parsedCipherFunc, err := ske.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("failed to decrypt reparsed SKE: %s", err)
+ return
+ }
+ if !bytes.Equal(key, parsedKey) {
+ t.Errorf("keys don't match after Decrypt: %x (original) vs %x (parsed)", key, parsedKey)
+ }
+ if parsedCipherFunc != cipherFunc {
+ t.Errorf("cipher function doesn't match after Decrypt: %d (original) vs %d (parsed)", cipherFunc, parsedCipherFunc)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
new file mode 100644
index 000000000..6126030eb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
@@ -0,0 +1,290 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "crypto/cipher"
+ "crypto/sha1"
+ "crypto/subtle"
+ "golang.org/x/crypto/openpgp/errors"
+ "hash"
+ "io"
+ "strconv"
+)
+
+// SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
+// encrypted contents will consist of more OpenPGP packets. See RFC 4880,
+// sections 5.7 and 5.13.
+type SymmetricallyEncrypted struct {
+ MDC bool // true iff this is a type 18 packet and thus has an embedded MAC.
+ contents io.Reader
+ prefix []byte
+}
+
+const symmetricallyEncryptedVersion = 1
+
+func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
+ if se.MDC {
+ // See RFC 4880, section 5.13.
+ var buf [1]byte
+ _, err := readFull(r, buf[:])
+ if err != nil {
+ return err
+ }
+ if buf[0] != symmetricallyEncryptedVersion {
+ return errors.UnsupportedError("unknown SymmetricallyEncrypted version")
+ }
+ }
+ se.contents = r
+ return nil
+}
+
+// Decrypt returns a ReadCloser, from which the decrypted contents of the
+// packet can be read. An incorrect key can, with high probability, be detected
+// immediately and this will result in a KeyIncorrect error being returned.
+func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
+ keySize := c.KeySize()
+ if keySize == 0 {
+ return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
+ }
+ if len(key) != keySize {
+ return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
+ }
+
+ if se.prefix == nil {
+ se.prefix = make([]byte, c.blockSize()+2)
+ _, err := readFull(se.contents, se.prefix)
+ if err != nil {
+ return nil, err
+ }
+ } else if len(se.prefix) != c.blockSize()+2 {
+ return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
+ }
+
+ ocfbResync := OCFBResync
+ if se.MDC {
+ // MDC packets use a different form of OCFB mode.
+ ocfbResync = OCFBNoResync
+ }
+
+ s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
+ if s == nil {
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ plaintext := cipher.StreamReader{S: s, R: se.contents}
+
+ if se.MDC {
+ // MDC packets have an embedded hash that we need to check.
+ h := sha1.New()
+ h.Write(se.prefix)
+ return &seMDCReader{in: plaintext, h: h}, nil
+ }
+
+ // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
+ return seReader{plaintext}, nil
+}
+
+// seReader wraps an io.Reader with a no-op Close method.
+type seReader struct {
+ in io.Reader
+}
+
+func (ser seReader) Read(buf []byte) (int, error) {
+ return ser.in.Read(buf)
+}
+
+func (ser seReader) Close() error {
+ return nil
+}
+
+const mdcTrailerSize = 1 /* tag byte */ + 1 /* length byte */ + sha1.Size
+
+// An seMDCReader wraps an io.Reader, maintains a running hash and keeps hold
+// of the most recent 22 bytes (mdcTrailerSize). Upon EOF, those bytes form an
+// MDC packet containing a hash of the previous contents which is checked
+// against the running hash. See RFC 4880, section 5.13.
+type seMDCReader struct {
+ in io.Reader
+ h hash.Hash
+ trailer [mdcTrailerSize]byte
+ scratch [mdcTrailerSize]byte
+ trailerUsed int
+ error bool
+ eof bool
+}
+
+func (ser *seMDCReader) Read(buf []byte) (n int, err error) {
+ if ser.error {
+ err = io.ErrUnexpectedEOF
+ return
+ }
+ if ser.eof {
+ err = io.EOF
+ return
+ }
+
+ // If we haven't yet filled the trailer buffer then we must do that
+ // first.
+ for ser.trailerUsed < mdcTrailerSize {
+ n, err = ser.in.Read(ser.trailer[ser.trailerUsed:])
+ ser.trailerUsed += n
+ if err == io.EOF {
+ if ser.trailerUsed != mdcTrailerSize {
+ n = 0
+ err = io.ErrUnexpectedEOF
+ ser.error = true
+ return
+ }
+ ser.eof = true
+ n = 0
+ return
+ }
+
+ if err != nil {
+ n = 0
+ return
+ }
+ }
+
+ // If it's a short read then we read into a temporary buffer and shift
+ // the data into the caller's buffer.
+ if len(buf) <= mdcTrailerSize {
+ n, err = readFull(ser.in, ser.scratch[:len(buf)])
+ copy(buf, ser.trailer[:n])
+ ser.h.Write(buf[:n])
+ copy(ser.trailer[:], ser.trailer[n:])
+ copy(ser.trailer[mdcTrailerSize-n:], ser.scratch[:])
+ if n < len(buf) {
+ ser.eof = true
+ err = io.EOF
+ }
+ return
+ }
+
+ n, err = ser.in.Read(buf[mdcTrailerSize:])
+ copy(buf, ser.trailer[:])
+ ser.h.Write(buf[:n])
+ copy(ser.trailer[:], buf[n:])
+
+ if err == io.EOF {
+ ser.eof = true
+ }
+ return
+}
+
+// This is a new-format packet tag byte for a type 19 (MDC) packet.
+const mdcPacketTagByte = byte(0x80) | 0x40 | 19
+
+func (ser *seMDCReader) Close() error {
+ if ser.error {
+ return errors.SignatureError("error during reading")
+ }
+
+ for !ser.eof {
+ // We haven't seen EOF so we need to read to the end
+ var buf [1024]byte
+ _, err := ser.Read(buf[:])
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return errors.SignatureError("error during reading")
+ }
+ }
+
+ if ser.trailer[0] != mdcPacketTagByte || ser.trailer[1] != sha1.Size {
+ return errors.SignatureError("MDC packet not found")
+ }
+ ser.h.Write(ser.trailer[:2])
+
+ final := ser.h.Sum(nil)
+ if subtle.ConstantTimeCompare(final, ser.trailer[2:]) != 1 {
+ return errors.SignatureError("hash mismatch")
+ }
+ return nil
+}
+
+// An seMDCWriter writes through to an io.WriteCloser while maintains a running
+// hash of the data written. On close, it emits an MDC packet containing the
+// running hash.
+type seMDCWriter struct {
+ w io.WriteCloser
+ h hash.Hash
+}
+
+func (w *seMDCWriter) Write(buf []byte) (n int, err error) {
+ w.h.Write(buf)
+ return w.w.Write(buf)
+}
+
+func (w *seMDCWriter) Close() (err error) {
+ var buf [mdcTrailerSize]byte
+
+ buf[0] = mdcPacketTagByte
+ buf[1] = sha1.Size
+ w.h.Write(buf[:2])
+ digest := w.h.Sum(nil)
+ copy(buf[2:], digest)
+
+ _, err = w.w.Write(buf[:])
+ if err != nil {
+ return
+ }
+ return w.w.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() error {
+ return nil
+}
+
+// SerializeSymmetricallyEncrypted serializes a symmetrically encrypted packet
+// to w and returns a WriteCloser to which the to-be-encrypted packets can be
+// written.
+// If config is nil, sensible defaults will be used.
+func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) {
+ if c.KeySize() != len(key) {
+ return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
+ }
+ writeCloser := noOpCloser{w}
+ ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
+ if err != nil {
+ return
+ }
+
+ _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
+ if err != nil {
+ return
+ }
+
+ block := c.new(key)
+ blockSize := block.BlockSize()
+ iv := make([]byte, blockSize)
+ _, err = config.Random().Read(iv)
+ if err != nil {
+ return
+ }
+ s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
+ _, err = ciphertext.Write(prefix)
+ if err != nil {
+ return
+ }
+ plaintext := cipher.StreamWriter{S: s, W: ciphertext}
+
+ h := sha1.New()
+ h.Write(iv)
+ h.Write(iv[blockSize-2:])
+ contents = &seMDCWriter{w: plaintext, h: h}
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted_test.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted_test.go
new file mode 100644
index 000000000..c5c00f7b9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted_test.go
@@ -0,0 +1,123 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "encoding/hex"
+ "golang.org/x/crypto/openpgp/errors"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+// TestReader wraps a []byte and returns reads of a specific length.
+type testReader struct {
+ data []byte
+ stride int
+}
+
+func (t *testReader) Read(buf []byte) (n int, err error) {
+ n = t.stride
+ if n > len(t.data) {
+ n = len(t.data)
+ }
+ if n > len(buf) {
+ n = len(buf)
+ }
+ copy(buf, t.data)
+ t.data = t.data[n:]
+ if len(t.data) == 0 {
+ err = io.EOF
+ }
+ return
+}
+
+func testMDCReader(t *testing.T) {
+ mdcPlaintext, _ := hex.DecodeString(mdcPlaintextHex)
+
+ for stride := 1; stride < len(mdcPlaintext)/2; stride++ {
+ r := &testReader{data: mdcPlaintext, stride: stride}
+ mdcReader := &seMDCReader{in: r, h: sha1.New()}
+ body, err := ioutil.ReadAll(mdcReader)
+ if err != nil {
+ t.Errorf("stride: %d, error: %s", stride, err)
+ continue
+ }
+ if !bytes.Equal(body, mdcPlaintext[:len(mdcPlaintext)-22]) {
+ t.Errorf("stride: %d: bad contents %x", stride, body)
+ continue
+ }
+
+ err = mdcReader.Close()
+ if err != nil {
+ t.Errorf("stride: %d, error on Close: %s", stride, err)
+ }
+ }
+
+ mdcPlaintext[15] ^= 80
+
+ r := &testReader{data: mdcPlaintext, stride: 2}
+ mdcReader := &seMDCReader{in: r, h: sha1.New()}
+ _, err := ioutil.ReadAll(mdcReader)
+ if err != nil {
+ t.Errorf("corruption test, error: %s", err)
+ return
+ }
+ err = mdcReader.Close()
+ if err == nil {
+ t.Error("corruption: no error")
+ } else if _, ok := err.(*errors.SignatureError); !ok {
+ t.Errorf("corruption: expected SignatureError, got: %s", err)
+ }
+}
+
+const mdcPlaintextHex = "a302789c3b2d93c4e0eb9aba22283539b3203335af44a134afb800c849cb4c4de10200aff40b45d31432c80cb384299a0655966d6939dfdeed1dddf980"
+
+func TestSerialize(t *testing.T) {
+ buf := bytes.NewBuffer(nil)
+ c := CipherAES128
+ key := make([]byte, c.KeySize())
+
+ w, err := SerializeSymmetricallyEncrypted(buf, c, key, nil)
+ if err != nil {
+ t.Errorf("error from SerializeSymmetricallyEncrypted: %s", err)
+ return
+ }
+
+ contents := []byte("hello world\n")
+
+ w.Write(contents)
+ w.Close()
+
+ p, err := Read(buf)
+ if err != nil {
+ t.Errorf("error from Read: %s", err)
+ return
+ }
+
+ se, ok := p.(*SymmetricallyEncrypted)
+ if !ok {
+ t.Errorf("didn't read a *SymmetricallyEncrypted")
+ return
+ }
+
+ r, err := se.Decrypt(c, key)
+ if err != nil {
+ t.Errorf("error from Decrypt: %s", err)
+ return
+ }
+
+ contentsCopy := bytes.NewBuffer(nil)
+ _, err = io.Copy(contentsCopy, r)
+ if err != nil {
+ t.Errorf("error from io.Copy: %s", err)
+ return
+ }
+ if !bytes.Equal(contentsCopy.Bytes(), contents) {
+ t.Errorf("contents not equal got: %x want: %x", contentsCopy.Bytes(), contents)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go
new file mode 100644
index 000000000..96a2b382a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/userattribute.go
@@ -0,0 +1,91 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "image"
+ "image/jpeg"
+ "io"
+ "io/ioutil"
+)
+
+const UserAttrImageSubpacket = 1
+
+// UserAttribute is capable of storing other types of data about a user
+// beyond name, email and a text comment. In practice, user attributes are typically used
+// to store a signed thumbnail photo JPEG image of the user.
+// See RFC 4880, section 5.12.
+type UserAttribute struct {
+ Contents []*OpaqueSubpacket
+}
+
+// NewUserAttributePhoto creates a user attribute packet
+// containing the given images.
+func NewUserAttributePhoto(photos ...image.Image) (uat *UserAttribute, err error) {
+ uat = new(UserAttribute)
+ for _, photo := range photos {
+ var buf bytes.Buffer
+ // RFC 4880, Section 5.12.1.
+ data := []byte{
+ 0x10, 0x00, // Little-endian image header length (16 bytes)
+ 0x01, // Image header version 1
+ 0x01, // JPEG
+ 0, 0, 0, 0, // 12 reserved octets, must be all zero.
+ 0, 0, 0, 0,
+ 0, 0, 0, 0}
+ if _, err = buf.Write(data); err != nil {
+ return
+ }
+ if err = jpeg.Encode(&buf, photo, nil); err != nil {
+ return
+ }
+ uat.Contents = append(uat.Contents, &OpaqueSubpacket{
+ SubType: UserAttrImageSubpacket,
+ Contents: buf.Bytes()})
+ }
+ return
+}
+
+// NewUserAttribute creates a new user attribute packet containing the given subpackets.
+func NewUserAttribute(contents ...*OpaqueSubpacket) *UserAttribute {
+ return &UserAttribute{Contents: contents}
+}
+
+func (uat *UserAttribute) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.13
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ return
+ }
+ uat.Contents, err = OpaqueSubpackets(b)
+ return
+}
+
+// Serialize marshals the user attribute to w in the form of an OpenPGP packet, including
+// header.
+func (uat *UserAttribute) Serialize(w io.Writer) (err error) {
+ var buf bytes.Buffer
+ for _, sp := range uat.Contents {
+ sp.Serialize(&buf)
+ }
+ if err = serializeHeader(w, packetTypeUserAttribute, buf.Len()); err != nil {
+ return err
+ }
+ _, err = w.Write(buf.Bytes())
+ return
+}
+
+// ImageData returns zero or more byte slices, each containing
+// JPEG File Interchange Format (JFIF), for each photo in the
+// the user attribute packet.
+func (uat *UserAttribute) ImageData() (imageData [][]byte) {
+ for _, sp := range uat.Contents {
+ if sp.SubType == UserAttrImageSubpacket && len(sp.Contents) > 16 {
+ imageData = append(imageData, sp.Contents[16:])
+ }
+ }
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userattribute_test.go b/vendor/golang.org/x/crypto/openpgp/packet/userattribute_test.go
new file mode 100644
index 000000000..13ca5143c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/userattribute_test.go
@@ -0,0 +1,109 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "bytes"
+ "encoding/base64"
+ "image/color"
+ "image/jpeg"
+ "testing"
+)
+
+func TestParseUserAttribute(t *testing.T) {
+ r := base64.NewDecoder(base64.StdEncoding, bytes.NewBufferString(userAttributePacket))
+ for i := 0; i < 2; i++ {
+ p, err := Read(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+ uat := p.(*UserAttribute)
+ imgs := uat.ImageData()
+ if len(imgs) != 1 {
+ t.Errorf("Unexpected number of images in user attribute packet: %d", len(imgs))
+ }
+ if len(imgs[0]) != 3395 {
+ t.Errorf("Unexpected JPEG image size: %d", len(imgs[0]))
+ }
+ img, err := jpeg.Decode(bytes.NewBuffer(imgs[0]))
+ if err != nil {
+ t.Errorf("Error decoding JPEG image: %v", err)
+ }
+ // A pixel in my right eye.
+ pixel := color.NRGBAModel.Convert(img.At(56, 36))
+ ref := color.NRGBA{R: 157, G: 128, B: 124, A: 255}
+ if pixel != ref {
+ t.Errorf("Unexpected pixel color: %v", pixel)
+ }
+ w := bytes.NewBuffer(nil)
+ err = uat.Serialize(w)
+ if err != nil {
+ t.Errorf("Error writing user attribute: %v", err)
+ }
+ r = bytes.NewBuffer(w.Bytes())
+ }
+}
+
+const userAttributePacket = `
+0cyWzJQBEAABAQAAAAAAAAAAAAAAAP/Y/+AAEEpGSUYAAQIAAAEAAQAA/9sAQwAFAwQEBAMFBAQE
+BQUFBgcMCAcHBwcPCgsJDBEPEhIRDxEQExYcFxMUGhUQERghGBocHR8fHxMXIiQiHiQcHh8e/9sA
+QwEFBQUHBgcOCAgOHhQRFB4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e
+Hh4eHh4eHh4e/8AAEQgAZABkAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYH
+CAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHw
+JDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6
+g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk
+5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIB
+AgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEX
+GBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT
+lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX2
+9/j5+v/aAAwDAQACEQMRAD8A5uGP06VehQ4pIox04q5EnHSvAep+hIIl4zVuMHGPWmRrUWtalaaN
+pU2oXsgSGJSxPr6ClvoitErs0Itqjc7BQOpPAFYmrfEnwjojtHNqaXEynBjtx5hH4jj9a8B8d+Od
+W8UXZjWR4LJT+7t0Jwfc+prnIdO1CWZEW2mZ3HyDactXXDB3V5s8evm1namj6r0H4weCLtxG+ova
+ueP30RA/MV6not1bX0Ed1ZzxzwyDKvGwZSPqK+Ff+ES8R8t/ZV2oHUmM10Hgbxp4m8BatEfNnWBH
+/eWshOxx9Kmpg4te49RUM1kn+8Wh9zQ4P1FaMC7l465rjPh14y0fxnoseoaXOpfaPOgJ+eI98j09
+67W19M15bi4uzPSqTU480WXkjZkAyAR61DPE6OCSOalWRRgZxjvTb598sfU4FBwx5uY4T4feIm8P
+TeJbAgc65NIM+8cX+FFeLfF3Vr3SfiNrMFrMypJMJcDPUqP8KK+kpVFyLU+ar037SXqX4hxVpMY7
+1UhPpVlT2rybKx9smWYz3NeH/EDVLzxt40j8O6bITaQybPlbKkjq39K9O8fasdH8IahfKxWQRFIy
+Ou9uB/OuE/Z/0y3j1d9TuyoZCMs5xjuea1pLli5nn46q240l13PcfhN8EvDNtpcEl/CklyVBLuMk
+mvU/Dfwo0BL/AO13FjEDD/qyV7Vn+CvGPg8zRpJrVm8ikLtEg6+1ew2dxZ3EQaJgysuQPasH7eXW
+1zzsbVhT92kk/PsYieEND+zlPs6c/wCyAPyryH4wfCPRtW0u6j+xRLOxLxSoADkDpXY+MPjJ4c0S
+9k082d3O8ZKkxw5XI96ytK+IGk+IpFjRpod+Qq3C7QT6A1E6NenaXbqRg6rlLlqS0fRnxjpd1r/w
+w8afa7GWRPKbZLGeBKmeVNfZngLxNaeKfDdprVjxHcLlkJ5Vh1H5185/tDad9h8XOsqAw3Cb0cjq
+CfX61P8AsveKf7L8T3fhe5nxa3g324YniQdh9R/KuivTdSmp9TXB1/Z1nRlsfU249QBx1pWfcwI7
+Cq6u2Ovamb9rYz16V5x7Psz5q/aJhZfibcupIElvE3H+7j+lFbXx9szP45jlUfeso8/99OKK9elL
+3EeNVopzZVharCtxVRGGMk02S5JyFOB69zWTieypnL/GksfB+0cr9oQt69awPhPpD69Y3Ky3DWth
+CWluGU4LAdq3vibGs/g68BJygVxjrwRW5+ztoRv/AAs8EeCZnO/J/hzz/Kumi4wp3kePjlOdZKPY
+ml8Mvo6WM9ppi7J0EkQYMzkb1X0wW+bJHGACa+ivg14huZPCkjXUO6SImIYOQAP6UQ2sGneHmiWF
+CYoSAAuM8etXfhBpMr+EZ3SSNRcMx6ZxWdes6ytBGSwkMNFuo7pnP614Ut9Zn1C4uLySKcwObGFA
+Qnm4+XcR71h+CfDHiKCQWuv2YWFtw+bBZQD8rcE8n2Ney+GbGGQSM6I7xvtI681rXdp8hKRRp6t3
+FYPE1VDlsY1nQjWdl+J8w/tOeDZZ/AMd/EGefTHyxxyYjwfyODXg3waRh8UtEcFh+8Jb8FNfZPxh
+Ak8J6nbPIsiyW7LnseK+Ofh99ptPHFnf2lu0y2twGcKuSEPB/Q1WHk50miq1o14TXU+xop+On61H
+NMC6Nis1LgsAcUTSt1APFcXJZn0EqmhyvxA037friTYziBV6f7Tf40Vr3k4aXLx5OMZIzRXZB2ik
+efJXbPHJJcnaD9aN2R1qoGO8/WkuLlIV+YjdjpXSonQ5lTxfiTwzqCnkeQxx9BWx+zPrQsrBFYja
+zEfrXL6lfie3khcjY6lSPUGud+G3iA6FrY0uQ/KJsA9gCa0jSvFpnBi6tpKSPu++nsIfDFxeXciR
+qIicscY4rxTwB8RUkn1axsPEf2LTYx85kTGzqCUP8VcJ47+JOs+I0Hhq1njjt/ufIeSvq1VtE+Gs
+eoaUbSHUrkHdu3WtuX5Ix81XRh7OL5jirVpV5Whdn0F8C/iX4auVn0i612T7bASoe8wjTAd89K9g
+vtSt5NMa4t5lkRhgOh3Dn6V8aaz8KZrIR3OlQ6r56LySmSxxz06Vo/CHx34h0rxBP4XvJ5AjK2RP
+nEbAEj6ZxjPrWM6fMmoswqJxqJ1VZnqHxn1NLPwveqWHmNC2BnnNcD8DfDkGi+CH1m+ijN1qMzNA
+4GSIiAMf+hVxPxU8Tapc3c0F9MGCn5GU5BX0Pau3+HmrT3XgXSIJCBHDGdgAx1NYSpezha52Yauq
+1dya2Wh2onAIwTj1p0lxxWWLkhRyCKWa5O3ORXOos9KVQluZm83j0oqi84JyWH50Vdmc7ep43d3I
+t1Z2Iz2FYdxeSTsxyRnvTdVuDNcNluM9KrKcg817NOnZGNbEXdkNckjrXGeIIprPxFFdRHAlIwem
+COtdmxrG8Q2cd/ZNExw45RvQ1bVjim+dWNzw7eaTD4mN3dndCQCo6hmI5zXpj/Ea/wBHjkh0kwRW
+xXEfl4yTxXzXZalJDL9nuWKMmRnHcV2Hh3WreCyYXW2SWQhd5P3F6n+lS43d2cTm6d7Ox9EWPxH1
+ODQxPqWpCaSU/ukUc4z3/WvKW8UhviAdaMewYZG98gj9c1ymoa8LyWOJHwkTDaVPb0qpr+q2m6Nb
+cfvNo349az9mou9iZVXNWbub3jm98/Vza2ReV7lsJg/e3dsV654UR9N0K0sZP9ZDGFbHr3rzL4P+
+H7rXfEEWr3I3W1qf3IYdW9fwqDxf4k8UeH/G95p08kscHmk25dPlZT0we9YTj7SXKjpw1aNG8mj3
+FLv5ccU959ycnmvKPDnxB82YQarGsZPAlTp+IrvIr1ZIgySKwIyCOhFYTpyg9T0qWIhVV4svzPvf
+IdhgY4orPachj81FRdmtzxqdiZmJ9aQEgdqZcPtmbJ71DJcAZ5r20kkeXJtsfPIQDwPzrG1a+S3i
+LyHAHvmp7y7HOD1rlNdm+1T7Acovf3o+J2RMpezjzMvrob67pX9o2ShZlYgg/wAWKxZLLWLZ/Ke3
+mVh14yK9M+BMC3dre2ko3LHKCB7EV7EngeGQJdQ7HyBkMKS0djgq1W3c+XtK03U522RwzsTwNiEk
+ntXoHgf4calql9El/G8UZbLfLyfr7V9FeGvh+s+0Lbxxcglu2K1NW1nwN4Gk/wBLuI57tV5jjwzE
+/QVNS+0dWYRqNvXRFv4eeCodKsY1ggVIY1G3K4z714h+1Jqul3GpwaXYeXJLbzgyyrg4b+6D+HNb
+vjz436zq9m+naHF/ZdkeGfOZXH17V4Vqt2b29K+ZuOc5bnce5zWdPBShL2lTfojSeJhy+zp/NjVz
+1Bwa6DSfFGq6fbJFDKrov8DjPFcu97ZxsUe4jVhwVJ5Bpp1mwQiLewJPXacVq6fNpYyjOUXdHoKf
+EG8VQHsInbuVcgflRXnt5fIs2FYHgcgUVi8LG+xusdW/mN7U2KgEVkTzPt60UVfQ9eHxGHrV1MGi
+iD4V25x1qvdgLAMd6KK0pbHm4x++dp8FtUubLxJ5EIjMc+A4Za+qfD8pe1JZVOBmiinW3RyRPMfi
+R8QPE638+k2l6LK0Hylbddhb6nOa80mlkcmWR2kcnlnOSaKK7qCXKcNdu5narcSrAoBxvODWJIga
+VckjDdqKKwq/EaQ0gUdbjQ6mr7QGBUcd6tPBC6gtGpOOuKKKie5qn7qIpEXd0HSiiimSf//Z`
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userid.go b/vendor/golang.org/x/crypto/openpgp/packet/userid.go
new file mode 100644
index 000000000..d6bea7d4a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/userid.go
@@ -0,0 +1,160 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "io"
+ "io/ioutil"
+ "strings"
+)
+
+// UserId contains text that is intended to represent the name and email
+// address of the key holder. See RFC 4880, section 5.11. By convention, this
+// takes the form "Full Name (Comment) <email@example.com>"
+type UserId struct {
+ Id string // By convention, this takes the form "Full Name (Comment) <email@example.com>" which is split out in the fields below.
+
+ Name, Comment, Email string
+}
+
+func hasInvalidCharacters(s string) bool {
+ for _, c := range s {
+ switch c {
+ case '(', ')', '<', '>', 0:
+ return true
+ }
+ }
+ return false
+}
+
+// NewUserId returns a UserId or nil if any of the arguments contain invalid
+// characters. The invalid characters are '\x00', '(', ')', '<' and '>'
+func NewUserId(name, comment, email string) *UserId {
+ // RFC 4880 doesn't deal with the structure of userid strings; the
+ // name, comment and email form is just a convention. However, there's
+ // no convention about escaping the metacharacters and GPG just refuses
+ // to create user ids where, say, the name contains a '('. We mirror
+ // this behaviour.
+
+ if hasInvalidCharacters(name) || hasInvalidCharacters(comment) || hasInvalidCharacters(email) {
+ return nil
+ }
+
+ uid := new(UserId)
+ uid.Name, uid.Comment, uid.Email = name, comment, email
+ uid.Id = name
+ if len(comment) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "("
+ uid.Id += comment
+ uid.Id += ")"
+ }
+ if len(email) > 0 {
+ if len(uid.Id) > 0 {
+ uid.Id += " "
+ }
+ uid.Id += "<"
+ uid.Id += email
+ uid.Id += ">"
+ }
+ return uid
+}
+
+func (uid *UserId) parse(r io.Reader) (err error) {
+ // RFC 4880, section 5.11
+ b, err := ioutil.ReadAll(r)
+ if err != nil {
+ return
+ }
+ uid.Id = string(b)
+ uid.Name, uid.Comment, uid.Email = parseUserId(uid.Id)
+ return
+}
+
+// Serialize marshals uid to w in the form of an OpenPGP packet, including
+// header.
+func (uid *UserId) Serialize(w io.Writer) error {
+ err := serializeHeader(w, packetTypeUserId, len(uid.Id))
+ if err != nil {
+ return err
+ }
+ _, err = w.Write([]byte(uid.Id))
+ return err
+}
+
+// parseUserId extracts the name, comment and email from a user id string that
+// is formatted as "Full Name (Comment) <email@example.com>".
+func parseUserId(id string) (name, comment, email string) {
+ var n, c, e struct {
+ start, end int
+ }
+ var state int
+
+ for offset, rune := range id {
+ switch state {
+ case 0:
+ // Entering name
+ n.start = offset
+ state = 1
+ fallthrough
+ case 1:
+ // In name
+ if rune == '(' {
+ state = 2
+ n.end = offset
+ } else if rune == '<' {
+ state = 5
+ n.end = offset
+ }
+ case 2:
+ // Entering comment
+ c.start = offset
+ state = 3
+ fallthrough
+ case 3:
+ // In comment
+ if rune == ')' {
+ state = 4
+ c.end = offset
+ }
+ case 4:
+ // Between comment and email
+ if rune == '<' {
+ state = 5
+ }
+ case 5:
+ // Entering email
+ e.start = offset
+ state = 6
+ fallthrough
+ case 6:
+ // In email
+ if rune == '>' {
+ state = 7
+ e.end = offset
+ }
+ default:
+ // After email
+ }
+ }
+ switch state {
+ case 1:
+ // ended in the name
+ n.end = len(id)
+ case 3:
+ // ended in comment
+ c.end = len(id)
+ case 6:
+ // ended in email
+ e.end = len(id)
+ }
+
+ name = strings.TrimSpace(id[n.start:n.end])
+ comment = strings.TrimSpace(id[c.start:c.end])
+ email = strings.TrimSpace(id[e.start:e.end])
+ return
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/packet/userid_test.go b/vendor/golang.org/x/crypto/openpgp/packet/userid_test.go
new file mode 100644
index 000000000..296819389
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/packet/userid_test.go
@@ -0,0 +1,87 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package packet
+
+import (
+ "testing"
+)
+
+var userIdTests = []struct {
+ id string
+ name, comment, email string
+}{
+ {"", "", "", ""},
+ {"John Smith", "John Smith", "", ""},
+ {"John Smith ()", "John Smith", "", ""},
+ {"John Smith () <>", "John Smith", "", ""},
+ {"(comment", "", "comment", ""},
+ {"(comment)", "", "comment", ""},
+ {"<email", "", "", "email"},
+ {"<email> sdfk", "", "", "email"},
+ {" John Smith ( Comment ) asdkflj < email > lksdfj", "John Smith", "Comment", "email"},
+ {" John Smith < email > lksdfj", "John Smith", "", "email"},
+ {"(<foo", "", "<foo", ""},
+ {"René Descartes (العربي)", "René Descartes", "العربي", ""},
+}
+
+func TestParseUserId(t *testing.T) {
+ for i, test := range userIdTests {
+ name, comment, email := parseUserId(test.id)
+ if name != test.name {
+ t.Errorf("%d: name mismatch got:%s want:%s", i, name, test.name)
+ }
+ if comment != test.comment {
+ t.Errorf("%d: comment mismatch got:%s want:%s", i, comment, test.comment)
+ }
+ if email != test.email {
+ t.Errorf("%d: email mismatch got:%s want:%s", i, email, test.email)
+ }
+ }
+}
+
+var newUserIdTests = []struct {
+ name, comment, email, id string
+}{
+ {"foo", "", "", "foo"},
+ {"", "bar", "", "(bar)"},
+ {"", "", "baz", "<baz>"},
+ {"foo", "bar", "", "foo (bar)"},
+ {"foo", "", "baz", "foo <baz>"},
+ {"", "bar", "baz", "(bar) <baz>"},
+ {"foo", "bar", "baz", "foo (bar) <baz>"},
+}
+
+func TestNewUserId(t *testing.T) {
+ for i, test := range newUserIdTests {
+ uid := NewUserId(test.name, test.comment, test.email)
+ if uid == nil {
+ t.Errorf("#%d: returned nil", i)
+ continue
+ }
+ if uid.Id != test.id {
+ t.Errorf("#%d: got '%s', want '%s'", i, uid.Id, test.id)
+ }
+ }
+}
+
+var invalidNewUserIdTests = []struct {
+ name, comment, email string
+}{
+ {"foo(", "", ""},
+ {"foo<", "", ""},
+ {"", "bar)", ""},
+ {"", "bar<", ""},
+ {"", "", "baz>"},
+ {"", "", "baz)"},
+ {"", "", "baz\x00"},
+}
+
+func TestNewUserIdWithInvalidInput(t *testing.T) {
+ for i, test := range invalidNewUserIdTests {
+ if uid := NewUserId(test.name, test.comment, test.email); uid != nil {
+ t.Errorf("#%d: returned non-nil value: %#v", i, uid)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/read.go b/vendor/golang.org/x/crypto/openpgp/read.go
new file mode 100644
index 000000000..a8bb3de95
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/read.go
@@ -0,0 +1,442 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package openpgp implements high level operations on OpenPGP messages.
+package openpgp // import "golang.org/x/crypto/openpgp"
+
+import (
+ "crypto"
+ _ "crypto/sha256"
+ "hash"
+ "io"
+ "strconv"
+
+ "golang.org/x/crypto/openpgp/armor"
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/packet"
+)
+
+// SignatureType is the armor type for a PGP signature.
+var SignatureType = "PGP SIGNATURE"
+
+// readArmored reads an armored block with the given type.
+func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) {
+ block, err := armor.Decode(r)
+ if err != nil {
+ return
+ }
+
+ if block.Type != expectedType {
+ return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
+ }
+
+ return block.Body, nil
+}
+
+// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
+// signed message.
+type MessageDetails struct {
+ IsEncrypted bool // true if the message was encrypted.
+ EncryptedToKeyIds []uint64 // the list of recipient key ids.
+ IsSymmetricallyEncrypted bool // true if a passphrase could have decrypted the message.
+ DecryptedWith Key // the private key used to decrypt the message, if any.
+ IsSigned bool // true if the message is signed.
+ SignedByKeyId uint64 // the key id of the signer, if any.
+ SignedBy *Key // the key of the signer, if available.
+ LiteralData *packet.LiteralData // the metadata of the contents
+ UnverifiedBody io.Reader // the contents of the message.
+
+ // If IsSigned is true and SignedBy is non-zero then the signature will
+ // be verified as UnverifiedBody is read. The signature cannot be
+ // checked until the whole of UnverifiedBody is read so UnverifiedBody
+ // must be consumed until EOF before the data can trusted. Even if a
+ // message isn't signed (or the signer is unknown) the data may contain
+ // an authentication code that is only checked once UnverifiedBody has
+ // been consumed. Once EOF has been seen, the following fields are
+ // valid. (An authentication code failure is reported as a
+ // SignatureError error when reading from UnverifiedBody.)
+ SignatureError error // nil if the signature is good.
+ Signature *packet.Signature // the signature packet itself, if v4 (default)
+ SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature
+
+ decrypted io.ReadCloser
+}
+
+// A PromptFunction is used as a callback by functions that may need to decrypt
+// a private key, or prompt for a passphrase. It is called with a list of
+// acceptable, encrypted private keys and a boolean that indicates whether a
+// passphrase is usable. It should either decrypt a private key or return a
+// passphrase to try. If the decrypted private key or given passphrase isn't
+// correct, the function will be called again, forever. Any error returned will
+// be passed up.
+type PromptFunction func(keys []Key, symmetric bool) ([]byte, error)
+
+// A keyEnvelopePair is used to store a private key with the envelope that
+// contains a symmetric key, encrypted with that key.
+type keyEnvelopePair struct {
+ key Key
+ encryptedKey *packet.EncryptedKey
+}
+
+// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
+// The given KeyRing should contain both public keys (for signature
+// verification) and, possibly encrypted, private keys for decrypting.
+// If config is nil, sensible defaults will be used.
+func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) {
+ var p packet.Packet
+
+ var symKeys []*packet.SymmetricKeyEncrypted
+ var pubKeys []keyEnvelopePair
+ var se *packet.SymmetricallyEncrypted
+
+ packets := packet.NewReader(r)
+ md = new(MessageDetails)
+ md.IsEncrypted = true
+
+ // The message, if encrypted, starts with a number of packets
+ // containing an encrypted decryption key. The decryption key is either
+ // encrypted to a public key, or with a passphrase. This loop
+ // collects these packets.
+ParsePackets:
+ for {
+ p, err = packets.Next()
+ if err != nil {
+ return nil, err
+ }
+ switch p := p.(type) {
+ case *packet.SymmetricKeyEncrypted:
+ // This packet contains the decryption key encrypted with a passphrase.
+ md.IsSymmetricallyEncrypted = true
+ symKeys = append(symKeys, p)
+ case *packet.EncryptedKey:
+ // This packet contains the decryption key encrypted to a public key.
+ md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
+ switch p.Algo {
+ case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
+ break
+ default:
+ continue
+ }
+ var keys []Key
+ if p.KeyId == 0 {
+ keys = keyring.DecryptionKeys()
+ } else {
+ keys = keyring.KeysById(p.KeyId)
+ }
+ for _, k := range keys {
+ pubKeys = append(pubKeys, keyEnvelopePair{k, p})
+ }
+ case *packet.SymmetricallyEncrypted:
+ se = p
+ break ParsePackets
+ case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
+ // This message isn't encrypted.
+ if len(symKeys) != 0 || len(pubKeys) != 0 {
+ return nil, errors.StructuralError("key material not followed by encrypted message")
+ }
+ packets.Unread(p)
+ return readSignedMessage(packets, nil, keyring)
+ }
+ }
+
+ var candidates []Key
+ var decrypted io.ReadCloser
+
+ // Now that we have the list of encrypted keys we need to decrypt at
+ // least one of them or, if we cannot, we need to call the prompt
+ // function so that it can decrypt a key or give us a passphrase.
+FindKey:
+ for {
+ // See if any of the keys already have a private key available
+ candidates = candidates[:0]
+ candidateFingerprints := make(map[string]bool)
+
+ for _, pk := range pubKeys {
+ if pk.key.PrivateKey == nil {
+ continue
+ }
+ if !pk.key.PrivateKey.Encrypted {
+ if len(pk.encryptedKey.Key) == 0 {
+ pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
+ }
+ if len(pk.encryptedKey.Key) == 0 {
+ continue
+ }
+ decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
+ if err != nil && err != errors.ErrKeyIncorrect {
+ return nil, err
+ }
+ if decrypted != nil {
+ md.DecryptedWith = pk.key
+ break FindKey
+ }
+ } else {
+ fpr := string(pk.key.PublicKey.Fingerprint[:])
+ if v := candidateFingerprints[fpr]; v {
+ continue
+ }
+ candidates = append(candidates, pk.key)
+ candidateFingerprints[fpr] = true
+ }
+ }
+
+ if len(candidates) == 0 && len(symKeys) == 0 {
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ if prompt == nil {
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ passphrase, err := prompt(candidates, len(symKeys) != 0)
+ if err != nil {
+ return nil, err
+ }
+
+ // Try the symmetric passphrase first
+ if len(symKeys) != 0 && passphrase != nil {
+ for _, s := range symKeys {
+ key, cipherFunc, err := s.Decrypt(passphrase)
+ if err == nil {
+ decrypted, err = se.Decrypt(cipherFunc, key)
+ if err != nil && err != errors.ErrKeyIncorrect {
+ return nil, err
+ }
+ if decrypted != nil {
+ break FindKey
+ }
+ }
+
+ }
+ }
+ }
+
+ md.decrypted = decrypted
+ if err := packets.Push(decrypted); err != nil {
+ return nil, err
+ }
+ return readSignedMessage(packets, md, keyring)
+}
+
+// readSignedMessage reads a possibly signed message if mdin is non-zero then
+// that structure is updated and returned. Otherwise a fresh MessageDetails is
+// used.
+func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) {
+ if mdin == nil {
+ mdin = new(MessageDetails)
+ }
+ md = mdin
+
+ var p packet.Packet
+ var h hash.Hash
+ var wrappedHash hash.Hash
+FindLiteralData:
+ for {
+ p, err = packets.Next()
+ if err != nil {
+ return nil, err
+ }
+ switch p := p.(type) {
+ case *packet.Compressed:
+ if err := packets.Push(p.Body); err != nil {
+ return nil, err
+ }
+ case *packet.OnePassSignature:
+ if !p.IsLast {
+ return nil, errors.UnsupportedError("nested signatures")
+ }
+
+ h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
+ if err != nil {
+ md = nil
+ return
+ }
+
+ md.IsSigned = true
+ md.SignedByKeyId = p.KeyId
+ keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
+ if len(keys) > 0 {
+ md.SignedBy = &keys[0]
+ }
+ case *packet.LiteralData:
+ md.LiteralData = p
+ break FindLiteralData
+ }
+ }
+
+ if md.SignedBy != nil {
+ md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md}
+ } else if md.decrypted != nil {
+ md.UnverifiedBody = checkReader{md}
+ } else {
+ md.UnverifiedBody = md.LiteralData.Body
+ }
+
+ return md, nil
+}
+
+// hashForSignature returns a pair of hashes that can be used to verify a
+// signature. The signature may specify that the contents of the signed message
+// should be preprocessed (i.e. to normalize line endings). Thus this function
+// returns two hashes. The second should be used to hash the message itself and
+// performs any needed preprocessing.
+func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) {
+ if !hashId.Available() {
+ return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
+ }
+ h := hashId.New()
+
+ switch sigType {
+ case packet.SigTypeBinary:
+ return h, h, nil
+ case packet.SigTypeText:
+ return h, NewCanonicalTextHash(h), nil
+ }
+
+ return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
+}
+
+// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
+// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
+// MDC checks.
+type checkReader struct {
+ md *MessageDetails
+}
+
+func (cr checkReader) Read(buf []byte) (n int, err error) {
+ n, err = cr.md.LiteralData.Body.Read(buf)
+ if err == io.EOF {
+ mdcErr := cr.md.decrypted.Close()
+ if mdcErr != nil {
+ err = mdcErr
+ }
+ }
+ return
+}
+
+// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
+// the data as it is read. When it sees an EOF from the underlying io.Reader
+// it parses and checks a trailing Signature packet and triggers any MDC checks.
+type signatureCheckReader struct {
+ packets *packet.Reader
+ h, wrappedHash hash.Hash
+ md *MessageDetails
+}
+
+func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
+ n, err = scr.md.LiteralData.Body.Read(buf)
+ scr.wrappedHash.Write(buf[:n])
+ if err == io.EOF {
+ var p packet.Packet
+ p, scr.md.SignatureError = scr.packets.Next()
+ if scr.md.SignatureError != nil {
+ return
+ }
+
+ var ok bool
+ if scr.md.Signature, ok = p.(*packet.Signature); ok {
+ scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
+ } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok {
+ scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3)
+ } else {
+ scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
+ return
+ }
+
+ // The SymmetricallyEncrypted packet, if any, might have an
+ // unsigned hash of its own. In order to check this we need to
+ // close that Reader.
+ if scr.md.decrypted != nil {
+ mdcErr := scr.md.decrypted.Close()
+ if mdcErr != nil {
+ err = mdcErr
+ }
+ }
+ }
+ return
+}
+
+// CheckDetachedSignature takes a signed file and a detached signature and
+// returns the signer if the signature is valid. If the signer isn't known,
+// ErrUnknownIssuer is returned.
+func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
+ var issuerKeyId uint64
+ var hashFunc crypto.Hash
+ var sigType packet.SignatureType
+ var keys []Key
+ var p packet.Packet
+
+ packets := packet.NewReader(signature)
+ for {
+ p, err = packets.Next()
+ if err == io.EOF {
+ return nil, errors.ErrUnknownIssuer
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ switch sig := p.(type) {
+ case *packet.Signature:
+ if sig.IssuerKeyId == nil {
+ return nil, errors.StructuralError("signature doesn't have an issuer")
+ }
+ issuerKeyId = *sig.IssuerKeyId
+ hashFunc = sig.Hash
+ sigType = sig.SigType
+ case *packet.SignatureV3:
+ issuerKeyId = sig.IssuerKeyId
+ hashFunc = sig.Hash
+ sigType = sig.SigType
+ default:
+ return nil, errors.StructuralError("non signature packet found")
+ }
+
+ keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
+ if len(keys) > 0 {
+ break
+ }
+ }
+
+ if len(keys) == 0 {
+ panic("unreachable")
+ }
+
+ h, wrappedHash, err := hashForSignature(hashFunc, sigType)
+ if err != nil {
+ return nil, err
+ }
+
+ if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF {
+ return nil, err
+ }
+
+ for _, key := range keys {
+ switch sig := p.(type) {
+ case *packet.Signature:
+ err = key.PublicKey.VerifySignature(h, sig)
+ case *packet.SignatureV3:
+ err = key.PublicKey.VerifySignatureV3(h, sig)
+ default:
+ panic("unreachable")
+ }
+
+ if err == nil {
+ return key.Entity, nil
+ }
+ }
+
+ return nil, err
+}
+
+// CheckArmoredDetachedSignature performs the same actions as
+// CheckDetachedSignature but expects the signature to be armored.
+func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
+ body, err := readArmored(signature, SignatureType)
+ if err != nil {
+ return
+ }
+
+ return CheckDetachedSignature(keyring, signed, body)
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/read_test.go b/vendor/golang.org/x/crypto/openpgp/read_test.go
new file mode 100644
index 000000000..1fbfbac4c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/read_test.go
@@ -0,0 +1,613 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "bytes"
+ _ "crypto/sha512"
+ "encoding/hex"
+ "io"
+ "io/ioutil"
+ "strings"
+ "testing"
+
+ "golang.org/x/crypto/openpgp/armor"
+ "golang.org/x/crypto/openpgp/errors"
+)
+
+func readerFromHex(s string) io.Reader {
+ data, err := hex.DecodeString(s)
+ if err != nil {
+ panic("readerFromHex: bad input")
+ }
+ return bytes.NewBuffer(data)
+}
+
+func TestReadKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
+func TestRereadKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ if err != nil {
+ t.Errorf("error in initial parse: %s", err)
+ return
+ }
+ out := new(bytes.Buffer)
+ err = kring[0].Serialize(out)
+ if err != nil {
+ t.Errorf("error in serialization: %s", err)
+ return
+ }
+ kring, err = ReadKeyRing(out)
+ if err != nil {
+ t.Errorf("error in second parse: %s", err)
+ return
+ }
+
+ if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
+func TestReadPrivateKeyRing(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(kring) != 2 || uint32(kring[0].PrimaryKey.KeyId) != 0xC20C31BB || uint32(kring[1].PrimaryKey.KeyId) != 0x1E35246B || kring[0].PrimaryKey == nil {
+ t.Errorf("bad keyring: %#v", kring)
+ }
+}
+
+func TestReadDSAKey(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0x0CCC0360 {
+ t.Errorf("bad parse: %#v", kring)
+ }
+}
+
+func TestReadP256Key(t *testing.T) {
+ kring, err := ReadKeyRing(readerFromHex(p256TestKeyHex))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(kring) != 1 || uint32(kring[0].PrimaryKey.KeyId) != 0x5918513E {
+ t.Errorf("bad parse: %#v", kring)
+ }
+}
+
+func TestDSAHashTruncatation(t *testing.T) {
+ // dsaKeyWithSHA512 was generated with GnuPG and --cert-digest-algo
+ // SHA512 in order to require DSA hash truncation to verify correctly.
+ _, err := ReadKeyRing(readerFromHex(dsaKeyWithSHA512))
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestGetKeyById(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+
+ keys := kring.KeysById(0xa34d7e18c20c31bb)
+ if len(keys) != 1 || keys[0].Entity != kring[0] {
+ t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
+ }
+
+ keys = kring.KeysById(0xfd94408d4543314f)
+ if len(keys) != 1 || keys[0].Entity != kring[0] {
+ t.Errorf("bad result for 0xa34d7e18c20c31bb: %#v", keys)
+ }
+}
+
+func checkSignedMessage(t *testing.T, signedHex, expected string) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+
+ md, err := ReadMessage(readerFromHex(signedHex), kring, nil, nil)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ if !md.IsSigned || md.SignedByKeyId != 0xa34d7e18c20c31bb || md.SignedBy == nil || md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) != 0 || md.IsSymmetricallyEncrypted {
+ t.Errorf("bad MessageDetails: %#v", md)
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error reading UnverifiedBody: %s", err)
+ }
+ if string(contents) != expected {
+ t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
+ }
+ if md.SignatureError != nil || md.Signature == nil {
+ t.Errorf("failed to validate: %s", md.SignatureError)
+ }
+}
+
+func TestSignedMessage(t *testing.T) {
+ checkSignedMessage(t, signedMessageHex, signedInput)
+}
+
+func TestTextSignedMessage(t *testing.T) {
+ checkSignedMessage(t, signedTextMessageHex, signedTextInput)
+}
+
+// The reader should detect "compressed quines", which are compressed
+// packets that expand into themselves and cause an infinite recursive
+// parsing loop.
+// The packet in this test case comes from Taylor R. Campbell at
+// http://mumble.net/~campbell/misc/pgp-quine/
+func TestCampbellQuine(t *testing.T) {
+ md, err := ReadMessage(readerFromHex(campbellQuine), nil, nil, nil)
+ if md != nil {
+ t.Errorf("Reading a compressed quine should not return any data: %#v", md)
+ }
+ structural, ok := err.(errors.StructuralError)
+ if !ok {
+ t.Fatalf("Unexpected class of error: %T", err)
+ }
+ if !strings.Contains(string(structural), "too many layers of packets") {
+ t.Fatalf("Unexpected error: %s", err)
+ }
+}
+
+var signedEncryptedMessageTests = []struct {
+ keyRingHex string
+ messageHex string
+ signedByKeyId uint64
+ encryptedToKeyId uint64
+}{
+ {
+ testKeys1And2PrivateHex,
+ signedEncryptedMessageHex,
+ 0xa34d7e18c20c31bb,
+ 0x2a67d68660df41c7,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ signedEncryptedMessage2Hex,
+ 0x33af447ccd759b09,
+ 0xcf6a7abcd43e3673,
+ },
+}
+
+func TestSignedEncryptedMessage(t *testing.T) {
+ for i, test := range signedEncryptedMessageTests {
+ expected := "Signed and encrypted message\n"
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+ prompt := func(keys []Key, symmetric bool) ([]byte, error) {
+ if symmetric {
+ t.Errorf("prompt: message was marked as symmetrically encrypted")
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ if len(keys) == 0 {
+ t.Error("prompt: no keys requested")
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ err := keys[0].PrivateKey.Decrypt([]byte("passphrase"))
+ if err != nil {
+ t.Errorf("prompt: error decrypting key: %s", err)
+ return nil, errors.ErrKeyIncorrect
+ }
+
+ return nil, nil
+ }
+
+ md, err := ReadMessage(readerFromHex(test.messageHex), kring, prompt, nil)
+ if err != nil {
+ t.Errorf("#%d: error reading message: %s", i, err)
+ return
+ }
+
+ if !md.IsSigned || md.SignedByKeyId != test.signedByKeyId || md.SignedBy == nil || !md.IsEncrypted || md.IsSymmetricallyEncrypted || len(md.EncryptedToKeyIds) == 0 || md.EncryptedToKeyIds[0] != test.encryptedToKeyId {
+ t.Errorf("#%d: bad MessageDetails: %#v", i, md)
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading UnverifiedBody: %s", i, err)
+ }
+ if string(contents) != expected {
+ t.Errorf("#%d: bad UnverifiedBody got:%s want:%s", i, string(contents), expected)
+ }
+
+ if md.SignatureError != nil || md.Signature == nil {
+ t.Errorf("#%d: failed to validate: %s", i, md.SignatureError)
+ }
+ }
+}
+
+func TestUnspecifiedRecipient(t *testing.T) {
+ expected := "Recipient unspecified\n"
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+
+ md, err := ReadMessage(readerFromHex(recipientUnspecifiedHex), kring, nil, nil)
+ if err != nil {
+ t.Errorf("error reading message: %s", err)
+ return
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error reading UnverifiedBody: %s", err)
+ }
+ if string(contents) != expected {
+ t.Errorf("bad UnverifiedBody got:%s want:%s", string(contents), expected)
+ }
+}
+
+func TestSymmetricallyEncrypted(t *testing.T) {
+ firstTimeCalled := true
+
+ prompt := func(keys []Key, symmetric bool) ([]byte, error) {
+ if len(keys) != 0 {
+ t.Errorf("prompt: len(keys) = %d (want 0)", len(keys))
+ }
+
+ if !symmetric {
+ t.Errorf("symmetric is not set")
+ }
+
+ if firstTimeCalled {
+ firstTimeCalled = false
+ return []byte("wrongpassword"), nil
+ }
+
+ return []byte("password"), nil
+ }
+
+ md, err := ReadMessage(readerFromHex(symmetricallyEncryptedCompressedHex), nil, prompt, nil)
+ if err != nil {
+ t.Errorf("ReadMessage: %s", err)
+ return
+ }
+
+ contents, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("ReadAll: %s", err)
+ }
+
+ expectedCreationTime := uint32(1295992998)
+ if md.LiteralData.Time != expectedCreationTime {
+ t.Errorf("LiteralData.Time is %d, want %d", md.LiteralData.Time, expectedCreationTime)
+ }
+
+ const expected = "Symmetrically encrypted.\n"
+ if string(contents) != expected {
+ t.Errorf("contents got: %s want: %s", string(contents), expected)
+ }
+}
+
+func testDetachedSignature(t *testing.T, kring KeyRing, signature io.Reader, sigInput, tag string, expectedSignerKeyId uint64) {
+ signed := bytes.NewBufferString(sigInput)
+ signer, err := CheckDetachedSignature(kring, signed, signature)
+ if err != nil {
+ t.Errorf("%s: signature error: %s", tag, err)
+ return
+ }
+ if signer == nil {
+ t.Errorf("%s: signer is nil", tag)
+ return
+ }
+ if signer.PrimaryKey.KeyId != expectedSignerKeyId {
+ t.Errorf("%s: wrong signer got:%x want:%x", tag, signer.PrimaryKey.KeyId, expectedSignerKeyId)
+ }
+}
+
+func TestDetachedSignature(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureHex), signedInput, "binary", testKey1KeyId)
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureTextHex), signedInput, "text", testKey1KeyId)
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureV3TextHex), signedInput, "v3", testKey1KeyId)
+
+ incorrectSignedInput := signedInput + "X"
+ _, err := CheckDetachedSignature(kring, bytes.NewBufferString(incorrectSignedInput), readerFromHex(detachedSignatureHex))
+ if err == nil {
+ t.Fatal("CheckDetachedSignature returned without error for bad signature")
+ }
+ if err == errors.ErrUnknownIssuer {
+ t.Fatal("CheckDetachedSignature returned ErrUnknownIssuer when the signer was known, but the signature invalid")
+ }
+}
+
+func TestDetachedSignatureDSA(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureDSAHex), signedInput, "binary", testKey3KeyId)
+}
+
+func TestMultipleSignaturePacketsDSA(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyHex))
+ testDetachedSignature(t, kring, readerFromHex(missingHashFunctionHex+detachedSignatureDSAHex), signedInput, "binary", testKey3KeyId)
+}
+
+func TestDetachedSignatureP256(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(p256TestKeyHex))
+ testDetachedSignature(t, kring, readerFromHex(detachedSignatureP256Hex), signedInput, "binary", testKeyP256KeyId)
+}
+
+func testHashFunctionError(t *testing.T, signatureHex string) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ _, err := CheckDetachedSignature(kring, nil, readerFromHex(signatureHex))
+ if err == nil {
+ t.Fatal("Packet with bad hash type was correctly parsed")
+ }
+ unsupported, ok := err.(errors.UnsupportedError)
+ if !ok {
+ t.Fatalf("Unexpected class of error: %s", err)
+ }
+ if !strings.Contains(string(unsupported), "hash ") {
+ t.Fatalf("Unexpected error: %s", err)
+ }
+}
+
+func TestUnknownHashFunction(t *testing.T) {
+ // unknownHashFunctionHex contains a signature packet with hash
+ // function type 153 (which isn't a real hash function id).
+ testHashFunctionError(t, unknownHashFunctionHex)
+}
+
+func TestMissingHashFunction(t *testing.T) {
+ // missingHashFunctionHex contains a signature packet that uses
+ // RIPEMD160, which isn't compiled in. Since that's the only signature
+ // packet we don't find any suitable packets and end up with ErrUnknownIssuer
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2Hex))
+ _, err := CheckDetachedSignature(kring, nil, readerFromHex(missingHashFunctionHex))
+ if err == nil {
+ t.Fatal("Packet with missing hash type was correctly parsed")
+ }
+ if err != errors.ErrUnknownIssuer {
+ t.Fatalf("Unexpected class of error: %s", err)
+ }
+}
+
+func TestReadingArmoredPrivateKey(t *testing.T) {
+ el, err := ReadArmoredKeyRing(bytes.NewBufferString(armoredPrivateKeyBlock))
+ if err != nil {
+ t.Error(err)
+ }
+ if len(el) != 1 {
+ t.Errorf("got %d entities, wanted 1\n", len(el))
+ }
+}
+
+func TestReadingArmoredPublicKey(t *testing.T) {
+ el, err := ReadArmoredKeyRing(bytes.NewBufferString(e2ePublicKey))
+ if err != nil {
+ t.Error(err)
+ }
+ if len(el) != 1 {
+ t.Errorf("didn't get a valid entity")
+ }
+}
+
+func TestNoArmoredData(t *testing.T) {
+ _, err := ReadArmoredKeyRing(bytes.NewBufferString("foo"))
+ if _, ok := err.(errors.InvalidArgumentError); !ok {
+ t.Errorf("error was not an InvalidArgumentError: %s", err)
+ }
+}
+
+func testReadMessageError(t *testing.T, messageHex string) {
+ buf, err := hex.DecodeString(messageHex)
+ if err != nil {
+ t.Errorf("hex.DecodeString(): %v", err)
+ }
+
+ kr, err := ReadKeyRing(new(bytes.Buffer))
+ if err != nil {
+ t.Errorf("ReadKeyring(): %v", err)
+ }
+
+ _, err = ReadMessage(bytes.NewBuffer(buf), kr,
+ func([]Key, bool) ([]byte, error) {
+ return []byte("insecure"), nil
+ }, nil)
+
+ if err == nil {
+ t.Errorf("ReadMessage(): Unexpected nil error")
+ }
+}
+
+func TestIssue11503(t *testing.T) {
+ testReadMessageError(t, "8c040402000aa430aa8228b9248b01fc899a91197130303030")
+}
+
+func TestIssue11504(t *testing.T) {
+ testReadMessageError(t, "9303000130303030303030303030983002303030303030030000000130")
+}
+
+// TestSignatureV3Message tests the verification of V3 signature, generated
+// with a modern V4-style key. Some people have their clients set to generate
+// V3 signatures, so it's useful to be able to verify them.
+func TestSignatureV3Message(t *testing.T) {
+ sig, err := armor.Decode(strings.NewReader(signedMessageV3))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ key, err := ReadArmoredKeyRing(strings.NewReader(keyV4forVerifyingSignedMessageV3))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ md, err := ReadMessage(sig.Body, key, nil, nil)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ _, err = ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // We'll see a sig error here after reading in the UnverifiedBody above,
+ // if there was one to see.
+ if err = md.SignatureError; err != nil {
+ t.Error(err)
+ return
+ }
+
+ if md.SignatureV3 == nil {
+ t.Errorf("No available signature after checking signature")
+ return
+ }
+ if md.Signature != nil {
+ t.Errorf("Did not expect a signature V4 back")
+ return
+ }
+ return
+}
+
+const testKey1KeyId = 0xA34D7E18C20C31BB
+const testKey3KeyId = 0x338934250CCC0360
+const testKeyP256KeyId = 0xd44a2c495918513e
+
+const signedInput = "Signed message\nline 2\nline 3\n"
+const signedTextInput = "Signed message\r\nline 2\r\nline 3\r\n"
+
+const recipientUnspecifiedHex = "848c0300000000000000000103ff62d4d578d03cf40c3da998dfe216c074fa6ddec5e31c197c9666ba292830d91d18716a80f699f9d897389a90e6d62d0238f5f07a5248073c0f24920e4bc4a30c2d17ee4e0cae7c3d4aaa4e8dced50e3010a80ee692175fa0385f62ecca4b56ee6e9980aa3ec51b61b077096ac9e800edaf161268593eedb6cc7027ff5cb32745d250010d407a6221ae22ef18469b444f2822478c4d190b24d36371a95cb40087cdd42d9399c3d06a53c0673349bfb607927f20d1e122bde1e2bf3aa6cae6edf489629bcaa0689539ae3b718914d88ededc3b"
+
+const detachedSignatureHex = "889c04000102000605024d449cd1000a0910a34d7e18c20c31bb167603ff57718d09f28a519fdc7b5a68b6a3336da04df85e38c5cd5d5bd2092fa4629848a33d85b1729402a2aab39c3ac19f9d573f773cc62c264dc924c067a79dfd8a863ae06c7c8686120760749f5fd9b1e03a64d20a7df3446ddc8f0aeadeaeba7cbaee5c1e366d65b6a0c6cc749bcb912d2f15013f812795c2e29eb7f7b77f39ce77"
+
+const detachedSignatureTextHex = "889c04010102000605024d449d21000a0910a34d7e18c20c31bbc8c60400a24fbef7342603a41cb1165767bd18985d015fb72fe05db42db36cfb2f1d455967f1e491194fbf6cf88146222b23bf6ffbd50d17598d976a0417d3192ff9cc0034fd00f287b02e90418bbefe609484b09231e4e7a5f3562e199bf39909ab5276c4d37382fe088f6b5c3426fc1052865da8b3ab158672d58b6264b10823dc4b39"
+
+const detachedSignatureV3TextHex = "8900950305005255c25ca34d7e18c20c31bb0102bb3f04009f6589ef8a028d6e54f6eaf25432e590d31c3a41f4710897585e10c31e5e332c7f9f409af8512adceaff24d0da1474ab07aa7bce4f674610b010fccc5b579ae5eb00a127f272fb799f988ab8e4574c141da6dbfecfef7e6b2c478d9a3d2551ba741f260ee22bec762812f0053e05380bfdd55ad0f22d8cdf71b233fe51ae8a24"
+
+const detachedSignatureDSAHex = "884604001102000605024d6c4eac000a0910338934250ccc0360f18d00a087d743d6405ed7b87755476629600b8b694a39e900a0abff8126f46faf1547c1743c37b21b4ea15b8f83"
+
+const detachedSignatureP256Hex = "885e0400130a0006050256e5bb00000a0910d44a2c495918513edef001009841a4f792beb0befccb35c8838a6a87d9b936beaa86db6745ddc7b045eee0cf00fd1ac1f78306b17e965935dd3f8bae4587a76587e4af231efe19cc4011a8434817"
+
+const testKeys1And2Hex = "988d044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd0011010001b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b0020003b88d044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f0011010001889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab0020003988d044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b0020003b88d044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020003"
+
+const testKeys1And2PrivateHex = "9501d8044d3c5c10010400b1d13382944bd5aba23a4312968b5095d14f947f600eb478e14a6fcb16b0e0cac764884909c020bc495cfcc39a935387c661507bdb236a0612fb582cac3af9b29cc2c8c70090616c41b662f4da4c1201e195472eb7f4ae1ccbcbf9940fe21d985e379a5563dde5b9a23d35f1cfaa5790da3b79db26f23695107bfaca8e7b5bcd00110100010003ff4d91393b9a8e3430b14d6209df42f98dc927425b881f1209f319220841273a802a97c7bdb8b3a7740b3ab5866c4d1d308ad0d3a79bd1e883aacf1ac92dfe720285d10d08752a7efe3c609b1d00f17f2805b217be53999a7da7e493bfc3e9618fd17018991b8128aea70a05dbce30e4fbe626aa45775fa255dd9177aabf4df7cf0200c1ded12566e4bc2bb590455e5becfb2e2c9796482270a943343a7835de41080582c2be3caf5981aa838140e97afa40ad652a0b544f83eb1833b0957dce26e47b0200eacd6046741e9ce2ec5beb6fb5e6335457844fb09477f83b050a96be7da043e17f3a9523567ed40e7a521f818813a8b8a72209f1442844843ccc7eb9805442570200bdafe0438d97ac36e773c7162028d65844c4d463e2420aa2228c6e50dc2743c3d6c72d0d782a5173fe7be2169c8a9f4ef8a7cf3e37165e8c61b89c346cdc6c1799d2b41054657374204b6579203120285253412988b804130102002205024d3c5c10021b03060b090807030206150802090a0b0416020301021e01021780000a0910a34d7e18c20c31bbb5b304009cc45fe610b641a2c146331be94dade0a396e73ca725e1b25c21708d9cab46ecca5ccebc23055879df8f99eea39b377962a400f2ebdc36a7c99c333d74aeba346315137c3ff9d0a09b0273299090343048afb8107cf94cbd1400e3026f0ccac7ecebbc4d78588eb3e478fe2754d3ca664bcf3eac96ca4a6b0c8d7df5102f60f6b00200009d01d8044d3c5c10010400b201df61d67487301f11879d514f4248ade90c8f68c7af1284c161098de4c28c2850f1ec7b8e30f959793e571542ffc6532189409cb51c3d30dad78c4ad5165eda18b20d9826d8707d0f742e2ab492103a85bbd9ddf4f5720f6de7064feb0d39ee002219765bb07bcfb8b877f47abe270ddeda4f676108cecb6b9bb2ad484a4f00110100010003fd17a7490c22a79c59281fb7b20f5e6553ec0c1637ae382e8adaea295f50241037f8997cf42c1ce26417e015091451b15424b2c59eb8d4161b0975630408e394d3b00f88d4b4e18e2cc85e8251d4753a27c639c83f5ad4a571c4f19d7cd460b9b73c25ade730c99df09637bd173d8e3e981ac64432078263bb6dc30d3e974150dd0200d0ee05be3d4604d2146fb0457f31ba17c057560785aa804e8ca5530a7cd81d3440d0f4ba6851efcfd3954b7e68908fc0ba47f7ac37bf559c6c168b70d3a7c8cd0200da1c677c4bce06a068070f2b3733b0a714e88d62aa3f9a26c6f5216d48d5c2b5624144f3807c0df30be66b3268eeeca4df1fbded58faf49fc95dc3c35f134f8b01fd1396b6c0fc1b6c4f0eb8f5e44b8eace1e6073e20d0b8bc5385f86f1cf3f050f66af789f3ef1fc107b7f4421e19e0349c730c68f0a226981f4e889054fdb4dc149e8e889f04180102000905024d3c5c10021b0c000a0910a34d7e18c20c31bb1a03040085c8d62e16d05dc4e9dad64953c8a2eed8b6c12f92b1575eeaa6dcf7be9473dd5b24b37b6dffbb4e7c99ed1bd3cb11634be19b3e6e207bed7505c7ca111ccf47cb323bf1f8851eb6360e8034cbff8dd149993c959de89f8f77f38e7e98b8e3076323aa719328e2b408db5ec0d03936efd57422ba04f925cdc7b4c1af7590e40ab00200009501fe044d3c5c33010400b488c3e5f83f4d561f317817538d9d0397981e9aef1321ca68ebfae1cf8b7d388e19f4b5a24a82e2fbbf1c6c26557a6c5845307a03d815756f564ac7325b02bc83e87d5480a8fae848f07cb891f2d51ce7df83dcafdc12324517c86d472cc0ee10d47a68fd1d9ae49a6c19bbd36d82af597a0d88cc9c49de9df4e696fc1f0b5d0011010001fe030302e9030f3c783e14856063f16938530e148bc57a7aa3f3e4f90df9dceccdc779bc0835e1ad3d006e4a8d7b36d08b8e0de5a0d947254ecfbd22037e6572b426bcfdc517796b224b0036ff90bc574b5509bede85512f2eefb520fb4b02aa523ba739bff424a6fe81c5041f253f8d757e69a503d3563a104d0d49e9e890b9d0c26f96b55b743883b472caa7050c4acfd4a21f875bdf1258d88bd61224d303dc9df77f743137d51e6d5246b88c406780528fd9a3e15bab5452e5b93970d9dcc79f48b38651b9f15bfbcf6da452837e9cc70683d1bdca94507870f743e4ad902005812488dd342f836e72869afd00ce1850eea4cfa53ce10e3608e13d3c149394ee3cbd0e23d018fcbcb6e2ec5a1a22972d1d462ca05355d0d290dd2751e550d5efb38c6c89686344df64852bf4ff86638708f644e8ec6bd4af9b50d8541cb91891a431326ab2e332faa7ae86cfb6e0540aa63160c1e5cdd5a4add518b303fff0a20117c6bc77f7cfbaf36b04c865c6c2b42754657374204b6579203220285253412c20656e637279707465642070726976617465206b65792988b804130102002205024d3c5c33021b03060b090807030206150802090a0b0416020301021e01021780000a0910d4984f961e35246b98940400908a73b6a6169f700434f076c6c79015a49bee37130eaf23aaa3cfa9ce60bfe4acaa7bc95f1146ada5867e0079babb38804891f4f0b8ebca57a86b249dee786161a755b7a342e68ccf3f78ed6440a93a6626beb9a37aa66afcd4f888790cb4bb46d94a4ae3eb3d7d3e6b00f6bfec940303e89ec5b32a1eaaacce66497d539328b00200009d01fe044d3c5c33010400a4e913f9442abcc7f1804ccab27d2f787ffa592077ca935a8bb23165bd8d57576acac647cc596b2c3f814518cc8c82953c7a4478f32e0cf645630a5ba38d9618ef2bc3add69d459ae3dece5cab778938d988239f8c5ae437807075e06c828019959c644ff05ef6a5a1dab72227c98e3a040b0cf219026640698d7a13d8538a570011010001fe030302e9030f3c783e148560f936097339ae381d63116efcf802ff8b1c9360767db5219cc987375702a4123fd8657d3e22700f23f95020d1b261eda5257e9a72f9a918e8ef22dd5b3323ae03bbc1923dd224db988cadc16acc04b120a9f8b7e84da9716c53e0334d7b66586ddb9014df604b41be1e960dcfcbc96f4ed150a1a0dd070b9eb14276b9b6be413a769a75b519a53d3ecc0c220e85cd91ca354d57e7344517e64b43b6e29823cbd87eae26e2b2e78e6dedfbb76e3e9f77bcb844f9a8932eb3db2c3f9e44316e6f5d60e9e2a56e46b72abe6b06dc9a31cc63f10023d1f5e12d2a3ee93b675c96f504af0001220991c88db759e231b3320dcedf814dcf723fd9857e3d72d66a0f2af26950b915abdf56c1596f46a325bf17ad4810d3535fb02a259b247ac3dbd4cc3ecf9c51b6c07cebb009c1506fba0a89321ec8683e3fd009a6e551d50243e2d5092fefb3321083a4bad91320dc624bd6b5dddf93553e3d53924c05bfebec1fb4bd47e89a1a889f04180102000905024d3c5c33021b0c000a0910d4984f961e35246b26c703ff7ee29ef53bc1ae1ead533c408fa136db508434e233d6e62be621e031e5940bbd4c08142aed0f82217e7c3e1ec8de574bc06ccf3c36633be41ad78a9eacd209f861cae7b064100758545cc9dd83db71806dc1cfd5fb9ae5c7474bba0c19c44034ae61bae5eca379383339dece94ff56ff7aa44a582f3e5c38f45763af577c0934b0020000"
+
+const dsaElGamalTestKeysHex = "9501e1044dfcb16a110400aa3e5c1a1f43dd28c2ffae8abf5cfce555ee874134d8ba0a0f7b868ce2214beddc74e5e1e21ded354a95d18acdaf69e5e342371a71fbb9093162e0c5f3427de413a7f2c157d83f5cd2f9d791256dc4f6f0e13f13c3302af27f2384075ab3021dff7a050e14854bbde0a1094174855fc02f0bae8e00a340d94a1f22b32e48485700a0cec672ac21258fb95f61de2ce1af74b2c4fa3e6703ff698edc9be22c02ae4d916e4fa223f819d46582c0516235848a77b577ea49018dcd5e9e15cff9dbb4663a1ae6dd7580fa40946d40c05f72814b0f88481207e6c0832c3bded4853ebba0a7e3bd8e8c66df33d5a537cd4acf946d1080e7a3dcea679cb2b11a72a33a2b6a9dc85f466ad2ddf4c3db6283fa645343286971e3dd700703fc0c4e290d45767f370831a90187e74e9972aae5bff488eeff7d620af0362bfb95c1a6c3413ab5d15a2e4139e5d07a54d72583914661ed6a87cce810be28a0aa8879a2dd39e52fb6fe800f4f181ac7e328f740cde3d09a05cecf9483e4cca4253e60d4429ffd679d9996a520012aad119878c941e3cf151459873bdfc2a9563472fe0303027a728f9feb3b864260a1babe83925ce794710cfd642ee4ae0e5b9d74cee49e9c67b6cd0ea5dfbb582132195a121356a1513e1bca73e5b80c58c7ccb4164453412f456c47616d616c2054657374204b65792031886204131102002205024dfcb16a021b03060b090807030206150802090a0b0416020301021e01021780000a091033af447ccd759b09fadd00a0b8fd6f5a790bad7e9f2dbb7632046dc4493588db009c087c6a9ba9f7f49fab221587a74788c00db4889ab00200009d0157044dfcb16a1004008dec3f9291205255ccff8c532318133a6840739dd68b03ba942676f9038612071447bf07d00d559c5c0875724ea16a4c774f80d8338b55fca691a0522e530e604215b467bbc9ccfd483a1da99d7bc2648b4318fdbd27766fc8bfad3fddb37c62b8ae7ccfe9577e9b8d1e77c1d417ed2c2ef02d52f4da11600d85d3229607943700030503ff506c94c87c8cab778e963b76cf63770f0a79bf48fb49d3b4e52234620fc9f7657f9f8d56c96a2b7c7826ae6b57ebb2221a3fe154b03b6637cea7e6d98e3e45d87cf8dc432f723d3d71f89c5192ac8d7290684d2c25ce55846a80c9a7823f6acd9bb29fa6cd71f20bc90eccfca20451d0c976e460e672b000df49466408d527affe0303027a728f9feb3b864260abd761730327bca2aaa4ea0525c175e92bf240682a0e83b226f97ecb2e935b62c9a133858ce31b271fa8eb41f6a1b3cd72a63025ce1a75ee4180dcc284884904181102000905024dfcb16a021b0c000a091033af447ccd759b09dd0b009e3c3e7296092c81bee5a19929462caaf2fff3ae26009e218c437a2340e7ea628149af1ec98ec091a43992b00200009501e1044dfcb1be1104009f61faa61aa43df75d128cbe53de528c4aec49ce9360c992e70c77072ad5623de0a3a6212771b66b39a30dad6781799e92608316900518ec01184a85d872365b7d2ba4bacfb5882ea3c2473d3750dc6178cc1cf82147fb58caa28b28e9f12f6d1efcb0534abed644156c91cca4ab78834268495160b2400bc422beb37d237c2300a0cac94911b6d493bda1e1fbc6feeca7cb7421d34b03fe22cec6ccb39675bb7b94a335c2b7be888fd3906a1125f33301d8aa6ec6ee6878f46f73961c8d57a3e9544d8ef2a2cbfd4d52da665b1266928cfe4cb347a58c412815f3b2d2369dec04b41ac9a71cc9547426d5ab941cccf3b18575637ccfb42df1a802df3cfe0a999f9e7109331170e3a221991bf868543960f8c816c28097e503fe319db10fb98049f3a57d7c80c420da66d56f3644371631fad3f0ff4040a19a4fedc2d07727a1b27576f75a4d28c47d8246f27071e12d7a8de62aad216ddbae6aa02efd6b8a3e2818cda48526549791ab277e447b3a36c57cefe9b592f5eab73959743fcc8e83cbefec03a329b55018b53eec196765ae40ef9e20521a603c551efe0303020950d53a146bf9c66034d00c23130cce95576a2ff78016ca471276e8227fb30b1ffbd92e61804fb0c3eff9e30b1a826ee8f3e4730b4d86273ca977b4164453412f456c47616d616c2054657374204b65792032886204131102002205024dfcb1be021b03060b090807030206150802090a0b0416020301021e01021780000a0910a86bf526325b21b22bd9009e34511620415c974750a20df5cb56b182f3b48e6600a0a9466cb1a1305a84953445f77d461593f1d42bc1b00200009d0157044dfcb1be1004009565a951da1ee87119d600c077198f1c1bceb0f7aa54552489298e41ff788fa8f0d43a69871f0f6f77ebdfb14a4260cf9fbeb65d5844b4272a1904dd95136d06c3da745dc46327dd44a0f16f60135914368c8039a34033862261806bb2c5ce1152e2840254697872c85441ccb7321431d75a747a4bfb1d2c66362b51ce76311700030503fc0ea76601c196768070b7365a200e6ddb09307f262d5f39eec467b5f5784e22abdf1aa49226f59ab37cb49969d8f5230ea65caf56015abda62604544ed526c5c522bf92bed178a078789f6c807b6d34885688024a5bed9e9f8c58d11d4b82487b44c5f470c5606806a0443b79cadb45e0f897a561a53f724e5349b9267c75ca17fe0303020950d53a146bf9c660bc5f4ce8f072465e2d2466434320c1e712272fafc20e342fe7608101580fa1a1a367e60486a7cd1246b7ef5586cf5e10b32762b710a30144f12dd17dd4884904181102000905024dfcb1be021b0c000a0910a86bf526325b21b2904c00a0b2b66b4b39ccffda1d10f3ea8d58f827e30a8b8e009f4255b2d8112a184e40cde43a34e8655ca7809370b0020000"
+
+const signedMessageHex = "a3019bc0cbccc0c4b8d8b74ee2108fe16ec6d3ca490cbe362d3f8333d3f352531472538b8b13d353b97232f352158c20943157c71c16064626063656269052062e4e01987e9b6fccff4b7df3a34c534b23e679cbec3bc0f8f6e64dfb4b55fe3f8efa9ce110ddb5cd79faf1d753c51aecfa669f7e7aa043436596cccc3359cb7dd6bbe9ecaa69e5989d9e57209571edc0b2fa7f57b9b79a64ee6e99ce1371395fee92fec2796f7b15a77c386ff668ee27f6d38f0baa6c438b561657377bf6acff3c5947befd7bf4c196252f1d6e5c524d0300"
+
+const signedTextMessageHex = "a3019bc0cbccc8c4b8d8b74ee2108fe16ec6d36a250cbece0c178233d3f352531472538b8b13d35379b97232f352158ca0b4312f57c71c1646462606365626906a062e4e019811591798ff99bf8afee860b0d8a8c2a85c3387e3bcf0bb3b17987f2bbcfab2aa526d930cbfd3d98757184df3995c9f3e7790e36e3e9779f06089d4c64e9e47dd6202cb6e9bc73c5d11bb59fbaf89d22d8dc7cf199ddf17af96e77c5f65f9bbed56f427bd8db7af37f6c9984bf9385efaf5f184f986fb3e6adb0ecfe35bbf92d16a7aa2a344fb0bc52fb7624f0200"
+
+const signedEncryptedMessageHex = "848c032a67d68660df41c70103ff5789d0de26b6a50c985a02a13131ca829c413a35d0e6fa8d6842599252162808ac7439c72151c8c6183e76923fe3299301414d0c25a2f06a2257db3839e7df0ec964773f6e4c4ac7ff3b48c444237166dd46ba8ff443a5410dc670cb486672fdbe7c9dfafb75b4fea83af3a204fe2a7dfa86bd20122b4f3d2646cbeecb8f7be8d2c03b018bd210b1d3791e1aba74b0f1034e122ab72e760492c192383cf5e20b5628bd043272d63df9b923f147eb6091cd897553204832aba48fec54aa447547bb16305a1024713b90e77fd0065f1918271947549205af3c74891af22ee0b56cd29bfec6d6e351901cd4ab3ece7c486f1e32a792d4e474aed98ee84b3f591c7dff37b64e0ecd68fd036d517e412dcadf85840ce184ad7921ad446c4ee28db80447aea1ca8d4f574db4d4e37688158ddd19e14ee2eab4873d46947d65d14a23e788d912cf9a19624ca7352469b72a83866b7c23cb5ace3deab3c7018061b0ba0f39ed2befe27163e5083cf9b8271e3e3d52cc7ad6e2a3bd81d4c3d7022f8d"
+
+const signedEncryptedMessage2Hex = "85010e03cf6a7abcd43e36731003fb057f5495b79db367e277cdbe4ab90d924ddee0c0381494112ff8c1238fb0184af35d1731573b01bc4c55ecacd2aafbe2003d36310487d1ecc9ac994f3fada7f9f7f5c3a64248ab7782906c82c6ff1303b69a84d9a9529c31ecafbcdb9ba87e05439897d87e8a2a3dec55e14df19bba7f7bd316291c002ae2efd24f83f9e3441203fc081c0c23dc3092a454ca8a082b27f631abf73aca341686982e8fbda7e0e7d863941d68f3de4a755c2964407f4b5e0477b3196b8c93d551dd23c8beef7d0f03fbb1b6066f78907faf4bf1677d8fcec72651124080e0b7feae6b476e72ab207d38d90b958759fdedfc3c6c35717c9dbfc979b3cfbbff0a76d24a5e57056bb88acbd2a901ef64bc6e4db02adc05b6250ff378de81dca18c1910ab257dff1b9771b85bb9bbe0a69f5989e6d1710a35e6dfcceb7d8fb5ccea8db3932b3d9ff3fe0d327597c68b3622aec8e3716c83a6c93f497543b459b58ba504ed6bcaa747d37d2ca746fe49ae0a6ce4a8b694234e941b5159ff8bd34b9023da2814076163b86f40eed7c9472f81b551452d5ab87004a373c0172ec87ea6ce42ccfa7dbdad66b745496c4873d8019e8c28d6b3"
+
+const symmetricallyEncryptedCompressedHex = "8c0d04030302eb4a03808145d0d260c92f714339e13de5a79881216431925bf67ee2898ea61815f07894cd0703c50d0a76ef64d482196f47a8bc729af9b80bb6"
+
+const dsaTestKeyHex = "9901a2044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const dsaTestKeyPrivateHex = "9501bb044d6c49de110400cb5ce438cf9250907ac2ba5bf6547931270b89f7c4b53d9d09f4d0213a5ef2ec1f26806d3d259960f872a4a102ef1581ea3f6d6882d15134f21ef6a84de933cc34c47cc9106efe3bd84c6aec12e78523661e29bc1a61f0aab17fa58a627fd5fd33f5149153fbe8cd70edf3d963bc287ef875270ff14b5bfdd1bca4483793923b00a0fe46d76cb6e4cbdc568435cd5480af3266d610d303fe33ae8273f30a96d4d34f42fa28ce1112d425b2e3bf7ea553d526e2db6b9255e9dc7419045ce817214d1a0056dbc8d5289956a4b1b69f20f1105124096e6a438f41f2e2495923b0f34b70642607d45559595c7fe94d7fa85fc41bf7d68c1fd509ebeaa5f315f6059a446b9369c277597e4f474a9591535354c7e7f4fd98a08aa60400b130c24ff20bdfbf683313f5daebf1c9b34b3bdadfc77f2ddd72ee1fb17e56c473664bc21d66467655dd74b9005e3a2bacce446f1920cd7017231ae447b67036c9b431b8179deacd5120262d894c26bc015bffe3d827ba7087ad9b700d2ca1f6d16cc1786581e5dd065f293c31209300f9b0afcc3f7c08dd26d0a22d87580b4d00009f592e0619d823953577d4503061706843317e4fee083db41054657374204b65792033202844534129886204131102002205024d6c49de021b03060b090807030206150802090a0b0416020301021e01021780000a0910338934250ccc03607e0400a0bdb9193e8a6b96fc2dfc108ae848914b504481f100a09c4dc148cb693293a67af24dd40d2b13a9e36794"
+
+const p256TestKeyHex = "98520456e5b83813082a8648ce3d030107020304a2072cd6d21321266c758cc5b83fab0510f751cb8d91897cddb7047d8d6f185546e2107111b0a95cb8ef063c33245502af7a65f004d5919d93ee74eb71a66253b424502d3235362054657374204b6579203c696e76616c6964406578616d706c652e636f6d3e8879041313080021050256e5b838021b03050b09080702061508090a0b020416020301021e01021780000a0910d44a2c495918513e54e50100dfa64f97d9b47766fc1943c6314ba3f2b2a103d71ad286dc5b1efb96a345b0c80100dbc8150b54241f559da6ef4baacea6d31902b4f4b1bdc09b34bf0502334b7754b8560456e5b83812082a8648ce3d030107020304bfe3cea9cee13486f8d518aa487fecab451f25467d2bf08e58f63e5fa525d5482133e6a79299c274b068ef0be448152ad65cf11cf764348588ca4f6a0bcf22b6030108078861041813080009050256e5b838021b0c000a0910d44a2c495918513e4a4800ff49d589fa64024ad30be363a032e3a0e0e6f5db56ba4c73db850518bf0121b8f20100fd78e065f4c70ea5be9df319ea67e493b936fc78da834a71828043d3154af56e"
+
+const p256TestKeyPrivateHex = "94a50456e5b83813082a8648ce3d030107020304a2072cd6d21321266c758cc5b83fab0510f751cb8d91897cddb7047d8d6f185546e2107111b0a95cb8ef063c33245502af7a65f004d5919d93ee74eb71a66253fe070302f0c2bfb0b6c30f87ee1599472b8636477eab23ced13b271886a4b50ed34c9d8436af5af5b8f88921f0efba6ef8c37c459bbb88bc1c6a13bbd25c4ce9b1e97679569ee77645d469bf4b43de637f5561b424502d3235362054657374204b6579203c696e76616c6964406578616d706c652e636f6d3e8879041313080021050256e5b838021b03050b09080702061508090a0b020416020301021e01021780000a0910d44a2c495918513e54e50100dfa64f97d9b47766fc1943c6314ba3f2b2a103d71ad286dc5b1efb96a345b0c80100dbc8150b54241f559da6ef4baacea6d31902b4f4b1bdc09b34bf0502334b77549ca90456e5b83812082a8648ce3d030107020304bfe3cea9cee13486f8d518aa487fecab451f25467d2bf08e58f63e5fa525d5482133e6a79299c274b068ef0be448152ad65cf11cf764348588ca4f6a0bcf22b603010807fe0703027510012471a603cfee2968dce19f732721ddf03e966fd133b4e3c7a685b788705cbc46fb026dc94724b830c9edbaecd2fb2c662f23169516cacd1fe423f0475c364ecc10abcabcfd4bbbda1a36a1bd8861041813080009050256e5b838021b0c000a0910d44a2c495918513e4a4800ff49d589fa64024ad30be363a032e3a0e0e6f5db56ba4c73db850518bf0121b8f20100fd78e065f4c70ea5be9df319ea67e493b936fc78da834a71828043d3154af56e"
+
+const armoredPrivateKeyBlock = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+lQHYBE2rFNoBBADFwqWQIW/DSqcB4yCQqnAFTJ27qS5AnB46ccAdw3u4Greeu3Bp
+idpoHdjULy7zSKlwR1EA873dO/k/e11Ml3dlAFUinWeejWaK2ugFP6JjiieSsrKn
+vWNicdCS4HTWn0X4sjl0ZiAygw6GNhqEQ3cpLeL0g8E9hnYzJKQ0LWJa0QARAQAB
+AAP/TB81EIo2VYNmTq0pK1ZXwUpxCrvAAIG3hwKjEzHcbQznsjNvPUihZ+NZQ6+X
+0HCfPAdPkGDCLCb6NavcSW+iNnLTrdDnSI6+3BbIONqWWdRDYJhqZCkqmG6zqSfL
+IdkJgCw94taUg5BWP/AAeQrhzjChvpMQTVKQL5mnuZbUCeMCAN5qrYMP2S9iKdnk
+VANIFj7656ARKt/nf4CBzxcpHTyB8+d2CtPDKCmlJP6vL8t58Jmih+kHJMvC0dzn
+gr5f5+sCAOOe5gt9e0am7AvQWhdbHVfJU0TQJx+m2OiCJAqGTB1nvtBLHdJnfdC9
+TnXXQ6ZXibqLyBies/xeY2sCKL5qtTMCAKnX9+9d/5yQxRyrQUHt1NYhaXZnJbHx
+q4ytu0eWz+5i68IYUSK69jJ1NWPM0T6SkqpB3KCAIv68VFm9PxqG1KmhSrQIVGVz
+dCBLZXmIuAQTAQIAIgUCTasU2gIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AA
+CgkQO9o98PRieSoLhgQAkLEZex02Qt7vGhZzMwuN0R22w3VwyYyjBx+fM3JFETy1
+ut4xcLJoJfIaF5ZS38UplgakHG0FQ+b49i8dMij0aZmDqGxrew1m4kBfjXw9B/v+
+eIqpODryb6cOSwyQFH0lQkXC040pjq9YqDsO5w0WYNXYKDnzRV0p4H1pweo2VDid
+AdgETasU2gEEAN46UPeWRqKHvA99arOxee38fBt2CI08iiWyI8T3J6ivtFGixSqV
+bRcPxYO/qLpVe5l84Nb3X71GfVXlc9hyv7CD6tcowL59hg1E/DC5ydI8K8iEpUmK
+/UnHdIY5h8/kqgGxkY/T/hgp5fRQgW1ZoZxLajVlMRZ8W4tFtT0DeA+JABEBAAEA
+A/0bE1jaaZKj6ndqcw86jd+QtD1SF+Cf21CWRNeLKnUds4FRRvclzTyUMuWPkUeX
+TaNNsUOFqBsf6QQ2oHUBBK4VCHffHCW4ZEX2cd6umz7mpHW6XzN4DECEzOVksXtc
+lUC1j4UB91DC/RNQqwX1IV2QLSwssVotPMPqhOi0ZLNY7wIA3n7DWKInxYZZ4K+6
+rQ+POsz6brEoRHwr8x6XlHenq1Oki855pSa1yXIARoTrSJkBtn5oI+f8AzrnN0BN
+oyeQAwIA/7E++3HDi5aweWrViiul9cd3rcsS0dEnksPhvS0ozCJiHsq/6GFmy7J8
+QSHZPteedBnZyNp5jR+H7cIfVN3KgwH/Skq4PsuPhDq5TKK6i8Pc1WW8MA6DXTdU
+nLkX7RGmMwjC0DBf7KWAlPjFaONAX3a8ndnz//fy1q7u2l9AZwrj1qa1iJ8EGAEC
+AAkFAk2rFNoCGwwACgkQO9o98PRieSo2/QP/WTzr4ioINVsvN1akKuekmEMI3LAp
+BfHwatufxxP1U+3Si/6YIk7kuPB9Hs+pRqCXzbvPRrI8NHZBmc8qIGthishdCYad
+AHcVnXjtxrULkQFGbGvhKURLvS9WnzD/m1K2zzwxzkPTzT9/Yf06O6Mal5AdugPL
+VrM0m72/jnpKo04=
+=zNCn
+-----END PGP PRIVATE KEY BLOCK-----`
+
+const e2ePublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Charset: UTF-8
+
+xv8AAABSBAAAAAATCCqGSM49AwEHAgME1LRoXSpOxtHXDUdmuvzchyg6005qIBJ4
+sfaSxX7QgH9RV2ONUhC+WiayCNADq+UMzuR/vunSr4aQffXvuGnR383/AAAAFDxk
+Z2lsQHlhaG9vLWluYy5jb20+wv8AAACGBBATCAA4/wAAAAWCVGvAG/8AAAACiwn/
+AAAACZC2VkQCOjdvYf8AAAAFlQgJCgv/AAAAA5YBAv8AAAACngEAAE1BAP0X8veD
+24IjmI5/C6ZAfVNXxgZZFhTAACFX75jUA3oD6AEAzoSwKf1aqH6oq62qhCN/pekX
++WAsVMBhNwzLpqtCRjLO/wAAAFYEAAAAABIIKoZIzj0DAQcCAwT50ain7vXiIRv8
+B1DO3x3cE/aattZ5sHNixJzRCXi2vQIA5QmOxZ6b5jjUekNbdHG3SZi1a2Ak5mfX
+fRxC/5VGAwEIB8L/AAAAZQQYEwgAGP8AAAAFglRrwBz/AAAACZC2VkQCOjdvYQAA
+FJAA9isX3xtGyMLYwp2F3nXm7QEdY5bq5VUcD/RJlj792VwA/1wH0pCzVLl4Q9F9
+ex7En5r7rHR5xwX82Msc+Rq9dSyO
+=7MrZ
+-----END PGP PUBLIC KEY BLOCK-----`
+
+const dsaKeyWithSHA512 = `9901a2044f04b07f110400db244efecc7316553ee08d179972aab87bb1214de7692593fcf5b6feb1c80fba268722dd464748539b85b81d574cd2d7ad0ca2444de4d849b8756bad7768c486c83a824f9bba4af773d11742bdfb4ac3b89ef8cc9452d4aad31a37e4b630d33927bff68e879284a1672659b8b298222fc68f370f3e24dccacc4a862442b9438b00a0ea444a24088dc23e26df7daf8f43cba3bffc4fe703fe3d6cd7fdca199d54ed8ae501c30e3ec7871ea9cdd4cf63cfe6fc82281d70a5b8bb493f922cd99fba5f088935596af087c8d818d5ec4d0b9afa7f070b3d7c1dd32a84fca08d8280b4890c8da1dde334de8e3cad8450eed2a4a4fcc2db7b8e5528b869a74a7f0189e11ef097ef1253582348de072bb07a9fa8ab838e993cef0ee203ff49298723e2d1f549b00559f886cd417a41692ce58d0ac1307dc71d85a8af21b0cf6eaa14baf2922d3a70389bedf17cc514ba0febbd107675a372fe84b90162a9e88b14d4b1c6be855b96b33fb198c46f058568817780435b6936167ebb3724b680f32bf27382ada2e37a879b3d9de2abe0c3f399350afd1ad438883f4791e2e3b4184453412068617368207472756e636174696f6e207465737488620413110a002205024f04b07f021b03060b090807030206150802090a0b0416020301021e01021780000a0910ef20e0cefca131581318009e2bf3bf047a44d75a9bacd00161ee04d435522397009a03a60d51bd8a568c6c021c8d7cf1be8d990d6417b0020003`
+
+const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6acc0b21f32ffff01010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101`
+
+const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000`
+
+const keyV4forVerifyingSignedMessageV3 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: GPGTools - https://gpgtools.org
+
+mI0EVfxoFQEEAMBIqmbDfYygcvP6Phr1wr1XI41IF7Qixqybs/foBF8qqblD9gIY
+BKpXjnBOtbkcVOJ0nljd3/sQIfH4E0vQwK5/4YRQSI59eKOqd6Fx+fWQOLG+uu6z
+tewpeCj9LLHvibx/Sc7VWRnrznia6ftrXxJ/wHMezSab3tnGC0YPVdGNABEBAAG0
+JEdvY3J5cHRvIFRlc3QgS2V5IDx0aGVtYXhAZ21haWwuY29tPoi5BBMBCgAjBQJV
+/GgVAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQeXnQmhdGW9PFVAP+
+K7TU0qX5ArvIONIxh/WAweyOk884c5cE8f+3NOPOOCRGyVy0FId5A7MmD5GOQh4H
+JseOZVEVCqlmngEvtHZb3U1VYtVGE5WZ+6rQhGsMcWP5qaT4soYwMBlSYxgYwQcx
+YhN9qOr292f9j2Y//TTIJmZT4Oa+lMxhWdqTfX+qMgG4jQRV/GgVAQQArhFSiij1
+b+hT3dnapbEU+23Z1yTu1DfF6zsxQ4XQWEV3eR8v+8mEDDNcz8oyyF56k6UQ3rXi
+UMTIwRDg4V6SbZmaFbZYCOwp/EmXJ3rfhm7z7yzXj2OFN22luuqbyVhuL7LRdB0M
+pxgmjXb4tTvfgKd26x34S+QqUJ7W6uprY4sAEQEAAYifBBgBCgAJBQJV/GgVAhsM
+AAoJEHl50JoXRlvT7y8D/02ckx4OMkKBZo7viyrBw0MLG92i+DC2bs35PooHR6zz
+786mitjOp5z2QWNLBvxC70S0qVfCIz8jKupO1J6rq6Z8CcbLF3qjm6h1omUBf8Nd
+EfXKD2/2HV6zMKVknnKzIEzauh+eCKS2CeJUSSSryap/QLVAjRnckaES/OsEWhNB
+=RZia
+-----END PGP PUBLIC KEY BLOCK-----
+`
+
+const signedMessageV3 = `-----BEGIN PGP MESSAGE-----
+Comment: GPGTools - https://gpgtools.org
+
+owGbwMvMwMVYWXlhlrhb9GXG03JJDKF/MtxDMjKLFYAoUaEktbhEITe1uDgxPVWP
+q5NhKjMrWAVcC9evD8z/bF/uWNjqtk/X3y5/38XGRQHm/57rrDRYuGnTw597Xqka
+uM3137/hH3Os+Jf2dc0fXOITKwJvXJvecPVs0ta+Vg7ZO1MLn8w58Xx+6L58mbka
+DGHyU9yTueZE8D+QF/Tz28Y78dqtF56R1VPn9Xw4uJqrWYdd7b3vIZ1V6R4Nh05d
+iT57d/OhWwA=
+=hG7R
+-----END PGP MESSAGE-----
+`
diff --git a/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go b/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go
new file mode 100644
index 000000000..4b9a44ca2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/s2k/s2k.go
@@ -0,0 +1,273 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package s2k implements the various OpenPGP string-to-key transforms as
+// specified in RFC 4800 section 3.7.1.
+package s2k // import "golang.org/x/crypto/openpgp/s2k"
+
+import (
+ "crypto"
+ "hash"
+ "io"
+ "strconv"
+
+ "golang.org/x/crypto/openpgp/errors"
+)
+
+// Config collects configuration parameters for s2k key-stretching
+// transformatioms. A nil *Config is valid and results in all default
+// values. Currently, Config is used only by the Serialize function in
+// this package.
+type Config struct {
+ // Hash is the default hash function to be used. If
+ // nil, SHA1 is used.
+ Hash crypto.Hash
+ // S2KCount is only used for symmetric encryption. It
+ // determines the strength of the passphrase stretching when
+ // the said passphrase is hashed to produce a key. S2KCount
+ // should be between 1024 and 65011712, inclusive. If Config
+ // is nil or S2KCount is 0, the value 65536 used. Not all
+ // values in the above range can be represented. S2KCount will
+ // be rounded up to the next representable value if it cannot
+ // be encoded exactly. When set, it is strongly encrouraged to
+ // use a value that is at least 65536. See RFC 4880 Section
+ // 3.7.1.3.
+ S2KCount int
+}
+
+func (c *Config) hash() crypto.Hash {
+ if c == nil || uint(c.Hash) == 0 {
+ // SHA1 is the historical default in this package.
+ return crypto.SHA1
+ }
+
+ return c.Hash
+}
+
+func (c *Config) encodedCount() uint8 {
+ if c == nil || c.S2KCount == 0 {
+ return 96 // The common case. Correspoding to 65536
+ }
+
+ i := c.S2KCount
+ switch {
+ // Behave like GPG. Should we make 65536 the lowest value used?
+ case i < 1024:
+ i = 1024
+ case i > 65011712:
+ i = 65011712
+ }
+
+ return encodeCount(i)
+}
+
+// encodeCount converts an iterative "count" in the range 1024 to
+// 65011712, inclusive, to an encoded count. The return value is the
+// octet that is actually stored in the GPG file. encodeCount panics
+// if i is not in the above range (encodedCount above takes care to
+// pass i in the correct range). See RFC 4880 Section 3.7.7.1.
+func encodeCount(i int) uint8 {
+ if i < 1024 || i > 65011712 {
+ panic("count arg i outside the required range")
+ }
+
+ for encoded := 0; encoded < 256; encoded++ {
+ count := decodeCount(uint8(encoded))
+ if count >= i {
+ return uint8(encoded)
+ }
+ }
+
+ return 255
+}
+
+// decodeCount returns the s2k mode 3 iterative "count" corresponding to
+// the encoded octet c.
+func decodeCount(c uint8) int {
+ return (16 + int(c&15)) << (uint32(c>>4) + 6)
+}
+
+// Simple writes to out the result of computing the Simple S2K function (RFC
+// 4880, section 3.7.1.1) using the given hash and input passphrase.
+func Simple(out []byte, h hash.Hash, in []byte) {
+ Salted(out, h, in, nil)
+}
+
+var zero [1]byte
+
+// Salted writes to out the result of computing the Salted S2K function (RFC
+// 4880, section 3.7.1.2) using the given hash, input passphrase and salt.
+func Salted(out []byte, h hash.Hash, in []byte, salt []byte) {
+ done := 0
+ var digest []byte
+
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ h.Write(salt)
+ h.Write(in)
+ digest = h.Sum(digest[:0])
+ n := copy(out[done:], digest)
+ done += n
+ }
+}
+
+// Iterated writes to out the result of computing the Iterated and Salted S2K
+// function (RFC 4880, section 3.7.1.3) using the given hash, input passphrase,
+// salt and iteration count.
+func Iterated(out []byte, h hash.Hash, in []byte, salt []byte, count int) {
+ combined := make([]byte, len(in)+len(salt))
+ copy(combined, salt)
+ copy(combined[len(salt):], in)
+
+ if count < len(combined) {
+ count = len(combined)
+ }
+
+ done := 0
+ var digest []byte
+ for i := 0; done < len(out); i++ {
+ h.Reset()
+ for j := 0; j < i; j++ {
+ h.Write(zero[:])
+ }
+ written := 0
+ for written < count {
+ if written+len(combined) > count {
+ todo := count - written
+ h.Write(combined[:todo])
+ written = count
+ } else {
+ h.Write(combined)
+ written += len(combined)
+ }
+ }
+ digest = h.Sum(digest[:0])
+ n := copy(out[done:], digest)
+ done += n
+ }
+}
+
+// Parse reads a binary specification for a string-to-key transformation from r
+// and returns a function which performs that transform.
+func Parse(r io.Reader) (f func(out, in []byte), err error) {
+ var buf [9]byte
+
+ _, err = io.ReadFull(r, buf[:2])
+ if err != nil {
+ return
+ }
+
+ hash, ok := HashIdToHash(buf[1])
+ if !ok {
+ return nil, errors.UnsupportedError("hash for S2K function: " + strconv.Itoa(int(buf[1])))
+ }
+ if !hash.Available() {
+ return nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hash)))
+ }
+ h := hash.New()
+
+ switch buf[0] {
+ case 0:
+ f := func(out, in []byte) {
+ Simple(out, h, in)
+ }
+ return f, nil
+ case 1:
+ _, err = io.ReadFull(r, buf[:8])
+ if err != nil {
+ return
+ }
+ f := func(out, in []byte) {
+ Salted(out, h, in, buf[:8])
+ }
+ return f, nil
+ case 3:
+ _, err = io.ReadFull(r, buf[:9])
+ if err != nil {
+ return
+ }
+ count := decodeCount(buf[8])
+ f := func(out, in []byte) {
+ Iterated(out, h, in, buf[:8], count)
+ }
+ return f, nil
+ }
+
+ return nil, errors.UnsupportedError("S2K function")
+}
+
+// Serialize salts and stretches the given passphrase and writes the
+// resulting key into key. It also serializes an S2K descriptor to
+// w. The key stretching can be configured with c, which may be
+// nil. In that case, sensible defaults will be used.
+func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Config) error {
+ var buf [11]byte
+ buf[0] = 3 /* iterated and salted */
+ buf[1], _ = HashToHashId(c.hash())
+ salt := buf[2:10]
+ if _, err := io.ReadFull(rand, salt); err != nil {
+ return err
+ }
+ encodedCount := c.encodedCount()
+ count := decodeCount(encodedCount)
+ buf[10] = encodedCount
+ if _, err := w.Write(buf[:]); err != nil {
+ return err
+ }
+
+ Iterated(key, c.hash().New(), passphrase, salt, count)
+ return nil
+}
+
+// hashToHashIdMapping contains pairs relating OpenPGP's hash identifier with
+// Go's crypto.Hash type. See RFC 4880, section 9.4.
+var hashToHashIdMapping = []struct {
+ id byte
+ hash crypto.Hash
+ name string
+}{
+ {1, crypto.MD5, "MD5"},
+ {2, crypto.SHA1, "SHA1"},
+ {3, crypto.RIPEMD160, "RIPEMD160"},
+ {8, crypto.SHA256, "SHA256"},
+ {9, crypto.SHA384, "SHA384"},
+ {10, crypto.SHA512, "SHA512"},
+ {11, crypto.SHA224, "SHA224"},
+}
+
+// HashIdToHash returns a crypto.Hash which corresponds to the given OpenPGP
+// hash id.
+func HashIdToHash(id byte) (h crypto.Hash, ok bool) {
+ for _, m := range hashToHashIdMapping {
+ if m.id == id {
+ return m.hash, true
+ }
+ }
+ return 0, false
+}
+
+// HashIdToString returns the name of the hash function corresponding to the
+// given OpenPGP hash id.
+func HashIdToString(id byte) (name string, ok bool) {
+ for _, m := range hashToHashIdMapping {
+ if m.id == id {
+ return m.name, true
+ }
+ }
+
+ return "", false
+}
+
+// HashIdToHash returns an OpenPGP hash id which corresponds the given Hash.
+func HashToHashId(h crypto.Hash) (id byte, ok bool) {
+ for _, m := range hashToHashIdMapping {
+ if m.hash == h {
+ return m.id, true
+ }
+ }
+ return 0, false
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go b/vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go
new file mode 100644
index 000000000..183d26056
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/s2k/s2k_test.go
@@ -0,0 +1,137 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package s2k
+
+import (
+ "bytes"
+ "crypto"
+ _ "crypto/md5"
+ "crypto/rand"
+ "crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+ "encoding/hex"
+ "testing"
+
+ _ "golang.org/x/crypto/ripemd160"
+)
+
+var saltedTests = []struct {
+ in, out string
+}{
+ {"hello", "10295ac1"},
+ {"world", "ac587a5e"},
+ {"foo", "4dda8077"},
+ {"bar", "bd8aac6b9ea9cae04eae6a91c6133b58b5d9a61c14f355516ed9370456"},
+ {"x", "f1d3f289"},
+ {"xxxxxxxxxxxxxxxxxxxxxxx", "e00d7b45"},
+}
+
+func TestSalted(t *testing.T) {
+ h := sha1.New()
+ salt := [4]byte{1, 2, 3, 4}
+
+ for i, test := range saltedTests {
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ Salted(out, h, []byte(test.in), salt[:])
+ if !bytes.Equal(expected, out) {
+ t.Errorf("#%d, got: %x want: %x", i, out, expected)
+ }
+ }
+}
+
+var iteratedTests = []struct {
+ in, out string
+}{
+ {"hello", "83126105"},
+ {"world", "6fa317f9"},
+ {"foo", "8fbc35b9"},
+ {"bar", "2af5a99b54f093789fd657f19bd245af7604d0f6ae06f66602a46a08ae"},
+ {"x", "5a684dfe"},
+ {"xxxxxxxxxxxxxxxxxxxxxxx", "18955174"},
+}
+
+func TestIterated(t *testing.T) {
+ h := sha1.New()
+ salt := [4]byte{4, 3, 2, 1}
+
+ for i, test := range iteratedTests {
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ Iterated(out, h, []byte(test.in), salt[:], 31)
+ if !bytes.Equal(expected, out) {
+ t.Errorf("#%d, got: %x want: %x", i, out, expected)
+ }
+ }
+}
+
+var parseTests = []struct {
+ spec, in, out string
+}{
+ /* Simple with SHA1 */
+ {"0002", "hello", "aaf4c61d"},
+ /* Salted with SHA1 */
+ {"01020102030405060708", "hello", "f4f7d67e"},
+ /* Iterated with SHA1 */
+ {"03020102030405060708f1", "hello", "f2a57b7c"},
+}
+
+func TestParse(t *testing.T) {
+ for i, test := range parseTests {
+ spec, _ := hex.DecodeString(test.spec)
+ buf := bytes.NewBuffer(spec)
+ f, err := Parse(buf)
+ if err != nil {
+ t.Errorf("%d: Parse returned error: %s", i, err)
+ continue
+ }
+
+ expected, _ := hex.DecodeString(test.out)
+ out := make([]byte, len(expected))
+ f(out, []byte(test.in))
+ if !bytes.Equal(out, expected) {
+ t.Errorf("%d: output got: %x want: %x", i, out, expected)
+ }
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+func TestSerialize(t *testing.T) {
+ hashes := []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.RIPEMD160,
+ crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA224}
+ testCounts := []int{-1, 0, 1024, 65536, 4063232, 65011712}
+ for _, h := range hashes {
+ for _, c := range testCounts {
+ testSerializeConfig(t, &Config{Hash: h, S2KCount: c})
+ }
+ }
+}
+
+func testSerializeConfig(t *testing.T, c *Config) {
+ t.Logf("Running testSerializeConfig() with config: %+v", c)
+
+ buf := bytes.NewBuffer(nil)
+ key := make([]byte, 16)
+ passphrase := []byte("testing")
+ err := Serialize(buf, key, rand.Reader, passphrase, c)
+ if err != nil {
+ t.Errorf("failed to serialize: %s", err)
+ return
+ }
+
+ f, err := Parse(buf)
+ if err != nil {
+ t.Errorf("failed to reparse: %s", err)
+ return
+ }
+ key2 := make([]byte, len(key))
+ f(key2, passphrase)
+ if !bytes.Equal(key2, key) {
+ t.Errorf("keys don't match: %x (serialied) vs %x (parsed)", key, key2)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/write.go b/vendor/golang.org/x/crypto/openpgp/write.go
new file mode 100644
index 000000000..15aaa1a01
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/write.go
@@ -0,0 +1,378 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "crypto"
+ "hash"
+ "io"
+ "strconv"
+ "time"
+
+ "golang.org/x/crypto/openpgp/armor"
+ "golang.org/x/crypto/openpgp/errors"
+ "golang.org/x/crypto/openpgp/packet"
+ "golang.org/x/crypto/openpgp/s2k"
+)
+
+// DetachSign signs message with the private key from signer (which must
+// already have been decrypted) and writes the signature to w.
+// If config is nil, sensible defaults will be used.
+func DetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+ return detachSign(w, signer, message, packet.SigTypeBinary, config)
+}
+
+// ArmoredDetachSign signs message with the private key from signer (which
+// must already have been decrypted) and writes an armored signature to w.
+// If config is nil, sensible defaults will be used.
+func ArmoredDetachSign(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) (err error) {
+ return armoredDetachSign(w, signer, message, packet.SigTypeBinary, config)
+}
+
+// DetachSignText signs message (after canonicalising the line endings) with
+// the private key from signer (which must already have been decrypted) and
+// writes the signature to w.
+// If config is nil, sensible defaults will be used.
+func DetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+ return detachSign(w, signer, message, packet.SigTypeText, config)
+}
+
+// ArmoredDetachSignText signs message (after canonicalising the line endings)
+// with the private key from signer (which must already have been decrypted)
+// and writes an armored signature to w.
+// If config is nil, sensible defaults will be used.
+func ArmoredDetachSignText(w io.Writer, signer *Entity, message io.Reader, config *packet.Config) error {
+ return armoredDetachSign(w, signer, message, packet.SigTypeText, config)
+}
+
+func armoredDetachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
+ out, err := armor.Encode(w, SignatureType, nil)
+ if err != nil {
+ return
+ }
+ err = detachSign(out, signer, message, sigType, config)
+ if err != nil {
+ return
+ }
+ return out.Close()
+}
+
+func detachSign(w io.Writer, signer *Entity, message io.Reader, sigType packet.SignatureType, config *packet.Config) (err error) {
+ if signer.PrivateKey == nil {
+ return errors.InvalidArgumentError("signing key doesn't have a private key")
+ }
+ if signer.PrivateKey.Encrypted {
+ return errors.InvalidArgumentError("signing key is encrypted")
+ }
+
+ sig := new(packet.Signature)
+ sig.SigType = sigType
+ sig.PubKeyAlgo = signer.PrivateKey.PubKeyAlgo
+ sig.Hash = config.Hash()
+ sig.CreationTime = config.Now()
+ sig.IssuerKeyId = &signer.PrivateKey.KeyId
+
+ h, wrappedHash, err := hashForSignature(sig.Hash, sig.SigType)
+ if err != nil {
+ return
+ }
+ io.Copy(wrappedHash, message)
+
+ err = sig.Sign(h, signer.PrivateKey, config)
+ if err != nil {
+ return
+ }
+
+ return sig.Serialize(w)
+}
+
+// FileHints contains metadata about encrypted files. This metadata is, itself,
+// encrypted.
+type FileHints struct {
+ // IsBinary can be set to hint that the contents are binary data.
+ IsBinary bool
+ // FileName hints at the name of the file that should be written. It's
+ // truncated to 255 bytes if longer. It may be empty to suggest that the
+ // file should not be written to disk. It may be equal to "_CONSOLE" to
+ // suggest the data should not be written to disk.
+ FileName string
+ // ModTime contains the modification time of the file, or the zero time if not applicable.
+ ModTime time.Time
+}
+
+// SymmetricallyEncrypt acts like gpg -c: it encrypts a file with a passphrase.
+// The resulting WriteCloser must be closed after the contents of the file have
+// been written.
+// If config is nil, sensible defaults will be used.
+func SymmetricallyEncrypt(ciphertext io.Writer, passphrase []byte, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ key, err := packet.SerializeSymmetricKeyEncrypted(ciphertext, passphrase, config)
+ if err != nil {
+ return
+ }
+ w, err := packet.SerializeSymmetricallyEncrypted(ciphertext, config.Cipher(), key, config)
+ if err != nil {
+ return
+ }
+
+ literaldata := w
+ if algo := config.Compression(); algo != packet.CompressionNone {
+ var compConfig *packet.CompressionConfig
+ if config != nil {
+ compConfig = config.CompressionConfig
+ }
+ literaldata, err = packet.SerializeCompressed(w, algo, compConfig)
+ if err != nil {
+ return
+ }
+ }
+
+ var epochSeconds uint32
+ if !hints.ModTime.IsZero() {
+ epochSeconds = uint32(hints.ModTime.Unix())
+ }
+ return packet.SerializeLiteral(literaldata, hints.IsBinary, hints.FileName, epochSeconds)
+}
+
+// intersectPreferences mutates and returns a prefix of a that contains only
+// the values in the intersection of a and b. The order of a is preserved.
+func intersectPreferences(a []uint8, b []uint8) (intersection []uint8) {
+ var j int
+ for _, v := range a {
+ for _, v2 := range b {
+ if v == v2 {
+ a[j] = v
+ j++
+ break
+ }
+ }
+ }
+
+ return a[:j]
+}
+
+func hashToHashId(h crypto.Hash) uint8 {
+ v, ok := s2k.HashToHashId(h)
+ if !ok {
+ panic("tried to convert unknown hash")
+ }
+ return v
+}
+
+// Encrypt encrypts a message to a number of recipients and, optionally, signs
+// it. hints contains optional information, that is also encrypted, that aids
+// the recipients in processing the message. The resulting WriteCloser must
+// be closed after the contents of the file have been written.
+// If config is nil, sensible defaults will be used.
+func Encrypt(ciphertext io.Writer, to []*Entity, signed *Entity, hints *FileHints, config *packet.Config) (plaintext io.WriteCloser, err error) {
+ var signer *packet.PrivateKey
+ if signed != nil {
+ signKey, ok := signed.signingKey(config.Now())
+ if !ok {
+ return nil, errors.InvalidArgumentError("no valid signing keys")
+ }
+ signer = signKey.PrivateKey
+ if signer == nil {
+ return nil, errors.InvalidArgumentError("no private key in signing key")
+ }
+ if signer.Encrypted {
+ return nil, errors.InvalidArgumentError("signing key must be decrypted")
+ }
+ }
+
+ // These are the possible ciphers that we'll use for the message.
+ candidateCiphers := []uint8{
+ uint8(packet.CipherAES128),
+ uint8(packet.CipherAES256),
+ uint8(packet.CipherCAST5),
+ }
+ // These are the possible hash functions that we'll use for the signature.
+ candidateHashes := []uint8{
+ hashToHashId(crypto.SHA256),
+ hashToHashId(crypto.SHA512),
+ hashToHashId(crypto.SHA1),
+ hashToHashId(crypto.RIPEMD160),
+ }
+ // In the event that a recipient doesn't specify any supported ciphers
+ // or hash functions, these are the ones that we assume that every
+ // implementation supports.
+ defaultCiphers := candidateCiphers[len(candidateCiphers)-1:]
+ defaultHashes := candidateHashes[len(candidateHashes)-1:]
+
+ encryptKeys := make([]Key, len(to))
+ for i := range to {
+ var ok bool
+ encryptKeys[i], ok = to[i].encryptionKey(config.Now())
+ if !ok {
+ return nil, errors.InvalidArgumentError("cannot encrypt a message to key id " + strconv.FormatUint(to[i].PrimaryKey.KeyId, 16) + " because it has no encryption keys")
+ }
+
+ sig := to[i].primaryIdentity().SelfSignature
+
+ preferredSymmetric := sig.PreferredSymmetric
+ if len(preferredSymmetric) == 0 {
+ preferredSymmetric = defaultCiphers
+ }
+ preferredHashes := sig.PreferredHash
+ if len(preferredHashes) == 0 {
+ preferredHashes = defaultHashes
+ }
+ candidateCiphers = intersectPreferences(candidateCiphers, preferredSymmetric)
+ candidateHashes = intersectPreferences(candidateHashes, preferredHashes)
+ }
+
+ if len(candidateCiphers) == 0 || len(candidateHashes) == 0 {
+ return nil, errors.InvalidArgumentError("cannot encrypt because recipient set shares no common algorithms")
+ }
+
+ cipher := packet.CipherFunction(candidateCiphers[0])
+ // If the cipher specifed by config is a candidate, we'll use that.
+ configuredCipher := config.Cipher()
+ for _, c := range candidateCiphers {
+ cipherFunc := packet.CipherFunction(c)
+ if cipherFunc == configuredCipher {
+ cipher = cipherFunc
+ break
+ }
+ }
+
+ var hash crypto.Hash
+ for _, hashId := range candidateHashes {
+ if h, ok := s2k.HashIdToHash(hashId); ok && h.Available() {
+ hash = h
+ break
+ }
+ }
+
+ // If the hash specified by config is a candidate, we'll use that.
+ if configuredHash := config.Hash(); configuredHash.Available() {
+ for _, hashId := range candidateHashes {
+ if h, ok := s2k.HashIdToHash(hashId); ok && h == configuredHash {
+ hash = h
+ break
+ }
+ }
+ }
+
+ if hash == 0 {
+ hashId := candidateHashes[0]
+ name, ok := s2k.HashIdToString(hashId)
+ if !ok {
+ name = "#" + strconv.Itoa(int(hashId))
+ }
+ return nil, errors.InvalidArgumentError("cannot encrypt because no candidate hash functions are compiled in. (Wanted " + name + " in this case.)")
+ }
+
+ symKey := make([]byte, cipher.KeySize())
+ if _, err := io.ReadFull(config.Random(), symKey); err != nil {
+ return nil, err
+ }
+
+ for _, key := range encryptKeys {
+ if err := packet.SerializeEncryptedKey(ciphertext, key.PublicKey, cipher, symKey, config); err != nil {
+ return nil, err
+ }
+ }
+
+ encryptedData, err := packet.SerializeSymmetricallyEncrypted(ciphertext, cipher, symKey, config)
+ if err != nil {
+ return
+ }
+
+ if signer != nil {
+ ops := &packet.OnePassSignature{
+ SigType: packet.SigTypeBinary,
+ Hash: hash,
+ PubKeyAlgo: signer.PubKeyAlgo,
+ KeyId: signer.KeyId,
+ IsLast: true,
+ }
+ if err := ops.Serialize(encryptedData); err != nil {
+ return nil, err
+ }
+ }
+
+ if hints == nil {
+ hints = &FileHints{}
+ }
+
+ w := encryptedData
+ if signer != nil {
+ // If we need to write a signature packet after the literal
+ // data then we need to stop literalData from closing
+ // encryptedData.
+ w = noOpCloser{encryptedData}
+
+ }
+ var epochSeconds uint32
+ if !hints.ModTime.IsZero() {
+ epochSeconds = uint32(hints.ModTime.Unix())
+ }
+ literalData, err := packet.SerializeLiteral(w, hints.IsBinary, hints.FileName, epochSeconds)
+ if err != nil {
+ return nil, err
+ }
+
+ if signer != nil {
+ return signatureWriter{encryptedData, literalData, hash, hash.New(), signer, config}, nil
+ }
+ return literalData, nil
+}
+
+// signatureWriter hashes the contents of a message while passing it along to
+// literalData. When closed, it closes literalData, writes a signature packet
+// to encryptedData and then also closes encryptedData.
+type signatureWriter struct {
+ encryptedData io.WriteCloser
+ literalData io.WriteCloser
+ hashType crypto.Hash
+ h hash.Hash
+ signer *packet.PrivateKey
+ config *packet.Config
+}
+
+func (s signatureWriter) Write(data []byte) (int, error) {
+ s.h.Write(data)
+ return s.literalData.Write(data)
+}
+
+func (s signatureWriter) Close() error {
+ sig := &packet.Signature{
+ SigType: packet.SigTypeBinary,
+ PubKeyAlgo: s.signer.PubKeyAlgo,
+ Hash: s.hashType,
+ CreationTime: s.config.Now(),
+ IssuerKeyId: &s.signer.KeyId,
+ }
+
+ if err := sig.Sign(s.h, s.signer, s.config); err != nil {
+ return err
+ }
+ if err := s.literalData.Close(); err != nil {
+ return err
+ }
+ if err := sig.Serialize(s.encryptedData); err != nil {
+ return err
+ }
+ return s.encryptedData.Close()
+}
+
+// noOpCloser is like an ioutil.NopCloser, but for an io.Writer.
+// TODO: we have two of these in OpenPGP packages alone. This probably needs
+// to be promoted somewhere more common.
+type noOpCloser struct {
+ w io.Writer
+}
+
+func (c noOpCloser) Write(data []byte) (n int, err error) {
+ return c.w.Write(data)
+}
+
+func (c noOpCloser) Close() error {
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/openpgp/write_test.go b/vendor/golang.org/x/crypto/openpgp/write_test.go
new file mode 100644
index 000000000..2161ebcd7
--- /dev/null
+++ b/vendor/golang.org/x/crypto/openpgp/write_test.go
@@ -0,0 +1,273 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package openpgp
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "testing"
+ "time"
+
+ "golang.org/x/crypto/openpgp/packet"
+)
+
+func TestSignDetached(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+ out := bytes.NewBuffer(nil)
+ message := bytes.NewBufferString(signedInput)
+ err := DetachSign(out, kring[0], message, nil)
+ if err != nil {
+ t.Error(err)
+ }
+
+ testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
+}
+
+func TestSignTextDetached(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(testKeys1And2PrivateHex))
+ out := bytes.NewBuffer(nil)
+ message := bytes.NewBufferString(signedInput)
+ err := DetachSignText(out, kring[0], message, nil)
+ if err != nil {
+ t.Error(err)
+ }
+
+ testDetachedSignature(t, kring, out, signedInput, "check", testKey1KeyId)
+}
+
+func TestSignDetachedDSA(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(dsaTestKeyPrivateHex))
+ out := bytes.NewBuffer(nil)
+ message := bytes.NewBufferString(signedInput)
+ err := DetachSign(out, kring[0], message, nil)
+ if err != nil {
+ t.Error(err)
+ }
+
+ testDetachedSignature(t, kring, out, signedInput, "check", testKey3KeyId)
+}
+
+func TestSignDetachedP256(t *testing.T) {
+ kring, _ := ReadKeyRing(readerFromHex(p256TestKeyPrivateHex))
+ kring[0].PrivateKey.Decrypt([]byte("passphrase"))
+
+ out := bytes.NewBuffer(nil)
+ message := bytes.NewBufferString(signedInput)
+ err := DetachSign(out, kring[0], message, nil)
+ if err != nil {
+ t.Error(err)
+ }
+
+ testDetachedSignature(t, kring, out, signedInput, "check", testKeyP256KeyId)
+}
+
+func TestNewEntity(t *testing.T) {
+ if testing.Short() {
+ return
+ }
+
+ // Check bit-length with no config.
+ e, err := NewEntity("Test User", "test", "test@example.com", nil)
+ if err != nil {
+ t.Errorf("failed to create entity: %s", err)
+ return
+ }
+ bl, err := e.PrimaryKey.BitLength()
+ if err != nil {
+ t.Errorf("failed to find bit length: %s", err)
+ }
+ if int(bl) != defaultRSAKeyBits {
+ t.Errorf("BitLength %v, expected %v", defaultRSAKeyBits)
+ }
+
+ // Check bit-length with a config.
+ cfg := &packet.Config{RSABits: 1024}
+ e, err = NewEntity("Test User", "test", "test@example.com", cfg)
+ if err != nil {
+ t.Errorf("failed to create entity: %s", err)
+ return
+ }
+ bl, err = e.PrimaryKey.BitLength()
+ if err != nil {
+ t.Errorf("failed to find bit length: %s", err)
+ }
+ if int(bl) != cfg.RSABits {
+ t.Errorf("BitLength %v, expected %v", bl, cfg.RSABits)
+ }
+
+ w := bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w, nil); err != nil {
+ t.Errorf("failed to serialize entity: %s", err)
+ return
+ }
+ serialized := w.Bytes()
+
+ el, err := ReadKeyRing(w)
+ if err != nil {
+ t.Errorf("failed to reparse entity: %s", err)
+ return
+ }
+
+ if len(el) != 1 {
+ t.Errorf("wrong number of entities found, got %d, want 1", len(el))
+ }
+
+ w = bytes.NewBuffer(nil)
+ if err := e.SerializePrivate(w, nil); err != nil {
+ t.Errorf("failed to serialize entity second time: %s", err)
+ return
+ }
+
+ if !bytes.Equal(w.Bytes(), serialized) {
+ t.Errorf("results differed")
+ }
+}
+
+func TestSymmetricEncryption(t *testing.T) {
+ buf := new(bytes.Buffer)
+ plaintext, err := SymmetricallyEncrypt(buf, []byte("testing"), nil, nil)
+ if err != nil {
+ t.Errorf("error writing headers: %s", err)
+ return
+ }
+ message := []byte("hello world\n")
+ _, err = plaintext.Write(message)
+ if err != nil {
+ t.Errorf("error writing to plaintext writer: %s", err)
+ }
+ err = plaintext.Close()
+ if err != nil {
+ t.Errorf("error closing plaintext writer: %s", err)
+ }
+
+ md, err := ReadMessage(buf, nil, func(keys []Key, symmetric bool) ([]byte, error) {
+ return []byte("testing"), nil
+ }, nil)
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ messageBuf := bytes.NewBuffer(nil)
+ _, err = io.Copy(messageBuf, md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("error rereading message: %s", err)
+ }
+ if !bytes.Equal(message, messageBuf.Bytes()) {
+ t.Errorf("recovered message incorrect got '%s', want '%s'", messageBuf.Bytes(), message)
+ }
+}
+
+var testEncryptionTests = []struct {
+ keyRingHex string
+ isSigned bool
+}{
+ {
+ testKeys1And2PrivateHex,
+ false,
+ },
+ {
+ testKeys1And2PrivateHex,
+ true,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ false,
+ },
+ {
+ dsaElGamalTestKeysHex,
+ true,
+ },
+}
+
+func TestEncryption(t *testing.T) {
+ for i, test := range testEncryptionTests {
+ kring, _ := ReadKeyRing(readerFromHex(test.keyRingHex))
+
+ passphrase := []byte("passphrase")
+ for _, entity := range kring {
+ if entity.PrivateKey != nil && entity.PrivateKey.Encrypted {
+ err := entity.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt key", i)
+ }
+ }
+ for _, subkey := range entity.Subkeys {
+ if subkey.PrivateKey != nil && subkey.PrivateKey.Encrypted {
+ err := subkey.PrivateKey.Decrypt(passphrase)
+ if err != nil {
+ t.Errorf("#%d: failed to decrypt subkey", i)
+ }
+ }
+ }
+ }
+
+ var signed *Entity
+ if test.isSigned {
+ signed = kring[0]
+ }
+
+ buf := new(bytes.Buffer)
+ w, err := Encrypt(buf, kring[:1], signed, nil /* no hints */, nil)
+ if err != nil {
+ t.Errorf("#%d: error in Encrypt: %s", i, err)
+ continue
+ }
+
+ const message = "testing"
+ _, err = w.Write([]byte(message))
+ if err != nil {
+ t.Errorf("#%d: error writing plaintext: %s", i, err)
+ continue
+ }
+ err = w.Close()
+ if err != nil {
+ t.Errorf("#%d: error closing WriteCloser: %s", i, err)
+ continue
+ }
+
+ md, err := ReadMessage(buf, kring, nil /* no prompt */, nil)
+ if err != nil {
+ t.Errorf("#%d: error reading message: %s", i, err)
+ continue
+ }
+
+ testTime, _ := time.Parse("2006-01-02", "2013-07-01")
+ if test.isSigned {
+ signKey, _ := kring[0].signingKey(testTime)
+ expectedKeyId := signKey.PublicKey.KeyId
+ if md.SignedByKeyId != expectedKeyId {
+ t.Errorf("#%d: message signed by wrong key id, got: %d, want: %d", i, *md.SignedBy, expectedKeyId)
+ }
+ if md.SignedBy == nil {
+ t.Errorf("#%d: failed to find the signing Entity", i)
+ }
+ }
+
+ plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
+ if err != nil {
+ t.Errorf("#%d: error reading encrypted contents: %s", i, err)
+ continue
+ }
+
+ encryptKey, _ := kring[0].encryptionKey(testTime)
+ expectedKeyId := encryptKey.PublicKey.KeyId
+ if len(md.EncryptedToKeyIds) != 1 || md.EncryptedToKeyIds[0] != expectedKeyId {
+ t.Errorf("#%d: expected message to be encrypted to %v, but got %#v", i, expectedKeyId, md.EncryptedToKeyIds)
+ }
+
+ if string(plaintext) != message {
+ t.Errorf("#%d: got: %s, want: %s", i, string(plaintext), message)
+ }
+
+ if test.isSigned {
+ if md.SignatureError != nil {
+ t.Errorf("#%d: signature error: %s", i, md.SignatureError)
+ }
+ if md.Signature == nil {
+ t.Error("signature missing")
+ }
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/otr/libotr_test_helper.c b/vendor/golang.org/x/crypto/otr/libotr_test_helper.c
new file mode 100644
index 000000000..b3ca072d4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/otr/libotr_test_helper.c
@@ -0,0 +1,197 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code can be compiled and used to test the otr package against libotr.
+// See otr_test.go.
+
+// +build ignore
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <proto.h>
+#include <message.h>
+#include <privkey.h>
+
+static int g_session_established = 0;
+
+OtrlPolicy policy(void *opdata, ConnContext *context) {
+ return OTRL_POLICY_ALWAYS;
+}
+
+int is_logged_in(void *opdata, const char *accountname, const char *protocol,
+ const char *recipient) {
+ return 1;
+}
+
+void inject_message(void *opdata, const char *accountname, const char *protocol,
+ const char *recipient, const char *message) {
+ printf("%s\n", message);
+ fflush(stdout);
+ fprintf(stderr, "libotr helper sent: %s\n", message);
+}
+
+void update_context_list(void *opdata) {}
+
+void new_fingerprint(void *opdata, OtrlUserState us, const char *accountname,
+ const char *protocol, const char *username,
+ unsigned char fingerprint[20]) {
+ fprintf(stderr, "NEW FINGERPRINT\n");
+ g_session_established = 1;
+}
+
+void write_fingerprints(void *opdata) {}
+
+void gone_secure(void *opdata, ConnContext *context) {}
+
+void gone_insecure(void *opdata, ConnContext *context) {}
+
+void still_secure(void *opdata, ConnContext *context, int is_reply) {}
+
+int max_message_size(void *opdata, ConnContext *context) { return 99999; }
+
+const char *account_name(void *opdata, const char *account,
+ const char *protocol) {
+ return "ACCOUNT";
+}
+
+void account_name_free(void *opdata, const char *account_name) {}
+
+const char *error_message(void *opdata, ConnContext *context,
+ OtrlErrorCode err_code) {
+ return "ERR";
+}
+
+void error_message_free(void *opdata, const char *msg) {}
+
+void resent_msg_prefix_free(void *opdata, const char *prefix) {}
+
+void handle_smp_event(void *opdata, OtrlSMPEvent smp_event,
+ ConnContext *context, unsigned short progress_event,
+ char *question) {}
+
+void handle_msg_event(void *opdata, OtrlMessageEvent msg_event,
+ ConnContext *context, const char *message,
+ gcry_error_t err) {
+ fprintf(stderr, "msg event: %d %s\n", msg_event, message);
+}
+
+OtrlMessageAppOps uiops = {
+ policy,
+ NULL,
+ is_logged_in,
+ inject_message,
+ update_context_list,
+ new_fingerprint,
+ write_fingerprints,
+ gone_secure,
+ gone_insecure,
+ still_secure,
+ max_message_size,
+ account_name,
+ account_name_free,
+ NULL, /* received_symkey */
+ error_message,
+ error_message_free,
+ NULL, /* resent_msg_prefix */
+ resent_msg_prefix_free,
+ handle_smp_event,
+ handle_msg_event,
+ NULL /* create_instag */,
+ NULL /* convert_msg */,
+ NULL /* convert_free */,
+ NULL /* timer_control */,
+};
+
+static const char kPrivateKeyData[] =
+ "(privkeys (account (name \"account\") (protocol proto) (private-key (dsa "
+ "(p "
+ "#00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F"
+ "30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E"
+ "5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB"
+ "8C031D3561FECEE72EBB4A090D450A9B7A857#) (q "
+ "#00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#) (g "
+ "#535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F"
+ "1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F"
+ "6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57"
+ "597766A2F9CE3857D7ACE3E1E3BC1FC6F26#) (y "
+ "#0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF"
+ "2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93"
+ "454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A"
+ "3C0FF501E3DC673B76D7BABF349009B6ECF#) (x "
+ "#14D0345A3562C480A039E3C72764F72D79043216#)))))\n";
+
+int main() {
+ OTRL_INIT;
+
+ // We have to write the private key information to a file because the libotr
+ // API demands a filename to read from.
+ const char *tmpdir = "/tmp";
+ if (getenv("TMP")) {
+ tmpdir = getenv("TMP");
+ }
+
+ char private_key_file[256];
+ snprintf(private_key_file, sizeof(private_key_file),
+ "%s/libotr_test_helper_privatekeys-XXXXXX", tmpdir);
+ int fd = mkstemp(private_key_file);
+ if (fd == -1) {
+ perror("creating temp file");
+ }
+ write(fd, kPrivateKeyData, sizeof(kPrivateKeyData) - 1);
+ close(fd);
+
+ OtrlUserState userstate = otrl_userstate_create();
+ otrl_privkey_read(userstate, private_key_file);
+ unlink(private_key_file);
+
+ fprintf(stderr, "libotr helper started\n");
+
+ char buf[4096];
+
+ for (;;) {
+ char *message = fgets(buf, sizeof(buf), stdin);
+ if (strlen(message) == 0) {
+ break;
+ }
+ message[strlen(message) - 1] = 0;
+ fprintf(stderr, "libotr helper got: %s\n", message);
+
+ char *newmessage = NULL;
+ OtrlTLV *tlvs;
+ int ignore_message = otrl_message_receiving(
+ userstate, &uiops, NULL, "account", "proto", "peer", message,
+ &newmessage, &tlvs, NULL, NULL, NULL);
+ if (tlvs) {
+ otrl_tlv_free(tlvs);
+ }
+
+ if (newmessage != NULL) {
+ fprintf(stderr, "libotr got: %s\n", newmessage);
+ otrl_message_free(newmessage);
+
+ gcry_error_t err;
+ char *newmessage = NULL;
+
+ err = otrl_message_sending(userstate, &uiops, NULL, "account", "proto",
+ "peer", 0, "test message", NULL, &newmessage,
+ OTRL_FRAGMENT_SEND_SKIP, NULL, NULL, NULL);
+ if (newmessage == NULL) {
+ fprintf(stderr, "libotr didn't encrypt message\n");
+ return 1;
+ }
+ write(1, newmessage, strlen(newmessage));
+ write(1, "\n", 1);
+ fprintf(stderr, "libotr sent: %s\n", newmessage);
+ otrl_message_free(newmessage);
+
+ g_session_established = 0;
+ write(1, "?OTRv2?\n", 8);
+ fprintf(stderr, "libotr sent: ?OTRv2\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/vendor/golang.org/x/crypto/otr/otr.go b/vendor/golang.org/x/crypto/otr/otr.go
new file mode 100644
index 000000000..549be116d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/otr/otr.go
@@ -0,0 +1,1408 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package otr implements the Off The Record protocol as specified in
+// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html
+package otr // import "golang.org/x/crypto/otr"
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/dsa"
+ "crypto/hmac"
+ "crypto/rand"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/subtle"
+ "encoding/base64"
+ "encoding/hex"
+ "errors"
+ "hash"
+ "io"
+ "math/big"
+ "strconv"
+)
+
+// SecurityChange describes a change in the security state of a Conversation.
+type SecurityChange int
+
+const (
+ NoChange SecurityChange = iota
+ // NewKeys indicates that a key exchange has completed. This occurs
+ // when a conversation first becomes encrypted, and when the keys are
+ // renegotiated within an encrypted conversation.
+ NewKeys
+ // SMPSecretNeeded indicates that the peer has started an
+ // authentication and that we need to supply a secret. Call SMPQuestion
+ // to get the optional, human readable challenge and then Authenticate
+ // to supply the matching secret.
+ SMPSecretNeeded
+ // SMPComplete indicates that an authentication completed. The identity
+ // of the peer has now been confirmed.
+ SMPComplete
+ // SMPFailed indicates that an authentication failed.
+ SMPFailed
+ // ConversationEnded indicates that the peer ended the secure
+ // conversation.
+ ConversationEnded
+)
+
+// QueryMessage can be sent to a peer to start an OTR conversation.
+var QueryMessage = "?OTRv2?"
+
+// ErrorPrefix can be used to make an OTR error by appending an error message
+// to it.
+var ErrorPrefix = "?OTR Error:"
+
+var (
+ fragmentPartSeparator = []byte(",")
+ fragmentPrefix = []byte("?OTR,")
+ msgPrefix = []byte("?OTR:")
+ queryMarker = []byte("?OTR")
+)
+
+// isQuery attempts to parse an OTR query from msg and returns the greatest
+// common version, or 0 if msg is not an OTR query.
+func isQuery(msg []byte) (greatestCommonVersion int) {
+ pos := bytes.Index(msg, queryMarker)
+ if pos == -1 {
+ return 0
+ }
+ for i, c := range msg[pos+len(queryMarker):] {
+ if i == 0 {
+ if c == '?' {
+ // Indicates support for version 1, but we don't
+ // implement that.
+ continue
+ }
+
+ if c != 'v' {
+ // Invalid message
+ return 0
+ }
+
+ continue
+ }
+
+ if c == '?' {
+ // End of message
+ return
+ }
+
+ if c == ' ' || c == '\t' {
+ // Probably an invalid message
+ return 0
+ }
+
+ if c == '2' {
+ greatestCommonVersion = 2
+ }
+ }
+
+ return 0
+}
+
+const (
+ statePlaintext = iota
+ stateEncrypted
+ stateFinished
+)
+
+const (
+ authStateNone = iota
+ authStateAwaitingDHKey
+ authStateAwaitingRevealSig
+ authStateAwaitingSig
+)
+
+const (
+ msgTypeDHCommit = 2
+ msgTypeData = 3
+ msgTypeDHKey = 10
+ msgTypeRevealSig = 17
+ msgTypeSig = 18
+)
+
+const (
+ // If the requested fragment size is less than this, it will be ignored.
+ minFragmentSize = 18
+ // Messages are padded to a multiple of this number of bytes.
+ paddingGranularity = 256
+ // The number of bytes in a Diffie-Hellman private value (320-bits).
+ dhPrivateBytes = 40
+ // The number of bytes needed to represent an element of the DSA
+ // subgroup (160-bits).
+ dsaSubgroupBytes = 20
+ // The number of bytes of the MAC that are sent on the wire (160-bits).
+ macPrefixBytes = 20
+)
+
+// These are the global, common group parameters for OTR.
+var (
+ p *big.Int // group prime
+ g *big.Int // group generator
+ q *big.Int // group order
+ pMinus2 *big.Int
+)
+
+func init() {
+ p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16)
+ q, _ = new(big.Int).SetString("7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68948127044533E63A0105DF531D89CD9128A5043CC71A026EF7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9EE1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AFC1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF", 16)
+ g = new(big.Int).SetInt64(2)
+ pMinus2 = new(big.Int).Sub(p, g)
+}
+
+// Conversation represents a relation with a peer. The zero value is a valid
+// Conversation, although PrivateKey must be set.
+//
+// When communicating with a peer, all inbound messages should be passed to
+// Conversation.Receive and all outbound messages to Conversation.Send. The
+// Conversation will take care of maintaining the encryption state and
+// negotiating encryption as needed.
+type Conversation struct {
+ // PrivateKey contains the private key to use to sign key exchanges.
+ PrivateKey *PrivateKey
+
+ // Rand can be set to override the entropy source. Otherwise,
+ // crypto/rand will be used.
+ Rand io.Reader
+ // If FragmentSize is set, all messages produced by Receive and Send
+ // will be fragmented into messages of, at most, this number of bytes.
+ FragmentSize int
+
+ // Once Receive has returned NewKeys once, the following fields are
+ // valid.
+ SSID [8]byte
+ TheirPublicKey PublicKey
+
+ state, authState int
+
+ r [16]byte
+ x, y *big.Int
+ gx, gy *big.Int
+ gxBytes []byte
+ digest [sha256.Size]byte
+
+ revealKeys, sigKeys akeKeys
+
+ myKeyId uint32
+ myCurrentDHPub *big.Int
+ myCurrentDHPriv *big.Int
+ myLastDHPub *big.Int
+ myLastDHPriv *big.Int
+
+ theirKeyId uint32
+ theirCurrentDHPub *big.Int
+ theirLastDHPub *big.Int
+
+ keySlots [4]keySlot
+
+ myCounter [8]byte
+ theirLastCtr [8]byte
+ oldMACs []byte
+
+ k, n int // fragment state
+ frag []byte
+
+ smp smpState
+}
+
+// A keySlot contains key material for a specific (their keyid, my keyid) pair.
+type keySlot struct {
+ // used is true if this slot is valid. If false, it's free for reuse.
+ used bool
+ theirKeyId uint32
+ myKeyId uint32
+ sendAESKey, recvAESKey []byte
+ sendMACKey, recvMACKey []byte
+ theirLastCtr [8]byte
+}
+
+// akeKeys are generated during key exchange. There's one set for the reveal
+// signature message and another for the signature message. In the protocol
+// spec the latter are indicated with a prime mark.
+type akeKeys struct {
+ c [16]byte
+ m1, m2 [32]byte
+}
+
+func (c *Conversation) rand() io.Reader {
+ if c.Rand != nil {
+ return c.Rand
+ }
+ return rand.Reader
+}
+
+func (c *Conversation) randMPI(buf []byte) *big.Int {
+ _, err := io.ReadFull(c.rand(), buf)
+ if err != nil {
+ panic("otr: short read from random source")
+ }
+
+ return new(big.Int).SetBytes(buf)
+}
+
+// tlv represents the type-length value from the protocol.
+type tlv struct {
+ typ, length uint16
+ data []byte
+}
+
+const (
+ tlvTypePadding = 0
+ tlvTypeDisconnected = 1
+ tlvTypeSMP1 = 2
+ tlvTypeSMP2 = 3
+ tlvTypeSMP3 = 4
+ tlvTypeSMP4 = 5
+ tlvTypeSMPAbort = 6
+ tlvTypeSMP1WithQuestion = 7
+)
+
+// Receive handles a message from a peer. It returns a human readable message,
+// an indicator of whether that message was encrypted, a hint about the
+// encryption state and zero or more messages to send back to the peer.
+// These messages do not need to be passed to Send before transmission.
+func (c *Conversation) Receive(in []byte) (out []byte, encrypted bool, change SecurityChange, toSend [][]byte, err error) {
+ if bytes.HasPrefix(in, fragmentPrefix) {
+ in, err = c.processFragment(in)
+ if in == nil || err != nil {
+ return
+ }
+ }
+
+ if bytes.HasPrefix(in, msgPrefix) && in[len(in)-1] == '.' {
+ in = in[len(msgPrefix) : len(in)-1]
+ } else if version := isQuery(in); version > 0 {
+ c.authState = authStateAwaitingDHKey
+ c.reset()
+ toSend = c.encode(c.generateDHCommit())
+ return
+ } else {
+ // plaintext message
+ out = in
+ return
+ }
+
+ msg := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ msgLen, err := base64.StdEncoding.Decode(msg, in)
+ if err != nil {
+ err = errors.New("otr: invalid base64 encoding in message")
+ return
+ }
+ msg = msg[:msgLen]
+
+ // The first two bytes are the protocol version (2)
+ if len(msg) < 3 || msg[0] != 0 || msg[1] != 2 {
+ err = errors.New("otr: invalid OTR message")
+ return
+ }
+
+ msgType := int(msg[2])
+ msg = msg[3:]
+
+ switch msgType {
+ case msgTypeDHCommit:
+ switch c.authState {
+ case authStateNone:
+ c.authState = authStateAwaitingRevealSig
+ if err = c.processDHCommit(msg); err != nil {
+ return
+ }
+ c.reset()
+ toSend = c.encode(c.generateDHKey())
+ return
+ case authStateAwaitingDHKey:
+ // This is a 'SYN-crossing'. The greater digest wins.
+ var cmp int
+ if cmp, err = c.compareToDHCommit(msg); err != nil {
+ return
+ }
+ if cmp > 0 {
+ // We win. Retransmit DH commit.
+ toSend = c.encode(c.serializeDHCommit())
+ return
+ } else {
+ // They win. We forget about our DH commit.
+ c.authState = authStateAwaitingRevealSig
+ if err = c.processDHCommit(msg); err != nil {
+ return
+ }
+ c.reset()
+ toSend = c.encode(c.generateDHKey())
+ return
+ }
+ case authStateAwaitingRevealSig:
+ if err = c.processDHCommit(msg); err != nil {
+ return
+ }
+ toSend = c.encode(c.serializeDHKey())
+ case authStateAwaitingSig:
+ if err = c.processDHCommit(msg); err != nil {
+ return
+ }
+ c.reset()
+ toSend = c.encode(c.generateDHKey())
+ c.authState = authStateAwaitingRevealSig
+ default:
+ panic("bad state")
+ }
+ case msgTypeDHKey:
+ switch c.authState {
+ case authStateAwaitingDHKey:
+ var isSame bool
+ if isSame, err = c.processDHKey(msg); err != nil {
+ return
+ }
+ if isSame {
+ err = errors.New("otr: unexpected duplicate DH key")
+ return
+ }
+ toSend = c.encode(c.generateRevealSig())
+ c.authState = authStateAwaitingSig
+ case authStateAwaitingSig:
+ var isSame bool
+ if isSame, err = c.processDHKey(msg); err != nil {
+ return
+ }
+ if isSame {
+ toSend = c.encode(c.serializeDHKey())
+ }
+ }
+ case msgTypeRevealSig:
+ if c.authState != authStateAwaitingRevealSig {
+ return
+ }
+ if err = c.processRevealSig(msg); err != nil {
+ return
+ }
+ toSend = c.encode(c.generateSig())
+ c.authState = authStateNone
+ c.state = stateEncrypted
+ change = NewKeys
+ case msgTypeSig:
+ if c.authState != authStateAwaitingSig {
+ return
+ }
+ if err = c.processSig(msg); err != nil {
+ return
+ }
+ c.authState = authStateNone
+ c.state = stateEncrypted
+ change = NewKeys
+ case msgTypeData:
+ if c.state != stateEncrypted {
+ err = errors.New("otr: encrypted message received without encrypted session established")
+ return
+ }
+ var tlvs []tlv
+ out, tlvs, err = c.processData(msg)
+ encrypted = true
+
+ EachTLV:
+ for _, inTLV := range tlvs {
+ switch inTLV.typ {
+ case tlvTypeDisconnected:
+ change = ConversationEnded
+ c.state = stateFinished
+ break EachTLV
+ case tlvTypeSMP1, tlvTypeSMP2, tlvTypeSMP3, tlvTypeSMP4, tlvTypeSMPAbort, tlvTypeSMP1WithQuestion:
+ var reply tlv
+ var complete bool
+ reply, complete, err = c.processSMP(inTLV)
+ if err == smpSecretMissingError {
+ err = nil
+ change = SMPSecretNeeded
+ c.smp.saved = &inTLV
+ return
+ }
+ if err == smpFailureError {
+ err = nil
+ change = SMPFailed
+ } else if complete {
+ change = SMPComplete
+ }
+ if reply.typ != 0 {
+ toSend = c.encode(c.generateData(nil, &reply))
+ }
+ break EachTLV
+ default:
+ // skip unknown TLVs
+ }
+ }
+ default:
+ err = errors.New("otr: unknown message type " + strconv.Itoa(msgType))
+ }
+
+ return
+}
+
+// Send takes a human readable message from the local user, possibly encrypts
+// it and returns zero one or more messages to send to the peer.
+func (c *Conversation) Send(msg []byte) ([][]byte, error) {
+ switch c.state {
+ case statePlaintext:
+ return [][]byte{msg}, nil
+ case stateEncrypted:
+ return c.encode(c.generateData(msg, nil)), nil
+ case stateFinished:
+ return nil, errors.New("otr: cannot send message because secure conversation has finished")
+ }
+
+ return nil, errors.New("otr: cannot send message in current state")
+}
+
+// SMPQuestion returns the human readable challenge question from the peer.
+// It's only valid after Receive has returned SMPSecretNeeded.
+func (c *Conversation) SMPQuestion() string {
+ return c.smp.question
+}
+
+// Authenticate begins an authentication with the peer. Authentication involves
+// an optional challenge message and a shared secret. The authentication
+// proceeds until either Receive returns SMPComplete, SMPSecretNeeded (which
+// indicates that a new authentication is happening and thus this one was
+// aborted) or SMPFailed.
+func (c *Conversation) Authenticate(question string, mutualSecret []byte) (toSend [][]byte, err error) {
+ if c.state != stateEncrypted {
+ err = errors.New("otr: can't authenticate a peer without a secure conversation established")
+ return
+ }
+
+ if c.smp.saved != nil {
+ c.calcSMPSecret(mutualSecret, false /* they started it */)
+
+ var out tlv
+ var complete bool
+ out, complete, err = c.processSMP(*c.smp.saved)
+ if complete {
+ panic("SMP completed on the first message")
+ }
+ c.smp.saved = nil
+ if out.typ != 0 {
+ toSend = c.encode(c.generateData(nil, &out))
+ }
+ return
+ }
+
+ c.calcSMPSecret(mutualSecret, true /* we started it */)
+ outs := c.startSMP(question)
+ for _, out := range outs {
+ toSend = append(toSend, c.encode(c.generateData(nil, &out))...)
+ }
+ return
+}
+
+// End ends a secure conversation by generating a termination message for
+// the peer and switches to unencrypted communication.
+func (c *Conversation) End() (toSend [][]byte) {
+ switch c.state {
+ case statePlaintext:
+ return nil
+ case stateEncrypted:
+ c.state = statePlaintext
+ return c.encode(c.generateData(nil, &tlv{typ: tlvTypeDisconnected}))
+ case stateFinished:
+ c.state = statePlaintext
+ return nil
+ }
+ panic("unreachable")
+}
+
+// IsEncrypted returns true if a message passed to Send would be encrypted
+// before transmission. This result remains valid until the next call to
+// Receive or End, which may change the state of the Conversation.
+func (c *Conversation) IsEncrypted() bool {
+ return c.state == stateEncrypted
+}
+
+var fragmentError = errors.New("otr: invalid OTR fragment")
+
+// processFragment processes a fragmented OTR message and possibly returns a
+// complete message. Fragmented messages look like "?OTR,k,n,msg," where k is
+// the fragment number (starting from 1), n is the number of fragments in this
+// message and msg is a substring of the base64 encoded message.
+func (c *Conversation) processFragment(in []byte) (out []byte, err error) {
+ in = in[len(fragmentPrefix):] // remove "?OTR,"
+ parts := bytes.Split(in, fragmentPartSeparator)
+ if len(parts) != 4 || len(parts[3]) != 0 {
+ return nil, fragmentError
+ }
+
+ k, err := strconv.Atoi(string(parts[0]))
+ if err != nil {
+ return nil, fragmentError
+ }
+
+ n, err := strconv.Atoi(string(parts[1]))
+ if err != nil {
+ return nil, fragmentError
+ }
+
+ if k < 1 || n < 1 || k > n {
+ return nil, fragmentError
+ }
+
+ if k == 1 {
+ c.frag = append(c.frag[:0], parts[2]...)
+ c.k, c.n = k, n
+ } else if n == c.n && k == c.k+1 {
+ c.frag = append(c.frag, parts[2]...)
+ c.k++
+ } else {
+ c.frag = c.frag[:0]
+ c.n, c.k = 0, 0
+ }
+
+ if c.n > 0 && c.k == c.n {
+ c.n, c.k = 0, 0
+ return c.frag, nil
+ }
+
+ return nil, nil
+}
+
+func (c *Conversation) generateDHCommit() []byte {
+ _, err := io.ReadFull(c.rand(), c.r[:])
+ if err != nil {
+ panic("otr: short read from random source")
+ }
+
+ var xBytes [dhPrivateBytes]byte
+ c.x = c.randMPI(xBytes[:])
+ c.gx = new(big.Int).Exp(g, c.x, p)
+ c.gy = nil
+ c.gxBytes = appendMPI(nil, c.gx)
+
+ h := sha256.New()
+ h.Write(c.gxBytes)
+ h.Sum(c.digest[:0])
+
+ aesCipher, err := aes.NewCipher(c.r[:])
+ if err != nil {
+ panic(err.Error())
+ }
+
+ var iv [aes.BlockSize]byte
+ ctr := cipher.NewCTR(aesCipher, iv[:])
+ ctr.XORKeyStream(c.gxBytes, c.gxBytes)
+
+ return c.serializeDHCommit()
+}
+
+func (c *Conversation) serializeDHCommit() []byte {
+ var ret []byte
+ ret = appendU16(ret, 2) // protocol version
+ ret = append(ret, msgTypeDHCommit)
+ ret = appendData(ret, c.gxBytes)
+ ret = appendData(ret, c.digest[:])
+ return ret
+}
+
+func (c *Conversation) processDHCommit(in []byte) error {
+ var ok1, ok2 bool
+ c.gxBytes, in, ok1 = getData(in)
+ digest, in, ok2 := getData(in)
+ if !ok1 || !ok2 || len(in) > 0 {
+ return errors.New("otr: corrupt DH commit message")
+ }
+ copy(c.digest[:], digest)
+ return nil
+}
+
+func (c *Conversation) compareToDHCommit(in []byte) (int, error) {
+ _, in, ok1 := getData(in)
+ digest, in, ok2 := getData(in)
+ if !ok1 || !ok2 || len(in) > 0 {
+ return 0, errors.New("otr: corrupt DH commit message")
+ }
+ return bytes.Compare(c.digest[:], digest), nil
+}
+
+func (c *Conversation) generateDHKey() []byte {
+ var yBytes [dhPrivateBytes]byte
+ c.y = c.randMPI(yBytes[:])
+ c.gy = new(big.Int).Exp(g, c.y, p)
+ return c.serializeDHKey()
+}
+
+func (c *Conversation) serializeDHKey() []byte {
+ var ret []byte
+ ret = appendU16(ret, 2) // protocol version
+ ret = append(ret, msgTypeDHKey)
+ ret = appendMPI(ret, c.gy)
+ return ret
+}
+
+func (c *Conversation) processDHKey(in []byte) (isSame bool, err error) {
+ gy, in, ok := getMPI(in)
+ if !ok {
+ err = errors.New("otr: corrupt DH key message")
+ return
+ }
+ if gy.Cmp(g) < 0 || gy.Cmp(pMinus2) > 0 {
+ err = errors.New("otr: DH value out of range")
+ return
+ }
+ if c.gy != nil {
+ isSame = c.gy.Cmp(gy) == 0
+ return
+ }
+ c.gy = gy
+ return
+}
+
+func (c *Conversation) generateEncryptedSignature(keys *akeKeys, xFirst bool) ([]byte, []byte) {
+ var xb []byte
+ xb = c.PrivateKey.PublicKey.Serialize(xb)
+
+ var verifyData []byte
+ if xFirst {
+ verifyData = appendMPI(verifyData, c.gx)
+ verifyData = appendMPI(verifyData, c.gy)
+ } else {
+ verifyData = appendMPI(verifyData, c.gy)
+ verifyData = appendMPI(verifyData, c.gx)
+ }
+ verifyData = append(verifyData, xb...)
+ verifyData = appendU32(verifyData, c.myKeyId)
+
+ mac := hmac.New(sha256.New, keys.m1[:])
+ mac.Write(verifyData)
+ mb := mac.Sum(nil)
+
+ xb = appendU32(xb, c.myKeyId)
+ xb = append(xb, c.PrivateKey.Sign(c.rand(), mb)...)
+
+ aesCipher, err := aes.NewCipher(keys.c[:])
+ if err != nil {
+ panic(err.Error())
+ }
+ var iv [aes.BlockSize]byte
+ ctr := cipher.NewCTR(aesCipher, iv[:])
+ ctr.XORKeyStream(xb, xb)
+
+ mac = hmac.New(sha256.New, keys.m2[:])
+ encryptedSig := appendData(nil, xb)
+ mac.Write(encryptedSig)
+
+ return encryptedSig, mac.Sum(nil)
+}
+
+func (c *Conversation) generateRevealSig() []byte {
+ s := new(big.Int).Exp(c.gy, c.x, p)
+ c.calcAKEKeys(s)
+ c.myKeyId++
+
+ encryptedSig, mac := c.generateEncryptedSignature(&c.revealKeys, true /* gx comes first */)
+
+ c.myCurrentDHPub = c.gx
+ c.myCurrentDHPriv = c.x
+ c.rotateDHKeys()
+ incCounter(&c.myCounter)
+
+ var ret []byte
+ ret = appendU16(ret, 2)
+ ret = append(ret, msgTypeRevealSig)
+ ret = appendData(ret, c.r[:])
+ ret = append(ret, encryptedSig...)
+ ret = append(ret, mac[:20]...)
+ return ret
+}
+
+func (c *Conversation) processEncryptedSig(encryptedSig, theirMAC []byte, keys *akeKeys, xFirst bool) error {
+ mac := hmac.New(sha256.New, keys.m2[:])
+ mac.Write(appendData(nil, encryptedSig))
+ myMAC := mac.Sum(nil)[:20]
+
+ if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
+ return errors.New("bad signature MAC in encrypted signature")
+ }
+
+ aesCipher, err := aes.NewCipher(keys.c[:])
+ if err != nil {
+ panic(err.Error())
+ }
+ var iv [aes.BlockSize]byte
+ ctr := cipher.NewCTR(aesCipher, iv[:])
+ ctr.XORKeyStream(encryptedSig, encryptedSig)
+
+ sig := encryptedSig
+ sig, ok1 := c.TheirPublicKey.Parse(sig)
+ keyId, sig, ok2 := getU32(sig)
+ if !ok1 || !ok2 {
+ return errors.New("otr: corrupt encrypted signature")
+ }
+
+ var verifyData []byte
+ if xFirst {
+ verifyData = appendMPI(verifyData, c.gx)
+ verifyData = appendMPI(verifyData, c.gy)
+ } else {
+ verifyData = appendMPI(verifyData, c.gy)
+ verifyData = appendMPI(verifyData, c.gx)
+ }
+ verifyData = c.TheirPublicKey.Serialize(verifyData)
+ verifyData = appendU32(verifyData, keyId)
+
+ mac = hmac.New(sha256.New, keys.m1[:])
+ mac.Write(verifyData)
+ mb := mac.Sum(nil)
+
+ sig, ok1 = c.TheirPublicKey.Verify(mb, sig)
+ if !ok1 {
+ return errors.New("bad signature in encrypted signature")
+ }
+ if len(sig) > 0 {
+ return errors.New("corrupt encrypted signature")
+ }
+
+ c.theirKeyId = keyId
+ zero(c.theirLastCtr[:])
+ return nil
+}
+
+func (c *Conversation) processRevealSig(in []byte) error {
+ r, in, ok1 := getData(in)
+ encryptedSig, in, ok2 := getData(in)
+ theirMAC := in
+ if !ok1 || !ok2 || len(theirMAC) != 20 {
+ return errors.New("otr: corrupt reveal signature message")
+ }
+
+ aesCipher, err := aes.NewCipher(r)
+ if err != nil {
+ return errors.New("otr: cannot create AES cipher from reveal signature message: " + err.Error())
+ }
+ var iv [aes.BlockSize]byte
+ ctr := cipher.NewCTR(aesCipher, iv[:])
+ ctr.XORKeyStream(c.gxBytes, c.gxBytes)
+ h := sha256.New()
+ h.Write(c.gxBytes)
+ digest := h.Sum(nil)
+ if len(digest) != len(c.digest) || subtle.ConstantTimeCompare(digest, c.digest[:]) == 0 {
+ return errors.New("otr: bad commit MAC in reveal signature message")
+ }
+ var rest []byte
+ c.gx, rest, ok1 = getMPI(c.gxBytes)
+ if !ok1 || len(rest) > 0 {
+ return errors.New("otr: gx corrupt after decryption")
+ }
+ if c.gx.Cmp(g) < 0 || c.gx.Cmp(pMinus2) > 0 {
+ return errors.New("otr: DH value out of range")
+ }
+ s := new(big.Int).Exp(c.gx, c.y, p)
+ c.calcAKEKeys(s)
+
+ if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.revealKeys, true /* gx comes first */); err != nil {
+ return errors.New("otr: in reveal signature message: " + err.Error())
+ }
+
+ c.theirCurrentDHPub = c.gx
+ c.theirLastDHPub = nil
+
+ return nil
+}
+
+func (c *Conversation) generateSig() []byte {
+ c.myKeyId++
+
+ encryptedSig, mac := c.generateEncryptedSignature(&c.sigKeys, false /* gy comes first */)
+
+ c.myCurrentDHPub = c.gy
+ c.myCurrentDHPriv = c.y
+ c.rotateDHKeys()
+ incCounter(&c.myCounter)
+
+ var ret []byte
+ ret = appendU16(ret, 2)
+ ret = append(ret, msgTypeSig)
+ ret = append(ret, encryptedSig...)
+ ret = append(ret, mac[:macPrefixBytes]...)
+ return ret
+}
+
+func (c *Conversation) processSig(in []byte) error {
+ encryptedSig, in, ok1 := getData(in)
+ theirMAC := in
+ if !ok1 || len(theirMAC) != macPrefixBytes {
+ return errors.New("otr: corrupt signature message")
+ }
+
+ if err := c.processEncryptedSig(encryptedSig, theirMAC, &c.sigKeys, false /* gy comes first */); err != nil {
+ return errors.New("otr: in signature message: " + err.Error())
+ }
+
+ c.theirCurrentDHPub = c.gy
+ c.theirLastDHPub = nil
+
+ return nil
+}
+
+func (c *Conversation) rotateDHKeys() {
+ // evict slots using our retired key id
+ for i := range c.keySlots {
+ slot := &c.keySlots[i]
+ if slot.used && slot.myKeyId == c.myKeyId-1 {
+ slot.used = false
+ c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
+ }
+ }
+
+ c.myLastDHPriv = c.myCurrentDHPriv
+ c.myLastDHPub = c.myCurrentDHPub
+
+ var xBytes [dhPrivateBytes]byte
+ c.myCurrentDHPriv = c.randMPI(xBytes[:])
+ c.myCurrentDHPub = new(big.Int).Exp(g, c.myCurrentDHPriv, p)
+ c.myKeyId++
+}
+
+func (c *Conversation) processData(in []byte) (out []byte, tlvs []tlv, err error) {
+ origIn := in
+ flags, in, ok1 := getU8(in)
+ theirKeyId, in, ok2 := getU32(in)
+ myKeyId, in, ok3 := getU32(in)
+ y, in, ok4 := getMPI(in)
+ counter, in, ok5 := getNBytes(in, 8)
+ encrypted, in, ok6 := getData(in)
+ macedData := origIn[:len(origIn)-len(in)]
+ theirMAC, in, ok7 := getNBytes(in, macPrefixBytes)
+ _, in, ok8 := getData(in)
+ if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 || !ok6 || !ok7 || !ok8 || len(in) > 0 {
+ err = errors.New("otr: corrupt data message")
+ return
+ }
+
+ ignoreErrors := flags&1 != 0
+
+ slot, err := c.calcDataKeys(myKeyId, theirKeyId)
+ if err != nil {
+ if ignoreErrors {
+ err = nil
+ }
+ return
+ }
+
+ mac := hmac.New(sha1.New, slot.recvMACKey)
+ mac.Write([]byte{0, 2, 3})
+ mac.Write(macedData)
+ myMAC := mac.Sum(nil)
+ if len(myMAC) != len(theirMAC) || subtle.ConstantTimeCompare(myMAC, theirMAC) == 0 {
+ if !ignoreErrors {
+ err = errors.New("otr: bad MAC on data message")
+ }
+ return
+ }
+
+ if bytes.Compare(counter, slot.theirLastCtr[:]) <= 0 {
+ err = errors.New("otr: counter regressed")
+ return
+ }
+ copy(slot.theirLastCtr[:], counter)
+
+ var iv [aes.BlockSize]byte
+ copy(iv[:], counter)
+ aesCipher, err := aes.NewCipher(slot.recvAESKey)
+ if err != nil {
+ panic(err.Error())
+ }
+ ctr := cipher.NewCTR(aesCipher, iv[:])
+ ctr.XORKeyStream(encrypted, encrypted)
+ decrypted := encrypted
+
+ if myKeyId == c.myKeyId {
+ c.rotateDHKeys()
+ }
+ if theirKeyId == c.theirKeyId {
+ // evict slots using their retired key id
+ for i := range c.keySlots {
+ slot := &c.keySlots[i]
+ if slot.used && slot.theirKeyId == theirKeyId-1 {
+ slot.used = false
+ c.oldMACs = append(c.oldMACs, slot.recvMACKey...)
+ }
+ }
+
+ c.theirLastDHPub = c.theirCurrentDHPub
+ c.theirKeyId++
+ c.theirCurrentDHPub = y
+ }
+
+ if nulPos := bytes.IndexByte(decrypted, 0); nulPos >= 0 {
+ out = decrypted[:nulPos]
+ tlvData := decrypted[nulPos+1:]
+ for len(tlvData) > 0 {
+ var t tlv
+ var ok1, ok2, ok3 bool
+
+ t.typ, tlvData, ok1 = getU16(tlvData)
+ t.length, tlvData, ok2 = getU16(tlvData)
+ t.data, tlvData, ok3 = getNBytes(tlvData, int(t.length))
+ if !ok1 || !ok2 || !ok3 {
+ err = errors.New("otr: corrupt tlv data")
+ }
+ tlvs = append(tlvs, t)
+ }
+ } else {
+ out = decrypted
+ }
+
+ return
+}
+
+func (c *Conversation) generateData(msg []byte, extra *tlv) []byte {
+ slot, err := c.calcDataKeys(c.myKeyId-1, c.theirKeyId)
+ if err != nil {
+ panic("otr: failed to generate sending keys: " + err.Error())
+ }
+
+ var plaintext []byte
+ plaintext = append(plaintext, msg...)
+ plaintext = append(plaintext, 0)
+
+ padding := paddingGranularity - ((len(plaintext) + 4) % paddingGranularity)
+ plaintext = appendU16(plaintext, tlvTypePadding)
+ plaintext = appendU16(plaintext, uint16(padding))
+ for i := 0; i < padding; i++ {
+ plaintext = append(plaintext, 0)
+ }
+
+ if extra != nil {
+ plaintext = appendU16(plaintext, extra.typ)
+ plaintext = appendU16(plaintext, uint16(len(extra.data)))
+ plaintext = append(plaintext, extra.data...)
+ }
+
+ encrypted := make([]byte, len(plaintext))
+
+ var iv [aes.BlockSize]byte
+ copy(iv[:], c.myCounter[:])
+ aesCipher, err := aes.NewCipher(slot.sendAESKey)
+ if err != nil {
+ panic(err.Error())
+ }
+ ctr := cipher.NewCTR(aesCipher, iv[:])
+ ctr.XORKeyStream(encrypted, plaintext)
+
+ var ret []byte
+ ret = appendU16(ret, 2)
+ ret = append(ret, msgTypeData)
+ ret = append(ret, 0 /* flags */)
+ ret = appendU32(ret, c.myKeyId-1)
+ ret = appendU32(ret, c.theirKeyId)
+ ret = appendMPI(ret, c.myCurrentDHPub)
+ ret = append(ret, c.myCounter[:]...)
+ ret = appendData(ret, encrypted)
+
+ mac := hmac.New(sha1.New, slot.sendMACKey)
+ mac.Write(ret)
+ ret = append(ret, mac.Sum(nil)[:macPrefixBytes]...)
+ ret = appendData(ret, c.oldMACs)
+ c.oldMACs = nil
+ incCounter(&c.myCounter)
+
+ return ret
+}
+
+func incCounter(counter *[8]byte) {
+ for i := 7; i >= 0; i-- {
+ counter[i]++
+ if counter[i] > 0 {
+ break
+ }
+ }
+}
+
+// calcDataKeys computes the keys used to encrypt a data message given the key
+// IDs.
+func (c *Conversation) calcDataKeys(myKeyId, theirKeyId uint32) (slot *keySlot, err error) {
+ // Check for a cache hit.
+ for i := range c.keySlots {
+ slot = &c.keySlots[i]
+ if slot.used && slot.theirKeyId == theirKeyId && slot.myKeyId == myKeyId {
+ return
+ }
+ }
+
+ // Find an empty slot to write into.
+ slot = nil
+ for i := range c.keySlots {
+ if !c.keySlots[i].used {
+ slot = &c.keySlots[i]
+ break
+ }
+ }
+ if slot == nil {
+ return nil, errors.New("otr: internal error: no more key slots")
+ }
+
+ var myPriv, myPub, theirPub *big.Int
+
+ if myKeyId == c.myKeyId {
+ myPriv = c.myCurrentDHPriv
+ myPub = c.myCurrentDHPub
+ } else if myKeyId == c.myKeyId-1 {
+ myPriv = c.myLastDHPriv
+ myPub = c.myLastDHPub
+ } else {
+ err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when I'm on " + strconv.FormatUint(uint64(c.myKeyId), 10))
+ return
+ }
+
+ if theirKeyId == c.theirKeyId {
+ theirPub = c.theirCurrentDHPub
+ } else if theirKeyId == c.theirKeyId-1 && c.theirLastDHPub != nil {
+ theirPub = c.theirLastDHPub
+ } else {
+ err = errors.New("otr: peer requested keyid " + strconv.FormatUint(uint64(myKeyId), 10) + " when they're on " + strconv.FormatUint(uint64(c.myKeyId), 10))
+ return
+ }
+
+ var sendPrefixByte, recvPrefixByte [1]byte
+
+ if myPub.Cmp(theirPub) > 0 {
+ // we're the high end
+ sendPrefixByte[0], recvPrefixByte[0] = 1, 2
+ } else {
+ // we're the low end
+ sendPrefixByte[0], recvPrefixByte[0] = 2, 1
+ }
+
+ s := new(big.Int).Exp(theirPub, myPriv, p)
+ sBytes := appendMPI(nil, s)
+
+ h := sha1.New()
+ h.Write(sendPrefixByte[:])
+ h.Write(sBytes)
+ slot.sendAESKey = h.Sum(slot.sendAESKey[:0])[:16]
+
+ h.Reset()
+ h.Write(slot.sendAESKey)
+ slot.sendMACKey = h.Sum(slot.sendMACKey[:0])
+
+ h.Reset()
+ h.Write(recvPrefixByte[:])
+ h.Write(sBytes)
+ slot.recvAESKey = h.Sum(slot.recvAESKey[:0])[:16]
+
+ h.Reset()
+ h.Write(slot.recvAESKey)
+ slot.recvMACKey = h.Sum(slot.recvMACKey[:0])
+
+ slot.theirKeyId = theirKeyId
+ slot.myKeyId = myKeyId
+ slot.used = true
+
+ zero(slot.theirLastCtr[:])
+ return
+}
+
+func (c *Conversation) calcAKEKeys(s *big.Int) {
+ mpi := appendMPI(nil, s)
+ h := sha256.New()
+
+ var cBytes [32]byte
+ hashWithPrefix(c.SSID[:], 0, mpi, h)
+
+ hashWithPrefix(cBytes[:], 1, mpi, h)
+ copy(c.revealKeys.c[:], cBytes[:16])
+ copy(c.sigKeys.c[:], cBytes[16:])
+
+ hashWithPrefix(c.revealKeys.m1[:], 2, mpi, h)
+ hashWithPrefix(c.revealKeys.m2[:], 3, mpi, h)
+ hashWithPrefix(c.sigKeys.m1[:], 4, mpi, h)
+ hashWithPrefix(c.sigKeys.m2[:], 5, mpi, h)
+}
+
+func hashWithPrefix(out []byte, prefix byte, in []byte, h hash.Hash) {
+ h.Reset()
+ var p [1]byte
+ p[0] = prefix
+ h.Write(p[:])
+ h.Write(in)
+ if len(out) == h.Size() {
+ h.Sum(out[:0])
+ } else {
+ digest := h.Sum(nil)
+ copy(out, digest)
+ }
+}
+
+func (c *Conversation) encode(msg []byte) [][]byte {
+ b64 := make([]byte, base64.StdEncoding.EncodedLen(len(msg))+len(msgPrefix)+1)
+ base64.StdEncoding.Encode(b64[len(msgPrefix):], msg)
+ copy(b64, msgPrefix)
+ b64[len(b64)-1] = '.'
+
+ if c.FragmentSize < minFragmentSize || len(b64) <= c.FragmentSize {
+ // We can encode this in a single fragment.
+ return [][]byte{b64}
+ }
+
+ // We have to fragment this message.
+ var ret [][]byte
+ bytesPerFragment := c.FragmentSize - minFragmentSize
+ numFragments := (len(b64) + bytesPerFragment) / bytesPerFragment
+
+ for i := 0; i < numFragments; i++ {
+ frag := []byte("?OTR," + strconv.Itoa(i+1) + "," + strconv.Itoa(numFragments) + ",")
+ todo := bytesPerFragment
+ if todo > len(b64) {
+ todo = len(b64)
+ }
+ frag = append(frag, b64[:todo]...)
+ b64 = b64[todo:]
+ frag = append(frag, ',')
+ ret = append(ret, frag)
+ }
+
+ return ret
+}
+
+func (c *Conversation) reset() {
+ c.myKeyId = 0
+
+ for i := range c.keySlots {
+ c.keySlots[i].used = false
+ }
+}
+
+type PublicKey struct {
+ dsa.PublicKey
+}
+
+func (pk *PublicKey) Parse(in []byte) ([]byte, bool) {
+ var ok bool
+ var pubKeyType uint16
+
+ if pubKeyType, in, ok = getU16(in); !ok || pubKeyType != 0 {
+ return nil, false
+ }
+ if pk.P, in, ok = getMPI(in); !ok {
+ return nil, false
+ }
+ if pk.Q, in, ok = getMPI(in); !ok {
+ return nil, false
+ }
+ if pk.G, in, ok = getMPI(in); !ok {
+ return nil, false
+ }
+ if pk.Y, in, ok = getMPI(in); !ok {
+ return nil, false
+ }
+
+ return in, true
+}
+
+func (pk *PublicKey) Serialize(in []byte) []byte {
+ in = appendU16(in, 0)
+ in = appendMPI(in, pk.P)
+ in = appendMPI(in, pk.Q)
+ in = appendMPI(in, pk.G)
+ in = appendMPI(in, pk.Y)
+ return in
+}
+
+// Fingerprint returns the 20-byte, binary fingerprint of the PublicKey.
+func (pk *PublicKey) Fingerprint() []byte {
+ b := pk.Serialize(nil)
+ h := sha1.New()
+ h.Write(b[2:])
+ return h.Sum(nil)
+}
+
+func (pk *PublicKey) Verify(hashed, sig []byte) ([]byte, bool) {
+ if len(sig) != 2*dsaSubgroupBytes {
+ return nil, false
+ }
+ r := new(big.Int).SetBytes(sig[:dsaSubgroupBytes])
+ s := new(big.Int).SetBytes(sig[dsaSubgroupBytes:])
+ ok := dsa.Verify(&pk.PublicKey, hashed, r, s)
+ return sig[dsaSubgroupBytes*2:], ok
+}
+
+type PrivateKey struct {
+ PublicKey
+ dsa.PrivateKey
+}
+
+func (priv *PrivateKey) Sign(rand io.Reader, hashed []byte) []byte {
+ r, s, err := dsa.Sign(rand, &priv.PrivateKey, hashed)
+ if err != nil {
+ panic(err.Error())
+ }
+ rBytes := r.Bytes()
+ sBytes := s.Bytes()
+ if len(rBytes) > dsaSubgroupBytes || len(sBytes) > dsaSubgroupBytes {
+ panic("DSA signature too large")
+ }
+
+ out := make([]byte, 2*dsaSubgroupBytes)
+ copy(out[dsaSubgroupBytes-len(rBytes):], rBytes)
+ copy(out[len(out)-len(sBytes):], sBytes)
+ return out
+}
+
+func (priv *PrivateKey) Serialize(in []byte) []byte {
+ in = priv.PublicKey.Serialize(in)
+ in = appendMPI(in, priv.PrivateKey.X)
+ return in
+}
+
+func (priv *PrivateKey) Parse(in []byte) ([]byte, bool) {
+ in, ok := priv.PublicKey.Parse(in)
+ if !ok {
+ return in, ok
+ }
+ priv.PrivateKey.PublicKey = priv.PublicKey.PublicKey
+ priv.PrivateKey.X, in, ok = getMPI(in)
+ return in, ok
+}
+
+func (priv *PrivateKey) Generate(rand io.Reader) {
+ if err := dsa.GenerateParameters(&priv.PrivateKey.PublicKey.Parameters, rand, dsa.L1024N160); err != nil {
+ panic(err.Error())
+ }
+ if err := dsa.GenerateKey(&priv.PrivateKey, rand); err != nil {
+ panic(err.Error())
+ }
+ priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
+}
+
+func notHex(r rune) bool {
+ if r >= '0' && r <= '9' ||
+ r >= 'a' && r <= 'f' ||
+ r >= 'A' && r <= 'F' {
+ return false
+ }
+
+ return true
+}
+
+// Import parses the contents of a libotr private key file.
+func (priv *PrivateKey) Import(in []byte) bool {
+ mpiStart := []byte(" #")
+
+ mpis := make([]*big.Int, 5)
+
+ for i := 0; i < len(mpis); i++ {
+ start := bytes.Index(in, mpiStart)
+ if start == -1 {
+ return false
+ }
+ in = in[start+len(mpiStart):]
+ end := bytes.IndexFunc(in, notHex)
+ if end == -1 {
+ return false
+ }
+ hexBytes := in[:end]
+ in = in[end:]
+
+ if len(hexBytes)&1 != 0 {
+ return false
+ }
+
+ mpiBytes := make([]byte, len(hexBytes)/2)
+ if _, err := hex.Decode(mpiBytes, hexBytes); err != nil {
+ return false
+ }
+
+ mpis[i] = new(big.Int).SetBytes(mpiBytes)
+ }
+
+ priv.PrivateKey.P = mpis[0]
+ priv.PrivateKey.Q = mpis[1]
+ priv.PrivateKey.G = mpis[2]
+ priv.PrivateKey.Y = mpis[3]
+ priv.PrivateKey.X = mpis[4]
+ priv.PublicKey.PublicKey = priv.PrivateKey.PublicKey
+
+ a := new(big.Int).Exp(priv.PrivateKey.G, priv.PrivateKey.X, priv.PrivateKey.P)
+ return a.Cmp(priv.PrivateKey.Y) == 0
+}
+
+func getU8(in []byte) (uint8, []byte, bool) {
+ if len(in) < 1 {
+ return 0, in, false
+ }
+ return in[0], in[1:], true
+}
+
+func getU16(in []byte) (uint16, []byte, bool) {
+ if len(in) < 2 {
+ return 0, in, false
+ }
+ r := uint16(in[0])<<8 | uint16(in[1])
+ return r, in[2:], true
+}
+
+func getU32(in []byte) (uint32, []byte, bool) {
+ if len(in) < 4 {
+ return 0, in, false
+ }
+ r := uint32(in[0])<<24 | uint32(in[1])<<16 | uint32(in[2])<<8 | uint32(in[3])
+ return r, in[4:], true
+}
+
+func getMPI(in []byte) (*big.Int, []byte, bool) {
+ l, in, ok := getU32(in)
+ if !ok || uint32(len(in)) < l {
+ return nil, in, false
+ }
+ r := new(big.Int).SetBytes(in[:l])
+ return r, in[l:], true
+}
+
+func getData(in []byte) ([]byte, []byte, bool) {
+ l, in, ok := getU32(in)
+ if !ok || uint32(len(in)) < l {
+ return nil, in, false
+ }
+ return in[:l], in[l:], true
+}
+
+func getNBytes(in []byte, n int) ([]byte, []byte, bool) {
+ if len(in) < n {
+ return nil, in, false
+ }
+ return in[:n], in[n:], true
+}
+
+func appendU16(out []byte, v uint16) []byte {
+ out = append(out, byte(v>>8), byte(v))
+ return out
+}
+
+func appendU32(out []byte, v uint32) []byte {
+ out = append(out, byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
+ return out
+}
+
+func appendData(out, v []byte) []byte {
+ out = appendU32(out, uint32(len(v)))
+ out = append(out, v...)
+ return out
+}
+
+func appendMPI(out []byte, v *big.Int) []byte {
+ vBytes := v.Bytes()
+ out = appendU32(out, uint32(len(vBytes)))
+ out = append(out, vBytes...)
+ return out
+}
+
+func appendMPIs(out []byte, mpis ...*big.Int) []byte {
+ for _, mpi := range mpis {
+ out = appendMPI(out, mpi)
+ }
+ return out
+}
+
+func zero(b []byte) {
+ for i := range b {
+ b[i] = 0
+ }
+}
diff --git a/vendor/golang.org/x/crypto/otr/otr_test.go b/vendor/golang.org/x/crypto/otr/otr_test.go
new file mode 100644
index 000000000..cfcd062b2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/otr/otr_test.go
@@ -0,0 +1,470 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package otr
+
+import (
+ "bufio"
+ "bytes"
+ "crypto/rand"
+ "encoding/hex"
+ "math/big"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+var isQueryTests = []struct {
+ msg string
+ expectedVersion int
+}{
+ {"foo", 0},
+ {"?OtR", 0},
+ {"?OtR?", 0},
+ {"?OTR?", 0},
+ {"?OTRv?", 0},
+ {"?OTRv1?", 0},
+ {"?OTR?v1?", 0},
+ {"?OTR?v?", 0},
+ {"?OTR?v2?", 2},
+ {"?OTRv2?", 2},
+ {"?OTRv23?", 2},
+ {"?OTRv23 ?", 0},
+}
+
+func TestIsQuery(t *testing.T) {
+ for i, test := range isQueryTests {
+ version := isQuery([]byte(test.msg))
+ if version != test.expectedVersion {
+ t.Errorf("#%d: got %d, want %d", i, version, test.expectedVersion)
+ }
+ }
+}
+
+var alicePrivateKeyHex = "000000000080c81c2cb2eb729b7e6fd48e975a932c638b3a9055478583afa46755683e30102447f6da2d8bec9f386bbb5da6403b0040fee8650b6ab2d7f32c55ab017ae9b6aec8c324ab5844784e9a80e194830d548fb7f09a0410df2c4d5c8bc2b3e9ad484e65412be689cf0834694e0839fb2954021521ffdffb8f5c32c14dbf2020b3ce7500000014da4591d58def96de61aea7b04a8405fe1609308d000000808ddd5cb0b9d66956e3dea5a915d9aba9d8a6e7053b74dadb2fc52f9fe4e5bcc487d2305485ed95fed026ad93f06ebb8c9e8baf693b7887132c7ffdd3b0f72f4002ff4ed56583ca7c54458f8c068ca3e8a4dfa309d1dd5d34e2a4b68e6f4338835e5e0fb4317c9e4c7e4806dafda3ef459cd563775a586dd91b1319f72621bf3f00000080b8147e74d8c45e6318c37731b8b33b984a795b3653c2cd1d65cc99efe097cb7eb2fa49569bab5aab6e8a1c261a27d0f7840a5e80b317e6683042b59b6dceca2879c6ffc877a465be690c15e4a42f9a7588e79b10faac11b1ce3741fcef7aba8ce05327a2c16d279ee1b3d77eb783fb10e3356caa25635331e26dd42b8396c4d00000001420bec691fea37ecea58a5c717142f0b804452f57"
+
+var aliceFingerprintHex = "0bb01c360424522e94ee9c346ce877a1a4288b2f"
+
+var bobPrivateKeyHex = "000000000080a5138eb3d3eb9c1d85716faecadb718f87d31aaed1157671d7fee7e488f95e8e0ba60ad449ec732710a7dec5190f7182af2e2f98312d98497221dff160fd68033dd4f3a33b7c078d0d9f66e26847e76ca7447d4bab35486045090572863d9e4454777f24d6706f63e02548dfec2d0a620af37bbc1d24f884708a212c343b480d00000014e9c58f0ea21a5e4dfd9f44b6a9f7f6a9961a8fa9000000803c4d111aebd62d3c50c2889d420a32cdf1e98b70affcc1fcf44d59cca2eb019f6b774ef88153fb9b9615441a5fe25ea2d11b74ce922ca0232bd81b3c0fcac2a95b20cb6e6c0c5c1ace2e26f65dc43c751af0edbb10d669890e8ab6beea91410b8b2187af1a8347627a06ecea7e0f772c28aae9461301e83884860c9b656c722f0000008065af8625a555ea0e008cd04743671a3cda21162e83af045725db2eb2bb52712708dc0cc1a84c08b3649b88a966974bde27d8612c2861792ec9f08786a246fcadd6d8d3a81a32287745f309238f47618c2bd7612cb8b02d940571e0f30b96420bcd462ff542901b46109b1e5ad6423744448d20a57818a8cbb1647d0fea3b664e0000001440f9f2eb554cb00d45a5826b54bfa419b6980e48"
+
+func TestKeySerialization(t *testing.T) {
+ var priv PrivateKey
+ alicePrivateKey, _ := hex.DecodeString(alicePrivateKeyHex)
+ rest, ok := priv.Parse(alicePrivateKey)
+ if !ok {
+ t.Error("failed to parse private key")
+ }
+ if len(rest) > 0 {
+ t.Error("data remaining after parsing private key")
+ }
+
+ out := priv.Serialize(nil)
+ if !bytes.Equal(alicePrivateKey, out) {
+ t.Errorf("serialization (%x) is not equal to original (%x)", out, alicePrivateKey)
+ }
+
+ aliceFingerprint, _ := hex.DecodeString(aliceFingerprintHex)
+ fingerprint := priv.PublicKey.Fingerprint()
+ if !bytes.Equal(aliceFingerprint, fingerprint) {
+ t.Errorf("fingerprint (%x) is not equal to expected value (%x)", fingerprint, aliceFingerprint)
+ }
+}
+
+const libOTRPrivateKey = `(privkeys
+ (account
+(name "foo@example.com")
+(protocol prpl-jabber)
+(private-key
+ (dsa
+ (p #00FC07ABCF0DC916AFF6E9AE47BEF60C7AB9B4D6B2469E436630E36F8A489BE812486A09F30B71224508654940A835301ACC525A4FF133FC152CC53DCC59D65C30A54F1993FE13FE63E5823D4C746DB21B90F9B9C00B49EC7404AB1D929BA7FBA12F2E45C6E0A651689750E8528AB8C031D3561FECEE72EBB4A090D450A9B7A857#)
+ (q #00997BD266EF7B1F60A5C23F3A741F2AEFD07A2081#)
+ (g #535E360E8A95EBA46A4F7DE50AD6E9B2A6DB785A66B64EB9F20338D2A3E8FB0E94725848F1AA6CC567CB83A1CC517EC806F2E92EAE71457E80B2210A189B91250779434B41FC8A8873F6DB94BEA7D177F5D59E7E114EE10A49CFD9CEF88AE43387023B672927BA74B04EB6BBB5E57597766A2F9CE3857D7ACE3E1E3BC1FC6F26#)
+ (y #0AC8670AD767D7A8D9D14CC1AC6744CD7D76F993B77FFD9E39DF01E5A6536EF65E775FCEF2A983E2A19BD6415500F6979715D9FD1257E1FE2B6F5E1E74B333079E7C880D39868462A93454B41877BE62E5EF0A041C2EE9C9E76BD1E12AE25D9628DECB097025DD625EF49C3258A1A3C0FF501E3DC673B76D7BABF349009B6ECF#)
+ (x #14D0345A3562C480A039E3C72764F72D79043216#)
+ )
+ )
+ )
+)`
+
+func TestParseLibOTRPrivateKey(t *testing.T) {
+ var priv PrivateKey
+
+ if !priv.Import([]byte(libOTRPrivateKey)) {
+ t.Fatalf("Failed to import sample private key")
+ }
+}
+
+func TestSignVerify(t *testing.T) {
+ var priv PrivateKey
+ alicePrivateKey, _ := hex.DecodeString(alicePrivateKeyHex)
+ _, ok := priv.Parse(alicePrivateKey)
+ if !ok {
+ t.Error("failed to parse private key")
+ }
+
+ var msg [32]byte
+ rand.Reader.Read(msg[:])
+
+ sig := priv.Sign(rand.Reader, msg[:])
+ rest, ok := priv.PublicKey.Verify(msg[:], sig)
+ if !ok {
+ t.Errorf("signature (%x) of %x failed to verify", sig, msg[:])
+ } else if len(rest) > 0 {
+ t.Error("signature data remains after verification")
+ }
+
+ sig[10] ^= 80
+ _, ok = priv.PublicKey.Verify(msg[:], sig)
+ if ok {
+ t.Errorf("corrupted signature (%x) of %x verified", sig, msg[:])
+ }
+}
+
+func setupConversation(t *testing.T) (alice, bob *Conversation) {
+ alicePrivateKey, _ := hex.DecodeString(alicePrivateKeyHex)
+ bobPrivateKey, _ := hex.DecodeString(bobPrivateKeyHex)
+
+ alice, bob = new(Conversation), new(Conversation)
+
+ alice.PrivateKey = new(PrivateKey)
+ bob.PrivateKey = new(PrivateKey)
+ alice.PrivateKey.Parse(alicePrivateKey)
+ bob.PrivateKey.Parse(bobPrivateKey)
+ alice.FragmentSize = 100
+ bob.FragmentSize = 100
+
+ if alice.IsEncrypted() {
+ t.Error("Alice believes that the conversation is secure before we've started")
+ }
+ if bob.IsEncrypted() {
+ t.Error("Bob believes that the conversation is secure before we've started")
+ }
+
+ performHandshake(t, alice, bob)
+ return alice, bob
+}
+
+func performHandshake(t *testing.T, alice, bob *Conversation) {
+ var alicesMessage, bobsMessage [][]byte
+ var out []byte
+ var aliceChange, bobChange SecurityChange
+ var err error
+ alicesMessage = append(alicesMessage, []byte(QueryMessage))
+
+ for round := 0; len(alicesMessage) > 0 || len(bobsMessage) > 0; round++ {
+ bobsMessage = nil
+ for i, msg := range alicesMessage {
+ out, _, bobChange, bobsMessage, err = bob.Receive(msg)
+ if len(out) > 0 {
+ t.Errorf("Bob generated output during key exchange, round %d, message %d", round, i)
+ }
+ if err != nil {
+ t.Fatalf("Bob returned an error, round %d, message %d (%x): %s", round, i, msg, err)
+ }
+ if len(bobsMessage) > 0 && i != len(alicesMessage)-1 {
+ t.Errorf("Bob produced output while processing a fragment, round %d, message %d", round, i)
+ }
+ }
+
+ alicesMessage = nil
+ for i, msg := range bobsMessage {
+ out, _, aliceChange, alicesMessage, err = alice.Receive(msg)
+ if len(out) > 0 {
+ t.Errorf("Alice generated output during key exchange, round %d, message %d", round, i)
+ }
+ if err != nil {
+ t.Fatalf("Alice returned an error, round %d, message %d (%x): %s", round, i, msg, err)
+ }
+ if len(alicesMessage) > 0 && i != len(bobsMessage)-1 {
+ t.Errorf("Alice produced output while processing a fragment, round %d, message %d", round, i)
+ }
+ }
+ }
+
+ if aliceChange != NewKeys {
+ t.Errorf("Alice terminated without signaling new keys")
+ }
+ if bobChange != NewKeys {
+ t.Errorf("Bob terminated without signaling new keys")
+ }
+
+ if !bytes.Equal(alice.SSID[:], bob.SSID[:]) {
+ t.Errorf("Session identifiers don't match. Alice has %x, Bob has %x", alice.SSID[:], bob.SSID[:])
+ }
+
+ if !alice.IsEncrypted() {
+ t.Error("Alice doesn't believe that the conversation is secure")
+ }
+ if !bob.IsEncrypted() {
+ t.Error("Bob doesn't believe that the conversation is secure")
+ }
+}
+
+const (
+ firstRoundTrip = iota
+ subsequentRoundTrip
+ noMACKeyCheck
+)
+
+func roundTrip(t *testing.T, alice, bob *Conversation, message []byte, macKeyCheck int) {
+ alicesMessage, err := alice.Send(message)
+ if err != nil {
+ t.Errorf("Error from Alice sending message: %s", err)
+ }
+
+ if len(alice.oldMACs) != 0 {
+ t.Errorf("Alice has not revealed all MAC keys")
+ }
+
+ for i, msg := range alicesMessage {
+ out, encrypted, _, _, err := bob.Receive(msg)
+
+ if err != nil {
+ t.Errorf("Error generated while processing test message: %s", err.Error())
+ }
+ if len(out) > 0 {
+ if i != len(alicesMessage)-1 {
+ t.Fatal("Bob produced a message while processing a fragment of Alice's")
+ }
+ if !encrypted {
+ t.Errorf("Message was not marked as encrypted")
+ }
+ if !bytes.Equal(out, message) {
+ t.Errorf("Message corrupted: got %x, want %x", out, message)
+ }
+ }
+ }
+
+ switch macKeyCheck {
+ case firstRoundTrip:
+ if len(bob.oldMACs) != 0 {
+ t.Errorf("Bob should not have MAC keys to reveal")
+ }
+ case subsequentRoundTrip:
+ if len(bob.oldMACs) != 40 {
+ t.Errorf("Bob has %d bytes of MAC keys to reveal, but should have 40", len(bob.oldMACs))
+ }
+ }
+
+ bobsMessage, err := bob.Send(message)
+ if err != nil {
+ t.Errorf("Error from Bob sending message: %s", err)
+ }
+
+ if len(bob.oldMACs) != 0 {
+ t.Errorf("Bob has not revealed all MAC keys")
+ }
+
+ for i, msg := range bobsMessage {
+ out, encrypted, _, _, err := alice.Receive(msg)
+
+ if err != nil {
+ t.Errorf("Error generated while processing test message: %s", err.Error())
+ }
+ if len(out) > 0 {
+ if i != len(bobsMessage)-1 {
+ t.Fatal("Alice produced a message while processing a fragment of Bob's")
+ }
+ if !encrypted {
+ t.Errorf("Message was not marked as encrypted")
+ }
+ if !bytes.Equal(out, message) {
+ t.Errorf("Message corrupted: got %x, want %x", out, message)
+ }
+ }
+ }
+
+ switch macKeyCheck {
+ case firstRoundTrip:
+ if len(alice.oldMACs) != 20 {
+ t.Errorf("Alice has %d bytes of MAC keys to reveal, but should have 20", len(alice.oldMACs))
+ }
+ case subsequentRoundTrip:
+ if len(alice.oldMACs) != 40 {
+ t.Errorf("Alice has %d bytes of MAC keys to reveal, but should have 40", len(alice.oldMACs))
+ }
+ }
+}
+
+func TestConversation(t *testing.T) {
+ alice, bob := setupConversation(t)
+
+ var testMessages = [][]byte{
+ []byte("hello"), []byte("bye"),
+ }
+
+ roundTripType := firstRoundTrip
+
+ for _, testMessage := range testMessages {
+ roundTrip(t, alice, bob, testMessage, roundTripType)
+ roundTripType = subsequentRoundTrip
+ }
+}
+
+func TestGoodSMP(t *testing.T) {
+ var alice, bob Conversation
+
+ alice.smp.secret = new(big.Int).SetInt64(42)
+ bob.smp.secret = alice.smp.secret
+
+ var alicesMessages, bobsMessages []tlv
+ var aliceComplete, bobComplete bool
+ var err error
+ var out tlv
+
+ alicesMessages = alice.startSMP("")
+ for round := 0; len(alicesMessages) > 0 || len(bobsMessages) > 0; round++ {
+ bobsMessages = bobsMessages[:0]
+ for i, msg := range alicesMessages {
+ out, bobComplete, err = bob.processSMP(msg)
+ if err != nil {
+ t.Errorf("Error from Bob in round %d: %s", round, err)
+ }
+ if bobComplete && i != len(alicesMessages)-1 {
+ t.Errorf("Bob returned a completed signal before processing all of Alice's messages in round %d", round)
+ }
+ if out.typ != 0 {
+ bobsMessages = append(bobsMessages, out)
+ }
+ }
+
+ alicesMessages = alicesMessages[:0]
+ for i, msg := range bobsMessages {
+ out, aliceComplete, err = alice.processSMP(msg)
+ if err != nil {
+ t.Errorf("Error from Alice in round %d: %s", round, err)
+ }
+ if aliceComplete && i != len(bobsMessages)-1 {
+ t.Errorf("Alice returned a completed signal before processing all of Bob's messages in round %d", round)
+ }
+ if out.typ != 0 {
+ alicesMessages = append(alicesMessages, out)
+ }
+ }
+ }
+
+ if !aliceComplete || !bobComplete {
+ t.Errorf("SMP completed without both sides reporting success: alice: %v, bob: %v\n", aliceComplete, bobComplete)
+ }
+}
+
+func TestBadSMP(t *testing.T) {
+ var alice, bob Conversation
+
+ alice.smp.secret = new(big.Int).SetInt64(42)
+ bob.smp.secret = new(big.Int).SetInt64(43)
+
+ var alicesMessages, bobsMessages []tlv
+
+ alicesMessages = alice.startSMP("")
+ for round := 0; len(alicesMessages) > 0 || len(bobsMessages) > 0; round++ {
+ bobsMessages = bobsMessages[:0]
+ for _, msg := range alicesMessages {
+ out, complete, _ := bob.processSMP(msg)
+ if complete {
+ t.Errorf("Bob signaled completion in round %d", round)
+ }
+ if out.typ != 0 {
+ bobsMessages = append(bobsMessages, out)
+ }
+ }
+
+ alicesMessages = alicesMessages[:0]
+ for _, msg := range bobsMessages {
+ out, complete, _ := alice.processSMP(msg)
+ if complete {
+ t.Errorf("Alice signaled completion in round %d", round)
+ }
+ if out.typ != 0 {
+ alicesMessages = append(alicesMessages, out)
+ }
+ }
+ }
+}
+
+func TestRehandshaking(t *testing.T) {
+ alice, bob := setupConversation(t)
+ roundTrip(t, alice, bob, []byte("test"), firstRoundTrip)
+ roundTrip(t, alice, bob, []byte("test 2"), subsequentRoundTrip)
+ roundTrip(t, alice, bob, []byte("test 3"), subsequentRoundTrip)
+ roundTrip(t, alice, bob, []byte("test 4"), subsequentRoundTrip)
+ roundTrip(t, alice, bob, []byte("test 5"), subsequentRoundTrip)
+ roundTrip(t, alice, bob, []byte("test 6"), subsequentRoundTrip)
+ roundTrip(t, alice, bob, []byte("test 7"), subsequentRoundTrip)
+ roundTrip(t, alice, bob, []byte("test 8"), subsequentRoundTrip)
+ performHandshake(t, alice, bob)
+ roundTrip(t, alice, bob, []byte("test"), noMACKeyCheck)
+ roundTrip(t, alice, bob, []byte("test 2"), noMACKeyCheck)
+}
+
+func TestAgainstLibOTR(t *testing.T) {
+ // This test requires otr.c.test to be built as /tmp/a.out.
+ // If enabled, this tests runs forever performing OTR handshakes in a
+ // loop.
+ return
+
+ alicePrivateKey, _ := hex.DecodeString(alicePrivateKeyHex)
+ var alice Conversation
+ alice.PrivateKey = new(PrivateKey)
+ alice.PrivateKey.Parse(alicePrivateKey)
+
+ cmd := exec.Command("/tmp/a.out")
+ cmd.Stderr = os.Stderr
+
+ out, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer out.Close()
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ in := bufio.NewReader(stdout)
+
+ if err := cmd.Start(); err != nil {
+ t.Fatal(err)
+ }
+
+ out.Write([]byte(QueryMessage))
+ out.Write([]byte("\n"))
+ var expectedText = []byte("test message")
+
+ for {
+ line, isPrefix, err := in.ReadLine()
+ if isPrefix {
+ t.Fatal("line from subprocess too long")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ text, encrypted, change, alicesMessage, err := alice.Receive(line)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, msg := range alicesMessage {
+ out.Write(msg)
+ out.Write([]byte("\n"))
+ }
+ if change == NewKeys {
+ alicesMessage, err := alice.Send([]byte("Go -> libotr test message"))
+ if err != nil {
+ t.Fatalf("error sending message: %s", err.Error())
+ } else {
+ for _, msg := range alicesMessage {
+ out.Write(msg)
+ out.Write([]byte("\n"))
+ }
+ }
+ }
+ if len(text) > 0 {
+ if !bytes.Equal(text, expectedText) {
+ t.Fatalf("expected %x, but got %x", expectedText, text)
+ }
+ if !encrypted {
+ t.Fatal("message wasn't encrypted")
+ }
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/otr/smp.go b/vendor/golang.org/x/crypto/otr/smp.go
new file mode 100644
index 000000000..dc6de4ee0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/otr/smp.go
@@ -0,0 +1,572 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements the Socialist Millionaires Protocol as described in
+// http://www.cypherpunks.ca/otr/Protocol-v2-3.1.0.html. The protocol
+// specification is required in order to understand this code and, where
+// possible, the variable names in the code match up with the spec.
+
+package otr
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "errors"
+ "hash"
+ "math/big"
+)
+
+type smpFailure string
+
+func (s smpFailure) Error() string {
+ return string(s)
+}
+
+var smpFailureError = smpFailure("otr: SMP protocol failed")
+var smpSecretMissingError = smpFailure("otr: mutual secret needed")
+
+const smpVersion = 1
+
+const (
+ smpState1 = iota
+ smpState2
+ smpState3
+ smpState4
+)
+
+type smpState struct {
+ state int
+ a2, a3, b2, b3, pb, qb *big.Int
+ g2a, g3a *big.Int
+ g2, g3 *big.Int
+ g3b, papb, qaqb, ra *big.Int
+ saved *tlv
+ secret *big.Int
+ question string
+}
+
+func (c *Conversation) startSMP(question string) (tlvs []tlv) {
+ if c.smp.state != smpState1 {
+ tlvs = append(tlvs, c.generateSMPAbort())
+ }
+ tlvs = append(tlvs, c.generateSMP1(question))
+ c.smp.question = ""
+ c.smp.state = smpState2
+ return
+}
+
+func (c *Conversation) resetSMP() {
+ c.smp.state = smpState1
+ c.smp.secret = nil
+ c.smp.question = ""
+}
+
+func (c *Conversation) processSMP(in tlv) (out tlv, complete bool, err error) {
+ data := in.data
+
+ switch in.typ {
+ case tlvTypeSMPAbort:
+ if c.smp.state != smpState1 {
+ err = smpFailureError
+ }
+ c.resetSMP()
+ return
+ case tlvTypeSMP1WithQuestion:
+ // We preprocess this into a SMP1 message.
+ nulPos := bytes.IndexByte(data, 0)
+ if nulPos == -1 {
+ err = errors.New("otr: SMP message with question didn't contain a NUL byte")
+ return
+ }
+ c.smp.question = string(data[:nulPos])
+ data = data[nulPos+1:]
+ }
+
+ numMPIs, data, ok := getU32(data)
+ if !ok || numMPIs > 20 {
+ err = errors.New("otr: corrupt SMP message")
+ return
+ }
+
+ mpis := make([]*big.Int, numMPIs)
+ for i := range mpis {
+ var ok bool
+ mpis[i], data, ok = getMPI(data)
+ if !ok {
+ err = errors.New("otr: corrupt SMP message")
+ return
+ }
+ }
+
+ switch in.typ {
+ case tlvTypeSMP1, tlvTypeSMP1WithQuestion:
+ if c.smp.state != smpState1 {
+ c.resetSMP()
+ out = c.generateSMPAbort()
+ return
+ }
+ if c.smp.secret == nil {
+ err = smpSecretMissingError
+ return
+ }
+ if err = c.processSMP1(mpis); err != nil {
+ return
+ }
+ c.smp.state = smpState3
+ out = c.generateSMP2()
+ case tlvTypeSMP2:
+ if c.smp.state != smpState2 {
+ c.resetSMP()
+ out = c.generateSMPAbort()
+ return
+ }
+ if out, err = c.processSMP2(mpis); err != nil {
+ out = c.generateSMPAbort()
+ return
+ }
+ c.smp.state = smpState4
+ case tlvTypeSMP3:
+ if c.smp.state != smpState3 {
+ c.resetSMP()
+ out = c.generateSMPAbort()
+ return
+ }
+ if out, err = c.processSMP3(mpis); err != nil {
+ return
+ }
+ c.smp.state = smpState1
+ c.smp.secret = nil
+ complete = true
+ case tlvTypeSMP4:
+ if c.smp.state != smpState4 {
+ c.resetSMP()
+ out = c.generateSMPAbort()
+ return
+ }
+ if err = c.processSMP4(mpis); err != nil {
+ out = c.generateSMPAbort()
+ return
+ }
+ c.smp.state = smpState1
+ c.smp.secret = nil
+ complete = true
+ default:
+ panic("unknown SMP message")
+ }
+
+ return
+}
+
+func (c *Conversation) calcSMPSecret(mutualSecret []byte, weStarted bool) {
+ h := sha256.New()
+ h.Write([]byte{smpVersion})
+ if weStarted {
+ h.Write(c.PrivateKey.PublicKey.Fingerprint())
+ h.Write(c.TheirPublicKey.Fingerprint())
+ } else {
+ h.Write(c.TheirPublicKey.Fingerprint())
+ h.Write(c.PrivateKey.PublicKey.Fingerprint())
+ }
+ h.Write(c.SSID[:])
+ h.Write(mutualSecret)
+ c.smp.secret = new(big.Int).SetBytes(h.Sum(nil))
+}
+
+func (c *Conversation) generateSMP1(question string) tlv {
+ var randBuf [16]byte
+ c.smp.a2 = c.randMPI(randBuf[:])
+ c.smp.a3 = c.randMPI(randBuf[:])
+ g2a := new(big.Int).Exp(g, c.smp.a2, p)
+ g3a := new(big.Int).Exp(g, c.smp.a3, p)
+ h := sha256.New()
+
+ r2 := c.randMPI(randBuf[:])
+ r := new(big.Int).Exp(g, r2, p)
+ c2 := new(big.Int).SetBytes(hashMPIs(h, 1, r))
+ d2 := new(big.Int).Mul(c.smp.a2, c2)
+ d2.Sub(r2, d2)
+ d2.Mod(d2, q)
+ if d2.Sign() < 0 {
+ d2.Add(d2, q)
+ }
+
+ r3 := c.randMPI(randBuf[:])
+ r.Exp(g, r3, p)
+ c3 := new(big.Int).SetBytes(hashMPIs(h, 2, r))
+ d3 := new(big.Int).Mul(c.smp.a3, c3)
+ d3.Sub(r3, d3)
+ d3.Mod(d3, q)
+ if d3.Sign() < 0 {
+ d3.Add(d3, q)
+ }
+
+ var ret tlv
+ if len(question) > 0 {
+ ret.typ = tlvTypeSMP1WithQuestion
+ ret.data = append(ret.data, question...)
+ ret.data = append(ret.data, 0)
+ } else {
+ ret.typ = tlvTypeSMP1
+ }
+ ret.data = appendU32(ret.data, 6)
+ ret.data = appendMPIs(ret.data, g2a, c2, d2, g3a, c3, d3)
+ return ret
+}
+
+func (c *Conversation) processSMP1(mpis []*big.Int) error {
+ if len(mpis) != 6 {
+ return errors.New("otr: incorrect number of arguments in SMP1 message")
+ }
+ g2a := mpis[0]
+ c2 := mpis[1]
+ d2 := mpis[2]
+ g3a := mpis[3]
+ c3 := mpis[4]
+ d3 := mpis[5]
+ h := sha256.New()
+
+ r := new(big.Int).Exp(g, d2, p)
+ s := new(big.Int).Exp(g2a, c2, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+ t := new(big.Int).SetBytes(hashMPIs(h, 1, r))
+ if c2.Cmp(t) != 0 {
+ return errors.New("otr: ZKP c2 incorrect in SMP1 message")
+ }
+ r.Exp(g, d3, p)
+ s.Exp(g3a, c3, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+ t.SetBytes(hashMPIs(h, 2, r))
+ if c3.Cmp(t) != 0 {
+ return errors.New("otr: ZKP c3 incorrect in SMP1 message")
+ }
+
+ c.smp.g2a = g2a
+ c.smp.g3a = g3a
+ return nil
+}
+
+func (c *Conversation) generateSMP2() tlv {
+ var randBuf [16]byte
+ b2 := c.randMPI(randBuf[:])
+ c.smp.b3 = c.randMPI(randBuf[:])
+ r2 := c.randMPI(randBuf[:])
+ r3 := c.randMPI(randBuf[:])
+ r4 := c.randMPI(randBuf[:])
+ r5 := c.randMPI(randBuf[:])
+ r6 := c.randMPI(randBuf[:])
+
+ g2b := new(big.Int).Exp(g, b2, p)
+ g3b := new(big.Int).Exp(g, c.smp.b3, p)
+
+ r := new(big.Int).Exp(g, r2, p)
+ h := sha256.New()
+ c2 := new(big.Int).SetBytes(hashMPIs(h, 3, r))
+ d2 := new(big.Int).Mul(b2, c2)
+ d2.Sub(r2, d2)
+ d2.Mod(d2, q)
+ if d2.Sign() < 0 {
+ d2.Add(d2, q)
+ }
+
+ r.Exp(g, r3, p)
+ c3 := new(big.Int).SetBytes(hashMPIs(h, 4, r))
+ d3 := new(big.Int).Mul(c.smp.b3, c3)
+ d3.Sub(r3, d3)
+ d3.Mod(d3, q)
+ if d3.Sign() < 0 {
+ d3.Add(d3, q)
+ }
+
+ c.smp.g2 = new(big.Int).Exp(c.smp.g2a, b2, p)
+ c.smp.g3 = new(big.Int).Exp(c.smp.g3a, c.smp.b3, p)
+ c.smp.pb = new(big.Int).Exp(c.smp.g3, r4, p)
+ c.smp.qb = new(big.Int).Exp(g, r4, p)
+ r.Exp(c.smp.g2, c.smp.secret, p)
+ c.smp.qb.Mul(c.smp.qb, r)
+ c.smp.qb.Mod(c.smp.qb, p)
+
+ s := new(big.Int)
+ s.Exp(c.smp.g2, r6, p)
+ r.Exp(g, r5, p)
+ s.Mul(r, s)
+ s.Mod(s, p)
+ r.Exp(c.smp.g3, r5, p)
+ cp := new(big.Int).SetBytes(hashMPIs(h, 5, r, s))
+
+ // D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q
+
+ s.Mul(r4, cp)
+ r.Sub(r5, s)
+ d5 := new(big.Int).Mod(r, q)
+ if d5.Sign() < 0 {
+ d5.Add(d5, q)
+ }
+
+ s.Mul(c.smp.secret, cp)
+ r.Sub(r6, s)
+ d6 := new(big.Int).Mod(r, q)
+ if d6.Sign() < 0 {
+ d6.Add(d6, q)
+ }
+
+ var ret tlv
+ ret.typ = tlvTypeSMP2
+ ret.data = appendU32(ret.data, 11)
+ ret.data = appendMPIs(ret.data, g2b, c2, d2, g3b, c3, d3, c.smp.pb, c.smp.qb, cp, d5, d6)
+ return ret
+}
+
+func (c *Conversation) processSMP2(mpis []*big.Int) (out tlv, err error) {
+ if len(mpis) != 11 {
+ err = errors.New("otr: incorrect number of arguments in SMP2 message")
+ return
+ }
+ g2b := mpis[0]
+ c2 := mpis[1]
+ d2 := mpis[2]
+ g3b := mpis[3]
+ c3 := mpis[4]
+ d3 := mpis[5]
+ pb := mpis[6]
+ qb := mpis[7]
+ cp := mpis[8]
+ d5 := mpis[9]
+ d6 := mpis[10]
+ h := sha256.New()
+
+ r := new(big.Int).Exp(g, d2, p)
+ s := new(big.Int).Exp(g2b, c2, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+ s.SetBytes(hashMPIs(h, 3, r))
+ if c2.Cmp(s) != 0 {
+ err = errors.New("otr: ZKP c2 failed in SMP2 message")
+ return
+ }
+
+ r.Exp(g, d3, p)
+ s.Exp(g3b, c3, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+ s.SetBytes(hashMPIs(h, 4, r))
+ if c3.Cmp(s) != 0 {
+ err = errors.New("otr: ZKP c3 failed in SMP2 message")
+ return
+ }
+
+ c.smp.g2 = new(big.Int).Exp(g2b, c.smp.a2, p)
+ c.smp.g3 = new(big.Int).Exp(g3b, c.smp.a3, p)
+
+ r.Exp(g, d5, p)
+ s.Exp(c.smp.g2, d6, p)
+ r.Mul(r, s)
+ s.Exp(qb, cp, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+
+ s.Exp(c.smp.g3, d5, p)
+ t := new(big.Int).Exp(pb, cp, p)
+ s.Mul(s, t)
+ s.Mod(s, p)
+ t.SetBytes(hashMPIs(h, 5, s, r))
+ if cp.Cmp(t) != 0 {
+ err = errors.New("otr: ZKP cP failed in SMP2 message")
+ return
+ }
+
+ var randBuf [16]byte
+ r4 := c.randMPI(randBuf[:])
+ r5 := c.randMPI(randBuf[:])
+ r6 := c.randMPI(randBuf[:])
+ r7 := c.randMPI(randBuf[:])
+
+ pa := new(big.Int).Exp(c.smp.g3, r4, p)
+ r.Exp(c.smp.g2, c.smp.secret, p)
+ qa := new(big.Int).Exp(g, r4, p)
+ qa.Mul(qa, r)
+ qa.Mod(qa, p)
+
+ r.Exp(g, r5, p)
+ s.Exp(c.smp.g2, r6, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+
+ s.Exp(c.smp.g3, r5, p)
+ cp.SetBytes(hashMPIs(h, 6, s, r))
+
+ r.Mul(r4, cp)
+ d5 = new(big.Int).Sub(r5, r)
+ d5.Mod(d5, q)
+ if d5.Sign() < 0 {
+ d5.Add(d5, q)
+ }
+
+ r.Mul(c.smp.secret, cp)
+ d6 = new(big.Int).Sub(r6, r)
+ d6.Mod(d6, q)
+ if d6.Sign() < 0 {
+ d6.Add(d6, q)
+ }
+
+ r.ModInverse(qb, p)
+ qaqb := new(big.Int).Mul(qa, r)
+ qaqb.Mod(qaqb, p)
+
+ ra := new(big.Int).Exp(qaqb, c.smp.a3, p)
+ r.Exp(qaqb, r7, p)
+ s.Exp(g, r7, p)
+ cr := new(big.Int).SetBytes(hashMPIs(h, 7, s, r))
+
+ r.Mul(c.smp.a3, cr)
+ d7 := new(big.Int).Sub(r7, r)
+ d7.Mod(d7, q)
+ if d7.Sign() < 0 {
+ d7.Add(d7, q)
+ }
+
+ c.smp.g3b = g3b
+ c.smp.qaqb = qaqb
+
+ r.ModInverse(pb, p)
+ c.smp.papb = new(big.Int).Mul(pa, r)
+ c.smp.papb.Mod(c.smp.papb, p)
+ c.smp.ra = ra
+
+ out.typ = tlvTypeSMP3
+ out.data = appendU32(out.data, 8)
+ out.data = appendMPIs(out.data, pa, qa, cp, d5, d6, ra, cr, d7)
+ return
+}
+
+func (c *Conversation) processSMP3(mpis []*big.Int) (out tlv, err error) {
+ if len(mpis) != 8 {
+ err = errors.New("otr: incorrect number of arguments in SMP3 message")
+ return
+ }
+ pa := mpis[0]
+ qa := mpis[1]
+ cp := mpis[2]
+ d5 := mpis[3]
+ d6 := mpis[4]
+ ra := mpis[5]
+ cr := mpis[6]
+ d7 := mpis[7]
+ h := sha256.New()
+
+ r := new(big.Int).Exp(g, d5, p)
+ s := new(big.Int).Exp(c.smp.g2, d6, p)
+ r.Mul(r, s)
+ s.Exp(qa, cp, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+
+ s.Exp(c.smp.g3, d5, p)
+ t := new(big.Int).Exp(pa, cp, p)
+ s.Mul(s, t)
+ s.Mod(s, p)
+ t.SetBytes(hashMPIs(h, 6, s, r))
+ if t.Cmp(cp) != 0 {
+ err = errors.New("otr: ZKP cP failed in SMP3 message")
+ return
+ }
+
+ r.ModInverse(c.smp.qb, p)
+ qaqb := new(big.Int).Mul(qa, r)
+ qaqb.Mod(qaqb, p)
+
+ r.Exp(qaqb, d7, p)
+ s.Exp(ra, cr, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+
+ s.Exp(g, d7, p)
+ t.Exp(c.smp.g3a, cr, p)
+ s.Mul(s, t)
+ s.Mod(s, p)
+ t.SetBytes(hashMPIs(h, 7, s, r))
+ if t.Cmp(cr) != 0 {
+ err = errors.New("otr: ZKP cR failed in SMP3 message")
+ return
+ }
+
+ var randBuf [16]byte
+ r7 := c.randMPI(randBuf[:])
+ rb := new(big.Int).Exp(qaqb, c.smp.b3, p)
+
+ r.Exp(qaqb, r7, p)
+ s.Exp(g, r7, p)
+ cr = new(big.Int).SetBytes(hashMPIs(h, 8, s, r))
+
+ r.Mul(c.smp.b3, cr)
+ d7 = new(big.Int).Sub(r7, r)
+ d7.Mod(d7, q)
+ if d7.Sign() < 0 {
+ d7.Add(d7, q)
+ }
+
+ out.typ = tlvTypeSMP4
+ out.data = appendU32(out.data, 3)
+ out.data = appendMPIs(out.data, rb, cr, d7)
+
+ r.ModInverse(c.smp.pb, p)
+ r.Mul(pa, r)
+ r.Mod(r, p)
+ s.Exp(ra, c.smp.b3, p)
+ if r.Cmp(s) != 0 {
+ err = smpFailureError
+ }
+
+ return
+}
+
+func (c *Conversation) processSMP4(mpis []*big.Int) error {
+ if len(mpis) != 3 {
+ return errors.New("otr: incorrect number of arguments in SMP4 message")
+ }
+ rb := mpis[0]
+ cr := mpis[1]
+ d7 := mpis[2]
+ h := sha256.New()
+
+ r := new(big.Int).Exp(c.smp.qaqb, d7, p)
+ s := new(big.Int).Exp(rb, cr, p)
+ r.Mul(r, s)
+ r.Mod(r, p)
+
+ s.Exp(g, d7, p)
+ t := new(big.Int).Exp(c.smp.g3b, cr, p)
+ s.Mul(s, t)
+ s.Mod(s, p)
+ t.SetBytes(hashMPIs(h, 8, s, r))
+ if t.Cmp(cr) != 0 {
+ return errors.New("otr: ZKP cR failed in SMP4 message")
+ }
+
+ r.Exp(rb, c.smp.a3, p)
+ if r.Cmp(c.smp.papb) != 0 {
+ return smpFailureError
+ }
+
+ return nil
+}
+
+func (c *Conversation) generateSMPAbort() tlv {
+ return tlv{typ: tlvTypeSMPAbort}
+}
+
+func hashMPIs(h hash.Hash, magic byte, mpis ...*big.Int) []byte {
+ if h != nil {
+ h.Reset()
+ } else {
+ h = sha256.New()
+ }
+
+ h.Write([]byte{magic})
+ for _, mpi := range mpis {
+ h.Write(appendMPI(nil, mpi))
+ }
+ return h.Sum(nil)
+}
diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
new file mode 100644
index 000000000..593f65300
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
@@ -0,0 +1,77 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
+2898 / PKCS #5 v2.0.
+
+A key derivation function is useful when encrypting data based on a password
+or any other not-fully-random data. It uses a pseudorandom function to derive
+a secure encryption key based on the password.
+
+While v2.0 of the standard defines only one pseudorandom function to use,
+HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
+Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
+choose, you can pass the `New` functions from the different SHA packages to
+pbkdf2.Key.
+*/
+package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
+
+import (
+ "crypto/hmac"
+ "hash"
+)
+
+// Key derives a key from the password, salt and iteration count, returning a
+// []byte of length keylen that can be used as cryptographic key. The key is
+// derived based on the method described as PBKDF2 with the HMAC variant using
+// the supplied hash function.
+//
+// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
+// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
+// doing:
+//
+// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
+//
+// Remember to get a good random salt. At least 8 bytes is recommended by the
+// RFC.
+//
+// Using a higher iteration count will increase the cost of an exhaustive
+// search but will also make derivation proportionally slower.
+func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
+ prf := hmac.New(h, password)
+ hashLen := prf.Size()
+ numBlocks := (keyLen + hashLen - 1) / hashLen
+
+ var buf [4]byte
+ dk := make([]byte, 0, numBlocks*hashLen)
+ U := make([]byte, hashLen)
+ for block := 1; block <= numBlocks; block++ {
+ // N.B.: || means concatenation, ^ means XOR
+ // for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
+ // U_1 = PRF(password, salt || uint(i))
+ prf.Reset()
+ prf.Write(salt)
+ buf[0] = byte(block >> 24)
+ buf[1] = byte(block >> 16)
+ buf[2] = byte(block >> 8)
+ buf[3] = byte(block)
+ prf.Write(buf[:4])
+ dk = prf.Sum(dk)
+ T := dk[len(dk)-hashLen:]
+ copy(U, T)
+
+ // U_n = PRF(password, U_(n-1))
+ for n := 2; n <= iter; n++ {
+ prf.Reset()
+ prf.Write(U)
+ U = U[:0]
+ U = prf.Sum(U)
+ for x := range U {
+ T[x] ^= U[x]
+ }
+ }
+ }
+ return dk[:keyLen]
+}
diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2_test.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2_test.go
new file mode 100644
index 000000000..137924061
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2_test.go
@@ -0,0 +1,157 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pbkdf2
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "crypto/sha256"
+ "hash"
+ "testing"
+)
+
+type testVector struct {
+ password string
+ salt string
+ iter int
+ output []byte
+}
+
+// Test vectors from RFC 6070, http://tools.ietf.org/html/rfc6070
+var sha1TestVectors = []testVector{
+ {
+ "password",
+ "salt",
+ 1,
+ []byte{
+ 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+ 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+ 0x2f, 0xe0, 0x37, 0xa6,
+ },
+ },
+ {
+ "password",
+ "salt",
+ 2,
+ []byte{
+ 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+ 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+ 0xd8, 0xde, 0x89, 0x57,
+ },
+ },
+ {
+ "password",
+ "salt",
+ 4096,
+ []byte{
+ 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+ 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+ 0x65, 0xa4, 0x29, 0xc1,
+ },
+ },
+ // // This one takes too long
+ // {
+ // "password",
+ // "salt",
+ // 16777216,
+ // []byte{
+ // 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
+ // 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
+ // 0x26, 0x34, 0xe9, 0x84,
+ // },
+ // },
+ {
+ "passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ 4096,
+ []byte{
+ 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+ 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+ 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+ 0x38,
+ },
+ },
+ {
+ "pass\000word",
+ "sa\000lt",
+ 4096,
+ []byte{
+ 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+ 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3,
+ },
+ },
+}
+
+// Test vectors from
+// http://stackoverflow.com/questions/5130513/pbkdf2-hmac-sha2-test-vectors
+var sha256TestVectors = []testVector{
+ {
+ "password",
+ "salt",
+ 1,
+ []byte{
+ 0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c,
+ 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37,
+ 0xa8, 0x65, 0x48, 0xc9,
+ },
+ },
+ {
+ "password",
+ "salt",
+ 2,
+ []byte{
+ 0xae, 0x4d, 0x0c, 0x95, 0xaf, 0x6b, 0x46, 0xd3,
+ 0x2d, 0x0a, 0xdf, 0xf9, 0x28, 0xf0, 0x6d, 0xd0,
+ 0x2a, 0x30, 0x3f, 0x8e,
+ },
+ },
+ {
+ "password",
+ "salt",
+ 4096,
+ []byte{
+ 0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41,
+ 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d,
+ 0x96, 0x28, 0x93, 0xa0,
+ },
+ },
+ {
+ "passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ 4096,
+ []byte{
+ 0x34, 0x8c, 0x89, 0xdb, 0xcb, 0xd3, 0x2b, 0x2f,
+ 0x32, 0xd8, 0x14, 0xb8, 0x11, 0x6e, 0x84, 0xcf,
+ 0x2b, 0x17, 0x34, 0x7e, 0xbc, 0x18, 0x00, 0x18,
+ 0x1c,
+ },
+ },
+ {
+ "pass\000word",
+ "sa\000lt",
+ 4096,
+ []byte{
+ 0x89, 0xb6, 0x9d, 0x05, 0x16, 0xf8, 0x29, 0x89,
+ 0x3c, 0x69, 0x62, 0x26, 0x65, 0x0a, 0x86, 0x87,
+ },
+ },
+}
+
+func testHash(t *testing.T, h func() hash.Hash, hashName string, vectors []testVector) {
+ for i, v := range vectors {
+ o := Key([]byte(v.password), []byte(v.salt), v.iter, len(v.output), h)
+ if !bytes.Equal(o, v.output) {
+ t.Errorf("%s %d: expected %x, got %x", hashName, i, v.output, o)
+ }
+ }
+}
+
+func TestWithHMACSHA1(t *testing.T) {
+ testHash(t, sha1.New, "SHA1", sha1TestVectors)
+}
+
+func TestWithHMACSHA256(t *testing.T) {
+ testHash(t, sha256.New, "SHA256", sha256TestVectors)
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/bmp-string.go b/vendor/golang.org/x/crypto/pkcs12/bmp-string.go
new file mode 100644
index 000000000..284d2a68f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/bmp-string.go
@@ -0,0 +1,50 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "errors"
+ "unicode/utf16"
+)
+
+// bmpString returns s encoded in UCS-2 with a zero terminator.
+func bmpString(s string) ([]byte, error) {
+ // References:
+ // https://tools.ietf.org/html/rfc7292#appendix-B.1
+ // http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
+ // - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes
+ // EncodeRune returns 0xfffd if the rune does not need special encoding
+ // - the above RFC provides the info that BMPStrings are NULL terminated.
+
+ ret := make([]byte, 0, 2*len(s)+2)
+
+ for _, r := range s {
+ if t, _ := utf16.EncodeRune(r); t != 0xfffd {
+ return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
+ }
+ ret = append(ret, byte(r/256), byte(r%256))
+ }
+
+ return append(ret, 0, 0), nil
+}
+
+func decodeBMPString(bmpString []byte) (string, error) {
+ if len(bmpString)%2 != 0 {
+ return "", errors.New("pkcs12: odd-length BMP string")
+ }
+
+ // strip terminator if present
+ if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
+ bmpString = bmpString[:l-2]
+ }
+
+ s := make([]uint16, 0, len(bmpString)/2)
+ for len(bmpString) > 0 {
+ s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
+ bmpString = bmpString[2:]
+ }
+
+ return string(utf16.Decode(s)), nil
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/bmp-string_test.go b/vendor/golang.org/x/crypto/pkcs12/bmp-string_test.go
new file mode 100644
index 000000000..7fca55f4e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/bmp-string_test.go
@@ -0,0 +1,63 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+var bmpStringTests = []struct {
+ in string
+ expectedHex string
+ shouldFail bool
+}{
+ {"", "0000", false},
+ // Example from https://tools.ietf.org/html/rfc7292#appendix-B.
+ {"Beavis", "0042006500610076006900730000", false},
+ // Some characters from the "Letterlike Symbols Unicode block".
+ {"\u2115 - Double-struck N", "21150020002d00200044006f00750062006c0065002d00730074007200750063006b0020004e0000", false},
+ // any character outside the BMP should trigger an error.
+ {"\U0001f000 East wind (Mahjong)", "", true},
+}
+
+func TestBMPString(t *testing.T) {
+ for i, test := range bmpStringTests {
+ expected, err := hex.DecodeString(test.expectedHex)
+ if err != nil {
+ t.Fatalf("#%d: failed to decode expectation", i)
+ }
+
+ out, err := bmpString(test.in)
+ if err == nil && test.shouldFail {
+ t.Errorf("#%d: expected to fail, but produced %x", i, out)
+ continue
+ }
+
+ if err != nil && !test.shouldFail {
+ t.Errorf("#%d: failed unexpectedly: %s", i, err)
+ continue
+ }
+
+ if !test.shouldFail {
+ if !bytes.Equal(out, expected) {
+ t.Errorf("#%d: expected %s, got %x", i, test.expectedHex, out)
+ continue
+ }
+
+ roundTrip, err := decodeBMPString(out)
+ if err != nil {
+ t.Errorf("#%d: decoding output gave an error: %s", i, err)
+ continue
+ }
+
+ if roundTrip != test.in {
+ t.Errorf("#%d: decoding output resulted in %q, but it should have been %q", i, roundTrip, test.in)
+ continue
+ }
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/crypto.go b/vendor/golang.org/x/crypto/pkcs12/crypto.go
new file mode 100644
index 000000000..4bd4470ec
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/crypto.go
@@ -0,0 +1,131 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+
+ "golang.org/x/crypto/pkcs12/internal/rc2"
+)
+
+var (
+ oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
+ oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6})
+)
+
+// pbeCipher is an abstraction of a PKCS#12 cipher.
+type pbeCipher interface {
+ // create returns a cipher.Block given a key.
+ create(key []byte) (cipher.Block, error)
+ // deriveKey returns a key derived from the given password and salt.
+ deriveKey(salt, password []byte, iterations int) []byte
+ // deriveKey returns an IV derived from the given password and salt.
+ deriveIV(salt, password []byte, iterations int) []byte
+}
+
+type shaWithTripleDESCBC struct{}
+
+func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) {
+ return des.NewTripleDESCipher(key)
+}
+
+func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
+}
+
+func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
+}
+
+type shaWith40BitRC2CBC struct{}
+
+func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) {
+ return rc2.New(key, len(key)*8)
+}
+
+func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
+}
+
+func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte {
+ return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
+}
+
+type pbeParams struct {
+ Salt []byte
+ Iterations int
+}
+
+func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) {
+ var cipherType pbeCipher
+
+ switch {
+ case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC):
+ cipherType = shaWithTripleDESCBC{}
+ case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC):
+ cipherType = shaWith40BitRC2CBC{}
+ default:
+ return nil, 0, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported")
+ }
+
+ var params pbeParams
+ if err := unmarshal(algorithm.Parameters.FullBytes, &params); err != nil {
+ return nil, 0, err
+ }
+
+ key := cipherType.deriveKey(params.Salt, password, params.Iterations)
+ iv := cipherType.deriveIV(params.Salt, password, params.Iterations)
+
+ block, err := cipherType.create(key)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil
+}
+
+func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) {
+ cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password)
+ if err != nil {
+ return nil, err
+ }
+
+ encrypted := info.Data()
+ if len(encrypted) == 0 {
+ return nil, errors.New("pkcs12: empty encrypted data")
+ }
+ if len(encrypted)%blockSize != 0 {
+ return nil, errors.New("pkcs12: input is not a multiple of the block size")
+ }
+ decrypted = make([]byte, len(encrypted))
+ cbc.CryptBlocks(decrypted, encrypted)
+
+ psLen := int(decrypted[len(decrypted)-1])
+ if psLen == 0 || psLen > blockSize {
+ return nil, ErrDecryption
+ }
+
+ if len(decrypted) < psLen {
+ return nil, ErrDecryption
+ }
+ ps := decrypted[len(decrypted)-psLen:]
+ decrypted = decrypted[:len(decrypted)-psLen]
+ if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 {
+ return nil, ErrDecryption
+ }
+
+ return
+}
+
+// decryptable abstracts a object that contains ciphertext.
+type decryptable interface {
+ Algorithm() pkix.AlgorithmIdentifier
+ Data() []byte
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/crypto_test.go b/vendor/golang.org/x/crypto/pkcs12/crypto_test.go
new file mode 100644
index 000000000..eb4dae8fc
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/crypto_test.go
@@ -0,0 +1,125 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "bytes"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "testing"
+)
+
+var sha1WithTripleDES = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
+
+func TestPbDecrypterFor(t *testing.T) {
+ params, _ := asn1.Marshal(pbeParams{
+ Salt: []byte{1, 2, 3, 4, 5, 6, 7, 8},
+ Iterations: 2048,
+ })
+ alg := pkix.AlgorithmIdentifier{
+ Algorithm: asn1.ObjectIdentifier([]int{1, 2, 3}),
+ Parameters: asn1.RawValue{
+ FullBytes: params,
+ },
+ }
+
+ pass, _ := bmpString("Sesame open")
+
+ _, _, err := pbDecrypterFor(alg, pass)
+ if _, ok := err.(NotImplementedError); !ok {
+ t.Errorf("expected not implemented error, got: %T %s", err, err)
+ }
+
+ alg.Algorithm = sha1WithTripleDES
+ cbc, blockSize, err := pbDecrypterFor(alg, pass)
+ if err != nil {
+ t.Errorf("unexpected error from pbDecrypterFor %v", err)
+ }
+ if blockSize != 8 {
+ t.Errorf("unexpected block size %d, wanted 8", blockSize)
+ }
+
+ plaintext := []byte{1, 2, 3, 4, 5, 6, 7, 8}
+ expectedCiphertext := []byte{185, 73, 135, 249, 137, 1, 122, 247}
+ ciphertext := make([]byte, len(plaintext))
+ cbc.CryptBlocks(ciphertext, plaintext)
+
+ if bytes.Compare(ciphertext, expectedCiphertext) != 0 {
+ t.Errorf("bad ciphertext, got %x but wanted %x", ciphertext, expectedCiphertext)
+ }
+}
+
+var pbDecryptTests = []struct {
+ in []byte
+ expected []byte
+ expectedError error
+}{
+ {
+ []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\xa0\x9a\xdf\x5a\x58\xa0\xea\x46"), // 7 padding bytes
+ []byte("A secret!"),
+ nil,
+ },
+ {
+ []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\x96\x24\x2f\x71\x7e\x32\x3f\xe7"), // 8 padding bytes
+ []byte("A secret"),
+ nil,
+ },
+ {
+ []byte("\x35\x0c\xc0\x8d\xab\xa9\x5d\x30\x7f\x9a\xec\x6a\xd8\x9b\x9c\xd9"), // 9 padding bytes, incorrect
+ nil,
+ ErrDecryption,
+ },
+ {
+ []byte("\xb2\xf9\x6e\x06\x60\xae\x20\xcf\x08\xa0\x7b\xd9\x6b\x20\xef\x41"), // incorrect padding bytes: [ ... 0x04 0x02 ]
+ nil,
+ ErrDecryption,
+ },
+}
+
+func TestPbDecrypt(t *testing.T) {
+ for i, test := range pbDecryptTests {
+ decryptable := testDecryptable{
+ data: test.in,
+ algorithm: pkix.AlgorithmIdentifier{
+ Algorithm: sha1WithTripleDES,
+ Parameters: pbeParams{
+ Salt: []byte("\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8"),
+ Iterations: 4096,
+ }.RawASN1(),
+ },
+ }
+ password, _ := bmpString("sesame")
+
+ plaintext, err := pbDecrypt(decryptable, password)
+ if err != test.expectedError {
+ t.Errorf("#%d: got error %q, but wanted %q", i, err, test.expectedError)
+ continue
+ }
+
+ if !bytes.Equal(plaintext, test.expected) {
+ t.Errorf("#%d: got %x, but wanted %x", i, plaintext, test.expected)
+ }
+ }
+}
+
+type testDecryptable struct {
+ data []byte
+ algorithm pkix.AlgorithmIdentifier
+}
+
+func (d testDecryptable) Algorithm() pkix.AlgorithmIdentifier { return d.algorithm }
+func (d testDecryptable) Data() []byte { return d.data }
+
+func (params pbeParams) RawASN1() (raw asn1.RawValue) {
+ asn1Bytes, err := asn1.Marshal(params)
+ if err != nil {
+ panic(err)
+ }
+ _, err = asn1.Unmarshal(asn1Bytes, &raw)
+ if err != nil {
+ panic(err)
+ }
+ return
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/errors.go b/vendor/golang.org/x/crypto/pkcs12/errors.go
new file mode 100644
index 000000000..7377ce6fb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/errors.go
@@ -0,0 +1,23 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import "errors"
+
+var (
+ // ErrDecryption represents a failure to decrypt the input.
+ ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding")
+
+ // ErrIncorrectPassword is returned when an incorrect password is detected.
+ // Usually, P12/PFX data is signed to be able to verify the password.
+ ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect")
+)
+
+// NotImplementedError indicates that the input is not currently supported.
+type NotImplementedError string
+
+func (e NotImplementedError) Error() string {
+ return "pkcs12: " + string(e)
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/internal/rc2/bench_test.go b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/bench_test.go
new file mode 100644
index 000000000..3347f338c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/bench_test.go
@@ -0,0 +1,27 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rc2
+
+import (
+ "testing"
+)
+
+func BenchmarkEncrypt(b *testing.B) {
+ r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
+ b.ResetTimer()
+ var src [8]byte
+ for i := 0; i < b.N; i++ {
+ r.Encrypt(src[:], src[:])
+ }
+}
+
+func BenchmarkDecrypt(b *testing.B) {
+ r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64)
+ b.ResetTimer()
+ var src [8]byte
+ for i := 0; i < b.N; i++ {
+ r.Decrypt(src[:], src[:])
+ }
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go
new file mode 100644
index 000000000..8c7090258
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go
@@ -0,0 +1,274 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rc2 implements the RC2 cipher
+/*
+https://www.ietf.org/rfc/rfc2268.txt
+http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf
+
+This code is licensed under the MIT license.
+*/
+package rc2
+
+import (
+ "crypto/cipher"
+ "encoding/binary"
+)
+
+// The rc2 block size in bytes
+const BlockSize = 8
+
+type rc2Cipher struct {
+ k [64]uint16
+}
+
+// New returns a new rc2 cipher with the given key and effective key length t1
+func New(key []byte, t1 int) (cipher.Block, error) {
+ // TODO(dgryski): error checking for key length
+ return &rc2Cipher{
+ k: expandKey(key, t1),
+ }, nil
+}
+
+func (*rc2Cipher) BlockSize() int { return BlockSize }
+
+var piTable = [256]byte{
+ 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
+ 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
+ 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
+ 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
+ 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
+ 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
+ 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
+ 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
+ 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
+ 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
+ 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
+ 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
+ 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
+ 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
+ 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
+ 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad,
+}
+
+func expandKey(key []byte, t1 int) [64]uint16 {
+
+ l := make([]byte, 128)
+ copy(l, key)
+
+ var t = len(key)
+ var t8 = (t1 + 7) / 8
+ var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8))))
+
+ for i := len(key); i < 128; i++ {
+ l[i] = piTable[l[i-1]+l[uint8(i-t)]]
+ }
+
+ l[128-t8] = piTable[l[128-t8]&tm]
+
+ for i := 127 - t8; i >= 0; i-- {
+ l[i] = piTable[l[i+1]^l[i+t8]]
+ }
+
+ var k [64]uint16
+
+ for i := range k {
+ k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256
+ }
+
+ return k
+}
+
+func rotl16(x uint16, b uint) uint16 {
+ return (x >> (16 - b)) | (x << b)
+}
+
+func (c *rc2Cipher) Encrypt(dst, src []byte) {
+
+ r0 := binary.LittleEndian.Uint16(src[0:])
+ r1 := binary.LittleEndian.Uint16(src[2:])
+ r2 := binary.LittleEndian.Uint16(src[4:])
+ r3 := binary.LittleEndian.Uint16(src[6:])
+
+ var j int
+
+ for j <= 16 {
+ // mix r0
+ r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+ r0 = rotl16(r0, 1)
+ j++
+
+ // mix r1
+ r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+ r1 = rotl16(r1, 2)
+ j++
+
+ // mix r2
+ r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+ r2 = rotl16(r2, 3)
+ j++
+
+ // mix r3
+ r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+ r3 = rotl16(r3, 5)
+ j++
+
+ }
+
+ r0 = r0 + c.k[r3&63]
+ r1 = r1 + c.k[r0&63]
+ r2 = r2 + c.k[r1&63]
+ r3 = r3 + c.k[r2&63]
+
+ for j <= 40 {
+
+ // mix r0
+ r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+ r0 = rotl16(r0, 1)
+ j++
+
+ // mix r1
+ r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+ r1 = rotl16(r1, 2)
+ j++
+
+ // mix r2
+ r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+ r2 = rotl16(r2, 3)
+ j++
+
+ // mix r3
+ r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+ r3 = rotl16(r3, 5)
+ j++
+
+ }
+
+ r0 = r0 + c.k[r3&63]
+ r1 = r1 + c.k[r0&63]
+ r2 = r2 + c.k[r1&63]
+ r3 = r3 + c.k[r2&63]
+
+ for j <= 60 {
+
+ // mix r0
+ r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
+ r0 = rotl16(r0, 1)
+ j++
+
+ // mix r1
+ r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
+ r1 = rotl16(r1, 2)
+ j++
+
+ // mix r2
+ r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
+ r2 = rotl16(r2, 3)
+ j++
+
+ // mix r3
+ r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
+ r3 = rotl16(r3, 5)
+ j++
+ }
+
+ binary.LittleEndian.PutUint16(dst[0:], r0)
+ binary.LittleEndian.PutUint16(dst[2:], r1)
+ binary.LittleEndian.PutUint16(dst[4:], r2)
+ binary.LittleEndian.PutUint16(dst[6:], r3)
+}
+
+func (c *rc2Cipher) Decrypt(dst, src []byte) {
+
+ r0 := binary.LittleEndian.Uint16(src[0:])
+ r1 := binary.LittleEndian.Uint16(src[2:])
+ r2 := binary.LittleEndian.Uint16(src[4:])
+ r3 := binary.LittleEndian.Uint16(src[6:])
+
+ j := 63
+
+ for j >= 44 {
+ // unmix r3
+ r3 = rotl16(r3, 16-5)
+ r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+ j--
+
+ // unmix r2
+ r2 = rotl16(r2, 16-3)
+ r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+ j--
+
+ // unmix r1
+ r1 = rotl16(r1, 16-2)
+ r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+ j--
+
+ // unmix r0
+ r0 = rotl16(r0, 16-1)
+ r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+ j--
+ }
+
+ r3 = r3 - c.k[r2&63]
+ r2 = r2 - c.k[r1&63]
+ r1 = r1 - c.k[r0&63]
+ r0 = r0 - c.k[r3&63]
+
+ for j >= 20 {
+ // unmix r3
+ r3 = rotl16(r3, 16-5)
+ r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+ j--
+
+ // unmix r2
+ r2 = rotl16(r2, 16-3)
+ r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+ j--
+
+ // unmix r1
+ r1 = rotl16(r1, 16-2)
+ r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+ j--
+
+ // unmix r0
+ r0 = rotl16(r0, 16-1)
+ r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+ j--
+
+ }
+
+ r3 = r3 - c.k[r2&63]
+ r2 = r2 - c.k[r1&63]
+ r1 = r1 - c.k[r0&63]
+ r0 = r0 - c.k[r3&63]
+
+ for j >= 0 {
+
+ // unmix r3
+ r3 = rotl16(r3, 16-5)
+ r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
+ j--
+
+ // unmix r2
+ r2 = rotl16(r2, 16-3)
+ r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
+ j--
+
+ // unmix r1
+ r1 = rotl16(r1, 16-2)
+ r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
+ j--
+
+ // unmix r0
+ r0 = rotl16(r0, 16-1)
+ r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
+ j--
+
+ }
+
+ binary.LittleEndian.PutUint16(dst[0:], r0)
+ binary.LittleEndian.PutUint16(dst[2:], r1)
+ binary.LittleEndian.PutUint16(dst[4:], r2)
+ binary.LittleEndian.PutUint16(dst[6:], r3)
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2_test.go b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2_test.go
new file mode 100644
index 000000000..8a49dfaf3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2_test.go
@@ -0,0 +1,93 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rc2
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+func TestEncryptDecrypt(t *testing.T) {
+
+ // TODO(dgryski): add the rest of the test vectors from the RFC
+ var tests = []struct {
+ key string
+ plain string
+ cipher string
+ t1 int
+ }{
+ {
+ "0000000000000000",
+ "0000000000000000",
+ "ebb773f993278eff",
+ 63,
+ },
+ {
+ "ffffffffffffffff",
+ "ffffffffffffffff",
+ "278b27e42e2f0d49",
+ 64,
+ },
+ {
+ "3000000000000000",
+ "1000000000000001",
+ "30649edf9be7d2c2",
+ 64,
+ },
+ {
+ "88",
+ "0000000000000000",
+ "61a8a244adacccf0",
+ 64,
+ },
+ {
+ "88bca90e90875a",
+ "0000000000000000",
+ "6ccf4308974c267f",
+ 64,
+ },
+ {
+ "88bca90e90875a7f0f79c384627bafb2",
+ "0000000000000000",
+ "1a807d272bbe5db1",
+ 64,
+ },
+ {
+ "88bca90e90875a7f0f79c384627bafb2",
+ "0000000000000000",
+ "2269552ab0f85ca6",
+ 128,
+ },
+ {
+ "88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e",
+ "0000000000000000",
+ "5b78d3a43dfff1f1",
+ 129,
+ },
+ }
+
+ for _, tt := range tests {
+ k, _ := hex.DecodeString(tt.key)
+ p, _ := hex.DecodeString(tt.plain)
+ c, _ := hex.DecodeString(tt.cipher)
+
+ b, _ := New(k, tt.t1)
+
+ var dst [8]byte
+
+ b.Encrypt(dst[:], p)
+
+ if !bytes.Equal(dst[:], c) {
+ t.Errorf("encrypt failed: got % 2x wanted % 2x\n", dst, c)
+ }
+
+ b.Decrypt(dst[:], c)
+
+ if !bytes.Equal(dst[:], p) {
+ t.Errorf("decrypt failed: got % 2x wanted % 2x\n", dst, p)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/mac.go b/vendor/golang.org/x/crypto/pkcs12/mac.go
new file mode 100644
index 000000000..5f38aa7de
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/mac.go
@@ -0,0 +1,45 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+)
+
+type macData struct {
+ Mac digestInfo
+ MacSalt []byte
+ Iterations int `asn1:"optional,default:1"`
+}
+
+// from PKCS#7:
+type digestInfo struct {
+ Algorithm pkix.AlgorithmIdentifier
+ Digest []byte
+}
+
+var (
+ oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
+)
+
+func verifyMac(macData *macData, message, password []byte) error {
+ if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
+ return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
+ }
+
+ key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
+
+ mac := hmac.New(sha1.New, key)
+ mac.Write(message)
+ expectedMAC := mac.Sum(nil)
+
+ if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
+ return ErrIncorrectPassword
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/mac_test.go b/vendor/golang.org/x/crypto/pkcs12/mac_test.go
new file mode 100644
index 000000000..1ed4ff21e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/mac_test.go
@@ -0,0 +1,42 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "encoding/asn1"
+ "testing"
+)
+
+func TestVerifyMac(t *testing.T) {
+ td := macData{
+ Mac: digestInfo{
+ Digest: []byte{0x18, 0x20, 0x3d, 0xff, 0x1e, 0x16, 0xf4, 0x92, 0xf2, 0xaf, 0xc8, 0x91, 0xa9, 0xba, 0xd6, 0xca, 0x9d, 0xee, 0x51, 0x93},
+ },
+ MacSalt: []byte{1, 2, 3, 4, 5, 6, 7, 8},
+ Iterations: 2048,
+ }
+
+ message := []byte{11, 12, 13, 14, 15}
+ password, _ := bmpString("")
+
+ td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 3})
+ err := verifyMac(&td, message, password)
+ if _, ok := err.(NotImplementedError); !ok {
+ t.Errorf("err: %v", err)
+ }
+
+ td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
+ err = verifyMac(&td, message, password)
+ if err != ErrIncorrectPassword {
+ t.Errorf("Expected incorrect password, got err: %v", err)
+ }
+
+ password, _ = bmpString("Sesame open")
+ err = verifyMac(&td, message, password)
+ if err != nil {
+ t.Errorf("err: %v", err)
+ }
+
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/pbkdf.go b/vendor/golang.org/x/crypto/pkcs12/pbkdf.go
new file mode 100644
index 000000000..5c419d41e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/pbkdf.go
@@ -0,0 +1,170 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "bytes"
+ "crypto/sha1"
+ "math/big"
+)
+
+var (
+ one = big.NewInt(1)
+)
+
+// sha1Sum returns the SHA-1 hash of in.
+func sha1Sum(in []byte) []byte {
+ sum := sha1.Sum(in)
+ return sum[:]
+}
+
+// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of
+// repeats of pattern.
+func fillWithRepeats(pattern []byte, v int) []byte {
+ if len(pattern) == 0 {
+ return nil
+ }
+ outputLen := v * ((len(pattern) + v - 1) / v)
+ return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen]
+}
+
+func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
+ // implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments
+
+ // Let H be a hash function built around a compression function f:
+
+ // Z_2^u x Z_2^v -> Z_2^u
+
+ // (that is, H has a chaining variable and output of length u bits, and
+ // the message input to the compression function of H is v bits). The
+ // values for u and v are as follows:
+
+ // HASH FUNCTION VALUE u VALUE v
+ // MD2, MD5 128 512
+ // SHA-1 160 512
+ // SHA-224 224 512
+ // SHA-256 256 512
+ // SHA-384 384 1024
+ // SHA-512 512 1024
+ // SHA-512/224 224 1024
+ // SHA-512/256 256 1024
+
+ // Furthermore, let r be the iteration count.
+
+ // We assume here that u and v are both multiples of 8, as are the
+ // lengths of the password and salt strings (which we denote by p and s,
+ // respectively) and the number n of pseudorandom bits required. In
+ // addition, u and v are of course non-zero.
+
+ // For information on security considerations for MD5 [19], see [25] and
+ // [1], and on those for MD2, see [18].
+
+ // The following procedure can be used to produce pseudorandom bits for
+ // a particular "purpose" that is identified by a byte called "ID".
+ // This standard specifies 3 different values for the ID byte:
+
+ // 1. If ID=1, then the pseudorandom bits being produced are to be used
+ // as key material for performing encryption or decryption.
+
+ // 2. If ID=2, then the pseudorandom bits being produced are to be used
+ // as an IV (Initial Value) for encryption or decryption.
+
+ // 3. If ID=3, then the pseudorandom bits being produced are to be used
+ // as an integrity key for MACing.
+
+ // 1. Construct a string, D (the "diversifier"), by concatenating v/8
+ // copies of ID.
+ var D []byte
+ for i := 0; i < v; i++ {
+ D = append(D, ID)
+ }
+
+ // 2. Concatenate copies of the salt together to create a string S of
+ // length v(ceiling(s/v)) bits (the final copy of the salt may be
+ // truncated to create S). Note that if the salt is the empty
+ // string, then so is S.
+
+ S := fillWithRepeats(salt, v)
+
+ // 3. Concatenate copies of the password together to create a string P
+ // of length v(ceiling(p/v)) bits (the final copy of the password
+ // may be truncated to create P). Note that if the password is the
+ // empty string, then so is P.
+
+ P := fillWithRepeats(password, v)
+
+ // 4. Set I=S||P to be the concatenation of S and P.
+ I := append(S, P...)
+
+ // 5. Set c=ceiling(n/u).
+ c := (size + u - 1) / u
+
+ // 6. For i=1, 2, ..., c, do the following:
+ A := make([]byte, c*20)
+ var IjBuf []byte
+ for i := 0; i < c; i++ {
+ // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
+ // H(H(H(... H(D||I))))
+ Ai := hash(append(D, I...))
+ for j := 1; j < r; j++ {
+ Ai = hash(Ai)
+ }
+ copy(A[i*20:], Ai[:])
+
+ if i < c-1 { // skip on last iteration
+ // B. Concatenate copies of Ai to create a string B of length v
+ // bits (the final copy of Ai may be truncated to create B).
+ var B []byte
+ for len(B) < v {
+ B = append(B, Ai[:]...)
+ }
+ B = B[:v]
+
+ // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
+ // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
+ // setting I_j=(I_j+B+1) mod 2^v for each j.
+ {
+ Bbi := new(big.Int).SetBytes(B)
+ Ij := new(big.Int)
+
+ for j := 0; j < len(I)/v; j++ {
+ Ij.SetBytes(I[j*v : (j+1)*v])
+ Ij.Add(Ij, Bbi)
+ Ij.Add(Ij, one)
+ Ijb := Ij.Bytes()
+ // We expect Ijb to be exactly v bytes,
+ // if it is longer or shorter we must
+ // adjust it accordingly.
+ if len(Ijb) > v {
+ Ijb = Ijb[len(Ijb)-v:]
+ }
+ if len(Ijb) < v {
+ if IjBuf == nil {
+ IjBuf = make([]byte, v)
+ }
+ bytesShort := v - len(Ijb)
+ for i := 0; i < bytesShort; i++ {
+ IjBuf[i] = 0
+ }
+ copy(IjBuf[bytesShort:], Ijb)
+ Ijb = IjBuf
+ }
+ copy(I[j*v:(j+1)*v], Ijb)
+ }
+ }
+ }
+ }
+ // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
+ // bit string, A.
+
+ // 8. Use the first n bits of A as the output of this entire process.
+ return A[:size]
+
+ // If the above process is being used to generate a DES key, the process
+ // should be used to create 64 random bits, and the key's parity bits
+ // should be set after the 64 bits have been produced. Similar concerns
+ // hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any
+ // similar keys with parity bits "built into them".
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/pbkdf_test.go b/vendor/golang.org/x/crypto/pkcs12/pbkdf_test.go
new file mode 100644
index 000000000..262037d7e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/pbkdf_test.go
@@ -0,0 +1,34 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestThatPBKDFWorksCorrectlyForLongKeys(t *testing.T) {
+ cipherInfo := shaWithTripleDESCBC{}
+
+ salt := []byte("\xff\xff\xff\xff\xff\xff\xff\xff")
+ password, _ := bmpString("sesame")
+ key := cipherInfo.deriveKey(salt, password, 2048)
+
+ if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); bytes.Compare(key, expected) != 0 {
+ t.Fatalf("expected key '%x', but found '%x'", expected, key)
+ }
+}
+
+func TestThatPBKDFHandlesLeadingZeros(t *testing.T) {
+ // This test triggers a case where I_j (in step 6C) ends up with leading zero
+ // byte, meaning that len(Ijb) < v (leading zeros get stripped by big.Int).
+ // This was previously causing bug whereby certain inputs would break the
+ // derivation and produce the wrong output.
+ key := pbkdf(sha1Sum, 20, 64, []byte("\xf3\x7e\x05\xb5\x18\x32\x4b\x4b"), []byte("\x00\x00"), 2048, 1, 24)
+ expected := []byte("\x00\xf7\x59\xff\x47\xd1\x4d\xd0\x36\x65\xd5\x94\x3c\xb3\xc4\xa3\x9a\x25\x55\xc0\x2a\xed\x66\xe1")
+ if bytes.Compare(key, expected) != 0 {
+ t.Fatalf("expected key '%x', but found '%x'", expected, key)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/pkcs12.go b/vendor/golang.org/x/crypto/pkcs12/pkcs12.go
new file mode 100644
index 000000000..ad6341e60
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/pkcs12.go
@@ -0,0 +1,342 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkcs12 implements some of PKCS#12.
+//
+// This implementation is distilled from https://tools.ietf.org/html/rfc7292
+// and referenced documents. It is intended for decoding P12/PFX-stored
+// certificates and keys for use with the crypto/tls package.
+package pkcs12
+
+import (
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/hex"
+ "encoding/pem"
+ "errors"
+)
+
+var (
+ oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
+ oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
+
+ oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
+ oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
+ oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
+)
+
+type pfxPdu struct {
+ Version int
+ AuthSafe contentInfo
+ MacData macData `asn1:"optional"`
+}
+
+type contentInfo struct {
+ ContentType asn1.ObjectIdentifier
+ Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
+}
+
+type encryptedData struct {
+ Version int
+ EncryptedContentInfo encryptedContentInfo
+}
+
+type encryptedContentInfo struct {
+ ContentType asn1.ObjectIdentifier
+ ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
+ EncryptedContent []byte `asn1:"tag:0,optional"`
+}
+
+func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
+ return i.ContentEncryptionAlgorithm
+}
+
+func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
+
+type safeBag struct {
+ Id asn1.ObjectIdentifier
+ Value asn1.RawValue `asn1:"tag:0,explicit"`
+ Attributes []pkcs12Attribute `asn1:"set,optional"`
+}
+
+type pkcs12Attribute struct {
+ Id asn1.ObjectIdentifier
+ Value asn1.RawValue `asn1:"set"`
+}
+
+type encryptedPrivateKeyInfo struct {
+ AlgorithmIdentifier pkix.AlgorithmIdentifier
+ EncryptedData []byte
+}
+
+func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
+ return i.AlgorithmIdentifier
+}
+
+func (i encryptedPrivateKeyInfo) Data() []byte {
+ return i.EncryptedData
+}
+
+// PEM block types
+const (
+ certificateType = "CERTIFICATE"
+ privateKeyType = "PRIVATE KEY"
+)
+
+// unmarshal calls asn1.Unmarshal, but also returns an error if there is any
+// trailing data after unmarshaling.
+func unmarshal(in []byte, out interface{}) error {
+ trailing, err := asn1.Unmarshal(in, out)
+ if err != nil {
+ return err
+ }
+ if len(trailing) != 0 {
+ return errors.New("pkcs12: trailing data found")
+ }
+ return nil
+}
+
+// ConvertToPEM converts all "safe bags" contained in pfxData to PEM blocks.
+func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
+ encodedPassword, err := bmpString(password)
+ if err != nil {
+ return nil, ErrIncorrectPassword
+ }
+
+ bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
+
+ blocks := make([]*pem.Block, 0, len(bags))
+ for _, bag := range bags {
+ block, err := convertBag(&bag, encodedPassword)
+ if err != nil {
+ return nil, err
+ }
+ blocks = append(blocks, block)
+ }
+
+ return blocks, nil
+}
+
+func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
+ block := &pem.Block{
+ Headers: make(map[string]string),
+ }
+
+ for _, attribute := range bag.Attributes {
+ k, v, err := convertAttribute(&attribute)
+ if err != nil {
+ return nil, err
+ }
+ block.Headers[k] = v
+ }
+
+ switch {
+ case bag.Id.Equal(oidCertBag):
+ block.Type = certificateType
+ certsData, err := decodeCertBag(bag.Value.Bytes)
+ if err != nil {
+ return nil, err
+ }
+ block.Bytes = certsData
+ case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
+ block.Type = privateKeyType
+
+ key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
+ if err != nil {
+ return nil, err
+ }
+
+ switch key := key.(type) {
+ case *rsa.PrivateKey:
+ block.Bytes = x509.MarshalPKCS1PrivateKey(key)
+ case *ecdsa.PrivateKey:
+ block.Bytes, err = x509.MarshalECPrivateKey(key)
+ if err != nil {
+ return nil, err
+ }
+ default:
+ return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
+ }
+ default:
+ return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
+ }
+ return block, nil
+}
+
+func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
+ isString := false
+
+ switch {
+ case attribute.Id.Equal(oidFriendlyName):
+ key = "friendlyName"
+ isString = true
+ case attribute.Id.Equal(oidLocalKeyID):
+ key = "localKeyId"
+ case attribute.Id.Equal(oidMicrosoftCSPName):
+ // This key is chosen to match OpenSSL.
+ key = "Microsoft CSP Name"
+ isString = true
+ default:
+ return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
+ }
+
+ if isString {
+ if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
+ return "", "", err
+ }
+ if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
+ return "", "", err
+ }
+ } else {
+ var id []byte
+ if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
+ return "", "", err
+ }
+ value = hex.EncodeToString(id)
+ }
+
+ return key, value, nil
+}
+
+// Decode extracts a certificate and private key from pfxData. This function
+// assumes that there is only one certificate and only one private key in the
+// pfxData.
+func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
+ encodedPassword, err := bmpString(password)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if len(bags) != 2 {
+ err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
+ return
+ }
+
+ for _, bag := range bags {
+ switch {
+ case bag.Id.Equal(oidCertBag):
+ if certificate != nil {
+ err = errors.New("pkcs12: expected exactly one certificate bag")
+ }
+
+ certsData, err := decodeCertBag(bag.Value.Bytes)
+ if err != nil {
+ return nil, nil, err
+ }
+ certs, err := x509.ParseCertificates(certsData)
+ if err != nil {
+ return nil, nil, err
+ }
+ if len(certs) != 1 {
+ err = errors.New("pkcs12: expected exactly one certificate in the certBag")
+ return nil, nil, err
+ }
+ certificate = certs[0]
+
+ case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
+ if privateKey != nil {
+ err = errors.New("pkcs12: expected exactly one key bag")
+ }
+
+ if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
+ return nil, nil, err
+ }
+ }
+ }
+
+ if certificate == nil {
+ return nil, nil, errors.New("pkcs12: certificate missing")
+ }
+ if privateKey == nil {
+ return nil, nil, errors.New("pkcs12: private key missing")
+ }
+
+ return
+}
+
+func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
+ pfx := new(pfxPdu)
+ if err := unmarshal(p12Data, pfx); err != nil {
+ return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
+ }
+
+ if pfx.Version != 3 {
+ return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
+ }
+
+ if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
+ return nil, nil, NotImplementedError("only password-protected PFX is implemented")
+ }
+
+ // unmarshal the explicit bytes in the content for type 'data'
+ if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
+ return nil, nil, err
+ }
+
+ if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
+ return nil, nil, errors.New("pkcs12: no MAC in data")
+ }
+
+ if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
+ if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
+ // some implementations use an empty byte array
+ // for the empty string password try one more
+ // time with empty-empty password
+ password = nil
+ err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+ }
+
+ var authenticatedSafe []contentInfo
+ if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
+ return nil, nil, err
+ }
+
+ if len(authenticatedSafe) != 2 {
+ return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
+ }
+
+ for _, ci := range authenticatedSafe {
+ var data []byte
+
+ switch {
+ case ci.ContentType.Equal(oidDataContentType):
+ if err := unmarshal(ci.Content.Bytes, &data); err != nil {
+ return nil, nil, err
+ }
+ case ci.ContentType.Equal(oidEncryptedDataContentType):
+ var encryptedData encryptedData
+ if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
+ return nil, nil, err
+ }
+ if encryptedData.Version != 0 {
+ return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
+ }
+ if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
+ return nil, nil, err
+ }
+ default:
+ return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
+ }
+
+ var safeContents []safeBag
+ if err := unmarshal(data, &safeContents); err != nil {
+ return nil, nil, err
+ }
+ bags = append(bags, safeContents...)
+ }
+
+ return bags, password, nil
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/pkcs12_test.go b/vendor/golang.org/x/crypto/pkcs12/pkcs12_test.go
new file mode 100644
index 000000000..14dd2a6c5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/pkcs12_test.go
@@ -0,0 +1,138 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "crypto/rsa"
+ "crypto/tls"
+ "encoding/base64"
+ "encoding/pem"
+ "testing"
+)
+
+func TestPfx(t *testing.T) {
+ for commonName, base64P12 := range testdata {
+ p12, _ := base64.StdEncoding.DecodeString(base64P12)
+
+ priv, cert, err := Decode(p12, "")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err := priv.(*rsa.PrivateKey).Validate(); err != nil {
+ t.Errorf("error while validating private key: %v", err)
+ }
+
+ if cert.Subject.CommonName != commonName {
+ t.Errorf("expected common name to be %q, but found %q", commonName, cert.Subject.CommonName)
+ }
+ }
+}
+
+func TestPEM(t *testing.T) {
+ for commonName, base64P12 := range testdata {
+ p12, _ := base64.StdEncoding.DecodeString(base64P12)
+
+ blocks, err := ToPEM(p12, "")
+ if err != nil {
+ t.Fatalf("error while converting to PEM: %s", err)
+ }
+
+ var pemData []byte
+ for _, b := range blocks {
+ pemData = append(pemData, pem.EncodeToMemory(b)...)
+ }
+
+ cert, err := tls.X509KeyPair(pemData, pemData)
+ if err != nil {
+ t.Errorf("err while converting to key pair: %v", err)
+ }
+ config := tls.Config{
+ Certificates: []tls.Certificate{cert},
+ }
+ config.BuildNameToCertificate()
+
+ if _, exists := config.NameToCertificate[commonName]; !exists {
+ t.Errorf("did not find our cert in PEM?: %v", config.NameToCertificate)
+ }
+ }
+}
+
+func ExampleToPEM() {
+ p12, _ := base64.StdEncoding.DecodeString(`MIIJzgIBAzCCCZQGCS ... CA+gwggPk==`)
+
+ blocks, err := ToPEM(p12, "password")
+ if err != nil {
+ panic(err)
+ }
+
+ var pemData []byte
+ for _, b := range blocks {
+ pemData = append(pemData, pem.EncodeToMemory(b)...)
+ }
+
+ // then use PEM data for tls to construct tls certificate:
+ cert, err := tls.X509KeyPair(pemData, pemData)
+ if err != nil {
+ panic(err)
+ }
+
+ config := &tls.Config{
+ Certificates: []tls.Certificate{cert},
+ }
+
+ _ = config
+}
+
+var testdata = map[string]string{
+ // 'null' password test case
+ "Windows Azure Tools": `MIIKDAIBAzCCCcwGCSqGSIb3DQEHAaCCCb0Eggm5MIIJtTCCBe4GCSqGSIb3DQEHAaCCBd8EggXbMIIF1zCCBdMGCyqGSIb3DQEMCgECoIIE7jCCBOowHAYKKoZIhvcNAQwBAzAOBAhStUNnlTGV+gICB9AEggTIJ81JIossF6boFWpPtkiQRPtI6DW6e9QD4/WvHAVrM2bKdpMzSMsCML5NyuddANTKHBVq00Jc9keqGNAqJPKkjhSUebzQFyhe0E1oI9T4zY5UKr/I8JclOeccH4QQnsySzYUG2SnniXnQ+JrG3juetli7EKth9h6jLc6xbubPadY5HMB3wL/eG/kJymiXwU2KQ9Mgd4X6jbcV+NNCE/8jbZHvSTCPeYTJIjxfeX61Sj5kFKUCzERbsnpyevhY3X0eYtEDezZQarvGmXtMMdzf8HJHkWRdk9VLDLgjk8uiJif/+X4FohZ37ig0CpgC2+dP4DGugaZZ51hb8tN9GeCKIsrmWogMXDIVd0OACBp/EjJVmFB6y0kUCXxUE0TZt0XA1tjAGJcjDUpBvTntZjPsnH/4ZySy+s2d9OOhJ6pzRQBRm360TzkFdSwk9DLiLdGfv4pwMMu/vNGBlqjP/1sQtj+jprJiD1sDbCl4AdQZVoMBQHadF2uSD4/o17XG/Ci0r2h6Htc2yvZMAbEY4zMjjIn2a+vqIxD6onexaek1R3zbkS9j19D6EN9EWn8xgz80YRCyW65znZk8xaIhhvlU/mg7sTxeyuqroBZNcq6uDaQTehDpyH7bY2l4zWRpoj10a6JfH2q5shYz8Y6UZC/kOTfuGqbZDNZWro/9pYquvNNW0M847E5t9bsf9VkAAMHRGBbWoVoU9VpI0UnoXSfvpOo+aXa2DSq5sHHUTVY7A9eov3z5IqT+pligx11xcs+YhDWcU8di3BTJisohKvv5Y8WSkm/rloiZd4ig269k0jTRk1olP/vCksPli4wKG2wdsd5o42nX1yL7mFfXocOANZbB+5qMkiwdyoQSk+Vq+C8nAZx2bbKhUq2MbrORGMzOe0Hh0x2a0PeObycN1Bpyv7Mp3ZI9h5hBnONKCnqMhtyQHUj/nNvbJUnDVYNfoOEqDiEqqEwB7YqWzAKz8KW0OIqdlM8uiQ4JqZZlFllnWJUfaiDrdFM3lYSnFQBkzeVlts6GpDOOBjCYd7dcCNS6kq6pZC6p6HN60Twu0JnurZD6RT7rrPkIGE8vAenFt4iGe/yF52fahCSY8Ws4K0UTwN7bAS+4xRHVCWvE8sMRZsRCHizb5laYsVrPZJhE6+hux6OBb6w8kwPYXc+ud5v6UxawUWgt6uPwl8mlAtU9Z7Miw4Nn/wtBkiLL/ke1UI1gqJtcQXgHxx6mzsjh41+nAgTvdbsSEyU6vfOmxGj3Rwc1eOrIhJUqn5YjOWfzzsz/D5DzWKmwXIwdspt1p+u+kol1N3f2wT9fKPnd/RGCb4g/1hc3Aju4DQYgGY782l89CEEdalpQ/35bQczMFk6Fje12HykakWEXd/bGm9Unh82gH84USiRpeOfQvBDYoqEyrY3zkFZzBjhDqa+jEcAj41tcGx47oSfDq3iVYCdL7HSIjtnyEktVXd7mISZLoMt20JACFcMw+mrbjlug+eU7o2GR7T+LwtOp/p4LZqyLa7oQJDwde1BNZtm3TCK2P1mW94QDL0nDUps5KLtr1DaZXEkRbjSJub2ZE9WqDHyU3KA8G84Tq/rN1IoNu/if45jacyPje1Npj9IftUZSP22nV7HMwZtwQ4P4MYHRMBMGCSqGSIb3DQEJFTEGBAQBAAAAMFsGCSqGSIb3DQEJFDFOHkwAewBCADQAQQA0AEYARQBCADAALQBBADEAOABBAC0ANAA0AEIAQgAtAEIANQBGADIALQA0ADkAMQBFAEYAMQA1ADIAQgBBADEANgB9MF0GCSsGAQQBgjcRATFQHk4ATQBpAGMAcgBvAHMAbwBmAHQAIABTAG8AZgB0AHcAYQByAGUAIABLAGUAeQAgAFMAdABvAHIAYQBnAGUAIABQAHIAbwB2AGkAZABlAHIwggO/BgkqhkiG9w0BBwagggOwMIIDrAIBADCCA6UGCSqGSIb3DQEHATAcBgoqhkiG9w0BDAEGMA4ECEBk5ZAYpu0WAgIH0ICCA3hik4mQFGpw9Ha8TQPtk+j2jwWdxfF0+sTk6S8PTsEfIhB7wPltjiCK92Uv2tCBQnodBUmatIfkpnRDEySmgmdglmOCzj204lWAMRs94PoALGn3JVBXbO1vIDCbAPOZ7Z0Hd0/1t2hmk8v3//QJGUg+qr59/4y/MuVfIg4qfkPcC2QSvYWcK3oTf6SFi5rv9B1IOWFgN5D0+C+x/9Lb/myPYX+rbOHrwtJ4W1fWKoz9g7wwmGFA9IJ2DYGuH8ifVFbDFT1Vcgsvs8arSX7oBsJVW0qrP7XkuDRe3EqCmKW7rBEwYrFznhxZcRDEpMwbFoSvgSIZ4XhFY9VKYglT+JpNH5iDceYEBOQL4vBLpxNUk3l5jKaBNxVa14AIBxq18bVHJ+STInhLhad4u10v/Xbx7wIL3f9DX1yLAkPrpBYbNHS2/ew6H/ySDJnoIDxkw2zZ4qJ+qUJZ1S0lbZVG+VT0OP5uF6tyOSpbMlcGkdl3z254n6MlCrTifcwkzscysDsgKXaYQw06rzrPW6RDub+t+hXzGny799fS9jhQMLDmOggaQ7+LA4oEZsfT89HLMWxJYDqjo3gIfjciV2mV54R684qLDS+AO09U49e6yEbwGlq8lpmO/pbXCbpGbB1b3EomcQbxdWxW2WEkkEd/VBn81K4M3obmywwXJkw+tPXDXfBmzzaqqCR+onMQ5ME1nMkY8ybnfoCc1bDIupjVWsEL2Wvq752RgI6KqzVNr1ew1IdqV5AWN2fOfek+0vi3Jd9FHF3hx8JMwjJL9dZsETV5kHtYJtE7wJ23J68BnCt2eI0GEuwXcCf5EdSKN/xXCTlIokc4Qk/gzRdIZsvcEJ6B1lGovKG54X4IohikqTjiepjbsMWj38yxDmK3mtENZ9ci8FPfbbvIEcOCZIinuY3qFUlRSbx7VUerEoV1IP3clUwexVQo4lHFee2jd7ocWsdSqSapW7OWUupBtDzRkqVhE7tGria+i1W2d6YLlJ21QTjyapWJehAMO637OdbJCCzDs1cXbodRRE7bsP492ocJy8OX66rKdhYbg8srSFNKdb3pF3UDNbN9jhI/t8iagRhNBhlQtTr1me2E/c86Q18qcRXl4bcXTt6acgCeffK6Y26LcVlrgjlD33AEYRRUeyC+rpxbT0aMjdFderlndKRIyG23mSp0HaUwNzAfMAcGBSsOAwIaBBRlviCbIyRrhIysg2dc/KbLFTc2vQQUg4rfwHMM4IKYRD/fsd1x6dda+wQ=`,
+ // empty string password test case
+ "testing@example.com": `MIIJzgIBAzCCCZQGCSqGSIb3DQEHAaCCCYUEggmBMIIJfTCCA/cGCSqGSIb3DQEHBqCCA+gwggPk
+AgEAMIID3QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIIszfRGqcmPcCAggAgIIDsOZ9Eg1L
+s5Wx8JhYoV3HAL4aRnkAWvTYB5NISZOgSgIQTssmt/3A7134dibTmaT/93LikkL3cTKLnQzJ4wDf
+YZ1bprpVJvUqz+HFT79m27bP9zYXFrvxWBJbxjYKTSjQMgz+h8LAEpXXGajCmxMJ1oCOtdXkhhzc
+LdZN6SAYgtmtyFnCdMEDskSggGuLb3fw84QEJ/Sj6FAULXunW/CPaS7Ce0TMsKmNU/jfFWj3yXXw
+ro0kwjKiVLpVFlnBlHo2OoVU7hmkm59YpGhLgS7nxLD3n7nBroQ0ID1+8R01NnV9XLGoGzxMm1te
+6UyTCkr5mj+kEQ8EP1Ys7g/TC411uhVWySMt/rcpkx7Vz1r9kYEAzJpONAfr6cuEVkPKrxpq4Fh0
+2fzlKBky0i/hrfIEUmngh+ERHUb/Mtv/fkv1j5w9suESbhsMLLiCXAlsP1UWMX+3bNizi3WVMEts
+FM2k9byn+p8IUD/A8ULlE4kEaWeoc+2idkCNQkLGuIdGUXUFVm58se0auUkVRoRJx8x4CkMesT8j
+b1H831W66YRWoEwwDQp2kK1lA2vQXxdVHWlFevMNxJeromLzj3ayiaFrfByeUXhR2S+Hpm+c0yNR
+4UVU9WED2kacsZcpRm9nlEa5sr28mri5JdBrNa/K02OOhvKCxr5ZGmbOVzUQKla2z4w+Ku9k8POm
+dfDNU/fGx1b5hcFWtghXe3msWVsSJrQihnN6q1ughzNiYZlJUGcHdZDRtiWwCFI0bR8h/Dmg9uO9
+4rawQQrjIRT7B8yF3UbkZyAqs8Ppb1TsMeNPHh1rxEfGVQknh/48ouJYsmtbnzugTUt3mJCXXiL+
+XcPMV6bBVAUu4aaVKSmg9+yJtY4/VKv10iw88ktv29fViIdBe3t6l/oPuvQgbQ8dqf4T8w0l/uKZ
+9lS1Na9jfT1vCoS7F5TRi+tmyj1vL5kr/amEIW6xKEP6oeAMvCMtbPAzVEj38zdJ1R22FfuIBxkh
+f0Zl7pdVbmzRxl/SBx9iIBJSqAvcXItiT0FIj8HxQ+0iZKqMQMiBuNWJf5pYOLWGrIyntCWwHuaQ
+wrx0sTGuEL9YXLEAsBDrsvzLkx/56E4INGZFrH8G7HBdW6iGqb22IMI4GHltYSyBRKbB0gadYTyv
+abPEoqww8o7/85aPSzOTJ/53ozD438Q+d0u9SyDuOb60SzCD/zPuCEd78YgtXJwBYTuUNRT27FaM
+3LGMX8Hz+6yPNRnmnA2XKPn7dx/IlaqAjIs8MIIFfgYJKoZIhvcNAQcBoIIFbwSCBWswggVnMIIF
+YwYLKoZIhvcNAQwKAQKgggTuMIIE6jAcBgoqhkiG9w0BDAEDMA4ECJr0cClYqOlcAgIIAASCBMhe
+OQSiP2s0/46ONXcNeVAkz2ksW3u/+qorhSiskGZ0b3dFa1hhgBU2Q7JVIkc4Hf7OXaT1eVQ8oqND
+uhqsNz83/kqYo70+LS8Hocj49jFgWAKrf/yQkdyP1daHa2yzlEw4mkpqOfnIORQHvYCa8nEApspZ
+wVu8y6WVuLHKU67mel7db2xwstQp7PRuSAYqGjTfAylElog8ASdaqqYbYIrCXucF8iF9oVgmb/Qo
+xrXshJ9aSLO4MuXlTPELmWgj07AXKSb90FKNihE+y0bWb9LPVFY1Sly3AX9PfrtkSXIZwqW3phpv
+MxGxQl/R6mr1z+hlTfY9Wdpb5vlKXPKA0L0Rt8d2pOesylFi6esJoS01QgP1kJILjbrV731kvDc0
+Jsd+Oxv4BMwA7ClG8w1EAOInc/GrV1MWFGw/HeEqj3CZ/l/0jv9bwkbVeVCiIhoL6P6lVx9pXq4t
+KZ0uKg/tk5TVJmG2vLcMLvezD0Yk3G2ZOMrywtmskrwoF7oAUpO9e87szoH6fEvUZlkDkPVW1NV4
+cZk3DBSQiuA3VOOg8qbo/tx/EE3H59P0axZWno2GSB0wFPWd1aj+b//tJEJHaaNR6qPRj4IWj9ru
+Qbc8eRAcVWleHg8uAehSvUXlFpyMQREyrnpvMGddpiTC8N4UMrrBRhV7+UbCOWhxPCbItnInBqgl
+1JpSZIP7iUtsIMdu3fEC2cdbXMTRul+4rdzUR7F9OaezV3jjvcAbDvgbK1CpyC+MJ1Mxm/iTgk9V
+iUArydhlR8OniN84GyGYoYCW9O/KUwb6ASmeFOu/msx8x6kAsSQHIkKqMKv0TUR3kZnkxUvdpBGP
+KTl4YCTvNGX4dYALBqrAETRDhua2KVBD/kEttDHwBNVbN2xi81+Mc7ml461aADfk0c66R/m2sjHB
+2tN9+wG12OIWFQjL6wF/UfJMYamxx2zOOExiId29Opt57uYiNVLOO4ourPewHPeH0u8Gz35aero7
+lkt7cZAe1Q0038JUuE/QGlnK4lESK9UkSIQAjSaAlTsrcfwtQxB2EjoOoLhwH5mvxUEmcNGNnXUc
+9xj3M5BD3zBz3Ft7G3YMMDwB1+zC2l+0UG0MGVjMVaeoy32VVNvxgX7jk22OXG1iaOB+PY9kdk+O
+X+52BGSf/rD6X0EnqY7XuRPkMGgjtpZeAYxRQnFtCZgDY4wYheuxqSSpdF49yNczSPLkgB3CeCfS
++9NTKN7aC6hBbmW/8yYh6OvSiCEwY0lFS/T+7iaVxr1loE4zI1y/FFp4Pe1qfLlLttVlkygga2UU
+SCunTQ8UB/M5IXWKkhMOO11dP4niWwb39Y7pCWpau7mwbXOKfRPX96cgHnQJK5uG+BesDD1oYnX0
+6frN7FOnTSHKruRIwuI8KnOQ/I+owmyz71wiv5LMQt+yM47UrEjB/EZa5X8dpEwOZvkdqL7utcyo
+l0XH5kWMXdW856LL/FYftAqJIDAmtX1TXF/rbP6mPyN/IlDC0gjP84Uzd/a2UyTIWr+wk49Ek3vQ
+/uDamq6QrwAxVmNh5Tset5Vhpc1e1kb7mRMZIzxSP8JcTuYd45oFKi98I8YjvueHVZce1g7OudQP
+SbFQoJvdT46iBg1TTatlltpOiH2mFaxWVS0xYjAjBgkqhkiG9w0BCRUxFgQUdA9eVqvETX4an/c8
+p8SsTugkit8wOwYJKoZIhvcNAQkUMS4eLABGAHIAaQBlAG4AZABsAHkAIABuAGEAbQBlACAAZgBv
+AHIAIABjAGUAcgB0MDEwITAJBgUrDgMCGgUABBRFsNz3Zd1O1GI8GTuFwCWuDOjEEwQIuBEfIcAy
+HQ8CAggA`,
+}
diff --git a/vendor/golang.org/x/crypto/pkcs12/safebags.go b/vendor/golang.org/x/crypto/pkcs12/safebags.go
new file mode 100644
index 000000000..def1f7b98
--- /dev/null
+++ b/vendor/golang.org/x/crypto/pkcs12/safebags.go
@@ -0,0 +1,57 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pkcs12
+
+import (
+ "crypto/x509"
+ "encoding/asn1"
+ "errors"
+)
+
+var (
+ // see https://tools.ietf.org/html/rfc7292#appendix-D
+ oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1})
+ oidPKCS8ShroundedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2})
+ oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3})
+)
+
+type certBag struct {
+ Id asn1.ObjectIdentifier
+ Data []byte `asn1:"tag:0,explicit"`
+}
+
+func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) {
+ pkinfo := new(encryptedPrivateKeyInfo)
+ if err = unmarshal(asn1Data, pkinfo); err != nil {
+ return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error())
+ }
+
+ pkData, err := pbDecrypt(pkinfo, password)
+ if err != nil {
+ return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error())
+ }
+
+ ret := new(asn1.RawValue)
+ if err = unmarshal(pkData, ret); err != nil {
+ return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error())
+ }
+
+ if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil {
+ return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error())
+ }
+
+ return privateKey, nil
+}
+
+func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) {
+ bag := new(certBag)
+ if err := unmarshal(asn1Data, bag); err != nil {
+ return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error())
+ }
+ if !bag.Id.Equal(oidCertTypeX509Certificate) {
+ return nil, NotImplementedError("only X509 certificates are supported")
+ }
+ return bag.Data, nil
+}
diff --git a/vendor/golang.org/x/crypto/poly1305/const_amd64.s b/vendor/golang.org/x/crypto/poly1305/const_amd64.s
new file mode 100644
index 000000000..8e861f337
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/const_amd64.s
@@ -0,0 +1,45 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+DATA ·SCALE(SB)/8, $0x37F4000000000000
+GLOBL ·SCALE(SB), 8, $8
+DATA ·TWO32(SB)/8, $0x41F0000000000000
+GLOBL ·TWO32(SB), 8, $8
+DATA ·TWO64(SB)/8, $0x43F0000000000000
+GLOBL ·TWO64(SB), 8, $8
+DATA ·TWO96(SB)/8, $0x45F0000000000000
+GLOBL ·TWO96(SB), 8, $8
+DATA ·ALPHA32(SB)/8, $0x45E8000000000000
+GLOBL ·ALPHA32(SB), 8, $8
+DATA ·ALPHA64(SB)/8, $0x47E8000000000000
+GLOBL ·ALPHA64(SB), 8, $8
+DATA ·ALPHA96(SB)/8, $0x49E8000000000000
+GLOBL ·ALPHA96(SB), 8, $8
+DATA ·ALPHA130(SB)/8, $0x4C08000000000000
+GLOBL ·ALPHA130(SB), 8, $8
+DATA ·DOFFSET0(SB)/8, $0x4330000000000000
+GLOBL ·DOFFSET0(SB), 8, $8
+DATA ·DOFFSET1(SB)/8, $0x4530000000000000
+GLOBL ·DOFFSET1(SB), 8, $8
+DATA ·DOFFSET2(SB)/8, $0x4730000000000000
+GLOBL ·DOFFSET2(SB), 8, $8
+DATA ·DOFFSET3(SB)/8, $0x4930000000000000
+GLOBL ·DOFFSET3(SB), 8, $8
+DATA ·DOFFSET3MINUSTWO128(SB)/8, $0x492FFFFE00000000
+GLOBL ·DOFFSET3MINUSTWO128(SB), 8, $8
+DATA ·HOFFSET0(SB)/8, $0x43300001FFFFFFFB
+GLOBL ·HOFFSET0(SB), 8, $8
+DATA ·HOFFSET1(SB)/8, $0x45300001FFFFFFFE
+GLOBL ·HOFFSET1(SB), 8, $8
+DATA ·HOFFSET2(SB)/8, $0x47300001FFFFFFFE
+GLOBL ·HOFFSET2(SB), 8, $8
+DATA ·HOFFSET3(SB)/8, $0x49300003FFFFFFFE
+GLOBL ·HOFFSET3(SB), 8, $8
+DATA ·ROUNDING(SB)/2, $0x137f
+GLOBL ·ROUNDING(SB), 8, $2
diff --git a/vendor/golang.org/x/crypto/poly1305/poly1305.go b/vendor/golang.org/x/crypto/poly1305/poly1305.go
new file mode 100644
index 000000000..4a5f826f7
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/poly1305.go
@@ -0,0 +1,32 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package poly1305 implements Poly1305 one-time message authentication code as specified in http://cr.yp.to/mac/poly1305-20050329.pdf.
+
+Poly1305 is a fast, one-time authentication function. It is infeasible for an
+attacker to generate an authenticator for a message without the key. However, a
+key must only be used for a single message. Authenticating two different
+messages with the same key allows an attacker to forge authenticators for other
+messages with the same key.
+
+Poly1305 was originally coupled with AES in order to make Poly1305-AES. AES was
+used with a fixed key in order to generate one-time keys from an nonce.
+However, in this package AES isn't used and the one-time key is specified
+directly.
+*/
+package poly1305 // import "golang.org/x/crypto/poly1305"
+
+import "crypto/subtle"
+
+// TagSize is the size, in bytes, of a poly1305 authenticator.
+const TagSize = 16
+
+// Verify returns true if mac is a valid authenticator for m with the given
+// key.
+func Verify(mac *[16]byte, m []byte, key *[32]byte) bool {
+ var tmp [16]byte
+ Sum(&tmp, m, key)
+ return subtle.ConstantTimeCompare(tmp[:], mac[:]) == 1
+}
diff --git a/vendor/golang.org/x/crypto/poly1305/poly1305_amd64.s b/vendor/golang.org/x/crypto/poly1305/poly1305_amd64.s
new file mode 100644
index 000000000..f8d4ee928
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/poly1305_amd64.s
@@ -0,0 +1,497 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// +build amd64,!gccgo,!appengine
+
+// func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]key)
+TEXT ·poly1305(SB),0,$224-32
+ MOVQ out+0(FP),DI
+ MOVQ m+8(FP),SI
+ MOVQ mlen+16(FP),DX
+ MOVQ key+24(FP),CX
+
+ MOVQ SP,R11
+ MOVQ $31,R9
+ NOTQ R9
+ ANDQ R9,SP
+ ADDQ $32,SP
+
+ MOVQ R11,32(SP)
+ MOVQ R12,40(SP)
+ MOVQ R13,48(SP)
+ MOVQ R14,56(SP)
+ MOVQ R15,64(SP)
+ MOVQ BX,72(SP)
+ MOVQ BP,80(SP)
+ FLDCW ·ROUNDING(SB)
+ MOVL 0(CX),R8
+ MOVL 4(CX),R9
+ MOVL 8(CX),AX
+ MOVL 12(CX),R10
+ MOVQ DI,88(SP)
+ MOVQ CX,96(SP)
+ MOVL $0X43300000,108(SP)
+ MOVL $0X45300000,116(SP)
+ MOVL $0X47300000,124(SP)
+ MOVL $0X49300000,132(SP)
+ ANDL $0X0FFFFFFF,R8
+ ANDL $0X0FFFFFFC,R9
+ ANDL $0X0FFFFFFC,AX
+ ANDL $0X0FFFFFFC,R10
+ MOVL R8,104(SP)
+ MOVL R9,112(SP)
+ MOVL AX,120(SP)
+ MOVL R10,128(SP)
+ FMOVD 104(SP), F0
+ FSUBD ·DOFFSET0(SB), F0
+ FMOVD 112(SP), F0
+ FSUBD ·DOFFSET1(SB), F0
+ FMOVD 120(SP), F0
+ FSUBD ·DOFFSET2(SB), F0
+ FMOVD 128(SP), F0
+ FSUBD ·DOFFSET3(SB), F0
+ FXCHD F0, F3
+ FMOVDP F0, 136(SP)
+ FXCHD F0, F1
+ FMOVD F0, 144(SP)
+ FMULD ·SCALE(SB), F0
+ FMOVDP F0, 152(SP)
+ FMOVD F0, 160(SP)
+ FMULD ·SCALE(SB), F0
+ FMOVDP F0, 168(SP)
+ FMOVD F0, 176(SP)
+ FMULD ·SCALE(SB), F0
+ FMOVDP F0, 184(SP)
+ FLDZ
+ FLDZ
+ FLDZ
+ FLDZ
+ CMPQ DX,$16
+ JB ADDATMOST15BYTES
+ INITIALATLEAST16BYTES:
+ MOVL 12(SI),DI
+ MOVL 8(SI),CX
+ MOVL 4(SI),R8
+ MOVL 0(SI),R9
+ MOVL DI,128(SP)
+ MOVL CX,120(SP)
+ MOVL R8,112(SP)
+ MOVL R9,104(SP)
+ ADDQ $16,SI
+ SUBQ $16,DX
+ FXCHD F0, F3
+ FADDD 128(SP), F0
+ FSUBD ·DOFFSET3MINUSTWO128(SB), F0
+ FXCHD F0, F1
+ FADDD 112(SP), F0
+ FSUBD ·DOFFSET1(SB), F0
+ FXCHD F0, F2
+ FADDD 120(SP), F0
+ FSUBD ·DOFFSET2(SB), F0
+ FXCHD F0, F3
+ FADDD 104(SP), F0
+ FSUBD ·DOFFSET0(SB), F0
+ CMPQ DX,$16
+ JB MULTIPLYADDATMOST15BYTES
+ MULTIPLYADDATLEAST16BYTES:
+ MOVL 12(SI),DI
+ MOVL 8(SI),CX
+ MOVL 4(SI),R8
+ MOVL 0(SI),R9
+ MOVL DI,128(SP)
+ MOVL CX,120(SP)
+ MOVL R8,112(SP)
+ MOVL R9,104(SP)
+ ADDQ $16,SI
+ SUBQ $16,DX
+ FMOVD ·ALPHA130(SB), F0
+ FADDD F2,F0
+ FSUBD ·ALPHA130(SB), F0
+ FSUBD F0,F2
+ FMULD ·SCALE(SB), F0
+ FMOVD ·ALPHA32(SB), F0
+ FADDD F2,F0
+ FSUBD ·ALPHA32(SB), F0
+ FSUBD F0,F2
+ FXCHD F0, F2
+ FADDDP F0,F1
+ FMOVD ·ALPHA64(SB), F0
+ FADDD F4,F0
+ FSUBD ·ALPHA64(SB), F0
+ FSUBD F0,F4
+ FMOVD ·ALPHA96(SB), F0
+ FADDD F6,F0
+ FSUBD ·ALPHA96(SB), F0
+ FSUBD F0,F6
+ FXCHD F0, F6
+ FADDDP F0,F1
+ FXCHD F0, F3
+ FADDDP F0,F5
+ FXCHD F0, F3
+ FADDDP F0,F1
+ FMOVD 176(SP), F0
+ FMULD F3,F0
+ FMOVD 160(SP), F0
+ FMULD F4,F0
+ FMOVD 144(SP), F0
+ FMULD F5,F0
+ FMOVD 136(SP), F0
+ FMULDP F0,F6
+ FMOVD 160(SP), F0
+ FMULD F4,F0
+ FADDDP F0,F3
+ FMOVD 144(SP), F0
+ FMULD F4,F0
+ FADDDP F0,F2
+ FMOVD 136(SP), F0
+ FMULD F4,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULDP F0,F4
+ FXCHD F0, F3
+ FADDDP F0,F5
+ FMOVD 144(SP), F0
+ FMULD F4,F0
+ FADDDP F0,F2
+ FMOVD 136(SP), F0
+ FMULD F4,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULD F4,F0
+ FADDDP F0,F3
+ FMOVD 168(SP), F0
+ FMULDP F0,F4
+ FXCHD F0, F3
+ FADDDP F0,F4
+ FMOVD 136(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F1
+ FXCHD F0, F3
+ FMOVD 184(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F3
+ FXCHD F0, F1
+ FMOVD 168(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F1
+ FMOVD 152(SP), F0
+ FMULDP F0,F5
+ FXCHD F0, F4
+ FADDDP F0,F1
+ CMPQ DX,$16
+ FXCHD F0, F2
+ FMOVD 128(SP), F0
+ FSUBD ·DOFFSET3MINUSTWO128(SB), F0
+ FADDDP F0,F1
+ FXCHD F0, F1
+ FMOVD 120(SP), F0
+ FSUBD ·DOFFSET2(SB), F0
+ FADDDP F0,F1
+ FXCHD F0, F3
+ FMOVD 112(SP), F0
+ FSUBD ·DOFFSET1(SB), F0
+ FADDDP F0,F1
+ FXCHD F0, F2
+ FMOVD 104(SP), F0
+ FSUBD ·DOFFSET0(SB), F0
+ FADDDP F0,F1
+ JAE MULTIPLYADDATLEAST16BYTES
+ MULTIPLYADDATMOST15BYTES:
+ FMOVD ·ALPHA130(SB), F0
+ FADDD F2,F0
+ FSUBD ·ALPHA130(SB), F0
+ FSUBD F0,F2
+ FMULD ·SCALE(SB), F0
+ FMOVD ·ALPHA32(SB), F0
+ FADDD F2,F0
+ FSUBD ·ALPHA32(SB), F0
+ FSUBD F0,F2
+ FMOVD ·ALPHA64(SB), F0
+ FADDD F5,F0
+ FSUBD ·ALPHA64(SB), F0
+ FSUBD F0,F5
+ FMOVD ·ALPHA96(SB), F0
+ FADDD F7,F0
+ FSUBD ·ALPHA96(SB), F0
+ FSUBD F0,F7
+ FXCHD F0, F7
+ FADDDP F0,F1
+ FXCHD F0, F5
+ FADDDP F0,F1
+ FXCHD F0, F3
+ FADDDP F0,F5
+ FADDDP F0,F1
+ FMOVD 176(SP), F0
+ FMULD F1,F0
+ FMOVD 160(SP), F0
+ FMULD F2,F0
+ FMOVD 144(SP), F0
+ FMULD F3,F0
+ FMOVD 136(SP), F0
+ FMULDP F0,F4
+ FMOVD 160(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F3
+ FMOVD 144(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F2
+ FMOVD 136(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULDP F0,F5
+ FXCHD F0, F4
+ FADDDP F0,F3
+ FMOVD 144(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F2
+ FMOVD 136(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F4
+ FMOVD 168(SP), F0
+ FMULDP F0,F5
+ FXCHD F0, F4
+ FADDDP F0,F2
+ FMOVD 136(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F4
+ FMOVD 168(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F3
+ FMOVD 152(SP), F0
+ FMULDP F0,F5
+ FXCHD F0, F4
+ FADDDP F0,F1
+ ADDATMOST15BYTES:
+ CMPQ DX,$0
+ JE NOMOREBYTES
+ MOVL $0,0(SP)
+ MOVL $0, 4 (SP)
+ MOVL $0, 8 (SP)
+ MOVL $0, 12 (SP)
+ LEAQ 0(SP),DI
+ MOVQ DX,CX
+ REP; MOVSB
+ MOVB $1,0(DI)
+ MOVL 12 (SP),DI
+ MOVL 8 (SP),SI
+ MOVL 4 (SP),DX
+ MOVL 0(SP),CX
+ MOVL DI,128(SP)
+ MOVL SI,120(SP)
+ MOVL DX,112(SP)
+ MOVL CX,104(SP)
+ FXCHD F0, F3
+ FADDD 128(SP), F0
+ FSUBD ·DOFFSET3(SB), F0
+ FXCHD F0, F2
+ FADDD 120(SP), F0
+ FSUBD ·DOFFSET2(SB), F0
+ FXCHD F0, F1
+ FADDD 112(SP), F0
+ FSUBD ·DOFFSET1(SB), F0
+ FXCHD F0, F3
+ FADDD 104(SP), F0
+ FSUBD ·DOFFSET0(SB), F0
+ FMOVD ·ALPHA130(SB), F0
+ FADDD F3,F0
+ FSUBD ·ALPHA130(SB), F0
+ FSUBD F0,F3
+ FMULD ·SCALE(SB), F0
+ FMOVD ·ALPHA32(SB), F0
+ FADDD F2,F0
+ FSUBD ·ALPHA32(SB), F0
+ FSUBD F0,F2
+ FMOVD ·ALPHA64(SB), F0
+ FADDD F6,F0
+ FSUBD ·ALPHA64(SB), F0
+ FSUBD F0,F6
+ FMOVD ·ALPHA96(SB), F0
+ FADDD F5,F0
+ FSUBD ·ALPHA96(SB), F0
+ FSUBD F0,F5
+ FXCHD F0, F4
+ FADDDP F0,F3
+ FXCHD F0, F6
+ FADDDP F0,F1
+ FXCHD F0, F3
+ FADDDP F0,F5
+ FXCHD F0, F3
+ FADDDP F0,F1
+ FMOVD 176(SP), F0
+ FMULD F3,F0
+ FMOVD 160(SP), F0
+ FMULD F4,F0
+ FMOVD 144(SP), F0
+ FMULD F5,F0
+ FMOVD 136(SP), F0
+ FMULDP F0,F6
+ FMOVD 160(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F3
+ FMOVD 144(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F2
+ FMOVD 136(SP), F0
+ FMULD F5,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULDP F0,F5
+ FXCHD F0, F4
+ FADDDP F0,F5
+ FMOVD 144(SP), F0
+ FMULD F6,F0
+ FADDDP F0,F2
+ FMOVD 136(SP), F0
+ FMULD F6,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULD F6,F0
+ FADDDP F0,F4
+ FMOVD 168(SP), F0
+ FMULDP F0,F6
+ FXCHD F0, F5
+ FADDDP F0,F4
+ FMOVD 136(SP), F0
+ FMULD F2,F0
+ FADDDP F0,F1
+ FMOVD 184(SP), F0
+ FMULD F2,F0
+ FADDDP F0,F5
+ FMOVD 168(SP), F0
+ FMULD F2,F0
+ FADDDP F0,F3
+ FMOVD 152(SP), F0
+ FMULDP F0,F2
+ FXCHD F0, F1
+ FADDDP F0,F3
+ FXCHD F0, F3
+ FXCHD F0, F2
+ NOMOREBYTES:
+ MOVL $0,R10
+ FMOVD ·ALPHA130(SB), F0
+ FADDD F4,F0
+ FSUBD ·ALPHA130(SB), F0
+ FSUBD F0,F4
+ FMULD ·SCALE(SB), F0
+ FMOVD ·ALPHA32(SB), F0
+ FADDD F2,F0
+ FSUBD ·ALPHA32(SB), F0
+ FSUBD F0,F2
+ FMOVD ·ALPHA64(SB), F0
+ FADDD F4,F0
+ FSUBD ·ALPHA64(SB), F0
+ FSUBD F0,F4
+ FMOVD ·ALPHA96(SB), F0
+ FADDD F6,F0
+ FSUBD ·ALPHA96(SB), F0
+ FXCHD F0, F6
+ FSUBD F6,F0
+ FXCHD F0, F4
+ FADDDP F0,F3
+ FXCHD F0, F4
+ FADDDP F0,F1
+ FXCHD F0, F2
+ FADDDP F0,F3
+ FXCHD F0, F4
+ FADDDP F0,F3
+ FXCHD F0, F3
+ FADDD ·HOFFSET0(SB), F0
+ FXCHD F0, F3
+ FADDD ·HOFFSET1(SB), F0
+ FXCHD F0, F1
+ FADDD ·HOFFSET2(SB), F0
+ FXCHD F0, F2
+ FADDD ·HOFFSET3(SB), F0
+ FXCHD F0, F3
+ FMOVDP F0, 104(SP)
+ FMOVDP F0, 112(SP)
+ FMOVDP F0, 120(SP)
+ FMOVDP F0, 128(SP)
+ MOVL 108(SP),DI
+ ANDL $63,DI
+ MOVL 116(SP),SI
+ ANDL $63,SI
+ MOVL 124(SP),DX
+ ANDL $63,DX
+ MOVL 132(SP),CX
+ ANDL $63,CX
+ MOVL 112(SP),R8
+ ADDL DI,R8
+ MOVQ R8,112(SP)
+ MOVL 120(SP),DI
+ ADCL SI,DI
+ MOVQ DI,120(SP)
+ MOVL 128(SP),DI
+ ADCL DX,DI
+ MOVQ DI,128(SP)
+ MOVL R10,DI
+ ADCL CX,DI
+ MOVQ DI,136(SP)
+ MOVQ $5,DI
+ MOVL 104(SP),SI
+ ADDL SI,DI
+ MOVQ DI,104(SP)
+ MOVL R10,DI
+ MOVQ 112(SP),DX
+ ADCL DX,DI
+ MOVQ DI,112(SP)
+ MOVL R10,DI
+ MOVQ 120(SP),CX
+ ADCL CX,DI
+ MOVQ DI,120(SP)
+ MOVL R10,DI
+ MOVQ 128(SP),R8
+ ADCL R8,DI
+ MOVQ DI,128(SP)
+ MOVQ $0XFFFFFFFC,DI
+ MOVQ 136(SP),R9
+ ADCL R9,DI
+ SARL $16,DI
+ MOVQ DI,R9
+ XORL $0XFFFFFFFF,R9
+ ANDQ DI,SI
+ MOVQ 104(SP),AX
+ ANDQ R9,AX
+ ORQ AX,SI
+ ANDQ DI,DX
+ MOVQ 112(SP),AX
+ ANDQ R9,AX
+ ORQ AX,DX
+ ANDQ DI,CX
+ MOVQ 120(SP),AX
+ ANDQ R9,AX
+ ORQ AX,CX
+ ANDQ DI,R8
+ MOVQ 128(SP),DI
+ ANDQ R9,DI
+ ORQ DI,R8
+ MOVQ 88(SP),DI
+ MOVQ 96(SP),R9
+ ADDL 16(R9),SI
+ ADCL 20(R9),DX
+ ADCL 24(R9),CX
+ ADCL 28(R9),R8
+ MOVL SI,0(DI)
+ MOVL DX,4(DI)
+ MOVL CX,8(DI)
+ MOVL R8,12(DI)
+ MOVQ 32(SP),R11
+ MOVQ 40(SP),R12
+ MOVQ 48(SP),R13
+ MOVQ 56(SP),R14
+ MOVQ 64(SP),R15
+ MOVQ 72(SP),BX
+ MOVQ 80(SP),BP
+ MOVQ R11,SP
+ RET
diff --git a/vendor/golang.org/x/crypto/poly1305/poly1305_arm.s b/vendor/golang.org/x/crypto/poly1305/poly1305_arm.s
new file mode 100644
index 000000000..c15386744
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/poly1305_arm.s
@@ -0,0 +1,379 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This code was translated into a form compatible with 5a from the public
+// domain source by Andrew Moon: github.com/floodyberry/poly1305-opt/blob/master/app/extensions/poly1305.
+
+// +build arm,!gccgo,!appengine
+
+DATA poly1305_init_constants_armv6<>+0x00(SB)/4, $0x3ffffff
+DATA poly1305_init_constants_armv6<>+0x04(SB)/4, $0x3ffff03
+DATA poly1305_init_constants_armv6<>+0x08(SB)/4, $0x3ffc0ff
+DATA poly1305_init_constants_armv6<>+0x0c(SB)/4, $0x3f03fff
+DATA poly1305_init_constants_armv6<>+0x10(SB)/4, $0x00fffff
+GLOBL poly1305_init_constants_armv6<>(SB), 8, $20
+
+// Warning: the linker may use R11 to synthesize certain instructions. Please
+// take care and verify that no synthetic instructions use it.
+
+TEXT poly1305_init_ext_armv6<>(SB),4,$-4
+ MOVM.DB.W [R4-R11], (R13)
+ MOVM.IA.W (R1), [R2-R5]
+ MOVW $poly1305_init_constants_armv6<>(SB), R7
+ MOVW R2, R8
+ MOVW R2>>26, R9
+ MOVW R3>>20, g
+ MOVW R4>>14, R11
+ MOVW R5>>8, R12
+ ORR R3<<6, R9, R9
+ ORR R4<<12, g, g
+ ORR R5<<18, R11, R11
+ MOVM.IA (R7), [R2-R6]
+ AND R8, R2, R2
+ AND R9, R3, R3
+ AND g, R4, R4
+ AND R11, R5, R5
+ AND R12, R6, R6
+ MOVM.IA.W [R2-R6], (R0)
+ EOR R2, R2, R2
+ EOR R3, R3, R3
+ EOR R4, R4, R4
+ EOR R5, R5, R5
+ EOR R6, R6, R6
+ MOVM.IA.W [R2-R6], (R0)
+ MOVM.IA.W (R1), [R2-R5]
+ MOVM.IA [R2-R6], (R0)
+ MOVM.IA.W (R13), [R4-R11]
+ RET
+
+#define MOVW_UNALIGNED(Rsrc, Rdst, Rtmp, offset) \
+ MOVBU (offset+0)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+0)(Rdst); \
+ MOVBU (offset+1)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+1)(Rdst); \
+ MOVBU (offset+2)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+2)(Rdst); \
+ MOVBU (offset+3)(Rsrc), Rtmp; \
+ MOVBU Rtmp, (offset+3)(Rdst)
+
+TEXT poly1305_blocks_armv6<>(SB),4,$-4
+ MOVM.DB.W [R4, R5, R6, R7, R8, R9, g, R11, R14], (R13)
+ SUB $128, R13
+ MOVW R0, 36(R13)
+ MOVW R1, 40(R13)
+ MOVW R2, 44(R13)
+ MOVW R1, R14
+ MOVW R2, R12
+ MOVW 56(R0), R8
+ WORD $0xe1180008 // TST R8, R8 not working see issue 5921
+ EOR R6, R6, R6
+ MOVW.EQ $(1<<24), R6
+ MOVW R6, 32(R13)
+ ADD $64, R13, g
+ MOVM.IA (R0), [R0-R9]
+ MOVM.IA [R0-R4], (g)
+ CMP $16, R12
+ BLO poly1305_blocks_armv6_done
+poly1305_blocks_armv6_mainloop:
+ WORD $0xe31e0003 // TST R14, #3 not working see issue 5921
+ BEQ poly1305_blocks_armv6_mainloop_aligned
+ ADD $48, R13, g
+ MOVW_UNALIGNED(R14, g, R0, 0)
+ MOVW_UNALIGNED(R14, g, R0, 4)
+ MOVW_UNALIGNED(R14, g, R0, 8)
+ MOVW_UNALIGNED(R14, g, R0, 12)
+ MOVM.IA (g), [R0-R3]
+ ADD $16, R14
+ B poly1305_blocks_armv6_mainloop_loaded
+poly1305_blocks_armv6_mainloop_aligned:
+ MOVM.IA.W (R14), [R0-R3]
+poly1305_blocks_armv6_mainloop_loaded:
+ MOVW R0>>26, g
+ MOVW R1>>20, R11
+ MOVW R2>>14, R12
+ MOVW R14, 40(R13)
+ MOVW R3>>8, R4
+ ORR R1<<6, g, g
+ ORR R2<<12, R11, R11
+ ORR R3<<18, R12, R12
+ BIC $0xfc000000, R0, R0
+ BIC $0xfc000000, g, g
+ MOVW 32(R13), R3
+ BIC $0xfc000000, R11, R11
+ BIC $0xfc000000, R12, R12
+ ADD R0, R5, R5
+ ADD g, R6, R6
+ ORR R3, R4, R4
+ ADD R11, R7, R7
+ ADD $64, R13, R14
+ ADD R12, R8, R8
+ ADD R4, R9, R9
+ MOVM.IA (R14), [R0-R4]
+ MULLU R4, R5, (R11, g)
+ MULLU R3, R5, (R14, R12)
+ MULALU R3, R6, (R11, g)
+ MULALU R2, R6, (R14, R12)
+ MULALU R2, R7, (R11, g)
+ MULALU R1, R7, (R14, R12)
+ ADD R4<<2, R4, R4
+ ADD R3<<2, R3, R3
+ MULALU R1, R8, (R11, g)
+ MULALU R0, R8, (R14, R12)
+ MULALU R0, R9, (R11, g)
+ MULALU R4, R9, (R14, R12)
+ MOVW g, 24(R13)
+ MOVW R11, 28(R13)
+ MOVW R12, 16(R13)
+ MOVW R14, 20(R13)
+ MULLU R2, R5, (R11, g)
+ MULLU R1, R5, (R14, R12)
+ MULALU R1, R6, (R11, g)
+ MULALU R0, R6, (R14, R12)
+ MULALU R0, R7, (R11, g)
+ MULALU R4, R7, (R14, R12)
+ ADD R2<<2, R2, R2
+ ADD R1<<2, R1, R1
+ MULALU R4, R8, (R11, g)
+ MULALU R3, R8, (R14, R12)
+ MULALU R3, R9, (R11, g)
+ MULALU R2, R9, (R14, R12)
+ MOVW g, 8(R13)
+ MOVW R11, 12(R13)
+ MOVW R12, 0(R13)
+ MOVW R14, w+4(SP)
+ MULLU R0, R5, (R11, g)
+ MULALU R4, R6, (R11, g)
+ MULALU R3, R7, (R11, g)
+ MULALU R2, R8, (R11, g)
+ MULALU R1, R9, (R11, g)
+ MOVM.IA (R13), [R0-R7]
+ MOVW g>>26, R12
+ MOVW R4>>26, R14
+ ORR R11<<6, R12, R12
+ ORR R5<<6, R14, R14
+ BIC $0xfc000000, g, g
+ BIC $0xfc000000, R4, R4
+ ADD.S R12, R0, R0
+ ADC $0, R1, R1
+ ADD.S R14, R6, R6
+ ADC $0, R7, R7
+ MOVW R0>>26, R12
+ MOVW R6>>26, R14
+ ORR R1<<6, R12, R12
+ ORR R7<<6, R14, R14
+ BIC $0xfc000000, R0, R0
+ BIC $0xfc000000, R6, R6
+ ADD R14<<2, R14, R14
+ ADD.S R12, R2, R2
+ ADC $0, R3, R3
+ ADD R14, g, g
+ MOVW R2>>26, R12
+ MOVW g>>26, R14
+ ORR R3<<6, R12, R12
+ BIC $0xfc000000, g, R5
+ BIC $0xfc000000, R2, R7
+ ADD R12, R4, R4
+ ADD R14, R0, R0
+ MOVW R4>>26, R12
+ BIC $0xfc000000, R4, R8
+ ADD R12, R6, R9
+ MOVW w+44(SP), R12
+ MOVW w+40(SP), R14
+ MOVW R0, R6
+ CMP $32, R12
+ SUB $16, R12, R12
+ MOVW R12, 44(R13)
+ BHS poly1305_blocks_armv6_mainloop
+poly1305_blocks_armv6_done:
+ MOVW 36(R13), R12
+ MOVW R5, 20(R12)
+ MOVW R6, 24(R12)
+ MOVW R7, 28(R12)
+ MOVW R8, 32(R12)
+ MOVW R9, 36(R12)
+ ADD $128, R13, R13
+ MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, g, R11, R14]
+ RET
+
+#define MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp) \
+ MOVBU.P 1(Rsrc), Rtmp; \
+ MOVBU.P Rtmp, 1(Rdst); \
+ MOVBU.P 1(Rsrc), Rtmp; \
+ MOVBU.P Rtmp, 1(Rdst)
+
+#define MOVWP_UNALIGNED(Rsrc, Rdst, Rtmp) \
+ MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp); \
+ MOVHUP_UNALIGNED(Rsrc, Rdst, Rtmp)
+
+TEXT poly1305_finish_ext_armv6<>(SB),4,$-4
+ MOVM.DB.W [R4, R5, R6, R7, R8, R9, g, R11, R14], (R13)
+ SUB $16, R13, R13
+ MOVW R0, R5
+ MOVW R1, R6
+ MOVW R2, R7
+ MOVW R3, R8
+ AND.S R2, R2, R2
+ BEQ poly1305_finish_ext_armv6_noremaining
+ EOR R0, R0
+ MOVW R13, R9
+ MOVW R0, 0(R13)
+ MOVW R0, 4(R13)
+ MOVW R0, 8(R13)
+ MOVW R0, 12(R13)
+ WORD $0xe3110003 // TST R1, #3 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_aligned
+ WORD $0xe3120008 // TST R2, #8 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip8
+ MOVWP_UNALIGNED(R1, R9, g)
+ MOVWP_UNALIGNED(R1, R9, g)
+poly1305_finish_ext_armv6_skip8:
+ WORD $0xe3120004 // TST $4, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip4
+ MOVWP_UNALIGNED(R1, R9, g)
+poly1305_finish_ext_armv6_skip4:
+ WORD $0xe3120002 // TST $2, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip2
+ MOVHUP_UNALIGNED(R1, R9, g)
+ B poly1305_finish_ext_armv6_skip2
+poly1305_finish_ext_armv6_aligned:
+ WORD $0xe3120008 // TST R2, #8 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip8_aligned
+ MOVM.IA.W (R1), [g-R11]
+ MOVM.IA.W [g-R11], (R9)
+poly1305_finish_ext_armv6_skip8_aligned:
+ WORD $0xe3120004 // TST $4, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip4_aligned
+ MOVW.P 4(R1), g
+ MOVW.P g, 4(R9)
+poly1305_finish_ext_armv6_skip4_aligned:
+ WORD $0xe3120002 // TST $2, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip2
+ MOVHU.P 2(R1), g
+ MOVH.P g, 2(R9)
+poly1305_finish_ext_armv6_skip2:
+ WORD $0xe3120001 // TST $1, R2 not working see issue 5921
+ BEQ poly1305_finish_ext_armv6_skip1
+ MOVBU.P 1(R1), g
+ MOVBU.P g, 1(R9)
+poly1305_finish_ext_armv6_skip1:
+ MOVW $1, R11
+ MOVBU R11, 0(R9)
+ MOVW R11, 56(R5)
+ MOVW R5, R0
+ MOVW R13, R1
+ MOVW $16, R2
+ BL poly1305_blocks_armv6<>(SB)
+poly1305_finish_ext_armv6_noremaining:
+ MOVW 20(R5), R0
+ MOVW 24(R5), R1
+ MOVW 28(R5), R2
+ MOVW 32(R5), R3
+ MOVW 36(R5), R4
+ MOVW R4>>26, R12
+ BIC $0xfc000000, R4, R4
+ ADD R12<<2, R12, R12
+ ADD R12, R0, R0
+ MOVW R0>>26, R12
+ BIC $0xfc000000, R0, R0
+ ADD R12, R1, R1
+ MOVW R1>>26, R12
+ BIC $0xfc000000, R1, R1
+ ADD R12, R2, R2
+ MOVW R2>>26, R12
+ BIC $0xfc000000, R2, R2
+ ADD R12, R3, R3
+ MOVW R3>>26, R12
+ BIC $0xfc000000, R3, R3
+ ADD R12, R4, R4
+ ADD $5, R0, R6
+ MOVW R6>>26, R12
+ BIC $0xfc000000, R6, R6
+ ADD R12, R1, R7
+ MOVW R7>>26, R12
+ BIC $0xfc000000, R7, R7
+ ADD R12, R2, g
+ MOVW g>>26, R12
+ BIC $0xfc000000, g, g
+ ADD R12, R3, R11
+ MOVW $-(1<<26), R12
+ ADD R11>>26, R12, R12
+ BIC $0xfc000000, R11, R11
+ ADD R12, R4, R14
+ MOVW R14>>31, R12
+ SUB $1, R12
+ AND R12, R6, R6
+ AND R12, R7, R7
+ AND R12, g, g
+ AND R12, R11, R11
+ AND R12, R14, R14
+ MVN R12, R12
+ AND R12, R0, R0
+ AND R12, R1, R1
+ AND R12, R2, R2
+ AND R12, R3, R3
+ AND R12, R4, R4
+ ORR R6, R0, R0
+ ORR R7, R1, R1
+ ORR g, R2, R2
+ ORR R11, R3, R3
+ ORR R14, R4, R4
+ ORR R1<<26, R0, R0
+ MOVW R1>>6, R1
+ ORR R2<<20, R1, R1
+ MOVW R2>>12, R2
+ ORR R3<<14, R2, R2
+ MOVW R3>>18, R3
+ ORR R4<<8, R3, R3
+ MOVW 40(R5), R6
+ MOVW 44(R5), R7
+ MOVW 48(R5), g
+ MOVW 52(R5), R11
+ ADD.S R6, R0, R0
+ ADC.S R7, R1, R1
+ ADC.S g, R2, R2
+ ADC.S R11, R3, R3
+ MOVM.IA [R0-R3], (R8)
+ MOVW R5, R12
+ EOR R0, R0, R0
+ EOR R1, R1, R1
+ EOR R2, R2, R2
+ EOR R3, R3, R3
+ EOR R4, R4, R4
+ EOR R5, R5, R5
+ EOR R6, R6, R6
+ EOR R7, R7, R7
+ MOVM.IA.W [R0-R7], (R12)
+ MOVM.IA [R0-R7], (R12)
+ ADD $16, R13, R13
+ MOVM.IA.W (R13), [R4, R5, R6, R7, R8, R9, g, R11, R14]
+ RET
+
+// func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]key)
+TEXT ·poly1305_auth_armv6(SB),0,$280-16
+ MOVW out+0(FP), R4
+ MOVW m+4(FP), R5
+ MOVW mlen+8(FP), R6
+ MOVW key+12(FP), R7
+
+ MOVW R13, R8
+ BIC $63, R13
+ SUB $64, R13, R13
+ MOVW R13, R0
+ MOVW R7, R1
+ BL poly1305_init_ext_armv6<>(SB)
+ BIC.S $15, R6, R2
+ BEQ poly1305_auth_armv6_noblocks
+ MOVW R13, R0
+ MOVW R5, R1
+ ADD R2, R5, R5
+ SUB R2, R6, R6
+ BL poly1305_blocks_armv6<>(SB)
+poly1305_auth_armv6_noblocks:
+ MOVW R13, R0
+ MOVW R5, R1
+ MOVW R6, R2
+ MOVW R4, R3
+ BL poly1305_finish_ext_armv6<>(SB)
+ MOVW R8, R13
+ RET
diff --git a/vendor/golang.org/x/crypto/poly1305/poly1305_test.go b/vendor/golang.org/x/crypto/poly1305/poly1305_test.go
new file mode 100644
index 000000000..b3e92310b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/poly1305_test.go
@@ -0,0 +1,86 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package poly1305
+
+import (
+ "bytes"
+ "testing"
+ "unsafe"
+)
+
+var testData = []struct {
+ in, k, correct []byte
+}{
+ {
+ []byte("Hello world!"),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2, 0xf0},
+ },
+ {
+ make([]byte, 32),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc, 0x03, 0x07},
+ },
+ {
+ make([]byte, 2007),
+ []byte("this is 32-byte key for Poly1305"),
+ []byte{0xda, 0x84, 0xbc, 0xab, 0x02, 0x67, 0x6c, 0x38, 0xcd, 0xb0, 0x15, 0x60, 0x42, 0x74, 0xc2, 0xaa},
+ },
+ {
+ make([]byte, 2007),
+ make([]byte, 32),
+ make([]byte, 16),
+ },
+}
+
+func testSum(t *testing.T, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+
+ for i, v := range testData {
+ in := v.in
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ copy(key[:], v.k)
+ Sum(&out, in, &key)
+ if !bytes.Equal(out[:], v.correct) {
+ t.Errorf("%d: expected %x, got %x", i, v.correct, out[:])
+ }
+ }
+}
+
+func TestSum(t *testing.T) { testSum(t, false) }
+func TestSumUnaligned(t *testing.T) { testSum(t, true) }
+
+func benchmark(b *testing.B, size int, unaligned bool) {
+ var out [16]byte
+ var key [32]byte
+ in := make([]byte, size)
+ if unaligned {
+ in = unalignBytes(in)
+ }
+ b.SetBytes(int64(len(in)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Sum(&out, in, &key)
+ }
+}
+
+func Benchmark64(b *testing.B) { benchmark(b, 64, false) }
+func Benchmark1K(b *testing.B) { benchmark(b, 1024, false) }
+func Benchmark64Unaligned(b *testing.B) { benchmark(b, 64, true) }
+func Benchmark1KUnaligned(b *testing.B) { benchmark(b, 1024, true) }
+
+func unalignBytes(in []byte) []byte {
+ out := make([]byte, len(in)+1)
+ if uintptr(unsafe.Pointer(&out[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
+ out = out[1:]
+ } else {
+ out = out[:len(in)]
+ }
+ copy(out, in)
+ return out
+}
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_amd64.go b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go
new file mode 100644
index 000000000..6775c703f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/sum_amd64.go
@@ -0,0 +1,24 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!gccgo,!appengine
+
+package poly1305
+
+// This function is implemented in poly1305_amd64.s
+
+//go:noescape
+
+func poly1305(out *[16]byte, m *byte, mlen uint64, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305(out, mPtr, uint64(len(m)), key)
+}
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_arm.go b/vendor/golang.org/x/crypto/poly1305/sum_arm.go
new file mode 100644
index 000000000..50b979c24
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/sum_arm.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build arm,!gccgo,!appengine
+
+package poly1305
+
+// This function is implemented in poly1305_arm.s
+
+//go:noescape
+
+func poly1305_auth_armv6(out *[16]byte, m *byte, mlen uint32, key *[32]byte)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ var mPtr *byte
+ if len(m) > 0 {
+ mPtr = &m[0]
+ }
+ poly1305_auth_armv6(out, mPtr, uint32(len(m)), key)
+}
diff --git a/vendor/golang.org/x/crypto/poly1305/sum_ref.go b/vendor/golang.org/x/crypto/poly1305/sum_ref.go
new file mode 100644
index 000000000..0b24fc78b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/poly1305/sum_ref.go
@@ -0,0 +1,1531 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!arm gccgo appengine
+
+package poly1305
+
+// Based on original, public domain implementation from NaCl by D. J.
+// Bernstein.
+
+import "math"
+
+const (
+ alpham80 = 0.00000000558793544769287109375
+ alpham48 = 24.0
+ alpham16 = 103079215104.0
+ alpha0 = 6755399441055744.0
+ alpha18 = 1770887431076116955136.0
+ alpha32 = 29014219670751100192948224.0
+ alpha50 = 7605903601369376408980219232256.0
+ alpha64 = 124615124604835863084731911901282304.0
+ alpha82 = 32667107224410092492483962313449748299776.0
+ alpha96 = 535217884764734955396857238543560676143529984.0
+ alpha112 = 35076039295941670036888435985190792471742381031424.0
+ alpha130 = 9194973245195333150150082162901855101712434733101613056.0
+ scale = 0.0000000000000000000000000000000000000036734198463196484624023016788195177431833298649127735047148490821200539357960224151611328125
+ offset0 = 6755408030990331.0
+ offset1 = 29014256564239239022116864.0
+ offset2 = 124615283061160854719918951570079744.0
+ offset3 = 535219245894202480694386063513315216128475136.0
+)
+
+// Sum generates an authenticator for m using a one-time key and puts the
+// 16-byte result into out. Authenticating two different messages with the same
+// key allows an attacker to forge messages at will.
+func Sum(out *[16]byte, m []byte, key *[32]byte) {
+ r := key
+ s := key[16:]
+ var (
+ y7 float64
+ y6 float64
+ y1 float64
+ y0 float64
+ y5 float64
+ y4 float64
+ x7 float64
+ x6 float64
+ x1 float64
+ x0 float64
+ y3 float64
+ y2 float64
+ x5 float64
+ r3lowx0 float64
+ x4 float64
+ r0lowx6 float64
+ x3 float64
+ r3highx0 float64
+ x2 float64
+ r0highx6 float64
+ r0lowx0 float64
+ sr1lowx6 float64
+ r0highx0 float64
+ sr1highx6 float64
+ sr3low float64
+ r1lowx0 float64
+ sr2lowx6 float64
+ r1highx0 float64
+ sr2highx6 float64
+ r2lowx0 float64
+ sr3lowx6 float64
+ r2highx0 float64
+ sr3highx6 float64
+ r1highx4 float64
+ r1lowx4 float64
+ r0highx4 float64
+ r0lowx4 float64
+ sr3highx4 float64
+ sr3lowx4 float64
+ sr2highx4 float64
+ sr2lowx4 float64
+ r0lowx2 float64
+ r0highx2 float64
+ r1lowx2 float64
+ r1highx2 float64
+ r2lowx2 float64
+ r2highx2 float64
+ sr3lowx2 float64
+ sr3highx2 float64
+ z0 float64
+ z1 float64
+ z2 float64
+ z3 float64
+ m0 int64
+ m1 int64
+ m2 int64
+ m3 int64
+ m00 uint32
+ m01 uint32
+ m02 uint32
+ m03 uint32
+ m10 uint32
+ m11 uint32
+ m12 uint32
+ m13 uint32
+ m20 uint32
+ m21 uint32
+ m22 uint32
+ m23 uint32
+ m30 uint32
+ m31 uint32
+ m32 uint32
+ m33 uint64
+ lbelow2 int32
+ lbelow3 int32
+ lbelow4 int32
+ lbelow5 int32
+ lbelow6 int32
+ lbelow7 int32
+ lbelow8 int32
+ lbelow9 int32
+ lbelow10 int32
+ lbelow11 int32
+ lbelow12 int32
+ lbelow13 int32
+ lbelow14 int32
+ lbelow15 int32
+ s00 uint32
+ s01 uint32
+ s02 uint32
+ s03 uint32
+ s10 uint32
+ s11 uint32
+ s12 uint32
+ s13 uint32
+ s20 uint32
+ s21 uint32
+ s22 uint32
+ s23 uint32
+ s30 uint32
+ s31 uint32
+ s32 uint32
+ s33 uint32
+ bits32 uint64
+ f uint64
+ f0 uint64
+ f1 uint64
+ f2 uint64
+ f3 uint64
+ f4 uint64
+ g uint64
+ g0 uint64
+ g1 uint64
+ g2 uint64
+ g3 uint64
+ g4 uint64
+ )
+
+ var p int32
+
+ l := int32(len(m))
+
+ r00 := uint32(r[0])
+
+ r01 := uint32(r[1])
+
+ r02 := uint32(r[2])
+ r0 := int64(2151)
+
+ r03 := uint32(r[3])
+ r03 &= 15
+ r0 <<= 51
+
+ r10 := uint32(r[4])
+ r10 &= 252
+ r01 <<= 8
+ r0 += int64(r00)
+
+ r11 := uint32(r[5])
+ r02 <<= 16
+ r0 += int64(r01)
+
+ r12 := uint32(r[6])
+ r03 <<= 24
+ r0 += int64(r02)
+
+ r13 := uint32(r[7])
+ r13 &= 15
+ r1 := int64(2215)
+ r0 += int64(r03)
+
+ d0 := r0
+ r1 <<= 51
+ r2 := int64(2279)
+
+ r20 := uint32(r[8])
+ r20 &= 252
+ r11 <<= 8
+ r1 += int64(r10)
+
+ r21 := uint32(r[9])
+ r12 <<= 16
+ r1 += int64(r11)
+
+ r22 := uint32(r[10])
+ r13 <<= 24
+ r1 += int64(r12)
+
+ r23 := uint32(r[11])
+ r23 &= 15
+ r2 <<= 51
+ r1 += int64(r13)
+
+ d1 := r1
+ r21 <<= 8
+ r2 += int64(r20)
+
+ r30 := uint32(r[12])
+ r30 &= 252
+ r22 <<= 16
+ r2 += int64(r21)
+
+ r31 := uint32(r[13])
+ r23 <<= 24
+ r2 += int64(r22)
+
+ r32 := uint32(r[14])
+ r2 += int64(r23)
+ r3 := int64(2343)
+
+ d2 := r2
+ r3 <<= 51
+
+ r33 := uint32(r[15])
+ r33 &= 15
+ r31 <<= 8
+ r3 += int64(r30)
+
+ r32 <<= 16
+ r3 += int64(r31)
+
+ r33 <<= 24
+ r3 += int64(r32)
+
+ r3 += int64(r33)
+ h0 := alpha32 - alpha32
+
+ d3 := r3
+ h1 := alpha32 - alpha32
+
+ h2 := alpha32 - alpha32
+
+ h3 := alpha32 - alpha32
+
+ h4 := alpha32 - alpha32
+
+ r0low := math.Float64frombits(uint64(d0))
+ h5 := alpha32 - alpha32
+
+ r1low := math.Float64frombits(uint64(d1))
+ h6 := alpha32 - alpha32
+
+ r2low := math.Float64frombits(uint64(d2))
+ h7 := alpha32 - alpha32
+
+ r0low -= alpha0
+
+ r1low -= alpha32
+
+ r2low -= alpha64
+
+ r0high := r0low + alpha18
+
+ r3low := math.Float64frombits(uint64(d3))
+
+ r1high := r1low + alpha50
+ sr1low := scale * r1low
+
+ r2high := r2low + alpha82
+ sr2low := scale * r2low
+
+ r0high -= alpha18
+ r0high_stack := r0high
+
+ r3low -= alpha96
+
+ r1high -= alpha50
+ r1high_stack := r1high
+
+ sr1high := sr1low + alpham80
+
+ r0low -= r0high
+
+ r2high -= alpha82
+ sr3low = scale * r3low
+
+ sr2high := sr2low + alpham48
+
+ r1low -= r1high
+ r1low_stack := r1low
+
+ sr1high -= alpham80
+ sr1high_stack := sr1high
+
+ r2low -= r2high
+ r2low_stack := r2low
+
+ sr2high -= alpham48
+ sr2high_stack := sr2high
+
+ r3high := r3low + alpha112
+ r0low_stack := r0low
+
+ sr1low -= sr1high
+ sr1low_stack := sr1low
+
+ sr3high := sr3low + alpham16
+ r2high_stack := r2high
+
+ sr2low -= sr2high
+ sr2low_stack := sr2low
+
+ r3high -= alpha112
+ r3high_stack := r3high
+
+ sr3high -= alpham16
+ sr3high_stack := sr3high
+
+ r3low -= r3high
+ r3low_stack := r3low
+
+ sr3low -= sr3high
+ sr3low_stack := sr3low
+
+ if l < 16 {
+ goto addatmost15bytes
+ }
+
+ m00 = uint32(m[p+0])
+ m0 = 2151
+
+ m0 <<= 51
+ m1 = 2215
+ m01 = uint32(m[p+1])
+
+ m1 <<= 51
+ m2 = 2279
+ m02 = uint32(m[p+2])
+
+ m2 <<= 51
+ m3 = 2343
+ m03 = uint32(m[p+3])
+
+ m10 = uint32(m[p+4])
+ m01 <<= 8
+ m0 += int64(m00)
+
+ m11 = uint32(m[p+5])
+ m02 <<= 16
+ m0 += int64(m01)
+
+ m12 = uint32(m[p+6])
+ m03 <<= 24
+ m0 += int64(m02)
+
+ m13 = uint32(m[p+7])
+ m3 <<= 51
+ m0 += int64(m03)
+
+ m20 = uint32(m[p+8])
+ m11 <<= 8
+ m1 += int64(m10)
+
+ m21 = uint32(m[p+9])
+ m12 <<= 16
+ m1 += int64(m11)
+
+ m22 = uint32(m[p+10])
+ m13 <<= 24
+ m1 += int64(m12)
+
+ m23 = uint32(m[p+11])
+ m1 += int64(m13)
+
+ m30 = uint32(m[p+12])
+ m21 <<= 8
+ m2 += int64(m20)
+
+ m31 = uint32(m[p+13])
+ m22 <<= 16
+ m2 += int64(m21)
+
+ m32 = uint32(m[p+14])
+ m23 <<= 24
+ m2 += int64(m22)
+
+ m33 = uint64(m[p+15])
+ m2 += int64(m23)
+
+ d0 = m0
+ m31 <<= 8
+ m3 += int64(m30)
+
+ d1 = m1
+ m32 <<= 16
+ m3 += int64(m31)
+
+ d2 = m2
+ m33 += 256
+
+ m33 <<= 24
+ m3 += int64(m32)
+
+ m3 += int64(m33)
+ d3 = m3
+
+ p += 16
+ l -= 16
+
+ z0 = math.Float64frombits(uint64(d0))
+
+ z1 = math.Float64frombits(uint64(d1))
+
+ z2 = math.Float64frombits(uint64(d2))
+
+ z3 = math.Float64frombits(uint64(d3))
+
+ z0 -= alpha0
+
+ z1 -= alpha32
+
+ z2 -= alpha64
+
+ z3 -= alpha96
+
+ h0 += z0
+
+ h1 += z1
+
+ h3 += z2
+
+ h5 += z3
+
+ if l < 16 {
+ goto multiplyaddatmost15bytes
+ }
+
+multiplyaddatleast16bytes:
+
+ m2 = 2279
+ m20 = uint32(m[p+8])
+ y7 = h7 + alpha130
+
+ m2 <<= 51
+ m3 = 2343
+ m21 = uint32(m[p+9])
+ y6 = h6 + alpha130
+
+ m3 <<= 51
+ m0 = 2151
+ m22 = uint32(m[p+10])
+ y1 = h1 + alpha32
+
+ m0 <<= 51
+ m1 = 2215
+ m23 = uint32(m[p+11])
+ y0 = h0 + alpha32
+
+ m1 <<= 51
+ m30 = uint32(m[p+12])
+ y7 -= alpha130
+
+ m21 <<= 8
+ m2 += int64(m20)
+ m31 = uint32(m[p+13])
+ y6 -= alpha130
+
+ m22 <<= 16
+ m2 += int64(m21)
+ m32 = uint32(m[p+14])
+ y1 -= alpha32
+
+ m23 <<= 24
+ m2 += int64(m22)
+ m33 = uint64(m[p+15])
+ y0 -= alpha32
+
+ m2 += int64(m23)
+ m00 = uint32(m[p+0])
+ y5 = h5 + alpha96
+
+ m31 <<= 8
+ m3 += int64(m30)
+ m01 = uint32(m[p+1])
+ y4 = h4 + alpha96
+
+ m32 <<= 16
+ m02 = uint32(m[p+2])
+ x7 = h7 - y7
+ y7 *= scale
+
+ m33 += 256
+ m03 = uint32(m[p+3])
+ x6 = h6 - y6
+ y6 *= scale
+
+ m33 <<= 24
+ m3 += int64(m31)
+ m10 = uint32(m[p+4])
+ x1 = h1 - y1
+
+ m01 <<= 8
+ m3 += int64(m32)
+ m11 = uint32(m[p+5])
+ x0 = h0 - y0
+
+ m3 += int64(m33)
+ m0 += int64(m00)
+ m12 = uint32(m[p+6])
+ y5 -= alpha96
+
+ m02 <<= 16
+ m0 += int64(m01)
+ m13 = uint32(m[p+7])
+ y4 -= alpha96
+
+ m03 <<= 24
+ m0 += int64(m02)
+ d2 = m2
+ x1 += y7
+
+ m0 += int64(m03)
+ d3 = m3
+ x0 += y6
+
+ m11 <<= 8
+ m1 += int64(m10)
+ d0 = m0
+ x7 += y5
+
+ m12 <<= 16
+ m1 += int64(m11)
+ x6 += y4
+
+ m13 <<= 24
+ m1 += int64(m12)
+ y3 = h3 + alpha64
+
+ m1 += int64(m13)
+ d1 = m1
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+ z2 = math.Float64frombits(uint64(d2))
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+ z3 = math.Float64frombits(uint64(d3))
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+ z2 -= alpha64
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+ z3 -= alpha96
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ p += 16
+ l -= 16
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ z1 = math.Float64frombits(uint64(d1))
+ h0 += sr3lowx2
+
+ z0 = math.Float64frombits(uint64(d0))
+ h1 += sr3highx2
+
+ z1 -= alpha32
+
+ z0 -= alpha0
+
+ h5 += z3
+
+ h3 += z2
+
+ h1 += z1
+
+ h0 += z0
+
+ if l >= 16 {
+ goto multiplyaddatleast16bytes
+ }
+
+multiplyaddatmost15bytes:
+
+ y7 = h7 + alpha130
+
+ y6 = h6 + alpha130
+
+ y1 = h1 + alpha32
+
+ y0 = h0 + alpha32
+
+ y7 -= alpha130
+
+ y6 -= alpha130
+
+ y1 -= alpha32
+
+ y0 -= alpha32
+
+ y5 = h5 + alpha96
+
+ y4 = h4 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ x6 = h6 - y6
+ y6 *= scale
+
+ x1 = h1 - y1
+
+ x0 = h0 - y0
+
+ y5 -= alpha96
+
+ y4 -= alpha96
+
+ x1 += y7
+
+ x0 += y6
+
+ x7 += y5
+
+ x6 += y4
+
+ y3 = h3 + alpha64
+
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ h0 += sr3lowx2
+
+ h1 += sr3highx2
+
+addatmost15bytes:
+
+ if l == 0 {
+ goto nomorebytes
+ }
+
+ lbelow2 = l - 2
+
+ lbelow3 = l - 3
+
+ lbelow2 >>= 31
+ lbelow4 = l - 4
+
+ m00 = uint32(m[p+0])
+ lbelow3 >>= 31
+ p += lbelow2
+
+ m01 = uint32(m[p+1])
+ lbelow4 >>= 31
+ p += lbelow3
+
+ m02 = uint32(m[p+2])
+ p += lbelow4
+ m0 = 2151
+
+ m03 = uint32(m[p+3])
+ m0 <<= 51
+ m1 = 2215
+
+ m0 += int64(m00)
+ m01 &^= uint32(lbelow2)
+
+ m02 &^= uint32(lbelow3)
+ m01 -= uint32(lbelow2)
+
+ m01 <<= 8
+ m03 &^= uint32(lbelow4)
+
+ m0 += int64(m01)
+ lbelow2 -= lbelow3
+
+ m02 += uint32(lbelow2)
+ lbelow3 -= lbelow4
+
+ m02 <<= 16
+ m03 += uint32(lbelow3)
+
+ m03 <<= 24
+ m0 += int64(m02)
+
+ m0 += int64(m03)
+ lbelow5 = l - 5
+
+ lbelow6 = l - 6
+ lbelow7 = l - 7
+
+ lbelow5 >>= 31
+ lbelow8 = l - 8
+
+ lbelow6 >>= 31
+ p += lbelow5
+
+ m10 = uint32(m[p+4])
+ lbelow7 >>= 31
+ p += lbelow6
+
+ m11 = uint32(m[p+5])
+ lbelow8 >>= 31
+ p += lbelow7
+
+ m12 = uint32(m[p+6])
+ m1 <<= 51
+ p += lbelow8
+
+ m13 = uint32(m[p+7])
+ m10 &^= uint32(lbelow5)
+ lbelow4 -= lbelow5
+
+ m10 += uint32(lbelow4)
+ lbelow5 -= lbelow6
+
+ m11 &^= uint32(lbelow6)
+ m11 += uint32(lbelow5)
+
+ m11 <<= 8
+ m1 += int64(m10)
+
+ m1 += int64(m11)
+ m12 &^= uint32(lbelow7)
+
+ lbelow6 -= lbelow7
+ m13 &^= uint32(lbelow8)
+
+ m12 += uint32(lbelow6)
+ lbelow7 -= lbelow8
+
+ m12 <<= 16
+ m13 += uint32(lbelow7)
+
+ m13 <<= 24
+ m1 += int64(m12)
+
+ m1 += int64(m13)
+ m2 = 2279
+
+ lbelow9 = l - 9
+ m3 = 2343
+
+ lbelow10 = l - 10
+ lbelow11 = l - 11
+
+ lbelow9 >>= 31
+ lbelow12 = l - 12
+
+ lbelow10 >>= 31
+ p += lbelow9
+
+ m20 = uint32(m[p+8])
+ lbelow11 >>= 31
+ p += lbelow10
+
+ m21 = uint32(m[p+9])
+ lbelow12 >>= 31
+ p += lbelow11
+
+ m22 = uint32(m[p+10])
+ m2 <<= 51
+ p += lbelow12
+
+ m23 = uint32(m[p+11])
+ m20 &^= uint32(lbelow9)
+ lbelow8 -= lbelow9
+
+ m20 += uint32(lbelow8)
+ lbelow9 -= lbelow10
+
+ m21 &^= uint32(lbelow10)
+ m21 += uint32(lbelow9)
+
+ m21 <<= 8
+ m2 += int64(m20)
+
+ m2 += int64(m21)
+ m22 &^= uint32(lbelow11)
+
+ lbelow10 -= lbelow11
+ m23 &^= uint32(lbelow12)
+
+ m22 += uint32(lbelow10)
+ lbelow11 -= lbelow12
+
+ m22 <<= 16
+ m23 += uint32(lbelow11)
+
+ m23 <<= 24
+ m2 += int64(m22)
+
+ m3 <<= 51
+ lbelow13 = l - 13
+
+ lbelow13 >>= 31
+ lbelow14 = l - 14
+
+ lbelow14 >>= 31
+ p += lbelow13
+ lbelow15 = l - 15
+
+ m30 = uint32(m[p+12])
+ lbelow15 >>= 31
+ p += lbelow14
+
+ m31 = uint32(m[p+13])
+ p += lbelow15
+ m2 += int64(m23)
+
+ m32 = uint32(m[p+14])
+ m30 &^= uint32(lbelow13)
+ lbelow12 -= lbelow13
+
+ m30 += uint32(lbelow12)
+ lbelow13 -= lbelow14
+
+ m3 += int64(m30)
+ m31 &^= uint32(lbelow14)
+
+ m31 += uint32(lbelow13)
+ m32 &^= uint32(lbelow15)
+
+ m31 <<= 8
+ lbelow14 -= lbelow15
+
+ m3 += int64(m31)
+ m32 += uint32(lbelow14)
+ d0 = m0
+
+ m32 <<= 16
+ m33 = uint64(lbelow15 + 1)
+ d1 = m1
+
+ m33 <<= 24
+ m3 += int64(m32)
+ d2 = m2
+
+ m3 += int64(m33)
+ d3 = m3
+
+ z3 = math.Float64frombits(uint64(d3))
+
+ z2 = math.Float64frombits(uint64(d2))
+
+ z1 = math.Float64frombits(uint64(d1))
+
+ z0 = math.Float64frombits(uint64(d0))
+
+ z3 -= alpha96
+
+ z2 -= alpha64
+
+ z1 -= alpha32
+
+ z0 -= alpha0
+
+ h5 += z3
+
+ h3 += z2
+
+ h1 += z1
+
+ h0 += z0
+
+ y7 = h7 + alpha130
+
+ y6 = h6 + alpha130
+
+ y1 = h1 + alpha32
+
+ y0 = h0 + alpha32
+
+ y7 -= alpha130
+
+ y6 -= alpha130
+
+ y1 -= alpha32
+
+ y0 -= alpha32
+
+ y5 = h5 + alpha96
+
+ y4 = h4 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ x6 = h6 - y6
+ y6 *= scale
+
+ x1 = h1 - y1
+
+ x0 = h0 - y0
+
+ y5 -= alpha96
+
+ y4 -= alpha96
+
+ x1 += y7
+
+ x0 += y6
+
+ x7 += y5
+
+ x6 += y4
+
+ y3 = h3 + alpha64
+
+ y2 = h2 + alpha64
+
+ x0 += x1
+
+ x6 += x7
+
+ y3 -= alpha64
+ r3low = r3low_stack
+
+ y2 -= alpha64
+ r0low = r0low_stack
+
+ x5 = h5 - y5
+ r3lowx0 = r3low * x0
+ r3high = r3high_stack
+
+ x4 = h4 - y4
+ r0lowx6 = r0low * x6
+ r0high = r0high_stack
+
+ x3 = h3 - y3
+ r3highx0 = r3high * x0
+ sr1low = sr1low_stack
+
+ x2 = h2 - y2
+ r0highx6 = r0high * x6
+ sr1high = sr1high_stack
+
+ x5 += y3
+ r0lowx0 = r0low * x0
+ r1low = r1low_stack
+
+ h6 = r3lowx0 + r0lowx6
+ sr1lowx6 = sr1low * x6
+ r1high = r1high_stack
+
+ x4 += y2
+ r0highx0 = r0high * x0
+ sr2low = sr2low_stack
+
+ h7 = r3highx0 + r0highx6
+ sr1highx6 = sr1high * x6
+ sr2high = sr2high_stack
+
+ x3 += y1
+ r1lowx0 = r1low * x0
+ r2low = r2low_stack
+
+ h0 = r0lowx0 + sr1lowx6
+ sr2lowx6 = sr2low * x6
+ r2high = r2high_stack
+
+ x2 += y0
+ r1highx0 = r1high * x0
+ sr3low = sr3low_stack
+
+ h1 = r0highx0 + sr1highx6
+ sr2highx6 = sr2high * x6
+ sr3high = sr3high_stack
+
+ x4 += x5
+ r2lowx0 = r2low * x0
+
+ h2 = r1lowx0 + sr2lowx6
+ sr3lowx6 = sr3low * x6
+
+ x2 += x3
+ r2highx0 = r2high * x0
+
+ h3 = r1highx0 + sr2highx6
+ sr3highx6 = sr3high * x6
+
+ r1highx4 = r1high * x4
+
+ h4 = r2lowx0 + sr3lowx6
+ r1lowx4 = r1low * x4
+
+ r0highx4 = r0high * x4
+
+ h5 = r2highx0 + sr3highx6
+ r0lowx4 = r0low * x4
+
+ h7 += r1highx4
+ sr3highx4 = sr3high * x4
+
+ h6 += r1lowx4
+ sr3lowx4 = sr3low * x4
+
+ h5 += r0highx4
+ sr2highx4 = sr2high * x4
+
+ h4 += r0lowx4
+ sr2lowx4 = sr2low * x4
+
+ h3 += sr3highx4
+ r0lowx2 = r0low * x2
+
+ h2 += sr3lowx4
+ r0highx2 = r0high * x2
+
+ h1 += sr2highx4
+ r1lowx2 = r1low * x2
+
+ h0 += sr2lowx4
+ r1highx2 = r1high * x2
+
+ h2 += r0lowx2
+ r2lowx2 = r2low * x2
+
+ h3 += r0highx2
+ r2highx2 = r2high * x2
+
+ h4 += r1lowx2
+ sr3lowx2 = sr3low * x2
+
+ h5 += r1highx2
+ sr3highx2 = sr3high * x2
+
+ h6 += r2lowx2
+
+ h7 += r2highx2
+
+ h0 += sr3lowx2
+
+ h1 += sr3highx2
+
+nomorebytes:
+
+ y7 = h7 + alpha130
+
+ y0 = h0 + alpha32
+
+ y1 = h1 + alpha32
+
+ y2 = h2 + alpha64
+
+ y7 -= alpha130
+
+ y3 = h3 + alpha64
+
+ y4 = h4 + alpha96
+
+ y5 = h5 + alpha96
+
+ x7 = h7 - y7
+ y7 *= scale
+
+ y0 -= alpha32
+
+ y1 -= alpha32
+
+ y2 -= alpha64
+
+ h6 += x7
+
+ y3 -= alpha64
+
+ y4 -= alpha96
+
+ y5 -= alpha96
+
+ y6 = h6 + alpha130
+
+ x0 = h0 - y0
+
+ x1 = h1 - y1
+
+ x2 = h2 - y2
+
+ y6 -= alpha130
+
+ x0 += y7
+
+ x3 = h3 - y3
+
+ x4 = h4 - y4
+
+ x5 = h5 - y5
+
+ x6 = h6 - y6
+
+ y6 *= scale
+
+ x2 += y0
+
+ x3 += y1
+
+ x4 += y2
+
+ x0 += y6
+
+ x5 += y3
+
+ x6 += y4
+
+ x2 += x3
+
+ x0 += x1
+
+ x4 += x5
+
+ x6 += y5
+
+ x2 += offset1
+ d1 = int64(math.Float64bits(x2))
+
+ x0 += offset0
+ d0 = int64(math.Float64bits(x0))
+
+ x4 += offset2
+ d2 = int64(math.Float64bits(x4))
+
+ x6 += offset3
+ d3 = int64(math.Float64bits(x6))
+
+ f0 = uint64(d0)
+
+ f1 = uint64(d1)
+ bits32 = math.MaxUint64
+
+ f2 = uint64(d2)
+ bits32 >>= 32
+
+ f3 = uint64(d3)
+ f = f0 >> 32
+
+ f0 &= bits32
+ f &= 255
+
+ f1 += f
+ g0 = f0 + 5
+
+ g = g0 >> 32
+ g0 &= bits32
+
+ f = f1 >> 32
+ f1 &= bits32
+
+ f &= 255
+ g1 = f1 + g
+
+ g = g1 >> 32
+ f2 += f
+
+ f = f2 >> 32
+ g1 &= bits32
+
+ f2 &= bits32
+ f &= 255
+
+ f3 += f
+ g2 = f2 + g
+
+ g = g2 >> 32
+ g2 &= bits32
+
+ f4 = f3 >> 32
+ f3 &= bits32
+
+ f4 &= 255
+ g3 = f3 + g
+
+ g = g3 >> 32
+ g3 &= bits32
+
+ g4 = f4 + g
+
+ g4 = g4 - 4
+ s00 = uint32(s[0])
+
+ f = uint64(int64(g4) >> 63)
+ s01 = uint32(s[1])
+
+ f0 &= f
+ g0 &^= f
+ s02 = uint32(s[2])
+
+ f1 &= f
+ f0 |= g0
+ s03 = uint32(s[3])
+
+ g1 &^= f
+ f2 &= f
+ s10 = uint32(s[4])
+
+ f3 &= f
+ g2 &^= f
+ s11 = uint32(s[5])
+
+ g3 &^= f
+ f1 |= g1
+ s12 = uint32(s[6])
+
+ f2 |= g2
+ f3 |= g3
+ s13 = uint32(s[7])
+
+ s01 <<= 8
+ f0 += uint64(s00)
+ s20 = uint32(s[8])
+
+ s02 <<= 16
+ f0 += uint64(s01)
+ s21 = uint32(s[9])
+
+ s03 <<= 24
+ f0 += uint64(s02)
+ s22 = uint32(s[10])
+
+ s11 <<= 8
+ f1 += uint64(s10)
+ s23 = uint32(s[11])
+
+ s12 <<= 16
+ f1 += uint64(s11)
+ s30 = uint32(s[12])
+
+ s13 <<= 24
+ f1 += uint64(s12)
+ s31 = uint32(s[13])
+
+ f0 += uint64(s03)
+ f1 += uint64(s13)
+ s32 = uint32(s[14])
+
+ s21 <<= 8
+ f2 += uint64(s20)
+ s33 = uint32(s[15])
+
+ s22 <<= 16
+ f2 += uint64(s21)
+
+ s23 <<= 24
+ f2 += uint64(s22)
+
+ s31 <<= 8
+ f3 += uint64(s30)
+
+ s32 <<= 16
+ f3 += uint64(s31)
+
+ s33 <<= 24
+ f3 += uint64(s32)
+
+ f2 += uint64(s23)
+ f3 += uint64(s33)
+
+ out[0] = byte(f0)
+ f0 >>= 8
+ out[1] = byte(f0)
+ f0 >>= 8
+ out[2] = byte(f0)
+ f0 >>= 8
+ out[3] = byte(f0)
+ f0 >>= 8
+ f1 += f0
+
+ out[4] = byte(f1)
+ f1 >>= 8
+ out[5] = byte(f1)
+ f1 >>= 8
+ out[6] = byte(f1)
+ f1 >>= 8
+ out[7] = byte(f1)
+ f1 >>= 8
+ f2 += f1
+
+ out[8] = byte(f2)
+ f2 >>= 8
+ out[9] = byte(f2)
+ f2 >>= 8
+ out[10] = byte(f2)
+ f2 >>= 8
+ out[11] = byte(f2)
+ f2 >>= 8
+ f3 += f2
+
+ out[12] = byte(f3)
+ f3 >>= 8
+ out[13] = byte(f3)
+ f3 >>= 8
+ out[14] = byte(f3)
+ f3 >>= 8
+ out[15] = byte(f3)
+}
diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go
new file mode 100644
index 000000000..6c6e84236
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160.go
@@ -0,0 +1,120 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ripemd160 implements the RIPEMD-160 hash algorithm.
+package ripemd160 // import "golang.org/x/crypto/ripemd160"
+
+// RIPEMD-160 is designed by by Hans Dobbertin, Antoon Bosselaers, and Bart
+// Preneel with specifications available at:
+// http://homes.esat.kuleuven.be/~cosicart/pdf/AB-9601/AB-9601.pdf.
+
+import (
+ "crypto"
+ "hash"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.RIPEMD160, New)
+}
+
+// The size of the checksum in bytes.
+const Size = 20
+
+// The block size of the hash algorithm in bytes.
+const BlockSize = 64
+
+const (
+ _s0 = 0x67452301
+ _s1 = 0xefcdab89
+ _s2 = 0x98badcfe
+ _s3 = 0x10325476
+ _s4 = 0xc3d2e1f0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [5]uint32 // running context
+ x [BlockSize]byte // temporary buffer
+ nx int // index into x
+ tc uint64 // total count of bytes processed
+}
+
+func (d *digest) Reset() {
+ d.s[0], d.s[1], d.s[2], d.s[3], d.s[4] = _s0, _s1, _s2, _s3, _s4
+ d.nx = 0
+ d.tc = 0
+}
+
+// New returns a new hash.Hash computing the checksum.
+func New() hash.Hash {
+ result := new(digest)
+ result.Reset()
+ return result
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
+ nn = len(p)
+ d.tc += uint64(nn)
+ if d.nx > 0 {
+ n := len(p)
+ if n > BlockSize-d.nx {
+ n = BlockSize - d.nx
+ }
+ for i := 0; i < n; i++ {
+ d.x[d.nx+i] = p[i]
+ }
+ d.nx += n
+ if d.nx == BlockSize {
+ _Block(d, d.x[0:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ n := _Block(d, p)
+ p = p[n:]
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d0 *digest) Sum(in []byte) []byte {
+ // Make a copy of d0 so that caller can keep writing and summing.
+ d := *d0
+
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ tc := d.tc
+ var tmp [64]byte
+ tmp[0] = 0x80
+ if tc%64 < 56 {
+ d.Write(tmp[0 : 56-tc%64])
+ } else {
+ d.Write(tmp[0 : 64+56-tc%64])
+ }
+
+ // Length in bits.
+ tc <<= 3
+ for i := uint(0); i < 8; i++ {
+ tmp[i] = byte(tc >> (8 * i))
+ }
+ d.Write(tmp[0:8])
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ var digest [Size]byte
+ for i, s := range d.s {
+ digest[i*4] = byte(s)
+ digest[i*4+1] = byte(s >> 8)
+ digest[i*4+2] = byte(s >> 16)
+ digest[i*4+3] = byte(s >> 24)
+ }
+
+ return append(in, digest[:]...)
+}
diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go
new file mode 100644
index 000000000..5df1b2593
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160_test.go
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ripemd160
+
+// Test vectors are from:
+// http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+type mdTest struct {
+ out string
+ in string
+}
+
+var vectors = [...]mdTest{
+ {"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
+ {"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
+ {"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
+ {"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
+ {"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
+ {"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
+ {"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
+ {"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
+}
+
+func TestVectors(t *testing.T) {
+ for i := 0; i < len(vectors); i++ {
+ tv := vectors[i]
+ md := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(md, tv.in)
+ } else {
+ io.WriteString(md, tv.in[0:len(tv.in)/2])
+ md.Sum(nil)
+ io.WriteString(md, tv.in[len(tv.in)/2:])
+ }
+ s := fmt.Sprintf("%x", md.Sum(nil))
+ if s != tv.out {
+ t.Fatalf("RIPEMD-160[%d](%s) = %s, expected %s", j, tv.in, s, tv.out)
+ }
+ md.Reset()
+ }
+ }
+}
+
+func TestMillionA(t *testing.T) {
+ md := New()
+ for i := 0; i < 100000; i++ {
+ io.WriteString(md, "aaaaaaaaaa")
+ }
+ out := "52783243c1697bdbe16d37f97f68f08325dc1528"
+ s := fmt.Sprintf("%x", md.Sum(nil))
+ if s != out {
+ t.Fatalf("RIPEMD-160 (1 million 'a') = %s, expected %s", s, out)
+ }
+ md.Reset()
+}
diff --git a/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go
new file mode 100644
index 000000000..7bc8e6c48
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ripemd160/ripemd160block.go
@@ -0,0 +1,161 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// RIPEMD-160 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package ripemd160
+
+// work buffer indices and roll amounts for one line
+var _n = [80]uint{
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13,
+}
+
+var _r = [80]uint{
+ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6,
+}
+
+// same for the other parallel one
+var n_ = [80]uint{
+ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11,
+}
+
+var r_ = [80]uint{
+ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11,
+}
+
+func _Block(md *digest, p []byte) int {
+ n := 0
+ var x [16]uint32
+ var alpha, beta uint32
+ for len(p) >= BlockSize {
+ a, b, c, d, e := md.s[0], md.s[1], md.s[2], md.s[3], md.s[4]
+ aa, bb, cc, dd, ee := a, b, c, d, e
+ j := 0
+ for i := 0; i < 16; i++ {
+ x[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
+ j += 4
+ }
+
+ // round 1
+ i := 0
+ for i < 16 {
+ alpha = a + (b ^ c ^ d) + x[_n[i]]
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb ^ (cc | ^dd)) + x[n_[i]] + 0x50a28be6
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 2
+ for i < 32 {
+ alpha = a + (b&c | ^b&d) + x[_n[i]] + 0x5a827999
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb&dd | cc&^dd) + x[n_[i]] + 0x5c4dd124
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 3
+ for i < 48 {
+ alpha = a + (b | ^c ^ d) + x[_n[i]] + 0x6ed9eba1
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb | ^cc ^ dd) + x[n_[i]] + 0x6d703ef3
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 4
+ for i < 64 {
+ alpha = a + (b&d | c&^d) + x[_n[i]] + 0x8f1bbcdc
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb&cc | ^bb&dd) + x[n_[i]] + 0x7a6d76e9
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // round 5
+ for i < 80 {
+ alpha = a + (b ^ (c | ^d)) + x[_n[i]] + 0xa953fd4e
+ s := _r[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + e
+ beta = c<<10 | c>>22
+ a, b, c, d, e = e, alpha, b, beta, d
+
+ // parallel line
+ alpha = aa + (bb ^ cc ^ dd) + x[n_[i]]
+ s = r_[i]
+ alpha = (alpha<<s | alpha>>(32-s)) + ee
+ beta = cc<<10 | cc>>22
+ aa, bb, cc, dd, ee = ee, alpha, bb, beta, dd
+
+ i++
+ }
+
+ // combine results
+ dd += c + md.s[1]
+ md.s[1] = md.s[2] + d + ee
+ md.s[2] = md.s[3] + e + aa
+ md.s[3] = md.s[4] + a + bb
+ md.s[4] = md.s[0] + b + cc
+ md.s[0] = dd
+
+ p = p[BlockSize:]
+ n += BlockSize
+ }
+ return n
+}
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go b/vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go
new file mode 100644
index 000000000..4c96147c8
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa/hsalsa20.go
@@ -0,0 +1,144 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package salsa provides low-level access to functions in the Salsa family.
+package salsa // import "golang.org/x/crypto/salsa20/salsa"
+
+// Sigma is the Salsa20 constant for 256-bit keys.
+var Sigma = [16]byte{'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', '2', '-', 'b', 'y', 't', 'e', ' ', 'k'}
+
+// HSalsa20 applies the HSalsa20 core function to a 16-byte input in, 32-byte
+// key k, and 16-byte constant c, and puts the result into the 32-byte array
+// out.
+func HSalsa20(out *[32]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
+ x0 := uint32(c[0]) | uint32(c[1])<<8 | uint32(c[2])<<16 | uint32(c[3])<<24
+ x1 := uint32(k[0]) | uint32(k[1])<<8 | uint32(k[2])<<16 | uint32(k[3])<<24
+ x2 := uint32(k[4]) | uint32(k[5])<<8 | uint32(k[6])<<16 | uint32(k[7])<<24
+ x3 := uint32(k[8]) | uint32(k[9])<<8 | uint32(k[10])<<16 | uint32(k[11])<<24
+ x4 := uint32(k[12]) | uint32(k[13])<<8 | uint32(k[14])<<16 | uint32(k[15])<<24
+ x5 := uint32(c[4]) | uint32(c[5])<<8 | uint32(c[6])<<16 | uint32(c[7])<<24
+ x6 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
+ x7 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
+ x8 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
+ x9 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
+ x10 := uint32(c[8]) | uint32(c[9])<<8 | uint32(c[10])<<16 | uint32(c[11])<<24
+ x11 := uint32(k[16]) | uint32(k[17])<<8 | uint32(k[18])<<16 | uint32(k[19])<<24
+ x12 := uint32(k[20]) | uint32(k[21])<<8 | uint32(k[22])<<16 | uint32(k[23])<<24
+ x13 := uint32(k[24]) | uint32(k[25])<<8 | uint32(k[26])<<16 | uint32(k[27])<<24
+ x14 := uint32(k[28]) | uint32(k[29])<<8 | uint32(k[30])<<16 | uint32(k[31])<<24
+ x15 := uint32(c[12]) | uint32(c[13])<<8 | uint32(c[14])<<16 | uint32(c[15])<<24
+
+ for i := 0; i < 20; i += 2 {
+ u := x0 + x12
+ x4 ^= u<<7 | u>>(32-7)
+ u = x4 + x0
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x4
+ x12 ^= u<<13 | u>>(32-13)
+ u = x12 + x8
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x1
+ x9 ^= u<<7 | u>>(32-7)
+ u = x9 + x5
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x9
+ x1 ^= u<<13 | u>>(32-13)
+ u = x1 + x13
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x6
+ x14 ^= u<<7 | u>>(32-7)
+ u = x14 + x10
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x14
+ x6 ^= u<<13 | u>>(32-13)
+ u = x6 + x2
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x11
+ x3 ^= u<<7 | u>>(32-7)
+ u = x3 + x15
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x3
+ x11 ^= u<<13 | u>>(32-13)
+ u = x11 + x7
+ x15 ^= u<<18 | u>>(32-18)
+
+ u = x0 + x3
+ x1 ^= u<<7 | u>>(32-7)
+ u = x1 + x0
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x1
+ x3 ^= u<<13 | u>>(32-13)
+ u = x3 + x2
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x4
+ x6 ^= u<<7 | u>>(32-7)
+ u = x6 + x5
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x6
+ x4 ^= u<<13 | u>>(32-13)
+ u = x4 + x7
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x9
+ x11 ^= u<<7 | u>>(32-7)
+ u = x11 + x10
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x11
+ x9 ^= u<<13 | u>>(32-13)
+ u = x9 + x8
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x14
+ x12 ^= u<<7 | u>>(32-7)
+ u = x12 + x15
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x12
+ x14 ^= u<<13 | u>>(32-13)
+ u = x14 + x13
+ x15 ^= u<<18 | u>>(32-18)
+ }
+ out[0] = byte(x0)
+ out[1] = byte(x0 >> 8)
+ out[2] = byte(x0 >> 16)
+ out[3] = byte(x0 >> 24)
+
+ out[4] = byte(x5)
+ out[5] = byte(x5 >> 8)
+ out[6] = byte(x5 >> 16)
+ out[7] = byte(x5 >> 24)
+
+ out[8] = byte(x10)
+ out[9] = byte(x10 >> 8)
+ out[10] = byte(x10 >> 16)
+ out[11] = byte(x10 >> 24)
+
+ out[12] = byte(x15)
+ out[13] = byte(x15 >> 8)
+ out[14] = byte(x15 >> 16)
+ out[15] = byte(x15 >> 24)
+
+ out[16] = byte(x6)
+ out[17] = byte(x6 >> 8)
+ out[18] = byte(x6 >> 16)
+ out[19] = byte(x6 >> 24)
+
+ out[20] = byte(x7)
+ out[21] = byte(x7 >> 8)
+ out[22] = byte(x7 >> 16)
+ out[23] = byte(x7 >> 24)
+
+ out[24] = byte(x8)
+ out[25] = byte(x8 >> 8)
+ out[26] = byte(x8 >> 16)
+ out[27] = byte(x8 >> 24)
+
+ out[28] = byte(x9)
+ out[29] = byte(x9 >> 8)
+ out[30] = byte(x9 >> 16)
+ out[31] = byte(x9 >> 24)
+}
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa/salsa2020_amd64.s b/vendor/golang.org/x/crypto/salsa20/salsa/salsa2020_amd64.s
new file mode 100644
index 000000000..6e1df9639
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa/salsa2020_amd64.s
@@ -0,0 +1,902 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!appengine,!gccgo
+
+// This code was translated into a form compatible with 6a from the public
+// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
+
+// func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
+TEXT ·salsa2020XORKeyStream(SB),0,$512-40
+ MOVQ out+0(FP),DI
+ MOVQ in+8(FP),SI
+ MOVQ n+16(FP),DX
+ MOVQ nonce+24(FP),CX
+ MOVQ key+32(FP),R8
+
+ MOVQ SP,R11
+ MOVQ $31,R9
+ NOTQ R9
+ ANDQ R9,SP
+ ADDQ $32,SP
+
+ MOVQ R11,352(SP)
+ MOVQ R12,360(SP)
+ MOVQ R13,368(SP)
+ MOVQ R14,376(SP)
+ MOVQ R15,384(SP)
+ MOVQ BX,392(SP)
+ MOVQ BP,400(SP)
+ MOVQ DX,R9
+ MOVQ CX,DX
+ MOVQ R8,R10
+ CMPQ R9,$0
+ JBE DONE
+ START:
+ MOVL 20(R10),CX
+ MOVL 0(R10),R8
+ MOVL 0(DX),AX
+ MOVL 16(R10),R11
+ MOVL CX,0(SP)
+ MOVL R8, 4 (SP)
+ MOVL AX, 8 (SP)
+ MOVL R11, 12 (SP)
+ MOVL 8(DX),CX
+ MOVL 24(R10),R8
+ MOVL 4(R10),AX
+ MOVL 4(DX),R11
+ MOVL CX,16(SP)
+ MOVL R8, 20 (SP)
+ MOVL AX, 24 (SP)
+ MOVL R11, 28 (SP)
+ MOVL 12(DX),CX
+ MOVL 12(R10),DX
+ MOVL 28(R10),R8
+ MOVL 8(R10),AX
+ MOVL DX,32(SP)
+ MOVL CX, 36 (SP)
+ MOVL R8, 40 (SP)
+ MOVL AX, 44 (SP)
+ MOVQ $1634760805,DX
+ MOVQ $857760878,CX
+ MOVQ $2036477234,R8
+ MOVQ $1797285236,AX
+ MOVL DX,48(SP)
+ MOVL CX, 52 (SP)
+ MOVL R8, 56 (SP)
+ MOVL AX, 60 (SP)
+ CMPQ R9,$256
+ JB BYTESBETWEEN1AND255
+ MOVOA 48(SP),X0
+ PSHUFL $0X55,X0,X1
+ PSHUFL $0XAA,X0,X2
+ PSHUFL $0XFF,X0,X3
+ PSHUFL $0X00,X0,X0
+ MOVOA X1,64(SP)
+ MOVOA X2,80(SP)
+ MOVOA X3,96(SP)
+ MOVOA X0,112(SP)
+ MOVOA 0(SP),X0
+ PSHUFL $0XAA,X0,X1
+ PSHUFL $0XFF,X0,X2
+ PSHUFL $0X00,X0,X3
+ PSHUFL $0X55,X0,X0
+ MOVOA X1,128(SP)
+ MOVOA X2,144(SP)
+ MOVOA X3,160(SP)
+ MOVOA X0,176(SP)
+ MOVOA 16(SP),X0
+ PSHUFL $0XFF,X0,X1
+ PSHUFL $0X55,X0,X2
+ PSHUFL $0XAA,X0,X0
+ MOVOA X1,192(SP)
+ MOVOA X2,208(SP)
+ MOVOA X0,224(SP)
+ MOVOA 32(SP),X0
+ PSHUFL $0X00,X0,X1
+ PSHUFL $0XAA,X0,X2
+ PSHUFL $0XFF,X0,X0
+ MOVOA X1,240(SP)
+ MOVOA X2,256(SP)
+ MOVOA X0,272(SP)
+ BYTESATLEAST256:
+ MOVL 16(SP),DX
+ MOVL 36 (SP),CX
+ MOVL DX,288(SP)
+ MOVL CX,304(SP)
+ ADDQ $1,DX
+ SHLQ $32,CX
+ ADDQ CX,DX
+ MOVQ DX,CX
+ SHRQ $32,CX
+ MOVL DX, 292 (SP)
+ MOVL CX, 308 (SP)
+ ADDQ $1,DX
+ SHLQ $32,CX
+ ADDQ CX,DX
+ MOVQ DX,CX
+ SHRQ $32,CX
+ MOVL DX, 296 (SP)
+ MOVL CX, 312 (SP)
+ ADDQ $1,DX
+ SHLQ $32,CX
+ ADDQ CX,DX
+ MOVQ DX,CX
+ SHRQ $32,CX
+ MOVL DX, 300 (SP)
+ MOVL CX, 316 (SP)
+ ADDQ $1,DX
+ SHLQ $32,CX
+ ADDQ CX,DX
+ MOVQ DX,CX
+ SHRQ $32,CX
+ MOVL DX,16(SP)
+ MOVL CX, 36 (SP)
+ MOVQ R9,408(SP)
+ MOVQ $20,DX
+ MOVOA 64(SP),X0
+ MOVOA 80(SP),X1
+ MOVOA 96(SP),X2
+ MOVOA 256(SP),X3
+ MOVOA 272(SP),X4
+ MOVOA 128(SP),X5
+ MOVOA 144(SP),X6
+ MOVOA 176(SP),X7
+ MOVOA 192(SP),X8
+ MOVOA 208(SP),X9
+ MOVOA 224(SP),X10
+ MOVOA 304(SP),X11
+ MOVOA 112(SP),X12
+ MOVOA 160(SP),X13
+ MOVOA 240(SP),X14
+ MOVOA 288(SP),X15
+ MAINLOOP1:
+ MOVOA X1,320(SP)
+ MOVOA X2,336(SP)
+ MOVOA X13,X1
+ PADDL X12,X1
+ MOVOA X1,X2
+ PSLLL $7,X1
+ PXOR X1,X14
+ PSRLL $25,X2
+ PXOR X2,X14
+ MOVOA X7,X1
+ PADDL X0,X1
+ MOVOA X1,X2
+ PSLLL $7,X1
+ PXOR X1,X11
+ PSRLL $25,X2
+ PXOR X2,X11
+ MOVOA X12,X1
+ PADDL X14,X1
+ MOVOA X1,X2
+ PSLLL $9,X1
+ PXOR X1,X15
+ PSRLL $23,X2
+ PXOR X2,X15
+ MOVOA X0,X1
+ PADDL X11,X1
+ MOVOA X1,X2
+ PSLLL $9,X1
+ PXOR X1,X9
+ PSRLL $23,X2
+ PXOR X2,X9
+ MOVOA X14,X1
+ PADDL X15,X1
+ MOVOA X1,X2
+ PSLLL $13,X1
+ PXOR X1,X13
+ PSRLL $19,X2
+ PXOR X2,X13
+ MOVOA X11,X1
+ PADDL X9,X1
+ MOVOA X1,X2
+ PSLLL $13,X1
+ PXOR X1,X7
+ PSRLL $19,X2
+ PXOR X2,X7
+ MOVOA X15,X1
+ PADDL X13,X1
+ MOVOA X1,X2
+ PSLLL $18,X1
+ PXOR X1,X12
+ PSRLL $14,X2
+ PXOR X2,X12
+ MOVOA 320(SP),X1
+ MOVOA X12,320(SP)
+ MOVOA X9,X2
+ PADDL X7,X2
+ MOVOA X2,X12
+ PSLLL $18,X2
+ PXOR X2,X0
+ PSRLL $14,X12
+ PXOR X12,X0
+ MOVOA X5,X2
+ PADDL X1,X2
+ MOVOA X2,X12
+ PSLLL $7,X2
+ PXOR X2,X3
+ PSRLL $25,X12
+ PXOR X12,X3
+ MOVOA 336(SP),X2
+ MOVOA X0,336(SP)
+ MOVOA X6,X0
+ PADDL X2,X0
+ MOVOA X0,X12
+ PSLLL $7,X0
+ PXOR X0,X4
+ PSRLL $25,X12
+ PXOR X12,X4
+ MOVOA X1,X0
+ PADDL X3,X0
+ MOVOA X0,X12
+ PSLLL $9,X0
+ PXOR X0,X10
+ PSRLL $23,X12
+ PXOR X12,X10
+ MOVOA X2,X0
+ PADDL X4,X0
+ MOVOA X0,X12
+ PSLLL $9,X0
+ PXOR X0,X8
+ PSRLL $23,X12
+ PXOR X12,X8
+ MOVOA X3,X0
+ PADDL X10,X0
+ MOVOA X0,X12
+ PSLLL $13,X0
+ PXOR X0,X5
+ PSRLL $19,X12
+ PXOR X12,X5
+ MOVOA X4,X0
+ PADDL X8,X0
+ MOVOA X0,X12
+ PSLLL $13,X0
+ PXOR X0,X6
+ PSRLL $19,X12
+ PXOR X12,X6
+ MOVOA X10,X0
+ PADDL X5,X0
+ MOVOA X0,X12
+ PSLLL $18,X0
+ PXOR X0,X1
+ PSRLL $14,X12
+ PXOR X12,X1
+ MOVOA 320(SP),X0
+ MOVOA X1,320(SP)
+ MOVOA X4,X1
+ PADDL X0,X1
+ MOVOA X1,X12
+ PSLLL $7,X1
+ PXOR X1,X7
+ PSRLL $25,X12
+ PXOR X12,X7
+ MOVOA X8,X1
+ PADDL X6,X1
+ MOVOA X1,X12
+ PSLLL $18,X1
+ PXOR X1,X2
+ PSRLL $14,X12
+ PXOR X12,X2
+ MOVOA 336(SP),X12
+ MOVOA X2,336(SP)
+ MOVOA X14,X1
+ PADDL X12,X1
+ MOVOA X1,X2
+ PSLLL $7,X1
+ PXOR X1,X5
+ PSRLL $25,X2
+ PXOR X2,X5
+ MOVOA X0,X1
+ PADDL X7,X1
+ MOVOA X1,X2
+ PSLLL $9,X1
+ PXOR X1,X10
+ PSRLL $23,X2
+ PXOR X2,X10
+ MOVOA X12,X1
+ PADDL X5,X1
+ MOVOA X1,X2
+ PSLLL $9,X1
+ PXOR X1,X8
+ PSRLL $23,X2
+ PXOR X2,X8
+ MOVOA X7,X1
+ PADDL X10,X1
+ MOVOA X1,X2
+ PSLLL $13,X1
+ PXOR X1,X4
+ PSRLL $19,X2
+ PXOR X2,X4
+ MOVOA X5,X1
+ PADDL X8,X1
+ MOVOA X1,X2
+ PSLLL $13,X1
+ PXOR X1,X14
+ PSRLL $19,X2
+ PXOR X2,X14
+ MOVOA X10,X1
+ PADDL X4,X1
+ MOVOA X1,X2
+ PSLLL $18,X1
+ PXOR X1,X0
+ PSRLL $14,X2
+ PXOR X2,X0
+ MOVOA 320(SP),X1
+ MOVOA X0,320(SP)
+ MOVOA X8,X0
+ PADDL X14,X0
+ MOVOA X0,X2
+ PSLLL $18,X0
+ PXOR X0,X12
+ PSRLL $14,X2
+ PXOR X2,X12
+ MOVOA X11,X0
+ PADDL X1,X0
+ MOVOA X0,X2
+ PSLLL $7,X0
+ PXOR X0,X6
+ PSRLL $25,X2
+ PXOR X2,X6
+ MOVOA 336(SP),X2
+ MOVOA X12,336(SP)
+ MOVOA X3,X0
+ PADDL X2,X0
+ MOVOA X0,X12
+ PSLLL $7,X0
+ PXOR X0,X13
+ PSRLL $25,X12
+ PXOR X12,X13
+ MOVOA X1,X0
+ PADDL X6,X0
+ MOVOA X0,X12
+ PSLLL $9,X0
+ PXOR X0,X15
+ PSRLL $23,X12
+ PXOR X12,X15
+ MOVOA X2,X0
+ PADDL X13,X0
+ MOVOA X0,X12
+ PSLLL $9,X0
+ PXOR X0,X9
+ PSRLL $23,X12
+ PXOR X12,X9
+ MOVOA X6,X0
+ PADDL X15,X0
+ MOVOA X0,X12
+ PSLLL $13,X0
+ PXOR X0,X11
+ PSRLL $19,X12
+ PXOR X12,X11
+ MOVOA X13,X0
+ PADDL X9,X0
+ MOVOA X0,X12
+ PSLLL $13,X0
+ PXOR X0,X3
+ PSRLL $19,X12
+ PXOR X12,X3
+ MOVOA X15,X0
+ PADDL X11,X0
+ MOVOA X0,X12
+ PSLLL $18,X0
+ PXOR X0,X1
+ PSRLL $14,X12
+ PXOR X12,X1
+ MOVOA X9,X0
+ PADDL X3,X0
+ MOVOA X0,X12
+ PSLLL $18,X0
+ PXOR X0,X2
+ PSRLL $14,X12
+ PXOR X12,X2
+ MOVOA 320(SP),X12
+ MOVOA 336(SP),X0
+ SUBQ $2,DX
+ JA MAINLOOP1
+ PADDL 112(SP),X12
+ PADDL 176(SP),X7
+ PADDL 224(SP),X10
+ PADDL 272(SP),X4
+ MOVD X12,DX
+ MOVD X7,CX
+ MOVD X10,R8
+ MOVD X4,R9
+ PSHUFL $0X39,X12,X12
+ PSHUFL $0X39,X7,X7
+ PSHUFL $0X39,X10,X10
+ PSHUFL $0X39,X4,X4
+ XORL 0(SI),DX
+ XORL 4(SI),CX
+ XORL 8(SI),R8
+ XORL 12(SI),R9
+ MOVL DX,0(DI)
+ MOVL CX,4(DI)
+ MOVL R8,8(DI)
+ MOVL R9,12(DI)
+ MOVD X12,DX
+ MOVD X7,CX
+ MOVD X10,R8
+ MOVD X4,R9
+ PSHUFL $0X39,X12,X12
+ PSHUFL $0X39,X7,X7
+ PSHUFL $0X39,X10,X10
+ PSHUFL $0X39,X4,X4
+ XORL 64(SI),DX
+ XORL 68(SI),CX
+ XORL 72(SI),R8
+ XORL 76(SI),R9
+ MOVL DX,64(DI)
+ MOVL CX,68(DI)
+ MOVL R8,72(DI)
+ MOVL R9,76(DI)
+ MOVD X12,DX
+ MOVD X7,CX
+ MOVD X10,R8
+ MOVD X4,R9
+ PSHUFL $0X39,X12,X12
+ PSHUFL $0X39,X7,X7
+ PSHUFL $0X39,X10,X10
+ PSHUFL $0X39,X4,X4
+ XORL 128(SI),DX
+ XORL 132(SI),CX
+ XORL 136(SI),R8
+ XORL 140(SI),R9
+ MOVL DX,128(DI)
+ MOVL CX,132(DI)
+ MOVL R8,136(DI)
+ MOVL R9,140(DI)
+ MOVD X12,DX
+ MOVD X7,CX
+ MOVD X10,R8
+ MOVD X4,R9
+ XORL 192(SI),DX
+ XORL 196(SI),CX
+ XORL 200(SI),R8
+ XORL 204(SI),R9
+ MOVL DX,192(DI)
+ MOVL CX,196(DI)
+ MOVL R8,200(DI)
+ MOVL R9,204(DI)
+ PADDL 240(SP),X14
+ PADDL 64(SP),X0
+ PADDL 128(SP),X5
+ PADDL 192(SP),X8
+ MOVD X14,DX
+ MOVD X0,CX
+ MOVD X5,R8
+ MOVD X8,R9
+ PSHUFL $0X39,X14,X14
+ PSHUFL $0X39,X0,X0
+ PSHUFL $0X39,X5,X5
+ PSHUFL $0X39,X8,X8
+ XORL 16(SI),DX
+ XORL 20(SI),CX
+ XORL 24(SI),R8
+ XORL 28(SI),R9
+ MOVL DX,16(DI)
+ MOVL CX,20(DI)
+ MOVL R8,24(DI)
+ MOVL R9,28(DI)
+ MOVD X14,DX
+ MOVD X0,CX
+ MOVD X5,R8
+ MOVD X8,R9
+ PSHUFL $0X39,X14,X14
+ PSHUFL $0X39,X0,X0
+ PSHUFL $0X39,X5,X5
+ PSHUFL $0X39,X8,X8
+ XORL 80(SI),DX
+ XORL 84(SI),CX
+ XORL 88(SI),R8
+ XORL 92(SI),R9
+ MOVL DX,80(DI)
+ MOVL CX,84(DI)
+ MOVL R8,88(DI)
+ MOVL R9,92(DI)
+ MOVD X14,DX
+ MOVD X0,CX
+ MOVD X5,R8
+ MOVD X8,R9
+ PSHUFL $0X39,X14,X14
+ PSHUFL $0X39,X0,X0
+ PSHUFL $0X39,X5,X5
+ PSHUFL $0X39,X8,X8
+ XORL 144(SI),DX
+ XORL 148(SI),CX
+ XORL 152(SI),R8
+ XORL 156(SI),R9
+ MOVL DX,144(DI)
+ MOVL CX,148(DI)
+ MOVL R8,152(DI)
+ MOVL R9,156(DI)
+ MOVD X14,DX
+ MOVD X0,CX
+ MOVD X5,R8
+ MOVD X8,R9
+ XORL 208(SI),DX
+ XORL 212(SI),CX
+ XORL 216(SI),R8
+ XORL 220(SI),R9
+ MOVL DX,208(DI)
+ MOVL CX,212(DI)
+ MOVL R8,216(DI)
+ MOVL R9,220(DI)
+ PADDL 288(SP),X15
+ PADDL 304(SP),X11
+ PADDL 80(SP),X1
+ PADDL 144(SP),X6
+ MOVD X15,DX
+ MOVD X11,CX
+ MOVD X1,R8
+ MOVD X6,R9
+ PSHUFL $0X39,X15,X15
+ PSHUFL $0X39,X11,X11
+ PSHUFL $0X39,X1,X1
+ PSHUFL $0X39,X6,X6
+ XORL 32(SI),DX
+ XORL 36(SI),CX
+ XORL 40(SI),R8
+ XORL 44(SI),R9
+ MOVL DX,32(DI)
+ MOVL CX,36(DI)
+ MOVL R8,40(DI)
+ MOVL R9,44(DI)
+ MOVD X15,DX
+ MOVD X11,CX
+ MOVD X1,R8
+ MOVD X6,R9
+ PSHUFL $0X39,X15,X15
+ PSHUFL $0X39,X11,X11
+ PSHUFL $0X39,X1,X1
+ PSHUFL $0X39,X6,X6
+ XORL 96(SI),DX
+ XORL 100(SI),CX
+ XORL 104(SI),R8
+ XORL 108(SI),R9
+ MOVL DX,96(DI)
+ MOVL CX,100(DI)
+ MOVL R8,104(DI)
+ MOVL R9,108(DI)
+ MOVD X15,DX
+ MOVD X11,CX
+ MOVD X1,R8
+ MOVD X6,R9
+ PSHUFL $0X39,X15,X15
+ PSHUFL $0X39,X11,X11
+ PSHUFL $0X39,X1,X1
+ PSHUFL $0X39,X6,X6
+ XORL 160(SI),DX
+ XORL 164(SI),CX
+ XORL 168(SI),R8
+ XORL 172(SI),R9
+ MOVL DX,160(DI)
+ MOVL CX,164(DI)
+ MOVL R8,168(DI)
+ MOVL R9,172(DI)
+ MOVD X15,DX
+ MOVD X11,CX
+ MOVD X1,R8
+ MOVD X6,R9
+ XORL 224(SI),DX
+ XORL 228(SI),CX
+ XORL 232(SI),R8
+ XORL 236(SI),R9
+ MOVL DX,224(DI)
+ MOVL CX,228(DI)
+ MOVL R8,232(DI)
+ MOVL R9,236(DI)
+ PADDL 160(SP),X13
+ PADDL 208(SP),X9
+ PADDL 256(SP),X3
+ PADDL 96(SP),X2
+ MOVD X13,DX
+ MOVD X9,CX
+ MOVD X3,R8
+ MOVD X2,R9
+ PSHUFL $0X39,X13,X13
+ PSHUFL $0X39,X9,X9
+ PSHUFL $0X39,X3,X3
+ PSHUFL $0X39,X2,X2
+ XORL 48(SI),DX
+ XORL 52(SI),CX
+ XORL 56(SI),R8
+ XORL 60(SI),R9
+ MOVL DX,48(DI)
+ MOVL CX,52(DI)
+ MOVL R8,56(DI)
+ MOVL R9,60(DI)
+ MOVD X13,DX
+ MOVD X9,CX
+ MOVD X3,R8
+ MOVD X2,R9
+ PSHUFL $0X39,X13,X13
+ PSHUFL $0X39,X9,X9
+ PSHUFL $0X39,X3,X3
+ PSHUFL $0X39,X2,X2
+ XORL 112(SI),DX
+ XORL 116(SI),CX
+ XORL 120(SI),R8
+ XORL 124(SI),R9
+ MOVL DX,112(DI)
+ MOVL CX,116(DI)
+ MOVL R8,120(DI)
+ MOVL R9,124(DI)
+ MOVD X13,DX
+ MOVD X9,CX
+ MOVD X3,R8
+ MOVD X2,R9
+ PSHUFL $0X39,X13,X13
+ PSHUFL $0X39,X9,X9
+ PSHUFL $0X39,X3,X3
+ PSHUFL $0X39,X2,X2
+ XORL 176(SI),DX
+ XORL 180(SI),CX
+ XORL 184(SI),R8
+ XORL 188(SI),R9
+ MOVL DX,176(DI)
+ MOVL CX,180(DI)
+ MOVL R8,184(DI)
+ MOVL R9,188(DI)
+ MOVD X13,DX
+ MOVD X9,CX
+ MOVD X3,R8
+ MOVD X2,R9
+ XORL 240(SI),DX
+ XORL 244(SI),CX
+ XORL 248(SI),R8
+ XORL 252(SI),R9
+ MOVL DX,240(DI)
+ MOVL CX,244(DI)
+ MOVL R8,248(DI)
+ MOVL R9,252(DI)
+ MOVQ 408(SP),R9
+ SUBQ $256,R9
+ ADDQ $256,SI
+ ADDQ $256,DI
+ CMPQ R9,$256
+ JAE BYTESATLEAST256
+ CMPQ R9,$0
+ JBE DONE
+ BYTESBETWEEN1AND255:
+ CMPQ R9,$64
+ JAE NOCOPY
+ MOVQ DI,DX
+ LEAQ 416(SP),DI
+ MOVQ R9,CX
+ REP; MOVSB
+ LEAQ 416(SP),DI
+ LEAQ 416(SP),SI
+ NOCOPY:
+ MOVQ R9,408(SP)
+ MOVOA 48(SP),X0
+ MOVOA 0(SP),X1
+ MOVOA 16(SP),X2
+ MOVOA 32(SP),X3
+ MOVOA X1,X4
+ MOVQ $20,CX
+ MAINLOOP2:
+ PADDL X0,X4
+ MOVOA X0,X5
+ MOVOA X4,X6
+ PSLLL $7,X4
+ PSRLL $25,X6
+ PXOR X4,X3
+ PXOR X6,X3
+ PADDL X3,X5
+ MOVOA X3,X4
+ MOVOA X5,X6
+ PSLLL $9,X5
+ PSRLL $23,X6
+ PXOR X5,X2
+ PSHUFL $0X93,X3,X3
+ PXOR X6,X2
+ PADDL X2,X4
+ MOVOA X2,X5
+ MOVOA X4,X6
+ PSLLL $13,X4
+ PSRLL $19,X6
+ PXOR X4,X1
+ PSHUFL $0X4E,X2,X2
+ PXOR X6,X1
+ PADDL X1,X5
+ MOVOA X3,X4
+ MOVOA X5,X6
+ PSLLL $18,X5
+ PSRLL $14,X6
+ PXOR X5,X0
+ PSHUFL $0X39,X1,X1
+ PXOR X6,X0
+ PADDL X0,X4
+ MOVOA X0,X5
+ MOVOA X4,X6
+ PSLLL $7,X4
+ PSRLL $25,X6
+ PXOR X4,X1
+ PXOR X6,X1
+ PADDL X1,X5
+ MOVOA X1,X4
+ MOVOA X5,X6
+ PSLLL $9,X5
+ PSRLL $23,X6
+ PXOR X5,X2
+ PSHUFL $0X93,X1,X1
+ PXOR X6,X2
+ PADDL X2,X4
+ MOVOA X2,X5
+ MOVOA X4,X6
+ PSLLL $13,X4
+ PSRLL $19,X6
+ PXOR X4,X3
+ PSHUFL $0X4E,X2,X2
+ PXOR X6,X3
+ PADDL X3,X5
+ MOVOA X1,X4
+ MOVOA X5,X6
+ PSLLL $18,X5
+ PSRLL $14,X6
+ PXOR X5,X0
+ PSHUFL $0X39,X3,X3
+ PXOR X6,X0
+ PADDL X0,X4
+ MOVOA X0,X5
+ MOVOA X4,X6
+ PSLLL $7,X4
+ PSRLL $25,X6
+ PXOR X4,X3
+ PXOR X6,X3
+ PADDL X3,X5
+ MOVOA X3,X4
+ MOVOA X5,X6
+ PSLLL $9,X5
+ PSRLL $23,X6
+ PXOR X5,X2
+ PSHUFL $0X93,X3,X3
+ PXOR X6,X2
+ PADDL X2,X4
+ MOVOA X2,X5
+ MOVOA X4,X6
+ PSLLL $13,X4
+ PSRLL $19,X6
+ PXOR X4,X1
+ PSHUFL $0X4E,X2,X2
+ PXOR X6,X1
+ PADDL X1,X5
+ MOVOA X3,X4
+ MOVOA X5,X6
+ PSLLL $18,X5
+ PSRLL $14,X6
+ PXOR X5,X0
+ PSHUFL $0X39,X1,X1
+ PXOR X6,X0
+ PADDL X0,X4
+ MOVOA X0,X5
+ MOVOA X4,X6
+ PSLLL $7,X4
+ PSRLL $25,X6
+ PXOR X4,X1
+ PXOR X6,X1
+ PADDL X1,X5
+ MOVOA X1,X4
+ MOVOA X5,X6
+ PSLLL $9,X5
+ PSRLL $23,X6
+ PXOR X5,X2
+ PSHUFL $0X93,X1,X1
+ PXOR X6,X2
+ PADDL X2,X4
+ MOVOA X2,X5
+ MOVOA X4,X6
+ PSLLL $13,X4
+ PSRLL $19,X6
+ PXOR X4,X3
+ PSHUFL $0X4E,X2,X2
+ PXOR X6,X3
+ SUBQ $4,CX
+ PADDL X3,X5
+ MOVOA X1,X4
+ MOVOA X5,X6
+ PSLLL $18,X5
+ PXOR X7,X7
+ PSRLL $14,X6
+ PXOR X5,X0
+ PSHUFL $0X39,X3,X3
+ PXOR X6,X0
+ JA MAINLOOP2
+ PADDL 48(SP),X0
+ PADDL 0(SP),X1
+ PADDL 16(SP),X2
+ PADDL 32(SP),X3
+ MOVD X0,CX
+ MOVD X1,R8
+ MOVD X2,R9
+ MOVD X3,AX
+ PSHUFL $0X39,X0,X0
+ PSHUFL $0X39,X1,X1
+ PSHUFL $0X39,X2,X2
+ PSHUFL $0X39,X3,X3
+ XORL 0(SI),CX
+ XORL 48(SI),R8
+ XORL 32(SI),R9
+ XORL 16(SI),AX
+ MOVL CX,0(DI)
+ MOVL R8,48(DI)
+ MOVL R9,32(DI)
+ MOVL AX,16(DI)
+ MOVD X0,CX
+ MOVD X1,R8
+ MOVD X2,R9
+ MOVD X3,AX
+ PSHUFL $0X39,X0,X0
+ PSHUFL $0X39,X1,X1
+ PSHUFL $0X39,X2,X2
+ PSHUFL $0X39,X3,X3
+ XORL 20(SI),CX
+ XORL 4(SI),R8
+ XORL 52(SI),R9
+ XORL 36(SI),AX
+ MOVL CX,20(DI)
+ MOVL R8,4(DI)
+ MOVL R9,52(DI)
+ MOVL AX,36(DI)
+ MOVD X0,CX
+ MOVD X1,R8
+ MOVD X2,R9
+ MOVD X3,AX
+ PSHUFL $0X39,X0,X0
+ PSHUFL $0X39,X1,X1
+ PSHUFL $0X39,X2,X2
+ PSHUFL $0X39,X3,X3
+ XORL 40(SI),CX
+ XORL 24(SI),R8
+ XORL 8(SI),R9
+ XORL 56(SI),AX
+ MOVL CX,40(DI)
+ MOVL R8,24(DI)
+ MOVL R9,8(DI)
+ MOVL AX,56(DI)
+ MOVD X0,CX
+ MOVD X1,R8
+ MOVD X2,R9
+ MOVD X3,AX
+ XORL 60(SI),CX
+ XORL 44(SI),R8
+ XORL 28(SI),R9
+ XORL 12(SI),AX
+ MOVL CX,60(DI)
+ MOVL R8,44(DI)
+ MOVL R9,28(DI)
+ MOVL AX,12(DI)
+ MOVQ 408(SP),R9
+ MOVL 16(SP),CX
+ MOVL 36 (SP),R8
+ ADDQ $1,CX
+ SHLQ $32,R8
+ ADDQ R8,CX
+ MOVQ CX,R8
+ SHRQ $32,R8
+ MOVL CX,16(SP)
+ MOVL R8, 36 (SP)
+ CMPQ R9,$64
+ JA BYTESATLEAST65
+ JAE BYTESATLEAST64
+ MOVQ DI,SI
+ MOVQ DX,DI
+ MOVQ R9,CX
+ REP; MOVSB
+ BYTESATLEAST64:
+ DONE:
+ MOVQ 352(SP),R11
+ MOVQ 360(SP),R12
+ MOVQ 368(SP),R13
+ MOVQ 376(SP),R14
+ MOVQ 384(SP),R15
+ MOVQ 392(SP),BX
+ MOVQ 400(SP),BP
+ MOVQ R11,SP
+ RET
+ BYTESATLEAST65:
+ SUBQ $64,R9
+ ADDQ $64,DI
+ ADDQ $64,SI
+ JMP BYTESBETWEEN1AND255
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go b/vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go
new file mode 100644
index 000000000..9bfc0927c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa/salsa208.go
@@ -0,0 +1,199 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package salsa
+
+// Core208 applies the Salsa20/8 core function to the 64-byte array in and puts
+// the result into the 64-byte array out. The input and output may be the same array.
+func Core208(out *[64]byte, in *[64]byte) {
+ j0 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
+ j1 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
+ j2 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
+ j3 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
+ j4 := uint32(in[16]) | uint32(in[17])<<8 | uint32(in[18])<<16 | uint32(in[19])<<24
+ j5 := uint32(in[20]) | uint32(in[21])<<8 | uint32(in[22])<<16 | uint32(in[23])<<24
+ j6 := uint32(in[24]) | uint32(in[25])<<8 | uint32(in[26])<<16 | uint32(in[27])<<24
+ j7 := uint32(in[28]) | uint32(in[29])<<8 | uint32(in[30])<<16 | uint32(in[31])<<24
+ j8 := uint32(in[32]) | uint32(in[33])<<8 | uint32(in[34])<<16 | uint32(in[35])<<24
+ j9 := uint32(in[36]) | uint32(in[37])<<8 | uint32(in[38])<<16 | uint32(in[39])<<24
+ j10 := uint32(in[40]) | uint32(in[41])<<8 | uint32(in[42])<<16 | uint32(in[43])<<24
+ j11 := uint32(in[44]) | uint32(in[45])<<8 | uint32(in[46])<<16 | uint32(in[47])<<24
+ j12 := uint32(in[48]) | uint32(in[49])<<8 | uint32(in[50])<<16 | uint32(in[51])<<24
+ j13 := uint32(in[52]) | uint32(in[53])<<8 | uint32(in[54])<<16 | uint32(in[55])<<24
+ j14 := uint32(in[56]) | uint32(in[57])<<8 | uint32(in[58])<<16 | uint32(in[59])<<24
+ j15 := uint32(in[60]) | uint32(in[61])<<8 | uint32(in[62])<<16 | uint32(in[63])<<24
+
+ x0, x1, x2, x3, x4, x5, x6, x7, x8 := j0, j1, j2, j3, j4, j5, j6, j7, j8
+ x9, x10, x11, x12, x13, x14, x15 := j9, j10, j11, j12, j13, j14, j15
+
+ for i := 0; i < 8; i += 2 {
+ u := x0 + x12
+ x4 ^= u<<7 | u>>(32-7)
+ u = x4 + x0
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x4
+ x12 ^= u<<13 | u>>(32-13)
+ u = x12 + x8
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x1
+ x9 ^= u<<7 | u>>(32-7)
+ u = x9 + x5
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x9
+ x1 ^= u<<13 | u>>(32-13)
+ u = x1 + x13
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x6
+ x14 ^= u<<7 | u>>(32-7)
+ u = x14 + x10
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x14
+ x6 ^= u<<13 | u>>(32-13)
+ u = x6 + x2
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x11
+ x3 ^= u<<7 | u>>(32-7)
+ u = x3 + x15
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x3
+ x11 ^= u<<13 | u>>(32-13)
+ u = x11 + x7
+ x15 ^= u<<18 | u>>(32-18)
+
+ u = x0 + x3
+ x1 ^= u<<7 | u>>(32-7)
+ u = x1 + x0
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x1
+ x3 ^= u<<13 | u>>(32-13)
+ u = x3 + x2
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x4
+ x6 ^= u<<7 | u>>(32-7)
+ u = x6 + x5
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x6
+ x4 ^= u<<13 | u>>(32-13)
+ u = x4 + x7
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x9
+ x11 ^= u<<7 | u>>(32-7)
+ u = x11 + x10
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x11
+ x9 ^= u<<13 | u>>(32-13)
+ u = x9 + x8
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x14
+ x12 ^= u<<7 | u>>(32-7)
+ u = x12 + x15
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x12
+ x14 ^= u<<13 | u>>(32-13)
+ u = x14 + x13
+ x15 ^= u<<18 | u>>(32-18)
+ }
+ x0 += j0
+ x1 += j1
+ x2 += j2
+ x3 += j3
+ x4 += j4
+ x5 += j5
+ x6 += j6
+ x7 += j7
+ x8 += j8
+ x9 += j9
+ x10 += j10
+ x11 += j11
+ x12 += j12
+ x13 += j13
+ x14 += j14
+ x15 += j15
+
+ out[0] = byte(x0)
+ out[1] = byte(x0 >> 8)
+ out[2] = byte(x0 >> 16)
+ out[3] = byte(x0 >> 24)
+
+ out[4] = byte(x1)
+ out[5] = byte(x1 >> 8)
+ out[6] = byte(x1 >> 16)
+ out[7] = byte(x1 >> 24)
+
+ out[8] = byte(x2)
+ out[9] = byte(x2 >> 8)
+ out[10] = byte(x2 >> 16)
+ out[11] = byte(x2 >> 24)
+
+ out[12] = byte(x3)
+ out[13] = byte(x3 >> 8)
+ out[14] = byte(x3 >> 16)
+ out[15] = byte(x3 >> 24)
+
+ out[16] = byte(x4)
+ out[17] = byte(x4 >> 8)
+ out[18] = byte(x4 >> 16)
+ out[19] = byte(x4 >> 24)
+
+ out[20] = byte(x5)
+ out[21] = byte(x5 >> 8)
+ out[22] = byte(x5 >> 16)
+ out[23] = byte(x5 >> 24)
+
+ out[24] = byte(x6)
+ out[25] = byte(x6 >> 8)
+ out[26] = byte(x6 >> 16)
+ out[27] = byte(x6 >> 24)
+
+ out[28] = byte(x7)
+ out[29] = byte(x7 >> 8)
+ out[30] = byte(x7 >> 16)
+ out[31] = byte(x7 >> 24)
+
+ out[32] = byte(x8)
+ out[33] = byte(x8 >> 8)
+ out[34] = byte(x8 >> 16)
+ out[35] = byte(x8 >> 24)
+
+ out[36] = byte(x9)
+ out[37] = byte(x9 >> 8)
+ out[38] = byte(x9 >> 16)
+ out[39] = byte(x9 >> 24)
+
+ out[40] = byte(x10)
+ out[41] = byte(x10 >> 8)
+ out[42] = byte(x10 >> 16)
+ out[43] = byte(x10 >> 24)
+
+ out[44] = byte(x11)
+ out[45] = byte(x11 >> 8)
+ out[46] = byte(x11 >> 16)
+ out[47] = byte(x11 >> 24)
+
+ out[48] = byte(x12)
+ out[49] = byte(x12 >> 8)
+ out[50] = byte(x12 >> 16)
+ out[51] = byte(x12 >> 24)
+
+ out[52] = byte(x13)
+ out[53] = byte(x13 >> 8)
+ out[54] = byte(x13 >> 16)
+ out[55] = byte(x13 >> 24)
+
+ out[56] = byte(x14)
+ out[57] = byte(x14 >> 8)
+ out[58] = byte(x14 >> 16)
+ out[59] = byte(x14 >> 24)
+
+ out[60] = byte(x15)
+ out[61] = byte(x15 >> 8)
+ out[62] = byte(x15 >> 16)
+ out[63] = byte(x15 >> 24)
+}
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go b/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go
new file mode 100644
index 000000000..903c7858e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_amd64.go
@@ -0,0 +1,23 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64,!appengine,!gccgo
+
+package salsa
+
+// This function is implemented in salsa2020_amd64.s.
+
+//go:noescape
+
+func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
+
+// XORKeyStream crypts bytes from in to out using the given key and counters.
+// In and out may be the same slice but otherwise should not overlap. Counter
+// contains the raw salsa20 counter bytes (both nonce and block counter).
+func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
+ if len(in) == 0 {
+ return
+ }
+ salsa2020XORKeyStream(&out[0], &in[0], uint64(len(in)), &counter[0], &key[0])
+}
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go b/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go
new file mode 100644
index 000000000..95f8ca5bb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa/salsa20_ref.go
@@ -0,0 +1,234 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64 appengine gccgo
+
+package salsa
+
+const rounds = 20
+
+// core applies the Salsa20 core function to 16-byte input in, 32-byte key k,
+// and 16-byte constant c, and puts the result into 64-byte array out.
+func core(out *[64]byte, in *[16]byte, k *[32]byte, c *[16]byte) {
+ j0 := uint32(c[0]) | uint32(c[1])<<8 | uint32(c[2])<<16 | uint32(c[3])<<24
+ j1 := uint32(k[0]) | uint32(k[1])<<8 | uint32(k[2])<<16 | uint32(k[3])<<24
+ j2 := uint32(k[4]) | uint32(k[5])<<8 | uint32(k[6])<<16 | uint32(k[7])<<24
+ j3 := uint32(k[8]) | uint32(k[9])<<8 | uint32(k[10])<<16 | uint32(k[11])<<24
+ j4 := uint32(k[12]) | uint32(k[13])<<8 | uint32(k[14])<<16 | uint32(k[15])<<24
+ j5 := uint32(c[4]) | uint32(c[5])<<8 | uint32(c[6])<<16 | uint32(c[7])<<24
+ j6 := uint32(in[0]) | uint32(in[1])<<8 | uint32(in[2])<<16 | uint32(in[3])<<24
+ j7 := uint32(in[4]) | uint32(in[5])<<8 | uint32(in[6])<<16 | uint32(in[7])<<24
+ j8 := uint32(in[8]) | uint32(in[9])<<8 | uint32(in[10])<<16 | uint32(in[11])<<24
+ j9 := uint32(in[12]) | uint32(in[13])<<8 | uint32(in[14])<<16 | uint32(in[15])<<24
+ j10 := uint32(c[8]) | uint32(c[9])<<8 | uint32(c[10])<<16 | uint32(c[11])<<24
+ j11 := uint32(k[16]) | uint32(k[17])<<8 | uint32(k[18])<<16 | uint32(k[19])<<24
+ j12 := uint32(k[20]) | uint32(k[21])<<8 | uint32(k[22])<<16 | uint32(k[23])<<24
+ j13 := uint32(k[24]) | uint32(k[25])<<8 | uint32(k[26])<<16 | uint32(k[27])<<24
+ j14 := uint32(k[28]) | uint32(k[29])<<8 | uint32(k[30])<<16 | uint32(k[31])<<24
+ j15 := uint32(c[12]) | uint32(c[13])<<8 | uint32(c[14])<<16 | uint32(c[15])<<24
+
+ x0, x1, x2, x3, x4, x5, x6, x7, x8 := j0, j1, j2, j3, j4, j5, j6, j7, j8
+ x9, x10, x11, x12, x13, x14, x15 := j9, j10, j11, j12, j13, j14, j15
+
+ for i := 0; i < rounds; i += 2 {
+ u := x0 + x12
+ x4 ^= u<<7 | u>>(32-7)
+ u = x4 + x0
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x4
+ x12 ^= u<<13 | u>>(32-13)
+ u = x12 + x8
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x1
+ x9 ^= u<<7 | u>>(32-7)
+ u = x9 + x5
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x9
+ x1 ^= u<<13 | u>>(32-13)
+ u = x1 + x13
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x6
+ x14 ^= u<<7 | u>>(32-7)
+ u = x14 + x10
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x14
+ x6 ^= u<<13 | u>>(32-13)
+ u = x6 + x2
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x11
+ x3 ^= u<<7 | u>>(32-7)
+ u = x3 + x15
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x3
+ x11 ^= u<<13 | u>>(32-13)
+ u = x11 + x7
+ x15 ^= u<<18 | u>>(32-18)
+
+ u = x0 + x3
+ x1 ^= u<<7 | u>>(32-7)
+ u = x1 + x0
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x1
+ x3 ^= u<<13 | u>>(32-13)
+ u = x3 + x2
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x4
+ x6 ^= u<<7 | u>>(32-7)
+ u = x6 + x5
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x6
+ x4 ^= u<<13 | u>>(32-13)
+ u = x4 + x7
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x9
+ x11 ^= u<<7 | u>>(32-7)
+ u = x11 + x10
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x11
+ x9 ^= u<<13 | u>>(32-13)
+ u = x9 + x8
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x14
+ x12 ^= u<<7 | u>>(32-7)
+ u = x12 + x15
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x12
+ x14 ^= u<<13 | u>>(32-13)
+ u = x14 + x13
+ x15 ^= u<<18 | u>>(32-18)
+ }
+ x0 += j0
+ x1 += j1
+ x2 += j2
+ x3 += j3
+ x4 += j4
+ x5 += j5
+ x6 += j6
+ x7 += j7
+ x8 += j8
+ x9 += j9
+ x10 += j10
+ x11 += j11
+ x12 += j12
+ x13 += j13
+ x14 += j14
+ x15 += j15
+
+ out[0] = byte(x0)
+ out[1] = byte(x0 >> 8)
+ out[2] = byte(x0 >> 16)
+ out[3] = byte(x0 >> 24)
+
+ out[4] = byte(x1)
+ out[5] = byte(x1 >> 8)
+ out[6] = byte(x1 >> 16)
+ out[7] = byte(x1 >> 24)
+
+ out[8] = byte(x2)
+ out[9] = byte(x2 >> 8)
+ out[10] = byte(x2 >> 16)
+ out[11] = byte(x2 >> 24)
+
+ out[12] = byte(x3)
+ out[13] = byte(x3 >> 8)
+ out[14] = byte(x3 >> 16)
+ out[15] = byte(x3 >> 24)
+
+ out[16] = byte(x4)
+ out[17] = byte(x4 >> 8)
+ out[18] = byte(x4 >> 16)
+ out[19] = byte(x4 >> 24)
+
+ out[20] = byte(x5)
+ out[21] = byte(x5 >> 8)
+ out[22] = byte(x5 >> 16)
+ out[23] = byte(x5 >> 24)
+
+ out[24] = byte(x6)
+ out[25] = byte(x6 >> 8)
+ out[26] = byte(x6 >> 16)
+ out[27] = byte(x6 >> 24)
+
+ out[28] = byte(x7)
+ out[29] = byte(x7 >> 8)
+ out[30] = byte(x7 >> 16)
+ out[31] = byte(x7 >> 24)
+
+ out[32] = byte(x8)
+ out[33] = byte(x8 >> 8)
+ out[34] = byte(x8 >> 16)
+ out[35] = byte(x8 >> 24)
+
+ out[36] = byte(x9)
+ out[37] = byte(x9 >> 8)
+ out[38] = byte(x9 >> 16)
+ out[39] = byte(x9 >> 24)
+
+ out[40] = byte(x10)
+ out[41] = byte(x10 >> 8)
+ out[42] = byte(x10 >> 16)
+ out[43] = byte(x10 >> 24)
+
+ out[44] = byte(x11)
+ out[45] = byte(x11 >> 8)
+ out[46] = byte(x11 >> 16)
+ out[47] = byte(x11 >> 24)
+
+ out[48] = byte(x12)
+ out[49] = byte(x12 >> 8)
+ out[50] = byte(x12 >> 16)
+ out[51] = byte(x12 >> 24)
+
+ out[52] = byte(x13)
+ out[53] = byte(x13 >> 8)
+ out[54] = byte(x13 >> 16)
+ out[55] = byte(x13 >> 24)
+
+ out[56] = byte(x14)
+ out[57] = byte(x14 >> 8)
+ out[58] = byte(x14 >> 16)
+ out[59] = byte(x14 >> 24)
+
+ out[60] = byte(x15)
+ out[61] = byte(x15 >> 8)
+ out[62] = byte(x15 >> 16)
+ out[63] = byte(x15 >> 24)
+}
+
+// XORKeyStream crypts bytes from in to out using the given key and counters.
+// In and out may be the same slice but otherwise should not overlap. Counter
+// contains the raw salsa20 counter bytes (both nonce and block counter).
+func XORKeyStream(out, in []byte, counter *[16]byte, key *[32]byte) {
+ var block [64]byte
+ var counterCopy [16]byte
+ copy(counterCopy[:], counter[:])
+
+ for len(in) >= 64 {
+ core(&block, &counterCopy, key, &Sigma)
+ for i, x := range block {
+ out[i] = in[i] ^ x
+ }
+ u := uint32(1)
+ for i := 8; i < 16; i++ {
+ u += uint32(counterCopy[i])
+ counterCopy[i] = byte(u)
+ u >>= 8
+ }
+ in = in[64:]
+ out = out[64:]
+ }
+
+ if len(in) > 0 {
+ core(&block, &counterCopy, key, &Sigma)
+ for i, v := range in {
+ out[i] = v ^ block[i]
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa/salsa_test.go b/vendor/golang.org/x/crypto/salsa20/salsa/salsa_test.go
new file mode 100644
index 000000000..f8cecd9e6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa/salsa_test.go
@@ -0,0 +1,35 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package salsa
+
+import "testing"
+
+func TestCore208(t *testing.T) {
+ in := [64]byte{
+ 0x7e, 0x87, 0x9a, 0x21, 0x4f, 0x3e, 0xc9, 0x86,
+ 0x7c, 0xa9, 0x40, 0xe6, 0x41, 0x71, 0x8f, 0x26,
+ 0xba, 0xee, 0x55, 0x5b, 0x8c, 0x61, 0xc1, 0xb5,
+ 0x0d, 0xf8, 0x46, 0x11, 0x6d, 0xcd, 0x3b, 0x1d,
+ 0xee, 0x24, 0xf3, 0x19, 0xdf, 0x9b, 0x3d, 0x85,
+ 0x14, 0x12, 0x1e, 0x4b, 0x5a, 0xc5, 0xaa, 0x32,
+ 0x76, 0x02, 0x1d, 0x29, 0x09, 0xc7, 0x48, 0x29,
+ 0xed, 0xeb, 0xc6, 0x8d, 0xb8, 0xb8, 0xc2, 0x5e}
+
+ out := [64]byte{
+ 0xa4, 0x1f, 0x85, 0x9c, 0x66, 0x08, 0xcc, 0x99,
+ 0x3b, 0x81, 0xca, 0xcb, 0x02, 0x0c, 0xef, 0x05,
+ 0x04, 0x4b, 0x21, 0x81, 0xa2, 0xfd, 0x33, 0x7d,
+ 0xfd, 0x7b, 0x1c, 0x63, 0x96, 0x68, 0x2f, 0x29,
+ 0xb4, 0x39, 0x31, 0x68, 0xe3, 0xc9, 0xe6, 0xbc,
+ 0xfe, 0x6b, 0xc5, 0xb7, 0xa0, 0x6d, 0x96, 0xba,
+ 0xe4, 0x24, 0xcc, 0x10, 0x2c, 0x91, 0x74, 0x5c,
+ 0x24, 0xad, 0x67, 0x3d, 0xc7, 0x61, 0x8f, 0x81,
+ }
+
+ Core208(&in, &in)
+ if in != out {
+ t.Errorf("expected %x, got %x", out, in)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa20.go b/vendor/golang.org/x/crypto/salsa20/salsa20.go
new file mode 100644
index 000000000..fde9846b6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa20.go
@@ -0,0 +1,54 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package salsa20 implements the Salsa20 stream cipher as specified in http://cr.yp.to/snuffle/spec.pdf.
+
+Salsa20 differs from many other stream ciphers in that it is message orientated
+rather than byte orientated. Keystream blocks are not preserved between calls,
+therefore each side must encrypt/decrypt data with the same segmentation.
+
+Another aspect of this difference is that part of the counter is exposed as
+an nonce in each call. Encrypting two different messages with the same (key,
+nonce) pair leads to trivial plaintext recovery. This is analogous to
+encrypting two different messages with the same key with a traditional stream
+cipher.
+
+This package also implements XSalsa20: a version of Salsa20 with a 24-byte
+nonce as specified in http://cr.yp.to/snuffle/xsalsa-20081128.pdf. Simply
+passing a 24-byte slice as the nonce triggers XSalsa20.
+*/
+package salsa20 // import "golang.org/x/crypto/salsa20"
+
+// TODO(agl): implement XORKeyStream12 and XORKeyStream8 - the reduced round variants of Salsa20.
+
+import (
+ "golang.org/x/crypto/salsa20/salsa"
+)
+
+// XORKeyStream crypts bytes from in to out using the given key and nonce. In
+// and out may be the same slice but otherwise should not overlap. Nonce must
+// be either 8 or 24 bytes long.
+func XORKeyStream(out, in []byte, nonce []byte, key *[32]byte) {
+ if len(out) < len(in) {
+ in = in[:len(out)]
+ }
+
+ var subNonce [16]byte
+
+ if len(nonce) == 24 {
+ var subKey [32]byte
+ var hNonce [16]byte
+ copy(hNonce[:], nonce[:16])
+ salsa.HSalsa20(&subKey, &hNonce, key, &salsa.Sigma)
+ copy(subNonce[:], nonce[16:])
+ key = &subKey
+ } else if len(nonce) == 8 {
+ copy(subNonce[:], nonce[:])
+ } else {
+ panic("salsa20: nonce must be 8 or 24 bytes")
+ }
+
+ salsa.XORKeyStream(out, in, &subNonce, key)
+}
diff --git a/vendor/golang.org/x/crypto/salsa20/salsa20_test.go b/vendor/golang.org/x/crypto/salsa20/salsa20_test.go
new file mode 100644
index 000000000..0ef3328eb
--- /dev/null
+++ b/vendor/golang.org/x/crypto/salsa20/salsa20_test.go
@@ -0,0 +1,139 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package salsa20
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+func fromHex(s string) []byte {
+ ret, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return ret
+}
+
+// testVectors was taken from set 6 of the ECRYPT test vectors:
+// http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors?logsort=rev&rev=210&view=markup
+var testVectors = []struct {
+ key []byte
+ iv []byte
+ numBytes int
+ xor []byte
+}{
+ {
+ fromHex("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D"),
+ fromHex("0D74DB42A91077DE"),
+ 131072,
+ fromHex("C349B6A51A3EC9B712EAED3F90D8BCEE69B7628645F251A996F55260C62EF31FD6C6B0AEA94E136C9D984AD2DF3578F78E457527B03A0450580DD874F63B1AB9"),
+ },
+ {
+ fromHex("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12"),
+ fromHex("167DE44BB21980E7"),
+ 131072,
+ fromHex("C3EAAF32836BACE32D04E1124231EF47E101367D6305413A0EEB07C60698A2876E4D031870A739D6FFDDD208597AFF0A47AC17EDB0167DD67EBA84F1883D4DFD"),
+ },
+ {
+ fromHex("0A5DB00356A9FC4FA2F5489BEE4194E73A8DE03386D92C7FD22578CB1E71C417"),
+ fromHex("1F86ED54BB2289F0"),
+ 131072,
+ fromHex("3CD23C3DC90201ACC0CF49B440B6C417F0DC8D8410A716D5314C059E14B1A8D9A9FB8EA3D9C8DAE12B21402F674AA95C67B1FC514E994C9D3F3A6E41DFF5BBA6"),
+ },
+ {
+ fromHex("0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C"),
+ fromHex("288FF65DC42B92F9"),
+ 131072,
+ fromHex("E00EBCCD70D69152725F9987982178A2E2E139C7BCBE04CA8A0E99E318D9AB76F988C8549F75ADD790BA4F81C176DA653C1A043F11A958E169B6D2319F4EEC1A"),
+ },
+}
+
+func TestSalsa20(t *testing.T) {
+ var inBuf, outBuf []byte
+ var key [32]byte
+
+ for i, test := range testVectors {
+ if test.numBytes%64 != 0 {
+ t.Errorf("#%d: numBytes is not a multiple of 64", i)
+ continue
+ }
+
+ if test.numBytes > len(inBuf) {
+ inBuf = make([]byte, test.numBytes)
+ outBuf = make([]byte, test.numBytes)
+ }
+ in := inBuf[:test.numBytes]
+ out := outBuf[:test.numBytes]
+ copy(key[:], test.key)
+ XORKeyStream(out, in, test.iv, &key)
+
+ var xor [64]byte
+ for len(out) > 0 {
+ for i := 0; i < 64; i++ {
+ xor[i] ^= out[i]
+ }
+ out = out[64:]
+ }
+
+ if !bytes.Equal(xor[:], test.xor) {
+ t.Errorf("#%d: bad result", i)
+ }
+ }
+}
+
+var xSalsa20TestData = []struct {
+ in, nonce, key, out []byte
+}{
+ {
+ []byte("Hello world!"),
+ []byte("24-byte nonce for xsalsa"),
+ []byte("this is 32-byte key for xsalsa20"),
+ []byte{0x00, 0x2d, 0x45, 0x13, 0x84, 0x3f, 0xc2, 0x40, 0xc4, 0x01, 0xe5, 0x41},
+ },
+ {
+ make([]byte, 64),
+ []byte("24-byte nonce for xsalsa"),
+ []byte("this is 32-byte key for xsalsa20"),
+ []byte{0x48, 0x48, 0x29, 0x7f, 0xeb, 0x1f, 0xb5, 0x2f, 0xb6,
+ 0x6d, 0x81, 0x60, 0x9b, 0xd5, 0x47, 0xfa, 0xbc, 0xbe, 0x70,
+ 0x26, 0xed, 0xc8, 0xb5, 0xe5, 0xe4, 0x49, 0xd0, 0x88, 0xbf,
+ 0xa6, 0x9c, 0x08, 0x8f, 0x5d, 0x8d, 0xa1, 0xd7, 0x91, 0x26,
+ 0x7c, 0x2c, 0x19, 0x5a, 0x7f, 0x8c, 0xae, 0x9c, 0x4b, 0x40,
+ 0x50, 0xd0, 0x8c, 0xe6, 0xd3, 0xa1, 0x51, 0xec, 0x26, 0x5f,
+ 0x3a, 0x58, 0xe4, 0x76, 0x48},
+ },
+}
+
+func TestXSalsa20(t *testing.T) {
+ var key [32]byte
+
+ for i, test := range xSalsa20TestData {
+ out := make([]byte, len(test.in))
+ copy(key[:], test.key)
+ XORKeyStream(out, test.in, test.nonce, &key)
+ if !bytes.Equal(out, test.out) {
+ t.Errorf("%d: expected %x, got %x", i, test.out, out)
+ }
+ }
+}
+
+var (
+ keyArray [32]byte
+ key = &keyArray
+ nonce [8]byte
+ msg = make([]byte, 1<<10)
+)
+
+func BenchmarkXOR1K(b *testing.B) {
+ b.StopTimer()
+ out := make([]byte, 1024)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ XORKeyStream(out, msg[:1024], nonce[:], key)
+ }
+ b.SetBytes(1024)
+}
diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go
new file mode 100644
index 000000000..dc0124b1f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/scrypt/scrypt.go
@@ -0,0 +1,243 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package scrypt implements the scrypt key derivation function as defined in
+// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
+// Functions" (http://www.tarsnap.com/scrypt/scrypt.pdf).
+package scrypt // import "golang.org/x/crypto/scrypt"
+
+import (
+ "crypto/sha256"
+ "errors"
+
+ "golang.org/x/crypto/pbkdf2"
+)
+
+const maxInt = int(^uint(0) >> 1)
+
+// blockCopy copies n numbers from src into dst.
+func blockCopy(dst, src []uint32, n int) {
+ copy(dst, src[:n])
+}
+
+// blockXOR XORs numbers from dst with n numbers from src.
+func blockXOR(dst, src []uint32, n int) {
+ for i, v := range src[:n] {
+ dst[i] ^= v
+ }
+}
+
+// salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in,
+// and puts the result into both both tmp and out.
+func salsaXOR(tmp *[16]uint32, in, out []uint32) {
+ w0 := tmp[0] ^ in[0]
+ w1 := tmp[1] ^ in[1]
+ w2 := tmp[2] ^ in[2]
+ w3 := tmp[3] ^ in[3]
+ w4 := tmp[4] ^ in[4]
+ w5 := tmp[5] ^ in[5]
+ w6 := tmp[6] ^ in[6]
+ w7 := tmp[7] ^ in[7]
+ w8 := tmp[8] ^ in[8]
+ w9 := tmp[9] ^ in[9]
+ w10 := tmp[10] ^ in[10]
+ w11 := tmp[11] ^ in[11]
+ w12 := tmp[12] ^ in[12]
+ w13 := tmp[13] ^ in[13]
+ w14 := tmp[14] ^ in[14]
+ w15 := tmp[15] ^ in[15]
+
+ x0, x1, x2, x3, x4, x5, x6, x7, x8 := w0, w1, w2, w3, w4, w5, w6, w7, w8
+ x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15
+
+ for i := 0; i < 8; i += 2 {
+ u := x0 + x12
+ x4 ^= u<<7 | u>>(32-7)
+ u = x4 + x0
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x4
+ x12 ^= u<<13 | u>>(32-13)
+ u = x12 + x8
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x1
+ x9 ^= u<<7 | u>>(32-7)
+ u = x9 + x5
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x9
+ x1 ^= u<<13 | u>>(32-13)
+ u = x1 + x13
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x6
+ x14 ^= u<<7 | u>>(32-7)
+ u = x14 + x10
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x14
+ x6 ^= u<<13 | u>>(32-13)
+ u = x6 + x2
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x11
+ x3 ^= u<<7 | u>>(32-7)
+ u = x3 + x15
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x3
+ x11 ^= u<<13 | u>>(32-13)
+ u = x11 + x7
+ x15 ^= u<<18 | u>>(32-18)
+
+ u = x0 + x3
+ x1 ^= u<<7 | u>>(32-7)
+ u = x1 + x0
+ x2 ^= u<<9 | u>>(32-9)
+ u = x2 + x1
+ x3 ^= u<<13 | u>>(32-13)
+ u = x3 + x2
+ x0 ^= u<<18 | u>>(32-18)
+
+ u = x5 + x4
+ x6 ^= u<<7 | u>>(32-7)
+ u = x6 + x5
+ x7 ^= u<<9 | u>>(32-9)
+ u = x7 + x6
+ x4 ^= u<<13 | u>>(32-13)
+ u = x4 + x7
+ x5 ^= u<<18 | u>>(32-18)
+
+ u = x10 + x9
+ x11 ^= u<<7 | u>>(32-7)
+ u = x11 + x10
+ x8 ^= u<<9 | u>>(32-9)
+ u = x8 + x11
+ x9 ^= u<<13 | u>>(32-13)
+ u = x9 + x8
+ x10 ^= u<<18 | u>>(32-18)
+
+ u = x15 + x14
+ x12 ^= u<<7 | u>>(32-7)
+ u = x12 + x15
+ x13 ^= u<<9 | u>>(32-9)
+ u = x13 + x12
+ x14 ^= u<<13 | u>>(32-13)
+ u = x14 + x13
+ x15 ^= u<<18 | u>>(32-18)
+ }
+ x0 += w0
+ x1 += w1
+ x2 += w2
+ x3 += w3
+ x4 += w4
+ x5 += w5
+ x6 += w6
+ x7 += w7
+ x8 += w8
+ x9 += w9
+ x10 += w10
+ x11 += w11
+ x12 += w12
+ x13 += w13
+ x14 += w14
+ x15 += w15
+
+ out[0], tmp[0] = x0, x0
+ out[1], tmp[1] = x1, x1
+ out[2], tmp[2] = x2, x2
+ out[3], tmp[3] = x3, x3
+ out[4], tmp[4] = x4, x4
+ out[5], tmp[5] = x5, x5
+ out[6], tmp[6] = x6, x6
+ out[7], tmp[7] = x7, x7
+ out[8], tmp[8] = x8, x8
+ out[9], tmp[9] = x9, x9
+ out[10], tmp[10] = x10, x10
+ out[11], tmp[11] = x11, x11
+ out[12], tmp[12] = x12, x12
+ out[13], tmp[13] = x13, x13
+ out[14], tmp[14] = x14, x14
+ out[15], tmp[15] = x15, x15
+}
+
+func blockMix(tmp *[16]uint32, in, out []uint32, r int) {
+ blockCopy(tmp[:], in[(2*r-1)*16:], 16)
+ for i := 0; i < 2*r; i += 2 {
+ salsaXOR(tmp, in[i*16:], out[i*8:])
+ salsaXOR(tmp, in[i*16+16:], out[i*8+r*16:])
+ }
+}
+
+func integer(b []uint32, r int) uint64 {
+ j := (2*r - 1) * 16
+ return uint64(b[j]) | uint64(b[j+1])<<32
+}
+
+func smix(b []byte, r, N int, v, xy []uint32) {
+ var tmp [16]uint32
+ x := xy
+ y := xy[32*r:]
+
+ j := 0
+ for i := 0; i < 32*r; i++ {
+ x[i] = uint32(b[j]) | uint32(b[j+1])<<8 | uint32(b[j+2])<<16 | uint32(b[j+3])<<24
+ j += 4
+ }
+ for i := 0; i < N; i += 2 {
+ blockCopy(v[i*(32*r):], x, 32*r)
+ blockMix(&tmp, x, y, r)
+
+ blockCopy(v[(i+1)*(32*r):], y, 32*r)
+ blockMix(&tmp, y, x, r)
+ }
+ for i := 0; i < N; i += 2 {
+ j := int(integer(x, r) & uint64(N-1))
+ blockXOR(x, v[j*(32*r):], 32*r)
+ blockMix(&tmp, x, y, r)
+
+ j = int(integer(y, r) & uint64(N-1))
+ blockXOR(y, v[j*(32*r):], 32*r)
+ blockMix(&tmp, y, x, r)
+ }
+ j = 0
+ for _, v := range x[:32*r] {
+ b[j+0] = byte(v >> 0)
+ b[j+1] = byte(v >> 8)
+ b[j+2] = byte(v >> 16)
+ b[j+3] = byte(v >> 24)
+ j += 4
+ }
+}
+
+// Key derives a key from the password, salt, and cost parameters, returning
+// a byte slice of length keyLen that can be used as cryptographic key.
+//
+// N is a CPU/memory cost parameter, which must be a power of two greater than 1.
+// r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the
+// limits, the function returns a nil byte slice and an error.
+//
+// For example, you can get a derived key for e.g. AES-256 (which needs a
+// 32-byte key) by doing:
+//
+// dk := scrypt.Key([]byte("some password"), salt, 16384, 8, 1, 32)
+//
+// The recommended parameters for interactive logins as of 2009 are N=16384,
+// r=8, p=1. They should be increased as memory latency and CPU parallelism
+// increases. Remember to get a good random salt.
+func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) {
+ if N <= 1 || N&(N-1) != 0 {
+ return nil, errors.New("scrypt: N must be > 1 and a power of 2")
+ }
+ if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r {
+ return nil, errors.New("scrypt: parameters are too large")
+ }
+
+ xy := make([]uint32, 64*r)
+ v := make([]uint32, 32*N*r)
+ b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New)
+
+ for i := 0; i < p; i++ {
+ smix(b[i*128*r:], r, N, v, xy)
+ }
+
+ return pbkdf2.Key(password, b, 1, keyLen, sha256.New), nil
+}
diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt_test.go b/vendor/golang.org/x/crypto/scrypt/scrypt_test.go
new file mode 100644
index 000000000..e096c3a31
--- /dev/null
+++ b/vendor/golang.org/x/crypto/scrypt/scrypt_test.go
@@ -0,0 +1,160 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package scrypt
+
+import (
+ "bytes"
+ "testing"
+)
+
+type testVector struct {
+ password string
+ salt string
+ N, r, p int
+ output []byte
+}
+
+var good = []testVector{
+ {
+ "password",
+ "salt",
+ 2, 10, 10,
+ []byte{
+ 0x48, 0x2c, 0x85, 0x8e, 0x22, 0x90, 0x55, 0xe6, 0x2f,
+ 0x41, 0xe0, 0xec, 0x81, 0x9a, 0x5e, 0xe1, 0x8b, 0xdb,
+ 0x87, 0x25, 0x1a, 0x53, 0x4f, 0x75, 0xac, 0xd9, 0x5a,
+ 0xc5, 0xe5, 0xa, 0xa1, 0x5f,
+ },
+ },
+ {
+ "password",
+ "salt",
+ 16, 100, 100,
+ []byte{
+ 0x88, 0xbd, 0x5e, 0xdb, 0x52, 0xd1, 0xdd, 0x0, 0x18,
+ 0x87, 0x72, 0xad, 0x36, 0x17, 0x12, 0x90, 0x22, 0x4e,
+ 0x74, 0x82, 0x95, 0x25, 0xb1, 0x8d, 0x73, 0x23, 0xa5,
+ 0x7f, 0x91, 0x96, 0x3c, 0x37,
+ },
+ },
+ {
+ "this is a long \000 password",
+ "and this is a long \000 salt",
+ 16384, 8, 1,
+ []byte{
+ 0xc3, 0xf1, 0x82, 0xee, 0x2d, 0xec, 0x84, 0x6e, 0x70,
+ 0xa6, 0x94, 0x2f, 0xb5, 0x29, 0x98, 0x5a, 0x3a, 0x09,
+ 0x76, 0x5e, 0xf0, 0x4c, 0x61, 0x29, 0x23, 0xb1, 0x7f,
+ 0x18, 0x55, 0x5a, 0x37, 0x07, 0x6d, 0xeb, 0x2b, 0x98,
+ 0x30, 0xd6, 0x9d, 0xe5, 0x49, 0x26, 0x51, 0xe4, 0x50,
+ 0x6a, 0xe5, 0x77, 0x6d, 0x96, 0xd4, 0x0f, 0x67, 0xaa,
+ 0xee, 0x37, 0xe1, 0x77, 0x7b, 0x8a, 0xd5, 0xc3, 0x11,
+ 0x14, 0x32, 0xbb, 0x3b, 0x6f, 0x7e, 0x12, 0x64, 0x40,
+ 0x18, 0x79, 0xe6, 0x41, 0xae,
+ },
+ },
+ {
+ "p",
+ "s",
+ 2, 1, 1,
+ []byte{
+ 0x48, 0xb0, 0xd2, 0xa8, 0xa3, 0x27, 0x26, 0x11, 0x98,
+ 0x4c, 0x50, 0xeb, 0xd6, 0x30, 0xaf, 0x52,
+ },
+ },
+
+ {
+ "",
+ "",
+ 16, 1, 1,
+ []byte{
+ 0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20, 0x3b,
+ 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97, 0xf1, 0x6b,
+ 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8, 0xdf, 0xdf, 0xfa,
+ 0x3f, 0xed, 0xe2, 0x14, 0x42, 0xfc, 0xd0, 0x06, 0x9d,
+ 0xed, 0x09, 0x48, 0xf8, 0x32, 0x6a, 0x75, 0x3a, 0x0f,
+ 0xc8, 0x1f, 0x17, 0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d,
+ 0x36, 0x28, 0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89,
+ 0x06,
+ },
+ },
+ {
+ "password",
+ "NaCl",
+ 1024, 8, 16,
+ []byte{
+ 0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78,
+ 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe, 0x7c, 0x6a,
+ 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76,
+ 0x63, 0x4b, 0x37, 0x31, 0x62, 0x2e, 0xaf, 0x30, 0xd9,
+ 0x2e, 0x22, 0xa3, 0x88, 0x6f, 0xf1, 0x09, 0x27, 0x9d,
+ 0x98, 0x30, 0xda, 0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83,
+ 0xee, 0x6d, 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06,
+ 0x40,
+ },
+ },
+ {
+ "pleaseletmein", "SodiumChloride",
+ 16384, 8, 1,
+ []byte{
+ 0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48, 0x46,
+ 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb, 0xfd, 0xa8,
+ 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e, 0xa9, 0xb5, 0x43,
+ 0xf6, 0x54, 0x5d, 0xa1, 0xf2, 0xd5, 0x43, 0x29, 0x55,
+ 0x61, 0x3f, 0x0f, 0xcf, 0x62, 0xd4, 0x97, 0x05, 0x24,
+ 0x2a, 0x9a, 0xf9, 0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65,
+ 0x1e, 0x40, 0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58,
+ 0x87,
+ },
+ },
+ /*
+ // Disabled: needs 1 GiB RAM and takes too long for a simple test.
+ {
+ "pleaseletmein", "SodiumChloride",
+ 1048576, 8, 1,
+ []byte{
+ 0x21, 0x01, 0xcb, 0x9b, 0x6a, 0x51, 0x1a, 0xae, 0xad,
+ 0xdb, 0xbe, 0x09, 0xcf, 0x70, 0xf8, 0x81, 0xec, 0x56,
+ 0x8d, 0x57, 0x4a, 0x2f, 0xfd, 0x4d, 0xab, 0xe5, 0xee,
+ 0x98, 0x20, 0xad, 0xaa, 0x47, 0x8e, 0x56, 0xfd, 0x8f,
+ 0x4b, 0xa5, 0xd0, 0x9f, 0xfa, 0x1c, 0x6d, 0x92, 0x7c,
+ 0x40, 0xf4, 0xc3, 0x37, 0x30, 0x40, 0x49, 0xe8, 0xa9,
+ 0x52, 0xfb, 0xcb, 0xf4, 0x5c, 0x6f, 0xa7, 0x7a, 0x41,
+ 0xa4,
+ },
+ },
+ */
+}
+
+var bad = []testVector{
+ {"p", "s", 0, 1, 1, nil}, // N == 0
+ {"p", "s", 1, 1, 1, nil}, // N == 1
+ {"p", "s", 7, 8, 1, nil}, // N is not power of 2
+ {"p", "s", 16, maxInt / 2, maxInt / 2, nil}, // p * r too large
+}
+
+func TestKey(t *testing.T) {
+ for i, v := range good {
+ k, err := Key([]byte(v.password), []byte(v.salt), v.N, v.r, v.p, len(v.output))
+ if err != nil {
+ t.Errorf("%d: got unexpected error: %s", i, err)
+ }
+ if !bytes.Equal(k, v.output) {
+ t.Errorf("%d: expected %x, got %x", i, v.output, k)
+ }
+ }
+ for i, v := range bad {
+ _, err := Key([]byte(v.password), []byte(v.salt), v.N, v.r, v.p, 32)
+ if err == nil {
+ t.Errorf("%d: expected error, got nil", i)
+ }
+ }
+}
+
+func BenchmarkKey(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Key([]byte("password"), []byte("salt"), 16384, 8, 1, 64)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/sha3/doc.go b/vendor/golang.org/x/crypto/sha3/doc.go
new file mode 100644
index 000000000..a0ee3ae72
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/doc.go
@@ -0,0 +1,66 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha3 implements the SHA-3 fixed-output-length hash functions and
+// the SHAKE variable-output-length hash functions defined by FIPS-202.
+//
+// Both types of hash function use the "sponge" construction and the Keccak
+// permutation. For a detailed specification see http://keccak.noekeon.org/
+//
+//
+// Guidance
+//
+// If you aren't sure what function you need, use SHAKE256 with at least 64
+// bytes of output. The SHAKE instances are faster than the SHA3 instances;
+// the latter have to allocate memory to conform to the hash.Hash interface.
+//
+// If you need a secret-key MAC (message authentication code), prepend the
+// secret key to the input, hash with SHAKE256 and read at least 32 bytes of
+// output.
+//
+//
+// Security strengths
+//
+// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security
+// strength against preimage attacks of x bits. Since they only produce "x"
+// bits of output, their collision-resistance is only "x/2" bits.
+//
+// The SHAKE-256 and -128 functions have a generic security strength of 256 and
+// 128 bits against all attacks, provided that at least 2x bits of their output
+// is used. Requesting more than 64 or 32 bytes of output, respectively, does
+// not increase the collision-resistance of the SHAKE functions.
+//
+//
+// The sponge construction
+//
+// A sponge builds a pseudo-random function from a public pseudo-random
+// permutation, by applying the permutation to a state of "rate + capacity"
+// bytes, but hiding "capacity" of the bytes.
+//
+// A sponge starts out with a zero state. To hash an input using a sponge, up
+// to "rate" bytes of the input are XORed into the sponge's state. The sponge
+// is then "full" and the permutation is applied to "empty" it. This process is
+// repeated until all the input has been "absorbed". The input is then padded.
+// The digest is "squeezed" from the sponge in the same way, except that output
+// output is copied out instead of input being XORed in.
+//
+// A sponge is parameterized by its generic security strength, which is equal
+// to half its capacity; capacity + rate is equal to the permutation's width.
+// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means
+// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2.
+//
+//
+// Recommendations
+//
+// The SHAKE functions are recommended for most new uses. They can produce
+// output of arbitrary length. SHAKE256, with an output length of at least
+// 64 bytes, provides 256-bit security against all attacks. The Keccak team
+// recommends it for most applications upgrading from SHA2-512. (NIST chose a
+// much stronger, but much slower, sponge instance for SHA3-512.)
+//
+// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions.
+// They produce output of the same length, with the same security strengths
+// against all attacks. This means, in particular, that SHA3-256 only has
+// 128-bit collision resistance, because its output length is 32 bytes.
+package sha3 // import "golang.org/x/crypto/sha3"
diff --git a/vendor/golang.org/x/crypto/sha3/hashes.go b/vendor/golang.org/x/crypto/sha3/hashes.go
new file mode 100644
index 000000000..2b51cf4e9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/hashes.go
@@ -0,0 +1,65 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// This file provides functions for creating instances of the SHA-3
+// and SHAKE hash functions, as well as utility functions for hashing
+// bytes.
+
+import (
+ "hash"
+)
+
+// New224 creates a new SHA3-224 hash.
+// Its generic security strength is 224 bits against preimage attacks,
+// and 112 bits against collision attacks.
+func New224() hash.Hash { return &state{rate: 144, outputLen: 28, dsbyte: 0x06} }
+
+// New256 creates a new SHA3-256 hash.
+// Its generic security strength is 256 bits against preimage attacks,
+// and 128 bits against collision attacks.
+func New256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x06} }
+
+// New384 creates a new SHA3-384 hash.
+// Its generic security strength is 384 bits against preimage attacks,
+// and 192 bits against collision attacks.
+func New384() hash.Hash { return &state{rate: 104, outputLen: 48, dsbyte: 0x06} }
+
+// New512 creates a new SHA3-512 hash.
+// Its generic security strength is 512 bits against preimage attacks,
+// and 256 bits against collision attacks.
+func New512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x06} }
+
+// Sum224 returns the SHA3-224 digest of the data.
+func Sum224(data []byte) (digest [28]byte) {
+ h := New224()
+ h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
+
+// Sum256 returns the SHA3-256 digest of the data.
+func Sum256(data []byte) (digest [32]byte) {
+ h := New256()
+ h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
+
+// Sum384 returns the SHA3-384 digest of the data.
+func Sum384(data []byte) (digest [48]byte) {
+ h := New384()
+ h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
+
+// Sum512 returns the SHA3-512 digest of the data.
+func Sum512(data []byte) (digest [64]byte) {
+ h := New512()
+ h.Write(data)
+ h.Sum(digest[:0])
+ return
+}
diff --git a/vendor/golang.org/x/crypto/sha3/keccakf.go b/vendor/golang.org/x/crypto/sha3/keccakf.go
new file mode 100644
index 000000000..13e7058fa
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/keccakf.go
@@ -0,0 +1,410 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// rc stores the round constants for use in the ι step.
+var rc = [24]uint64{
+ 0x0000000000000001,
+ 0x0000000000008082,
+ 0x800000000000808A,
+ 0x8000000080008000,
+ 0x000000000000808B,
+ 0x0000000080000001,
+ 0x8000000080008081,
+ 0x8000000000008009,
+ 0x000000000000008A,
+ 0x0000000000000088,
+ 0x0000000080008009,
+ 0x000000008000000A,
+ 0x000000008000808B,
+ 0x800000000000008B,
+ 0x8000000000008089,
+ 0x8000000000008003,
+ 0x8000000000008002,
+ 0x8000000000000080,
+ 0x000000000000800A,
+ 0x800000008000000A,
+ 0x8000000080008081,
+ 0x8000000000008080,
+ 0x0000000080000001,
+ 0x8000000080008008,
+}
+
+// keccakF1600 applies the Keccak permutation to a 1600b-wide
+// state represented as a slice of 25 uint64s.
+func keccakF1600(a *[25]uint64) {
+ // Implementation translated from Keccak-inplace.c
+ // in the keccak reference code.
+ var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64
+
+ for i := 0; i < 24; i += 4 {
+ // Combines the 5 steps in each round into 2 steps.
+ // Unrolls 4 rounds per loop and spreads some steps across rounds.
+
+ // Round 1
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[6] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[12] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[18] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[24] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i]
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[16] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[22] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[3] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[1] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[7] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[19] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[11] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[23] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[4] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[2] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[8] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[14] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 2
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[16] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[7] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[23] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[14] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1]
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[11] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[2] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[18] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[6] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[22] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[4] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[1] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[8] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[24] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[12] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[3] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[19] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 3
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[11] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[22] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[8] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[19] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2]
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[1] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[12] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[23] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[16] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[2] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[24] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[6] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[3] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[14] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[7] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[18] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[4] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ // Round 4
+ bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20]
+ bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21]
+ bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22]
+ bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23]
+ bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24]
+ d0 = bc4 ^ (bc1<<1 | bc1>>63)
+ d1 = bc0 ^ (bc2<<1 | bc2>>63)
+ d2 = bc1 ^ (bc3<<1 | bc3>>63)
+ d3 = bc2 ^ (bc4<<1 | bc4>>63)
+ d4 = bc3 ^ (bc0<<1 | bc0>>63)
+
+ bc0 = a[0] ^ d0
+ t = a[1] ^ d1
+ bc1 = t<<44 | t>>(64-44)
+ t = a[2] ^ d2
+ bc2 = t<<43 | t>>(64-43)
+ t = a[3] ^ d3
+ bc3 = t<<21 | t>>(64-21)
+ t = a[4] ^ d4
+ bc4 = t<<14 | t>>(64-14)
+ a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3]
+ a[1] = bc1 ^ (bc3 &^ bc2)
+ a[2] = bc2 ^ (bc4 &^ bc3)
+ a[3] = bc3 ^ (bc0 &^ bc4)
+ a[4] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[5] ^ d0
+ bc2 = t<<3 | t>>(64-3)
+ t = a[6] ^ d1
+ bc3 = t<<45 | t>>(64-45)
+ t = a[7] ^ d2
+ bc4 = t<<61 | t>>(64-61)
+ t = a[8] ^ d3
+ bc0 = t<<28 | t>>(64-28)
+ t = a[9] ^ d4
+ bc1 = t<<20 | t>>(64-20)
+ a[5] = bc0 ^ (bc2 &^ bc1)
+ a[6] = bc1 ^ (bc3 &^ bc2)
+ a[7] = bc2 ^ (bc4 &^ bc3)
+ a[8] = bc3 ^ (bc0 &^ bc4)
+ a[9] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[10] ^ d0
+ bc4 = t<<18 | t>>(64-18)
+ t = a[11] ^ d1
+ bc0 = t<<1 | t>>(64-1)
+ t = a[12] ^ d2
+ bc1 = t<<6 | t>>(64-6)
+ t = a[13] ^ d3
+ bc2 = t<<25 | t>>(64-25)
+ t = a[14] ^ d4
+ bc3 = t<<8 | t>>(64-8)
+ a[10] = bc0 ^ (bc2 &^ bc1)
+ a[11] = bc1 ^ (bc3 &^ bc2)
+ a[12] = bc2 ^ (bc4 &^ bc3)
+ a[13] = bc3 ^ (bc0 &^ bc4)
+ a[14] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[15] ^ d0
+ bc1 = t<<36 | t>>(64-36)
+ t = a[16] ^ d1
+ bc2 = t<<10 | t>>(64-10)
+ t = a[17] ^ d2
+ bc3 = t<<15 | t>>(64-15)
+ t = a[18] ^ d3
+ bc4 = t<<56 | t>>(64-56)
+ t = a[19] ^ d4
+ bc0 = t<<27 | t>>(64-27)
+ a[15] = bc0 ^ (bc2 &^ bc1)
+ a[16] = bc1 ^ (bc3 &^ bc2)
+ a[17] = bc2 ^ (bc4 &^ bc3)
+ a[18] = bc3 ^ (bc0 &^ bc4)
+ a[19] = bc4 ^ (bc1 &^ bc0)
+
+ t = a[20] ^ d0
+ bc3 = t<<41 | t>>(64-41)
+ t = a[21] ^ d1
+ bc4 = t<<2 | t>>(64-2)
+ t = a[22] ^ d2
+ bc0 = t<<62 | t>>(64-62)
+ t = a[23] ^ d3
+ bc1 = t<<55 | t>>(64-55)
+ t = a[24] ^ d4
+ bc2 = t<<39 | t>>(64-39)
+ a[20] = bc0 ^ (bc2 &^ bc1)
+ a[21] = bc1 ^ (bc3 &^ bc2)
+ a[22] = bc2 ^ (bc4 &^ bc3)
+ a[23] = bc3 ^ (bc0 &^ bc4)
+ a[24] = bc4 ^ (bc1 &^ bc0)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/sha3/register.go b/vendor/golang.org/x/crypto/sha3/register.go
new file mode 100644
index 000000000..3cf6a22e0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/register.go
@@ -0,0 +1,18 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.4
+
+package sha3
+
+import (
+ "crypto"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.SHA3_224, New224)
+ crypto.RegisterHash(crypto.SHA3_256, New256)
+ crypto.RegisterHash(crypto.SHA3_384, New384)
+ crypto.RegisterHash(crypto.SHA3_512, New512)
+}
diff --git a/vendor/golang.org/x/crypto/sha3/sha3.go b/vendor/golang.org/x/crypto/sha3/sha3.go
new file mode 100644
index 000000000..c8fd31cb0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/sha3.go
@@ -0,0 +1,193 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// spongeDirection indicates the direction bytes are flowing through the sponge.
+type spongeDirection int
+
+const (
+ // spongeAbsorbing indicates that the sponge is absorbing input.
+ spongeAbsorbing spongeDirection = iota
+ // spongeSqueezing indicates that the sponge is being squeezed.
+ spongeSqueezing
+)
+
+const (
+ // maxRate is the maximum size of the internal buffer. SHAKE-256
+ // currently needs the largest buffer.
+ maxRate = 168
+)
+
+type state struct {
+ // Generic sponge components.
+ a [25]uint64 // main state of the hash
+ buf []byte // points into storage
+ rate int // the number of bytes of state to use
+
+ // dsbyte contains the "domain separation" bits and the first bit of
+ // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the
+ // SHA-3 and SHAKE functions by appending bitstrings to the message.
+ // Using a little-endian bit-ordering convention, these are "01" for SHA-3
+ // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the
+ // padding rule from section 5.1 is applied to pad the message to a multiple
+ // of the rate, which involves adding a "1" bit, zero or more "0" bits, and
+ // a final "1" bit. We merge the first "1" bit from the padding into dsbyte,
+ // giving 00000110b (0x06) and 00011111b (0x1f).
+ // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf
+ // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and
+ // Extendable-Output Functions (May 2014)"
+ dsbyte byte
+ storage [maxRate]byte
+
+ // Specific to SHA-3 and SHAKE.
+ fixedOutput bool // whether this is a fixed-ouput-length instance
+ outputLen int // the default output size in bytes
+ state spongeDirection // whether the sponge is absorbing or squeezing
+}
+
+// BlockSize returns the rate of sponge underlying this hash function.
+func (d *state) BlockSize() int { return d.rate }
+
+// Size returns the output size of the hash function in bytes.
+func (d *state) Size() int { return d.outputLen }
+
+// Reset clears the internal state by zeroing the sponge state and
+// the byte buffer, and setting Sponge.state to absorbing.
+func (d *state) Reset() {
+ // Zero the permutation's state.
+ for i := range d.a {
+ d.a[i] = 0
+ }
+ d.state = spongeAbsorbing
+ d.buf = d.storage[:0]
+}
+
+func (d *state) clone() *state {
+ ret := *d
+ if ret.state == spongeAbsorbing {
+ ret.buf = ret.storage[:len(ret.buf)]
+ } else {
+ ret.buf = ret.storage[d.rate-cap(d.buf) : d.rate]
+ }
+
+ return &ret
+}
+
+// permute applies the KeccakF-1600 permutation. It handles
+// any input-output buffering.
+func (d *state) permute() {
+ switch d.state {
+ case spongeAbsorbing:
+ // If we're absorbing, we need to xor the input into the state
+ // before applying the permutation.
+ xorIn(d, d.buf)
+ d.buf = d.storage[:0]
+ keccakF1600(&d.a)
+ case spongeSqueezing:
+ // If we're squeezing, we need to apply the permutatin before
+ // copying more output.
+ keccakF1600(&d.a)
+ d.buf = d.storage[:d.rate]
+ copyOut(d, d.buf)
+ }
+}
+
+// pads appends the domain separation bits in dsbyte, applies
+// the multi-bitrate 10..1 padding rule, and permutes the state.
+func (d *state) padAndPermute(dsbyte byte) {
+ if d.buf == nil {
+ d.buf = d.storage[:0]
+ }
+ // Pad with this instance's domain-separator bits. We know that there's
+ // at least one byte of space in d.buf because, if it were full,
+ // permute would have been called to empty it. dsbyte also contains the
+ // first one bit for the padding. See the comment in the state struct.
+ d.buf = append(d.buf, dsbyte)
+ zerosStart := len(d.buf)
+ d.buf = d.storage[:d.rate]
+ for i := zerosStart; i < d.rate; i++ {
+ d.buf[i] = 0
+ }
+ // This adds the final one bit for the padding. Because of the way that
+ // bits are numbered from the LSB upwards, the final bit is the MSB of
+ // the last byte.
+ d.buf[d.rate-1] ^= 0x80
+ // Apply the permutation
+ d.permute()
+ d.state = spongeSqueezing
+ d.buf = d.storage[:d.rate]
+ copyOut(d, d.buf)
+}
+
+// Write absorbs more data into the hash's state. It produces an error
+// if more data is written to the ShakeHash after writing
+func (d *state) Write(p []byte) (written int, err error) {
+ if d.state != spongeAbsorbing {
+ panic("sha3: write to sponge after read")
+ }
+ if d.buf == nil {
+ d.buf = d.storage[:0]
+ }
+ written = len(p)
+
+ for len(p) > 0 {
+ if len(d.buf) == 0 && len(p) >= d.rate {
+ // The fast path; absorb a full "rate" bytes of input and apply the permutation.
+ xorIn(d, p[:d.rate])
+ p = p[d.rate:]
+ keccakF1600(&d.a)
+ } else {
+ // The slow path; buffer the input until we can fill the sponge, and then xor it in.
+ todo := d.rate - len(d.buf)
+ if todo > len(p) {
+ todo = len(p)
+ }
+ d.buf = append(d.buf, p[:todo]...)
+ p = p[todo:]
+
+ // If the sponge is full, apply the permutation.
+ if len(d.buf) == d.rate {
+ d.permute()
+ }
+ }
+ }
+
+ return
+}
+
+// Read squeezes an arbitrary number of bytes from the sponge.
+func (d *state) Read(out []byte) (n int, err error) {
+ // If we're still absorbing, pad and apply the permutation.
+ if d.state == spongeAbsorbing {
+ d.padAndPermute(d.dsbyte)
+ }
+
+ n = len(out)
+
+ // Now, do the squeezing.
+ for len(out) > 0 {
+ n := copy(out, d.buf)
+ d.buf = d.buf[n:]
+ out = out[n:]
+
+ // Apply the permutation if we've squeezed the sponge dry.
+ if len(d.buf) == 0 {
+ d.permute()
+ }
+ }
+
+ return
+}
+
+// Sum applies padding to the hash state and then squeezes out the desired
+// number of output bytes.
+func (d *state) Sum(in []byte) []byte {
+ // Make a copy of the original hash so that caller can keep writing
+ // and summing.
+ dup := d.clone()
+ hash := make([]byte, dup.outputLen)
+ dup.Read(hash)
+ return append(in, hash...)
+}
diff --git a/vendor/golang.org/x/crypto/sha3/sha3_test.go b/vendor/golang.org/x/crypto/sha3/sha3_test.go
new file mode 100644
index 000000000..caf72f279
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/sha3_test.go
@@ -0,0 +1,306 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// Tests include all the ShortMsgKATs provided by the Keccak team at
+// https://github.com/gvanas/KeccakCodePackage
+//
+// They only include the zero-bit case of the bitwise testvectors
+// published by NIST in the draft of FIPS-202.
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/hex"
+ "encoding/json"
+ "hash"
+ "os"
+ "strings"
+ "testing"
+)
+
+const (
+ testString = "brekeccakkeccak koax koax"
+ katFilename = "testdata/keccakKats.json.deflate"
+)
+
+// Internal-use instances of SHAKE used to test against KATs.
+func newHashShake128() hash.Hash {
+ return &state{rate: 168, dsbyte: 0x1f, outputLen: 512}
+}
+func newHashShake256() hash.Hash {
+ return &state{rate: 136, dsbyte: 0x1f, outputLen: 512}
+}
+
+// testDigests contains functions returning hash.Hash instances
+// with output-length equal to the KAT length for both SHA-3 and
+// SHAKE instances.
+var testDigests = map[string]func() hash.Hash{
+ "SHA3-224": New224,
+ "SHA3-256": New256,
+ "SHA3-384": New384,
+ "SHA3-512": New512,
+ "SHAKE128": newHashShake128,
+ "SHAKE256": newHashShake256,
+}
+
+// testShakes contains functions that return ShakeHash instances for
+// testing the ShakeHash-specific interface.
+var testShakes = map[string]func() ShakeHash{
+ "SHAKE128": NewShake128,
+ "SHAKE256": NewShake256,
+}
+
+// decodeHex converts a hex-encoded string into a raw byte string.
+func decodeHex(s string) []byte {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+// structs used to marshal JSON test-cases.
+type KeccakKats struct {
+ Kats map[string][]struct {
+ Digest string `json:"digest"`
+ Length int64 `json:"length"`
+ Message string `json:"message"`
+ }
+}
+
+func testUnalignedAndGeneric(t *testing.T, testf func(impl string)) {
+ xorInOrig, copyOutOrig := xorIn, copyOut
+ xorIn, copyOut = xorInGeneric, copyOutGeneric
+ testf("generic")
+ if xorImplementationUnaligned != "generic" {
+ xorIn, copyOut = xorInUnaligned, copyOutUnaligned
+ testf("unaligned")
+ }
+ xorIn, copyOut = xorInOrig, copyOutOrig
+}
+
+// TestKeccakKats tests the SHA-3 and Shake implementations against all the
+// ShortMsgKATs from https://github.com/gvanas/KeccakCodePackage
+// (The testvectors are stored in keccakKats.json.deflate due to their length.)
+func TestKeccakKats(t *testing.T) {
+ testUnalignedAndGeneric(t, func(impl string) {
+ // Read the KATs.
+ deflated, err := os.Open(katFilename)
+ if err != nil {
+ t.Errorf("error opening %s: %s", katFilename, err)
+ }
+ file := flate.NewReader(deflated)
+ dec := json.NewDecoder(file)
+ var katSet KeccakKats
+ err = dec.Decode(&katSet)
+ if err != nil {
+ t.Errorf("error decoding KATs: %s", err)
+ }
+
+ // Do the KATs.
+ for functionName, kats := range katSet.Kats {
+ d := testDigests[functionName]()
+ for _, kat := range kats {
+ d.Reset()
+ in, err := hex.DecodeString(kat.Message)
+ if err != nil {
+ t.Errorf("error decoding KAT: %s", err)
+ }
+ d.Write(in[:kat.Length/8])
+ got := strings.ToUpper(hex.EncodeToString(d.Sum(nil)))
+ if got != kat.Digest {
+ t.Errorf("function=%s, implementation=%s, length=%d\nmessage:\n %s\ngot:\n %s\nwanted:\n %s",
+ functionName, impl, kat.Length, kat.Message, got, kat.Digest)
+ t.Logf("wanted %+v", kat)
+ t.FailNow()
+ }
+ continue
+ }
+ }
+ })
+}
+
+// TestUnalignedWrite tests that writing data in an arbitrary pattern with
+// small input buffers.
+func testUnalignedWrite(t *testing.T) {
+ testUnalignedAndGeneric(t, func(impl string) {
+ buf := sequentialBytes(0x10000)
+ for alg, df := range testDigests {
+ d := df()
+ d.Reset()
+ d.Write(buf)
+ want := d.Sum(nil)
+ d.Reset()
+ for i := 0; i < len(buf); {
+ // Cycle through offsets which make a 137 byte sequence.
+ // Because 137 is prime this sequence should exercise all corner cases.
+ offsets := [17]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1}
+ for _, j := range offsets {
+ if v := len(buf) - i; v < j {
+ j = v
+ }
+ d.Write(buf[i : i+j])
+ i += j
+ }
+ }
+ got := d.Sum(nil)
+ if !bytes.Equal(got, want) {
+ t.Errorf("Unaligned writes, implementation=%s, alg=%s\ngot %q, want %q", impl, alg, got, want)
+ }
+ }
+ })
+}
+
+// TestAppend checks that appending works when reallocation is necessary.
+func TestAppend(t *testing.T) {
+ testUnalignedAndGeneric(t, func(impl string) {
+ d := New224()
+
+ for capacity := 2; capacity <= 66; capacity += 64 {
+ // The first time around the loop, Sum will have to reallocate.
+ // The second time, it will not.
+ buf := make([]byte, 2, capacity)
+ d.Reset()
+ d.Write([]byte{0xcc})
+ buf = d.Sum(buf)
+ expected := "0000DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
+ if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
+ t.Errorf("got %s, want %s", got, expected)
+ }
+ }
+ })
+}
+
+// TestAppendNoRealloc tests that appending works when no reallocation is necessary.
+func TestAppendNoRealloc(t *testing.T) {
+ testUnalignedAndGeneric(t, func(impl string) {
+ buf := make([]byte, 1, 200)
+ d := New224()
+ d.Write([]byte{0xcc})
+ buf = d.Sum(buf)
+ expected := "00DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"
+ if got := strings.ToUpper(hex.EncodeToString(buf)); got != expected {
+ t.Errorf("%s: got %s, want %s", impl, got, expected)
+ }
+ })
+}
+
+// TestSqueezing checks that squeezing the full output a single time produces
+// the same output as repeatedly squeezing the instance.
+func TestSqueezing(t *testing.T) {
+ testUnalignedAndGeneric(t, func(impl string) {
+ for functionName, newShakeHash := range testShakes {
+ d0 := newShakeHash()
+ d0.Write([]byte(testString))
+ ref := make([]byte, 32)
+ d0.Read(ref)
+
+ d1 := newShakeHash()
+ d1.Write([]byte(testString))
+ var multiple []byte
+ for _ = range ref {
+ one := make([]byte, 1)
+ d1.Read(one)
+ multiple = append(multiple, one...)
+ }
+ if !bytes.Equal(ref, multiple) {
+ t.Errorf("%s (%s): squeezing %d bytes one at a time failed", functionName, impl, len(ref))
+ }
+ }
+ })
+}
+
+// sequentialBytes produces a buffer of size consecutive bytes 0x00, 0x01, ..., used for testing.
+func sequentialBytes(size int) []byte {
+ result := make([]byte, size)
+ for i := range result {
+ result[i] = byte(i)
+ }
+ return result
+}
+
+// BenchmarkPermutationFunction measures the speed of the permutation function
+// with no input data.
+func BenchmarkPermutationFunction(b *testing.B) {
+ b.SetBytes(int64(200))
+ var lanes [25]uint64
+ for i := 0; i < b.N; i++ {
+ keccakF1600(&lanes)
+ }
+}
+
+// benchmarkHash tests the speed to hash num buffers of buflen each.
+func benchmarkHash(b *testing.B, h hash.Hash, size, num int) {
+ b.StopTimer()
+ h.Reset()
+ data := sequentialBytes(size)
+ b.SetBytes(int64(size * num))
+ b.StartTimer()
+
+ var state []byte
+ for i := 0; i < b.N; i++ {
+ for j := 0; j < num; j++ {
+ h.Write(data)
+ }
+ state = h.Sum(state[:0])
+ }
+ b.StopTimer()
+ h.Reset()
+}
+
+// benchmarkShake is specialized to the Shake instances, which don't
+// require a copy on reading output.
+func benchmarkShake(b *testing.B, h ShakeHash, size, num int) {
+ b.StopTimer()
+ h.Reset()
+ data := sequentialBytes(size)
+ d := make([]byte, 32)
+
+ b.SetBytes(int64(size * num))
+ b.StartTimer()
+
+ for i := 0; i < b.N; i++ {
+ h.Reset()
+ for j := 0; j < num; j++ {
+ h.Write(data)
+ }
+ h.Read(d)
+ }
+}
+
+func BenchmarkSha3_512_MTU(b *testing.B) { benchmarkHash(b, New512(), 1350, 1) }
+func BenchmarkSha3_384_MTU(b *testing.B) { benchmarkHash(b, New384(), 1350, 1) }
+func BenchmarkSha3_256_MTU(b *testing.B) { benchmarkHash(b, New256(), 1350, 1) }
+func BenchmarkSha3_224_MTU(b *testing.B) { benchmarkHash(b, New224(), 1350, 1) }
+
+func BenchmarkShake128_MTU(b *testing.B) { benchmarkShake(b, NewShake128(), 1350, 1) }
+func BenchmarkShake256_MTU(b *testing.B) { benchmarkShake(b, NewShake256(), 1350, 1) }
+func BenchmarkShake256_16x(b *testing.B) { benchmarkShake(b, NewShake256(), 16, 1024) }
+func BenchmarkShake256_1MiB(b *testing.B) { benchmarkShake(b, NewShake256(), 1024, 1024) }
+
+func BenchmarkSha3_512_1MiB(b *testing.B) { benchmarkHash(b, New512(), 1024, 1024) }
+
+func Example_sum() {
+ buf := []byte("some data to hash")
+ // A hash needs to be 64 bytes long to have 256-bit collision resistance.
+ h := make([]byte, 64)
+ // Compute a 64-byte hash of buf and put it in h.
+ ShakeSum256(h, buf)
+}
+
+func Example_mac() {
+ k := []byte("this is a secret key; you should generate a strong random key that's at least 32 bytes long")
+ buf := []byte("and this is some data to authenticate")
+ // A MAC with 32 bytes of output has 256-bit security strength -- if you use at least a 32-byte-long key.
+ h := make([]byte, 32)
+ d := NewShake256()
+ // Write the key into the hash.
+ d.Write(k)
+ // Now write the data.
+ d.Write(buf)
+ // Read 32 bytes of output from the hash into h.
+ d.Read(h)
+}
diff --git a/vendor/golang.org/x/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go
new file mode 100644
index 000000000..841f9860f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/shake.go
@@ -0,0 +1,60 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+// This file defines the ShakeHash interface, and provides
+// functions for creating SHAKE instances, as well as utility
+// functions for hashing bytes to arbitrary-length output.
+
+import (
+ "io"
+)
+
+// ShakeHash defines the interface to hash functions that
+// support arbitrary-length output.
+type ShakeHash interface {
+ // Write absorbs more data into the hash's state. It panics if input is
+ // written to it after output has been read from it.
+ io.Writer
+
+ // Read reads more output from the hash; reading affects the hash's
+ // state. (ShakeHash.Read is thus very different from Hash.Sum)
+ // It never returns an error.
+ io.Reader
+
+ // Clone returns a copy of the ShakeHash in its current state.
+ Clone() ShakeHash
+
+ // Reset resets the ShakeHash to its initial state.
+ Reset()
+}
+
+func (d *state) Clone() ShakeHash {
+ return d.clone()
+}
+
+// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
+// Its generic security strength is 128 bits against all attacks if at
+// least 32 bytes of its output are used.
+func NewShake128() ShakeHash { return &state{rate: 168, dsbyte: 0x1f} }
+
+// NewShake256 creates a new SHAKE128 variable-output-length ShakeHash.
+// Its generic security strength is 256 bits against all attacks if
+// at least 64 bytes of its output are used.
+func NewShake256() ShakeHash { return &state{rate: 136, dsbyte: 0x1f} }
+
+// ShakeSum128 writes an arbitrary-length digest of data into hash.
+func ShakeSum128(hash, data []byte) {
+ h := NewShake128()
+ h.Write(data)
+ h.Read(hash)
+}
+
+// ShakeSum256 writes an arbitrary-length digest of data into hash.
+func ShakeSum256(hash, data []byte) {
+ h := NewShake256()
+ h.Write(data)
+ h.Read(hash)
+}
diff --git a/vendor/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate b/vendor/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
new file mode 100644
index 000000000..62e85ae24
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/testdata/keccakKats.json.deflate
Binary files differ
diff --git a/vendor/golang.org/x/crypto/sha3/xor.go b/vendor/golang.org/x/crypto/sha3/xor.go
new file mode 100644
index 000000000..46a0d63a6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/xor.go
@@ -0,0 +1,16 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !amd64,!386,!ppc64le appengine
+
+package sha3
+
+var (
+ xorIn = xorInGeneric
+ copyOut = copyOutGeneric
+ xorInUnaligned = xorInGeneric
+ copyOutUnaligned = copyOutGeneric
+)
+
+const xorImplementationUnaligned = "generic"
diff --git a/vendor/golang.org/x/crypto/sha3/xor_generic.go b/vendor/golang.org/x/crypto/sha3/xor_generic.go
new file mode 100644
index 000000000..fd35f02ef
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/xor_generic.go
@@ -0,0 +1,28 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha3
+
+import "encoding/binary"
+
+// xorInGeneric xors the bytes in buf into the state; it
+// makes no non-portable assumptions about memory layout
+// or alignment.
+func xorInGeneric(d *state, buf []byte) {
+ n := len(buf) / 8
+
+ for i := 0; i < n; i++ {
+ a := binary.LittleEndian.Uint64(buf)
+ d.a[i] ^= a
+ buf = buf[8:]
+ }
+}
+
+// copyOutGeneric copies ulint64s to a byte buffer.
+func copyOutGeneric(d *state, b []byte) {
+ for i := 0; len(b) >= 8; i++ {
+ binary.LittleEndian.PutUint64(b, d.a[i])
+ b = b[8:]
+ }
+}
diff --git a/vendor/golang.org/x/crypto/sha3/xor_unaligned.go b/vendor/golang.org/x/crypto/sha3/xor_unaligned.go
new file mode 100644
index 000000000..929a486a7
--- /dev/null
+++ b/vendor/golang.org/x/crypto/sha3/xor_unaligned.go
@@ -0,0 +1,58 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build amd64 386 ppc64le
+// +build !appengine
+
+package sha3
+
+import "unsafe"
+
+func xorInUnaligned(d *state, buf []byte) {
+ bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))
+ n := len(buf)
+ if n >= 72 {
+ d.a[0] ^= bw[0]
+ d.a[1] ^= bw[1]
+ d.a[2] ^= bw[2]
+ d.a[3] ^= bw[3]
+ d.a[4] ^= bw[4]
+ d.a[5] ^= bw[5]
+ d.a[6] ^= bw[6]
+ d.a[7] ^= bw[7]
+ d.a[8] ^= bw[8]
+ }
+ if n >= 104 {
+ d.a[9] ^= bw[9]
+ d.a[10] ^= bw[10]
+ d.a[11] ^= bw[11]
+ d.a[12] ^= bw[12]
+ }
+ if n >= 136 {
+ d.a[13] ^= bw[13]
+ d.a[14] ^= bw[14]
+ d.a[15] ^= bw[15]
+ d.a[16] ^= bw[16]
+ }
+ if n >= 144 {
+ d.a[17] ^= bw[17]
+ }
+ if n >= 168 {
+ d.a[18] ^= bw[18]
+ d.a[19] ^= bw[19]
+ d.a[20] ^= bw[20]
+ }
+}
+
+func copyOutUnaligned(d *state, buf []byte) {
+ ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0]))
+ copy(buf, ab[:])
+}
+
+var (
+ xorIn = xorInUnaligned
+ copyOut = copyOutUnaligned
+)
+
+const xorImplementationUnaligned = "unaligned"
diff --git a/vendor/golang.org/x/crypto/ssh/agent/client.go b/vendor/golang.org/x/crypto/ssh/agent/client.go
new file mode 100644
index 000000000..3f798e719
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/client.go
@@ -0,0 +1,622 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package agent implements the ssh-agent protocol, and provides both
+// a client and a server. The client can talk to a standard ssh-agent
+// that uses UNIX sockets, and one could implement an alternative
+// ssh-agent process using the sample server.
+//
+// References:
+// [PROTOCOL.agent]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
+package agent // import "golang.org/x/crypto/ssh/agent"
+
+import (
+ "bytes"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "encoding/base64"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "sync"
+
+ "golang.org/x/crypto/ssh"
+)
+
+// Agent represents the capabilities of an ssh-agent.
+type Agent interface {
+ // List returns the identities known to the agent.
+ List() ([]*Key, error)
+
+ // Sign has the agent sign the data using a protocol 2 key as defined
+ // in [PROTOCOL.agent] section 2.6.2.
+ Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
+
+ // Add adds a private key to the agent.
+ Add(key AddedKey) error
+
+ // Remove removes all identities with the given public key.
+ Remove(key ssh.PublicKey) error
+
+ // RemoveAll removes all identities.
+ RemoveAll() error
+
+ // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
+ Lock(passphrase []byte) error
+
+ // Unlock undoes the effect of Lock
+ Unlock(passphrase []byte) error
+
+ // Signers returns signers for all the known keys.
+ Signers() ([]ssh.Signer, error)
+}
+
+// AddedKey describes an SSH key to be added to an Agent.
+type AddedKey struct {
+ // PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey or
+ // *ecdsa.PrivateKey, which will be inserted into the agent.
+ PrivateKey interface{}
+ // Certificate, if not nil, is communicated to the agent and will be
+ // stored with the key.
+ Certificate *ssh.Certificate
+ // Comment is an optional, free-form string.
+ Comment string
+ // LifetimeSecs, if not zero, is the number of seconds that the
+ // agent will store the key for.
+ LifetimeSecs uint32
+ // ConfirmBeforeUse, if true, requests that the agent confirm with the
+ // user before each use of this key.
+ ConfirmBeforeUse bool
+}
+
+// See [PROTOCOL.agent], section 3.
+const (
+ agentRequestV1Identities = 1
+ agentRemoveAllV1Identities = 9
+
+ // 3.2 Requests from client to agent for protocol 2 key operations
+ agentAddIdentity = 17
+ agentRemoveIdentity = 18
+ agentRemoveAllIdentities = 19
+ agentAddIdConstrained = 25
+
+ // 3.3 Key-type independent requests from client to agent
+ agentAddSmartcardKey = 20
+ agentRemoveSmartcardKey = 21
+ agentLock = 22
+ agentUnlock = 23
+ agentAddSmartcardKeyConstrained = 26
+
+ // 3.7 Key constraint identifiers
+ agentConstrainLifetime = 1
+ agentConstrainConfirm = 2
+)
+
+// maxAgentResponseBytes is the maximum agent reply size that is accepted. This
+// is a sanity check, not a limit in the spec.
+const maxAgentResponseBytes = 16 << 20
+
+// Agent messages:
+// These structures mirror the wire format of the corresponding ssh agent
+// messages found in [PROTOCOL.agent].
+
+// 3.4 Generic replies from agent to client
+const agentFailure = 5
+
+type failureAgentMsg struct{}
+
+const agentSuccess = 6
+
+type successAgentMsg struct{}
+
+// See [PROTOCOL.agent], section 2.5.2.
+const agentRequestIdentities = 11
+
+type requestIdentitiesAgentMsg struct{}
+
+// See [PROTOCOL.agent], section 2.5.2.
+const agentIdentitiesAnswer = 12
+
+type identitiesAnswerAgentMsg struct {
+ NumKeys uint32 `sshtype:"12"`
+ Keys []byte `ssh:"rest"`
+}
+
+// See [PROTOCOL.agent], section 2.6.2.
+const agentSignRequest = 13
+
+type signRequestAgentMsg struct {
+ KeyBlob []byte `sshtype:"13"`
+ Data []byte
+ Flags uint32
+}
+
+// See [PROTOCOL.agent], section 2.6.2.
+
+// 3.6 Replies from agent to client for protocol 2 key operations
+const agentSignResponse = 14
+
+type signResponseAgentMsg struct {
+ SigBlob []byte `sshtype:"14"`
+}
+
+type publicKey struct {
+ Format string
+ Rest []byte `ssh:"rest"`
+}
+
+// Key represents a protocol 2 public key as defined in
+// [PROTOCOL.agent], section 2.5.2.
+type Key struct {
+ Format string
+ Blob []byte
+ Comment string
+}
+
+func clientErr(err error) error {
+ return fmt.Errorf("agent: client error: %v", err)
+}
+
+// String returns the storage form of an agent key with the format, base64
+// encoded serialized key, and the comment if it is not empty.
+func (k *Key) String() string {
+ s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob)
+
+ if k.Comment != "" {
+ s += " " + k.Comment
+ }
+
+ return s
+}
+
+// Type returns the public key type.
+func (k *Key) Type() string {
+ return k.Format
+}
+
+// Marshal returns key blob to satisfy the ssh.PublicKey interface.
+func (k *Key) Marshal() []byte {
+ return k.Blob
+}
+
+// Verify satisfies the ssh.PublicKey interface.
+func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
+ pubKey, err := ssh.ParsePublicKey(k.Blob)
+ if err != nil {
+ return fmt.Errorf("agent: bad public key: %v", err)
+ }
+ return pubKey.Verify(data, sig)
+}
+
+type wireKey struct {
+ Format string
+ Rest []byte `ssh:"rest"`
+}
+
+func parseKey(in []byte) (out *Key, rest []byte, err error) {
+ var record struct {
+ Blob []byte
+ Comment string
+ Rest []byte `ssh:"rest"`
+ }
+
+ if err := ssh.Unmarshal(in, &record); err != nil {
+ return nil, nil, err
+ }
+
+ var wk wireKey
+ if err := ssh.Unmarshal(record.Blob, &wk); err != nil {
+ return nil, nil, err
+ }
+
+ return &Key{
+ Format: wk.Format,
+ Blob: record.Blob,
+ Comment: record.Comment,
+ }, record.Rest, nil
+}
+
+// client is a client for an ssh-agent process.
+type client struct {
+ // conn is typically a *net.UnixConn
+ conn io.ReadWriter
+ // mu is used to prevent concurrent access to the agent
+ mu sync.Mutex
+}
+
+// NewClient returns an Agent that talks to an ssh-agent process over
+// the given connection.
+func NewClient(rw io.ReadWriter) Agent {
+ return &client{conn: rw}
+}
+
+// call sends an RPC to the agent. On success, the reply is
+// unmarshaled into reply and replyType is set to the first byte of
+// the reply, which contains the type of the message.
+func (c *client) call(req []byte) (reply interface{}, err error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ msg := make([]byte, 4+len(req))
+ binary.BigEndian.PutUint32(msg, uint32(len(req)))
+ copy(msg[4:], req)
+ if _, err = c.conn.Write(msg); err != nil {
+ return nil, clientErr(err)
+ }
+
+ var respSizeBuf [4]byte
+ if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil {
+ return nil, clientErr(err)
+ }
+ respSize := binary.BigEndian.Uint32(respSizeBuf[:])
+ if respSize > maxAgentResponseBytes {
+ return nil, clientErr(err)
+ }
+
+ buf := make([]byte, respSize)
+ if _, err = io.ReadFull(c.conn, buf); err != nil {
+ return nil, clientErr(err)
+ }
+ reply, err = unmarshal(buf)
+ if err != nil {
+ return nil, clientErr(err)
+ }
+ return reply, err
+}
+
+func (c *client) simpleCall(req []byte) error {
+ resp, err := c.call(req)
+ if err != nil {
+ return err
+ }
+ if _, ok := resp.(*successAgentMsg); ok {
+ return nil
+ }
+ return errors.New("agent: failure")
+}
+
+func (c *client) RemoveAll() error {
+ return c.simpleCall([]byte{agentRemoveAllIdentities})
+}
+
+func (c *client) Remove(key ssh.PublicKey) error {
+ req := ssh.Marshal(&agentRemoveIdentityMsg{
+ KeyBlob: key.Marshal(),
+ })
+ return c.simpleCall(req)
+}
+
+func (c *client) Lock(passphrase []byte) error {
+ req := ssh.Marshal(&agentLockMsg{
+ Passphrase: passphrase,
+ })
+ return c.simpleCall(req)
+}
+
+func (c *client) Unlock(passphrase []byte) error {
+ req := ssh.Marshal(&agentUnlockMsg{
+ Passphrase: passphrase,
+ })
+ return c.simpleCall(req)
+}
+
+// List returns the identities known to the agent.
+func (c *client) List() ([]*Key, error) {
+ // see [PROTOCOL.agent] section 2.5.2.
+ req := []byte{agentRequestIdentities}
+
+ msg, err := c.call(req)
+ if err != nil {
+ return nil, err
+ }
+
+ switch msg := msg.(type) {
+ case *identitiesAnswerAgentMsg:
+ if msg.NumKeys > maxAgentResponseBytes/8 {
+ return nil, errors.New("agent: too many keys in agent reply")
+ }
+ keys := make([]*Key, msg.NumKeys)
+ data := msg.Keys
+ for i := uint32(0); i < msg.NumKeys; i++ {
+ var key *Key
+ var err error
+ if key, data, err = parseKey(data); err != nil {
+ return nil, err
+ }
+ keys[i] = key
+ }
+ return keys, nil
+ case *failureAgentMsg:
+ return nil, errors.New("agent: failed to list keys")
+ }
+ panic("unreachable")
+}
+
+// Sign has the agent sign the data using a protocol 2 key as defined
+// in [PROTOCOL.agent] section 2.6.2.
+func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
+ req := ssh.Marshal(signRequestAgentMsg{
+ KeyBlob: key.Marshal(),
+ Data: data,
+ })
+
+ msg, err := c.call(req)
+ if err != nil {
+ return nil, err
+ }
+
+ switch msg := msg.(type) {
+ case *signResponseAgentMsg:
+ var sig ssh.Signature
+ if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil {
+ return nil, err
+ }
+
+ return &sig, nil
+ case *failureAgentMsg:
+ return nil, errors.New("agent: failed to sign challenge")
+ }
+ panic("unreachable")
+}
+
+// unmarshal parses an agent message in packet, returning the parsed
+// form and the message type of packet.
+func unmarshal(packet []byte) (interface{}, error) {
+ if len(packet) < 1 {
+ return nil, errors.New("agent: empty packet")
+ }
+ var msg interface{}
+ switch packet[0] {
+ case agentFailure:
+ return new(failureAgentMsg), nil
+ case agentSuccess:
+ return new(successAgentMsg), nil
+ case agentIdentitiesAnswer:
+ msg = new(identitiesAnswerAgentMsg)
+ case agentSignResponse:
+ msg = new(signResponseAgentMsg)
+ case agentV1IdentitiesAnswer:
+ msg = new(agentV1IdentityMsg)
+ default:
+ return nil, fmt.Errorf("agent: unknown type tag %d", packet[0])
+ }
+ if err := ssh.Unmarshal(packet, msg); err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+
+type rsaKeyMsg struct {
+ Type string `sshtype:"17|25"`
+ N *big.Int
+ E *big.Int
+ D *big.Int
+ Iqmp *big.Int // IQMP = Inverse Q Mod P
+ P *big.Int
+ Q *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type dsaKeyMsg struct {
+ Type string `sshtype:"17|25"`
+ P *big.Int
+ Q *big.Int
+ G *big.Int
+ Y *big.Int
+ X *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type ecdsaKeyMsg struct {
+ Type string `sshtype:"17|25"`
+ Curve string
+ KeyBytes []byte
+ D *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+// Insert adds a private key to the agent.
+func (c *client) insertKey(s interface{}, comment string, constraints []byte) error {
+ var req []byte
+ switch k := s.(type) {
+ case *rsa.PrivateKey:
+ if len(k.Primes) != 2 {
+ return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
+ }
+ k.Precompute()
+ req = ssh.Marshal(rsaKeyMsg{
+ Type: ssh.KeyAlgoRSA,
+ N: k.N,
+ E: big.NewInt(int64(k.E)),
+ D: k.D,
+ Iqmp: k.Precomputed.Qinv,
+ P: k.Primes[0],
+ Q: k.Primes[1],
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *dsa.PrivateKey:
+ req = ssh.Marshal(dsaKeyMsg{
+ Type: ssh.KeyAlgoDSA,
+ P: k.P,
+ Q: k.Q,
+ G: k.G,
+ Y: k.Y,
+ X: k.X,
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *ecdsa.PrivateKey:
+ nistID := fmt.Sprintf("nistp%d", k.Params().BitSize)
+ req = ssh.Marshal(ecdsaKeyMsg{
+ Type: "ecdsa-sha2-" + nistID,
+ Curve: nistID,
+ KeyBytes: elliptic.Marshal(k.Curve, k.X, k.Y),
+ D: k.D,
+ Comments: comment,
+ Constraints: constraints,
+ })
+ default:
+ return fmt.Errorf("agent: unsupported key type %T", s)
+ }
+
+ // if constraints are present then the message type needs to be changed.
+ if len(constraints) != 0 {
+ req[0] = agentAddIdConstrained
+ }
+
+ resp, err := c.call(req)
+ if err != nil {
+ return err
+ }
+ if _, ok := resp.(*successAgentMsg); ok {
+ return nil
+ }
+ return errors.New("agent: failure")
+}
+
+type rsaCertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ D *big.Int
+ Iqmp *big.Int // IQMP = Inverse Q Mod P
+ P *big.Int
+ Q *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type dsaCertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ X *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+type ecdsaCertMsg struct {
+ Type string `sshtype:"17|25"`
+ CertBytes []byte
+ D *big.Int
+ Comments string
+ Constraints []byte `ssh:"rest"`
+}
+
+// Insert adds a private key to the agent. If a certificate is given,
+// that certificate is added instead as public key.
+func (c *client) Add(key AddedKey) error {
+ var constraints []byte
+
+ if secs := key.LifetimeSecs; secs != 0 {
+ constraints = append(constraints, agentConstrainLifetime)
+
+ var secsBytes [4]byte
+ binary.BigEndian.PutUint32(secsBytes[:], secs)
+ constraints = append(constraints, secsBytes[:]...)
+ }
+
+ if key.ConfirmBeforeUse {
+ constraints = append(constraints, agentConstrainConfirm)
+ }
+
+ if cert := key.Certificate; cert == nil {
+ return c.insertKey(key.PrivateKey, key.Comment, constraints)
+ } else {
+ return c.insertCert(key.PrivateKey, cert, key.Comment, constraints)
+ }
+}
+
+func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error {
+ var req []byte
+ switch k := s.(type) {
+ case *rsa.PrivateKey:
+ if len(k.Primes) != 2 {
+ return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
+ }
+ k.Precompute()
+ req = ssh.Marshal(rsaCertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ D: k.D,
+ Iqmp: k.Precomputed.Qinv,
+ P: k.Primes[0],
+ Q: k.Primes[1],
+ Comments: comment,
+ Constraints: constraints,
+ })
+ case *dsa.PrivateKey:
+ req = ssh.Marshal(dsaCertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ X: k.X,
+ Comments: comment,
+ })
+ case *ecdsa.PrivateKey:
+ req = ssh.Marshal(ecdsaCertMsg{
+ Type: cert.Type(),
+ CertBytes: cert.Marshal(),
+ D: k.D,
+ Comments: comment,
+ })
+ default:
+ return fmt.Errorf("agent: unsupported key type %T", s)
+ }
+
+ // if constraints are present then the message type needs to be changed.
+ if len(constraints) != 0 {
+ req[0] = agentAddIdConstrained
+ }
+
+ signer, err := ssh.NewSignerFromKey(s)
+ if err != nil {
+ return err
+ }
+ if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
+ return errors.New("agent: signer and cert have different public key")
+ }
+
+ resp, err := c.call(req)
+ if err != nil {
+ return err
+ }
+ if _, ok := resp.(*successAgentMsg); ok {
+ return nil
+ }
+ return errors.New("agent: failure")
+}
+
+// Signers provides a callback for client authentication.
+func (c *client) Signers() ([]ssh.Signer, error) {
+ keys, err := c.List()
+ if err != nil {
+ return nil, err
+ }
+
+ var result []ssh.Signer
+ for _, k := range keys {
+ result = append(result, &agentKeyringSigner{c, k})
+ }
+ return result, nil
+}
+
+type agentKeyringSigner struct {
+ agent *client
+ pub ssh.PublicKey
+}
+
+func (s *agentKeyringSigner) PublicKey() ssh.PublicKey {
+ return s.pub
+}
+
+func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) {
+ // The agent has its own entropy source, so the rand argument is ignored.
+ return s.agent.Sign(s.pub, data)
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/client_test.go b/vendor/golang.org/x/crypto/ssh/agent/client_test.go
new file mode 100644
index 000000000..ec7198d54
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/client_test.go
@@ -0,0 +1,287 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "bytes"
+ "crypto/rand"
+ "errors"
+ "net"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strconv"
+ "testing"
+
+ "golang.org/x/crypto/ssh"
+)
+
+// startAgent executes ssh-agent, and returns a Agent interface to it.
+func startAgent(t *testing.T) (client Agent, socket string, cleanup func()) {
+ if testing.Short() {
+ // ssh-agent is not always available, and the key
+ // types supported vary by platform.
+ t.Skip("skipping test due to -short")
+ }
+
+ bin, err := exec.LookPath("ssh-agent")
+ if err != nil {
+ t.Skip("could not find ssh-agent")
+ }
+
+ cmd := exec.Command(bin, "-s")
+ out, err := cmd.Output()
+ if err != nil {
+ t.Fatalf("cmd.Output: %v", err)
+ }
+
+ /* Output looks like:
+
+ SSH_AUTH_SOCK=/tmp/ssh-P65gpcqArqvH/agent.15541; export SSH_AUTH_SOCK;
+ SSH_AGENT_PID=15542; export SSH_AGENT_PID;
+ echo Agent pid 15542;
+ */
+ fields := bytes.Split(out, []byte(";"))
+ line := bytes.SplitN(fields[0], []byte("="), 2)
+ line[0] = bytes.TrimLeft(line[0], "\n")
+ if string(line[0]) != "SSH_AUTH_SOCK" {
+ t.Fatalf("could not find key SSH_AUTH_SOCK in %q", fields[0])
+ }
+ socket = string(line[1])
+
+ line = bytes.SplitN(fields[2], []byte("="), 2)
+ line[0] = bytes.TrimLeft(line[0], "\n")
+ if string(line[0]) != "SSH_AGENT_PID" {
+ t.Fatalf("could not find key SSH_AGENT_PID in %q", fields[2])
+ }
+ pidStr := line[1]
+ pid, err := strconv.Atoi(string(pidStr))
+ if err != nil {
+ t.Fatalf("Atoi(%q): %v", pidStr, err)
+ }
+
+ conn, err := net.Dial("unix", string(socket))
+ if err != nil {
+ t.Fatalf("net.Dial: %v", err)
+ }
+
+ ac := NewClient(conn)
+ return ac, socket, func() {
+ proc, _ := os.FindProcess(pid)
+ if proc != nil {
+ proc.Kill()
+ }
+ conn.Close()
+ os.RemoveAll(filepath.Dir(socket))
+ }
+}
+
+func testAgent(t *testing.T, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
+ agent, _, cleanup := startAgent(t)
+ defer cleanup()
+
+ testAgentInterface(t, agent, key, cert, lifetimeSecs)
+}
+
+func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
+ signer, err := ssh.NewSignerFromKey(key)
+ if err != nil {
+ t.Fatalf("NewSignerFromKey(%T): %v", key, err)
+ }
+ // The agent should start up empty.
+ if keys, err := agent.List(); err != nil {
+ t.Fatalf("RequestIdentities: %v", err)
+ } else if len(keys) > 0 {
+ t.Fatalf("got %d keys, want 0: %v", len(keys), keys)
+ }
+
+ // Attempt to insert the key, with certificate if specified.
+ var pubKey ssh.PublicKey
+ if cert != nil {
+ err = agent.Add(AddedKey{
+ PrivateKey: key,
+ Certificate: cert,
+ Comment: "comment",
+ LifetimeSecs: lifetimeSecs,
+ })
+ pubKey = cert
+ } else {
+ err = agent.Add(AddedKey{PrivateKey: key, Comment: "comment", LifetimeSecs: lifetimeSecs})
+ pubKey = signer.PublicKey()
+ }
+ if err != nil {
+ t.Fatalf("insert(%T): %v", key, err)
+ }
+
+ // Did the key get inserted successfully?
+ if keys, err := agent.List(); err != nil {
+ t.Fatalf("List: %v", err)
+ } else if len(keys) != 1 {
+ t.Fatalf("got %v, want 1 key", keys)
+ } else if keys[0].Comment != "comment" {
+ t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment")
+ } else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) {
+ t.Fatalf("key mismatch")
+ }
+
+ // Can the agent make a valid signature?
+ data := []byte("hello")
+ sig, err := agent.Sign(pubKey, data)
+ if err != nil {
+ t.Fatalf("Sign(%s): %v", pubKey.Type(), err)
+ }
+
+ if err := pubKey.Verify(data, sig); err != nil {
+ t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
+ }
+}
+
+func TestAgent(t *testing.T) {
+ for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
+ testAgent(t, testPrivateKeys[keyType], nil, 0)
+ }
+}
+
+func TestCert(t *testing.T) {
+ cert := &ssh.Certificate{
+ Key: testPublicKeys["rsa"],
+ ValidBefore: ssh.CertTimeInfinity,
+ CertType: ssh.UserCert,
+ }
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+
+ testAgent(t, testPrivateKeys["rsa"], cert, 0)
+}
+
+func TestConstraints(t *testing.T) {
+ testAgent(t, testPrivateKeys["rsa"], nil, 3600 /* lifetime in seconds */)
+}
+
+// netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
+// therefore is buffered (net.Pipe deadlocks if both sides start with
+// a write.)
+func netPipe() (net.Conn, net.Conn, error) {
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ return nil, nil, err
+ }
+ defer listener.Close()
+ c1, err := net.Dial("tcp", listener.Addr().String())
+ if err != nil {
+ return nil, nil, err
+ }
+
+ c2, err := listener.Accept()
+ if err != nil {
+ c1.Close()
+ return nil, nil, err
+ }
+
+ return c1, c2, nil
+}
+
+func TestAuth(t *testing.T) {
+ a, b, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+
+ defer a.Close()
+ defer b.Close()
+
+ agent, _, cleanup := startAgent(t)
+ defer cleanup()
+
+ if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment"}); err != nil {
+ t.Errorf("Add: %v", err)
+ }
+
+ serverConf := ssh.ServerConfig{}
+ serverConf.AddHostKey(testSigners["rsa"])
+ serverConf.PublicKeyCallback = func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
+ if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
+ return nil, nil
+ }
+
+ return nil, errors.New("pubkey rejected")
+ }
+
+ go func() {
+ conn, _, _, err := ssh.NewServerConn(a, &serverConf)
+ if err != nil {
+ t.Fatalf("Server: %v", err)
+ }
+ conn.Close()
+ }()
+
+ conf := ssh.ClientConfig{}
+ conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers))
+ conn, _, _, err := ssh.NewClientConn(b, "", &conf)
+ if err != nil {
+ t.Fatalf("NewClientConn: %v", err)
+ }
+ conn.Close()
+}
+
+func TestLockClient(t *testing.T) {
+ agent, _, cleanup := startAgent(t)
+ defer cleanup()
+ testLockAgent(agent, t)
+}
+
+func testLockAgent(agent Agent, t *testing.T) {
+ if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment 1"}); err != nil {
+ t.Errorf("Add: %v", err)
+ }
+ if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["dsa"], Comment: "comment dsa"}); err != nil {
+ t.Errorf("Add: %v", err)
+ }
+ if keys, err := agent.List(); err != nil {
+ t.Errorf("List: %v", err)
+ } else if len(keys) != 2 {
+ t.Errorf("Want 2 keys, got %v", keys)
+ }
+
+ passphrase := []byte("secret")
+ if err := agent.Lock(passphrase); err != nil {
+ t.Errorf("Lock: %v", err)
+ }
+
+ if keys, err := agent.List(); err != nil {
+ t.Errorf("List: %v", err)
+ } else if len(keys) != 0 {
+ t.Errorf("Want 0 keys, got %v", keys)
+ }
+
+ signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"])
+ if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil {
+ t.Fatalf("Sign did not fail")
+ }
+
+ if err := agent.Remove(signer.PublicKey()); err == nil {
+ t.Fatalf("Remove did not fail")
+ }
+
+ if err := agent.RemoveAll(); err == nil {
+ t.Fatalf("RemoveAll did not fail")
+ }
+
+ if err := agent.Unlock(nil); err == nil {
+ t.Errorf("Unlock with wrong passphrase succeeded")
+ }
+ if err := agent.Unlock(passphrase); err != nil {
+ t.Errorf("Unlock: %v", err)
+ }
+
+ if err := agent.Remove(signer.PublicKey()); err != nil {
+ t.Fatalf("Remove: %v", err)
+ }
+
+ if keys, err := agent.List(); err != nil {
+ t.Errorf("List: %v", err)
+ } else if len(keys) != 1 {
+ t.Errorf("Want 1 keys, got %v", keys)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/example_test.go b/vendor/golang.org/x/crypto/ssh/agent/example_test.go
new file mode 100644
index 000000000..c1130f77a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/example_test.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent_test
+
+import (
+ "log"
+ "os"
+ "net"
+
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/agent"
+)
+
+func ExampleClientAgent() {
+ // ssh-agent has a UNIX socket under $SSH_AUTH_SOCK
+ socket := os.Getenv("SSH_AUTH_SOCK")
+ conn, err := net.Dial("unix", socket)
+ if err != nil {
+ log.Fatalf("net.Dial: %v", err)
+ }
+ agentClient := agent.NewClient(conn)
+ config := &ssh.ClientConfig{
+ User: "username",
+ Auth: []ssh.AuthMethod{
+ // Use a callback rather than PublicKeys
+ // so we only consult the agent once the remote server
+ // wants it.
+ ssh.PublicKeysCallback(agentClient.Signers),
+ },
+ }
+
+ sshc, err := ssh.Dial("tcp", "localhost:22", config)
+ if err != nil {
+ log.Fatalf("Dial: %v", err)
+ }
+ // .. use sshc
+ sshc.Close()
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/forward.go b/vendor/golang.org/x/crypto/ssh/agent/forward.go
new file mode 100644
index 000000000..fd24ba900
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/forward.go
@@ -0,0 +1,103 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "errors"
+ "io"
+ "net"
+ "sync"
+
+ "golang.org/x/crypto/ssh"
+)
+
+// RequestAgentForwarding sets up agent forwarding for the session.
+// ForwardToAgent or ForwardToRemote should be called to route
+// the authentication requests.
+func RequestAgentForwarding(session *ssh.Session) error {
+ ok, err := session.SendRequest("auth-agent-req@openssh.com", true, nil)
+ if err != nil {
+ return err
+ }
+ if !ok {
+ return errors.New("forwarding request denied")
+ }
+ return nil
+}
+
+// ForwardToAgent routes authentication requests to the given keyring.
+func ForwardToAgent(client *ssh.Client, keyring Agent) error {
+ channels := client.HandleChannelOpen(channelType)
+ if channels == nil {
+ return errors.New("agent: already have handler for " + channelType)
+ }
+
+ go func() {
+ for ch := range channels {
+ channel, reqs, err := ch.Accept()
+ if err != nil {
+ continue
+ }
+ go ssh.DiscardRequests(reqs)
+ go func() {
+ ServeAgent(keyring, channel)
+ channel.Close()
+ }()
+ }
+ }()
+ return nil
+}
+
+const channelType = "auth-agent@openssh.com"
+
+// ForwardToRemote routes authentication requests to the ssh-agent
+// process serving on the given unix socket.
+func ForwardToRemote(client *ssh.Client, addr string) error {
+ channels := client.HandleChannelOpen(channelType)
+ if channels == nil {
+ return errors.New("agent: already have handler for " + channelType)
+ }
+ conn, err := net.Dial("unix", addr)
+ if err != nil {
+ return err
+ }
+ conn.Close()
+
+ go func() {
+ for ch := range channels {
+ channel, reqs, err := ch.Accept()
+ if err != nil {
+ continue
+ }
+ go ssh.DiscardRequests(reqs)
+ go forwardUnixSocket(channel, addr)
+ }
+ }()
+ return nil
+}
+
+func forwardUnixSocket(channel ssh.Channel, addr string) {
+ conn, err := net.Dial("unix", addr)
+ if err != nil {
+ return
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ io.Copy(conn, channel)
+ conn.(*net.UnixConn).CloseWrite()
+ wg.Done()
+ }()
+ go func() {
+ io.Copy(channel, conn)
+ channel.CloseWrite()
+ wg.Done()
+ }()
+
+ wg.Wait()
+ conn.Close()
+ channel.Close()
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring.go b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
new file mode 100644
index 000000000..12ffa82b1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/keyring.go
@@ -0,0 +1,184 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "bytes"
+ "crypto/rand"
+ "crypto/subtle"
+ "errors"
+ "fmt"
+ "sync"
+
+ "golang.org/x/crypto/ssh"
+)
+
+type privKey struct {
+ signer ssh.Signer
+ comment string
+}
+
+type keyring struct {
+ mu sync.Mutex
+ keys []privKey
+
+ locked bool
+ passphrase []byte
+}
+
+var errLocked = errors.New("agent: locked")
+
+// NewKeyring returns an Agent that holds keys in memory. It is safe
+// for concurrent use by multiple goroutines.
+func NewKeyring() Agent {
+ return &keyring{}
+}
+
+// RemoveAll removes all identities.
+func (r *keyring) RemoveAll() error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+
+ r.keys = nil
+ return nil
+}
+
+// Remove removes all identities with the given public key.
+func (r *keyring) Remove(key ssh.PublicKey) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+
+ want := key.Marshal()
+ found := false
+ for i := 0; i < len(r.keys); {
+ if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) {
+ found = true
+ r.keys[i] = r.keys[len(r.keys)-1]
+ r.keys = r.keys[:len(r.keys)-1]
+ continue
+ } else {
+ i++
+ }
+ }
+
+ if !found {
+ return errors.New("agent: key not found")
+ }
+ return nil
+}
+
+// Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
+func (r *keyring) Lock(passphrase []byte) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+
+ r.locked = true
+ r.passphrase = passphrase
+ return nil
+}
+
+// Unlock undoes the effect of Lock
+func (r *keyring) Unlock(passphrase []byte) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if !r.locked {
+ return errors.New("agent: not locked")
+ }
+ if len(passphrase) != len(r.passphrase) || 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) {
+ return fmt.Errorf("agent: incorrect passphrase")
+ }
+
+ r.locked = false
+ r.passphrase = nil
+ return nil
+}
+
+// List returns the identities known to the agent.
+func (r *keyring) List() ([]*Key, error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ // section 2.7: locked agents return empty.
+ return nil, nil
+ }
+
+ var ids []*Key
+ for _, k := range r.keys {
+ pub := k.signer.PublicKey()
+ ids = append(ids, &Key{
+ Format: pub.Type(),
+ Blob: pub.Marshal(),
+ Comment: k.comment})
+ }
+ return ids, nil
+}
+
+// Insert adds a private key to the keyring. If a certificate
+// is given, that certificate is added as public key. Note that
+// any constraints given are ignored.
+func (r *keyring) Add(key AddedKey) error {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return errLocked
+ }
+ signer, err := ssh.NewSignerFromKey(key.PrivateKey)
+
+ if err != nil {
+ return err
+ }
+
+ if cert := key.Certificate; cert != nil {
+ signer, err = ssh.NewCertSigner(cert, signer)
+ if err != nil {
+ return err
+ }
+ }
+
+ r.keys = append(r.keys, privKey{signer, key.Comment})
+
+ return nil
+}
+
+// Sign returns a signature for the data.
+func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return nil, errLocked
+ }
+
+ wanted := key.Marshal()
+ for _, k := range r.keys {
+ if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) {
+ return k.signer.Sign(rand.Reader, data)
+ }
+ }
+ return nil, errors.New("not found")
+}
+
+// Signers returns signers for all the known keys.
+func (r *keyring) Signers() ([]ssh.Signer, error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if r.locked {
+ return nil, errLocked
+ }
+
+ s := make([]ssh.Signer, 0, len(r.keys))
+ for _, k := range r.keys {
+ s = append(s, k.signer)
+ }
+ return s, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/keyring_test.go b/vendor/golang.org/x/crypto/ssh/agent/keyring_test.go
new file mode 100644
index 000000000..7f0590571
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/keyring_test.go
@@ -0,0 +1,78 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "testing"
+)
+
+func addTestKey(t *testing.T, a Agent, keyName string) {
+ err := a.Add(AddedKey{
+ PrivateKey: testPrivateKeys[keyName],
+ Comment: keyName,
+ })
+ if err != nil {
+ t.Fatalf("failed to add key %q: %v", keyName, err)
+ }
+}
+
+func removeTestKey(t *testing.T, a Agent, keyName string) {
+ err := a.Remove(testPublicKeys[keyName])
+ if err != nil {
+ t.Fatalf("failed to remove key %q: %v", keyName, err)
+ }
+}
+
+func validateListedKeys(t *testing.T, a Agent, expectedKeys []string) {
+ listedKeys, err := a.List()
+ if err != nil {
+ t.Fatalf("failed to list keys: %v", err)
+ return
+ }
+ actualKeys := make(map[string]bool)
+ for _, key := range listedKeys {
+ actualKeys[key.Comment] = true
+ }
+
+ matchedKeys := make(map[string]bool)
+ for _, expectedKey := range expectedKeys {
+ if !actualKeys[expectedKey] {
+ t.Fatalf("expected key %q, but was not found", expectedKey)
+ } else {
+ matchedKeys[expectedKey] = true
+ }
+ }
+
+ for actualKey := range actualKeys {
+ if !matchedKeys[actualKey] {
+ t.Fatalf("key %q was found, but was not expected", actualKey)
+ }
+ }
+}
+
+func TestKeyringAddingAndRemoving(t *testing.T) {
+ keyNames := []string{"dsa", "ecdsa", "rsa", "user"}
+
+ // add all test private keys
+ k := NewKeyring()
+ for _, keyName := range keyNames {
+ addTestKey(t, k, keyName)
+ }
+ validateListedKeys(t, k, keyNames)
+
+ // remove a key in the middle
+ keyToRemove := keyNames[1]
+ keyNames = append(keyNames[:1], keyNames[2:]...)
+
+ removeTestKey(t, k, keyToRemove)
+ validateListedKeys(t, k, keyNames)
+
+ // remove all keys
+ err := k.RemoveAll()
+ if err != nil {
+ t.Fatalf("failed to remove all keys: %v", err)
+ }
+ validateListedKeys(t, k, []string{})
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/server.go b/vendor/golang.org/x/crypto/ssh/agent/server.go
new file mode 100644
index 000000000..c562fa6e8
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/server.go
@@ -0,0 +1,420 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "math/big"
+
+ "golang.org/x/crypto/ssh"
+)
+
+// Server wraps an Agent and uses it to implement the agent side of
+// the SSH-agent, wire protocol.
+type server struct {
+ agent Agent
+}
+
+func (s *server) processRequestBytes(reqData []byte) []byte {
+ rep, err := s.processRequest(reqData)
+ if err != nil {
+ if err != errLocked {
+ // TODO(hanwen): provide better logging interface?
+ log.Printf("agent %d: %v", reqData[0], err)
+ }
+ return []byte{agentFailure}
+ }
+
+ if err == nil && rep == nil {
+ return []byte{agentSuccess}
+ }
+
+ return ssh.Marshal(rep)
+}
+
+func marshalKey(k *Key) []byte {
+ var record struct {
+ Blob []byte
+ Comment string
+ }
+ record.Blob = k.Marshal()
+ record.Comment = k.Comment
+
+ return ssh.Marshal(&record)
+}
+
+// See [PROTOCOL.agent], section 2.5.1.
+const agentV1IdentitiesAnswer = 2
+
+type agentV1IdentityMsg struct {
+ Numkeys uint32 `sshtype:"2"`
+}
+
+type agentRemoveIdentityMsg struct {
+ KeyBlob []byte `sshtype:"18"`
+}
+
+type agentLockMsg struct {
+ Passphrase []byte `sshtype:"22"`
+}
+
+type agentUnlockMsg struct {
+ Passphrase []byte `sshtype:"23"`
+}
+
+func (s *server) processRequest(data []byte) (interface{}, error) {
+ switch data[0] {
+ case agentRequestV1Identities:
+ return &agentV1IdentityMsg{0}, nil
+
+ case agentRemoveAllV1Identities:
+ return nil, nil
+
+ case agentRemoveIdentity:
+ var req agentRemoveIdentityMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+
+ var wk wireKey
+ if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
+ return nil, err
+ }
+
+ return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob})
+
+ case agentRemoveAllIdentities:
+ return nil, s.agent.RemoveAll()
+
+ case agentLock:
+ var req agentLockMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+
+ return nil, s.agent.Lock(req.Passphrase)
+
+ case agentUnlock:
+ var req agentLockMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+ return nil, s.agent.Unlock(req.Passphrase)
+
+ case agentSignRequest:
+ var req signRequestAgentMsg
+ if err := ssh.Unmarshal(data, &req); err != nil {
+ return nil, err
+ }
+
+ var wk wireKey
+ if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil {
+ return nil, err
+ }
+
+ k := &Key{
+ Format: wk.Format,
+ Blob: req.KeyBlob,
+ }
+
+ sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags.
+ if err != nil {
+ return nil, err
+ }
+ return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil
+
+ case agentRequestIdentities:
+ keys, err := s.agent.List()
+ if err != nil {
+ return nil, err
+ }
+
+ rep := identitiesAnswerAgentMsg{
+ NumKeys: uint32(len(keys)),
+ }
+ for _, k := range keys {
+ rep.Keys = append(rep.Keys, marshalKey(k)...)
+ }
+ return rep, nil
+
+ case agentAddIdConstrained, agentAddIdentity:
+ return nil, s.insertIdentity(data)
+ }
+
+ return nil, fmt.Errorf("unknown opcode %d", data[0])
+}
+
+func parseRSAKey(req []byte) (*AddedKey, error) {
+ var k rsaKeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ if k.E.BitLen() > 30 {
+ return nil, errors.New("agent: RSA public exponent too large")
+ }
+ priv := &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ E: int(k.E.Int64()),
+ N: k.N,
+ },
+ D: k.D,
+ Primes: []*big.Int{k.P, k.Q},
+ }
+ priv.Precompute()
+
+ return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
+}
+
+func parseDSAKey(req []byte) (*AddedKey, error) {
+ var k dsaKeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ priv := &dsa.PrivateKey{
+ PublicKey: dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: k.P,
+ Q: k.Q,
+ G: k.G,
+ },
+ Y: k.Y,
+ },
+ X: k.X,
+ }
+
+ return &AddedKey{PrivateKey: priv, Comment: k.Comments}, nil
+}
+
+func unmarshalECDSA(curveName string, keyBytes []byte, privScalar *big.Int) (priv *ecdsa.PrivateKey, err error) {
+ priv = &ecdsa.PrivateKey{
+ D: privScalar,
+ }
+
+ switch curveName {
+ case "nistp256":
+ priv.Curve = elliptic.P256()
+ case "nistp384":
+ priv.Curve = elliptic.P384()
+ case "nistp521":
+ priv.Curve = elliptic.P521()
+ default:
+ return nil, fmt.Errorf("agent: unknown curve %q", curveName)
+ }
+
+ priv.X, priv.Y = elliptic.Unmarshal(priv.Curve, keyBytes)
+ if priv.X == nil || priv.Y == nil {
+ return nil, errors.New("agent: point not on curve")
+ }
+
+ return priv, nil
+}
+
+func parseECDSAKey(req []byte) (*AddedKey, error) {
+ var k ecdsaKeyMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+
+ priv, err := unmarshalECDSA(k.Curve, k.KeyBytes, k.D)
+ if err != nil {
+ return nil, err
+ }
+
+ return &AddedKey{PrivateKey: &priv, Comment: k.Comments}, nil
+}
+
+func parseRSACert(req []byte) (*AddedKey, error) {
+ var k rsaCertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad RSA certificate")
+ }
+
+ // An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go
+ var rsaPub struct {
+ Name string
+ E *big.Int
+ N *big.Int
+ }
+ if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil {
+ return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
+ }
+
+ if rsaPub.E.BitLen() > 30 {
+ return nil, errors.New("agent: RSA public exponent too large")
+ }
+
+ priv := rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ E: int(rsaPub.E.Int64()),
+ N: rsaPub.N,
+ },
+ D: k.D,
+ Primes: []*big.Int{k.Q, k.P},
+ }
+ priv.Precompute()
+
+ return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil
+}
+
+func parseDSACert(req []byte) (*AddedKey, error) {
+ var k dsaCertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad DSA certificate")
+ }
+
+ // A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go
+ var w struct {
+ Name string
+ P, Q, G, Y *big.Int
+ }
+ if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil {
+ return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
+ }
+
+ priv := &dsa.PrivateKey{
+ PublicKey: dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: w.P,
+ Q: w.Q,
+ G: w.G,
+ },
+ Y: w.Y,
+ },
+ X: k.X,
+ }
+
+ return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil
+}
+
+func parseECDSACert(req []byte) (*AddedKey, error) {
+ var k ecdsaCertMsg
+ if err := ssh.Unmarshal(req, &k); err != nil {
+ return nil, err
+ }
+
+ pubKey, err := ssh.ParsePublicKey(k.CertBytes)
+ if err != nil {
+ return nil, err
+ }
+ cert, ok := pubKey.(*ssh.Certificate)
+ if !ok {
+ return nil, errors.New("agent: bad ECDSA certificate")
+ }
+
+ // An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go
+ var ecdsaPub struct {
+ Name string
+ ID string
+ Key []byte
+ }
+ if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil {
+ return nil, err
+ }
+
+ priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D)
+ if err != nil {
+ return nil, err
+ }
+
+ return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil
+}
+
+func (s *server) insertIdentity(req []byte) error {
+ var record struct {
+ Type string `sshtype:"17|25"`
+ Rest []byte `ssh:"rest"`
+ }
+
+ if err := ssh.Unmarshal(req, &record); err != nil {
+ return err
+ }
+
+ var addedKey *AddedKey
+ var err error
+
+ switch record.Type {
+ case ssh.KeyAlgoRSA:
+ addedKey, err = parseRSAKey(req)
+ case ssh.KeyAlgoDSA:
+ addedKey, err = parseDSAKey(req)
+ case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
+ addedKey, err = parseECDSACert(req)
+ case ssh.CertAlgoRSAv01:
+ addedKey, err = parseRSACert(req)
+ case ssh.CertAlgoDSAv01:
+ addedKey, err = parseDSACert(req)
+ case ssh.CertAlgoECDSA256v01, ssh.CertAlgoECDSA384v01, ssh.CertAlgoECDSA521v01:
+ addedKey, err = parseECDSACert(req)
+ default:
+ return fmt.Errorf("agent: not implemented: %q", record.Type)
+ }
+
+ if err != nil {
+ return err
+ }
+ return s.agent.Add(*addedKey)
+}
+
+// ServeAgent serves the agent protocol on the given connection. It
+// returns when an I/O error occurs.
+func ServeAgent(agent Agent, c io.ReadWriter) error {
+ s := &server{agent}
+
+ var length [4]byte
+ for {
+ if _, err := io.ReadFull(c, length[:]); err != nil {
+ return err
+ }
+ l := binary.BigEndian.Uint32(length[:])
+ if l > maxAgentResponseBytes {
+ // We also cap requests.
+ return fmt.Errorf("agent: request too large: %d", l)
+ }
+
+ req := make([]byte, l)
+ if _, err := io.ReadFull(c, req); err != nil {
+ return err
+ }
+
+ repData := s.processRequestBytes(req)
+ if len(repData) > maxAgentResponseBytes {
+ return fmt.Errorf("agent: reply too large: %d bytes", len(repData))
+ }
+
+ binary.BigEndian.PutUint32(length[:], uint32(len(repData)))
+ if _, err := c.Write(length[:]); err != nil {
+ return err
+ }
+ if _, err := c.Write(repData); err != nil {
+ return err
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/server_test.go b/vendor/golang.org/x/crypto/ssh/agent/server_test.go
new file mode 100644
index 000000000..c324d6c5a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/server_test.go
@@ -0,0 +1,186 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package agent
+
+import (
+ "crypto"
+ "crypto/rand"
+ "fmt"
+ "testing"
+
+ "golang.org/x/crypto/ssh"
+)
+
+func TestServer(t *testing.T) {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+ client := NewClient(c1)
+
+ go ServeAgent(NewKeyring(), c2)
+
+ testAgentInterface(t, client, testPrivateKeys["rsa"], nil, 0)
+}
+
+func TestLockServer(t *testing.T) {
+ testLockAgent(NewKeyring(), t)
+}
+
+func TestSetupForwardAgent(t *testing.T) {
+ a, b, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+
+ defer a.Close()
+ defer b.Close()
+
+ _, socket, cleanup := startAgent(t)
+ defer cleanup()
+
+ serverConf := ssh.ServerConfig{
+ NoClientAuth: true,
+ }
+ serverConf.AddHostKey(testSigners["rsa"])
+ incoming := make(chan *ssh.ServerConn, 1)
+ go func() {
+ conn, _, _, err := ssh.NewServerConn(a, &serverConf)
+ if err != nil {
+ t.Fatalf("Server: %v", err)
+ }
+ incoming <- conn
+ }()
+
+ conf := ssh.ClientConfig{}
+ conn, chans, reqs, err := ssh.NewClientConn(b, "", &conf)
+ if err != nil {
+ t.Fatalf("NewClientConn: %v", err)
+ }
+ client := ssh.NewClient(conn, chans, reqs)
+
+ if err := ForwardToRemote(client, socket); err != nil {
+ t.Fatalf("SetupForwardAgent: %v", err)
+ }
+
+ server := <-incoming
+ ch, reqs, err := server.OpenChannel(channelType, nil)
+ if err != nil {
+ t.Fatalf("OpenChannel(%q): %v", channelType, err)
+ }
+ go ssh.DiscardRequests(reqs)
+
+ agentClient := NewClient(ch)
+ testAgentInterface(t, agentClient, testPrivateKeys["rsa"], nil, 0)
+ conn.Close()
+}
+
+func TestV1ProtocolMessages(t *testing.T) {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+ c := NewClient(c1)
+
+ go ServeAgent(NewKeyring(), c2)
+
+ testV1ProtocolMessages(t, c.(*client))
+}
+
+func testV1ProtocolMessages(t *testing.T, c *client) {
+ reply, err := c.call([]byte{agentRequestV1Identities})
+ if err != nil {
+ t.Fatalf("v1 request all failed: %v", err)
+ }
+ if msg, ok := reply.(*agentV1IdentityMsg); !ok || msg.Numkeys != 0 {
+ t.Fatalf("invalid request all response: %#v", reply)
+ }
+
+ reply, err = c.call([]byte{agentRemoveAllV1Identities})
+ if err != nil {
+ t.Fatalf("v1 remove all failed: %v", err)
+ }
+ if _, ok := reply.(*successAgentMsg); !ok {
+ t.Fatalf("invalid remove all response: %#v", reply)
+ }
+}
+
+func verifyKey(sshAgent Agent) error {
+ keys, err := sshAgent.List()
+ if err != nil {
+ return fmt.Errorf("listing keys: %v", err)
+ }
+
+ if len(keys) != 1 {
+ return fmt.Errorf("bad number of keys found. expected 1, got %d", len(keys))
+ }
+
+ buf := make([]byte, 128)
+ if _, err := rand.Read(buf); err != nil {
+ return fmt.Errorf("rand: %v", err)
+ }
+
+ sig, err := sshAgent.Sign(keys[0], buf)
+ if err != nil {
+ return fmt.Errorf("sign: %v", err)
+ }
+
+ if err := keys[0].Verify(buf, sig); err != nil {
+ return fmt.Errorf("verify: %v", err)
+ }
+ return nil
+}
+
+func addKeyToAgent(key crypto.PrivateKey) error {
+ sshAgent := NewKeyring()
+ if err := sshAgent.Add(AddedKey{PrivateKey: key}); err != nil {
+ return fmt.Errorf("add: %v", err)
+ }
+ return verifyKey(sshAgent)
+}
+
+func TestKeyTypes(t *testing.T) {
+ for k, v := range testPrivateKeys {
+ if err := addKeyToAgent(v); err != nil {
+ t.Errorf("error adding key type %s, %v", k, err)
+ }
+ }
+}
+
+func addCertToAgent(key crypto.PrivateKey, cert *ssh.Certificate) error {
+ sshAgent := NewKeyring()
+ if err := sshAgent.Add(AddedKey{PrivateKey: key, Certificate: cert}); err != nil {
+ return fmt.Errorf("add: %v", err)
+ }
+ return verifyKey(sshAgent)
+}
+
+func TestCertTypes(t *testing.T) {
+ for keyType, key := range testPublicKeys {
+ cert := &ssh.Certificate{
+ ValidPrincipals: []string{"gopher1"},
+ ValidAfter: 0,
+ ValidBefore: ssh.CertTimeInfinity,
+ Key: key,
+ Serial: 1,
+ CertType: ssh.UserCert,
+ SignatureKey: testPublicKeys["rsa"],
+ Permissions: ssh.Permissions{
+ CriticalOptions: map[string]string{},
+ Extensions: map[string]string{},
+ },
+ }
+ if err := cert.SignCert(rand.Reader, testSigners["rsa"]); err != nil {
+ t.Fatalf("signcert: %v", err)
+ }
+ if err := addCertToAgent(testPrivateKeys[keyType], cert); err != nil {
+ t.Fatalf("%v", err)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/agent/testdata_test.go b/vendor/golang.org/x/crypto/ssh/agent/testdata_test.go
new file mode 100644
index 000000000..b7a8781e1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/agent/testdata_test.go
@@ -0,0 +1,64 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places:
+// ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three
+// instances.
+
+package agent
+
+import (
+ "crypto/rand"
+ "fmt"
+
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/testdata"
+)
+
+var (
+ testPrivateKeys map[string]interface{}
+ testSigners map[string]ssh.Signer
+ testPublicKeys map[string]ssh.PublicKey
+)
+
+func init() {
+ var err error
+
+ n := len(testdata.PEMBytes)
+ testPrivateKeys = make(map[string]interface{}, n)
+ testSigners = make(map[string]ssh.Signer, n)
+ testPublicKeys = make(map[string]ssh.PublicKey, n)
+ for t, k := range testdata.PEMBytes {
+ testPrivateKeys[t], err = ssh.ParseRawPrivateKey(k)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err))
+ }
+ testSigners[t], err = ssh.NewSignerFromKey(testPrivateKeys[t])
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err))
+ }
+ testPublicKeys[t] = testSigners[t].PublicKey()
+ }
+
+ // Create a cert and sign it for use in tests.
+ testCert := &ssh.Certificate{
+ Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
+ ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage
+ ValidAfter: 0, // unix epoch
+ ValidBefore: ssh.CertTimeInfinity, // The end of currently representable time.
+ Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
+ Key: testPublicKeys["ecdsa"],
+ SignatureKey: testPublicKeys["rsa"],
+ Permissions: ssh.Permissions{
+ CriticalOptions: map[string]string{},
+ Extensions: map[string]string{},
+ },
+ }
+ testCert.SignCert(rand.Reader, testSigners["rsa"])
+ testPrivateKeys["cert"] = testPrivateKeys["ecdsa"]
+ testSigners["cert"], err = ssh.NewCertSigner(testCert, testSigners["ecdsa"])
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create certificate signer: %v", err))
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/benchmark_test.go b/vendor/golang.org/x/crypto/ssh/benchmark_test.go
new file mode 100644
index 000000000..d9f7eb9b6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/benchmark_test.go
@@ -0,0 +1,122 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "errors"
+ "io"
+ "net"
+ "testing"
+)
+
+type server struct {
+ *ServerConn
+ chans <-chan NewChannel
+}
+
+func newServer(c net.Conn, conf *ServerConfig) (*server, error) {
+ sconn, chans, reqs, err := NewServerConn(c, conf)
+ if err != nil {
+ return nil, err
+ }
+ go DiscardRequests(reqs)
+ return &server{sconn, chans}, nil
+}
+
+func (s *server) Accept() (NewChannel, error) {
+ n, ok := <-s.chans
+ if !ok {
+ return nil, io.EOF
+ }
+ return n, nil
+}
+
+func sshPipe() (Conn, *server, error) {
+ c1, c2, err := netPipe()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ clientConf := ClientConfig{
+ User: "user",
+ }
+ serverConf := ServerConfig{
+ NoClientAuth: true,
+ }
+ serverConf.AddHostKey(testSigners["ecdsa"])
+ done := make(chan *server, 1)
+ go func() {
+ server, err := newServer(c2, &serverConf)
+ if err != nil {
+ done <- nil
+ }
+ done <- server
+ }()
+
+ client, _, reqs, err := NewClientConn(c1, "", &clientConf)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ server := <-done
+ if server == nil {
+ return nil, nil, errors.New("server handshake failed.")
+ }
+ go DiscardRequests(reqs)
+
+ return client, server, nil
+}
+
+func BenchmarkEndToEnd(b *testing.B) {
+ b.StopTimer()
+
+ client, server, err := sshPipe()
+ if err != nil {
+ b.Fatalf("sshPipe: %v", err)
+ }
+
+ defer client.Close()
+ defer server.Close()
+
+ size := (1 << 20)
+ input := make([]byte, size)
+ output := make([]byte, size)
+ b.SetBytes(int64(size))
+ done := make(chan int, 1)
+
+ go func() {
+ newCh, err := server.Accept()
+ if err != nil {
+ b.Fatalf("Client: %v", err)
+ }
+ ch, incoming, err := newCh.Accept()
+ go DiscardRequests(incoming)
+ for i := 0; i < b.N; i++ {
+ if _, err := io.ReadFull(ch, output); err != nil {
+ b.Fatalf("ReadFull: %v", err)
+ }
+ }
+ ch.Close()
+ done <- 1
+ }()
+
+ ch, in, err := client.OpenChannel("speed", nil)
+ if err != nil {
+ b.Fatalf("OpenChannel: %v", err)
+ }
+ go DiscardRequests(in)
+
+ b.ResetTimer()
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ if _, err := ch.Write(input); err != nil {
+ b.Fatalf("WriteFull: %v", err)
+ }
+ }
+ ch.Close()
+ b.StopTimer()
+
+ <-done
+}
diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go
new file mode 100644
index 000000000..6931b5114
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/buffer.go
@@ -0,0 +1,98 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "io"
+ "sync"
+)
+
+// buffer provides a linked list buffer for data exchange
+// between producer and consumer. Theoretically the buffer is
+// of unlimited capacity as it does no allocation of its own.
+type buffer struct {
+ // protects concurrent access to head, tail and closed
+ *sync.Cond
+
+ head *element // the buffer that will be read first
+ tail *element // the buffer that will be read last
+
+ closed bool
+}
+
+// An element represents a single link in a linked list.
+type element struct {
+ buf []byte
+ next *element
+}
+
+// newBuffer returns an empty buffer that is not closed.
+func newBuffer() *buffer {
+ e := new(element)
+ b := &buffer{
+ Cond: newCond(),
+ head: e,
+ tail: e,
+ }
+ return b
+}
+
+// write makes buf available for Read to receive.
+// buf must not be modified after the call to write.
+func (b *buffer) write(buf []byte) {
+ b.Cond.L.Lock()
+ e := &element{buf: buf}
+ b.tail.next = e
+ b.tail = e
+ b.Cond.Signal()
+ b.Cond.L.Unlock()
+}
+
+// eof closes the buffer. Reads from the buffer once all
+// the data has been consumed will receive os.EOF.
+func (b *buffer) eof() error {
+ b.Cond.L.Lock()
+ b.closed = true
+ b.Cond.Signal()
+ b.Cond.L.Unlock()
+ return nil
+}
+
+// Read reads data from the internal buffer in buf. Reads will block
+// if no data is available, or until the buffer is closed.
+func (b *buffer) Read(buf []byte) (n int, err error) {
+ b.Cond.L.Lock()
+ defer b.Cond.L.Unlock()
+
+ for len(buf) > 0 {
+ // if there is data in b.head, copy it
+ if len(b.head.buf) > 0 {
+ r := copy(buf, b.head.buf)
+ buf, b.head.buf = buf[r:], b.head.buf[r:]
+ n += r
+ continue
+ }
+ // if there is a next buffer, make it the head
+ if len(b.head.buf) == 0 && b.head != b.tail {
+ b.head = b.head.next
+ continue
+ }
+
+ // if at least one byte has been copied, return
+ if n > 0 {
+ break
+ }
+
+ // if nothing was read, and there is nothing outstanding
+ // check to see if the buffer is closed.
+ if b.closed {
+ err = io.EOF
+ break
+ }
+ // out of buffers, wait for producer
+ b.Cond.Wait()
+ }
+ return
+}
diff --git a/vendor/golang.org/x/crypto/ssh/buffer_test.go b/vendor/golang.org/x/crypto/ssh/buffer_test.go
new file mode 100644
index 000000000..d5781cb3d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/buffer_test.go
@@ -0,0 +1,87 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "io"
+ "testing"
+)
+
+var alphabet = []byte("abcdefghijklmnopqrstuvwxyz")
+
+func TestBufferReadwrite(t *testing.T) {
+ b := newBuffer()
+ b.write(alphabet[:10])
+ r, _ := b.Read(make([]byte, 10))
+ if r != 10 {
+ t.Fatalf("Expected written == read == 10, written: 10, read %d", r)
+ }
+
+ b = newBuffer()
+ b.write(alphabet[:5])
+ r, _ = b.Read(make([]byte, 10))
+ if r != 5 {
+ t.Fatalf("Expected written == read == 5, written: 5, read %d", r)
+ }
+
+ b = newBuffer()
+ b.write(alphabet[:10])
+ r, _ = b.Read(make([]byte, 5))
+ if r != 5 {
+ t.Fatalf("Expected written == 10, read == 5, written: 10, read %d", r)
+ }
+
+ b = newBuffer()
+ b.write(alphabet[:5])
+ b.write(alphabet[5:15])
+ r, _ = b.Read(make([]byte, 10))
+ r2, _ := b.Read(make([]byte, 10))
+ if r != 10 || r2 != 5 || 15 != r+r2 {
+ t.Fatal("Expected written == read == 15")
+ }
+}
+
+func TestBufferClose(t *testing.T) {
+ b := newBuffer()
+ b.write(alphabet[:10])
+ b.eof()
+ _, err := b.Read(make([]byte, 5))
+ if err != nil {
+ t.Fatal("expected read of 5 to not return EOF")
+ }
+ b = newBuffer()
+ b.write(alphabet[:10])
+ b.eof()
+ r, err := b.Read(make([]byte, 5))
+ r2, err2 := b.Read(make([]byte, 10))
+ if r != 5 || r2 != 5 || err != nil || err2 != nil {
+ t.Fatal("expected reads of 5 and 5")
+ }
+
+ b = newBuffer()
+ b.write(alphabet[:10])
+ b.eof()
+ r, err = b.Read(make([]byte, 5))
+ r2, err2 = b.Read(make([]byte, 10))
+ r3, err3 := b.Read(make([]byte, 10))
+ if r != 5 || r2 != 5 || r3 != 0 || err != nil || err2 != nil || err3 != io.EOF {
+ t.Fatal("expected reads of 5 and 5 and 0, with EOF")
+ }
+
+ b = newBuffer()
+ b.write(make([]byte, 5))
+ b.write(make([]byte, 10))
+ b.eof()
+ r, err = b.Read(make([]byte, 9))
+ r2, err2 = b.Read(make([]byte, 3))
+ r3, err3 = b.Read(make([]byte, 3))
+ r4, err4 := b.Read(make([]byte, 10))
+ if err != nil || err2 != nil || err3 != nil || err4 != io.EOF {
+ t.Fatalf("Expected EOF on forth read only, err=%v, err2=%v, err3=%v, err4=%v", err, err2, err3, err4)
+ }
+ if r != 9 || r2 != 3 || r3 != 3 || r4 != 0 {
+ t.Fatal("Expected written == read == 15", r, r2, r3, r4)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go
new file mode 100644
index 000000000..6331c94d5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/certs.go
@@ -0,0 +1,503 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "sort"
+ "time"
+)
+
+// These constants from [PROTOCOL.certkeys] represent the algorithm names
+// for certificate types supported by this package.
+const (
+ CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com"
+ CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com"
+ CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
+ CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
+ CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
+ CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com"
+)
+
+// Certificate types distinguish between host and user
+// certificates. The values can be set in the CertType field of
+// Certificate.
+const (
+ UserCert = 1
+ HostCert = 2
+)
+
+// Signature represents a cryptographic signature.
+type Signature struct {
+ Format string
+ Blob []byte
+}
+
+// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
+// a certificate does not expire.
+const CertTimeInfinity = 1<<64 - 1
+
+// An Certificate represents an OpenSSH certificate as defined in
+// [PROTOCOL.certkeys]?rev=1.8.
+type Certificate struct {
+ Nonce []byte
+ Key PublicKey
+ Serial uint64
+ CertType uint32
+ KeyId string
+ ValidPrincipals []string
+ ValidAfter uint64
+ ValidBefore uint64
+ Permissions
+ Reserved []byte
+ SignatureKey PublicKey
+ Signature *Signature
+}
+
+// genericCertData holds the key-independent part of the certificate data.
+// Overall, certificates contain an nonce, public key fields and
+// key-independent fields.
+type genericCertData struct {
+ Serial uint64
+ CertType uint32
+ KeyId string
+ ValidPrincipals []byte
+ ValidAfter uint64
+ ValidBefore uint64
+ CriticalOptions []byte
+ Extensions []byte
+ Reserved []byte
+ SignatureKey []byte
+ Signature []byte
+}
+
+func marshalStringList(namelist []string) []byte {
+ var to []byte
+ for _, name := range namelist {
+ s := struct{ N string }{name}
+ to = append(to, Marshal(&s)...)
+ }
+ return to
+}
+
+type optionsTuple struct {
+ Key string
+ Value []byte
+}
+
+type optionsTupleValue struct {
+ Value string
+}
+
+// serialize a map of critical options or extensions
+// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
+// we need two length prefixes for a non-empty string value
+func marshalTuples(tups map[string]string) []byte {
+ keys := make([]string, 0, len(tups))
+ for key := range tups {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+
+ var ret []byte
+ for _, key := range keys {
+ s := optionsTuple{Key: key}
+ if value := tups[key]; len(value) > 0 {
+ s.Value = Marshal(&optionsTupleValue{value})
+ }
+ ret = append(ret, Marshal(&s)...)
+ }
+ return ret
+}
+
+// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
+// we need two length prefixes for a non-empty option value
+func parseTuples(in []byte) (map[string]string, error) {
+ tups := map[string]string{}
+ var lastKey string
+ var haveLastKey bool
+
+ for len(in) > 0 {
+ var key, val, extra []byte
+ var ok bool
+
+ if key, in, ok = parseString(in); !ok {
+ return nil, errShortRead
+ }
+ keyStr := string(key)
+ // according to [PROTOCOL.certkeys], the names must be in
+ // lexical order.
+ if haveLastKey && keyStr <= lastKey {
+ return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
+ }
+ lastKey, haveLastKey = keyStr, true
+ // the next field is a data field, which if non-empty has a string embedded
+ if val, in, ok = parseString(in); !ok {
+ return nil, errShortRead
+ }
+ if len(val) > 0 {
+ val, extra, ok = parseString(val)
+ if !ok {
+ return nil, errShortRead
+ }
+ if len(extra) > 0 {
+ return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
+ }
+ tups[keyStr] = string(val)
+ } else {
+ tups[keyStr] = ""
+ }
+ }
+ return tups, nil
+}
+
+func parseCert(in []byte, privAlgo string) (*Certificate, error) {
+ nonce, rest, ok := parseString(in)
+ if !ok {
+ return nil, errShortRead
+ }
+
+ key, rest, err := parsePubKey(rest, privAlgo)
+ if err != nil {
+ return nil, err
+ }
+
+ var g genericCertData
+ if err := Unmarshal(rest, &g); err != nil {
+ return nil, err
+ }
+
+ c := &Certificate{
+ Nonce: nonce,
+ Key: key,
+ Serial: g.Serial,
+ CertType: g.CertType,
+ KeyId: g.KeyId,
+ ValidAfter: g.ValidAfter,
+ ValidBefore: g.ValidBefore,
+ }
+
+ for principals := g.ValidPrincipals; len(principals) > 0; {
+ principal, rest, ok := parseString(principals)
+ if !ok {
+ return nil, errShortRead
+ }
+ c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
+ principals = rest
+ }
+
+ c.CriticalOptions, err = parseTuples(g.CriticalOptions)
+ if err != nil {
+ return nil, err
+ }
+ c.Extensions, err = parseTuples(g.Extensions)
+ if err != nil {
+ return nil, err
+ }
+ c.Reserved = g.Reserved
+ k, err := ParsePublicKey(g.SignatureKey)
+ if err != nil {
+ return nil, err
+ }
+
+ c.SignatureKey = k
+ c.Signature, rest, ok = parseSignatureBody(g.Signature)
+ if !ok || len(rest) > 0 {
+ return nil, errors.New("ssh: signature parse error")
+ }
+
+ return c, nil
+}
+
+type openSSHCertSigner struct {
+ pub *Certificate
+ signer Signer
+}
+
+// NewCertSigner returns a Signer that signs with the given Certificate, whose
+// private key is held by signer. It returns an error if the public key in cert
+// doesn't match the key used by signer.
+func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
+ if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
+ return nil, errors.New("ssh: signer and cert have different public key")
+ }
+
+ return &openSSHCertSigner{cert, signer}, nil
+}
+
+func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
+ return s.signer.Sign(rand, data)
+}
+
+func (s *openSSHCertSigner) PublicKey() PublicKey {
+ return s.pub
+}
+
+const sourceAddressCriticalOption = "source-address"
+
+// CertChecker does the work of verifying a certificate. Its methods
+// can be plugged into ClientConfig.HostKeyCallback and
+// ServerConfig.PublicKeyCallback. For the CertChecker to work,
+// minimally, the IsAuthority callback should be set.
+type CertChecker struct {
+ // SupportedCriticalOptions lists the CriticalOptions that the
+ // server application layer understands. These are only used
+ // for user certificates.
+ SupportedCriticalOptions []string
+
+ // IsAuthority should return true if the key is recognized as
+ // an authority. This allows for certificates to be signed by other
+ // certificates.
+ IsAuthority func(auth PublicKey) bool
+
+ // Clock is used for verifying time stamps. If nil, time.Now
+ // is used.
+ Clock func() time.Time
+
+ // UserKeyFallback is called when CertChecker.Authenticate encounters a
+ // public key that is not a certificate. It must implement validation
+ // of user keys or else, if nil, all such keys are rejected.
+ UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
+
+ // HostKeyFallback is called when CertChecker.CheckHostKey encounters a
+ // public key that is not a certificate. It must implement host key
+ // validation or else, if nil, all such keys are rejected.
+ HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error
+
+ // IsRevoked is called for each certificate so that revocation checking
+ // can be implemented. It should return true if the given certificate
+ // is revoked and false otherwise. If nil, no certificates are
+ // considered to have been revoked.
+ IsRevoked func(cert *Certificate) bool
+}
+
+// CheckHostKey checks a host key certificate. This method can be
+// plugged into ClientConfig.HostKeyCallback.
+func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
+ cert, ok := key.(*Certificate)
+ if !ok {
+ if c.HostKeyFallback != nil {
+ return c.HostKeyFallback(addr, remote, key)
+ }
+ return errors.New("ssh: non-certificate host key")
+ }
+ if cert.CertType != HostCert {
+ return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
+ }
+
+ return c.CheckCert(addr, cert)
+}
+
+// Authenticate checks a user certificate. Authenticate can be used as
+// a value for ServerConfig.PublicKeyCallback.
+func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
+ cert, ok := pubKey.(*Certificate)
+ if !ok {
+ if c.UserKeyFallback != nil {
+ return c.UserKeyFallback(conn, pubKey)
+ }
+ return nil, errors.New("ssh: normal key pairs not accepted")
+ }
+
+ if cert.CertType != UserCert {
+ return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
+ }
+
+ if err := c.CheckCert(conn.User(), cert); err != nil {
+ return nil, err
+ }
+
+ return &cert.Permissions, nil
+}
+
+// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
+// the signature of the certificate.
+func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
+ if c.IsRevoked != nil && c.IsRevoked(cert) {
+ return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial)
+ }
+
+ for opt, _ := range cert.CriticalOptions {
+ // sourceAddressCriticalOption will be enforced by
+ // serverAuthenticate
+ if opt == sourceAddressCriticalOption {
+ continue
+ }
+
+ found := false
+ for _, supp := range c.SupportedCriticalOptions {
+ if supp == opt {
+ found = true
+ break
+ }
+ }
+ if !found {
+ return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
+ }
+ }
+
+ if len(cert.ValidPrincipals) > 0 {
+ // By default, certs are valid for all users/hosts.
+ found := false
+ for _, p := range cert.ValidPrincipals {
+ if p == principal {
+ found = true
+ break
+ }
+ }
+ if !found {
+ return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
+ }
+ }
+
+ if !c.IsAuthority(cert.SignatureKey) {
+ return fmt.Errorf("ssh: certificate signed by unrecognized authority")
+ }
+
+ clock := c.Clock
+ if clock == nil {
+ clock = time.Now
+ }
+
+ unixNow := clock().Unix()
+ if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
+ return fmt.Errorf("ssh: cert is not yet valid")
+ }
+ if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
+ return fmt.Errorf("ssh: cert has expired")
+ }
+ if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
+ return fmt.Errorf("ssh: certificate signature does not verify")
+ }
+
+ return nil
+}
+
+// SignCert sets c.SignatureKey to the authority's public key and stores a
+// Signature, by authority, in the certificate.
+func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
+ c.Nonce = make([]byte, 32)
+ if _, err := io.ReadFull(rand, c.Nonce); err != nil {
+ return err
+ }
+ c.SignatureKey = authority.PublicKey()
+
+ sig, err := authority.Sign(rand, c.bytesForSigning())
+ if err != nil {
+ return err
+ }
+ c.Signature = sig
+ return nil
+}
+
+var certAlgoNames = map[string]string{
+ KeyAlgoRSA: CertAlgoRSAv01,
+ KeyAlgoDSA: CertAlgoDSAv01,
+ KeyAlgoECDSA256: CertAlgoECDSA256v01,
+ KeyAlgoECDSA384: CertAlgoECDSA384v01,
+ KeyAlgoECDSA521: CertAlgoECDSA521v01,
+ KeyAlgoED25519: CertAlgoED25519v01,
+}
+
+// certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
+// Panics if a non-certificate algorithm is passed.
+func certToPrivAlgo(algo string) string {
+ for privAlgo, pubAlgo := range certAlgoNames {
+ if pubAlgo == algo {
+ return privAlgo
+ }
+ }
+ panic("unknown cert algorithm")
+}
+
+func (cert *Certificate) bytesForSigning() []byte {
+ c2 := *cert
+ c2.Signature = nil
+ out := c2.Marshal()
+ // Drop trailing signature length.
+ return out[:len(out)-4]
+}
+
+// Marshal serializes c into OpenSSH's wire format. It is part of the
+// PublicKey interface.
+func (c *Certificate) Marshal() []byte {
+ generic := genericCertData{
+ Serial: c.Serial,
+ CertType: c.CertType,
+ KeyId: c.KeyId,
+ ValidPrincipals: marshalStringList(c.ValidPrincipals),
+ ValidAfter: uint64(c.ValidAfter),
+ ValidBefore: uint64(c.ValidBefore),
+ CriticalOptions: marshalTuples(c.CriticalOptions),
+ Extensions: marshalTuples(c.Extensions),
+ Reserved: c.Reserved,
+ SignatureKey: c.SignatureKey.Marshal(),
+ }
+ if c.Signature != nil {
+ generic.Signature = Marshal(c.Signature)
+ }
+ genericBytes := Marshal(&generic)
+ keyBytes := c.Key.Marshal()
+ _, keyBytes, _ = parseString(keyBytes)
+ prefix := Marshal(&struct {
+ Name string
+ Nonce []byte
+ Key []byte `ssh:"rest"`
+ }{c.Type(), c.Nonce, keyBytes})
+
+ result := make([]byte, 0, len(prefix)+len(genericBytes))
+ result = append(result, prefix...)
+ result = append(result, genericBytes...)
+ return result
+}
+
+// Type returns the key name. It is part of the PublicKey interface.
+func (c *Certificate) Type() string {
+ algo, ok := certAlgoNames[c.Key.Type()]
+ if !ok {
+ panic("unknown cert key type " + c.Key.Type())
+ }
+ return algo
+}
+
+// Verify verifies a signature against the certificate's public
+// key. It is part of the PublicKey interface.
+func (c *Certificate) Verify(data []byte, sig *Signature) error {
+ return c.Key.Verify(data, sig)
+}
+
+func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
+ format, in, ok := parseString(in)
+ if !ok {
+ return
+ }
+
+ out = &Signature{
+ Format: string(format),
+ }
+
+ if out.Blob, in, ok = parseString(in); !ok {
+ return
+ }
+
+ return out, in, ok
+}
+
+func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
+ sigBytes, rest, ok := parseString(in)
+ if !ok {
+ return
+ }
+
+ out, trailing, ok := parseSignatureBody(sigBytes)
+ if !ok || len(trailing) > 0 {
+ return nil, nil, false
+ }
+ return
+}
diff --git a/vendor/golang.org/x/crypto/ssh/certs_test.go b/vendor/golang.org/x/crypto/ssh/certs_test.go
new file mode 100644
index 000000000..c5f2e5330
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/certs_test.go
@@ -0,0 +1,216 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "crypto/rand"
+ "reflect"
+ "testing"
+ "time"
+)
+
+// Cert generated by ssh-keygen 6.0p1 Debian-4.
+// % ssh-keygen -s ca-key -I test user-key
+const exampleSSHCert = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgb1srW/W3ZDjYAO45xLYAwzHBDLsJ4Ux6ICFIkTjb1LEAAAADAQABAAAAYQCkoR51poH0wE8w72cqSB8Sszx+vAhzcMdCO0wqHTj7UNENHWEXGrU0E0UQekD7U+yhkhtoyjbPOVIP7hNa6aRk/ezdh/iUnCIt4Jt1v3Z1h1P+hA4QuYFMHNB+rmjPwAcAAAAAAAAAAAAAAAEAAAAEdGVzdAAAAAAAAAAAAAAAAP//////////AAAAAAAAAIIAAAAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9yd2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGVybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAAHcAAAAHc3NoLXJzYQAAAAMBAAEAAABhANFS2kaktpSGc+CcmEKPyw9mJC4nZKxHKTgLVZeaGbFZOvJTNzBspQHdy7Q1uKSfktxpgjZnksiu/tFF9ngyY2KFoc+U88ya95IZUycBGCUbBQ8+bhDtw/icdDGQD5WnUwAAAG8AAAAHc3NoLXJzYQAAAGC8Y9Z2LQKhIhxf52773XaWrXdxP0t3GBVo4A10vUWiYoAGepr6rQIoGGXFxT4B9Gp+nEBJjOwKDXPrAevow0T9ca8gZN+0ykbhSrXLE5Ao48rqr3zP4O1/9P7e6gp0gw8=`
+
+func TestParseCert(t *testing.T) {
+ authKeyBytes := []byte(exampleSSHCert)
+
+ key, _, _, rest, err := ParseAuthorizedKey(authKeyBytes)
+ if err != nil {
+ t.Fatalf("ParseAuthorizedKey: %v", err)
+ }
+ if len(rest) > 0 {
+ t.Errorf("rest: got %q, want empty", rest)
+ }
+
+ if _, ok := key.(*Certificate); !ok {
+ t.Fatalf("got %v (%T), want *Certificate", key, key)
+ }
+
+ marshaled := MarshalAuthorizedKey(key)
+ // Before comparison, remove the trailing newline that
+ // MarshalAuthorizedKey adds.
+ marshaled = marshaled[:len(marshaled)-1]
+ if !bytes.Equal(authKeyBytes, marshaled) {
+ t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, authKeyBytes)
+ }
+}
+
+// Cert generated by ssh-keygen OpenSSH_6.8p1 OS X 10.10.3
+// % ssh-keygen -s ca -I testcert -O source-address=192.168.1.0/24 -O force-command=/bin/sleep user.pub
+// user.pub key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDACh1rt2DXfV3hk6fszSQcQ/rueMId0kVD9U7nl8cfEnFxqOCrNT92g4laQIGl2mn8lsGZfTLg8ksHq3gkvgO3oo/0wHy4v32JeBOHTsN5AL4gfHNEhWeWb50ev47hnTsRIt9P4dxogeUo/hTu7j9+s9lLpEQXCvq6xocXQt0j8MV9qZBBXFLXVT3cWIkSqOdwt/5ZBg+1GSrc7WfCXVWgTk4a20uPMuJPxU4RQwZW6X3+O8Pqo8C3cW0OzZRFP6gUYUKUsTI5WntlS+LAxgw1mZNsozFGdbiOPRnEryE3SRldh9vjDR3tin1fGpA5P7+CEB/bqaXtG3V+F2OkqaMN
+// Critical Options:
+// force-command /bin/sleep
+// source-address 192.168.1.0/24
+// Extensions:
+// permit-X11-forwarding
+// permit-agent-forwarding
+// permit-port-forwarding
+// permit-pty
+// permit-user-rc
+const exampleSSHCertWithOptions = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgDyysCJY0XrO1n03EeRRoITnTPdjENFmWDs9X58PP3VUAAAADAQABAAABAQDACh1rt2DXfV3hk6fszSQcQ/rueMId0kVD9U7nl8cfEnFxqOCrNT92g4laQIGl2mn8lsGZfTLg8ksHq3gkvgO3oo/0wHy4v32JeBOHTsN5AL4gfHNEhWeWb50ev47hnTsRIt9P4dxogeUo/hTu7j9+s9lLpEQXCvq6xocXQt0j8MV9qZBBXFLXVT3cWIkSqOdwt/5ZBg+1GSrc7WfCXVWgTk4a20uPMuJPxU4RQwZW6X3+O8Pqo8C3cW0OzZRFP6gUYUKUsTI5WntlS+LAxgw1mZNsozFGdbiOPRnEryE3SRldh9vjDR3tin1fGpA5P7+CEB/bqaXtG3V+F2OkqaMNAAAAAAAAAAAAAAABAAAACHRlc3RjZXJ0AAAAAAAAAAAAAAAA//////////8AAABLAAAADWZvcmNlLWNvbW1hbmQAAAAOAAAACi9iaW4vc2xlZXAAAAAOc291cmNlLWFkZHJlc3MAAAASAAAADjE5Mi4xNjguMS4wLzI0AAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAwU+c5ui5A8+J/CFpjW8wCa52bEODA808WWQDCSuTG/eMXNf59v9Y8Pk0F1E9dGCosSNyVcB/hacUrc6He+i97+HJCyKavBsE6GDxrjRyxYqAlfcOXi/IVmaUGiO8OQ39d4GHrjToInKvExSUeleQyH4Y4/e27T/pILAqPFL3fyrvMLT5qU9QyIt6zIpa7GBP5+urouNavMprV3zsfIqNBbWypinOQAw823a5wN+zwXnhZrgQiHZ/USG09Y6k98y1dTVz8YHlQVR4D3lpTAsKDKJ5hCH9WU4fdf+lU8OyNGaJ/vz0XNqxcToe1l4numLTnaoSuH89pHryjqurB7lJKwAAAQ8AAAAHc3NoLXJzYQAAAQCaHvUIoPL1zWUHIXLvu96/HU1s/i4CAW2IIEuGgxCUCiFj6vyTyYtgxQxcmbfZf6eaITlS6XJZa7Qq4iaFZh75C1DXTX8labXhRSD4E2t//AIP9MC1rtQC5xo6FmbQ+BoKcDskr+mNACcbRSxs3IL3bwCfWDnIw2WbVox9ZdcthJKk4UoCW4ix4QwdHw7zlddlz++fGEEVhmTbll1SUkycGApPFBsAYRTMupUJcYPIeReBI/m8XfkoMk99bV8ZJQTAd7OekHY2/48Ff53jLmyDjP7kNw1F8OaPtkFs6dGJXta4krmaekPy87j+35In5hFj7yoOqvSbmYUkeX70/GGQ`
+
+func TestParseCertWithOptions(t *testing.T) {
+ opts := map[string]string{
+ "source-address": "192.168.1.0/24",
+ "force-command": "/bin/sleep",
+ }
+ exts := map[string]string{
+ "permit-X11-forwarding": "",
+ "permit-agent-forwarding": "",
+ "permit-port-forwarding": "",
+ "permit-pty": "",
+ "permit-user-rc": "",
+ }
+ authKeyBytes := []byte(exampleSSHCertWithOptions)
+
+ key, _, _, rest, err := ParseAuthorizedKey(authKeyBytes)
+ if err != nil {
+ t.Fatalf("ParseAuthorizedKey: %v", err)
+ }
+ if len(rest) > 0 {
+ t.Errorf("rest: got %q, want empty", rest)
+ }
+ cert, ok := key.(*Certificate)
+ if !ok {
+ t.Fatalf("got %v (%T), want *Certificate", key, key)
+ }
+ if !reflect.DeepEqual(cert.CriticalOptions, opts) {
+ t.Errorf("unexpected critical options - got %v, want %v", cert.CriticalOptions, opts)
+ }
+ if !reflect.DeepEqual(cert.Extensions, exts) {
+ t.Errorf("unexpected Extensions - got %v, want %v", cert.Extensions, exts)
+ }
+ marshaled := MarshalAuthorizedKey(key)
+ // Before comparison, remove the trailing newline that
+ // MarshalAuthorizedKey adds.
+ marshaled = marshaled[:len(marshaled)-1]
+ if !bytes.Equal(authKeyBytes, marshaled) {
+ t.Errorf("marshaled certificate does not match original: got %q, want %q", marshaled, authKeyBytes)
+ }
+}
+
+func TestValidateCert(t *testing.T) {
+ key, _, _, _, err := ParseAuthorizedKey([]byte(exampleSSHCert))
+ if err != nil {
+ t.Fatalf("ParseAuthorizedKey: %v", err)
+ }
+ validCert, ok := key.(*Certificate)
+ if !ok {
+ t.Fatalf("got %v (%T), want *Certificate", key, key)
+ }
+ checker := CertChecker{}
+ checker.IsAuthority = func(k PublicKey) bool {
+ return bytes.Equal(k.Marshal(), validCert.SignatureKey.Marshal())
+ }
+
+ if err := checker.CheckCert("user", validCert); err != nil {
+ t.Errorf("Unable to validate certificate: %v", err)
+ }
+ invalidCert := &Certificate{
+ Key: testPublicKeys["rsa"],
+ SignatureKey: testPublicKeys["ecdsa"],
+ ValidBefore: CertTimeInfinity,
+ Signature: &Signature{},
+ }
+ if err := checker.CheckCert("user", invalidCert); err == nil {
+ t.Error("Invalid cert signature passed validation")
+ }
+}
+
+func TestValidateCertTime(t *testing.T) {
+ cert := Certificate{
+ ValidPrincipals: []string{"user"},
+ Key: testPublicKeys["rsa"],
+ ValidAfter: 50,
+ ValidBefore: 100,
+ }
+
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+
+ for ts, ok := range map[int64]bool{
+ 25: false,
+ 50: true,
+ 99: true,
+ 100: false,
+ 125: false,
+ } {
+ checker := CertChecker{
+ Clock: func() time.Time { return time.Unix(ts, 0) },
+ }
+ checker.IsAuthority = func(k PublicKey) bool {
+ return bytes.Equal(k.Marshal(),
+ testPublicKeys["ecdsa"].Marshal())
+ }
+
+ if v := checker.CheckCert("user", &cert); (v == nil) != ok {
+ t.Errorf("Authenticate(%d): %v", ts, v)
+ }
+ }
+}
+
+// TODO(hanwen): tests for
+//
+// host keys:
+// * fallbacks
+
+func TestHostKeyCert(t *testing.T) {
+ cert := &Certificate{
+ ValidPrincipals: []string{"hostname", "hostname.domain"},
+ Key: testPublicKeys["rsa"],
+ ValidBefore: CertTimeInfinity,
+ CertType: HostCert,
+ }
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+
+ checker := &CertChecker{
+ IsAuthority: func(p PublicKey) bool {
+ return bytes.Equal(testPublicKeys["ecdsa"].Marshal(), p.Marshal())
+ },
+ }
+
+ certSigner, err := NewCertSigner(cert, testSigners["rsa"])
+ if err != nil {
+ t.Errorf("NewCertSigner: %v", err)
+ }
+
+ for _, name := range []string{"hostname", "otherhost"} {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ errc := make(chan error)
+
+ go func() {
+ conf := ServerConfig{
+ NoClientAuth: true,
+ }
+ conf.AddHostKey(certSigner)
+ _, _, _, err := NewServerConn(c1, &conf)
+ errc <- err
+ }()
+
+ config := &ClientConfig{
+ User: "user",
+ HostKeyCallback: checker.CheckHostKey,
+ }
+ _, _, _, err = NewClientConn(c2, name, config)
+
+ succeed := name == "hostname"
+ if (err == nil) != succeed {
+ t.Fatalf("NewClientConn(%q): %v", name, err)
+ }
+
+ err = <-errc
+ if (err == nil) != succeed {
+ t.Fatalf("NewServerConn(%q): %v", name, err)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go
new file mode 100644
index 000000000..6671c98c2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/channel.go
@@ -0,0 +1,631 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "sync"
+)
+
+const (
+ minPacketLength = 9
+ // channelMaxPacket contains the maximum number of bytes that will be
+ // sent in a single packet. As per RFC 4253, section 6.1, 32k is also
+ // the minimum.
+ channelMaxPacket = 1 << 15
+ // We follow OpenSSH here.
+ channelWindowSize = 64 * channelMaxPacket
+)
+
+// NewChannel represents an incoming request to a channel. It must either be
+// accepted for use by calling Accept, or rejected by calling Reject.
+type NewChannel interface {
+ // Accept accepts the channel creation request. It returns the Channel
+ // and a Go channel containing SSH requests. The Go channel must be
+ // serviced otherwise the Channel will hang.
+ Accept() (Channel, <-chan *Request, error)
+
+ // Reject rejects the channel creation request. After calling
+ // this, no other methods on the Channel may be called.
+ Reject(reason RejectionReason, message string) error
+
+ // ChannelType returns the type of the channel, as supplied by the
+ // client.
+ ChannelType() string
+
+ // ExtraData returns the arbitrary payload for this channel, as supplied
+ // by the client. This data is specific to the channel type.
+ ExtraData() []byte
+}
+
+// A Channel is an ordered, reliable, flow-controlled, duplex stream
+// that is multiplexed over an SSH connection.
+type Channel interface {
+ // Read reads up to len(data) bytes from the channel.
+ Read(data []byte) (int, error)
+
+ // Write writes len(data) bytes to the channel.
+ Write(data []byte) (int, error)
+
+ // Close signals end of channel use. No data may be sent after this
+ // call.
+ Close() error
+
+ // CloseWrite signals the end of sending in-band
+ // data. Requests may still be sent, and the other side may
+ // still send data
+ CloseWrite() error
+
+ // SendRequest sends a channel request. If wantReply is true,
+ // it will wait for a reply and return the result as a
+ // boolean, otherwise the return value will be false. Channel
+ // requests are out-of-band messages so they may be sent even
+ // if the data stream is closed or blocked by flow control.
+ SendRequest(name string, wantReply bool, payload []byte) (bool, error)
+
+ // Stderr returns an io.ReadWriter that writes to this channel
+ // with the extended data type set to stderr. Stderr may
+ // safely be read and written from a different goroutine than
+ // Read and Write respectively.
+ Stderr() io.ReadWriter
+}
+
+// Request is a request sent outside of the normal stream of
+// data. Requests can either be specific to an SSH channel, or they
+// can be global.
+type Request struct {
+ Type string
+ WantReply bool
+ Payload []byte
+
+ ch *channel
+ mux *mux
+}
+
+// Reply sends a response to a request. It must be called for all requests
+// where WantReply is true and is a no-op otherwise. The payload argument is
+// ignored for replies to channel-specific requests.
+func (r *Request) Reply(ok bool, payload []byte) error {
+ if !r.WantReply {
+ return nil
+ }
+
+ if r.ch == nil {
+ return r.mux.ackRequest(ok, payload)
+ }
+
+ return r.ch.ackRequest(ok)
+}
+
+// RejectionReason is an enumeration used when rejecting channel creation
+// requests. See RFC 4254, section 5.1.
+type RejectionReason uint32
+
+const (
+ Prohibited RejectionReason = iota + 1
+ ConnectionFailed
+ UnknownChannelType
+ ResourceShortage
+)
+
+// String converts the rejection reason to human readable form.
+func (r RejectionReason) String() string {
+ switch r {
+ case Prohibited:
+ return "administratively prohibited"
+ case ConnectionFailed:
+ return "connect failed"
+ case UnknownChannelType:
+ return "unknown channel type"
+ case ResourceShortage:
+ return "resource shortage"
+ }
+ return fmt.Sprintf("unknown reason %d", int(r))
+}
+
+func min(a uint32, b int) uint32 {
+ if a < uint32(b) {
+ return a
+ }
+ return uint32(b)
+}
+
+type channelDirection uint8
+
+const (
+ channelInbound channelDirection = iota
+ channelOutbound
+)
+
+// channel is an implementation of the Channel interface that works
+// with the mux class.
+type channel struct {
+ // R/O after creation
+ chanType string
+ extraData []byte
+ localId, remoteId uint32
+
+ // maxIncomingPayload and maxRemotePayload are the maximum
+ // payload sizes of normal and extended data packets for
+ // receiving and sending, respectively. The wire packet will
+ // be 9 or 13 bytes larger (excluding encryption overhead).
+ maxIncomingPayload uint32
+ maxRemotePayload uint32
+
+ mux *mux
+
+ // decided is set to true if an accept or reject message has been sent
+ // (for outbound channels) or received (for inbound channels).
+ decided bool
+
+ // direction contains either channelOutbound, for channels created
+ // locally, or channelInbound, for channels created by the peer.
+ direction channelDirection
+
+ // Pending internal channel messages.
+ msg chan interface{}
+
+ // Since requests have no ID, there can be only one request
+ // with WantReply=true outstanding. This lock is held by a
+ // goroutine that has such an outgoing request pending.
+ sentRequestMu sync.Mutex
+
+ incomingRequests chan *Request
+
+ sentEOF bool
+
+ // thread-safe data
+ remoteWin window
+ pending *buffer
+ extPending *buffer
+
+ // windowMu protects myWindow, the flow-control window.
+ windowMu sync.Mutex
+ myWindow uint32
+
+ // writeMu serializes calls to mux.conn.writePacket() and
+ // protects sentClose and packetPool. This mutex must be
+ // different from windowMu, as writePacket can block if there
+ // is a key exchange pending.
+ writeMu sync.Mutex
+ sentClose bool
+
+ // packetPool has a buffer for each extended channel ID to
+ // save allocations during writes.
+ packetPool map[uint32][]byte
+}
+
+// writePacket sends a packet. If the packet is a channel close, it updates
+// sentClose. This method takes the lock c.writeMu.
+func (c *channel) writePacket(packet []byte) error {
+ c.writeMu.Lock()
+ if c.sentClose {
+ c.writeMu.Unlock()
+ return io.EOF
+ }
+ c.sentClose = (packet[0] == msgChannelClose)
+ err := c.mux.conn.writePacket(packet)
+ c.writeMu.Unlock()
+ return err
+}
+
+func (c *channel) sendMessage(msg interface{}) error {
+ if debugMux {
+ log.Printf("send(%d): %#v", c.mux.chanList.offset, msg)
+ }
+
+ p := Marshal(msg)
+ binary.BigEndian.PutUint32(p[1:], c.remoteId)
+ return c.writePacket(p)
+}
+
+// WriteExtended writes data to a specific extended stream. These streams are
+// used, for example, for stderr.
+func (c *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) {
+ if c.sentEOF {
+ return 0, io.EOF
+ }
+ // 1 byte message type, 4 bytes remoteId, 4 bytes data length
+ opCode := byte(msgChannelData)
+ headerLength := uint32(9)
+ if extendedCode > 0 {
+ headerLength += 4
+ opCode = msgChannelExtendedData
+ }
+
+ c.writeMu.Lock()
+ packet := c.packetPool[extendedCode]
+ // We don't remove the buffer from packetPool, so
+ // WriteExtended calls from different goroutines will be
+ // flagged as errors by the race detector.
+ c.writeMu.Unlock()
+
+ for len(data) > 0 {
+ space := min(c.maxRemotePayload, len(data))
+ if space, err = c.remoteWin.reserve(space); err != nil {
+ return n, err
+ }
+ if want := headerLength + space; uint32(cap(packet)) < want {
+ packet = make([]byte, want)
+ } else {
+ packet = packet[:want]
+ }
+
+ todo := data[:space]
+
+ packet[0] = opCode
+ binary.BigEndian.PutUint32(packet[1:], c.remoteId)
+ if extendedCode > 0 {
+ binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode))
+ }
+ binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo)))
+ copy(packet[headerLength:], todo)
+ if err = c.writePacket(packet); err != nil {
+ return n, err
+ }
+
+ n += len(todo)
+ data = data[len(todo):]
+ }
+
+ c.writeMu.Lock()
+ c.packetPool[extendedCode] = packet
+ c.writeMu.Unlock()
+
+ return n, err
+}
+
+func (c *channel) handleData(packet []byte) error {
+ headerLen := 9
+ isExtendedData := packet[0] == msgChannelExtendedData
+ if isExtendedData {
+ headerLen = 13
+ }
+ if len(packet) < headerLen {
+ // malformed data packet
+ return parseError(packet[0])
+ }
+
+ var extended uint32
+ if isExtendedData {
+ extended = binary.BigEndian.Uint32(packet[5:])
+ }
+
+ length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen])
+ if length == 0 {
+ return nil
+ }
+ if length > c.maxIncomingPayload {
+ // TODO(hanwen): should send Disconnect?
+ return errors.New("ssh: incoming packet exceeds maximum payload size")
+ }
+
+ data := packet[headerLen:]
+ if length != uint32(len(data)) {
+ return errors.New("ssh: wrong packet length")
+ }
+
+ c.windowMu.Lock()
+ if c.myWindow < length {
+ c.windowMu.Unlock()
+ // TODO(hanwen): should send Disconnect with reason?
+ return errors.New("ssh: remote side wrote too much")
+ }
+ c.myWindow -= length
+ c.windowMu.Unlock()
+
+ if extended == 1 {
+ c.extPending.write(data)
+ } else if extended > 0 {
+ // discard other extended data.
+ } else {
+ c.pending.write(data)
+ }
+ return nil
+}
+
+func (c *channel) adjustWindow(n uint32) error {
+ c.windowMu.Lock()
+ // Since myWindow is managed on our side, and can never exceed
+ // the initial window setting, we don't worry about overflow.
+ c.myWindow += uint32(n)
+ c.windowMu.Unlock()
+ return c.sendMessage(windowAdjustMsg{
+ AdditionalBytes: uint32(n),
+ })
+}
+
+func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) {
+ switch extended {
+ case 1:
+ n, err = c.extPending.Read(data)
+ case 0:
+ n, err = c.pending.Read(data)
+ default:
+ return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended)
+ }
+
+ if n > 0 {
+ err = c.adjustWindow(uint32(n))
+ // sendWindowAdjust can return io.EOF if the remote
+ // peer has closed the connection, however we want to
+ // defer forwarding io.EOF to the caller of Read until
+ // the buffer has been drained.
+ if n > 0 && err == io.EOF {
+ err = nil
+ }
+ }
+
+ return n, err
+}
+
+func (c *channel) close() {
+ c.pending.eof()
+ c.extPending.eof()
+ close(c.msg)
+ close(c.incomingRequests)
+ c.writeMu.Lock()
+ // This is not necessary for a normal channel teardown, but if
+ // there was another error, it is.
+ c.sentClose = true
+ c.writeMu.Unlock()
+ // Unblock writers.
+ c.remoteWin.close()
+}
+
+// responseMessageReceived is called when a success or failure message is
+// received on a channel to check that such a message is reasonable for the
+// given channel.
+func (c *channel) responseMessageReceived() error {
+ if c.direction == channelInbound {
+ return errors.New("ssh: channel response message received on inbound channel")
+ }
+ if c.decided {
+ return errors.New("ssh: duplicate response received for channel")
+ }
+ c.decided = true
+ return nil
+}
+
+func (c *channel) handlePacket(packet []byte) error {
+ switch packet[0] {
+ case msgChannelData, msgChannelExtendedData:
+ return c.handleData(packet)
+ case msgChannelClose:
+ c.sendMessage(channelCloseMsg{PeersId: c.remoteId})
+ c.mux.chanList.remove(c.localId)
+ c.close()
+ return nil
+ case msgChannelEOF:
+ // RFC 4254 is mute on how EOF affects dataExt messages but
+ // it is logical to signal EOF at the same time.
+ c.extPending.eof()
+ c.pending.eof()
+ return nil
+ }
+
+ decoded, err := decode(packet)
+ if err != nil {
+ return err
+ }
+
+ switch msg := decoded.(type) {
+ case *channelOpenFailureMsg:
+ if err := c.responseMessageReceived(); err != nil {
+ return err
+ }
+ c.mux.chanList.remove(msg.PeersId)
+ c.msg <- msg
+ case *channelOpenConfirmMsg:
+ if err := c.responseMessageReceived(); err != nil {
+ return err
+ }
+ if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
+ return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize)
+ }
+ c.remoteId = msg.MyId
+ c.maxRemotePayload = msg.MaxPacketSize
+ c.remoteWin.add(msg.MyWindow)
+ c.msg <- msg
+ case *windowAdjustMsg:
+ if !c.remoteWin.add(msg.AdditionalBytes) {
+ return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes)
+ }
+ case *channelRequestMsg:
+ req := Request{
+ Type: msg.Request,
+ WantReply: msg.WantReply,
+ Payload: msg.RequestSpecificData,
+ ch: c,
+ }
+
+ c.incomingRequests <- &req
+ default:
+ c.msg <- msg
+ }
+ return nil
+}
+
+func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel {
+ ch := &channel{
+ remoteWin: window{Cond: newCond()},
+ myWindow: channelWindowSize,
+ pending: newBuffer(),
+ extPending: newBuffer(),
+ direction: direction,
+ incomingRequests: make(chan *Request, 16),
+ msg: make(chan interface{}, 16),
+ chanType: chanType,
+ extraData: extraData,
+ mux: m,
+ packetPool: make(map[uint32][]byte),
+ }
+ ch.localId = m.chanList.add(ch)
+ return ch
+}
+
+var errUndecided = errors.New("ssh: must Accept or Reject channel")
+var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once")
+
+type extChannel struct {
+ code uint32
+ ch *channel
+}
+
+func (e *extChannel) Write(data []byte) (n int, err error) {
+ return e.ch.WriteExtended(data, e.code)
+}
+
+func (e *extChannel) Read(data []byte) (n int, err error) {
+ return e.ch.ReadExtended(data, e.code)
+}
+
+func (c *channel) Accept() (Channel, <-chan *Request, error) {
+ if c.decided {
+ return nil, nil, errDecidedAlready
+ }
+ c.maxIncomingPayload = channelMaxPacket
+ confirm := channelOpenConfirmMsg{
+ PeersId: c.remoteId,
+ MyId: c.localId,
+ MyWindow: c.myWindow,
+ MaxPacketSize: c.maxIncomingPayload,
+ }
+ c.decided = true
+ if err := c.sendMessage(confirm); err != nil {
+ return nil, nil, err
+ }
+
+ return c, c.incomingRequests, nil
+}
+
+func (ch *channel) Reject(reason RejectionReason, message string) error {
+ if ch.decided {
+ return errDecidedAlready
+ }
+ reject := channelOpenFailureMsg{
+ PeersId: ch.remoteId,
+ Reason: reason,
+ Message: message,
+ Language: "en",
+ }
+ ch.decided = true
+ return ch.sendMessage(reject)
+}
+
+func (ch *channel) Read(data []byte) (int, error) {
+ if !ch.decided {
+ return 0, errUndecided
+ }
+ return ch.ReadExtended(data, 0)
+}
+
+func (ch *channel) Write(data []byte) (int, error) {
+ if !ch.decided {
+ return 0, errUndecided
+ }
+ return ch.WriteExtended(data, 0)
+}
+
+func (ch *channel) CloseWrite() error {
+ if !ch.decided {
+ return errUndecided
+ }
+ ch.sentEOF = true
+ return ch.sendMessage(channelEOFMsg{
+ PeersId: ch.remoteId})
+}
+
+func (ch *channel) Close() error {
+ if !ch.decided {
+ return errUndecided
+ }
+
+ return ch.sendMessage(channelCloseMsg{
+ PeersId: ch.remoteId})
+}
+
+// Extended returns an io.ReadWriter that sends and receives data on the given,
+// SSH extended stream. Such streams are used, for example, for stderr.
+func (ch *channel) Extended(code uint32) io.ReadWriter {
+ if !ch.decided {
+ return nil
+ }
+ return &extChannel{code, ch}
+}
+
+func (ch *channel) Stderr() io.ReadWriter {
+ return ch.Extended(1)
+}
+
+func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
+ if !ch.decided {
+ return false, errUndecided
+ }
+
+ if wantReply {
+ ch.sentRequestMu.Lock()
+ defer ch.sentRequestMu.Unlock()
+ }
+
+ msg := channelRequestMsg{
+ PeersId: ch.remoteId,
+ Request: name,
+ WantReply: wantReply,
+ RequestSpecificData: payload,
+ }
+
+ if err := ch.sendMessage(msg); err != nil {
+ return false, err
+ }
+
+ if wantReply {
+ m, ok := (<-ch.msg)
+ if !ok {
+ return false, io.EOF
+ }
+ switch m.(type) {
+ case *channelRequestFailureMsg:
+ return false, nil
+ case *channelRequestSuccessMsg:
+ return true, nil
+ default:
+ return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m)
+ }
+ }
+
+ return false, nil
+}
+
+// ackRequest either sends an ack or nack to the channel request.
+func (ch *channel) ackRequest(ok bool) error {
+ if !ch.decided {
+ return errUndecided
+ }
+
+ var msg interface{}
+ if !ok {
+ msg = channelRequestFailureMsg{
+ PeersId: ch.remoteId,
+ }
+ } else {
+ msg = channelRequestSuccessMsg{
+ PeersId: ch.remoteId,
+ }
+ }
+ return ch.sendMessage(msg)
+}
+
+func (ch *channel) ChannelType() string {
+ return ch.chanType
+}
+
+func (ch *channel) ExtraData() []byte {
+ return ch.extraData
+}
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go
new file mode 100644
index 000000000..2732963f3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/cipher.go
@@ -0,0 +1,552 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rc4"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "io/ioutil"
+)
+
+const (
+ packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher.
+
+ // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations
+ // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC
+ // indicates implementations SHOULD be able to handle larger packet sizes, but then
+ // waffles on about reasonable limits.
+ //
+ // OpenSSH caps their maxPacket at 256kB so we choose to do
+ // the same. maxPacket is also used to ensure that uint32
+ // length fields do not overflow, so it should remain well
+ // below 4G.
+ maxPacket = 256 * 1024
+)
+
+// noneCipher implements cipher.Stream and provides no encryption. It is used
+// by the transport before the first key-exchange.
+type noneCipher struct{}
+
+func (c noneCipher) XORKeyStream(dst, src []byte) {
+ copy(dst, src)
+}
+
+func newAESCTR(key, iv []byte) (cipher.Stream, error) {
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+ return cipher.NewCTR(c, iv), nil
+}
+
+func newRC4(key, iv []byte) (cipher.Stream, error) {
+ return rc4.NewCipher(key)
+}
+
+type streamCipherMode struct {
+ keySize int
+ ivSize int
+ skip int
+ createFunc func(key, iv []byte) (cipher.Stream, error)
+}
+
+func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) {
+ if len(key) < c.keySize {
+ panic("ssh: key length too small for cipher")
+ }
+ if len(iv) < c.ivSize {
+ panic("ssh: iv too small for cipher")
+ }
+
+ stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize])
+ if err != nil {
+ return nil, err
+ }
+
+ var streamDump []byte
+ if c.skip > 0 {
+ streamDump = make([]byte, 512)
+ }
+
+ for remainingToDump := c.skip; remainingToDump > 0; {
+ dumpThisTime := remainingToDump
+ if dumpThisTime > len(streamDump) {
+ dumpThisTime = len(streamDump)
+ }
+ stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime])
+ remainingToDump -= dumpThisTime
+ }
+
+ return stream, nil
+}
+
+// cipherModes documents properties of supported ciphers. Ciphers not included
+// are not supported and will not be negotiated, even if explicitly requested in
+// ClientConfig.Crypto.Ciphers.
+var cipherModes = map[string]*streamCipherMode{
+ // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms
+ // are defined in the order specified in the RFC.
+ "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR},
+ "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR},
+ "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR},
+
+ // Ciphers from RFC4345, which introduces security-improved arcfour ciphers.
+ // They are defined in the order specified in the RFC.
+ "arcfour128": {16, 0, 1536, newRC4},
+ "arcfour256": {32, 0, 1536, newRC4},
+
+ // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol.
+ // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and
+ // RC4) has problems with weak keys, and should be used with caution."
+ // RFC4345 introduces improved versions of Arcfour.
+ "arcfour": {16, 0, 0, newRC4},
+
+ // AES-GCM is not a stream cipher, so it is constructed with a
+ // special case. If we add any more non-stream ciphers, we
+ // should invest a cleaner way to do this.
+ gcmCipherID: {16, 12, 0, nil},
+
+ // CBC mode is insecure and so is not included in the default config.
+ // (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely
+ // needed, it's possible to specify a custom Config to enable it.
+ // You should expect that an active attacker can recover plaintext if
+ // you do.
+ aes128cbcID: {16, aes.BlockSize, 0, nil},
+}
+
+// prefixLen is the length of the packet prefix that contains the packet length
+// and number of padding bytes.
+const prefixLen = 5
+
+// streamPacketCipher is a packetCipher using a stream cipher.
+type streamPacketCipher struct {
+ mac hash.Hash
+ cipher cipher.Stream
+
+ // The following members are to avoid per-packet allocations.
+ prefix [prefixLen]byte
+ seqNumBytes [4]byte
+ padding [2 * packetSizeMultiple]byte
+ packetData []byte
+ macResult []byte
+}
+
+// readPacket reads and decrypt a single packet from the reader argument.
+func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+ if _, err := io.ReadFull(r, s.prefix[:]); err != nil {
+ return nil, err
+ }
+
+ s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
+ length := binary.BigEndian.Uint32(s.prefix[0:4])
+ paddingLength := uint32(s.prefix[4])
+
+ var macSize uint32
+ if s.mac != nil {
+ s.mac.Reset()
+ binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
+ s.mac.Write(s.seqNumBytes[:])
+ s.mac.Write(s.prefix[:])
+ macSize = uint32(s.mac.Size())
+ }
+
+ if length <= paddingLength+1 {
+ return nil, errors.New("ssh: invalid packet length, packet too small")
+ }
+
+ if length > maxPacket {
+ return nil, errors.New("ssh: invalid packet length, packet too large")
+ }
+
+ // the maxPacket check above ensures that length-1+macSize
+ // does not overflow.
+ if uint32(cap(s.packetData)) < length-1+macSize {
+ s.packetData = make([]byte, length-1+macSize)
+ } else {
+ s.packetData = s.packetData[:length-1+macSize]
+ }
+
+ if _, err := io.ReadFull(r, s.packetData); err != nil {
+ return nil, err
+ }
+ mac := s.packetData[length-1:]
+ data := s.packetData[:length-1]
+ s.cipher.XORKeyStream(data, data)
+
+ if s.mac != nil {
+ s.mac.Write(data)
+ s.macResult = s.mac.Sum(s.macResult[:0])
+ if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
+ return nil, errors.New("ssh: MAC failure")
+ }
+ }
+
+ return s.packetData[:length-paddingLength-1], nil
+}
+
+// writePacket encrypts and sends a packet of data to the writer argument
+func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+ if len(packet) > maxPacket {
+ return errors.New("ssh: packet too large")
+ }
+
+ paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple
+ if paddingLength < 4 {
+ paddingLength += packetSizeMultiple
+ }
+
+ length := len(packet) + 1 + paddingLength
+ binary.BigEndian.PutUint32(s.prefix[:], uint32(length))
+ s.prefix[4] = byte(paddingLength)
+ padding := s.padding[:paddingLength]
+ if _, err := io.ReadFull(rand, padding); err != nil {
+ return err
+ }
+
+ if s.mac != nil {
+ s.mac.Reset()
+ binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
+ s.mac.Write(s.seqNumBytes[:])
+ s.mac.Write(s.prefix[:])
+ s.mac.Write(packet)
+ s.mac.Write(padding)
+ }
+
+ s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
+ s.cipher.XORKeyStream(packet, packet)
+ s.cipher.XORKeyStream(padding, padding)
+
+ if _, err := w.Write(s.prefix[:]); err != nil {
+ return err
+ }
+ if _, err := w.Write(packet); err != nil {
+ return err
+ }
+ if _, err := w.Write(padding); err != nil {
+ return err
+ }
+
+ if s.mac != nil {
+ s.macResult = s.mac.Sum(s.macResult[:0])
+ if _, err := w.Write(s.macResult); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+type gcmCipher struct {
+ aead cipher.AEAD
+ prefix [4]byte
+ iv []byte
+ buf []byte
+}
+
+func newGCMCipher(iv, key, macKey []byte) (packetCipher, error) {
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ aead, err := cipher.NewGCM(c)
+ if err != nil {
+ return nil, err
+ }
+
+ return &gcmCipher{
+ aead: aead,
+ iv: iv,
+ }, nil
+}
+
+const gcmTagSize = 16
+
+func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+ // Pad out to multiple of 16 bytes. This is different from the
+ // stream cipher because that encrypts the length too.
+ padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple)
+ if padding < 4 {
+ padding += packetSizeMultiple
+ }
+
+ length := uint32(len(packet) + int(padding) + 1)
+ binary.BigEndian.PutUint32(c.prefix[:], length)
+ if _, err := w.Write(c.prefix[:]); err != nil {
+ return err
+ }
+
+ if cap(c.buf) < int(length) {
+ c.buf = make([]byte, length)
+ } else {
+ c.buf = c.buf[:length]
+ }
+
+ c.buf[0] = padding
+ copy(c.buf[1:], packet)
+ if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil {
+ return err
+ }
+ c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:])
+ if _, err := w.Write(c.buf); err != nil {
+ return err
+ }
+ c.incIV()
+
+ return nil
+}
+
+func (c *gcmCipher) incIV() {
+ for i := 4 + 7; i >= 4; i-- {
+ c.iv[i]++
+ if c.iv[i] != 0 {
+ break
+ }
+ }
+}
+
+func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+ if _, err := io.ReadFull(r, c.prefix[:]); err != nil {
+ return nil, err
+ }
+ length := binary.BigEndian.Uint32(c.prefix[:])
+ if length > maxPacket {
+ return nil, errors.New("ssh: max packet length exceeded.")
+ }
+
+ if cap(c.buf) < int(length+gcmTagSize) {
+ c.buf = make([]byte, length+gcmTagSize)
+ } else {
+ c.buf = c.buf[:length+gcmTagSize]
+ }
+
+ if _, err := io.ReadFull(r, c.buf); err != nil {
+ return nil, err
+ }
+
+ plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:])
+ if err != nil {
+ return nil, err
+ }
+ c.incIV()
+
+ padding := plain[0]
+ if padding < 4 || padding >= 20 {
+ return nil, fmt.Errorf("ssh: illegal padding %d", padding)
+ }
+
+ if int(padding+1) >= len(plain) {
+ return nil, fmt.Errorf("ssh: padding %d too large", padding)
+ }
+ plain = plain[1 : length-uint32(padding)]
+ return plain, nil
+}
+
+// cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1
+type cbcCipher struct {
+ mac hash.Hash
+ macSize uint32
+ decrypter cipher.BlockMode
+ encrypter cipher.BlockMode
+
+ // The following members are to avoid per-packet allocations.
+ seqNumBytes [4]byte
+ packetData []byte
+ macResult []byte
+
+ // Amount of data we should still read to hide which
+ // verification error triggered.
+ oracleCamouflage uint32
+}
+
+func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) {
+ c, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ cbc := &cbcCipher{
+ mac: macModes[algs.MAC].new(macKey),
+ decrypter: cipher.NewCBCDecrypter(c, iv),
+ encrypter: cipher.NewCBCEncrypter(c, iv),
+ packetData: make([]byte, 1024),
+ }
+ if cbc.mac != nil {
+ cbc.macSize = uint32(cbc.mac.Size())
+ }
+
+ return cbc, nil
+}
+
+func maxUInt32(a, b int) uint32 {
+ if a > b {
+ return uint32(a)
+ }
+ return uint32(b)
+}
+
+const (
+ cbcMinPacketSizeMultiple = 8
+ cbcMinPacketSize = 16
+ cbcMinPaddingSize = 4
+)
+
+// cbcError represents a verification error that may leak information.
+type cbcError string
+
+func (e cbcError) Error() string { return string(e) }
+
+func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) {
+ p, err := c.readPacketLeaky(seqNum, r)
+ if err != nil {
+ if _, ok := err.(cbcError); ok {
+ // Verification error: read a fixed amount of
+ // data, to make distinguishing between
+ // failing MAC and failing length check more
+ // difficult.
+ io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage))
+ }
+ }
+ return p, err
+}
+
+func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) {
+ blockSize := c.decrypter.BlockSize()
+
+ // Read the header, which will include some of the subsequent data in the
+ // case of block ciphers - this is copied back to the payload later.
+ // How many bytes of payload/padding will be read with this first read.
+ firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize)
+ firstBlock := c.packetData[:firstBlockLength]
+ if _, err := io.ReadFull(r, firstBlock); err != nil {
+ return nil, err
+ }
+
+ c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength
+
+ c.decrypter.CryptBlocks(firstBlock, firstBlock)
+ length := binary.BigEndian.Uint32(firstBlock[:4])
+ if length > maxPacket {
+ return nil, cbcError("ssh: packet too large")
+ }
+ if length+4 < maxUInt32(cbcMinPacketSize, blockSize) {
+ // The minimum size of a packet is 16 (or the cipher block size, whichever
+ // is larger) bytes.
+ return nil, cbcError("ssh: packet too small")
+ }
+ // The length of the packet (including the length field but not the MAC) must
+ // be a multiple of the block size or 8, whichever is larger.
+ if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 {
+ return nil, cbcError("ssh: invalid packet length multiple")
+ }
+
+ paddingLength := uint32(firstBlock[4])
+ if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 {
+ return nil, cbcError("ssh: invalid packet length")
+ }
+
+ // Positions within the c.packetData buffer:
+ macStart := 4 + length
+ paddingStart := macStart - paddingLength
+
+ // Entire packet size, starting before length, ending at end of mac.
+ entirePacketSize := macStart + c.macSize
+
+ // Ensure c.packetData is large enough for the entire packet data.
+ if uint32(cap(c.packetData)) < entirePacketSize {
+ // Still need to upsize and copy, but this should be rare at runtime, only
+ // on upsizing the packetData buffer.
+ c.packetData = make([]byte, entirePacketSize)
+ copy(c.packetData, firstBlock)
+ } else {
+ c.packetData = c.packetData[:entirePacketSize]
+ }
+
+ if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil {
+ return nil, err
+ } else {
+ c.oracleCamouflage -= uint32(n)
+ }
+
+ remainingCrypted := c.packetData[firstBlockLength:macStart]
+ c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted)
+
+ mac := c.packetData[macStart:]
+ if c.mac != nil {
+ c.mac.Reset()
+ binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
+ c.mac.Write(c.seqNumBytes[:])
+ c.mac.Write(c.packetData[:macStart])
+ c.macResult = c.mac.Sum(c.macResult[:0])
+ if subtle.ConstantTimeCompare(c.macResult, mac) != 1 {
+ return nil, cbcError("ssh: MAC failure")
+ }
+ }
+
+ return c.packetData[prefixLen:paddingStart], nil
+}
+
+func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error {
+ effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize())
+
+ // Length of encrypted portion of the packet (header, payload, padding).
+ // Enforce minimum padding and packet size.
+ encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize)
+ // Enforce block size.
+ encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize
+
+ length := encLength - 4
+ paddingLength := int(length) - (1 + len(packet))
+
+ // Overall buffer contains: header, payload, padding, mac.
+ // Space for the MAC is reserved in the capacity but not the slice length.
+ bufferSize := encLength + c.macSize
+ if uint32(cap(c.packetData)) < bufferSize {
+ c.packetData = make([]byte, encLength, bufferSize)
+ } else {
+ c.packetData = c.packetData[:encLength]
+ }
+
+ p := c.packetData
+
+ // Packet header.
+ binary.BigEndian.PutUint32(p, length)
+ p = p[4:]
+ p[0] = byte(paddingLength)
+
+ // Payload.
+ p = p[1:]
+ copy(p, packet)
+
+ // Padding.
+ p = p[len(packet):]
+ if _, err := io.ReadFull(rand, p); err != nil {
+ return err
+ }
+
+ if c.mac != nil {
+ c.mac.Reset()
+ binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum)
+ c.mac.Write(c.seqNumBytes[:])
+ c.mac.Write(c.packetData)
+ // The MAC is now appended into the capacity reserved for it earlier.
+ c.packetData = c.mac.Sum(c.packetData)
+ }
+
+ c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength])
+
+ if _, err := w.Write(c.packetData); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/cipher_test.go b/vendor/golang.org/x/crypto/ssh/cipher_test.go
new file mode 100644
index 000000000..54b92b6ed
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/cipher_test.go
@@ -0,0 +1,127 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/aes"
+ "crypto/rand"
+ "testing"
+)
+
+func TestDefaultCiphersExist(t *testing.T) {
+ for _, cipherAlgo := range supportedCiphers {
+ if _, ok := cipherModes[cipherAlgo]; !ok {
+ t.Errorf("default cipher %q is unknown", cipherAlgo)
+ }
+ }
+}
+
+func TestPacketCiphers(t *testing.T) {
+ // Still test aes128cbc cipher althought it's commented out.
+ cipherModes[aes128cbcID] = &streamCipherMode{16, aes.BlockSize, 0, nil}
+ defer delete(cipherModes, aes128cbcID)
+
+ for cipher := range cipherModes {
+ kr := &kexResult{Hash: crypto.SHA1}
+ algs := directionAlgorithms{
+ Cipher: cipher,
+ MAC: "hmac-sha1",
+ Compression: "none",
+ }
+ client, err := newPacketCipher(clientKeys, algs, kr)
+ if err != nil {
+ t.Errorf("newPacketCipher(client, %q): %v", cipher, err)
+ continue
+ }
+ server, err := newPacketCipher(clientKeys, algs, kr)
+ if err != nil {
+ t.Errorf("newPacketCipher(client, %q): %v", cipher, err)
+ continue
+ }
+
+ want := "bla bla"
+ input := []byte(want)
+ buf := &bytes.Buffer{}
+ if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
+ t.Errorf("writePacket(%q): %v", cipher, err)
+ continue
+ }
+
+ packet, err := server.readPacket(0, buf)
+ if err != nil {
+ t.Errorf("readPacket(%q): %v", cipher, err)
+ continue
+ }
+
+ if string(packet) != want {
+ t.Errorf("roundtrip(%q): got %q, want %q", cipher, packet, want)
+ }
+ }
+}
+
+func TestCBCOracleCounterMeasure(t *testing.T) {
+ cipherModes[aes128cbcID] = &streamCipherMode{16, aes.BlockSize, 0, nil}
+ defer delete(cipherModes, aes128cbcID)
+
+ kr := &kexResult{Hash: crypto.SHA1}
+ algs := directionAlgorithms{
+ Cipher: aes128cbcID,
+ MAC: "hmac-sha1",
+ Compression: "none",
+ }
+ client, err := newPacketCipher(clientKeys, algs, kr)
+ if err != nil {
+ t.Fatalf("newPacketCipher(client): %v", err)
+ }
+
+ want := "bla bla"
+ input := []byte(want)
+ buf := &bytes.Buffer{}
+ if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
+ t.Errorf("writePacket: %v", err)
+ }
+
+ packetSize := buf.Len()
+ buf.Write(make([]byte, 2*maxPacket))
+
+ // We corrupt each byte, but this usually will only test the
+ // 'packet too large' or 'MAC failure' cases.
+ lastRead := -1
+ for i := 0; i < packetSize; i++ {
+ server, err := newPacketCipher(clientKeys, algs, kr)
+ if err != nil {
+ t.Fatalf("newPacketCipher(client): %v", err)
+ }
+
+ fresh := &bytes.Buffer{}
+ fresh.Write(buf.Bytes())
+ fresh.Bytes()[i] ^= 0x01
+
+ before := fresh.Len()
+ _, err = server.readPacket(0, fresh)
+ if err == nil {
+ t.Errorf("corrupt byte %d: readPacket succeeded ", i)
+ continue
+ }
+ if _, ok := err.(cbcError); !ok {
+ t.Errorf("corrupt byte %d: got %v (%T), want cbcError", i, err, err)
+ continue
+ }
+
+ after := fresh.Len()
+ bytesRead := before - after
+ if bytesRead < maxPacket {
+ t.Errorf("corrupt byte %d: read %d bytes, want more than %d", i, bytesRead, maxPacket)
+ continue
+ }
+
+ if i > 0 && bytesRead != lastRead {
+ t.Errorf("corrupt byte %d: read %d bytes, want %d bytes read", i, bytesRead, lastRead)
+ }
+ lastRead = bytesRead
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go
new file mode 100644
index 000000000..0212a20c9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/client.go
@@ -0,0 +1,213 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "errors"
+ "fmt"
+ "net"
+ "sync"
+ "time"
+)
+
+// Client implements a traditional SSH client that supports shells,
+// subprocesses, port forwarding and tunneled dialing.
+type Client struct {
+ Conn
+
+ forwards forwardList // forwarded tcpip connections from the remote side
+ mu sync.Mutex
+ channelHandlers map[string]chan NewChannel
+}
+
+// HandleChannelOpen returns a channel on which NewChannel requests
+// for the given type are sent. If the type already is being handled,
+// nil is returned. The channel is closed when the connection is closed.
+func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if c.channelHandlers == nil {
+ // The SSH channel has been closed.
+ c := make(chan NewChannel)
+ close(c)
+ return c
+ }
+
+ ch := c.channelHandlers[channelType]
+ if ch != nil {
+ return nil
+ }
+
+ ch = make(chan NewChannel, 16)
+ c.channelHandlers[channelType] = ch
+ return ch
+}
+
+// NewClient creates a Client on top of the given connection.
+func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
+ conn := &Client{
+ Conn: c,
+ channelHandlers: make(map[string]chan NewChannel, 1),
+ }
+
+ go conn.handleGlobalRequests(reqs)
+ go conn.handleChannelOpens(chans)
+ go func() {
+ conn.Wait()
+ conn.forwards.closeAll()
+ }()
+ go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
+ return conn
+}
+
+// NewClientConn establishes an authenticated SSH connection using c
+// as the underlying transport. The Request and NewChannel channels
+// must be serviced or the connection will hang.
+func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
+ fullConf := *config
+ fullConf.SetDefaults()
+ conn := &connection{
+ sshConn: sshConn{conn: c},
+ }
+
+ if err := conn.clientHandshake(addr, &fullConf); err != nil {
+ c.Close()
+ return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err)
+ }
+ conn.mux = newMux(conn.transport)
+ return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
+}
+
+// clientHandshake performs the client side key exchange. See RFC 4253 Section
+// 7.
+func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error {
+ if config.ClientVersion != "" {
+ c.clientVersion = []byte(config.ClientVersion)
+ } else {
+ c.clientVersion = []byte(packageVersion)
+ }
+ var err error
+ c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
+ if err != nil {
+ return err
+ }
+
+ c.transport = newClientTransport(
+ newTransport(c.sshConn.conn, config.Rand, true /* is client */),
+ c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr())
+ if err := c.transport.requestInitialKeyChange(); err != nil {
+ return err
+ }
+
+ // We just did the key change, so the session ID is established.
+ c.sessionID = c.transport.getSessionID()
+
+ return c.clientAuthenticate(config)
+}
+
+// verifyHostKeySignature verifies the host key obtained in the key
+// exchange.
+func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error {
+ sig, rest, ok := parseSignatureBody(result.Signature)
+ if len(rest) > 0 || !ok {
+ return errors.New("ssh: signature parse error")
+ }
+
+ return hostKey.Verify(result.H, sig)
+}
+
+// NewSession opens a new Session for this client. (A session is a remote
+// execution of a program.)
+func (c *Client) NewSession() (*Session, error) {
+ ch, in, err := c.OpenChannel("session", nil)
+ if err != nil {
+ return nil, err
+ }
+ return newSession(ch, in)
+}
+
+func (c *Client) handleGlobalRequests(incoming <-chan *Request) {
+ for r := range incoming {
+ // This handles keepalive messages and matches
+ // the behaviour of OpenSSH.
+ r.Reply(false, nil)
+ }
+}
+
+// handleChannelOpens channel open messages from the remote side.
+func (c *Client) handleChannelOpens(in <-chan NewChannel) {
+ for ch := range in {
+ c.mu.Lock()
+ handler := c.channelHandlers[ch.ChannelType()]
+ c.mu.Unlock()
+
+ if handler != nil {
+ handler <- ch
+ } else {
+ ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType()))
+ }
+ }
+
+ c.mu.Lock()
+ for _, ch := range c.channelHandlers {
+ close(ch)
+ }
+ c.channelHandlers = nil
+ c.mu.Unlock()
+}
+
+// Dial starts a client connection to the given SSH server. It is a
+// convenience function that connects to the given network address,
+// initiates the SSH handshake, and then sets up a Client. For access
+// to incoming channels and requests, use net.Dial with NewClientConn
+// instead.
+func Dial(network, addr string, config *ClientConfig) (*Client, error) {
+ conn, err := net.DialTimeout(network, addr, config.Timeout)
+ if err != nil {
+ return nil, err
+ }
+ c, chans, reqs, err := NewClientConn(conn, addr, config)
+ if err != nil {
+ return nil, err
+ }
+ return NewClient(c, chans, reqs), nil
+}
+
+// A ClientConfig structure is used to configure a Client. It must not be
+// modified after having been passed to an SSH function.
+type ClientConfig struct {
+ // Config contains configuration that is shared between clients and
+ // servers.
+ Config
+
+ // User contains the username to authenticate as.
+ User string
+
+ // Auth contains possible authentication methods to use with the
+ // server. Only the first instance of a particular RFC 4252 method will
+ // be used during authentication.
+ Auth []AuthMethod
+
+ // HostKeyCallback, if not nil, is called during the cryptographic
+ // handshake to validate the server's host key. A nil HostKeyCallback
+ // implies that all host keys are accepted.
+ HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+
+ // ClientVersion contains the version identification string that will
+ // be used for the connection. If empty, a reasonable default is used.
+ ClientVersion string
+
+ // HostKeyAlgorithms lists the key types that the client will
+ // accept from the server as host key, in order of
+ // preference. If empty, a reasonable default is used. Any
+ // string returned from PublicKey.Type method may be used, or
+ // any of the CertAlgoXxxx and KeyAlgoXxxx constants.
+ HostKeyAlgorithms []string
+
+ // Timeout is the maximum amount of time for the TCP connection to establish.
+ //
+ // A Timeout of zero means no timeout.
+ Timeout time.Duration
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go
new file mode 100644
index 000000000..6956ce451
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/client_auth.go
@@ -0,0 +1,439 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+)
+
+// clientAuthenticate authenticates with the remote server. See RFC 4252.
+func (c *connection) clientAuthenticate(config *ClientConfig) error {
+ // initiate user auth session
+ if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil {
+ return err
+ }
+ packet, err := c.transport.readPacket()
+ if err != nil {
+ return err
+ }
+ var serviceAccept serviceAcceptMsg
+ if err := Unmarshal(packet, &serviceAccept); err != nil {
+ return err
+ }
+
+ // during the authentication phase the client first attempts the "none" method
+ // then any untried methods suggested by the server.
+ tried := make(map[string]bool)
+ var lastMethods []string
+ for auth := AuthMethod(new(noneAuth)); auth != nil; {
+ ok, methods, err := auth.auth(c.transport.getSessionID(), config.User, c.transport, config.Rand)
+ if err != nil {
+ return err
+ }
+ if ok {
+ // success
+ return nil
+ }
+ tried[auth.method()] = true
+ if methods == nil {
+ methods = lastMethods
+ }
+ lastMethods = methods
+
+ auth = nil
+
+ findNext:
+ for _, a := range config.Auth {
+ candidateMethod := a.method()
+ if tried[candidateMethod] {
+ continue
+ }
+ for _, meth := range methods {
+ if meth == candidateMethod {
+ auth = a
+ break findNext
+ }
+ }
+ }
+ }
+ return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried))
+}
+
+func keys(m map[string]bool) []string {
+ s := make([]string, 0, len(m))
+
+ for key := range m {
+ s = append(s, key)
+ }
+ return s
+}
+
+// An AuthMethod represents an instance of an RFC 4252 authentication method.
+type AuthMethod interface {
+ // auth authenticates user over transport t.
+ // Returns true if authentication is successful.
+ // If authentication is not successful, a []string of alternative
+ // method names is returned. If the slice is nil, it will be ignored
+ // and the previous set of possible methods will be reused.
+ auth(session []byte, user string, p packetConn, rand io.Reader) (bool, []string, error)
+
+ // method returns the RFC 4252 method name.
+ method() string
+}
+
+// "none" authentication, RFC 4252 section 5.2.
+type noneAuth int
+
+func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
+ if err := c.writePacket(Marshal(&userAuthRequestMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: "none",
+ })); err != nil {
+ return false, nil, err
+ }
+
+ return handleAuthResponse(c)
+}
+
+func (n *noneAuth) method() string {
+ return "none"
+}
+
+// passwordCallback is an AuthMethod that fetches the password through
+// a function call, e.g. by prompting the user.
+type passwordCallback func() (password string, err error)
+
+func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
+ type passwordAuthMsg struct {
+ User string `sshtype:"50"`
+ Service string
+ Method string
+ Reply bool
+ Password string
+ }
+
+ pw, err := cb()
+ // REVIEW NOTE: is there a need to support skipping a password attempt?
+ // The program may only find out that the user doesn't have a password
+ // when prompting.
+ if err != nil {
+ return false, nil, err
+ }
+
+ if err := c.writePacket(Marshal(&passwordAuthMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: cb.method(),
+ Reply: false,
+ Password: pw,
+ })); err != nil {
+ return false, nil, err
+ }
+
+ return handleAuthResponse(c)
+}
+
+func (cb passwordCallback) method() string {
+ return "password"
+}
+
+// Password returns an AuthMethod using the given password.
+func Password(secret string) AuthMethod {
+ return passwordCallback(func() (string, error) { return secret, nil })
+}
+
+// PasswordCallback returns an AuthMethod that uses a callback for
+// fetching a password.
+func PasswordCallback(prompt func() (secret string, err error)) AuthMethod {
+ return passwordCallback(prompt)
+}
+
+type publickeyAuthMsg struct {
+ User string `sshtype:"50"`
+ Service string
+ Method string
+ // HasSig indicates to the receiver packet that the auth request is signed and
+ // should be used for authentication of the request.
+ HasSig bool
+ Algoname string
+ PubKey []byte
+ // Sig is tagged with "rest" so Marshal will exclude it during
+ // validateKey
+ Sig []byte `ssh:"rest"`
+}
+
+// publicKeyCallback is an AuthMethod that uses a set of key
+// pairs for authentication.
+type publicKeyCallback func() ([]Signer, error)
+
+func (cb publicKeyCallback) method() string {
+ return "publickey"
+}
+
+func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
+ // Authentication is performed in two stages. The first stage sends an
+ // enquiry to test if each key is acceptable to the remote. The second
+ // stage attempts to authenticate with the valid keys obtained in the
+ // first stage.
+
+ signers, err := cb()
+ if err != nil {
+ return false, nil, err
+ }
+ var validKeys []Signer
+ for _, signer := range signers {
+ if ok, err := validateKey(signer.PublicKey(), user, c); ok {
+ validKeys = append(validKeys, signer)
+ } else {
+ if err != nil {
+ return false, nil, err
+ }
+ }
+ }
+
+ // methods that may continue if this auth is not successful.
+ var methods []string
+ for _, signer := range validKeys {
+ pub := signer.PublicKey()
+
+ pubKey := pub.Marshal()
+ sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: cb.method(),
+ }, []byte(pub.Type()), pubKey))
+ if err != nil {
+ return false, nil, err
+ }
+
+ // manually wrap the serialized signature in a string
+ s := Marshal(sign)
+ sig := make([]byte, stringLength(len(s)))
+ marshalString(sig, s)
+ msg := publickeyAuthMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: cb.method(),
+ HasSig: true,
+ Algoname: pub.Type(),
+ PubKey: pubKey,
+ Sig: sig,
+ }
+ p := Marshal(&msg)
+ if err := c.writePacket(p); err != nil {
+ return false, nil, err
+ }
+ var success bool
+ success, methods, err = handleAuthResponse(c)
+ if err != nil {
+ return false, nil, err
+ }
+ if success {
+ return success, methods, err
+ }
+ }
+ return false, methods, nil
+}
+
+// validateKey validates the key provided is acceptable to the server.
+func validateKey(key PublicKey, user string, c packetConn) (bool, error) {
+ pubKey := key.Marshal()
+ msg := publickeyAuthMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: "publickey",
+ HasSig: false,
+ Algoname: key.Type(),
+ PubKey: pubKey,
+ }
+ if err := c.writePacket(Marshal(&msg)); err != nil {
+ return false, err
+ }
+
+ return confirmKeyAck(key, c)
+}
+
+func confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
+ pubKey := key.Marshal()
+ algoname := key.Type()
+
+ for {
+ packet, err := c.readPacket()
+ if err != nil {
+ return false, err
+ }
+ switch packet[0] {
+ case msgUserAuthBanner:
+ // TODO(gpaul): add callback to present the banner to the user
+ case msgUserAuthPubKeyOk:
+ var msg userAuthPubKeyOkMsg
+ if err := Unmarshal(packet, &msg); err != nil {
+ return false, err
+ }
+ if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) {
+ return false, nil
+ }
+ return true, nil
+ case msgUserAuthFailure:
+ return false, nil
+ default:
+ return false, unexpectedMessageError(msgUserAuthSuccess, packet[0])
+ }
+ }
+}
+
+// PublicKeys returns an AuthMethod that uses the given key
+// pairs.
+func PublicKeys(signers ...Signer) AuthMethod {
+ return publicKeyCallback(func() ([]Signer, error) { return signers, nil })
+}
+
+// PublicKeysCallback returns an AuthMethod that runs the given
+// function to obtain a list of key pairs.
+func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod {
+ return publicKeyCallback(getSigners)
+}
+
+// handleAuthResponse returns whether the preceding authentication request succeeded
+// along with a list of remaining authentication methods to try next and
+// an error if an unexpected response was received.
+func handleAuthResponse(c packetConn) (bool, []string, error) {
+ for {
+ packet, err := c.readPacket()
+ if err != nil {
+ return false, nil, err
+ }
+
+ switch packet[0] {
+ case msgUserAuthBanner:
+ // TODO: add callback to present the banner to the user
+ case msgUserAuthFailure:
+ var msg userAuthFailureMsg
+ if err := Unmarshal(packet, &msg); err != nil {
+ return false, nil, err
+ }
+ return false, msg.Methods, nil
+ case msgUserAuthSuccess:
+ return true, nil, nil
+ default:
+ return false, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0])
+ }
+ }
+}
+
+// KeyboardInteractiveChallenge should print questions, optionally
+// disabling echoing (e.g. for passwords), and return all the answers.
+// Challenge may be called multiple times in a single session. After
+// successful authentication, the server may send a challenge with no
+// questions, for which the user and instruction messages should be
+// printed. RFC 4256 section 3.3 details how the UI should behave for
+// both CLI and GUI environments.
+type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error)
+
+// KeyboardInteractive returns a AuthMethod using a prompt/response
+// sequence controlled by the server.
+func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod {
+ return challenge
+}
+
+func (cb KeyboardInteractiveChallenge) method() string {
+ return "keyboard-interactive"
+}
+
+func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
+ type initiateMsg struct {
+ User string `sshtype:"50"`
+ Service string
+ Method string
+ Language string
+ Submethods string
+ }
+
+ if err := c.writePacket(Marshal(&initiateMsg{
+ User: user,
+ Service: serviceSSH,
+ Method: "keyboard-interactive",
+ })); err != nil {
+ return false, nil, err
+ }
+
+ for {
+ packet, err := c.readPacket()
+ if err != nil {
+ return false, nil, err
+ }
+
+ // like handleAuthResponse, but with less options.
+ switch packet[0] {
+ case msgUserAuthBanner:
+ // TODO: Print banners during userauth.
+ continue
+ case msgUserAuthInfoRequest:
+ // OK
+ case msgUserAuthFailure:
+ var msg userAuthFailureMsg
+ if err := Unmarshal(packet, &msg); err != nil {
+ return false, nil, err
+ }
+ return false, msg.Methods, nil
+ case msgUserAuthSuccess:
+ return true, nil, nil
+ default:
+ return false, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0])
+ }
+
+ var msg userAuthInfoRequestMsg
+ if err := Unmarshal(packet, &msg); err != nil {
+ return false, nil, err
+ }
+
+ // Manually unpack the prompt/echo pairs.
+ rest := msg.Prompts
+ var prompts []string
+ var echos []bool
+ for i := 0; i < int(msg.NumPrompts); i++ {
+ prompt, r, ok := parseString(rest)
+ if !ok || len(r) == 0 {
+ return false, nil, errors.New("ssh: prompt format error")
+ }
+ prompts = append(prompts, string(prompt))
+ echos = append(echos, r[0] != 0)
+ rest = r[1:]
+ }
+
+ if len(rest) != 0 {
+ return false, nil, errors.New("ssh: extra data following keyboard-interactive pairs")
+ }
+
+ answers, err := cb(msg.User, msg.Instruction, prompts, echos)
+ if err != nil {
+ return false, nil, err
+ }
+
+ if len(answers) != len(prompts) {
+ return false, nil, errors.New("ssh: not enough answers from keyboard-interactive callback")
+ }
+ responseLength := 1 + 4
+ for _, a := range answers {
+ responseLength += stringLength(len(a))
+ }
+ serialized := make([]byte, responseLength)
+ p := serialized
+ p[0] = msgUserAuthInfoResponse
+ p = p[1:]
+ p = marshalUint32(p, uint32(len(answers)))
+ for _, a := range answers {
+ p = marshalString(p, []byte(a))
+ }
+
+ if err := c.writePacket(serialized); err != nil {
+ return false, nil, err
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth_test.go b/vendor/golang.org/x/crypto/ssh/client_auth_test.go
new file mode 100644
index 000000000..2ea44624f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/client_auth_test.go
@@ -0,0 +1,393 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "strings"
+ "testing"
+)
+
+type keyboardInteractive map[string]string
+
+func (cr keyboardInteractive) Challenge(user string, instruction string, questions []string, echos []bool) ([]string, error) {
+ var answers []string
+ for _, q := range questions {
+ answers = append(answers, cr[q])
+ }
+ return answers, nil
+}
+
+// reused internally by tests
+var clientPassword = "tiger"
+
+// tryAuth runs a handshake with a given config against an SSH server
+// with config serverConfig
+func tryAuth(t *testing.T, config *ClientConfig) error {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ certChecker := CertChecker{
+ IsAuthority: func(k PublicKey) bool {
+ return bytes.Equal(k.Marshal(), testPublicKeys["ecdsa"].Marshal())
+ },
+ UserKeyFallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
+ if conn.User() == "testuser" && bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
+ return nil, nil
+ }
+
+ return nil, fmt.Errorf("pubkey for %q not acceptable", conn.User())
+ },
+ IsRevoked: func(c *Certificate) bool {
+ return c.Serial == 666
+ },
+ }
+
+ serverConfig := &ServerConfig{
+ PasswordCallback: func(conn ConnMetadata, pass []byte) (*Permissions, error) {
+ if conn.User() == "testuser" && string(pass) == clientPassword {
+ return nil, nil
+ }
+ return nil, errors.New("password auth failed")
+ },
+ PublicKeyCallback: certChecker.Authenticate,
+ KeyboardInteractiveCallback: func(conn ConnMetadata, challenge KeyboardInteractiveChallenge) (*Permissions, error) {
+ ans, err := challenge("user",
+ "instruction",
+ []string{"question1", "question2"},
+ []bool{true, true})
+ if err != nil {
+ return nil, err
+ }
+ ok := conn.User() == "testuser" && ans[0] == "answer1" && ans[1] == "answer2"
+ if ok {
+ challenge("user", "motd", nil, nil)
+ return nil, nil
+ }
+ return nil, errors.New("keyboard-interactive failed")
+ },
+ AuthLogCallback: func(conn ConnMetadata, method string, err error) {
+ t.Logf("user %q, method %q: %v", conn.User(), method, err)
+ },
+ }
+ serverConfig.AddHostKey(testSigners["rsa"])
+
+ go newServer(c1, serverConfig)
+ _, _, _, err = NewClientConn(c2, "", config)
+ return err
+}
+
+func TestClientAuthPublicKey(t *testing.T) {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ PublicKeys(testSigners["rsa"]),
+ },
+ }
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+}
+
+func TestAuthMethodPassword(t *testing.T) {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ Password(clientPassword),
+ },
+ }
+
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+}
+
+func TestAuthMethodFallback(t *testing.T) {
+ var passwordCalled bool
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ PublicKeys(testSigners["rsa"]),
+ PasswordCallback(
+ func() (string, error) {
+ passwordCalled = true
+ return "WRONG", nil
+ }),
+ },
+ }
+
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+
+ if passwordCalled {
+ t.Errorf("password auth tried before public-key auth.")
+ }
+}
+
+func TestAuthMethodWrongPassword(t *testing.T) {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ Password("wrong"),
+ PublicKeys(testSigners["rsa"]),
+ },
+ }
+
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+}
+
+func TestAuthMethodKeyboardInteractive(t *testing.T) {
+ answers := keyboardInteractive(map[string]string{
+ "question1": "answer1",
+ "question2": "answer2",
+ })
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ KeyboardInteractive(answers.Challenge),
+ },
+ }
+
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("unable to dial remote side: %s", err)
+ }
+}
+
+func TestAuthMethodWrongKeyboardInteractive(t *testing.T) {
+ answers := keyboardInteractive(map[string]string{
+ "question1": "answer1",
+ "question2": "WRONG",
+ })
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ KeyboardInteractive(answers.Challenge),
+ },
+ }
+
+ if err := tryAuth(t, config); err == nil {
+ t.Fatalf("wrong answers should not have authenticated with KeyboardInteractive")
+ }
+}
+
+// the mock server will only authenticate ssh-rsa keys
+func TestAuthMethodInvalidPublicKey(t *testing.T) {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ PublicKeys(testSigners["dsa"]),
+ },
+ }
+
+ if err := tryAuth(t, config); err == nil {
+ t.Fatalf("dsa private key should not have authenticated with rsa public key")
+ }
+}
+
+// the client should authenticate with the second key
+func TestAuthMethodRSAandDSA(t *testing.T) {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ PublicKeys(testSigners["dsa"], testSigners["rsa"]),
+ },
+ }
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("client could not authenticate with rsa key: %v", err)
+ }
+}
+
+func TestClientHMAC(t *testing.T) {
+ for _, mac := range supportedMACs {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ PublicKeys(testSigners["rsa"]),
+ },
+ Config: Config{
+ MACs: []string{mac},
+ },
+ }
+ if err := tryAuth(t, config); err != nil {
+ t.Fatalf("client could not authenticate with mac algo %s: %v", mac, err)
+ }
+ }
+}
+
+// issue 4285.
+func TestClientUnsupportedCipher(t *testing.T) {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ PublicKeys(),
+ },
+ Config: Config{
+ Ciphers: []string{"aes128-cbc"}, // not currently supported
+ },
+ }
+ if err := tryAuth(t, config); err == nil {
+ t.Errorf("expected no ciphers in common")
+ }
+}
+
+func TestClientUnsupportedKex(t *testing.T) {
+ config := &ClientConfig{
+ User: "testuser",
+ Auth: []AuthMethod{
+ PublicKeys(),
+ },
+ Config: Config{
+ KeyExchanges: []string{"diffie-hellman-group-exchange-sha256"}, // not currently supported
+ },
+ }
+ if err := tryAuth(t, config); err == nil || !strings.Contains(err.Error(), "common algorithm") {
+ t.Errorf("got %v, expected 'common algorithm'", err)
+ }
+}
+
+func TestClientLoginCert(t *testing.T) {
+ cert := &Certificate{
+ Key: testPublicKeys["rsa"],
+ ValidBefore: CertTimeInfinity,
+ CertType: UserCert,
+ }
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ certSigner, err := NewCertSigner(cert, testSigners["rsa"])
+ if err != nil {
+ t.Fatalf("NewCertSigner: %v", err)
+ }
+
+ clientConfig := &ClientConfig{
+ User: "user",
+ }
+ clientConfig.Auth = append(clientConfig.Auth, PublicKeys(certSigner))
+
+ t.Log("should succeed")
+ if err := tryAuth(t, clientConfig); err != nil {
+ t.Errorf("cert login failed: %v", err)
+ }
+
+ t.Log("corrupted signature")
+ cert.Signature.Blob[0]++
+ if err := tryAuth(t, clientConfig); err == nil {
+ t.Errorf("cert login passed with corrupted sig")
+ }
+
+ t.Log("revoked")
+ cert.Serial = 666
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ if err := tryAuth(t, clientConfig); err == nil {
+ t.Errorf("revoked cert login succeeded")
+ }
+ cert.Serial = 1
+
+ t.Log("sign with wrong key")
+ cert.SignCert(rand.Reader, testSigners["dsa"])
+ if err := tryAuth(t, clientConfig); err == nil {
+ t.Errorf("cert login passed with non-authoritive key")
+ }
+
+ t.Log("host cert")
+ cert.CertType = HostCert
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ if err := tryAuth(t, clientConfig); err == nil {
+ t.Errorf("cert login passed with wrong type")
+ }
+ cert.CertType = UserCert
+
+ t.Log("principal specified")
+ cert.ValidPrincipals = []string{"user"}
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ if err := tryAuth(t, clientConfig); err != nil {
+ t.Errorf("cert login failed: %v", err)
+ }
+
+ t.Log("wrong principal specified")
+ cert.ValidPrincipals = []string{"fred"}
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ if err := tryAuth(t, clientConfig); err == nil {
+ t.Errorf("cert login passed with wrong principal")
+ }
+ cert.ValidPrincipals = nil
+
+ t.Log("added critical option")
+ cert.CriticalOptions = map[string]string{"root-access": "yes"}
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ if err := tryAuth(t, clientConfig); err == nil {
+ t.Errorf("cert login passed with unrecognized critical option")
+ }
+
+ t.Log("allowed source address")
+ cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24"}
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ if err := tryAuth(t, clientConfig); err != nil {
+ t.Errorf("cert login with source-address failed: %v", err)
+ }
+
+ t.Log("disallowed source address")
+ cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42"}
+ cert.SignCert(rand.Reader, testSigners["ecdsa"])
+ if err := tryAuth(t, clientConfig); err == nil {
+ t.Errorf("cert login with source-address succeeded")
+ }
+}
+
+func testPermissionsPassing(withPermissions bool, t *testing.T) {
+ serverConfig := &ServerConfig{
+ PublicKeyCallback: func(conn ConnMetadata, key PublicKey) (*Permissions, error) {
+ if conn.User() == "nopermissions" {
+ return nil, nil
+ } else {
+ return &Permissions{}, nil
+ }
+ },
+ }
+ serverConfig.AddHostKey(testSigners["rsa"])
+
+ clientConfig := &ClientConfig{
+ Auth: []AuthMethod{
+ PublicKeys(testSigners["rsa"]),
+ },
+ }
+ if withPermissions {
+ clientConfig.User = "permissions"
+ } else {
+ clientConfig.User = "nopermissions"
+ }
+
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ go NewClientConn(c2, "", clientConfig)
+ serverConn, err := newServer(c1, serverConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p := serverConn.Permissions; (p != nil) != withPermissions {
+ t.Fatalf("withPermissions is %t, but Permissions object is %#v", withPermissions, p)
+ }
+}
+
+func TestPermissionsPassing(t *testing.T) {
+ testPermissionsPassing(true, t)
+}
+
+func TestNoPermissionsPassing(t *testing.T) {
+ testPermissionsPassing(false, t)
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client_test.go b/vendor/golang.org/x/crypto/ssh/client_test.go
new file mode 100644
index 000000000..1fe790cb4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/client_test.go
@@ -0,0 +1,39 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "net"
+ "testing"
+)
+
+func testClientVersion(t *testing.T, config *ClientConfig, expected string) {
+ clientConn, serverConn := net.Pipe()
+ defer clientConn.Close()
+ receivedVersion := make(chan string, 1)
+ go func() {
+ version, err := readVersion(serverConn)
+ if err != nil {
+ receivedVersion <- ""
+ } else {
+ receivedVersion <- string(version)
+ }
+ serverConn.Close()
+ }()
+ NewClientConn(clientConn, "", config)
+ actual := <-receivedVersion
+ if actual != expected {
+ t.Fatalf("got %s; want %s", actual, expected)
+ }
+}
+
+func TestCustomClientVersion(t *testing.T) {
+ version := "Test-Client-Version-0.0"
+ testClientVersion(t, &ClientConfig{ClientVersion: version}, version)
+}
+
+func TestDefaultClientVersion(t *testing.T) {
+ testClientVersion(t, &ClientConfig{}, packageVersion)
+}
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
new file mode 100644
index 000000000..de029d6db
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -0,0 +1,356 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "crypto"
+ "crypto/rand"
+ "fmt"
+ "io"
+ "sync"
+
+ _ "crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+)
+
+// These are string constants in the SSH protocol.
+const (
+ compressionNone = "none"
+ serviceUserAuth = "ssh-userauth"
+ serviceSSH = "ssh-connection"
+)
+
+// supportedCiphers specifies the supported ciphers in preference order.
+var supportedCiphers = []string{
+ "aes128-ctr", "aes192-ctr", "aes256-ctr",
+ "aes128-gcm@openssh.com",
+ "arcfour256", "arcfour128",
+}
+
+// supportedKexAlgos specifies the supported key-exchange algorithms in
+// preference order.
+var supportedKexAlgos = []string{
+ kexAlgoCurve25519SHA256,
+ // P384 and P521 are not constant-time yet, but since we don't
+ // reuse ephemeral keys, using them for ECDH should be OK.
+ kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
+ kexAlgoDH14SHA1, kexAlgoDH1SHA1,
+}
+
+// supportedKexAlgos specifies the supported host-key algorithms (i.e. methods
+// of authenticating servers) in preference order.
+var supportedHostKeyAlgos = []string{
+ CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
+ CertAlgoECDSA384v01, CertAlgoECDSA521v01,
+
+ KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
+ KeyAlgoRSA, KeyAlgoDSA,
+
+ KeyAlgoED25519,
+}
+
+// supportedMACs specifies a default set of MAC algorithms in preference order.
+// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
+// because they have reached the end of their useful life.
+var supportedMACs = []string{
+ "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
+}
+
+var supportedCompressions = []string{compressionNone}
+
+// hashFuncs keeps the mapping of supported algorithms to their respective
+// hashes needed for signature verification.
+var hashFuncs = map[string]crypto.Hash{
+ KeyAlgoRSA: crypto.SHA1,
+ KeyAlgoDSA: crypto.SHA1,
+ KeyAlgoECDSA256: crypto.SHA256,
+ KeyAlgoECDSA384: crypto.SHA384,
+ KeyAlgoECDSA521: crypto.SHA512,
+ CertAlgoRSAv01: crypto.SHA1,
+ CertAlgoDSAv01: crypto.SHA1,
+ CertAlgoECDSA256v01: crypto.SHA256,
+ CertAlgoECDSA384v01: crypto.SHA384,
+ CertAlgoECDSA521v01: crypto.SHA512,
+}
+
+// unexpectedMessageError results when the SSH message that we received didn't
+// match what we wanted.
+func unexpectedMessageError(expected, got uint8) error {
+ return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
+}
+
+// parseError results from a malformed SSH message.
+func parseError(tag uint8) error {
+ return fmt.Errorf("ssh: parse error in message type %d", tag)
+}
+
+func findCommon(what string, client []string, server []string) (common string, err error) {
+ for _, c := range client {
+ for _, s := range server {
+ if c == s {
+ return c, nil
+ }
+ }
+ }
+ return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server)
+}
+
+type directionAlgorithms struct {
+ Cipher string
+ MAC string
+ Compression string
+}
+
+type algorithms struct {
+ kex string
+ hostKey string
+ w directionAlgorithms
+ r directionAlgorithms
+}
+
+func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) {
+ result := &algorithms{}
+
+ result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos)
+ if err != nil {
+ return
+ }
+
+ result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
+ if err != nil {
+ return
+ }
+
+ result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
+ if err != nil {
+ return
+ }
+
+ result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
+ if err != nil {
+ return
+ }
+
+ result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
+ if err != nil {
+ return
+ }
+
+ result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
+ if err != nil {
+ return
+ }
+
+ result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
+ if err != nil {
+ return
+ }
+
+ result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
+ if err != nil {
+ return
+ }
+
+ return result, nil
+}
+
+// If rekeythreshold is too small, we can't make any progress sending
+// stuff.
+const minRekeyThreshold uint64 = 256
+
+// Config contains configuration data common to both ServerConfig and
+// ClientConfig.
+type Config struct {
+ // Rand provides the source of entropy for cryptographic
+ // primitives. If Rand is nil, the cryptographic random reader
+ // in package crypto/rand will be used.
+ Rand io.Reader
+
+ // The maximum number of bytes sent or received after which a
+ // new key is negotiated. It must be at least 256. If
+ // unspecified, 1 gigabyte is used.
+ RekeyThreshold uint64
+
+ // The allowed key exchanges algorithms. If unspecified then a
+ // default set of algorithms is used.
+ KeyExchanges []string
+
+ // The allowed cipher algorithms. If unspecified then a sensible
+ // default is used.
+ Ciphers []string
+
+ // The allowed MAC algorithms. If unspecified then a sensible default
+ // is used.
+ MACs []string
+}
+
+// SetDefaults sets sensible values for unset fields in config. This is
+// exported for testing: Configs passed to SSH functions are copied and have
+// default values set automatically.
+func (c *Config) SetDefaults() {
+ if c.Rand == nil {
+ c.Rand = rand.Reader
+ }
+ if c.Ciphers == nil {
+ c.Ciphers = supportedCiphers
+ }
+ var ciphers []string
+ for _, c := range c.Ciphers {
+ if cipherModes[c] != nil {
+ // reject the cipher if we have no cipherModes definition
+ ciphers = append(ciphers, c)
+ }
+ }
+ c.Ciphers = ciphers
+
+ if c.KeyExchanges == nil {
+ c.KeyExchanges = supportedKexAlgos
+ }
+
+ if c.MACs == nil {
+ c.MACs = supportedMACs
+ }
+
+ if c.RekeyThreshold == 0 {
+ // RFC 4253, section 9 suggests rekeying after 1G.
+ c.RekeyThreshold = 1 << 30
+ }
+ if c.RekeyThreshold < minRekeyThreshold {
+ c.RekeyThreshold = minRekeyThreshold
+ }
+}
+
+// buildDataSignedForAuth returns the data that is signed in order to prove
+// possession of a private key. See RFC 4252, section 7.
+func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
+ data := struct {
+ Session []byte
+ Type byte
+ User string
+ Service string
+ Method string
+ Sign bool
+ Algo []byte
+ PubKey []byte
+ }{
+ sessionId,
+ msgUserAuthRequest,
+ req.User,
+ req.Service,
+ req.Method,
+ true,
+ algo,
+ pubKey,
+ }
+ return Marshal(data)
+}
+
+func appendU16(buf []byte, n uint16) []byte {
+ return append(buf, byte(n>>8), byte(n))
+}
+
+func appendU32(buf []byte, n uint32) []byte {
+ return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
+}
+
+func appendU64(buf []byte, n uint64) []byte {
+ return append(buf,
+ byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
+ byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
+}
+
+func appendInt(buf []byte, n int) []byte {
+ return appendU32(buf, uint32(n))
+}
+
+func appendString(buf []byte, s string) []byte {
+ buf = appendU32(buf, uint32(len(s)))
+ buf = append(buf, s...)
+ return buf
+}
+
+func appendBool(buf []byte, b bool) []byte {
+ if b {
+ return append(buf, 1)
+ }
+ return append(buf, 0)
+}
+
+// newCond is a helper to hide the fact that there is no usable zero
+// value for sync.Cond.
+func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
+
+// window represents the buffer available to clients
+// wishing to write to a channel.
+type window struct {
+ *sync.Cond
+ win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
+ writeWaiters int
+ closed bool
+}
+
+// add adds win to the amount of window available
+// for consumers.
+func (w *window) add(win uint32) bool {
+ // a zero sized window adjust is a noop.
+ if win == 0 {
+ return true
+ }
+ w.L.Lock()
+ if w.win+win < win {
+ w.L.Unlock()
+ return false
+ }
+ w.win += win
+ // It is unusual that multiple goroutines would be attempting to reserve
+ // window space, but not guaranteed. Use broadcast to notify all waiters
+ // that additional window is available.
+ w.Broadcast()
+ w.L.Unlock()
+ return true
+}
+
+// close sets the window to closed, so all reservations fail
+// immediately.
+func (w *window) close() {
+ w.L.Lock()
+ w.closed = true
+ w.Broadcast()
+ w.L.Unlock()
+}
+
+// reserve reserves win from the available window capacity.
+// If no capacity remains, reserve will block. reserve may
+// return less than requested.
+func (w *window) reserve(win uint32) (uint32, error) {
+ var err error
+ w.L.Lock()
+ w.writeWaiters++
+ w.Broadcast()
+ for w.win == 0 && !w.closed {
+ w.Wait()
+ }
+ w.writeWaiters--
+ if w.win < win {
+ win = w.win
+ }
+ w.win -= win
+ if w.closed {
+ err = io.EOF
+ }
+ w.L.Unlock()
+ return win, err
+}
+
+// waitWriterBlocked waits until some goroutine is blocked for further
+// writes. It is used in tests only.
+func (w *window) waitWriterBlocked() {
+ w.Cond.L.Lock()
+ for w.writeWaiters == 0 {
+ w.Cond.Wait()
+ }
+ w.Cond.L.Unlock()
+}
diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go
new file mode 100644
index 000000000..979d919e8
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/connection.go
@@ -0,0 +1,144 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "fmt"
+ "net"
+)
+
+// OpenChannelError is returned if the other side rejects an
+// OpenChannel request.
+type OpenChannelError struct {
+ Reason RejectionReason
+ Message string
+}
+
+func (e *OpenChannelError) Error() string {
+ return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message)
+}
+
+// ConnMetadata holds metadata for the connection.
+type ConnMetadata interface {
+ // User returns the user ID for this connection.
+ // It is empty if no authentication is used.
+ User() string
+
+ // SessionID returns the sesson hash, also denoted by H.
+ SessionID() []byte
+
+ // ClientVersion returns the client's version string as hashed
+ // into the session ID.
+ ClientVersion() []byte
+
+ // ServerVersion returns the server's version string as hashed
+ // into the session ID.
+ ServerVersion() []byte
+
+ // RemoteAddr returns the remote address for this connection.
+ RemoteAddr() net.Addr
+
+ // LocalAddr returns the local address for this connection.
+ LocalAddr() net.Addr
+}
+
+// Conn represents an SSH connection for both server and client roles.
+// Conn is the basis for implementing an application layer, such
+// as ClientConn, which implements the traditional shell access for
+// clients.
+type Conn interface {
+ ConnMetadata
+
+ // SendRequest sends a global request, and returns the
+ // reply. If wantReply is true, it returns the response status
+ // and payload. See also RFC4254, section 4.
+ SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error)
+
+ // OpenChannel tries to open an channel. If the request is
+ // rejected, it returns *OpenChannelError. On success it returns
+ // the SSH Channel and a Go channel for incoming, out-of-band
+ // requests. The Go channel must be serviced, or the
+ // connection will hang.
+ OpenChannel(name string, data []byte) (Channel, <-chan *Request, error)
+
+ // Close closes the underlying network connection
+ Close() error
+
+ // Wait blocks until the connection has shut down, and returns the
+ // error causing the shutdown.
+ Wait() error
+
+ // TODO(hanwen): consider exposing:
+ // RequestKeyChange
+ // Disconnect
+}
+
+// DiscardRequests consumes and rejects all requests from the
+// passed-in channel.
+func DiscardRequests(in <-chan *Request) {
+ for req := range in {
+ if req.WantReply {
+ req.Reply(false, nil)
+ }
+ }
+}
+
+// A connection represents an incoming connection.
+type connection struct {
+ transport *handshakeTransport
+ sshConn
+
+ // The connection protocol.
+ *mux
+}
+
+func (c *connection) Close() error {
+ return c.sshConn.conn.Close()
+}
+
+// sshconn provides net.Conn metadata, but disallows direct reads and
+// writes.
+type sshConn struct {
+ conn net.Conn
+
+ user string
+ sessionID []byte
+ clientVersion []byte
+ serverVersion []byte
+}
+
+func dup(src []byte) []byte {
+ dst := make([]byte, len(src))
+ copy(dst, src)
+ return dst
+}
+
+func (c *sshConn) User() string {
+ return c.user
+}
+
+func (c *sshConn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+func (c *sshConn) Close() error {
+ return c.conn.Close()
+}
+
+func (c *sshConn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+func (c *sshConn) SessionID() []byte {
+ return dup(c.sessionID)
+}
+
+func (c *sshConn) ClientVersion() []byte {
+ return dup(c.clientVersion)
+}
+
+func (c *sshConn) ServerVersion() []byte {
+ return dup(c.serverVersion)
+}
diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go
new file mode 100644
index 000000000..d6be89466
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/doc.go
@@ -0,0 +1,18 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package ssh implements an SSH client and server.
+
+SSH is a transport security protocol, an authentication protocol and a
+family of application protocols. The most typical application level
+protocol is a remote shell and this is specifically implemented. However,
+the multiplexed nature of SSH is exposed to users that wish to support
+others.
+
+References:
+ [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
+ [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
+*/
+package ssh // import "golang.org/x/crypto/ssh"
diff --git a/vendor/golang.org/x/crypto/ssh/example_test.go b/vendor/golang.org/x/crypto/ssh/example_test.go
new file mode 100644
index 000000000..25f995146
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/example_test.go
@@ -0,0 +1,243 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh_test
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net"
+ "net/http"
+
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+func ExampleNewServerConn() {
+ // An SSH server is represented by a ServerConfig, which holds
+ // certificate details and handles authentication of ServerConns.
+ config := &ssh.ServerConfig{
+ PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
+ // Should use constant-time compare (or better, salt+hash) in
+ // a production setting.
+ if c.User() == "testuser" && string(pass) == "tiger" {
+ return nil, nil
+ }
+ return nil, fmt.Errorf("password rejected for %q", c.User())
+ },
+ }
+
+ privateBytes, err := ioutil.ReadFile("id_rsa")
+ if err != nil {
+ panic("Failed to load private key")
+ }
+
+ private, err := ssh.ParsePrivateKey(privateBytes)
+ if err != nil {
+ panic("Failed to parse private key")
+ }
+
+ config.AddHostKey(private)
+
+ // Once a ServerConfig has been configured, connections can be
+ // accepted.
+ listener, err := net.Listen("tcp", "0.0.0.0:2022")
+ if err != nil {
+ panic("failed to listen for connection")
+ }
+ nConn, err := listener.Accept()
+ if err != nil {
+ panic("failed to accept incoming connection")
+ }
+
+ // Before use, a handshake must be performed on the incoming
+ // net.Conn.
+ _, chans, reqs, err := ssh.NewServerConn(nConn, config)
+ if err != nil {
+ panic("failed to handshake")
+ }
+ // The incoming Request channel must be serviced.
+ go ssh.DiscardRequests(reqs)
+
+ // Service the incoming Channel channel.
+ for newChannel := range chans {
+ // Channels have a type, depending on the application level
+ // protocol intended. In the case of a shell, the type is
+ // "session" and ServerShell may be used to present a simple
+ // terminal interface.
+ if newChannel.ChannelType() != "session" {
+ newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
+ continue
+ }
+ channel, requests, err := newChannel.Accept()
+ if err != nil {
+ panic("could not accept channel.")
+ }
+
+ // Sessions have out-of-band requests such as "shell",
+ // "pty-req" and "env". Here we handle only the
+ // "shell" request.
+ go func(in <-chan *ssh.Request) {
+ for req := range in {
+ ok := false
+ switch req.Type {
+ case "shell":
+ ok = true
+ if len(req.Payload) > 0 {
+ // We don't accept any
+ // commands, only the
+ // default shell.
+ ok = false
+ }
+ }
+ req.Reply(ok, nil)
+ }
+ }(requests)
+
+ term := terminal.NewTerminal(channel, "> ")
+
+ go func() {
+ defer channel.Close()
+ for {
+ line, err := term.ReadLine()
+ if err != nil {
+ break
+ }
+ fmt.Println(line)
+ }
+ }()
+ }
+}
+
+func ExampleDial() {
+ // An SSH client is represented with a ClientConn.
+ //
+ // To authenticate with the remote server you must pass at least one
+ // implementation of AuthMethod via the Auth field in ClientConfig.
+ config := &ssh.ClientConfig{
+ User: "username",
+ Auth: []ssh.AuthMethod{
+ ssh.Password("yourpassword"),
+ },
+ }
+ client, err := ssh.Dial("tcp", "yourserver.com:22", config)
+ if err != nil {
+ panic("Failed to dial: " + err.Error())
+ }
+
+ // Each ClientConn can support multiple interactive sessions,
+ // represented by a Session.
+ session, err := client.NewSession()
+ if err != nil {
+ panic("Failed to create session: " + err.Error())
+ }
+ defer session.Close()
+
+ // Once a Session is created, you can execute a single command on
+ // the remote side using the Run method.
+ var b bytes.Buffer
+ session.Stdout = &b
+ if err := session.Run("/usr/bin/whoami"); err != nil {
+ panic("Failed to run: " + err.Error())
+ }
+ fmt.Println(b.String())
+}
+
+func ExamplePublicKeys() {
+ // A public key may be used to authenticate against the remote
+ // server by using an unencrypted PEM-encoded private key file.
+ //
+ // If you have an encrypted private key, the crypto/x509 package
+ // can be used to decrypt it.
+ key, err := ioutil.ReadFile("/home/user/.ssh/id_rsa")
+ if err != nil {
+ log.Fatalf("unable to read private key: %v", err)
+ }
+
+ // Create the Signer for this private key.
+ signer, err := ssh.ParsePrivateKey(key)
+ if err != nil {
+ log.Fatalf("unable to parse private key: %v", err)
+ }
+
+ config := &ssh.ClientConfig{
+ User: "user",
+ Auth: []ssh.AuthMethod{
+ // Use the PublicKeys method for remote authentication.
+ ssh.PublicKeys(signer),
+ },
+ }
+
+ // Connect to the remote server and perform the SSH handshake.
+ client, err := ssh.Dial("tcp", "host.com:22", config)
+ if err != nil {
+ log.Fatalf("unable to connect: %v", err)
+ }
+ defer client.Close()
+}
+
+func ExampleClient_Listen() {
+ config := &ssh.ClientConfig{
+ User: "username",
+ Auth: []ssh.AuthMethod{
+ ssh.Password("password"),
+ },
+ }
+ // Dial your ssh server.
+ conn, err := ssh.Dial("tcp", "localhost:22", config)
+ if err != nil {
+ log.Fatalf("unable to connect: %s", err)
+ }
+ defer conn.Close()
+
+ // Request the remote side to open port 8080 on all interfaces.
+ l, err := conn.Listen("tcp", "0.0.0.0:8080")
+ if err != nil {
+ log.Fatalf("unable to register tcp forward: %v", err)
+ }
+ defer l.Close()
+
+ // Serve HTTP with your SSH server acting as a reverse proxy.
+ http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
+ fmt.Fprintf(resp, "Hello world!\n")
+ }))
+}
+
+func ExampleSession_RequestPty() {
+ // Create client config
+ config := &ssh.ClientConfig{
+ User: "username",
+ Auth: []ssh.AuthMethod{
+ ssh.Password("password"),
+ },
+ }
+ // Connect to ssh server
+ conn, err := ssh.Dial("tcp", "localhost:22", config)
+ if err != nil {
+ log.Fatalf("unable to connect: %s", err)
+ }
+ defer conn.Close()
+ // Create a session
+ session, err := conn.NewSession()
+ if err != nil {
+ log.Fatalf("unable to create session: %s", err)
+ }
+ defer session.Close()
+ // Set up terminal modes
+ modes := ssh.TerminalModes{
+ ssh.ECHO: 0, // disable echoing
+ ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
+ ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
+ }
+ // Request pseudo terminal
+ if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
+ log.Fatalf("request for pseudo terminal failed: %s", err)
+ }
+ // Start remote shell
+ if err := session.Shell(); err != nil {
+ log.Fatalf("failed to start shell: %s", err)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
new file mode 100644
index 000000000..86e2755f9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -0,0 +1,449 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "sync"
+)
+
+// debugHandshake, if set, prints messages sent and received. Key
+// exchange messages are printed as if DH were used, so the debug
+// messages are wrong when using ECDH.
+const debugHandshake = false
+
+// keyingTransport is a packet based transport that supports key
+// changes. It need not be thread-safe. It should pass through
+// msgNewKeys in both directions.
+type keyingTransport interface {
+ packetConn
+
+ // prepareKeyChange sets up a key change. The key change for a
+ // direction will be effected if a msgNewKeys message is sent
+ // or received.
+ prepareKeyChange(*algorithms, *kexResult) error
+}
+
+// handshakeTransport implements rekeying on top of a keyingTransport
+// and offers a thread-safe writePacket() interface.
+type handshakeTransport struct {
+ conn keyingTransport
+ config *Config
+
+ serverVersion []byte
+ clientVersion []byte
+
+ // hostKeys is non-empty if we are the server. In that case,
+ // it contains all host keys that can be used to sign the
+ // connection.
+ hostKeys []Signer
+
+ // hostKeyAlgorithms is non-empty if we are the client. In that case,
+ // we accept these key types from the server as host key.
+ hostKeyAlgorithms []string
+
+ // On read error, incoming is closed, and readError is set.
+ incoming chan []byte
+ readError error
+
+ // data for host key checking
+ hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+ dialAddress string
+ remoteAddr net.Addr
+
+ readSinceKex uint64
+
+ // Protects the writing side of the connection
+ mu sync.Mutex
+ cond *sync.Cond
+ sentInitPacket []byte
+ sentInitMsg *kexInitMsg
+ writtenSinceKex uint64
+ writeError error
+
+ // The session ID or nil if first kex did not complete yet.
+ sessionID []byte
+}
+
+func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport {
+ t := &handshakeTransport{
+ conn: conn,
+ serverVersion: serverVersion,
+ clientVersion: clientVersion,
+ incoming: make(chan []byte, 16),
+ config: config,
+ }
+ t.cond = sync.NewCond(&t.mu)
+ return t
+}
+
+func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport {
+ t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
+ t.dialAddress = dialAddr
+ t.remoteAddr = addr
+ t.hostKeyCallback = config.HostKeyCallback
+ if config.HostKeyAlgorithms != nil {
+ t.hostKeyAlgorithms = config.HostKeyAlgorithms
+ } else {
+ t.hostKeyAlgorithms = supportedHostKeyAlgos
+ }
+ go t.readLoop()
+ return t
+}
+
+func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport {
+ t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion)
+ t.hostKeys = config.hostKeys
+ go t.readLoop()
+ return t
+}
+
+func (t *handshakeTransport) getSessionID() []byte {
+ return t.sessionID
+}
+
+func (t *handshakeTransport) id() string {
+ if len(t.hostKeys) > 0 {
+ return "server"
+ }
+ return "client"
+}
+
+func (t *handshakeTransport) readPacket() ([]byte, error) {
+ p, ok := <-t.incoming
+ if !ok {
+ return nil, t.readError
+ }
+ return p, nil
+}
+
+func (t *handshakeTransport) readLoop() {
+ for {
+ p, err := t.readOnePacket()
+ if err != nil {
+ t.readError = err
+ close(t.incoming)
+ break
+ }
+ if p[0] == msgIgnore || p[0] == msgDebug {
+ continue
+ }
+ t.incoming <- p
+ }
+
+ // If we can't read, declare the writing part dead too.
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ if t.writeError == nil {
+ t.writeError = t.readError
+ }
+ t.cond.Broadcast()
+}
+
+func (t *handshakeTransport) readOnePacket() ([]byte, error) {
+ if t.readSinceKex > t.config.RekeyThreshold {
+ if err := t.requestKeyChange(); err != nil {
+ return nil, err
+ }
+ }
+
+ p, err := t.conn.readPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ t.readSinceKex += uint64(len(p))
+ if debugHandshake {
+ if p[0] == msgChannelData || p[0] == msgChannelExtendedData {
+ log.Printf("%s got data (packet %d bytes)", t.id(), len(p))
+ } else {
+ msg, err := decode(p)
+ log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err)
+ }
+ }
+ if p[0] != msgKexInit {
+ return p, nil
+ }
+
+ t.mu.Lock()
+
+ // By default, a key exchange is hidden from higher layers by
+ // translating it into msgIgnore.
+ successPacket := []byte{msgIgnore}
+ if t.sessionID == nil {
+ // sendKexInit() for the first kex waits for
+ // msgNewKeys so the authentication process is
+ // guaranteed to happen over an encrypted transport.
+ successPacket = []byte{msgNewKeys}
+ }
+
+ err = t.enterKeyExchangeLocked(p)
+ if err != nil {
+ // drop connection
+ t.conn.Close()
+ t.writeError = err
+ }
+
+ if debugHandshake {
+ log.Printf("%s exited key exchange, err %v", t.id(), err)
+ }
+
+ // Unblock writers.
+ t.sentInitMsg = nil
+ t.sentInitPacket = nil
+ t.cond.Broadcast()
+ t.writtenSinceKex = 0
+ t.mu.Unlock()
+
+ if err != nil {
+ return nil, err
+ }
+
+ t.readSinceKex = 0
+ return successPacket, nil
+}
+
+// keyChangeCategory describes whether a key exchange is the first on a
+// connection, or a subsequent one.
+type keyChangeCategory bool
+
+const (
+ firstKeyExchange keyChangeCategory = true
+ subsequentKeyExchange keyChangeCategory = false
+)
+
+// sendKexInit sends a key change message, and returns the message
+// that was sent. After initiating the key change, all writes will be
+// blocked until the change is done, and a failed key change will
+// close the underlying transport. This function is safe for
+// concurrent use by multiple goroutines.
+func (t *handshakeTransport) sendKexInit(isFirst keyChangeCategory) error {
+ t.mu.Lock()
+ // If this is the initial key change, but we already have a sessionID,
+ // then do nothing because the key exchange has already completed
+ // asynchronously.
+ if isFirst && t.sessionID != nil {
+ t.mu.Unlock()
+ return nil
+ }
+
+ _, _, err := t.sendKexInitLocked(isFirst)
+ t.mu.Unlock()
+ if err != nil {
+ return err
+ }
+ if isFirst {
+ if packet, err := t.readPacket(); err != nil {
+ return err
+ } else if packet[0] != msgNewKeys {
+ return unexpectedMessageError(msgNewKeys, packet[0])
+ }
+ }
+ return nil
+}
+
+func (t *handshakeTransport) requestInitialKeyChange() error {
+ return t.sendKexInit(firstKeyExchange)
+}
+
+func (t *handshakeTransport) requestKeyChange() error {
+ return t.sendKexInit(subsequentKeyExchange)
+}
+
+// sendKexInitLocked sends a key change message. t.mu must be locked
+// while this happens.
+func (t *handshakeTransport) sendKexInitLocked(isFirst keyChangeCategory) (*kexInitMsg, []byte, error) {
+ // kexInits may be sent either in response to the other side,
+ // or because our side wants to initiate a key change, so we
+ // may have already sent a kexInit. In that case, don't send a
+ // second kexInit.
+ if t.sentInitMsg != nil {
+ return t.sentInitMsg, t.sentInitPacket, nil
+ }
+
+ msg := &kexInitMsg{
+ KexAlgos: t.config.KeyExchanges,
+ CiphersClientServer: t.config.Ciphers,
+ CiphersServerClient: t.config.Ciphers,
+ MACsClientServer: t.config.MACs,
+ MACsServerClient: t.config.MACs,
+ CompressionClientServer: supportedCompressions,
+ CompressionServerClient: supportedCompressions,
+ }
+ io.ReadFull(rand.Reader, msg.Cookie[:])
+
+ if len(t.hostKeys) > 0 {
+ for _, k := range t.hostKeys {
+ msg.ServerHostKeyAlgos = append(
+ msg.ServerHostKeyAlgos, k.PublicKey().Type())
+ }
+ } else {
+ msg.ServerHostKeyAlgos = t.hostKeyAlgorithms
+ }
+ packet := Marshal(msg)
+
+ // writePacket destroys the contents, so save a copy.
+ packetCopy := make([]byte, len(packet))
+ copy(packetCopy, packet)
+
+ if err := t.conn.writePacket(packetCopy); err != nil {
+ return nil, nil, err
+ }
+
+ t.sentInitMsg = msg
+ t.sentInitPacket = packet
+ return msg, packet, nil
+}
+
+func (t *handshakeTransport) writePacket(p []byte) error {
+ t.mu.Lock()
+ defer t.mu.Unlock()
+
+ if t.writtenSinceKex > t.config.RekeyThreshold {
+ t.sendKexInitLocked(subsequentKeyExchange)
+ }
+ for t.sentInitMsg != nil && t.writeError == nil {
+ t.cond.Wait()
+ }
+ if t.writeError != nil {
+ return t.writeError
+ }
+ t.writtenSinceKex += uint64(len(p))
+
+ switch p[0] {
+ case msgKexInit:
+ return errors.New("ssh: only handshakeTransport can send kexInit")
+ case msgNewKeys:
+ return errors.New("ssh: only handshakeTransport can send newKeys")
+ default:
+ return t.conn.writePacket(p)
+ }
+}
+
+func (t *handshakeTransport) Close() error {
+ return t.conn.Close()
+}
+
+// enterKeyExchange runs the key exchange. t.mu must be held while running this.
+func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) error {
+ if debugHandshake {
+ log.Printf("%s entered key exchange", t.id())
+ }
+ myInit, myInitPacket, err := t.sendKexInitLocked(subsequentKeyExchange)
+ if err != nil {
+ return err
+ }
+
+ otherInit := &kexInitMsg{}
+ if err := Unmarshal(otherInitPacket, otherInit); err != nil {
+ return err
+ }
+
+ magics := handshakeMagics{
+ clientVersion: t.clientVersion,
+ serverVersion: t.serverVersion,
+ clientKexInit: otherInitPacket,
+ serverKexInit: myInitPacket,
+ }
+
+ clientInit := otherInit
+ serverInit := myInit
+ if len(t.hostKeys) == 0 {
+ clientInit = myInit
+ serverInit = otherInit
+
+ magics.clientKexInit = myInitPacket
+ magics.serverKexInit = otherInitPacket
+ }
+
+ algs, err := findAgreedAlgorithms(clientInit, serverInit)
+ if err != nil {
+ return err
+ }
+
+ // We don't send FirstKexFollows, but we handle receiving it.
+ if otherInit.FirstKexFollows && algs.kex != otherInit.KexAlgos[0] {
+ // other side sent a kex message for the wrong algorithm,
+ // which we have to ignore.
+ if _, err := t.conn.readPacket(); err != nil {
+ return err
+ }
+ }
+
+ kex, ok := kexAlgoMap[algs.kex]
+ if !ok {
+ return fmt.Errorf("ssh: unexpected key exchange algorithm %v", algs.kex)
+ }
+
+ var result *kexResult
+ if len(t.hostKeys) > 0 {
+ result, err = t.server(kex, algs, &magics)
+ } else {
+ result, err = t.client(kex, algs, &magics)
+ }
+
+ if err != nil {
+ return err
+ }
+
+ if t.sessionID == nil {
+ t.sessionID = result.H
+ }
+ result.SessionID = t.sessionID
+
+ t.conn.prepareKeyChange(algs, result)
+ if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
+ return err
+ }
+ if packet, err := t.conn.readPacket(); err != nil {
+ return err
+ } else if packet[0] != msgNewKeys {
+ return unexpectedMessageError(msgNewKeys, packet[0])
+ }
+
+ return nil
+}
+
+func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) {
+ var hostKey Signer
+ for _, k := range t.hostKeys {
+ if algs.hostKey == k.PublicKey().Type() {
+ hostKey = k
+ }
+ }
+
+ r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey)
+ return r, err
+}
+
+func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) {
+ result, err := kex.Client(t.conn, t.config.Rand, magics)
+ if err != nil {
+ return nil, err
+ }
+
+ hostKey, err := ParsePublicKey(result.HostKey)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := verifyHostKeySignature(hostKey, result); err != nil {
+ return nil, err
+ }
+
+ if t.hostKeyCallback != nil {
+ err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return result, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/handshake_test.go b/vendor/golang.org/x/crypto/ssh/handshake_test.go
new file mode 100644
index 000000000..da53d3a0d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/handshake_test.go
@@ -0,0 +1,486 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "crypto/rand"
+ "errors"
+ "fmt"
+ "net"
+ "reflect"
+ "runtime"
+ "strings"
+ "sync"
+ "testing"
+)
+
+type testChecker struct {
+ calls []string
+}
+
+func (t *testChecker) Check(dialAddr string, addr net.Addr, key PublicKey) error {
+ if dialAddr == "bad" {
+ return fmt.Errorf("dialAddr is bad")
+ }
+
+ if tcpAddr, ok := addr.(*net.TCPAddr); !ok || tcpAddr == nil {
+ return fmt.Errorf("testChecker: got %T want *net.TCPAddr", addr)
+ }
+
+ t.calls = append(t.calls, fmt.Sprintf("%s %v %s %x", dialAddr, addr, key.Type(), key.Marshal()))
+
+ return nil
+}
+
+// netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
+// therefore is buffered (net.Pipe deadlocks if both sides start with
+// a write.)
+func netPipe() (net.Conn, net.Conn, error) {
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ return nil, nil, err
+ }
+ defer listener.Close()
+ c1, err := net.Dial("tcp", listener.Addr().String())
+ if err != nil {
+ return nil, nil, err
+ }
+
+ c2, err := listener.Accept()
+ if err != nil {
+ c1.Close()
+ return nil, nil, err
+ }
+
+ return c1, c2, nil
+}
+
+func handshakePair(clientConf *ClientConfig, addr string) (client *handshakeTransport, server *handshakeTransport, err error) {
+ a, b, err := netPipe()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ trC := newTransport(a, rand.Reader, true)
+ trS := newTransport(b, rand.Reader, false)
+ clientConf.SetDefaults()
+
+ v := []byte("version")
+ client = newClientTransport(trC, v, v, clientConf, addr, a.RemoteAddr())
+
+ serverConf := &ServerConfig{}
+ serverConf.AddHostKey(testSigners["ecdsa"])
+ serverConf.AddHostKey(testSigners["rsa"])
+ serverConf.SetDefaults()
+ server = newServerTransport(trS, v, v, serverConf)
+
+ return client, server, nil
+}
+
+func TestHandshakeBasic(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("see golang.org/issue/7237")
+ }
+ checker := &testChecker{}
+ trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr")
+ if err != nil {
+ t.Fatalf("handshakePair: %v", err)
+ }
+
+ defer trC.Close()
+ defer trS.Close()
+
+ go func() {
+ // Client writes a bunch of stuff, and does a key
+ // change in the middle. This should not confuse the
+ // handshake in progress
+ for i := 0; i < 10; i++ {
+ p := []byte{msgRequestSuccess, byte(i)}
+ if err := trC.writePacket(p); err != nil {
+ t.Fatalf("sendPacket: %v", err)
+ }
+ if i == 5 {
+ // halfway through, we request a key change.
+ err := trC.sendKexInit(subsequentKeyExchange)
+ if err != nil {
+ t.Fatalf("sendKexInit: %v", err)
+ }
+ }
+ }
+ trC.Close()
+ }()
+
+ // Server checks that client messages come in cleanly
+ i := 0
+ for {
+ p, err := trS.readPacket()
+ if err != nil {
+ break
+ }
+ if p[0] == msgNewKeys {
+ continue
+ }
+ want := []byte{msgRequestSuccess, byte(i)}
+ if bytes.Compare(p, want) != 0 {
+ t.Errorf("message %d: got %q, want %q", i, p, want)
+ }
+ i++
+ }
+ if i != 10 {
+ t.Errorf("received %d messages, want 10.", i)
+ }
+
+ // If all went well, we registered exactly 1 key change.
+ if len(checker.calls) != 1 {
+ t.Fatalf("got %d host key checks, want 1", len(checker.calls))
+ }
+
+ pub := testSigners["ecdsa"].PublicKey()
+ want := fmt.Sprintf("%s %v %s %x", "addr", trC.remoteAddr, pub.Type(), pub.Marshal())
+ if want != checker.calls[0] {
+ t.Errorf("got %q want %q for host key check", checker.calls[0], want)
+ }
+}
+
+func TestHandshakeError(t *testing.T) {
+ checker := &testChecker{}
+ trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "bad")
+ if err != nil {
+ t.Fatalf("handshakePair: %v", err)
+ }
+ defer trC.Close()
+ defer trS.Close()
+
+ // send a packet
+ packet := []byte{msgRequestSuccess, 42}
+ if err := trC.writePacket(packet); err != nil {
+ t.Errorf("writePacket: %v", err)
+ }
+
+ // Now request a key change.
+ err = trC.sendKexInit(subsequentKeyExchange)
+ if err != nil {
+ t.Errorf("sendKexInit: %v", err)
+ }
+
+ // the key change will fail, and afterwards we can't write.
+ if err := trC.writePacket([]byte{msgRequestSuccess, 43}); err == nil {
+ t.Errorf("writePacket after botched rekey succeeded.")
+ }
+
+ readback, err := trS.readPacket()
+ if err != nil {
+ t.Fatalf("server closed too soon: %v", err)
+ }
+ if bytes.Compare(readback, packet) != 0 {
+ t.Errorf("got %q want %q", readback, packet)
+ }
+ readback, err = trS.readPacket()
+ if err == nil {
+ t.Errorf("got a message %q after failed key change", readback)
+ }
+}
+
+func TestForceFirstKex(t *testing.T) {
+ checker := &testChecker{}
+ trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr")
+ if err != nil {
+ t.Fatalf("handshakePair: %v", err)
+ }
+
+ defer trC.Close()
+ defer trS.Close()
+
+ trC.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth}))
+
+ // We setup the initial key exchange, but the remote side
+ // tries to send serviceRequestMsg in cleartext, which is
+ // disallowed.
+
+ err = trS.sendKexInit(firstKeyExchange)
+ if err == nil {
+ t.Errorf("server first kex init should reject unexpected packet")
+ }
+}
+
+func TestHandshakeTwice(t *testing.T) {
+ checker := &testChecker{}
+ trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr")
+ if err != nil {
+ t.Fatalf("handshakePair: %v", err)
+ }
+
+ defer trC.Close()
+ defer trS.Close()
+
+ // Both sides should ask for the first key exchange first.
+ err = trS.sendKexInit(firstKeyExchange)
+ if err != nil {
+ t.Errorf("server sendKexInit: %v", err)
+ }
+
+ err = trC.sendKexInit(firstKeyExchange)
+ if err != nil {
+ t.Errorf("client sendKexInit: %v", err)
+ }
+
+ sent := 0
+ // send a packet
+ packet := make([]byte, 5)
+ packet[0] = msgRequestSuccess
+ if err := trC.writePacket(packet); err != nil {
+ t.Errorf("writePacket: %v", err)
+ }
+ sent++
+
+ // Send another packet. Use a fresh one, since writePacket destroys.
+ packet = make([]byte, 5)
+ packet[0] = msgRequestSuccess
+ if err := trC.writePacket(packet); err != nil {
+ t.Errorf("writePacket: %v", err)
+ }
+ sent++
+
+ // 2nd key change.
+ err = trC.sendKexInit(subsequentKeyExchange)
+ if err != nil {
+ t.Errorf("sendKexInit: %v", err)
+ }
+
+ packet = make([]byte, 5)
+ packet[0] = msgRequestSuccess
+ if err := trC.writePacket(packet); err != nil {
+ t.Errorf("writePacket: %v", err)
+ }
+ sent++
+
+ packet = make([]byte, 5)
+ packet[0] = msgRequestSuccess
+ for i := 0; i < sent; i++ {
+ msg, err := trS.readPacket()
+ if err != nil {
+ t.Fatalf("server closed too soon: %v", err)
+ }
+
+ if bytes.Compare(msg, packet) != 0 {
+ t.Errorf("packet %d: got %q want %q", i, msg, packet)
+ }
+ }
+ if len(checker.calls) != 2 {
+ t.Errorf("got %d key changes, want 2", len(checker.calls))
+ }
+}
+
+func TestHandshakeAutoRekeyWrite(t *testing.T) {
+ checker := &testChecker{}
+ clientConf := &ClientConfig{HostKeyCallback: checker.Check}
+ clientConf.RekeyThreshold = 500
+ trC, trS, err := handshakePair(clientConf, "addr")
+ if err != nil {
+ t.Fatalf("handshakePair: %v", err)
+ }
+ defer trC.Close()
+ defer trS.Close()
+
+ for i := 0; i < 5; i++ {
+ packet := make([]byte, 251)
+ packet[0] = msgRequestSuccess
+ if err := trC.writePacket(packet); err != nil {
+ t.Errorf("writePacket: %v", err)
+ }
+ }
+
+ j := 0
+ for ; j < 5; j++ {
+ _, err := trS.readPacket()
+ if err != nil {
+ break
+ }
+ }
+
+ if j != 5 {
+ t.Errorf("got %d, want 5 messages", j)
+ }
+
+ if len(checker.calls) != 2 {
+ t.Errorf("got %d key changes, wanted 2", len(checker.calls))
+ }
+}
+
+type syncChecker struct {
+ called chan int
+}
+
+func (t *syncChecker) Check(dialAddr string, addr net.Addr, key PublicKey) error {
+ t.called <- 1
+ return nil
+}
+
+func TestHandshakeAutoRekeyRead(t *testing.T) {
+ sync := &syncChecker{make(chan int, 2)}
+ clientConf := &ClientConfig{
+ HostKeyCallback: sync.Check,
+ }
+ clientConf.RekeyThreshold = 500
+
+ trC, trS, err := handshakePair(clientConf, "addr")
+ if err != nil {
+ t.Fatalf("handshakePair: %v", err)
+ }
+ defer trC.Close()
+ defer trS.Close()
+
+ packet := make([]byte, 501)
+ packet[0] = msgRequestSuccess
+ if err := trS.writePacket(packet); err != nil {
+ t.Fatalf("writePacket: %v", err)
+ }
+ // While we read out the packet, a key change will be
+ // initiated.
+ if _, err := trC.readPacket(); err != nil {
+ t.Fatalf("readPacket(client): %v", err)
+ }
+
+ <-sync.called
+}
+
+// errorKeyingTransport generates errors after a given number of
+// read/write operations.
+type errorKeyingTransport struct {
+ packetConn
+ readLeft, writeLeft int
+}
+
+func (n *errorKeyingTransport) prepareKeyChange(*algorithms, *kexResult) error {
+ return nil
+}
+func (n *errorKeyingTransport) getSessionID() []byte {
+ return nil
+}
+
+func (n *errorKeyingTransport) writePacket(packet []byte) error {
+ if n.writeLeft == 0 {
+ n.Close()
+ return errors.New("barf")
+ }
+
+ n.writeLeft--
+ return n.packetConn.writePacket(packet)
+}
+
+func (n *errorKeyingTransport) readPacket() ([]byte, error) {
+ if n.readLeft == 0 {
+ n.Close()
+ return nil, errors.New("barf")
+ }
+
+ n.readLeft--
+ return n.packetConn.readPacket()
+}
+
+func TestHandshakeErrorHandlingRead(t *testing.T) {
+ for i := 0; i < 20; i++ {
+ testHandshakeErrorHandlingN(t, i, -1)
+ }
+}
+
+func TestHandshakeErrorHandlingWrite(t *testing.T) {
+ for i := 0; i < 20; i++ {
+ testHandshakeErrorHandlingN(t, -1, i)
+ }
+}
+
+// testHandshakeErrorHandlingN runs handshakes, injecting errors. If
+// handshakeTransport deadlocks, the go runtime will detect it and
+// panic.
+func testHandshakeErrorHandlingN(t *testing.T, readLimit, writeLimit int) {
+ msg := Marshal(&serviceRequestMsg{strings.Repeat("x", int(minRekeyThreshold)/4)})
+
+ a, b := memPipe()
+ defer a.Close()
+ defer b.Close()
+
+ key := testSigners["ecdsa"]
+ serverConf := Config{RekeyThreshold: minRekeyThreshold}
+ serverConf.SetDefaults()
+ serverConn := newHandshakeTransport(&errorKeyingTransport{a, readLimit, writeLimit}, &serverConf, []byte{'a'}, []byte{'b'})
+ serverConn.hostKeys = []Signer{key}
+ go serverConn.readLoop()
+
+ clientConf := Config{RekeyThreshold: 10 * minRekeyThreshold}
+ clientConf.SetDefaults()
+ clientConn := newHandshakeTransport(&errorKeyingTransport{b, -1, -1}, &clientConf, []byte{'a'}, []byte{'b'})
+ clientConn.hostKeyAlgorithms = []string{key.PublicKey().Type()}
+ go clientConn.readLoop()
+
+ var wg sync.WaitGroup
+ wg.Add(4)
+
+ for _, hs := range []packetConn{serverConn, clientConn} {
+ go func(c packetConn) {
+ for {
+ err := c.writePacket(msg)
+ if err != nil {
+ break
+ }
+ }
+ wg.Done()
+ }(hs)
+ go func(c packetConn) {
+ for {
+ _, err := c.readPacket()
+ if err != nil {
+ break
+ }
+ }
+ wg.Done()
+ }(hs)
+ }
+
+ wg.Wait()
+}
+
+func TestDisconnect(t *testing.T) {
+ if runtime.GOOS == "plan9" {
+ t.Skip("see golang.org/issue/7237")
+ }
+ checker := &testChecker{}
+ trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr")
+ if err != nil {
+ t.Fatalf("handshakePair: %v", err)
+ }
+
+ defer trC.Close()
+ defer trS.Close()
+
+ trC.writePacket([]byte{msgRequestSuccess, 0, 0})
+ errMsg := &disconnectMsg{
+ Reason: 42,
+ Message: "such is life",
+ }
+ trC.writePacket(Marshal(errMsg))
+ trC.writePacket([]byte{msgRequestSuccess, 0, 0})
+
+ packet, err := trS.readPacket()
+ if err != nil {
+ t.Fatalf("readPacket 1: %v", err)
+ }
+ if packet[0] != msgRequestSuccess {
+ t.Errorf("got packet %v, want packet type %d", packet, msgRequestSuccess)
+ }
+
+ _, err = trS.readPacket()
+ if err == nil {
+ t.Errorf("readPacket 2 succeeded")
+ } else if !reflect.DeepEqual(err, errMsg) {
+ t.Errorf("got error %#v, want %#v", err, errMsg)
+ }
+
+ _, err = trS.readPacket()
+ if err == nil {
+ t.Errorf("readPacket 3 succeeded")
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go
new file mode 100644
index 000000000..9285ee31d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/kex.go
@@ -0,0 +1,526 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/subtle"
+ "errors"
+ "io"
+ "math/big"
+
+ "golang.org/x/crypto/curve25519"
+)
+
+const (
+ kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
+ kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
+ kexAlgoECDH256 = "ecdh-sha2-nistp256"
+ kexAlgoECDH384 = "ecdh-sha2-nistp384"
+ kexAlgoECDH521 = "ecdh-sha2-nistp521"
+ kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org"
+)
+
+// kexResult captures the outcome of a key exchange.
+type kexResult struct {
+ // Session hash. See also RFC 4253, section 8.
+ H []byte
+
+ // Shared secret. See also RFC 4253, section 8.
+ K []byte
+
+ // Host key as hashed into H.
+ HostKey []byte
+
+ // Signature of H.
+ Signature []byte
+
+ // A cryptographic hash function that matches the security
+ // level of the key exchange algorithm. It is used for
+ // calculating H, and for deriving keys from H and K.
+ Hash crypto.Hash
+
+ // The session ID, which is the first H computed. This is used
+ // to derive key material inside the transport.
+ SessionID []byte
+}
+
+// handshakeMagics contains data that is always included in the
+// session hash.
+type handshakeMagics struct {
+ clientVersion, serverVersion []byte
+ clientKexInit, serverKexInit []byte
+}
+
+func (m *handshakeMagics) write(w io.Writer) {
+ writeString(w, m.clientVersion)
+ writeString(w, m.serverVersion)
+ writeString(w, m.clientKexInit)
+ writeString(w, m.serverKexInit)
+}
+
+// kexAlgorithm abstracts different key exchange algorithms.
+type kexAlgorithm interface {
+ // Server runs server-side key agreement, signing the result
+ // with a hostkey.
+ Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error)
+
+ // Client runs the client-side key agreement. Caller is
+ // responsible for verifying the host key signature.
+ Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error)
+}
+
+// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
+type dhGroup struct {
+ g, p *big.Int
+}
+
+func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
+ if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
+ return nil, errors.New("ssh: DH parameter out of bounds")
+ }
+ return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
+}
+
+func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) {
+ hashFunc := crypto.SHA1
+
+ x, err := rand.Int(randSource, group.p)
+ if err != nil {
+ return nil, err
+ }
+ X := new(big.Int).Exp(group.g, x, group.p)
+ kexDHInit := kexDHInitMsg{
+ X: X,
+ }
+ if err := c.writePacket(Marshal(&kexDHInit)); err != nil {
+ return nil, err
+ }
+
+ packet, err := c.readPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ var kexDHReply kexDHReplyMsg
+ if err = Unmarshal(packet, &kexDHReply); err != nil {
+ return nil, err
+ }
+
+ kInt, err := group.diffieHellman(kexDHReply.Y, x)
+ if err != nil {
+ return nil, err
+ }
+
+ h := hashFunc.New()
+ magics.write(h)
+ writeString(h, kexDHReply.HostKey)
+ writeInt(h, X)
+ writeInt(h, kexDHReply.Y)
+ K := make([]byte, intLength(kInt))
+ marshalInt(K, kInt)
+ h.Write(K)
+
+ return &kexResult{
+ H: h.Sum(nil),
+ K: K,
+ HostKey: kexDHReply.HostKey,
+ Signature: kexDHReply.Signature,
+ Hash: crypto.SHA1,
+ }, nil
+}
+
+func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
+ hashFunc := crypto.SHA1
+ packet, err := c.readPacket()
+ if err != nil {
+ return
+ }
+ var kexDHInit kexDHInitMsg
+ if err = Unmarshal(packet, &kexDHInit); err != nil {
+ return
+ }
+
+ y, err := rand.Int(randSource, group.p)
+ if err != nil {
+ return
+ }
+
+ Y := new(big.Int).Exp(group.g, y, group.p)
+ kInt, err := group.diffieHellman(kexDHInit.X, y)
+ if err != nil {
+ return nil, err
+ }
+
+ hostKeyBytes := priv.PublicKey().Marshal()
+
+ h := hashFunc.New()
+ magics.write(h)
+ writeString(h, hostKeyBytes)
+ writeInt(h, kexDHInit.X)
+ writeInt(h, Y)
+
+ K := make([]byte, intLength(kInt))
+ marshalInt(K, kInt)
+ h.Write(K)
+
+ H := h.Sum(nil)
+
+ // H is already a hash, but the hostkey signing will apply its
+ // own key-specific hash algorithm.
+ sig, err := signAndMarshal(priv, randSource, H)
+ if err != nil {
+ return nil, err
+ }
+
+ kexDHReply := kexDHReplyMsg{
+ HostKey: hostKeyBytes,
+ Y: Y,
+ Signature: sig,
+ }
+ packet = Marshal(&kexDHReply)
+
+ err = c.writePacket(packet)
+ return &kexResult{
+ H: H,
+ K: K,
+ HostKey: hostKeyBytes,
+ Signature: sig,
+ Hash: crypto.SHA1,
+ }, nil
+}
+
+// ecdh performs Elliptic Curve Diffie-Hellman key exchange as
+// described in RFC 5656, section 4.
+type ecdh struct {
+ curve elliptic.Curve
+}
+
+func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
+ ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
+ if err != nil {
+ return nil, err
+ }
+
+ kexInit := kexECDHInitMsg{
+ ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
+ }
+
+ serialized := Marshal(&kexInit)
+ if err := c.writePacket(serialized); err != nil {
+ return nil, err
+ }
+
+ packet, err := c.readPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ var reply kexECDHReplyMsg
+ if err = Unmarshal(packet, &reply); err != nil {
+ return nil, err
+ }
+
+ x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey)
+ if err != nil {
+ return nil, err
+ }
+
+ // generate shared secret
+ secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes())
+
+ h := ecHash(kex.curve).New()
+ magics.write(h)
+ writeString(h, reply.HostKey)
+ writeString(h, kexInit.ClientPubKey)
+ writeString(h, reply.EphemeralPubKey)
+ K := make([]byte, intLength(secret))
+ marshalInt(K, secret)
+ h.Write(K)
+
+ return &kexResult{
+ H: h.Sum(nil),
+ K: K,
+ HostKey: reply.HostKey,
+ Signature: reply.Signature,
+ Hash: ecHash(kex.curve),
+ }, nil
+}
+
+// unmarshalECKey parses and checks an EC key.
+func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) {
+ x, y = elliptic.Unmarshal(curve, pubkey)
+ if x == nil {
+ return nil, nil, errors.New("ssh: elliptic.Unmarshal failure")
+ }
+ if !validateECPublicKey(curve, x, y) {
+ return nil, nil, errors.New("ssh: public key not on curve")
+ }
+ return x, y, nil
+}
+
+// validateECPublicKey checks that the point is a valid public key for
+// the given curve. See [SEC1], 3.2.2
+func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool {
+ if x.Sign() == 0 && y.Sign() == 0 {
+ return false
+ }
+
+ if x.Cmp(curve.Params().P) >= 0 {
+ return false
+ }
+
+ if y.Cmp(curve.Params().P) >= 0 {
+ return false
+ }
+
+ if !curve.IsOnCurve(x, y) {
+ return false
+ }
+
+ // We don't check if N * PubKey == 0, since
+ //
+ // - the NIST curves have cofactor = 1, so this is implicit.
+ // (We don't foresee an implementation that supports non NIST
+ // curves)
+ //
+ // - for ephemeral keys, we don't need to worry about small
+ // subgroup attacks.
+ return true
+}
+
+func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
+ packet, err := c.readPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ var kexECDHInit kexECDHInitMsg
+ if err = Unmarshal(packet, &kexECDHInit); err != nil {
+ return nil, err
+ }
+
+ clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey)
+ if err != nil {
+ return nil, err
+ }
+
+ // We could cache this key across multiple users/multiple
+ // connection attempts, but the benefit is small. OpenSSH
+ // generates a new key for each incoming connection.
+ ephKey, err := ecdsa.GenerateKey(kex.curve, rand)
+ if err != nil {
+ return nil, err
+ }
+
+ hostKeyBytes := priv.PublicKey().Marshal()
+
+ serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y)
+
+ // generate shared secret
+ secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes())
+
+ h := ecHash(kex.curve).New()
+ magics.write(h)
+ writeString(h, hostKeyBytes)
+ writeString(h, kexECDHInit.ClientPubKey)
+ writeString(h, serializedEphKey)
+
+ K := make([]byte, intLength(secret))
+ marshalInt(K, secret)
+ h.Write(K)
+
+ H := h.Sum(nil)
+
+ // H is already a hash, but the hostkey signing will apply its
+ // own key-specific hash algorithm.
+ sig, err := signAndMarshal(priv, rand, H)
+ if err != nil {
+ return nil, err
+ }
+
+ reply := kexECDHReplyMsg{
+ EphemeralPubKey: serializedEphKey,
+ HostKey: hostKeyBytes,
+ Signature: sig,
+ }
+
+ serialized := Marshal(&reply)
+ if err := c.writePacket(serialized); err != nil {
+ return nil, err
+ }
+
+ return &kexResult{
+ H: H,
+ K: K,
+ HostKey: reply.HostKey,
+ Signature: sig,
+ Hash: ecHash(kex.curve),
+ }, nil
+}
+
+var kexAlgoMap = map[string]kexAlgorithm{}
+
+func init() {
+ // This is the group called diffie-hellman-group1-sha1 in RFC
+ // 4253 and Oakley Group 2 in RFC 2409.
+ p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
+ kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{
+ g: new(big.Int).SetInt64(2),
+ p: p,
+ }
+
+ // This is the group called diffie-hellman-group14-sha1 in RFC
+ // 4253 and Oakley Group 14 in RFC 3526.
+ p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
+
+ kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{
+ g: new(big.Int).SetInt64(2),
+ p: p,
+ }
+
+ kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()}
+ kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()}
+ kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()}
+ kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{}
+}
+
+// curve25519sha256 implements the curve25519-sha256@libssh.org key
+// agreement protocol, as described in
+// https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt
+type curve25519sha256 struct{}
+
+type curve25519KeyPair struct {
+ priv [32]byte
+ pub [32]byte
+}
+
+func (kp *curve25519KeyPair) generate(rand io.Reader) error {
+ if _, err := io.ReadFull(rand, kp.priv[:]); err != nil {
+ return err
+ }
+ curve25519.ScalarBaseMult(&kp.pub, &kp.priv)
+ return nil
+}
+
+// curve25519Zeros is just an array of 32 zero bytes so that we have something
+// convenient to compare against in order to reject curve25519 points with the
+// wrong order.
+var curve25519Zeros [32]byte
+
+func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) {
+ var kp curve25519KeyPair
+ if err := kp.generate(rand); err != nil {
+ return nil, err
+ }
+ if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil {
+ return nil, err
+ }
+
+ packet, err := c.readPacket()
+ if err != nil {
+ return nil, err
+ }
+
+ var reply kexECDHReplyMsg
+ if err = Unmarshal(packet, &reply); err != nil {
+ return nil, err
+ }
+ if len(reply.EphemeralPubKey) != 32 {
+ return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
+ }
+
+ var servPub, secret [32]byte
+ copy(servPub[:], reply.EphemeralPubKey)
+ curve25519.ScalarMult(&secret, &kp.priv, &servPub)
+ if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
+ return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
+ }
+
+ h := crypto.SHA256.New()
+ magics.write(h)
+ writeString(h, reply.HostKey)
+ writeString(h, kp.pub[:])
+ writeString(h, reply.EphemeralPubKey)
+
+ kInt := new(big.Int).SetBytes(secret[:])
+ K := make([]byte, intLength(kInt))
+ marshalInt(K, kInt)
+ h.Write(K)
+
+ return &kexResult{
+ H: h.Sum(nil),
+ K: K,
+ HostKey: reply.HostKey,
+ Signature: reply.Signature,
+ Hash: crypto.SHA256,
+ }, nil
+}
+
+func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) {
+ packet, err := c.readPacket()
+ if err != nil {
+ return
+ }
+ var kexInit kexECDHInitMsg
+ if err = Unmarshal(packet, &kexInit); err != nil {
+ return
+ }
+
+ if len(kexInit.ClientPubKey) != 32 {
+ return nil, errors.New("ssh: peer's curve25519 public value has wrong length")
+ }
+
+ var kp curve25519KeyPair
+ if err := kp.generate(rand); err != nil {
+ return nil, err
+ }
+
+ var clientPub, secret [32]byte
+ copy(clientPub[:], kexInit.ClientPubKey)
+ curve25519.ScalarMult(&secret, &kp.priv, &clientPub)
+ if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 {
+ return nil, errors.New("ssh: peer's curve25519 public value has wrong order")
+ }
+
+ hostKeyBytes := priv.PublicKey().Marshal()
+
+ h := crypto.SHA256.New()
+ magics.write(h)
+ writeString(h, hostKeyBytes)
+ writeString(h, kexInit.ClientPubKey)
+ writeString(h, kp.pub[:])
+
+ kInt := new(big.Int).SetBytes(secret[:])
+ K := make([]byte, intLength(kInt))
+ marshalInt(K, kInt)
+ h.Write(K)
+
+ H := h.Sum(nil)
+
+ sig, err := signAndMarshal(priv, rand, H)
+ if err != nil {
+ return nil, err
+ }
+
+ reply := kexECDHReplyMsg{
+ EphemeralPubKey: kp.pub[:],
+ HostKey: hostKeyBytes,
+ Signature: sig,
+ }
+ if err := c.writePacket(Marshal(&reply)); err != nil {
+ return nil, err
+ }
+ return &kexResult{
+ H: H,
+ K: K,
+ HostKey: hostKeyBytes,
+ Signature: sig,
+ Hash: crypto.SHA256,
+ }, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/kex_test.go b/vendor/golang.org/x/crypto/ssh/kex_test.go
new file mode 100644
index 000000000..12ca0acd3
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/kex_test.go
@@ -0,0 +1,50 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+// Key exchange tests.
+
+import (
+ "crypto/rand"
+ "reflect"
+ "testing"
+)
+
+func TestKexes(t *testing.T) {
+ type kexResultErr struct {
+ result *kexResult
+ err error
+ }
+
+ for name, kex := range kexAlgoMap {
+ a, b := memPipe()
+
+ s := make(chan kexResultErr, 1)
+ c := make(chan kexResultErr, 1)
+ var magics handshakeMagics
+ go func() {
+ r, e := kex.Client(a, rand.Reader, &magics)
+ a.Close()
+ c <- kexResultErr{r, e}
+ }()
+ go func() {
+ r, e := kex.Server(b, rand.Reader, &magics, testSigners["ecdsa"])
+ b.Close()
+ s <- kexResultErr{r, e}
+ }()
+
+ clientRes := <-c
+ serverRes := <-s
+ if clientRes.err != nil {
+ t.Errorf("client: %v", clientRes.err)
+ }
+ if serverRes.err != nil {
+ t.Errorf("server: %v", serverRes.err)
+ }
+ if !reflect.DeepEqual(clientRes.result, serverRes.result) {
+ t.Errorf("kex %q: mismatch %#v, %#v", name, clientRes.result, serverRes.result)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
new file mode 100644
index 000000000..d6167e783
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -0,0 +1,846 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/asn1"
+ "encoding/base64"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "strings"
+
+ "golang.org/x/crypto/ed25519"
+)
+
+// These constants represent the algorithm names for key types supported by this
+// package.
+const (
+ KeyAlgoRSA = "ssh-rsa"
+ KeyAlgoDSA = "ssh-dss"
+ KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
+ KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
+ KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
+ KeyAlgoED25519 = "ssh-ed25519"
+)
+
+// parsePubKey parses a public key of the given algorithm.
+// Use ParsePublicKey for keys with prepended algorithm.
+func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) {
+ switch algo {
+ case KeyAlgoRSA:
+ return parseRSA(in)
+ case KeyAlgoDSA:
+ return parseDSA(in)
+ case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
+ return parseECDSA(in)
+ case KeyAlgoED25519:
+ return parseED25519(in)
+ case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01:
+ cert, err := parseCert(in, certToPrivAlgo(algo))
+ if err != nil {
+ return nil, nil, err
+ }
+ return cert, nil, nil
+ }
+ return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo)
+}
+
+// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format
+// (see sshd(8) manual page) once the options and key type fields have been
+// removed.
+func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) {
+ in = bytes.TrimSpace(in)
+
+ i := bytes.IndexAny(in, " \t")
+ if i == -1 {
+ i = len(in)
+ }
+ base64Key := in[:i]
+
+ key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key)))
+ n, err := base64.StdEncoding.Decode(key, base64Key)
+ if err != nil {
+ return nil, "", err
+ }
+ key = key[:n]
+ out, err = ParsePublicKey(key)
+ if err != nil {
+ return nil, "", err
+ }
+ comment = string(bytes.TrimSpace(in[i:]))
+ return out, comment, nil
+}
+
+// ParseKnownHosts parses an entry in the format of the known_hosts file.
+//
+// The known_hosts format is documented in the sshd(8) manual page. This
+// function will parse a single entry from in. On successful return, marker
+// will contain the optional marker value (i.e. "cert-authority" or "revoked")
+// or else be empty, hosts will contain the hosts that this entry matches,
+// pubKey will contain the public key and comment will contain any trailing
+// comment at the end of the line. See the sshd(8) manual page for the various
+// forms that a host string can take.
+//
+// The unparsed remainder of the input will be returned in rest. This function
+// can be called repeatedly to parse multiple entries.
+//
+// If no entries were found in the input then err will be io.EOF. Otherwise a
+// non-nil err value indicates a parse error.
+func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) {
+ for len(in) > 0 {
+ end := bytes.IndexByte(in, '\n')
+ if end != -1 {
+ rest = in[end+1:]
+ in = in[:end]
+ } else {
+ rest = nil
+ }
+
+ end = bytes.IndexByte(in, '\r')
+ if end != -1 {
+ in = in[:end]
+ }
+
+ in = bytes.TrimSpace(in)
+ if len(in) == 0 || in[0] == '#' {
+ in = rest
+ continue
+ }
+
+ i := bytes.IndexAny(in, " \t")
+ if i == -1 {
+ in = rest
+ continue
+ }
+
+ // Strip out the begining of the known_host key.
+ // This is either an optional marker or a (set of) hostname(s).
+ keyFields := bytes.Fields(in)
+ if len(keyFields) < 3 || len(keyFields) > 5 {
+ return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data")
+ }
+
+ // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated
+ // list of hosts
+ marker := ""
+ if keyFields[0][0] == '@' {
+ marker = string(keyFields[0][1:])
+ keyFields = keyFields[1:]
+ }
+
+ hosts := string(keyFields[0])
+ // keyFields[1] contains the key type (e.g. “ssh-rsa”).
+ // However, that information is duplicated inside the
+ // base64-encoded key and so is ignored here.
+
+ key := bytes.Join(keyFields[2:], []byte(" "))
+ if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
+ return "", nil, nil, "", nil, err
+ }
+
+ return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
+ }
+
+ return "", nil, nil, "", nil, io.EOF
+}
+
+// ParseAuthorizedKeys parses a public key from an authorized_keys
+// file used in OpenSSH according to the sshd(8) manual page.
+func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
+ for len(in) > 0 {
+ end := bytes.IndexByte(in, '\n')
+ if end != -1 {
+ rest = in[end+1:]
+ in = in[:end]
+ } else {
+ rest = nil
+ }
+
+ end = bytes.IndexByte(in, '\r')
+ if end != -1 {
+ in = in[:end]
+ }
+
+ in = bytes.TrimSpace(in)
+ if len(in) == 0 || in[0] == '#' {
+ in = rest
+ continue
+ }
+
+ i := bytes.IndexAny(in, " \t")
+ if i == -1 {
+ in = rest
+ continue
+ }
+
+ if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
+ return out, comment, options, rest, nil
+ }
+
+ // No key type recognised. Maybe there's an options field at
+ // the beginning.
+ var b byte
+ inQuote := false
+ var candidateOptions []string
+ optionStart := 0
+ for i, b = range in {
+ isEnd := !inQuote && (b == ' ' || b == '\t')
+ if (b == ',' && !inQuote) || isEnd {
+ if i-optionStart > 0 {
+ candidateOptions = append(candidateOptions, string(in[optionStart:i]))
+ }
+ optionStart = i + 1
+ }
+ if isEnd {
+ break
+ }
+ if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) {
+ inQuote = !inQuote
+ }
+ }
+ for i < len(in) && (in[i] == ' ' || in[i] == '\t') {
+ i++
+ }
+ if i == len(in) {
+ // Invalid line: unmatched quote
+ in = rest
+ continue
+ }
+
+ in = in[i:]
+ i = bytes.IndexAny(in, " \t")
+ if i == -1 {
+ in = rest
+ continue
+ }
+
+ if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
+ options = candidateOptions
+ return out, comment, options, rest, nil
+ }
+
+ in = rest
+ continue
+ }
+
+ return nil, "", nil, nil, errors.New("ssh: no key found")
+}
+
+// ParsePublicKey parses an SSH public key formatted for use in
+// the SSH wire protocol according to RFC 4253, section 6.6.
+func ParsePublicKey(in []byte) (out PublicKey, err error) {
+ algo, in, ok := parseString(in)
+ if !ok {
+ return nil, errShortRead
+ }
+ var rest []byte
+ out, rest, err = parsePubKey(in, string(algo))
+ if len(rest) > 0 {
+ return nil, errors.New("ssh: trailing junk in public key")
+ }
+
+ return out, err
+}
+
+// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH
+// authorized_keys file. The return value ends with newline.
+func MarshalAuthorizedKey(key PublicKey) []byte {
+ b := &bytes.Buffer{}
+ b.WriteString(key.Type())
+ b.WriteByte(' ')
+ e := base64.NewEncoder(base64.StdEncoding, b)
+ e.Write(key.Marshal())
+ e.Close()
+ b.WriteByte('\n')
+ return b.Bytes()
+}
+
+// PublicKey is an abstraction of different types of public keys.
+type PublicKey interface {
+ // Type returns the key's type, e.g. "ssh-rsa".
+ Type() string
+
+ // Marshal returns the serialized key data in SSH wire format,
+ // with the name prefix.
+ Marshal() []byte
+
+ // Verify that sig is a signature on the given data using this
+ // key. This function will hash the data appropriately first.
+ Verify(data []byte, sig *Signature) error
+}
+
+// A Signer can create signatures that verify against a public key.
+type Signer interface {
+ // PublicKey returns an associated PublicKey instance.
+ PublicKey() PublicKey
+
+ // Sign returns raw signature for the given data. This method
+ // will apply the hash specified for the keytype to the data.
+ Sign(rand io.Reader, data []byte) (*Signature, error)
+}
+
+type rsaPublicKey rsa.PublicKey
+
+func (r *rsaPublicKey) Type() string {
+ return "ssh-rsa"
+}
+
+// parseRSA parses an RSA key according to RFC 4253, section 6.6.
+func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
+ var w struct {
+ E *big.Int
+ N *big.Int
+ Rest []byte `ssh:"rest"`
+ }
+ if err := Unmarshal(in, &w); err != nil {
+ return nil, nil, err
+ }
+
+ if w.E.BitLen() > 24 {
+ return nil, nil, errors.New("ssh: exponent too large")
+ }
+ e := w.E.Int64()
+ if e < 3 || e&1 == 0 {
+ return nil, nil, errors.New("ssh: incorrect exponent")
+ }
+
+ var key rsa.PublicKey
+ key.E = int(e)
+ key.N = w.N
+ return (*rsaPublicKey)(&key), w.Rest, nil
+}
+
+func (r *rsaPublicKey) Marshal() []byte {
+ e := new(big.Int).SetInt64(int64(r.E))
+ // RSA publickey struct layout should match the struct used by
+ // parseRSACert in the x/crypto/ssh/agent package.
+ wirekey := struct {
+ Name string
+ E *big.Int
+ N *big.Int
+ }{
+ KeyAlgoRSA,
+ e,
+ r.N,
+ }
+ return Marshal(&wirekey)
+}
+
+func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
+ if sig.Format != r.Type() {
+ return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
+ }
+ h := crypto.SHA1.New()
+ h.Write(data)
+ digest := h.Sum(nil)
+ return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob)
+}
+
+type dsaPublicKey dsa.PublicKey
+
+func (r *dsaPublicKey) Type() string {
+ return "ssh-dss"
+}
+
+// parseDSA parses an DSA key according to RFC 4253, section 6.6.
+func parseDSA(in []byte) (out PublicKey, rest []byte, err error) {
+ var w struct {
+ P, Q, G, Y *big.Int
+ Rest []byte `ssh:"rest"`
+ }
+ if err := Unmarshal(in, &w); err != nil {
+ return nil, nil, err
+ }
+
+ key := &dsaPublicKey{
+ Parameters: dsa.Parameters{
+ P: w.P,
+ Q: w.Q,
+ G: w.G,
+ },
+ Y: w.Y,
+ }
+ return key, w.Rest, nil
+}
+
+func (k *dsaPublicKey) Marshal() []byte {
+ // DSA publickey struct layout should match the struct used by
+ // parseDSACert in the x/crypto/ssh/agent package.
+ w := struct {
+ Name string
+ P, Q, G, Y *big.Int
+ }{
+ k.Type(),
+ k.P,
+ k.Q,
+ k.G,
+ k.Y,
+ }
+
+ return Marshal(&w)
+}
+
+func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
+ if sig.Format != k.Type() {
+ return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
+ }
+ h := crypto.SHA1.New()
+ h.Write(data)
+ digest := h.Sum(nil)
+
+ // Per RFC 4253, section 6.6,
+ // The value for 'dss_signature_blob' is encoded as a string containing
+ // r, followed by s (which are 160-bit integers, without lengths or
+ // padding, unsigned, and in network byte order).
+ // For DSS purposes, sig.Blob should be exactly 40 bytes in length.
+ if len(sig.Blob) != 40 {
+ return errors.New("ssh: DSA signature parse error")
+ }
+ r := new(big.Int).SetBytes(sig.Blob[:20])
+ s := new(big.Int).SetBytes(sig.Blob[20:])
+ if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) {
+ return nil
+ }
+ return errors.New("ssh: signature did not verify")
+}
+
+type dsaPrivateKey struct {
+ *dsa.PrivateKey
+}
+
+func (k *dsaPrivateKey) PublicKey() PublicKey {
+ return (*dsaPublicKey)(&k.PrivateKey.PublicKey)
+}
+
+func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
+ h := crypto.SHA1.New()
+ h.Write(data)
+ digest := h.Sum(nil)
+ r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
+ if err != nil {
+ return nil, err
+ }
+
+ sig := make([]byte, 40)
+ rb := r.Bytes()
+ sb := s.Bytes()
+
+ copy(sig[20-len(rb):20], rb)
+ copy(sig[40-len(sb):], sb)
+
+ return &Signature{
+ Format: k.PublicKey().Type(),
+ Blob: sig,
+ }, nil
+}
+
+type ecdsaPublicKey ecdsa.PublicKey
+
+func (key *ecdsaPublicKey) Type() string {
+ return "ecdsa-sha2-" + key.nistID()
+}
+
+func (key *ecdsaPublicKey) nistID() string {
+ switch key.Params().BitSize {
+ case 256:
+ return "nistp256"
+ case 384:
+ return "nistp384"
+ case 521:
+ return "nistp521"
+ }
+ panic("ssh: unsupported ecdsa key size")
+}
+
+type ed25519PublicKey ed25519.PublicKey
+
+func (key ed25519PublicKey) Type() string {
+ return KeyAlgoED25519
+}
+
+func parseED25519(in []byte) (out PublicKey, rest []byte, err error) {
+ var w struct {
+ KeyBytes []byte
+ Rest []byte `ssh:"rest"`
+ }
+
+ if err := Unmarshal(in, &w); err != nil {
+ return nil, nil, err
+ }
+
+ key := ed25519.PublicKey(w.KeyBytes)
+
+ return (ed25519PublicKey)(key), w.Rest, nil
+}
+
+func (key ed25519PublicKey) Marshal() []byte {
+ w := struct {
+ Name string
+ KeyBytes []byte
+ }{
+ KeyAlgoED25519,
+ []byte(key),
+ }
+ return Marshal(&w)
+}
+
+func (key ed25519PublicKey) Verify(b []byte, sig *Signature) error {
+ if sig.Format != key.Type() {
+ return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type())
+ }
+
+ edKey := (ed25519.PublicKey)(key)
+ if ok := ed25519.Verify(edKey, b, sig.Blob); !ok {
+ return errors.New("ssh: signature did not verify")
+ }
+
+ return nil
+}
+
+func supportedEllipticCurve(curve elliptic.Curve) bool {
+ return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
+}
+
+// ecHash returns the hash to match the given elliptic curve, see RFC
+// 5656, section 6.2.1
+func ecHash(curve elliptic.Curve) crypto.Hash {
+ bitSize := curve.Params().BitSize
+ switch {
+ case bitSize <= 256:
+ return crypto.SHA256
+ case bitSize <= 384:
+ return crypto.SHA384
+ }
+ return crypto.SHA512
+}
+
+// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
+func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
+ var w struct {
+ Curve string
+ KeyBytes []byte
+ Rest []byte `ssh:"rest"`
+ }
+
+ if err := Unmarshal(in, &w); err != nil {
+ return nil, nil, err
+ }
+
+ key := new(ecdsa.PublicKey)
+
+ switch w.Curve {
+ case "nistp256":
+ key.Curve = elliptic.P256()
+ case "nistp384":
+ key.Curve = elliptic.P384()
+ case "nistp521":
+ key.Curve = elliptic.P521()
+ default:
+ return nil, nil, errors.New("ssh: unsupported curve")
+ }
+
+ key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
+ if key.X == nil || key.Y == nil {
+ return nil, nil, errors.New("ssh: invalid curve point")
+ }
+ return (*ecdsaPublicKey)(key), w.Rest, nil
+}
+
+func (key *ecdsaPublicKey) Marshal() []byte {
+ // See RFC 5656, section 3.1.
+ keyBytes := elliptic.Marshal(key.Curve, key.X, key.Y)
+ // ECDSA publickey struct layout should match the struct used by
+ // parseECDSACert in the x/crypto/ssh/agent package.
+ w := struct {
+ Name string
+ ID string
+ Key []byte
+ }{
+ key.Type(),
+ key.nistID(),
+ keyBytes,
+ }
+
+ return Marshal(&w)
+}
+
+func (key *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
+ if sig.Format != key.Type() {
+ return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type())
+ }
+
+ h := ecHash(key.Curve).New()
+ h.Write(data)
+ digest := h.Sum(nil)
+
+ // Per RFC 5656, section 3.1.2,
+ // The ecdsa_signature_blob value has the following specific encoding:
+ // mpint r
+ // mpint s
+ var ecSig struct {
+ R *big.Int
+ S *big.Int
+ }
+
+ if err := Unmarshal(sig.Blob, &ecSig); err != nil {
+ return err
+ }
+
+ if ecdsa.Verify((*ecdsa.PublicKey)(key), digest, ecSig.R, ecSig.S) {
+ return nil
+ }
+ return errors.New("ssh: signature did not verify")
+}
+
+// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
+// *ecdsa.PrivateKey or any other crypto.Signer and returns a corresponding
+// Signer instance. ECDSA keys must use P-256, P-384 or P-521.
+func NewSignerFromKey(key interface{}) (Signer, error) {
+ switch key := key.(type) {
+ case crypto.Signer:
+ return NewSignerFromSigner(key)
+ case *dsa.PrivateKey:
+ return &dsaPrivateKey{key}, nil
+ default:
+ return nil, fmt.Errorf("ssh: unsupported key type %T", key)
+ }
+}
+
+type wrappedSigner struct {
+ signer crypto.Signer
+ pubKey PublicKey
+}
+
+// NewSignerFromSigner takes any crypto.Signer implementation and
+// returns a corresponding Signer interface. This can be used, for
+// example, with keys kept in hardware modules.
+func NewSignerFromSigner(signer crypto.Signer) (Signer, error) {
+ pubKey, err := NewPublicKey(signer.Public())
+ if err != nil {
+ return nil, err
+ }
+
+ return &wrappedSigner{signer, pubKey}, nil
+}
+
+func (s *wrappedSigner) PublicKey() PublicKey {
+ return s.pubKey
+}
+
+func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
+ var hashFunc crypto.Hash
+
+ switch key := s.pubKey.(type) {
+ case *rsaPublicKey, *dsaPublicKey:
+ hashFunc = crypto.SHA1
+ case *ecdsaPublicKey:
+ hashFunc = ecHash(key.Curve)
+ case ed25519PublicKey:
+ default:
+ return nil, fmt.Errorf("ssh: unsupported key type %T", key)
+ }
+
+ var digest []byte
+ if hashFunc != 0 {
+ h := hashFunc.New()
+ h.Write(data)
+ digest = h.Sum(nil)
+ } else {
+ digest = data
+ }
+
+ signature, err := s.signer.Sign(rand, digest, hashFunc)
+ if err != nil {
+ return nil, err
+ }
+
+ // crypto.Signer.Sign is expected to return an ASN.1-encoded signature
+ // for ECDSA and DSA, but that's not the encoding expected by SSH, so
+ // re-encode.
+ switch s.pubKey.(type) {
+ case *ecdsaPublicKey, *dsaPublicKey:
+ type asn1Signature struct {
+ R, S *big.Int
+ }
+ asn1Sig := new(asn1Signature)
+ _, err := asn1.Unmarshal(signature, asn1Sig)
+ if err != nil {
+ return nil, err
+ }
+
+ switch s.pubKey.(type) {
+ case *ecdsaPublicKey:
+ signature = Marshal(asn1Sig)
+
+ case *dsaPublicKey:
+ signature = make([]byte, 40)
+ r := asn1Sig.R.Bytes()
+ s := asn1Sig.S.Bytes()
+ copy(signature[20-len(r):20], r)
+ copy(signature[40-len(s):40], s)
+ }
+ }
+
+ return &Signature{
+ Format: s.pubKey.Type(),
+ Blob: signature,
+ }, nil
+}
+
+// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey,
+// ed25519.PublicKey, or any other crypto.Signer and returns a corresponding
+// Signer instance. ECDSA keys must use P-256, P-384 or P-521.
+func NewPublicKey(key interface{}) (PublicKey, error) {
+ switch key := key.(type) {
+ case *rsa.PublicKey:
+ return (*rsaPublicKey)(key), nil
+ case *ecdsa.PublicKey:
+ if !supportedEllipticCurve(key.Curve) {
+ return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported.")
+ }
+ return (*ecdsaPublicKey)(key), nil
+ case *dsa.PublicKey:
+ return (*dsaPublicKey)(key), nil
+ case ed25519.PublicKey:
+ return (ed25519PublicKey)(key), nil
+ default:
+ return nil, fmt.Errorf("ssh: unsupported key type %T", key)
+ }
+}
+
+// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports
+// the same keys as ParseRawPrivateKey.
+func ParsePrivateKey(pemBytes []byte) (Signer, error) {
+ key, err := ParseRawPrivateKey(pemBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewSignerFromKey(key)
+}
+
+// ParseRawPrivateKey returns a private key from a PEM encoded private key. It
+// supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys.
+func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
+ block, _ := pem.Decode(pemBytes)
+ if block == nil {
+ return nil, errors.New("ssh: no key found")
+ }
+
+ switch block.Type {
+ case "RSA PRIVATE KEY":
+ return x509.ParsePKCS1PrivateKey(block.Bytes)
+ case "EC PRIVATE KEY":
+ return x509.ParseECPrivateKey(block.Bytes)
+ case "DSA PRIVATE KEY":
+ return ParseDSAPrivateKey(block.Bytes)
+ case "OPENSSH PRIVATE KEY":
+ return parseOpenSSHPrivateKey(block.Bytes)
+ default:
+ return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
+ }
+}
+
+// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
+// specified by the OpenSSL DSA man page.
+func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
+ var k struct {
+ Version int
+ P *big.Int
+ Q *big.Int
+ G *big.Int
+ Priv *big.Int
+ Pub *big.Int
+ }
+ rest, err := asn1.Unmarshal(der, &k)
+ if err != nil {
+ return nil, errors.New("ssh: failed to parse DSA key: " + err.Error())
+ }
+ if len(rest) > 0 {
+ return nil, errors.New("ssh: garbage after DSA key")
+ }
+
+ return &dsa.PrivateKey{
+ PublicKey: dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: k.P,
+ Q: k.Q,
+ G: k.G,
+ },
+ Y: k.Priv,
+ },
+ X: k.Pub,
+ }, nil
+}
+
+// Implemented based on the documentation at
+// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
+func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
+ magic := append([]byte("openssh-key-v1"), 0)
+ if !bytes.Equal(magic, key[0:len(magic)]) {
+ return nil, errors.New("ssh: invalid openssh private key format")
+ }
+ remaining := key[len(magic):]
+
+ var w struct {
+ CipherName string
+ KdfName string
+ KdfOpts string
+ NumKeys uint32
+ PubKey []byte
+ PrivKeyBlock []byte
+ }
+
+ if err := Unmarshal(remaining, &w); err != nil {
+ return nil, err
+ }
+
+ pk1 := struct {
+ Check1 uint32
+ Check2 uint32
+ Keytype string
+ Pub []byte
+ Priv []byte
+ Comment string
+ Pad []byte `ssh:"rest"`
+ }{}
+
+ if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil {
+ return nil, err
+ }
+
+ if pk1.Check1 != pk1.Check2 {
+ return nil, errors.New("ssh: checkint mismatch")
+ }
+
+ // we only handle ed25519 keys currently
+ if pk1.Keytype != KeyAlgoED25519 {
+ return nil, errors.New("ssh: unhandled key type")
+ }
+
+ for i, b := range pk1.Pad {
+ if int(b) != i+1 {
+ return nil, errors.New("ssh: padding not as expected")
+ }
+ }
+
+ if len(pk1.Priv) != ed25519.PrivateKeySize {
+ return nil, errors.New("ssh: private key unexpected length")
+ }
+
+ pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
+ copy(pk, pk1.Priv)
+ return &pk, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/keys_test.go b/vendor/golang.org/x/crypto/ssh/keys_test.go
new file mode 100644
index 000000000..4c4c5bef6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/keys_test.go
@@ -0,0 +1,440 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "encoding/base64"
+ "fmt"
+ "reflect"
+ "strings"
+ "testing"
+
+ "golang.org/x/crypto/ed25519"
+ "golang.org/x/crypto/ssh/testdata"
+)
+
+func rawKey(pub PublicKey) interface{} {
+ switch k := pub.(type) {
+ case *rsaPublicKey:
+ return (*rsa.PublicKey)(k)
+ case *dsaPublicKey:
+ return (*dsa.PublicKey)(k)
+ case *ecdsaPublicKey:
+ return (*ecdsa.PublicKey)(k)
+ case ed25519PublicKey:
+ return (ed25519.PublicKey)(k)
+ case *Certificate:
+ return k
+ }
+ panic("unknown key type")
+}
+
+func TestKeyMarshalParse(t *testing.T) {
+ for _, priv := range testSigners {
+ pub := priv.PublicKey()
+ roundtrip, err := ParsePublicKey(pub.Marshal())
+ if err != nil {
+ t.Errorf("ParsePublicKey(%T): %v", pub, err)
+ }
+
+ k1 := rawKey(pub)
+ k2 := rawKey(roundtrip)
+
+ if !reflect.DeepEqual(k1, k2) {
+ t.Errorf("got %#v in roundtrip, want %#v", k2, k1)
+ }
+ }
+}
+
+func TestUnsupportedCurves(t *testing.T) {
+ raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+ if err != nil {
+ t.Fatalf("GenerateKey: %v", err)
+ }
+
+ if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P-256") {
+ t.Fatalf("NewPrivateKey should not succeed with P-224, got: %v", err)
+ }
+
+ if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P-256") {
+ t.Fatalf("NewPublicKey should not succeed with P-224, got: %v", err)
+ }
+}
+
+func TestNewPublicKey(t *testing.T) {
+ for _, k := range testSigners {
+ raw := rawKey(k.PublicKey())
+ // Skip certificates, as NewPublicKey does not support them.
+ if _, ok := raw.(*Certificate); ok {
+ continue
+ }
+ pub, err := NewPublicKey(raw)
+ if err != nil {
+ t.Errorf("NewPublicKey(%#v): %v", raw, err)
+ }
+ if !reflect.DeepEqual(k.PublicKey(), pub) {
+ t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey())
+ }
+ }
+}
+
+func TestKeySignVerify(t *testing.T) {
+ for _, priv := range testSigners {
+ pub := priv.PublicKey()
+
+ data := []byte("sign me")
+ sig, err := priv.Sign(rand.Reader, data)
+ if err != nil {
+ t.Fatalf("Sign(%T): %v", priv, err)
+ }
+
+ if err := pub.Verify(data, sig); err != nil {
+ t.Errorf("publicKey.Verify(%T): %v", priv, err)
+ }
+ sig.Blob[5]++
+ if err := pub.Verify(data, sig); err == nil {
+ t.Errorf("publicKey.Verify on broken sig did not fail")
+ }
+ }
+}
+
+func TestParseRSAPrivateKey(t *testing.T) {
+ key := testPrivateKeys["rsa"]
+
+ rsa, ok := key.(*rsa.PrivateKey)
+ if !ok {
+ t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
+ }
+
+ if err := rsa.Validate(); err != nil {
+ t.Errorf("Validate: %v", err)
+ }
+}
+
+func TestParseECPrivateKey(t *testing.T) {
+ key := testPrivateKeys["ecdsa"]
+
+ ecKey, ok := key.(*ecdsa.PrivateKey)
+ if !ok {
+ t.Fatalf("got %T, want *ecdsa.PrivateKey", ecKey)
+ }
+
+ if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
+ t.Fatalf("public key does not validate.")
+ }
+}
+
+func TestParseDSA(t *testing.T) {
+ // We actually exercise the ParsePrivateKey codepath here, as opposed to
+ // using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
+ // uses.
+ s, err := ParsePrivateKey(testdata.PEMBytes["dsa"])
+ if err != nil {
+ t.Fatalf("ParsePrivateKey returned error: %s", err)
+ }
+
+ data := []byte("sign me")
+ sig, err := s.Sign(rand.Reader, data)
+ if err != nil {
+ t.Fatalf("dsa.Sign: %v", err)
+ }
+
+ if err := s.PublicKey().Verify(data, sig); err != nil {
+ t.Errorf("Verify failed: %v", err)
+ }
+}
+
+// Tests for authorized_keys parsing.
+
+// getTestKey returns a public key, and its base64 encoding.
+func getTestKey() (PublicKey, string) {
+ k := testPublicKeys["rsa"]
+
+ b := &bytes.Buffer{}
+ e := base64.NewEncoder(base64.StdEncoding, b)
+ e.Write(k.Marshal())
+ e.Close()
+
+ return k, b.String()
+}
+
+func TestMarshalParsePublicKey(t *testing.T) {
+ pub, pubSerialized := getTestKey()
+ line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized)
+
+ authKeys := MarshalAuthorizedKey(pub)
+ actualFields := strings.Fields(string(authKeys))
+ if len(actualFields) == 0 {
+ t.Fatalf("failed authKeys: %v", authKeys)
+ }
+
+ // drop the comment
+ expectedFields := strings.Fields(line)[0:2]
+
+ if !reflect.DeepEqual(actualFields, expectedFields) {
+ t.Errorf("got %v, expected %v", actualFields, expectedFields)
+ }
+
+ actPub, _, _, _, err := ParseAuthorizedKey([]byte(line))
+ if err != nil {
+ t.Fatalf("cannot parse %v: %v", line, err)
+ }
+ if !reflect.DeepEqual(actPub, pub) {
+ t.Errorf("got %v, expected %v", actPub, pub)
+ }
+}
+
+type authResult struct {
+ pubKey PublicKey
+ options []string
+ comments string
+ rest string
+ ok bool
+}
+
+func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) {
+ rest := authKeys
+ var values []authResult
+ for len(rest) > 0 {
+ var r authResult
+ var err error
+ r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
+ r.ok = (err == nil)
+ t.Log(err)
+ r.rest = string(rest)
+ values = append(values, r)
+ }
+
+ if !reflect.DeepEqual(values, expected) {
+ t.Errorf("got %#v, expected %#v", values, expected)
+ }
+}
+
+func TestAuthorizedKeyBasic(t *testing.T) {
+ pub, pubSerialized := getTestKey()
+ line := "ssh-rsa " + pubSerialized + " user@host"
+ testAuthorizedKeys(t, []byte(line),
+ []authResult{
+ {pub, nil, "user@host", "", true},
+ })
+}
+
+func TestAuth(t *testing.T) {
+ pub, pubSerialized := getTestKey()
+ authWithOptions := []string{
+ `# comments to ignore before any keys...`,
+ ``,
+ `env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`,
+ `# comments to ignore, along with a blank line`,
+ ``,
+ `env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`,
+ ``,
+ `# more comments, plus a invalid entry`,
+ `ssh-rsa data-that-will-not-parse user@host3`,
+ }
+ for _, eol := range []string{"\n", "\r\n"} {
+ authOptions := strings.Join(authWithOptions, eol)
+ rest2 := strings.Join(authWithOptions[3:], eol)
+ rest3 := strings.Join(authWithOptions[6:], eol)
+ testAuthorizedKeys(t, []byte(authOptions), []authResult{
+ {pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
+ {pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
+ {nil, nil, "", "", false},
+ })
+ }
+}
+
+func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
+ pub, pubSerialized := getTestKey()
+ authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
+ testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{
+ {pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
+ })
+}
+
+func TestAuthWithQuotedCommaInEnv(t *testing.T) {
+ pub, pubSerialized := getTestKey()
+ authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
+ testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{
+ {pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
+ })
+}
+
+func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
+ pub, pubSerialized := getTestKey()
+ authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + ` user@host`)
+ authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
+ testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{
+ {pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
+ })
+
+ testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{
+ {pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
+ })
+}
+
+func TestAuthWithInvalidSpace(t *testing.T) {
+ _, pubSerialized := getTestKey()
+ authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
+#more to follow but still no valid keys`)
+ testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{
+ {nil, nil, "", "", false},
+ })
+}
+
+func TestAuthWithMissingQuote(t *testing.T) {
+ pub, pubSerialized := getTestKey()
+ authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
+env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
+
+ testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{
+ {pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
+ })
+}
+
+func TestInvalidEntry(t *testing.T) {
+ authInvalid := []byte(`ssh-rsa`)
+ _, _, _, _, err := ParseAuthorizedKey(authInvalid)
+ if err == nil {
+ t.Errorf("got valid entry for %q", authInvalid)
+ }
+}
+
+var knownHostsParseTests = []struct {
+ input string
+ err string
+
+ marker string
+ comment string
+ hosts []string
+ rest string
+} {
+ {
+ "",
+ "EOF",
+
+ "", "", nil, "",
+ },
+ {
+ "# Just a comment",
+ "EOF",
+
+ "", "", nil, "",
+ },
+ {
+ " \t ",
+ "EOF",
+
+ "", "", nil, "",
+ },
+ {
+ "localhost ssh-rsa {RSAPUB}",
+ "",
+
+ "", "", []string{"localhost"}, "",
+ },
+ {
+ "localhost\tssh-rsa {RSAPUB}",
+ "",
+
+ "", "", []string{"localhost"}, "",
+ },
+ {
+ "localhost\tssh-rsa {RSAPUB}\tcomment comment",
+ "",
+
+ "", "comment comment", []string{"localhost"}, "",
+ },
+ {
+ "localhost\tssh-rsa {RSAPUB}\tcomment comment\n",
+ "",
+
+ "", "comment comment", []string{"localhost"}, "",
+ },
+ {
+ "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\n",
+ "",
+
+ "", "comment comment", []string{"localhost"}, "",
+ },
+ {
+ "localhost\tssh-rsa {RSAPUB}\tcomment comment\r\nnext line",
+ "",
+
+ "", "comment comment", []string{"localhost"}, "next line",
+ },
+ {
+ "localhost,[host2:123]\tssh-rsa {RSAPUB}\tcomment comment",
+ "",
+
+ "", "comment comment", []string{"localhost","[host2:123]"}, "",
+ },
+ {
+ "@marker \tlocalhost,[host2:123]\tssh-rsa {RSAPUB}",
+ "",
+
+ "marker", "", []string{"localhost","[host2:123]"}, "",
+ },
+ {
+ "@marker \tlocalhost,[host2:123]\tssh-rsa aabbccdd",
+ "short read",
+
+ "", "", nil, "",
+ },
+}
+
+func TestKnownHostsParsing(t *testing.T) {
+ rsaPub, rsaPubSerialized := getTestKey()
+
+ for i, test := range knownHostsParseTests {
+ var expectedKey PublicKey
+ const rsaKeyToken = "{RSAPUB}"
+
+ input := test.input
+ if strings.Contains(input, rsaKeyToken) {
+ expectedKey = rsaPub
+ input = strings.Replace(test.input, rsaKeyToken, rsaPubSerialized, -1)
+ }
+
+ marker, hosts, pubKey, comment, rest, err := ParseKnownHosts([]byte(input))
+ if err != nil {
+ if len(test.err) == 0 {
+ t.Errorf("#%d: unexpectedly failed with %q", i, err)
+ } else if !strings.Contains(err.Error(), test.err) {
+ t.Errorf("#%d: expected error containing %q, but got %q", i, test.err, err)
+ }
+ continue
+ } else if len(test.err) != 0 {
+ t.Errorf("#%d: succeeded but expected error including %q", i, test.err)
+ continue
+ }
+
+ if !reflect.DeepEqual(expectedKey, pubKey) {
+ t.Errorf("#%d: expected key %#v, but got %#v", i, expectedKey, pubKey)
+ }
+
+ if marker != test.marker {
+ t.Errorf("#%d: expected marker %q, but got %q", i, test.marker, marker)
+ }
+
+ if comment != test.comment {
+ t.Errorf("#%d: expected comment %q, but got %q", i, test.comment, comment)
+ }
+
+ if !reflect.DeepEqual(test.hosts, hosts) {
+ t.Errorf("#%d: expected hosts %#v, but got %#v", i, test.hosts, hosts)
+ }
+
+ if rest := string(rest); rest != test.rest {
+ t.Errorf("#%d: expected remaining input to be %q, but got %q", i, test.rest, rest)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go
new file mode 100644
index 000000000..07744ad67
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/mac.go
@@ -0,0 +1,57 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+// Message authentication support
+
+import (
+ "crypto/hmac"
+ "crypto/sha1"
+ "crypto/sha256"
+ "hash"
+)
+
+type macMode struct {
+ keySize int
+ new func(key []byte) hash.Hash
+}
+
+// truncatingMAC wraps around a hash.Hash and truncates the output digest to
+// a given size.
+type truncatingMAC struct {
+ length int
+ hmac hash.Hash
+}
+
+func (t truncatingMAC) Write(data []byte) (int, error) {
+ return t.hmac.Write(data)
+}
+
+func (t truncatingMAC) Sum(in []byte) []byte {
+ out := t.hmac.Sum(in)
+ return out[:len(in)+t.length]
+}
+
+func (t truncatingMAC) Reset() {
+ t.hmac.Reset()
+}
+
+func (t truncatingMAC) Size() int {
+ return t.length
+}
+
+func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
+
+var macModes = map[string]*macMode{
+ "hmac-sha2-256": {32, func(key []byte) hash.Hash {
+ return hmac.New(sha256.New, key)
+ }},
+ "hmac-sha1": {20, func(key []byte) hash.Hash {
+ return hmac.New(sha1.New, key)
+ }},
+ "hmac-sha1-96": {20, func(key []byte) hash.Hash {
+ return truncatingMAC{12, hmac.New(sha1.New, key)}
+ }},
+}
diff --git a/vendor/golang.org/x/crypto/ssh/mempipe_test.go b/vendor/golang.org/x/crypto/ssh/mempipe_test.go
new file mode 100644
index 000000000..8697cd614
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/mempipe_test.go
@@ -0,0 +1,110 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "io"
+ "sync"
+ "testing"
+)
+
+// An in-memory packetConn. It is safe to call Close and writePacket
+// from different goroutines.
+type memTransport struct {
+ eof bool
+ pending [][]byte
+ write *memTransport
+ sync.Mutex
+ *sync.Cond
+}
+
+func (t *memTransport) readPacket() ([]byte, error) {
+ t.Lock()
+ defer t.Unlock()
+ for {
+ if len(t.pending) > 0 {
+ r := t.pending[0]
+ t.pending = t.pending[1:]
+ return r, nil
+ }
+ if t.eof {
+ return nil, io.EOF
+ }
+ t.Cond.Wait()
+ }
+}
+
+func (t *memTransport) closeSelf() error {
+ t.Lock()
+ defer t.Unlock()
+ if t.eof {
+ return io.EOF
+ }
+ t.eof = true
+ t.Cond.Broadcast()
+ return nil
+}
+
+func (t *memTransport) Close() error {
+ err := t.write.closeSelf()
+ t.closeSelf()
+ return err
+}
+
+func (t *memTransport) writePacket(p []byte) error {
+ t.write.Lock()
+ defer t.write.Unlock()
+ if t.write.eof {
+ return io.EOF
+ }
+ c := make([]byte, len(p))
+ copy(c, p)
+ t.write.pending = append(t.write.pending, c)
+ t.write.Cond.Signal()
+ return nil
+}
+
+func memPipe() (a, b packetConn) {
+ t1 := memTransport{}
+ t2 := memTransport{}
+ t1.write = &t2
+ t2.write = &t1
+ t1.Cond = sync.NewCond(&t1.Mutex)
+ t2.Cond = sync.NewCond(&t2.Mutex)
+ return &t1, &t2
+}
+
+func TestMemPipe(t *testing.T) {
+ a, b := memPipe()
+ if err := a.writePacket([]byte{42}); err != nil {
+ t.Fatalf("writePacket: %v", err)
+ }
+ if err := a.Close(); err != nil {
+ t.Fatal("Close: ", err)
+ }
+ p, err := b.readPacket()
+ if err != nil {
+ t.Fatal("readPacket: ", err)
+ }
+ if len(p) != 1 || p[0] != 42 {
+ t.Fatalf("got %v, want {42}", p)
+ }
+ p, err = b.readPacket()
+ if err != io.EOF {
+ t.Fatalf("got %v, %v, want EOF", p, err)
+ }
+}
+
+func TestDoubleClose(t *testing.T) {
+ a, _ := memPipe()
+ err := a.Close()
+ if err != nil {
+ t.Errorf("Close: %v", err)
+ }
+ err = a.Close()
+ if err != io.EOF {
+ t.Errorf("expect EOF on double close.")
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go
new file mode 100644
index 000000000..e6ecd3afa
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/messages.go
@@ -0,0 +1,758 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+// These are SSH message type numbers. They are scattered around several
+// documents but many were taken from [SSH-PARAMETERS].
+const (
+ msgIgnore = 2
+ msgUnimplemented = 3
+ msgDebug = 4
+ msgNewKeys = 21
+
+ // Standard authentication messages
+ msgUserAuthSuccess = 52
+ msgUserAuthBanner = 53
+)
+
+// SSH messages:
+//
+// These structures mirror the wire format of the corresponding SSH messages.
+// They are marshaled using reflection with the marshal and unmarshal functions
+// in this file. The only wrinkle is that a final member of type []byte with a
+// ssh tag of "rest" receives the remainder of a packet when unmarshaling.
+
+// See RFC 4253, section 11.1.
+const msgDisconnect = 1
+
+// disconnectMsg is the message that signals a disconnect. It is also
+// the error type returned from mux.Wait()
+type disconnectMsg struct {
+ Reason uint32 `sshtype:"1"`
+ Message string
+ Language string
+}
+
+func (d *disconnectMsg) Error() string {
+ return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message)
+}
+
+// See RFC 4253, section 7.1.
+const msgKexInit = 20
+
+type kexInitMsg struct {
+ Cookie [16]byte `sshtype:"20"`
+ KexAlgos []string
+ ServerHostKeyAlgos []string
+ CiphersClientServer []string
+ CiphersServerClient []string
+ MACsClientServer []string
+ MACsServerClient []string
+ CompressionClientServer []string
+ CompressionServerClient []string
+ LanguagesClientServer []string
+ LanguagesServerClient []string
+ FirstKexFollows bool
+ Reserved uint32
+}
+
+// See RFC 4253, section 8.
+
+// Diffie-Helman
+const msgKexDHInit = 30
+
+type kexDHInitMsg struct {
+ X *big.Int `sshtype:"30"`
+}
+
+const msgKexECDHInit = 30
+
+type kexECDHInitMsg struct {
+ ClientPubKey []byte `sshtype:"30"`
+}
+
+const msgKexECDHReply = 31
+
+type kexECDHReplyMsg struct {
+ HostKey []byte `sshtype:"31"`
+ EphemeralPubKey []byte
+ Signature []byte
+}
+
+const msgKexDHReply = 31
+
+type kexDHReplyMsg struct {
+ HostKey []byte `sshtype:"31"`
+ Y *big.Int
+ Signature []byte
+}
+
+// See RFC 4253, section 10.
+const msgServiceRequest = 5
+
+type serviceRequestMsg struct {
+ Service string `sshtype:"5"`
+}
+
+// See RFC 4253, section 10.
+const msgServiceAccept = 6
+
+type serviceAcceptMsg struct {
+ Service string `sshtype:"6"`
+}
+
+// See RFC 4252, section 5.
+const msgUserAuthRequest = 50
+
+type userAuthRequestMsg struct {
+ User string `sshtype:"50"`
+ Service string
+ Method string
+ Payload []byte `ssh:"rest"`
+}
+
+// Used for debug printouts of packets.
+type userAuthSuccessMsg struct {
+}
+
+// See RFC 4252, section 5.1
+const msgUserAuthFailure = 51
+
+type userAuthFailureMsg struct {
+ Methods []string `sshtype:"51"`
+ PartialSuccess bool
+}
+
+// See RFC 4256, section 3.2
+const msgUserAuthInfoRequest = 60
+const msgUserAuthInfoResponse = 61
+
+type userAuthInfoRequestMsg struct {
+ User string `sshtype:"60"`
+ Instruction string
+ DeprecatedLanguage string
+ NumPrompts uint32
+ Prompts []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.1.
+const msgChannelOpen = 90
+
+type channelOpenMsg struct {
+ ChanType string `sshtype:"90"`
+ PeersId uint32
+ PeersWindow uint32
+ MaxPacketSize uint32
+ TypeSpecificData []byte `ssh:"rest"`
+}
+
+const msgChannelExtendedData = 95
+const msgChannelData = 94
+
+// Used for debug print outs of packets.
+type channelDataMsg struct {
+ PeersId uint32 `sshtype:"94"`
+ Length uint32
+ Rest []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.1.
+const msgChannelOpenConfirm = 91
+
+type channelOpenConfirmMsg struct {
+ PeersId uint32 `sshtype:"91"`
+ MyId uint32
+ MyWindow uint32
+ MaxPacketSize uint32
+ TypeSpecificData []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.1.
+const msgChannelOpenFailure = 92
+
+type channelOpenFailureMsg struct {
+ PeersId uint32 `sshtype:"92"`
+ Reason RejectionReason
+ Message string
+ Language string
+}
+
+const msgChannelRequest = 98
+
+type channelRequestMsg struct {
+ PeersId uint32 `sshtype:"98"`
+ Request string
+ WantReply bool
+ RequestSpecificData []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 5.4.
+const msgChannelSuccess = 99
+
+type channelRequestSuccessMsg struct {
+ PeersId uint32 `sshtype:"99"`
+}
+
+// See RFC 4254, section 5.4.
+const msgChannelFailure = 100
+
+type channelRequestFailureMsg struct {
+ PeersId uint32 `sshtype:"100"`
+}
+
+// See RFC 4254, section 5.3
+const msgChannelClose = 97
+
+type channelCloseMsg struct {
+ PeersId uint32 `sshtype:"97"`
+}
+
+// See RFC 4254, section 5.3
+const msgChannelEOF = 96
+
+type channelEOFMsg struct {
+ PeersId uint32 `sshtype:"96"`
+}
+
+// See RFC 4254, section 4
+const msgGlobalRequest = 80
+
+type globalRequestMsg struct {
+ Type string `sshtype:"80"`
+ WantReply bool
+ Data []byte `ssh:"rest"`
+}
+
+// See RFC 4254, section 4
+const msgRequestSuccess = 81
+
+type globalRequestSuccessMsg struct {
+ Data []byte `ssh:"rest" sshtype:"81"`
+}
+
+// See RFC 4254, section 4
+const msgRequestFailure = 82
+
+type globalRequestFailureMsg struct {
+ Data []byte `ssh:"rest" sshtype:"82"`
+}
+
+// See RFC 4254, section 5.2
+const msgChannelWindowAdjust = 93
+
+type windowAdjustMsg struct {
+ PeersId uint32 `sshtype:"93"`
+ AdditionalBytes uint32
+}
+
+// See RFC 4252, section 7
+const msgUserAuthPubKeyOk = 60
+
+type userAuthPubKeyOkMsg struct {
+ Algo string `sshtype:"60"`
+ PubKey []byte
+}
+
+// typeTags returns the possible type bytes for the given reflect.Type, which
+// should be a struct. The possible values are separated by a '|' character.
+func typeTags(structType reflect.Type) (tags []byte) {
+ tagStr := structType.Field(0).Tag.Get("sshtype")
+
+ for _, tag := range strings.Split(tagStr, "|") {
+ i, err := strconv.Atoi(tag)
+ if err == nil {
+ tags = append(tags, byte(i))
+ }
+ }
+
+ return tags
+}
+
+func fieldError(t reflect.Type, field int, problem string) error {
+ if problem != "" {
+ problem = ": " + problem
+ }
+ return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem)
+}
+
+var errShortRead = errors.New("ssh: short read")
+
+// Unmarshal parses data in SSH wire format into a structure. The out
+// argument should be a pointer to struct. If the first member of the
+// struct has the "sshtype" tag set to a '|'-separated set of numbers
+// in decimal, the packet must start with one of those numbers. In
+// case of error, Unmarshal returns a ParseError or
+// UnexpectedMessageError.
+func Unmarshal(data []byte, out interface{}) error {
+ v := reflect.ValueOf(out).Elem()
+ structType := v.Type()
+ expectedTypes := typeTags(structType)
+
+ var expectedType byte
+ if len(expectedTypes) > 0 {
+ expectedType = expectedTypes[0]
+ }
+
+ if len(data) == 0 {
+ return parseError(expectedType)
+ }
+
+ if len(expectedTypes) > 0 {
+ goodType := false
+ for _, e := range expectedTypes {
+ if e > 0 && data[0] == e {
+ goodType = true
+ break
+ }
+ }
+ if !goodType {
+ return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes)
+ }
+ data = data[1:]
+ }
+
+ var ok bool
+ for i := 0; i < v.NumField(); i++ {
+ field := v.Field(i)
+ t := field.Type()
+ switch t.Kind() {
+ case reflect.Bool:
+ if len(data) < 1 {
+ return errShortRead
+ }
+ field.SetBool(data[0] != 0)
+ data = data[1:]
+ case reflect.Array:
+ if t.Elem().Kind() != reflect.Uint8 {
+ return fieldError(structType, i, "array of unsupported type")
+ }
+ if len(data) < t.Len() {
+ return errShortRead
+ }
+ for j, n := 0, t.Len(); j < n; j++ {
+ field.Index(j).Set(reflect.ValueOf(data[j]))
+ }
+ data = data[t.Len():]
+ case reflect.Uint64:
+ var u64 uint64
+ if u64, data, ok = parseUint64(data); !ok {
+ return errShortRead
+ }
+ field.SetUint(u64)
+ case reflect.Uint32:
+ var u32 uint32
+ if u32, data, ok = parseUint32(data); !ok {
+ return errShortRead
+ }
+ field.SetUint(uint64(u32))
+ case reflect.Uint8:
+ if len(data) < 1 {
+ return errShortRead
+ }
+ field.SetUint(uint64(data[0]))
+ data = data[1:]
+ case reflect.String:
+ var s []byte
+ if s, data, ok = parseString(data); !ok {
+ return fieldError(structType, i, "")
+ }
+ field.SetString(string(s))
+ case reflect.Slice:
+ switch t.Elem().Kind() {
+ case reflect.Uint8:
+ if structType.Field(i).Tag.Get("ssh") == "rest" {
+ field.Set(reflect.ValueOf(data))
+ data = nil
+ } else {
+ var s []byte
+ if s, data, ok = parseString(data); !ok {
+ return errShortRead
+ }
+ field.Set(reflect.ValueOf(s))
+ }
+ case reflect.String:
+ var nl []string
+ if nl, data, ok = parseNameList(data); !ok {
+ return errShortRead
+ }
+ field.Set(reflect.ValueOf(nl))
+ default:
+ return fieldError(structType, i, "slice of unsupported type")
+ }
+ case reflect.Ptr:
+ if t == bigIntType {
+ var n *big.Int
+ if n, data, ok = parseInt(data); !ok {
+ return errShortRead
+ }
+ field.Set(reflect.ValueOf(n))
+ } else {
+ return fieldError(structType, i, "pointer to unsupported type")
+ }
+ default:
+ return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t))
+ }
+ }
+
+ if len(data) != 0 {
+ return parseError(expectedType)
+ }
+
+ return nil
+}
+
+// Marshal serializes the message in msg to SSH wire format. The msg
+// argument should be a struct or pointer to struct. If the first
+// member has the "sshtype" tag set to a number in decimal, that
+// number is prepended to the result. If the last of member has the
+// "ssh" tag set to "rest", its contents are appended to the output.
+func Marshal(msg interface{}) []byte {
+ out := make([]byte, 0, 64)
+ return marshalStruct(out, msg)
+}
+
+func marshalStruct(out []byte, msg interface{}) []byte {
+ v := reflect.Indirect(reflect.ValueOf(msg))
+ msgTypes := typeTags(v.Type())
+ if len(msgTypes) > 0 {
+ out = append(out, msgTypes[0])
+ }
+
+ for i, n := 0, v.NumField(); i < n; i++ {
+ field := v.Field(i)
+ switch t := field.Type(); t.Kind() {
+ case reflect.Bool:
+ var v uint8
+ if field.Bool() {
+ v = 1
+ }
+ out = append(out, v)
+ case reflect.Array:
+ if t.Elem().Kind() != reflect.Uint8 {
+ panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface()))
+ }
+ for j, l := 0, t.Len(); j < l; j++ {
+ out = append(out, uint8(field.Index(j).Uint()))
+ }
+ case reflect.Uint32:
+ out = appendU32(out, uint32(field.Uint()))
+ case reflect.Uint64:
+ out = appendU64(out, uint64(field.Uint()))
+ case reflect.Uint8:
+ out = append(out, uint8(field.Uint()))
+ case reflect.String:
+ s := field.String()
+ out = appendInt(out, len(s))
+ out = append(out, s...)
+ case reflect.Slice:
+ switch t.Elem().Kind() {
+ case reflect.Uint8:
+ if v.Type().Field(i).Tag.Get("ssh") != "rest" {
+ out = appendInt(out, field.Len())
+ }
+ out = append(out, field.Bytes()...)
+ case reflect.String:
+ offset := len(out)
+ out = appendU32(out, 0)
+ if n := field.Len(); n > 0 {
+ for j := 0; j < n; j++ {
+ f := field.Index(j)
+ if j != 0 {
+ out = append(out, ',')
+ }
+ out = append(out, f.String()...)
+ }
+ // overwrite length value
+ binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4))
+ }
+ default:
+ panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface()))
+ }
+ case reflect.Ptr:
+ if t == bigIntType {
+ var n *big.Int
+ nValue := reflect.ValueOf(&n)
+ nValue.Elem().Set(field)
+ needed := intLength(n)
+ oldLength := len(out)
+
+ if cap(out)-len(out) < needed {
+ newOut := make([]byte, len(out), 2*(len(out)+needed))
+ copy(newOut, out)
+ out = newOut
+ }
+ out = out[:oldLength+needed]
+ marshalInt(out[oldLength:], n)
+ } else {
+ panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface()))
+ }
+ }
+ }
+
+ return out
+}
+
+var bigOne = big.NewInt(1)
+
+func parseString(in []byte) (out, rest []byte, ok bool) {
+ if len(in) < 4 {
+ return
+ }
+ length := binary.BigEndian.Uint32(in)
+ in = in[4:]
+ if uint32(len(in)) < length {
+ return
+ }
+ out = in[:length]
+ rest = in[length:]
+ ok = true
+ return
+}
+
+var (
+ comma = []byte{','}
+ emptyNameList = []string{}
+)
+
+func parseNameList(in []byte) (out []string, rest []byte, ok bool) {
+ contents, rest, ok := parseString(in)
+ if !ok {
+ return
+ }
+ if len(contents) == 0 {
+ out = emptyNameList
+ return
+ }
+ parts := bytes.Split(contents, comma)
+ out = make([]string, len(parts))
+ for i, part := range parts {
+ out[i] = string(part)
+ }
+ return
+}
+
+func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) {
+ contents, rest, ok := parseString(in)
+ if !ok {
+ return
+ }
+ out = new(big.Int)
+
+ if len(contents) > 0 && contents[0]&0x80 == 0x80 {
+ // This is a negative number
+ notBytes := make([]byte, len(contents))
+ for i := range notBytes {
+ notBytes[i] = ^contents[i]
+ }
+ out.SetBytes(notBytes)
+ out.Add(out, bigOne)
+ out.Neg(out)
+ } else {
+ // Positive number
+ out.SetBytes(contents)
+ }
+ ok = true
+ return
+}
+
+func parseUint32(in []byte) (uint32, []byte, bool) {
+ if len(in) < 4 {
+ return 0, nil, false
+ }
+ return binary.BigEndian.Uint32(in), in[4:], true
+}
+
+func parseUint64(in []byte) (uint64, []byte, bool) {
+ if len(in) < 8 {
+ return 0, nil, false
+ }
+ return binary.BigEndian.Uint64(in), in[8:], true
+}
+
+func intLength(n *big.Int) int {
+ length := 4 /* length bytes */
+ if n.Sign() < 0 {
+ nMinus1 := new(big.Int).Neg(n)
+ nMinus1.Sub(nMinus1, bigOne)
+ bitLen := nMinus1.BitLen()
+ if bitLen%8 == 0 {
+ // The number will need 0xff padding
+ length++
+ }
+ length += (bitLen + 7) / 8
+ } else if n.Sign() == 0 {
+ // A zero is the zero length string
+ } else {
+ bitLen := n.BitLen()
+ if bitLen%8 == 0 {
+ // The number will need 0x00 padding
+ length++
+ }
+ length += (bitLen + 7) / 8
+ }
+
+ return length
+}
+
+func marshalUint32(to []byte, n uint32) []byte {
+ binary.BigEndian.PutUint32(to, n)
+ return to[4:]
+}
+
+func marshalUint64(to []byte, n uint64) []byte {
+ binary.BigEndian.PutUint64(to, n)
+ return to[8:]
+}
+
+func marshalInt(to []byte, n *big.Int) []byte {
+ lengthBytes := to
+ to = to[4:]
+ length := 0
+
+ if n.Sign() < 0 {
+ // A negative number has to be converted to two's-complement
+ // form. So we'll subtract 1 and invert. If the
+ // most-significant-bit isn't set then we'll need to pad the
+ // beginning with 0xff in order to keep the number negative.
+ nMinus1 := new(big.Int).Neg(n)
+ nMinus1.Sub(nMinus1, bigOne)
+ bytes := nMinus1.Bytes()
+ for i := range bytes {
+ bytes[i] ^= 0xff
+ }
+ if len(bytes) == 0 || bytes[0]&0x80 == 0 {
+ to[0] = 0xff
+ to = to[1:]
+ length++
+ }
+ nBytes := copy(to, bytes)
+ to = to[nBytes:]
+ length += nBytes
+ } else if n.Sign() == 0 {
+ // A zero is the zero length string
+ } else {
+ bytes := n.Bytes()
+ if len(bytes) > 0 && bytes[0]&0x80 != 0 {
+ // We'll have to pad this with a 0x00 in order to
+ // stop it looking like a negative number.
+ to[0] = 0
+ to = to[1:]
+ length++
+ }
+ nBytes := copy(to, bytes)
+ to = to[nBytes:]
+ length += nBytes
+ }
+
+ lengthBytes[0] = byte(length >> 24)
+ lengthBytes[1] = byte(length >> 16)
+ lengthBytes[2] = byte(length >> 8)
+ lengthBytes[3] = byte(length)
+ return to
+}
+
+func writeInt(w io.Writer, n *big.Int) {
+ length := intLength(n)
+ buf := make([]byte, length)
+ marshalInt(buf, n)
+ w.Write(buf)
+}
+
+func writeString(w io.Writer, s []byte) {
+ var lengthBytes [4]byte
+ lengthBytes[0] = byte(len(s) >> 24)
+ lengthBytes[1] = byte(len(s) >> 16)
+ lengthBytes[2] = byte(len(s) >> 8)
+ lengthBytes[3] = byte(len(s))
+ w.Write(lengthBytes[:])
+ w.Write(s)
+}
+
+func stringLength(n int) int {
+ return 4 + n
+}
+
+func marshalString(to []byte, s []byte) []byte {
+ to[0] = byte(len(s) >> 24)
+ to[1] = byte(len(s) >> 16)
+ to[2] = byte(len(s) >> 8)
+ to[3] = byte(len(s))
+ to = to[4:]
+ copy(to, s)
+ return to[len(s):]
+}
+
+var bigIntType = reflect.TypeOf((*big.Int)(nil))
+
+// Decode a packet into its corresponding message.
+func decode(packet []byte) (interface{}, error) {
+ var msg interface{}
+ switch packet[0] {
+ case msgDisconnect:
+ msg = new(disconnectMsg)
+ case msgServiceRequest:
+ msg = new(serviceRequestMsg)
+ case msgServiceAccept:
+ msg = new(serviceAcceptMsg)
+ case msgKexInit:
+ msg = new(kexInitMsg)
+ case msgKexDHInit:
+ msg = new(kexDHInitMsg)
+ case msgKexDHReply:
+ msg = new(kexDHReplyMsg)
+ case msgUserAuthRequest:
+ msg = new(userAuthRequestMsg)
+ case msgUserAuthSuccess:
+ return new(userAuthSuccessMsg), nil
+ case msgUserAuthFailure:
+ msg = new(userAuthFailureMsg)
+ case msgUserAuthPubKeyOk:
+ msg = new(userAuthPubKeyOkMsg)
+ case msgGlobalRequest:
+ msg = new(globalRequestMsg)
+ case msgRequestSuccess:
+ msg = new(globalRequestSuccessMsg)
+ case msgRequestFailure:
+ msg = new(globalRequestFailureMsg)
+ case msgChannelOpen:
+ msg = new(channelOpenMsg)
+ case msgChannelData:
+ msg = new(channelDataMsg)
+ case msgChannelOpenConfirm:
+ msg = new(channelOpenConfirmMsg)
+ case msgChannelOpenFailure:
+ msg = new(channelOpenFailureMsg)
+ case msgChannelWindowAdjust:
+ msg = new(windowAdjustMsg)
+ case msgChannelEOF:
+ msg = new(channelEOFMsg)
+ case msgChannelClose:
+ msg = new(channelCloseMsg)
+ case msgChannelRequest:
+ msg = new(channelRequestMsg)
+ case msgChannelSuccess:
+ msg = new(channelRequestSuccessMsg)
+ case msgChannelFailure:
+ msg = new(channelRequestFailureMsg)
+ default:
+ return nil, unexpectedMessageError(0, packet[0])
+ }
+ if err := Unmarshal(packet, msg); err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/messages_test.go b/vendor/golang.org/x/crypto/ssh/messages_test.go
new file mode 100644
index 000000000..e79076412
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/messages_test.go
@@ -0,0 +1,288 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "math/big"
+ "math/rand"
+ "reflect"
+ "testing"
+ "testing/quick"
+)
+
+var intLengthTests = []struct {
+ val, length int
+}{
+ {0, 4 + 0},
+ {1, 4 + 1},
+ {127, 4 + 1},
+ {128, 4 + 2},
+ {-1, 4 + 1},
+}
+
+func TestIntLength(t *testing.T) {
+ for _, test := range intLengthTests {
+ v := new(big.Int).SetInt64(int64(test.val))
+ length := intLength(v)
+ if length != test.length {
+ t.Errorf("For %d, got length %d but expected %d", test.val, length, test.length)
+ }
+ }
+}
+
+type msgAllTypes struct {
+ Bool bool `sshtype:"21"`
+ Array [16]byte
+ Uint64 uint64
+ Uint32 uint32
+ Uint8 uint8
+ String string
+ Strings []string
+ Bytes []byte
+ Int *big.Int
+ Rest []byte `ssh:"rest"`
+}
+
+func (t *msgAllTypes) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &msgAllTypes{}
+ m.Bool = rand.Intn(2) == 1
+ randomBytes(m.Array[:], rand)
+ m.Uint64 = uint64(rand.Int63n(1<<63 - 1))
+ m.Uint32 = uint32(rand.Intn((1 << 31) - 1))
+ m.Uint8 = uint8(rand.Intn(1 << 8))
+ m.String = string(m.Array[:])
+ m.Strings = randomNameList(rand)
+ m.Bytes = m.Array[:]
+ m.Int = randomInt(rand)
+ m.Rest = m.Array[:]
+ return reflect.ValueOf(m)
+}
+
+func TestMarshalUnmarshal(t *testing.T) {
+ rand := rand.New(rand.NewSource(0))
+ iface := &msgAllTypes{}
+ ty := reflect.ValueOf(iface).Type()
+
+ n := 100
+ if testing.Short() {
+ n = 5
+ }
+ for j := 0; j < n; j++ {
+ v, ok := quick.Value(ty, rand)
+ if !ok {
+ t.Errorf("failed to create value")
+ break
+ }
+
+ m1 := v.Elem().Interface()
+ m2 := iface
+
+ marshaled := Marshal(m1)
+ if err := Unmarshal(marshaled, m2); err != nil {
+ t.Errorf("Unmarshal %#v: %s", m1, err)
+ break
+ }
+
+ if !reflect.DeepEqual(v.Interface(), m2) {
+ t.Errorf("got: %#v\nwant:%#v\n%x", m2, m1, marshaled)
+ break
+ }
+ }
+}
+
+func TestUnmarshalEmptyPacket(t *testing.T) {
+ var b []byte
+ var m channelRequestSuccessMsg
+ if err := Unmarshal(b, &m); err == nil {
+ t.Fatalf("unmarshal of empty slice succeeded")
+ }
+}
+
+func TestUnmarshalUnexpectedPacket(t *testing.T) {
+ type S struct {
+ I uint32 `sshtype:"43"`
+ S string
+ B bool
+ }
+
+ s := S{11, "hello", true}
+ packet := Marshal(s)
+ packet[0] = 42
+ roundtrip := S{}
+ err := Unmarshal(packet, &roundtrip)
+ if err == nil {
+ t.Fatal("expected error, not nil")
+ }
+}
+
+func TestMarshalPtr(t *testing.T) {
+ s := struct {
+ S string
+ }{"hello"}
+
+ m1 := Marshal(s)
+ m2 := Marshal(&s)
+ if !bytes.Equal(m1, m2) {
+ t.Errorf("got %q, want %q for marshaled pointer", m2, m1)
+ }
+}
+
+func TestBareMarshalUnmarshal(t *testing.T) {
+ type S struct {
+ I uint32
+ S string
+ B bool
+ }
+
+ s := S{42, "hello", true}
+ packet := Marshal(s)
+ roundtrip := S{}
+ Unmarshal(packet, &roundtrip)
+
+ if !reflect.DeepEqual(s, roundtrip) {
+ t.Errorf("got %#v, want %#v", roundtrip, s)
+ }
+}
+
+func TestBareMarshal(t *testing.T) {
+ type S2 struct {
+ I uint32
+ }
+ s := S2{42}
+ packet := Marshal(s)
+ i, rest, ok := parseUint32(packet)
+ if len(rest) > 0 || !ok {
+ t.Errorf("parseInt(%q): parse error", packet)
+ }
+ if i != s.I {
+ t.Errorf("got %d, want %d", i, s.I)
+ }
+}
+
+func TestUnmarshalShortKexInitPacket(t *testing.T) {
+ // This used to panic.
+ // Issue 11348
+ packet := []byte{0x14, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xff, 0xff, 0xff, 0xff}
+ kim := &kexInitMsg{}
+ if err := Unmarshal(packet, kim); err == nil {
+ t.Error("truncated packet unmarshaled without error")
+ }
+}
+
+func TestMarshalMultiTag(t *testing.T) {
+ var res struct {
+ A uint32 `sshtype:"1|2"`
+ }
+
+ good1 := struct {
+ A uint32 `sshtype:"1"`
+ }{
+ 1,
+ }
+ good2 := struct {
+ A uint32 `sshtype:"2"`
+ }{
+ 1,
+ }
+
+ if e := Unmarshal(Marshal(good1), &res); e != nil {
+ t.Errorf("error unmarshaling multipart tag: %v", e)
+ }
+
+ if e := Unmarshal(Marshal(good2), &res); e != nil {
+ t.Errorf("error unmarshaling multipart tag: %v", e)
+ }
+
+ bad1 := struct {
+ A uint32 `sshtype:"3"`
+ }{
+ 1,
+ }
+ if e := Unmarshal(Marshal(bad1), &res); e == nil {
+ t.Errorf("bad struct unmarshaled without error")
+ }
+}
+
+func randomBytes(out []byte, rand *rand.Rand) {
+ for i := 0; i < len(out); i++ {
+ out[i] = byte(rand.Int31())
+ }
+}
+
+func randomNameList(rand *rand.Rand) []string {
+ ret := make([]string, rand.Int31()&15)
+ for i := range ret {
+ s := make([]byte, 1+(rand.Int31()&15))
+ for j := range s {
+ s[j] = 'a' + uint8(rand.Int31()&15)
+ }
+ ret[i] = string(s)
+ }
+ return ret
+}
+
+func randomInt(rand *rand.Rand) *big.Int {
+ return new(big.Int).SetInt64(int64(int32(rand.Uint32())))
+}
+
+func (*kexInitMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ ki := &kexInitMsg{}
+ randomBytes(ki.Cookie[:], rand)
+ ki.KexAlgos = randomNameList(rand)
+ ki.ServerHostKeyAlgos = randomNameList(rand)
+ ki.CiphersClientServer = randomNameList(rand)
+ ki.CiphersServerClient = randomNameList(rand)
+ ki.MACsClientServer = randomNameList(rand)
+ ki.MACsServerClient = randomNameList(rand)
+ ki.CompressionClientServer = randomNameList(rand)
+ ki.CompressionServerClient = randomNameList(rand)
+ ki.LanguagesClientServer = randomNameList(rand)
+ ki.LanguagesServerClient = randomNameList(rand)
+ if rand.Int31()&1 == 1 {
+ ki.FirstKexFollows = true
+ }
+ return reflect.ValueOf(ki)
+}
+
+func (*kexDHInitMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ dhi := &kexDHInitMsg{}
+ dhi.X = randomInt(rand)
+ return reflect.ValueOf(dhi)
+}
+
+var (
+ _kexInitMsg = new(kexInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface()
+ _kexDHInitMsg = new(kexDHInitMsg).Generate(rand.New(rand.NewSource(0)), 10).Elem().Interface()
+
+ _kexInit = Marshal(_kexInitMsg)
+ _kexDHInit = Marshal(_kexDHInitMsg)
+)
+
+func BenchmarkMarshalKexInitMsg(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Marshal(_kexInitMsg)
+ }
+}
+
+func BenchmarkUnmarshalKexInitMsg(b *testing.B) {
+ m := new(kexInitMsg)
+ for i := 0; i < b.N; i++ {
+ Unmarshal(_kexInit, m)
+ }
+}
+
+func BenchmarkMarshalKexDHInitMsg(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Marshal(_kexDHInitMsg)
+ }
+}
+
+func BenchmarkUnmarshalKexDHInitMsg(b *testing.B) {
+ m := new(kexDHInitMsg)
+ for i := 0; i < b.N; i++ {
+ Unmarshal(_kexDHInit, m)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go
new file mode 100644
index 000000000..f3a3ddd78
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/mux.go
@@ -0,0 +1,330 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "encoding/binary"
+ "fmt"
+ "io"
+ "log"
+ "sync"
+ "sync/atomic"
+)
+
+// debugMux, if set, causes messages in the connection protocol to be
+// logged.
+const debugMux = false
+
+// chanList is a thread safe channel list.
+type chanList struct {
+ // protects concurrent access to chans
+ sync.Mutex
+
+ // chans are indexed by the local id of the channel, which the
+ // other side should send in the PeersId field.
+ chans []*channel
+
+ // This is a debugging aid: it offsets all IDs by this
+ // amount. This helps distinguish otherwise identical
+ // server/client muxes
+ offset uint32
+}
+
+// Assigns a channel ID to the given channel.
+func (c *chanList) add(ch *channel) uint32 {
+ c.Lock()
+ defer c.Unlock()
+ for i := range c.chans {
+ if c.chans[i] == nil {
+ c.chans[i] = ch
+ return uint32(i) + c.offset
+ }
+ }
+ c.chans = append(c.chans, ch)
+ return uint32(len(c.chans)-1) + c.offset
+}
+
+// getChan returns the channel for the given ID.
+func (c *chanList) getChan(id uint32) *channel {
+ id -= c.offset
+
+ c.Lock()
+ defer c.Unlock()
+ if id < uint32(len(c.chans)) {
+ return c.chans[id]
+ }
+ return nil
+}
+
+func (c *chanList) remove(id uint32) {
+ id -= c.offset
+ c.Lock()
+ if id < uint32(len(c.chans)) {
+ c.chans[id] = nil
+ }
+ c.Unlock()
+}
+
+// dropAll forgets all channels it knows, returning them in a slice.
+func (c *chanList) dropAll() []*channel {
+ c.Lock()
+ defer c.Unlock()
+ var r []*channel
+
+ for _, ch := range c.chans {
+ if ch == nil {
+ continue
+ }
+ r = append(r, ch)
+ }
+ c.chans = nil
+ return r
+}
+
+// mux represents the state for the SSH connection protocol, which
+// multiplexes many channels onto a single packet transport.
+type mux struct {
+ conn packetConn
+ chanList chanList
+
+ incomingChannels chan NewChannel
+
+ globalSentMu sync.Mutex
+ globalResponses chan interface{}
+ incomingRequests chan *Request
+
+ errCond *sync.Cond
+ err error
+}
+
+// When debugging, each new chanList instantiation has a different
+// offset.
+var globalOff uint32
+
+func (m *mux) Wait() error {
+ m.errCond.L.Lock()
+ defer m.errCond.L.Unlock()
+ for m.err == nil {
+ m.errCond.Wait()
+ }
+ return m.err
+}
+
+// newMux returns a mux that runs over the given connection.
+func newMux(p packetConn) *mux {
+ m := &mux{
+ conn: p,
+ incomingChannels: make(chan NewChannel, 16),
+ globalResponses: make(chan interface{}, 1),
+ incomingRequests: make(chan *Request, 16),
+ errCond: newCond(),
+ }
+ if debugMux {
+ m.chanList.offset = atomic.AddUint32(&globalOff, 1)
+ }
+
+ go m.loop()
+ return m
+}
+
+func (m *mux) sendMessage(msg interface{}) error {
+ p := Marshal(msg)
+ if debugMux {
+ log.Printf("send global(%d): %#v", m.chanList.offset, msg)
+ }
+ return m.conn.writePacket(p)
+}
+
+func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) {
+ if wantReply {
+ m.globalSentMu.Lock()
+ defer m.globalSentMu.Unlock()
+ }
+
+ if err := m.sendMessage(globalRequestMsg{
+ Type: name,
+ WantReply: wantReply,
+ Data: payload,
+ }); err != nil {
+ return false, nil, err
+ }
+
+ if !wantReply {
+ return false, nil, nil
+ }
+
+ msg, ok := <-m.globalResponses
+ if !ok {
+ return false, nil, io.EOF
+ }
+ switch msg := msg.(type) {
+ case *globalRequestFailureMsg:
+ return false, msg.Data, nil
+ case *globalRequestSuccessMsg:
+ return true, msg.Data, nil
+ default:
+ return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg)
+ }
+}
+
+// ackRequest must be called after processing a global request that
+// has WantReply set.
+func (m *mux) ackRequest(ok bool, data []byte) error {
+ if ok {
+ return m.sendMessage(globalRequestSuccessMsg{Data: data})
+ }
+ return m.sendMessage(globalRequestFailureMsg{Data: data})
+}
+
+func (m *mux) Close() error {
+ return m.conn.Close()
+}
+
+// loop runs the connection machine. It will process packets until an
+// error is encountered. To synchronize on loop exit, use mux.Wait.
+func (m *mux) loop() {
+ var err error
+ for err == nil {
+ err = m.onePacket()
+ }
+
+ for _, ch := range m.chanList.dropAll() {
+ ch.close()
+ }
+
+ close(m.incomingChannels)
+ close(m.incomingRequests)
+ close(m.globalResponses)
+
+ m.conn.Close()
+
+ m.errCond.L.Lock()
+ m.err = err
+ m.errCond.Broadcast()
+ m.errCond.L.Unlock()
+
+ if debugMux {
+ log.Println("loop exit", err)
+ }
+}
+
+// onePacket reads and processes one packet.
+func (m *mux) onePacket() error {
+ packet, err := m.conn.readPacket()
+ if err != nil {
+ return err
+ }
+
+ if debugMux {
+ if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData {
+ log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet))
+ } else {
+ p, _ := decode(packet)
+ log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet))
+ }
+ }
+
+ switch packet[0] {
+ case msgChannelOpen:
+ return m.handleChannelOpen(packet)
+ case msgGlobalRequest, msgRequestSuccess, msgRequestFailure:
+ return m.handleGlobalPacket(packet)
+ }
+
+ // assume a channel packet.
+ if len(packet) < 5 {
+ return parseError(packet[0])
+ }
+ id := binary.BigEndian.Uint32(packet[1:])
+ ch := m.chanList.getChan(id)
+ if ch == nil {
+ return fmt.Errorf("ssh: invalid channel %d", id)
+ }
+
+ return ch.handlePacket(packet)
+}
+
+func (m *mux) handleGlobalPacket(packet []byte) error {
+ msg, err := decode(packet)
+ if err != nil {
+ return err
+ }
+
+ switch msg := msg.(type) {
+ case *globalRequestMsg:
+ m.incomingRequests <- &Request{
+ Type: msg.Type,
+ WantReply: msg.WantReply,
+ Payload: msg.Data,
+ mux: m,
+ }
+ case *globalRequestSuccessMsg, *globalRequestFailureMsg:
+ m.globalResponses <- msg
+ default:
+ panic(fmt.Sprintf("not a global message %#v", msg))
+ }
+
+ return nil
+}
+
+// handleChannelOpen schedules a channel to be Accept()ed.
+func (m *mux) handleChannelOpen(packet []byte) error {
+ var msg channelOpenMsg
+ if err := Unmarshal(packet, &msg); err != nil {
+ return err
+ }
+
+ if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 {
+ failMsg := channelOpenFailureMsg{
+ PeersId: msg.PeersId,
+ Reason: ConnectionFailed,
+ Message: "invalid request",
+ Language: "en_US.UTF-8",
+ }
+ return m.sendMessage(failMsg)
+ }
+
+ c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData)
+ c.remoteId = msg.PeersId
+ c.maxRemotePayload = msg.MaxPacketSize
+ c.remoteWin.add(msg.PeersWindow)
+ m.incomingChannels <- c
+ return nil
+}
+
+func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) {
+ ch, err := m.openChannel(chanType, extra)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return ch, ch.incomingRequests, nil
+}
+
+func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) {
+ ch := m.newChannel(chanType, channelOutbound, extra)
+
+ ch.maxIncomingPayload = channelMaxPacket
+
+ open := channelOpenMsg{
+ ChanType: chanType,
+ PeersWindow: ch.myWindow,
+ MaxPacketSize: ch.maxIncomingPayload,
+ TypeSpecificData: extra,
+ PeersId: ch.localId,
+ }
+ if err := m.sendMessage(open); err != nil {
+ return nil, err
+ }
+
+ switch msg := (<-ch.msg).(type) {
+ case *channelOpenConfirmMsg:
+ return ch, nil
+ case *channelOpenFailureMsg:
+ return nil, &OpenChannelError{msg.Reason, msg.Message}
+ default:
+ return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/mux_test.go b/vendor/golang.org/x/crypto/ssh/mux_test.go
new file mode 100644
index 000000000..591aae8e8
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/mux_test.go
@@ -0,0 +1,502 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "io"
+ "io/ioutil"
+ "sync"
+ "testing"
+)
+
+func muxPair() (*mux, *mux) {
+ a, b := memPipe()
+
+ s := newMux(a)
+ c := newMux(b)
+
+ return s, c
+}
+
+// Returns both ends of a channel, and the mux for the the 2nd
+// channel.
+func channelPair(t *testing.T) (*channel, *channel, *mux) {
+ c, s := muxPair()
+
+ res := make(chan *channel, 1)
+ go func() {
+ newCh, ok := <-s.incomingChannels
+ if !ok {
+ t.Fatalf("No incoming channel")
+ }
+ if newCh.ChannelType() != "chan" {
+ t.Fatalf("got type %q want chan", newCh.ChannelType())
+ }
+ ch, _, err := newCh.Accept()
+ if err != nil {
+ t.Fatalf("Accept %v", err)
+ }
+ res <- ch.(*channel)
+ }()
+
+ ch, err := c.openChannel("chan", nil)
+ if err != nil {
+ t.Fatalf("OpenChannel: %v", err)
+ }
+
+ return <-res, ch, c
+}
+
+// Test that stderr and stdout can be addressed from different
+// goroutines. This is intended for use with the race detector.
+func TestMuxChannelExtendedThreadSafety(t *testing.T) {
+ writer, reader, mux := channelPair(t)
+ defer writer.Close()
+ defer reader.Close()
+ defer mux.Close()
+
+ var wr, rd sync.WaitGroup
+ magic := "hello world"
+
+ wr.Add(2)
+ go func() {
+ io.WriteString(writer, magic)
+ wr.Done()
+ }()
+ go func() {
+ io.WriteString(writer.Stderr(), magic)
+ wr.Done()
+ }()
+
+ rd.Add(2)
+ go func() {
+ c, err := ioutil.ReadAll(reader)
+ if string(c) != magic {
+ t.Fatalf("stdout read got %q, want %q (error %s)", c, magic, err)
+ }
+ rd.Done()
+ }()
+ go func() {
+ c, err := ioutil.ReadAll(reader.Stderr())
+ if string(c) != magic {
+ t.Fatalf("stderr read got %q, want %q (error %s)", c, magic, err)
+ }
+ rd.Done()
+ }()
+
+ wr.Wait()
+ writer.CloseWrite()
+ rd.Wait()
+}
+
+func TestMuxReadWrite(t *testing.T) {
+ s, c, mux := channelPair(t)
+ defer s.Close()
+ defer c.Close()
+ defer mux.Close()
+
+ magic := "hello world"
+ magicExt := "hello stderr"
+ go func() {
+ _, err := s.Write([]byte(magic))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ _, err = s.Extended(1).Write([]byte(magicExt))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ err = s.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+ }()
+
+ var buf [1024]byte
+ n, err := c.Read(buf[:])
+ if err != nil {
+ t.Fatalf("server Read: %v", err)
+ }
+ got := string(buf[:n])
+ if got != magic {
+ t.Fatalf("server: got %q want %q", got, magic)
+ }
+
+ n, err = c.Extended(1).Read(buf[:])
+ if err != nil {
+ t.Fatalf("server Read: %v", err)
+ }
+
+ got = string(buf[:n])
+ if got != magicExt {
+ t.Fatalf("server: got %q want %q", got, magic)
+ }
+}
+
+func TestMuxChannelOverflow(t *testing.T) {
+ reader, writer, mux := channelPair(t)
+ defer reader.Close()
+ defer writer.Close()
+ defer mux.Close()
+
+ wDone := make(chan int, 1)
+ go func() {
+ if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil {
+ t.Errorf("could not fill window: %v", err)
+ }
+ writer.Write(make([]byte, 1))
+ wDone <- 1
+ }()
+ writer.remoteWin.waitWriterBlocked()
+
+ // Send 1 byte.
+ packet := make([]byte, 1+4+4+1)
+ packet[0] = msgChannelData
+ marshalUint32(packet[1:], writer.remoteId)
+ marshalUint32(packet[5:], uint32(1))
+ packet[9] = 42
+
+ if err := writer.mux.conn.writePacket(packet); err != nil {
+ t.Errorf("could not send packet")
+ }
+ if _, err := reader.SendRequest("hello", true, nil); err == nil {
+ t.Errorf("SendRequest succeeded.")
+ }
+ <-wDone
+}
+
+func TestMuxChannelCloseWriteUnblock(t *testing.T) {
+ reader, writer, mux := channelPair(t)
+ defer reader.Close()
+ defer writer.Close()
+ defer mux.Close()
+
+ wDone := make(chan int, 1)
+ go func() {
+ if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil {
+ t.Errorf("could not fill window: %v", err)
+ }
+ if _, err := writer.Write(make([]byte, 1)); err != io.EOF {
+ t.Errorf("got %v, want EOF for unblock write", err)
+ }
+ wDone <- 1
+ }()
+
+ writer.remoteWin.waitWriterBlocked()
+ reader.Close()
+ <-wDone
+}
+
+func TestMuxConnectionCloseWriteUnblock(t *testing.T) {
+ reader, writer, mux := channelPair(t)
+ defer reader.Close()
+ defer writer.Close()
+ defer mux.Close()
+
+ wDone := make(chan int, 1)
+ go func() {
+ if _, err := writer.Write(make([]byte, channelWindowSize)); err != nil {
+ t.Errorf("could not fill window: %v", err)
+ }
+ if _, err := writer.Write(make([]byte, 1)); err != io.EOF {
+ t.Errorf("got %v, want EOF for unblock write", err)
+ }
+ wDone <- 1
+ }()
+
+ writer.remoteWin.waitWriterBlocked()
+ mux.Close()
+ <-wDone
+}
+
+func TestMuxReject(t *testing.T) {
+ client, server := muxPair()
+ defer server.Close()
+ defer client.Close()
+
+ go func() {
+ ch, ok := <-server.incomingChannels
+ if !ok {
+ t.Fatalf("Accept")
+ }
+ if ch.ChannelType() != "ch" || string(ch.ExtraData()) != "extra" {
+ t.Fatalf("unexpected channel: %q, %q", ch.ChannelType(), ch.ExtraData())
+ }
+ ch.Reject(RejectionReason(42), "message")
+ }()
+
+ ch, err := client.openChannel("ch", []byte("extra"))
+ if ch != nil {
+ t.Fatal("openChannel not rejected")
+ }
+
+ ocf, ok := err.(*OpenChannelError)
+ if !ok {
+ t.Errorf("got %#v want *OpenChannelError", err)
+ } else if ocf.Reason != 42 || ocf.Message != "message" {
+ t.Errorf("got %#v, want {Reason: 42, Message: %q}", ocf, "message")
+ }
+
+ want := "ssh: rejected: unknown reason 42 (message)"
+ if err.Error() != want {
+ t.Errorf("got %q, want %q", err.Error(), want)
+ }
+}
+
+func TestMuxChannelRequest(t *testing.T) {
+ client, server, mux := channelPair(t)
+ defer server.Close()
+ defer client.Close()
+ defer mux.Close()
+
+ var received int
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ for r := range server.incomingRequests {
+ received++
+ r.Reply(r.Type == "yes", nil)
+ }
+ wg.Done()
+ }()
+ _, err := client.SendRequest("yes", false, nil)
+ if err != nil {
+ t.Fatalf("SendRequest: %v", err)
+ }
+ ok, err := client.SendRequest("yes", true, nil)
+ if err != nil {
+ t.Fatalf("SendRequest: %v", err)
+ }
+
+ if !ok {
+ t.Errorf("SendRequest(yes): %v", ok)
+
+ }
+
+ ok, err = client.SendRequest("no", true, nil)
+ if err != nil {
+ t.Fatalf("SendRequest: %v", err)
+ }
+ if ok {
+ t.Errorf("SendRequest(no): %v", ok)
+
+ }
+
+ client.Close()
+ wg.Wait()
+
+ if received != 3 {
+ t.Errorf("got %d requests, want %d", received, 3)
+ }
+}
+
+func TestMuxGlobalRequest(t *testing.T) {
+ clientMux, serverMux := muxPair()
+ defer serverMux.Close()
+ defer clientMux.Close()
+
+ var seen bool
+ go func() {
+ for r := range serverMux.incomingRequests {
+ seen = seen || r.Type == "peek"
+ if r.WantReply {
+ err := r.Reply(r.Type == "yes",
+ append([]byte(r.Type), r.Payload...))
+ if err != nil {
+ t.Errorf("AckRequest: %v", err)
+ }
+ }
+ }
+ }()
+
+ _, _, err := clientMux.SendRequest("peek", false, nil)
+ if err != nil {
+ t.Errorf("SendRequest: %v", err)
+ }
+
+ ok, data, err := clientMux.SendRequest("yes", true, []byte("a"))
+ if !ok || string(data) != "yesa" || err != nil {
+ t.Errorf("SendRequest(\"yes\", true, \"a\"): %v %v %v",
+ ok, data, err)
+ }
+ if ok, data, err := clientMux.SendRequest("yes", true, []byte("a")); !ok || string(data) != "yesa" || err != nil {
+ t.Errorf("SendRequest(\"yes\", true, \"a\"): %v %v %v",
+ ok, data, err)
+ }
+
+ if ok, data, err := clientMux.SendRequest("no", true, []byte("a")); ok || string(data) != "noa" || err != nil {
+ t.Errorf("SendRequest(\"no\", true, \"a\"): %v %v %v",
+ ok, data, err)
+ }
+
+ if !seen {
+ t.Errorf("never saw 'peek' request")
+ }
+}
+
+func TestMuxGlobalRequestUnblock(t *testing.T) {
+ clientMux, serverMux := muxPair()
+ defer serverMux.Close()
+ defer clientMux.Close()
+
+ result := make(chan error, 1)
+ go func() {
+ _, _, err := clientMux.SendRequest("hello", true, nil)
+ result <- err
+ }()
+
+ <-serverMux.incomingRequests
+ serverMux.conn.Close()
+ err := <-result
+
+ if err != io.EOF {
+ t.Errorf("want EOF, got %v", io.EOF)
+ }
+}
+
+func TestMuxChannelRequestUnblock(t *testing.T) {
+ a, b, connB := channelPair(t)
+ defer a.Close()
+ defer b.Close()
+ defer connB.Close()
+
+ result := make(chan error, 1)
+ go func() {
+ _, err := a.SendRequest("hello", true, nil)
+ result <- err
+ }()
+
+ <-b.incomingRequests
+ connB.conn.Close()
+ err := <-result
+
+ if err != io.EOF {
+ t.Errorf("want EOF, got %v", err)
+ }
+}
+
+func TestMuxCloseChannel(t *testing.T) {
+ r, w, mux := channelPair(t)
+ defer mux.Close()
+ defer r.Close()
+ defer w.Close()
+
+ result := make(chan error, 1)
+ go func() {
+ var b [1024]byte
+ _, err := r.Read(b[:])
+ result <- err
+ }()
+ if err := w.Close(); err != nil {
+ t.Errorf("w.Close: %v", err)
+ }
+
+ if _, err := w.Write([]byte("hello")); err != io.EOF {
+ t.Errorf("got err %v, want io.EOF after Close", err)
+ }
+
+ if err := <-result; err != io.EOF {
+ t.Errorf("got %v (%T), want io.EOF", err, err)
+ }
+}
+
+func TestMuxCloseWriteChannel(t *testing.T) {
+ r, w, mux := channelPair(t)
+ defer mux.Close()
+
+ result := make(chan error, 1)
+ go func() {
+ var b [1024]byte
+ _, err := r.Read(b[:])
+ result <- err
+ }()
+ if err := w.CloseWrite(); err != nil {
+ t.Errorf("w.CloseWrite: %v", err)
+ }
+
+ if _, err := w.Write([]byte("hello")); err != io.EOF {
+ t.Errorf("got err %v, want io.EOF after CloseWrite", err)
+ }
+
+ if err := <-result; err != io.EOF {
+ t.Errorf("got %v (%T), want io.EOF", err, err)
+ }
+}
+
+func TestMuxInvalidRecord(t *testing.T) {
+ a, b := muxPair()
+ defer a.Close()
+ defer b.Close()
+
+ packet := make([]byte, 1+4+4+1)
+ packet[0] = msgChannelData
+ marshalUint32(packet[1:], 29348723 /* invalid channel id */)
+ marshalUint32(packet[5:], 1)
+ packet[9] = 42
+
+ a.conn.writePacket(packet)
+ go a.SendRequest("hello", false, nil)
+ // 'a' wrote an invalid packet, so 'b' has exited.
+ req, ok := <-b.incomingRequests
+ if ok {
+ t.Errorf("got request %#v after receiving invalid packet", req)
+ }
+}
+
+func TestZeroWindowAdjust(t *testing.T) {
+ a, b, mux := channelPair(t)
+ defer a.Close()
+ defer b.Close()
+ defer mux.Close()
+
+ go func() {
+ io.WriteString(a, "hello")
+ // bogus adjust.
+ a.sendMessage(windowAdjustMsg{})
+ io.WriteString(a, "world")
+ a.Close()
+ }()
+
+ want := "helloworld"
+ c, _ := ioutil.ReadAll(b)
+ if string(c) != want {
+ t.Errorf("got %q want %q", c, want)
+ }
+}
+
+func TestMuxMaxPacketSize(t *testing.T) {
+ a, b, mux := channelPair(t)
+ defer a.Close()
+ defer b.Close()
+ defer mux.Close()
+
+ large := make([]byte, a.maxRemotePayload+1)
+ packet := make([]byte, 1+4+4+1+len(large))
+ packet[0] = msgChannelData
+ marshalUint32(packet[1:], a.remoteId)
+ marshalUint32(packet[5:], uint32(len(large)))
+ packet[9] = 42
+
+ if err := a.mux.conn.writePacket(packet); err != nil {
+ t.Errorf("could not send packet")
+ }
+
+ go a.SendRequest("hello", false, nil)
+
+ _, ok := <-b.incomingRequests
+ if ok {
+ t.Errorf("connection still alive after receiving large packet.")
+ }
+}
+
+// Don't ship code with debug=true.
+func TestDebug(t *testing.T) {
+ if debugMux {
+ t.Error("mux debug switched on")
+ }
+ if debugHandshake {
+ t.Error("handshake debug switched on")
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
new file mode 100644
index 000000000..e73a1c1ae
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -0,0 +1,489 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+)
+
+// The Permissions type holds fine-grained permissions that are
+// specific to a user or a specific authentication method for a
+// user. Permissions, except for "source-address", must be enforced in
+// the server application layer, after successful authentication. The
+// Permissions are passed on in ServerConn so a server implementation
+// can honor them.
+type Permissions struct {
+ // Critical options restrict default permissions. Common
+ // restrictions are "source-address" and "force-command". If
+ // the server cannot enforce the restriction, or does not
+ // recognize it, the user should not authenticate.
+ CriticalOptions map[string]string
+
+ // Extensions are extra functionality that the server may
+ // offer on authenticated connections. Common extensions are
+ // "permit-agent-forwarding", "permit-X11-forwarding". Lack of
+ // support for an extension does not preclude authenticating a
+ // user.
+ Extensions map[string]string
+}
+
+// ServerConfig holds server specific configuration data.
+type ServerConfig struct {
+ // Config contains configuration shared between client and server.
+ Config
+
+ hostKeys []Signer
+
+ // NoClientAuth is true if clients are allowed to connect without
+ // authenticating.
+ NoClientAuth bool
+
+ // PasswordCallback, if non-nil, is called when a user
+ // attempts to authenticate using a password.
+ PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
+
+ // PublicKeyCallback, if non-nil, is called when a client attempts public
+ // key authentication. It must return true if the given public key is
+ // valid for the given user. For example, see CertChecker.Authenticate.
+ PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
+
+ // KeyboardInteractiveCallback, if non-nil, is called when
+ // keyboard-interactive authentication is selected (RFC
+ // 4256). The client object's Challenge function should be
+ // used to query the user. The callback may offer multiple
+ // Challenge rounds. To avoid information leaks, the client
+ // should be presented a challenge even if the user is
+ // unknown.
+ KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error)
+
+ // AuthLogCallback, if non-nil, is called to log all authentication
+ // attempts.
+ AuthLogCallback func(conn ConnMetadata, method string, err error)
+
+ // ServerVersion is the version identification string to announce in
+ // the public handshake.
+ // If empty, a reasonable default is used.
+ // Note that RFC 4253 section 4.2 requires that this string start with
+ // "SSH-2.0-".
+ ServerVersion string
+}
+
+// AddHostKey adds a private key as a host key. If an existing host
+// key exists with the same algorithm, it is overwritten. Each server
+// config must have at least one host key.
+func (s *ServerConfig) AddHostKey(key Signer) {
+ for i, k := range s.hostKeys {
+ if k.PublicKey().Type() == key.PublicKey().Type() {
+ s.hostKeys[i] = key
+ return
+ }
+ }
+
+ s.hostKeys = append(s.hostKeys, key)
+}
+
+// cachedPubKey contains the results of querying whether a public key is
+// acceptable for a user.
+type cachedPubKey struct {
+ user string
+ pubKeyData []byte
+ result error
+ perms *Permissions
+}
+
+const maxCachedPubKeys = 16
+
+// pubKeyCache caches tests for public keys. Since SSH clients
+// will query whether a public key is acceptable before attempting to
+// authenticate with it, we end up with duplicate queries for public
+// key validity. The cache only applies to a single ServerConn.
+type pubKeyCache struct {
+ keys []cachedPubKey
+}
+
+// get returns the result for a given user/algo/key tuple.
+func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) {
+ for _, k := range c.keys {
+ if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) {
+ return k, true
+ }
+ }
+ return cachedPubKey{}, false
+}
+
+// add adds the given tuple to the cache.
+func (c *pubKeyCache) add(candidate cachedPubKey) {
+ if len(c.keys) < maxCachedPubKeys {
+ c.keys = append(c.keys, candidate)
+ }
+}
+
+// ServerConn is an authenticated SSH connection, as seen from the
+// server
+type ServerConn struct {
+ Conn
+
+ // If the succeeding authentication callback returned a
+ // non-nil Permissions pointer, it is stored here.
+ Permissions *Permissions
+}
+
+// NewServerConn starts a new SSH server with c as the underlying
+// transport. It starts with a handshake and, if the handshake is
+// unsuccessful, it closes the connection and returns an error. The
+// Request and NewChannel channels must be serviced, or the connection
+// will hang.
+func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
+ fullConf := *config
+ fullConf.SetDefaults()
+ s := &connection{
+ sshConn: sshConn{conn: c},
+ }
+ perms, err := s.serverHandshake(&fullConf)
+ if err != nil {
+ c.Close()
+ return nil, nil, nil, err
+ }
+ return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil
+}
+
+// signAndMarshal signs the data with the appropriate algorithm,
+// and serializes the result in SSH wire format.
+func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) {
+ sig, err := k.Sign(rand, data)
+ if err != nil {
+ return nil, err
+ }
+
+ return Marshal(sig), nil
+}
+
+// handshake performs key exchange and user authentication.
+func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) {
+ if len(config.hostKeys) == 0 {
+ return nil, errors.New("ssh: server has no host keys")
+ }
+
+ if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil {
+ return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
+ }
+
+ if config.ServerVersion != "" {
+ s.serverVersion = []byte(config.ServerVersion)
+ } else {
+ s.serverVersion = []byte(packageVersion)
+ }
+ var err error
+ s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion)
+ if err != nil {
+ return nil, err
+ }
+
+ tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */)
+ s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config)
+
+ if err := s.transport.requestInitialKeyChange(); err != nil {
+ return nil, err
+ }
+
+ // We just did the key change, so the session ID is established.
+ s.sessionID = s.transport.getSessionID()
+
+ var packet []byte
+ if packet, err = s.transport.readPacket(); err != nil {
+ return nil, err
+ }
+
+ var serviceRequest serviceRequestMsg
+ if err = Unmarshal(packet, &serviceRequest); err != nil {
+ return nil, err
+ }
+ if serviceRequest.Service != serviceUserAuth {
+ return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating")
+ }
+ serviceAccept := serviceAcceptMsg{
+ Service: serviceUserAuth,
+ }
+ if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil {
+ return nil, err
+ }
+
+ perms, err := s.serverAuthenticate(config)
+ if err != nil {
+ return nil, err
+ }
+ s.mux = newMux(s.transport)
+ return perms, err
+}
+
+func isAcceptableAlgo(algo string) bool {
+ switch algo {
+ case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519,
+ CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01:
+ return true
+ }
+ return false
+}
+
+func checkSourceAddress(addr net.Addr, sourceAddr string) error {
+ if addr == nil {
+ return errors.New("ssh: no address known for client, but source-address match required")
+ }
+
+ tcpAddr, ok := addr.(*net.TCPAddr)
+ if !ok {
+ return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
+ }
+
+ if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
+ if bytes.Equal(allowedIP, tcpAddr.IP) {
+ return nil
+ }
+ } else {
+ _, ipNet, err := net.ParseCIDR(sourceAddr)
+ if err != nil {
+ return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
+ }
+
+ if ipNet.Contains(tcpAddr.IP) {
+ return nil
+ }
+ }
+
+ return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr)
+}
+
+func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
+ var err error
+ var cache pubKeyCache
+ var perms *Permissions
+
+userAuthLoop:
+ for {
+ var userAuthReq userAuthRequestMsg
+ if packet, err := s.transport.readPacket(); err != nil {
+ return nil, err
+ } else if err = Unmarshal(packet, &userAuthReq); err != nil {
+ return nil, err
+ }
+
+ if userAuthReq.Service != serviceSSH {
+ return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service)
+ }
+
+ s.user = userAuthReq.User
+ perms = nil
+ authErr := errors.New("no auth passed yet")
+
+ switch userAuthReq.Method {
+ case "none":
+ if config.NoClientAuth {
+ s.user = ""
+ authErr = nil
+ }
+ case "password":
+ if config.PasswordCallback == nil {
+ authErr = errors.New("ssh: password auth not configured")
+ break
+ }
+ payload := userAuthReq.Payload
+ if len(payload) < 1 || payload[0] != 0 {
+ return nil, parseError(msgUserAuthRequest)
+ }
+ payload = payload[1:]
+ password, payload, ok := parseString(payload)
+ if !ok || len(payload) > 0 {
+ return nil, parseError(msgUserAuthRequest)
+ }
+
+ perms, authErr = config.PasswordCallback(s, password)
+ case "keyboard-interactive":
+ if config.KeyboardInteractiveCallback == nil {
+ authErr = errors.New("ssh: keyboard-interactive auth not configubred")
+ break
+ }
+
+ prompter := &sshClientKeyboardInteractive{s}
+ perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge)
+ case "publickey":
+ if config.PublicKeyCallback == nil {
+ authErr = errors.New("ssh: publickey auth not configured")
+ break
+ }
+ payload := userAuthReq.Payload
+ if len(payload) < 1 {
+ return nil, parseError(msgUserAuthRequest)
+ }
+ isQuery := payload[0] == 0
+ payload = payload[1:]
+ algoBytes, payload, ok := parseString(payload)
+ if !ok {
+ return nil, parseError(msgUserAuthRequest)
+ }
+ algo := string(algoBytes)
+ if !isAcceptableAlgo(algo) {
+ authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
+ break
+ }
+
+ pubKeyData, payload, ok := parseString(payload)
+ if !ok {
+ return nil, parseError(msgUserAuthRequest)
+ }
+
+ pubKey, err := ParsePublicKey(pubKeyData)
+ if err != nil {
+ return nil, err
+ }
+
+ candidate, ok := cache.get(s.user, pubKeyData)
+ if !ok {
+ candidate.user = s.user
+ candidate.pubKeyData = pubKeyData
+ candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey)
+ if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" {
+ candidate.result = checkSourceAddress(
+ s.RemoteAddr(),
+ candidate.perms.CriticalOptions[sourceAddressCriticalOption])
+ }
+ cache.add(candidate)
+ }
+
+ if isQuery {
+ // The client can query if the given public key
+ // would be okay.
+ if len(payload) > 0 {
+ return nil, parseError(msgUserAuthRequest)
+ }
+
+ if candidate.result == nil {
+ okMsg := userAuthPubKeyOkMsg{
+ Algo: algo,
+ PubKey: pubKeyData,
+ }
+ if err = s.transport.writePacket(Marshal(&okMsg)); err != nil {
+ return nil, err
+ }
+ continue userAuthLoop
+ }
+ authErr = candidate.result
+ } else {
+ sig, payload, ok := parseSignature(payload)
+ if !ok || len(payload) > 0 {
+ return nil, parseError(msgUserAuthRequest)
+ }
+ // Ensure the public key algo and signature algo
+ // are supported. Compare the private key
+ // algorithm name that corresponds to algo with
+ // sig.Format. This is usually the same, but
+ // for certs, the names differ.
+ if !isAcceptableAlgo(sig.Format) {
+ break
+ }
+ signedData := buildDataSignedForAuth(s.transport.getSessionID(), userAuthReq, algoBytes, pubKeyData)
+
+ if err := pubKey.Verify(signedData, sig); err != nil {
+ return nil, err
+ }
+
+ authErr = candidate.result
+ perms = candidate.perms
+ }
+ default:
+ authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method)
+ }
+
+ if config.AuthLogCallback != nil {
+ config.AuthLogCallback(s, userAuthReq.Method, authErr)
+ }
+
+ if authErr == nil {
+ break userAuthLoop
+ }
+
+ var failureMsg userAuthFailureMsg
+ if config.PasswordCallback != nil {
+ failureMsg.Methods = append(failureMsg.Methods, "password")
+ }
+ if config.PublicKeyCallback != nil {
+ failureMsg.Methods = append(failureMsg.Methods, "publickey")
+ }
+ if config.KeyboardInteractiveCallback != nil {
+ failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive")
+ }
+
+ if len(failureMsg.Methods) == 0 {
+ return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false")
+ }
+
+ if err = s.transport.writePacket(Marshal(&failureMsg)); err != nil {
+ return nil, err
+ }
+ }
+
+ if err = s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil {
+ return nil, err
+ }
+ return perms, nil
+}
+
+// sshClientKeyboardInteractive implements a ClientKeyboardInteractive by
+// asking the client on the other side of a ServerConn.
+type sshClientKeyboardInteractive struct {
+ *connection
+}
+
+func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
+ if len(questions) != len(echos) {
+ return nil, errors.New("ssh: echos and questions must have equal length")
+ }
+
+ var prompts []byte
+ for i := range questions {
+ prompts = appendString(prompts, questions[i])
+ prompts = appendBool(prompts, echos[i])
+ }
+
+ if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{
+ Instruction: instruction,
+ NumPrompts: uint32(len(questions)),
+ Prompts: prompts,
+ })); err != nil {
+ return nil, err
+ }
+
+ packet, err := c.transport.readPacket()
+ if err != nil {
+ return nil, err
+ }
+ if packet[0] != msgUserAuthInfoResponse {
+ return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0])
+ }
+ packet = packet[1:]
+
+ n, packet, ok := parseUint32(packet)
+ if !ok || int(n) != len(questions) {
+ return nil, parseError(msgUserAuthInfoResponse)
+ }
+
+ for i := uint32(0); i < n; i++ {
+ ans, rest, ok := parseString(packet)
+ if !ok {
+ return nil, parseError(msgUserAuthInfoResponse)
+ }
+
+ answers = append(answers, string(ans))
+ packet = rest
+ }
+ if len(packet) != 0 {
+ return nil, errors.New("ssh: junk at end of message")
+ }
+
+ return answers, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go
new file mode 100644
index 000000000..09eb00919
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/session.go
@@ -0,0 +1,612 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+// Session implements an interactive session described in
+// "RFC 4254, section 6".
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "sync"
+)
+
+type Signal string
+
+// POSIX signals as listed in RFC 4254 Section 6.10.
+const (
+ SIGABRT Signal = "ABRT"
+ SIGALRM Signal = "ALRM"
+ SIGFPE Signal = "FPE"
+ SIGHUP Signal = "HUP"
+ SIGILL Signal = "ILL"
+ SIGINT Signal = "INT"
+ SIGKILL Signal = "KILL"
+ SIGPIPE Signal = "PIPE"
+ SIGQUIT Signal = "QUIT"
+ SIGSEGV Signal = "SEGV"
+ SIGTERM Signal = "TERM"
+ SIGUSR1 Signal = "USR1"
+ SIGUSR2 Signal = "USR2"
+)
+
+var signals = map[Signal]int{
+ SIGABRT: 6,
+ SIGALRM: 14,
+ SIGFPE: 8,
+ SIGHUP: 1,
+ SIGILL: 4,
+ SIGINT: 2,
+ SIGKILL: 9,
+ SIGPIPE: 13,
+ SIGQUIT: 3,
+ SIGSEGV: 11,
+ SIGTERM: 15,
+}
+
+type TerminalModes map[uint8]uint32
+
+// POSIX terminal mode flags as listed in RFC 4254 Section 8.
+const (
+ tty_OP_END = 0
+ VINTR = 1
+ VQUIT = 2
+ VERASE = 3
+ VKILL = 4
+ VEOF = 5
+ VEOL = 6
+ VEOL2 = 7
+ VSTART = 8
+ VSTOP = 9
+ VSUSP = 10
+ VDSUSP = 11
+ VREPRINT = 12
+ VWERASE = 13
+ VLNEXT = 14
+ VFLUSH = 15
+ VSWTCH = 16
+ VSTATUS = 17
+ VDISCARD = 18
+ IGNPAR = 30
+ PARMRK = 31
+ INPCK = 32
+ ISTRIP = 33
+ INLCR = 34
+ IGNCR = 35
+ ICRNL = 36
+ IUCLC = 37
+ IXON = 38
+ IXANY = 39
+ IXOFF = 40
+ IMAXBEL = 41
+ ISIG = 50
+ ICANON = 51
+ XCASE = 52
+ ECHO = 53
+ ECHOE = 54
+ ECHOK = 55
+ ECHONL = 56
+ NOFLSH = 57
+ TOSTOP = 58
+ IEXTEN = 59
+ ECHOCTL = 60
+ ECHOKE = 61
+ PENDIN = 62
+ OPOST = 70
+ OLCUC = 71
+ ONLCR = 72
+ OCRNL = 73
+ ONOCR = 74
+ ONLRET = 75
+ CS7 = 90
+ CS8 = 91
+ PARENB = 92
+ PARODD = 93
+ TTY_OP_ISPEED = 128
+ TTY_OP_OSPEED = 129
+)
+
+// A Session represents a connection to a remote command or shell.
+type Session struct {
+ // Stdin specifies the remote process's standard input.
+ // If Stdin is nil, the remote process reads from an empty
+ // bytes.Buffer.
+ Stdin io.Reader
+
+ // Stdout and Stderr specify the remote process's standard
+ // output and error.
+ //
+ // If either is nil, Run connects the corresponding file
+ // descriptor to an instance of ioutil.Discard. There is a
+ // fixed amount of buffering that is shared for the two streams.
+ // If either blocks it may eventually cause the remote
+ // command to block.
+ Stdout io.Writer
+ Stderr io.Writer
+
+ ch Channel // the channel backing this session
+ started bool // true once Start, Run or Shell is invoked.
+ copyFuncs []func() error
+ errors chan error // one send per copyFunc
+
+ // true if pipe method is active
+ stdinpipe, stdoutpipe, stderrpipe bool
+
+ // stdinPipeWriter is non-nil if StdinPipe has not been called
+ // and Stdin was specified by the user; it is the write end of
+ // a pipe connecting Session.Stdin to the stdin channel.
+ stdinPipeWriter io.WriteCloser
+
+ exitStatus chan error
+}
+
+// SendRequest sends an out-of-band channel request on the SSH channel
+// underlying the session.
+func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
+ return s.ch.SendRequest(name, wantReply, payload)
+}
+
+func (s *Session) Close() error {
+ return s.ch.Close()
+}
+
+// RFC 4254 Section 6.4.
+type setenvRequest struct {
+ Name string
+ Value string
+}
+
+// Setenv sets an environment variable that will be applied to any
+// command executed by Shell or Run.
+func (s *Session) Setenv(name, value string) error {
+ msg := setenvRequest{
+ Name: name,
+ Value: value,
+ }
+ ok, err := s.ch.SendRequest("env", true, Marshal(&msg))
+ if err == nil && !ok {
+ err = errors.New("ssh: setenv failed")
+ }
+ return err
+}
+
+// RFC 4254 Section 6.2.
+type ptyRequestMsg struct {
+ Term string
+ Columns uint32
+ Rows uint32
+ Width uint32
+ Height uint32
+ Modelist string
+}
+
+// RequestPty requests the association of a pty with the session on the remote host.
+func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error {
+ var tm []byte
+ for k, v := range termmodes {
+ kv := struct {
+ Key byte
+ Val uint32
+ }{k, v}
+
+ tm = append(tm, Marshal(&kv)...)
+ }
+ tm = append(tm, tty_OP_END)
+ req := ptyRequestMsg{
+ Term: term,
+ Columns: uint32(w),
+ Rows: uint32(h),
+ Width: uint32(w * 8),
+ Height: uint32(h * 8),
+ Modelist: string(tm),
+ }
+ ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req))
+ if err == nil && !ok {
+ err = errors.New("ssh: pty-req failed")
+ }
+ return err
+}
+
+// RFC 4254 Section 6.5.
+type subsystemRequestMsg struct {
+ Subsystem string
+}
+
+// RequestSubsystem requests the association of a subsystem with the session on the remote host.
+// A subsystem is a predefined command that runs in the background when the ssh session is initiated
+func (s *Session) RequestSubsystem(subsystem string) error {
+ msg := subsystemRequestMsg{
+ Subsystem: subsystem,
+ }
+ ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg))
+ if err == nil && !ok {
+ err = errors.New("ssh: subsystem request failed")
+ }
+ return err
+}
+
+// RFC 4254 Section 6.9.
+type signalMsg struct {
+ Signal string
+}
+
+// Signal sends the given signal to the remote process.
+// sig is one of the SIG* constants.
+func (s *Session) Signal(sig Signal) error {
+ msg := signalMsg{
+ Signal: string(sig),
+ }
+
+ _, err := s.ch.SendRequest("signal", false, Marshal(&msg))
+ return err
+}
+
+// RFC 4254 Section 6.5.
+type execMsg struct {
+ Command string
+}
+
+// Start runs cmd on the remote host. Typically, the remote
+// server passes cmd to the shell for interpretation.
+// A Session only accepts one call to Run, Start or Shell.
+func (s *Session) Start(cmd string) error {
+ if s.started {
+ return errors.New("ssh: session already started")
+ }
+ req := execMsg{
+ Command: cmd,
+ }
+
+ ok, err := s.ch.SendRequest("exec", true, Marshal(&req))
+ if err == nil && !ok {
+ err = fmt.Errorf("ssh: command %v failed", cmd)
+ }
+ if err != nil {
+ return err
+ }
+ return s.start()
+}
+
+// Run runs cmd on the remote host. Typically, the remote
+// server passes cmd to the shell for interpretation.
+// A Session only accepts one call to Run, Start, Shell, Output,
+// or CombinedOutput.
+//
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the command fails to run or doesn't complete successfully, the
+// error is of type *ExitError. Other error types may be
+// returned for I/O problems.
+func (s *Session) Run(cmd string) error {
+ err := s.Start(cmd)
+ if err != nil {
+ return err
+ }
+ return s.Wait()
+}
+
+// Output runs cmd on the remote host and returns its standard output.
+func (s *Session) Output(cmd string) ([]byte, error) {
+ if s.Stdout != nil {
+ return nil, errors.New("ssh: Stdout already set")
+ }
+ var b bytes.Buffer
+ s.Stdout = &b
+ err := s.Run(cmd)
+ return b.Bytes(), err
+}
+
+type singleWriter struct {
+ b bytes.Buffer
+ mu sync.Mutex
+}
+
+func (w *singleWriter) Write(p []byte) (int, error) {
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ return w.b.Write(p)
+}
+
+// CombinedOutput runs cmd on the remote host and returns its combined
+// standard output and standard error.
+func (s *Session) CombinedOutput(cmd string) ([]byte, error) {
+ if s.Stdout != nil {
+ return nil, errors.New("ssh: Stdout already set")
+ }
+ if s.Stderr != nil {
+ return nil, errors.New("ssh: Stderr already set")
+ }
+ var b singleWriter
+ s.Stdout = &b
+ s.Stderr = &b
+ err := s.Run(cmd)
+ return b.b.Bytes(), err
+}
+
+// Shell starts a login shell on the remote host. A Session only
+// accepts one call to Run, Start, Shell, Output, or CombinedOutput.
+func (s *Session) Shell() error {
+ if s.started {
+ return errors.New("ssh: session already started")
+ }
+
+ ok, err := s.ch.SendRequest("shell", true, nil)
+ if err == nil && !ok {
+ return errors.New("ssh: could not start shell")
+ }
+ if err != nil {
+ return err
+ }
+ return s.start()
+}
+
+func (s *Session) start() error {
+ s.started = true
+
+ type F func(*Session)
+ for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} {
+ setupFd(s)
+ }
+
+ s.errors = make(chan error, len(s.copyFuncs))
+ for _, fn := range s.copyFuncs {
+ go func(fn func() error) {
+ s.errors <- fn()
+ }(fn)
+ }
+ return nil
+}
+
+// Wait waits for the remote command to exit.
+//
+// The returned error is nil if the command runs, has no problems
+// copying stdin, stdout, and stderr, and exits with a zero exit
+// status.
+//
+// If the command fails to run or doesn't complete successfully, the
+// error is of type *ExitError. Other error types may be
+// returned for I/O problems.
+func (s *Session) Wait() error {
+ if !s.started {
+ return errors.New("ssh: session not started")
+ }
+ waitErr := <-s.exitStatus
+
+ if s.stdinPipeWriter != nil {
+ s.stdinPipeWriter.Close()
+ }
+ var copyError error
+ for _ = range s.copyFuncs {
+ if err := <-s.errors; err != nil && copyError == nil {
+ copyError = err
+ }
+ }
+ if waitErr != nil {
+ return waitErr
+ }
+ return copyError
+}
+
+func (s *Session) wait(reqs <-chan *Request) error {
+ wm := Waitmsg{status: -1}
+ // Wait for msg channel to be closed before returning.
+ for msg := range reqs {
+ switch msg.Type {
+ case "exit-status":
+ d := msg.Payload
+ wm.status = int(d[0])<<24 | int(d[1])<<16 | int(d[2])<<8 | int(d[3])
+ case "exit-signal":
+ var sigval struct {
+ Signal string
+ CoreDumped bool
+ Error string
+ Lang string
+ }
+ if err := Unmarshal(msg.Payload, &sigval); err != nil {
+ return err
+ }
+
+ // Must sanitize strings?
+ wm.signal = sigval.Signal
+ wm.msg = sigval.Error
+ wm.lang = sigval.Lang
+ default:
+ // This handles keepalives and matches
+ // OpenSSH's behaviour.
+ if msg.WantReply {
+ msg.Reply(false, nil)
+ }
+ }
+ }
+ if wm.status == 0 {
+ return nil
+ }
+ if wm.status == -1 {
+ // exit-status was never sent from server
+ if wm.signal == "" {
+ return errors.New("wait: remote command exited without exit status or exit signal")
+ }
+ wm.status = 128
+ if _, ok := signals[Signal(wm.signal)]; ok {
+ wm.status += signals[Signal(wm.signal)]
+ }
+ }
+ return &ExitError{wm}
+}
+
+func (s *Session) stdin() {
+ if s.stdinpipe {
+ return
+ }
+ var stdin io.Reader
+ if s.Stdin == nil {
+ stdin = new(bytes.Buffer)
+ } else {
+ r, w := io.Pipe()
+ go func() {
+ _, err := io.Copy(w, s.Stdin)
+ w.CloseWithError(err)
+ }()
+ stdin, s.stdinPipeWriter = r, w
+ }
+ s.copyFuncs = append(s.copyFuncs, func() error {
+ _, err := io.Copy(s.ch, stdin)
+ if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF {
+ err = err1
+ }
+ return err
+ })
+}
+
+func (s *Session) stdout() {
+ if s.stdoutpipe {
+ return
+ }
+ if s.Stdout == nil {
+ s.Stdout = ioutil.Discard
+ }
+ s.copyFuncs = append(s.copyFuncs, func() error {
+ _, err := io.Copy(s.Stdout, s.ch)
+ return err
+ })
+}
+
+func (s *Session) stderr() {
+ if s.stderrpipe {
+ return
+ }
+ if s.Stderr == nil {
+ s.Stderr = ioutil.Discard
+ }
+ s.copyFuncs = append(s.copyFuncs, func() error {
+ _, err := io.Copy(s.Stderr, s.ch.Stderr())
+ return err
+ })
+}
+
+// sessionStdin reroutes Close to CloseWrite.
+type sessionStdin struct {
+ io.Writer
+ ch Channel
+}
+
+func (s *sessionStdin) Close() error {
+ return s.ch.CloseWrite()
+}
+
+// StdinPipe returns a pipe that will be connected to the
+// remote command's standard input when the command starts.
+func (s *Session) StdinPipe() (io.WriteCloser, error) {
+ if s.Stdin != nil {
+ return nil, errors.New("ssh: Stdin already set")
+ }
+ if s.started {
+ return nil, errors.New("ssh: StdinPipe after process started")
+ }
+ s.stdinpipe = true
+ return &sessionStdin{s.ch, s.ch}, nil
+}
+
+// StdoutPipe returns a pipe that will be connected to the
+// remote command's standard output when the command starts.
+// There is a fixed amount of buffering that is shared between
+// stdout and stderr streams. If the StdoutPipe reader is
+// not serviced fast enough it may eventually cause the
+// remote command to block.
+func (s *Session) StdoutPipe() (io.Reader, error) {
+ if s.Stdout != nil {
+ return nil, errors.New("ssh: Stdout already set")
+ }
+ if s.started {
+ return nil, errors.New("ssh: StdoutPipe after process started")
+ }
+ s.stdoutpipe = true
+ return s.ch, nil
+}
+
+// StderrPipe returns a pipe that will be connected to the
+// remote command's standard error when the command starts.
+// There is a fixed amount of buffering that is shared between
+// stdout and stderr streams. If the StderrPipe reader is
+// not serviced fast enough it may eventually cause the
+// remote command to block.
+func (s *Session) StderrPipe() (io.Reader, error) {
+ if s.Stderr != nil {
+ return nil, errors.New("ssh: Stderr already set")
+ }
+ if s.started {
+ return nil, errors.New("ssh: StderrPipe after process started")
+ }
+ s.stderrpipe = true
+ return s.ch.Stderr(), nil
+}
+
+// newSession returns a new interactive session on the remote host.
+func newSession(ch Channel, reqs <-chan *Request) (*Session, error) {
+ s := &Session{
+ ch: ch,
+ }
+ s.exitStatus = make(chan error, 1)
+ go func() {
+ s.exitStatus <- s.wait(reqs)
+ }()
+
+ return s, nil
+}
+
+// An ExitError reports unsuccessful completion of a remote command.
+type ExitError struct {
+ Waitmsg
+}
+
+func (e *ExitError) Error() string {
+ return e.Waitmsg.String()
+}
+
+// Waitmsg stores the information about an exited remote command
+// as reported by Wait.
+type Waitmsg struct {
+ status int
+ signal string
+ msg string
+ lang string
+}
+
+// ExitStatus returns the exit status of the remote command.
+func (w Waitmsg) ExitStatus() int {
+ return w.status
+}
+
+// Signal returns the exit signal of the remote command if
+// it was terminated violently.
+func (w Waitmsg) Signal() string {
+ return w.signal
+}
+
+// Msg returns the exit message given by the remote command
+func (w Waitmsg) Msg() string {
+ return w.msg
+}
+
+// Lang returns the language tag. See RFC 3066
+func (w Waitmsg) Lang() string {
+ return w.lang
+}
+
+func (w Waitmsg) String() string {
+ str := fmt.Sprintf("Process exited with status %v", w.status)
+ if w.signal != "" {
+ str += fmt.Sprintf(" from signal %v", w.signal)
+ }
+ if w.msg != "" {
+ str += fmt.Sprintf(". Reason was: %v", w.msg)
+ }
+ return str
+}
diff --git a/vendor/golang.org/x/crypto/ssh/session_test.go b/vendor/golang.org/x/crypto/ssh/session_test.go
new file mode 100644
index 000000000..f7f0f7642
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/session_test.go
@@ -0,0 +1,774 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+// Session tests.
+
+import (
+ "bytes"
+ crypto_rand "crypto/rand"
+ "errors"
+ "io"
+ "io/ioutil"
+ "math/rand"
+ "net"
+ "testing"
+
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+type serverType func(Channel, <-chan *Request, *testing.T)
+
+// dial constructs a new test server and returns a *ClientConn.
+func dial(handler serverType, t *testing.T) *Client {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+
+ go func() {
+ defer c1.Close()
+ conf := ServerConfig{
+ NoClientAuth: true,
+ }
+ conf.AddHostKey(testSigners["rsa"])
+
+ _, chans, reqs, err := NewServerConn(c1, &conf)
+ if err != nil {
+ t.Fatalf("Unable to handshake: %v", err)
+ }
+ go DiscardRequests(reqs)
+
+ for newCh := range chans {
+ if newCh.ChannelType() != "session" {
+ newCh.Reject(UnknownChannelType, "unknown channel type")
+ continue
+ }
+
+ ch, inReqs, err := newCh.Accept()
+ if err != nil {
+ t.Errorf("Accept: %v", err)
+ continue
+ }
+ go func() {
+ handler(ch, inReqs, t)
+ }()
+ }
+ }()
+
+ config := &ClientConfig{
+ User: "testuser",
+ }
+
+ conn, chans, reqs, err := NewClientConn(c2, "", config)
+ if err != nil {
+ t.Fatalf("unable to dial remote side: %v", err)
+ }
+
+ return NewClient(conn, chans, reqs)
+}
+
+// Test a simple string is returned to session.Stdout.
+func TestSessionShell(t *testing.T) {
+ conn := dial(shellHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+ stdout := new(bytes.Buffer)
+ session.Stdout = stdout
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %s", err)
+ }
+ if err := session.Wait(); err != nil {
+ t.Fatalf("Remote command did not exit cleanly: %v", err)
+ }
+ actual := stdout.String()
+ if actual != "golang" {
+ t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
+ }
+}
+
+// TODO(dfc) add support for Std{in,err}Pipe when the Server supports it.
+
+// Test a simple string is returned via StdoutPipe.
+func TestSessionStdoutPipe(t *testing.T) {
+ conn := dial(shellHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+ stdout, err := session.StdoutPipe()
+ if err != nil {
+ t.Fatalf("Unable to request StdoutPipe(): %v", err)
+ }
+ var buf bytes.Buffer
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ done := make(chan bool, 1)
+ go func() {
+ if _, err := io.Copy(&buf, stdout); err != nil {
+ t.Errorf("Copy of stdout failed: %v", err)
+ }
+ done <- true
+ }()
+ if err := session.Wait(); err != nil {
+ t.Fatalf("Remote command did not exit cleanly: %v", err)
+ }
+ <-done
+ actual := buf.String()
+ if actual != "golang" {
+ t.Fatalf("Remote shell did not return expected string: expected=golang, actual=%s", actual)
+ }
+}
+
+// Test that a simple string is returned via the Output helper,
+// and that stderr is discarded.
+func TestSessionOutput(t *testing.T) {
+ conn := dial(fixedOutputHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+
+ buf, err := session.Output("") // cmd is ignored by fixedOutputHandler
+ if err != nil {
+ t.Error("Remote command did not exit cleanly:", err)
+ }
+ w := "this-is-stdout."
+ g := string(buf)
+ if g != w {
+ t.Error("Remote command did not return expected string:")
+ t.Logf("want %q", w)
+ t.Logf("got %q", g)
+ }
+}
+
+// Test that both stdout and stderr are returned
+// via the CombinedOutput helper.
+func TestSessionCombinedOutput(t *testing.T) {
+ conn := dial(fixedOutputHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+
+ buf, err := session.CombinedOutput("") // cmd is ignored by fixedOutputHandler
+ if err != nil {
+ t.Error("Remote command did not exit cleanly:", err)
+ }
+ const stdout = "this-is-stdout."
+ const stderr = "this-is-stderr."
+ g := string(buf)
+ if g != stdout+stderr && g != stderr+stdout {
+ t.Error("Remote command did not return expected string:")
+ t.Logf("want %q, or %q", stdout+stderr, stderr+stdout)
+ t.Logf("got %q", g)
+ }
+}
+
+// Test non-0 exit status is returned correctly.
+func TestExitStatusNonZero(t *testing.T) {
+ conn := dial(exitStatusNonZeroHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ err = session.Wait()
+ if err == nil {
+ t.Fatalf("expected command to fail but it didn't")
+ }
+ e, ok := err.(*ExitError)
+ if !ok {
+ t.Fatalf("expected *ExitError but got %T", err)
+ }
+ if e.ExitStatus() != 15 {
+ t.Fatalf("expected command to exit with 15 but got %v", e.ExitStatus())
+ }
+}
+
+// Test 0 exit status is returned correctly.
+func TestExitStatusZero(t *testing.T) {
+ conn := dial(exitStatusZeroHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ err = session.Wait()
+ if err != nil {
+ t.Fatalf("expected nil but got %v", err)
+ }
+}
+
+// Test exit signal and status are both returned correctly.
+func TestExitSignalAndStatus(t *testing.T) {
+ conn := dial(exitSignalAndStatusHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ err = session.Wait()
+ if err == nil {
+ t.Fatalf("expected command to fail but it didn't")
+ }
+ e, ok := err.(*ExitError)
+ if !ok {
+ t.Fatalf("expected *ExitError but got %T", err)
+ }
+ if e.Signal() != "TERM" || e.ExitStatus() != 15 {
+ t.Fatalf("expected command to exit with signal TERM and status 15 but got signal %s and status %v", e.Signal(), e.ExitStatus())
+ }
+}
+
+// Test exit signal and status are both returned correctly.
+func TestKnownExitSignalOnly(t *testing.T) {
+ conn := dial(exitSignalHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ err = session.Wait()
+ if err == nil {
+ t.Fatalf("expected command to fail but it didn't")
+ }
+ e, ok := err.(*ExitError)
+ if !ok {
+ t.Fatalf("expected *ExitError but got %T", err)
+ }
+ if e.Signal() != "TERM" || e.ExitStatus() != 143 {
+ t.Fatalf("expected command to exit with signal TERM and status 143 but got signal %s and status %v", e.Signal(), e.ExitStatus())
+ }
+}
+
+// Test exit signal and status are both returned correctly.
+func TestUnknownExitSignal(t *testing.T) {
+ conn := dial(exitSignalUnknownHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ err = session.Wait()
+ if err == nil {
+ t.Fatalf("expected command to fail but it didn't")
+ }
+ e, ok := err.(*ExitError)
+ if !ok {
+ t.Fatalf("expected *ExitError but got %T", err)
+ }
+ if e.Signal() != "SYS" || e.ExitStatus() != 128 {
+ t.Fatalf("expected command to exit with signal SYS and status 128 but got signal %s and status %v", e.Signal(), e.ExitStatus())
+ }
+}
+
+// Test WaitMsg is not returned if the channel closes abruptly.
+func TestExitWithoutStatusOrSignal(t *testing.T) {
+ conn := dial(exitWithoutSignalOrStatus, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("Unable to request new session: %v", err)
+ }
+ defer session.Close()
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ err = session.Wait()
+ if err == nil {
+ t.Fatalf("expected command to fail but it didn't")
+ }
+ _, ok := err.(*ExitError)
+ if ok {
+ // you can't actually test for errors.errorString
+ // because it's not exported.
+ t.Fatalf("expected *errorString but got %T", err)
+ }
+}
+
+// windowTestBytes is the number of bytes that we'll send to the SSH server.
+const windowTestBytes = 16000 * 200
+
+// TestServerWindow writes random data to the server. The server is expected to echo
+// the same data back, which is compared against the original.
+func TestServerWindow(t *testing.T) {
+ origBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
+ io.CopyN(origBuf, crypto_rand.Reader, windowTestBytes)
+ origBytes := origBuf.Bytes()
+
+ conn := dial(echoHandler, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer session.Close()
+ result := make(chan []byte)
+
+ go func() {
+ defer close(result)
+ echoedBuf := bytes.NewBuffer(make([]byte, 0, windowTestBytes))
+ serverStdout, err := session.StdoutPipe()
+ if err != nil {
+ t.Errorf("StdoutPipe failed: %v", err)
+ return
+ }
+ n, err := copyNRandomly("stdout", echoedBuf, serverStdout, windowTestBytes)
+ if err != nil && err != io.EOF {
+ t.Errorf("Read only %d bytes from server, expected %d: %v", n, windowTestBytes, err)
+ }
+ result <- echoedBuf.Bytes()
+ }()
+
+ serverStdin, err := session.StdinPipe()
+ if err != nil {
+ t.Fatalf("StdinPipe failed: %v", err)
+ }
+ written, err := copyNRandomly("stdin", serverStdin, origBuf, windowTestBytes)
+ if err != nil {
+ t.Fatalf("failed to copy origBuf to serverStdin: %v", err)
+ }
+ if written != windowTestBytes {
+ t.Fatalf("Wrote only %d of %d bytes to server", written, windowTestBytes)
+ }
+
+ echoedBytes := <-result
+
+ if !bytes.Equal(origBytes, echoedBytes) {
+ t.Fatalf("Echoed buffer differed from original, orig %d, echoed %d", len(origBytes), len(echoedBytes))
+ }
+}
+
+// Verify the client can handle a keepalive packet from the server.
+func TestClientHandlesKeepalives(t *testing.T) {
+ conn := dial(channelKeepaliveSender, t)
+ defer conn.Close()
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer session.Close()
+ if err := session.Shell(); err != nil {
+ t.Fatalf("Unable to execute command: %v", err)
+ }
+ err = session.Wait()
+ if err != nil {
+ t.Fatalf("expected nil but got: %v", err)
+ }
+}
+
+type exitStatusMsg struct {
+ Status uint32
+}
+
+type exitSignalMsg struct {
+ Signal string
+ CoreDumped bool
+ Errmsg string
+ Lang string
+}
+
+func handleTerminalRequests(in <-chan *Request) {
+ for req := range in {
+ ok := false
+ switch req.Type {
+ case "shell":
+ ok = true
+ if len(req.Payload) > 0 {
+ // We don't accept any commands, only the default shell.
+ ok = false
+ }
+ case "env":
+ ok = true
+ }
+ req.Reply(ok, nil)
+ }
+}
+
+func newServerShell(ch Channel, in <-chan *Request, prompt string) *terminal.Terminal {
+ term := terminal.NewTerminal(ch, prompt)
+ go handleTerminalRequests(in)
+ return term
+}
+
+func exitStatusZeroHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ // this string is returned to stdout
+ shell := newServerShell(ch, in, "> ")
+ readLine(shell, t)
+ sendStatus(0, ch, t)
+}
+
+func exitStatusNonZeroHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ shell := newServerShell(ch, in, "> ")
+ readLine(shell, t)
+ sendStatus(15, ch, t)
+}
+
+func exitSignalAndStatusHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ shell := newServerShell(ch, in, "> ")
+ readLine(shell, t)
+ sendStatus(15, ch, t)
+ sendSignal("TERM", ch, t)
+}
+
+func exitSignalHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ shell := newServerShell(ch, in, "> ")
+ readLine(shell, t)
+ sendSignal("TERM", ch, t)
+}
+
+func exitSignalUnknownHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ shell := newServerShell(ch, in, "> ")
+ readLine(shell, t)
+ sendSignal("SYS", ch, t)
+}
+
+func exitWithoutSignalOrStatus(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ shell := newServerShell(ch, in, "> ")
+ readLine(shell, t)
+}
+
+func shellHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ // this string is returned to stdout
+ shell := newServerShell(ch, in, "golang")
+ readLine(shell, t)
+ sendStatus(0, ch, t)
+}
+
+// Ignores the command, writes fixed strings to stderr and stdout.
+// Strings are "this-is-stdout." and "this-is-stderr.".
+func fixedOutputHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ _, err := ch.Read(nil)
+
+ req, ok := <-in
+ if !ok {
+ t.Fatalf("error: expected channel request, got: %#v", err)
+ return
+ }
+
+ // ignore request, always send some text
+ req.Reply(true, nil)
+
+ _, err = io.WriteString(ch, "this-is-stdout.")
+ if err != nil {
+ t.Fatalf("error writing on server: %v", err)
+ }
+ _, err = io.WriteString(ch.Stderr(), "this-is-stderr.")
+ if err != nil {
+ t.Fatalf("error writing on server: %v", err)
+ }
+ sendStatus(0, ch, t)
+}
+
+func readLine(shell *terminal.Terminal, t *testing.T) {
+ if _, err := shell.ReadLine(); err != nil && err != io.EOF {
+ t.Errorf("unable to read line: %v", err)
+ }
+}
+
+func sendStatus(status uint32, ch Channel, t *testing.T) {
+ msg := exitStatusMsg{
+ Status: status,
+ }
+ if _, err := ch.SendRequest("exit-status", false, Marshal(&msg)); err != nil {
+ t.Errorf("unable to send status: %v", err)
+ }
+}
+
+func sendSignal(signal string, ch Channel, t *testing.T) {
+ sig := exitSignalMsg{
+ Signal: signal,
+ CoreDumped: false,
+ Errmsg: "Process terminated",
+ Lang: "en-GB-oed",
+ }
+ if _, err := ch.SendRequest("exit-signal", false, Marshal(&sig)); err != nil {
+ t.Errorf("unable to send signal: %v", err)
+ }
+}
+
+func discardHandler(ch Channel, t *testing.T) {
+ defer ch.Close()
+ io.Copy(ioutil.Discard, ch)
+}
+
+func echoHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err != nil {
+ t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTestBytes, err)
+ }
+}
+
+// copyNRandomly copies n bytes from src to dst. It uses a variable, and random,
+// buffer size to exercise more code paths.
+func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, error) {
+ var (
+ buf = make([]byte, 32*1024)
+ written int
+ remaining = n
+ )
+ for remaining > 0 {
+ l := rand.Intn(1 << 15)
+ if remaining < l {
+ l = remaining
+ }
+ nr, er := src.Read(buf[:l])
+ nw, ew := dst.Write(buf[:nr])
+ remaining -= nw
+ written += nw
+ if ew != nil {
+ return written, ew
+ }
+ if nr != nw {
+ return written, io.ErrShortWrite
+ }
+ if er != nil && er != io.EOF {
+ return written, er
+ }
+ }
+ return written, nil
+}
+
+func channelKeepaliveSender(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ shell := newServerShell(ch, in, "> ")
+ readLine(shell, t)
+ if _, err := ch.SendRequest("keepalive@openssh.com", true, nil); err != nil {
+ t.Errorf("unable to send channel keepalive request: %v", err)
+ }
+ sendStatus(0, ch, t)
+}
+
+func TestClientWriteEOF(t *testing.T) {
+ conn := dial(simpleEchoHandler, t)
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer session.Close()
+ stdin, err := session.StdinPipe()
+ if err != nil {
+ t.Fatalf("StdinPipe failed: %v", err)
+ }
+ stdout, err := session.StdoutPipe()
+ if err != nil {
+ t.Fatalf("StdoutPipe failed: %v", err)
+ }
+
+ data := []byte(`0000`)
+ _, err = stdin.Write(data)
+ if err != nil {
+ t.Fatalf("Write failed: %v", err)
+ }
+ stdin.Close()
+
+ res, err := ioutil.ReadAll(stdout)
+ if err != nil {
+ t.Fatalf("Read failed: %v", err)
+ }
+
+ if !bytes.Equal(data, res) {
+ t.Fatalf("Read differed from write, wrote: %v, read: %v", data, res)
+ }
+}
+
+func simpleEchoHandler(ch Channel, in <-chan *Request, t *testing.T) {
+ defer ch.Close()
+ data, err := ioutil.ReadAll(ch)
+ if err != nil {
+ t.Errorf("handler read error: %v", err)
+ }
+ _, err = ch.Write(data)
+ if err != nil {
+ t.Errorf("handler write error: %v", err)
+ }
+}
+
+func TestSessionID(t *testing.T) {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ serverID := make(chan []byte, 1)
+ clientID := make(chan []byte, 1)
+
+ serverConf := &ServerConfig{
+ NoClientAuth: true,
+ }
+ serverConf.AddHostKey(testSigners["ecdsa"])
+ clientConf := &ClientConfig{
+ User: "user",
+ }
+
+ go func() {
+ conn, chans, reqs, err := NewServerConn(c1, serverConf)
+ if err != nil {
+ t.Fatalf("server handshake: %v", err)
+ }
+ serverID <- conn.SessionID()
+ go DiscardRequests(reqs)
+ for ch := range chans {
+ ch.Reject(Prohibited, "")
+ }
+ }()
+
+ go func() {
+ conn, chans, reqs, err := NewClientConn(c2, "", clientConf)
+ if err != nil {
+ t.Fatalf("client handshake: %v", err)
+ }
+ clientID <- conn.SessionID()
+ go DiscardRequests(reqs)
+ for ch := range chans {
+ ch.Reject(Prohibited, "")
+ }
+ }()
+
+ s := <-serverID
+ c := <-clientID
+ if bytes.Compare(s, c) != 0 {
+ t.Errorf("server session ID (%x) != client session ID (%x)", s, c)
+ } else if len(s) == 0 {
+ t.Errorf("client and server SessionID were empty.")
+ }
+}
+
+type noReadConn struct {
+ readSeen bool
+ net.Conn
+}
+
+func (c *noReadConn) Close() error {
+ return nil
+}
+
+func (c *noReadConn) Read(b []byte) (int, error) {
+ c.readSeen = true
+ return 0, errors.New("noReadConn error")
+}
+
+func TestInvalidServerConfiguration(t *testing.T) {
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ serveConn := noReadConn{Conn: c1}
+ serverConf := &ServerConfig{}
+
+ NewServerConn(&serveConn, serverConf)
+ if serveConn.readSeen {
+ t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing host key")
+ }
+
+ serverConf.AddHostKey(testSigners["ecdsa"])
+
+ NewServerConn(&serveConn, serverConf)
+ if serveConn.readSeen {
+ t.Fatalf("NewServerConn attempted to Read() from Conn while configuration is missing authentication method")
+ }
+}
+
+func TestHostKeyAlgorithms(t *testing.T) {
+ serverConf := &ServerConfig{
+ NoClientAuth: true,
+ }
+ serverConf.AddHostKey(testSigners["rsa"])
+ serverConf.AddHostKey(testSigners["ecdsa"])
+
+ connect := func(clientConf *ClientConfig, want string) {
+ var alg string
+ clientConf.HostKeyCallback = func(h string, a net.Addr, key PublicKey) error {
+ alg = key.Type()
+ return nil
+ }
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ go NewServerConn(c1, serverConf)
+ _, _, _, err = NewClientConn(c2, "", clientConf)
+ if err != nil {
+ t.Fatalf("NewClientConn: %v", err)
+ }
+ if alg != want {
+ t.Errorf("selected key algorithm %s, want %s", alg, want)
+ }
+ }
+
+ // By default, we get the preferred algorithm, which is ECDSA 256.
+
+ clientConf := &ClientConfig{}
+ connect(clientConf, KeyAlgoECDSA256)
+
+ // Client asks for RSA explicitly.
+ clientConf.HostKeyAlgorithms = []string{KeyAlgoRSA}
+ connect(clientConf, KeyAlgoRSA)
+
+ c1, c2, err := netPipe()
+ if err != nil {
+ t.Fatalf("netPipe: %v", err)
+ }
+ defer c1.Close()
+ defer c2.Close()
+
+ go NewServerConn(c1, serverConf)
+ clientConf.HostKeyAlgorithms = []string{"nonexistent-hostkey-algo"}
+ _, _, _, err = NewClientConn(c2, "", clientConf)
+ if err == nil {
+ t.Fatal("succeeded connecting with unknown hostkey algorithm")
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go
new file mode 100644
index 000000000..6151241ff
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/tcpip.go
@@ -0,0 +1,407 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "math/rand"
+ "net"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+// Listen requests the remote peer open a listening socket on
+// addr. Incoming connections will be available by calling Accept on
+// the returned net.Listener. The listener must be serviced, or the
+// SSH connection may hang.
+func (c *Client) Listen(n, addr string) (net.Listener, error) {
+ laddr, err := net.ResolveTCPAddr(n, addr)
+ if err != nil {
+ return nil, err
+ }
+ return c.ListenTCP(laddr)
+}
+
+// Automatic port allocation is broken with OpenSSH before 6.0. See
+// also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In
+// particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0,
+// rather than the actual port number. This means you can never open
+// two different listeners with auto allocated ports. We work around
+// this by trying explicit ports until we succeed.
+
+const openSSHPrefix = "OpenSSH_"
+
+var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano()))
+
+// isBrokenOpenSSHVersion returns true if the given version string
+// specifies a version of OpenSSH that is known to have a bug in port
+// forwarding.
+func isBrokenOpenSSHVersion(versionStr string) bool {
+ i := strings.Index(versionStr, openSSHPrefix)
+ if i < 0 {
+ return false
+ }
+ i += len(openSSHPrefix)
+ j := i
+ for ; j < len(versionStr); j++ {
+ if versionStr[j] < '0' || versionStr[j] > '9' {
+ break
+ }
+ }
+ version, _ := strconv.Atoi(versionStr[i:j])
+ return version < 6
+}
+
+// autoPortListenWorkaround simulates automatic port allocation by
+// trying random ports repeatedly.
+func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) {
+ var sshListener net.Listener
+ var err error
+ const tries = 10
+ for i := 0; i < tries; i++ {
+ addr := *laddr
+ addr.Port = 1024 + portRandomizer.Intn(60000)
+ sshListener, err = c.ListenTCP(&addr)
+ if err == nil {
+ laddr.Port = addr.Port
+ return sshListener, err
+ }
+ }
+ return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err)
+}
+
+// RFC 4254 7.1
+type channelForwardMsg struct {
+ addr string
+ rport uint32
+}
+
+// ListenTCP requests the remote peer open a listening socket
+// on laddr. Incoming connections will be available by calling
+// Accept on the returned net.Listener.
+func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
+ if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) {
+ return c.autoPortListenWorkaround(laddr)
+ }
+
+ m := channelForwardMsg{
+ laddr.IP.String(),
+ uint32(laddr.Port),
+ }
+ // send message
+ ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m))
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ return nil, errors.New("ssh: tcpip-forward request denied by peer")
+ }
+
+ // If the original port was 0, then the remote side will
+ // supply a real port number in the response.
+ if laddr.Port == 0 {
+ var p struct {
+ Port uint32
+ }
+ if err := Unmarshal(resp, &p); err != nil {
+ return nil, err
+ }
+ laddr.Port = int(p.Port)
+ }
+
+ // Register this forward, using the port number we obtained.
+ ch := c.forwards.add(*laddr)
+
+ return &tcpListener{laddr, c, ch}, nil
+}
+
+// forwardList stores a mapping between remote
+// forward requests and the tcpListeners.
+type forwardList struct {
+ sync.Mutex
+ entries []forwardEntry
+}
+
+// forwardEntry represents an established mapping of a laddr on a
+// remote ssh server to a channel connected to a tcpListener.
+type forwardEntry struct {
+ laddr net.TCPAddr
+ c chan forward
+}
+
+// forward represents an incoming forwarded tcpip connection. The
+// arguments to add/remove/lookup should be address as specified in
+// the original forward-request.
+type forward struct {
+ newCh NewChannel // the ssh client channel underlying this forward
+ raddr *net.TCPAddr // the raddr of the incoming connection
+}
+
+func (l *forwardList) add(addr net.TCPAddr) chan forward {
+ l.Lock()
+ defer l.Unlock()
+ f := forwardEntry{
+ addr,
+ make(chan forward, 1),
+ }
+ l.entries = append(l.entries, f)
+ return f.c
+}
+
+// See RFC 4254, section 7.2
+type forwardedTCPPayload struct {
+ Addr string
+ Port uint32
+ OriginAddr string
+ OriginPort uint32
+}
+
+// parseTCPAddr parses the originating address from the remote into a *net.TCPAddr.
+func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
+ if port == 0 || port > 65535 {
+ return nil, fmt.Errorf("ssh: port number out of range: %d", port)
+ }
+ ip := net.ParseIP(string(addr))
+ if ip == nil {
+ return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr)
+ }
+ return &net.TCPAddr{IP: ip, Port: int(port)}, nil
+}
+
+func (l *forwardList) handleChannels(in <-chan NewChannel) {
+ for ch := range in {
+ var payload forwardedTCPPayload
+ if err := Unmarshal(ch.ExtraData(), &payload); err != nil {
+ ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
+ continue
+ }
+
+ // RFC 4254 section 7.2 specifies that incoming
+ // addresses should list the address, in string
+ // format. It is implied that this should be an IP
+ // address, as it would be impossible to connect to it
+ // otherwise.
+ laddr, err := parseTCPAddr(payload.Addr, payload.Port)
+ if err != nil {
+ ch.Reject(ConnectionFailed, err.Error())
+ continue
+ }
+ raddr, err := parseTCPAddr(payload.OriginAddr, payload.OriginPort)
+ if err != nil {
+ ch.Reject(ConnectionFailed, err.Error())
+ continue
+ }
+
+ if ok := l.forward(*laddr, *raddr, ch); !ok {
+ // Section 7.2, implementations MUST reject spurious incoming
+ // connections.
+ ch.Reject(Prohibited, "no forward for address")
+ continue
+ }
+ }
+}
+
+// remove removes the forward entry, and the channel feeding its
+// listener.
+func (l *forwardList) remove(addr net.TCPAddr) {
+ l.Lock()
+ defer l.Unlock()
+ for i, f := range l.entries {
+ if addr.IP.Equal(f.laddr.IP) && addr.Port == f.laddr.Port {
+ l.entries = append(l.entries[:i], l.entries[i+1:]...)
+ close(f.c)
+ return
+ }
+ }
+}
+
+// closeAll closes and clears all forwards.
+func (l *forwardList) closeAll() {
+ l.Lock()
+ defer l.Unlock()
+ for _, f := range l.entries {
+ close(f.c)
+ }
+ l.entries = nil
+}
+
+func (l *forwardList) forward(laddr, raddr net.TCPAddr, ch NewChannel) bool {
+ l.Lock()
+ defer l.Unlock()
+ for _, f := range l.entries {
+ if laddr.IP.Equal(f.laddr.IP) && laddr.Port == f.laddr.Port {
+ f.c <- forward{ch, &raddr}
+ return true
+ }
+ }
+ return false
+}
+
+type tcpListener struct {
+ laddr *net.TCPAddr
+
+ conn *Client
+ in <-chan forward
+}
+
+// Accept waits for and returns the next connection to the listener.
+func (l *tcpListener) Accept() (net.Conn, error) {
+ s, ok := <-l.in
+ if !ok {
+ return nil, io.EOF
+ }
+ ch, incoming, err := s.newCh.Accept()
+ if err != nil {
+ return nil, err
+ }
+ go DiscardRequests(incoming)
+
+ return &tcpChanConn{
+ Channel: ch,
+ laddr: l.laddr,
+ raddr: s.raddr,
+ }, nil
+}
+
+// Close closes the listener.
+func (l *tcpListener) Close() error {
+ m := channelForwardMsg{
+ l.laddr.IP.String(),
+ uint32(l.laddr.Port),
+ }
+
+ // this also closes the listener.
+ l.conn.forwards.remove(*l.laddr)
+ ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m))
+ if err == nil && !ok {
+ err = errors.New("ssh: cancel-tcpip-forward failed")
+ }
+ return err
+}
+
+// Addr returns the listener's network address.
+func (l *tcpListener) Addr() net.Addr {
+ return l.laddr
+}
+
+// Dial initiates a connection to the addr from the remote host.
+// The resulting connection has a zero LocalAddr() and RemoteAddr().
+func (c *Client) Dial(n, addr string) (net.Conn, error) {
+ // Parse the address into host and numeric port.
+ host, portString, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+ port, err := strconv.ParseUint(portString, 10, 16)
+ if err != nil {
+ return nil, err
+ }
+ // Use a zero address for local and remote address.
+ zeroAddr := &net.TCPAddr{
+ IP: net.IPv4zero,
+ Port: 0,
+ }
+ ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port))
+ if err != nil {
+ return nil, err
+ }
+ return &tcpChanConn{
+ Channel: ch,
+ laddr: zeroAddr,
+ raddr: zeroAddr,
+ }, nil
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) {
+ if laddr == nil {
+ laddr = &net.TCPAddr{
+ IP: net.IPv4zero,
+ Port: 0,
+ }
+ }
+ ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port)
+ if err != nil {
+ return nil, err
+ }
+ return &tcpChanConn{
+ Channel: ch,
+ laddr: laddr,
+ raddr: raddr,
+ }, nil
+}
+
+// RFC 4254 7.2
+type channelOpenDirectMsg struct {
+ raddr string
+ rport uint32
+ laddr string
+ lport uint32
+}
+
+func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) {
+ msg := channelOpenDirectMsg{
+ raddr: raddr,
+ rport: uint32(rport),
+ laddr: laddr,
+ lport: uint32(lport),
+ }
+ ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg))
+ if err != nil {
+ return nil, err
+ }
+ go DiscardRequests(in)
+ return ch, err
+}
+
+type tcpChan struct {
+ Channel // the backing channel
+}
+
+// tcpChanConn fulfills the net.Conn interface without
+// the tcpChan having to hold laddr or raddr directly.
+type tcpChanConn struct {
+ Channel
+ laddr, raddr net.Addr
+}
+
+// LocalAddr returns the local network address.
+func (t *tcpChanConn) LocalAddr() net.Addr {
+ return t.laddr
+}
+
+// RemoteAddr returns the remote network address.
+func (t *tcpChanConn) RemoteAddr() net.Addr {
+ return t.raddr
+}
+
+// SetDeadline sets the read and write deadlines associated
+// with the connection.
+func (t *tcpChanConn) SetDeadline(deadline time.Time) error {
+ if err := t.SetReadDeadline(deadline); err != nil {
+ return err
+ }
+ return t.SetWriteDeadline(deadline)
+}
+
+// SetReadDeadline sets the read deadline.
+// A zero value for t means Read will not time out.
+// After the deadline, the error from Read will implement net.Error
+// with Timeout() == true.
+func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error {
+ return errors.New("ssh: tcpChan: deadline not supported")
+}
+
+// SetWriteDeadline exists to satisfy the net.Conn interface
+// but is not implemented by this type. It always returns an error.
+func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error {
+ return errors.New("ssh: tcpChan: deadline not supported")
+}
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip_test.go b/vendor/golang.org/x/crypto/ssh/tcpip_test.go
new file mode 100644
index 000000000..f1265cb49
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/tcpip_test.go
@@ -0,0 +1,20 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "testing"
+)
+
+func TestAutoPortListenBroken(t *testing.T) {
+ broken := "SSH-2.0-OpenSSH_5.9hh11"
+ works := "SSH-2.0-OpenSSH_6.1"
+ if !isBrokenOpenSSHVersion(broken) {
+ t.Errorf("version %q not marked as broken", broken)
+ }
+ if isBrokenOpenSSHVersion(works) {
+ t.Errorf("version %q marked as broken", works)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
new file mode 100644
index 000000000..741eeb13f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal.go
@@ -0,0 +1,892 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package terminal
+
+import (
+ "bytes"
+ "io"
+ "sync"
+ "unicode/utf8"
+)
+
+// EscapeCodes contains escape sequences that can be written to the terminal in
+// order to achieve different styles of text.
+type EscapeCodes struct {
+ // Foreground colors
+ Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
+
+ // Reset all attributes
+ Reset []byte
+}
+
+var vt100EscapeCodes = EscapeCodes{
+ Black: []byte{keyEscape, '[', '3', '0', 'm'},
+ Red: []byte{keyEscape, '[', '3', '1', 'm'},
+ Green: []byte{keyEscape, '[', '3', '2', 'm'},
+ Yellow: []byte{keyEscape, '[', '3', '3', 'm'},
+ Blue: []byte{keyEscape, '[', '3', '4', 'm'},
+ Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
+ Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
+ White: []byte{keyEscape, '[', '3', '7', 'm'},
+
+ Reset: []byte{keyEscape, '[', '0', 'm'},
+}
+
+// Terminal contains the state for running a VT100 terminal that is capable of
+// reading lines of input.
+type Terminal struct {
+ // AutoCompleteCallback, if non-null, is called for each keypress with
+ // the full input line and the current position of the cursor (in
+ // bytes, as an index into |line|). If it returns ok=false, the key
+ // press is processed normally. Otherwise it returns a replacement line
+ // and the new cursor position.
+ AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
+
+ // Escape contains a pointer to the escape codes for this terminal.
+ // It's always a valid pointer, although the escape codes themselves
+ // may be empty if the terminal doesn't support them.
+ Escape *EscapeCodes
+
+ // lock protects the terminal and the state in this object from
+ // concurrent processing of a key press and a Write() call.
+ lock sync.Mutex
+
+ c io.ReadWriter
+ prompt []rune
+
+ // line is the current line being entered.
+ line []rune
+ // pos is the logical position of the cursor in line
+ pos int
+ // echo is true if local echo is enabled
+ echo bool
+ // pasteActive is true iff there is a bracketed paste operation in
+ // progress.
+ pasteActive bool
+
+ // cursorX contains the current X value of the cursor where the left
+ // edge is 0. cursorY contains the row number where the first row of
+ // the current line is 0.
+ cursorX, cursorY int
+ // maxLine is the greatest value of cursorY so far.
+ maxLine int
+
+ termWidth, termHeight int
+
+ // outBuf contains the terminal data to be sent.
+ outBuf []byte
+ // remainder contains the remainder of any partial key sequences after
+ // a read. It aliases into inBuf.
+ remainder []byte
+ inBuf [256]byte
+
+ // history contains previously entered commands so that they can be
+ // accessed with the up and down keys.
+ history stRingBuffer
+ // historyIndex stores the currently accessed history entry, where zero
+ // means the immediately previous entry.
+ historyIndex int
+ // When navigating up and down the history it's possible to return to
+ // the incomplete, initial line. That value is stored in
+ // historyPending.
+ historyPending string
+}
+
+// NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
+// a local terminal, that terminal must first have been put into raw mode.
+// prompt is a string that is written at the start of each input line (i.e.
+// "> ").
+func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
+ return &Terminal{
+ Escape: &vt100EscapeCodes,
+ c: c,
+ prompt: []rune(prompt),
+ termWidth: 80,
+ termHeight: 24,
+ echo: true,
+ historyIndex: -1,
+ }
+}
+
+const (
+ keyCtrlD = 4
+ keyCtrlU = 21
+ keyEnter = '\r'
+ keyEscape = 27
+ keyBackspace = 127
+ keyUnknown = 0xd800 /* UTF-16 surrogate area */ + iota
+ keyUp
+ keyDown
+ keyLeft
+ keyRight
+ keyAltLeft
+ keyAltRight
+ keyHome
+ keyEnd
+ keyDeleteWord
+ keyDeleteLine
+ keyClearScreen
+ keyPasteStart
+ keyPasteEnd
+)
+
+var pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
+var pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
+
+// bytesToKey tries to parse a key sequence from b. If successful, it returns
+// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
+func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
+ if len(b) == 0 {
+ return utf8.RuneError, nil
+ }
+
+ if !pasteActive {
+ switch b[0] {
+ case 1: // ^A
+ return keyHome, b[1:]
+ case 5: // ^E
+ return keyEnd, b[1:]
+ case 8: // ^H
+ return keyBackspace, b[1:]
+ case 11: // ^K
+ return keyDeleteLine, b[1:]
+ case 12: // ^L
+ return keyClearScreen, b[1:]
+ case 23: // ^W
+ return keyDeleteWord, b[1:]
+ }
+ }
+
+ if b[0] != keyEscape {
+ if !utf8.FullRune(b) {
+ return utf8.RuneError, b
+ }
+ r, l := utf8.DecodeRune(b)
+ return r, b[l:]
+ }
+
+ if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
+ switch b[2] {
+ case 'A':
+ return keyUp, b[3:]
+ case 'B':
+ return keyDown, b[3:]
+ case 'C':
+ return keyRight, b[3:]
+ case 'D':
+ return keyLeft, b[3:]
+ case 'H':
+ return keyHome, b[3:]
+ case 'F':
+ return keyEnd, b[3:]
+ }
+ }
+
+ if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
+ switch b[5] {
+ case 'C':
+ return keyAltRight, b[6:]
+ case 'D':
+ return keyAltLeft, b[6:]
+ }
+ }
+
+ if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
+ return keyPasteStart, b[6:]
+ }
+
+ if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
+ return keyPasteEnd, b[6:]
+ }
+
+ // If we get here then we have a key that we don't recognise, or a
+ // partial sequence. It's not clear how one should find the end of a
+ // sequence without knowing them all, but it seems that [a-zA-Z~] only
+ // appears at the end of a sequence.
+ for i, c := range b[0:] {
+ if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
+ return keyUnknown, b[i+1:]
+ }
+ }
+
+ return utf8.RuneError, b
+}
+
+// queue appends data to the end of t.outBuf
+func (t *Terminal) queue(data []rune) {
+ t.outBuf = append(t.outBuf, []byte(string(data))...)
+}
+
+var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
+var space = []rune{' '}
+
+func isPrintable(key rune) bool {
+ isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
+ return key >= 32 && !isInSurrogateArea
+}
+
+// moveCursorToPos appends data to t.outBuf which will move the cursor to the
+// given, logical position in the text.
+func (t *Terminal) moveCursorToPos(pos int) {
+ if !t.echo {
+ return
+ }
+
+ x := visualLength(t.prompt) + pos
+ y := x / t.termWidth
+ x = x % t.termWidth
+
+ up := 0
+ if y < t.cursorY {
+ up = t.cursorY - y
+ }
+
+ down := 0
+ if y > t.cursorY {
+ down = y - t.cursorY
+ }
+
+ left := 0
+ if x < t.cursorX {
+ left = t.cursorX - x
+ }
+
+ right := 0
+ if x > t.cursorX {
+ right = x - t.cursorX
+ }
+
+ t.cursorX = x
+ t.cursorY = y
+ t.move(up, down, left, right)
+}
+
+func (t *Terminal) move(up, down, left, right int) {
+ movement := make([]rune, 3*(up+down+left+right))
+ m := movement
+ for i := 0; i < up; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'A'
+ m = m[3:]
+ }
+ for i := 0; i < down; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'B'
+ m = m[3:]
+ }
+ for i := 0; i < left; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'D'
+ m = m[3:]
+ }
+ for i := 0; i < right; i++ {
+ m[0] = keyEscape
+ m[1] = '['
+ m[2] = 'C'
+ m = m[3:]
+ }
+
+ t.queue(movement)
+}
+
+func (t *Terminal) clearLineToRight() {
+ op := []rune{keyEscape, '[', 'K'}
+ t.queue(op)
+}
+
+const maxLineLength = 4096
+
+func (t *Terminal) setLine(newLine []rune, newPos int) {
+ if t.echo {
+ t.moveCursorToPos(0)
+ t.writeLine(newLine)
+ for i := len(newLine); i < len(t.line); i++ {
+ t.writeLine(space)
+ }
+ t.moveCursorToPos(newPos)
+ }
+ t.line = newLine
+ t.pos = newPos
+}
+
+func (t *Terminal) advanceCursor(places int) {
+ t.cursorX += places
+ t.cursorY += t.cursorX / t.termWidth
+ if t.cursorY > t.maxLine {
+ t.maxLine = t.cursorY
+ }
+ t.cursorX = t.cursorX % t.termWidth
+
+ if places > 0 && t.cursorX == 0 {
+ // Normally terminals will advance the current position
+ // when writing a character. But that doesn't happen
+ // for the last character in a line. However, when
+ // writing a character (except a new line) that causes
+ // a line wrap, the position will be advanced two
+ // places.
+ //
+ // So, if we are stopping at the end of a line, we
+ // need to write a newline so that our cursor can be
+ // advanced to the next line.
+ t.outBuf = append(t.outBuf, '\n')
+ }
+}
+
+func (t *Terminal) eraseNPreviousChars(n int) {
+ if n == 0 {
+ return
+ }
+
+ if t.pos < n {
+ n = t.pos
+ }
+ t.pos -= n
+ t.moveCursorToPos(t.pos)
+
+ copy(t.line[t.pos:], t.line[n+t.pos:])
+ t.line = t.line[:len(t.line)-n]
+ if t.echo {
+ t.writeLine(t.line[t.pos:])
+ for i := 0; i < n; i++ {
+ t.queue(space)
+ }
+ t.advanceCursor(n)
+ t.moveCursorToPos(t.pos)
+ }
+}
+
+// countToLeftWord returns then number of characters from the cursor to the
+// start of the previous word.
+func (t *Terminal) countToLeftWord() int {
+ if t.pos == 0 {
+ return 0
+ }
+
+ pos := t.pos - 1
+ for pos > 0 {
+ if t.line[pos] != ' ' {
+ break
+ }
+ pos--
+ }
+ for pos > 0 {
+ if t.line[pos] == ' ' {
+ pos++
+ break
+ }
+ pos--
+ }
+
+ return t.pos - pos
+}
+
+// countToRightWord returns then number of characters from the cursor to the
+// start of the next word.
+func (t *Terminal) countToRightWord() int {
+ pos := t.pos
+ for pos < len(t.line) {
+ if t.line[pos] == ' ' {
+ break
+ }
+ pos++
+ }
+ for pos < len(t.line) {
+ if t.line[pos] != ' ' {
+ break
+ }
+ pos++
+ }
+ return pos - t.pos
+}
+
+// visualLength returns the number of visible glyphs in s.
+func visualLength(runes []rune) int {
+ inEscapeSeq := false
+ length := 0
+
+ for _, r := range runes {
+ switch {
+ case inEscapeSeq:
+ if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
+ inEscapeSeq = false
+ }
+ case r == '\x1b':
+ inEscapeSeq = true
+ default:
+ length++
+ }
+ }
+
+ return length
+}
+
+// handleKey processes the given key and, optionally, returns a line of text
+// that the user has entered.
+func (t *Terminal) handleKey(key rune) (line string, ok bool) {
+ if t.pasteActive && key != keyEnter {
+ t.addKeyToLine(key)
+ return
+ }
+
+ switch key {
+ case keyBackspace:
+ if t.pos == 0 {
+ return
+ }
+ t.eraseNPreviousChars(1)
+ case keyAltLeft:
+ // move left by a word.
+ t.pos -= t.countToLeftWord()
+ t.moveCursorToPos(t.pos)
+ case keyAltRight:
+ // move right by a word.
+ t.pos += t.countToRightWord()
+ t.moveCursorToPos(t.pos)
+ case keyLeft:
+ if t.pos == 0 {
+ return
+ }
+ t.pos--
+ t.moveCursorToPos(t.pos)
+ case keyRight:
+ if t.pos == len(t.line) {
+ return
+ }
+ t.pos++
+ t.moveCursorToPos(t.pos)
+ case keyHome:
+ if t.pos == 0 {
+ return
+ }
+ t.pos = 0
+ t.moveCursorToPos(t.pos)
+ case keyEnd:
+ if t.pos == len(t.line) {
+ return
+ }
+ t.pos = len(t.line)
+ t.moveCursorToPos(t.pos)
+ case keyUp:
+ entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
+ if !ok {
+ return "", false
+ }
+ if t.historyIndex == -1 {
+ t.historyPending = string(t.line)
+ }
+ t.historyIndex++
+ runes := []rune(entry)
+ t.setLine(runes, len(runes))
+ case keyDown:
+ switch t.historyIndex {
+ case -1:
+ return
+ case 0:
+ runes := []rune(t.historyPending)
+ t.setLine(runes, len(runes))
+ t.historyIndex--
+ default:
+ entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
+ if ok {
+ t.historyIndex--
+ runes := []rune(entry)
+ t.setLine(runes, len(runes))
+ }
+ }
+ case keyEnter:
+ t.moveCursorToPos(len(t.line))
+ t.queue([]rune("\r\n"))
+ line = string(t.line)
+ ok = true
+ t.line = t.line[:0]
+ t.pos = 0
+ t.cursorX = 0
+ t.cursorY = 0
+ t.maxLine = 0
+ case keyDeleteWord:
+ // Delete zero or more spaces and then one or more characters.
+ t.eraseNPreviousChars(t.countToLeftWord())
+ case keyDeleteLine:
+ // Delete everything from the current cursor position to the
+ // end of line.
+ for i := t.pos; i < len(t.line); i++ {
+ t.queue(space)
+ t.advanceCursor(1)
+ }
+ t.line = t.line[:t.pos]
+ t.moveCursorToPos(t.pos)
+ case keyCtrlD:
+ // Erase the character under the current position.
+ // The EOF case when the line is empty is handled in
+ // readLine().
+ if t.pos < len(t.line) {
+ t.pos++
+ t.eraseNPreviousChars(1)
+ }
+ case keyCtrlU:
+ t.eraseNPreviousChars(t.pos)
+ case keyClearScreen:
+ // Erases the screen and moves the cursor to the home position.
+ t.queue([]rune("\x1b[2J\x1b[H"))
+ t.queue(t.prompt)
+ t.cursorX, t.cursorY = 0, 0
+ t.advanceCursor(visualLength(t.prompt))
+ t.setLine(t.line, t.pos)
+ default:
+ if t.AutoCompleteCallback != nil {
+ prefix := string(t.line[:t.pos])
+ suffix := string(t.line[t.pos:])
+
+ t.lock.Unlock()
+ newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
+ t.lock.Lock()
+
+ if completeOk {
+ t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
+ return
+ }
+ }
+ if !isPrintable(key) {
+ return
+ }
+ if len(t.line) == maxLineLength {
+ return
+ }
+ t.addKeyToLine(key)
+ }
+ return
+}
+
+// addKeyToLine inserts the given key at the current position in the current
+// line.
+func (t *Terminal) addKeyToLine(key rune) {
+ if len(t.line) == cap(t.line) {
+ newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
+ copy(newLine, t.line)
+ t.line = newLine
+ }
+ t.line = t.line[:len(t.line)+1]
+ copy(t.line[t.pos+1:], t.line[t.pos:])
+ t.line[t.pos] = key
+ if t.echo {
+ t.writeLine(t.line[t.pos:])
+ }
+ t.pos++
+ t.moveCursorToPos(t.pos)
+}
+
+func (t *Terminal) writeLine(line []rune) {
+ for len(line) != 0 {
+ remainingOnLine := t.termWidth - t.cursorX
+ todo := len(line)
+ if todo > remainingOnLine {
+ todo = remainingOnLine
+ }
+ t.queue(line[:todo])
+ t.advanceCursor(visualLength(line[:todo]))
+ line = line[todo:]
+ }
+}
+
+func (t *Terminal) Write(buf []byte) (n int, err error) {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ if t.cursorX == 0 && t.cursorY == 0 {
+ // This is the easy case: there's nothing on the screen that we
+ // have to move out of the way.
+ return t.c.Write(buf)
+ }
+
+ // We have a prompt and possibly user input on the screen. We
+ // have to clear it first.
+ t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
+ t.cursorX = 0
+ t.clearLineToRight()
+
+ for t.cursorY > 0 {
+ t.move(1 /* up */, 0, 0, 0)
+ t.cursorY--
+ t.clearLineToRight()
+ }
+
+ if _, err = t.c.Write(t.outBuf); err != nil {
+ return
+ }
+ t.outBuf = t.outBuf[:0]
+
+ if n, err = t.c.Write(buf); err != nil {
+ return
+ }
+
+ t.writeLine(t.prompt)
+ if t.echo {
+ t.writeLine(t.line)
+ }
+
+ t.moveCursorToPos(t.pos)
+
+ if _, err = t.c.Write(t.outBuf); err != nil {
+ return
+ }
+ t.outBuf = t.outBuf[:0]
+ return
+}
+
+// ReadPassword temporarily changes the prompt and reads a password, without
+// echo, from the terminal.
+func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ oldPrompt := t.prompt
+ t.prompt = []rune(prompt)
+ t.echo = false
+
+ line, err = t.readLine()
+
+ t.prompt = oldPrompt
+ t.echo = true
+
+ return
+}
+
+// ReadLine returns a line of input from the terminal.
+func (t *Terminal) ReadLine() (line string, err error) {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ return t.readLine()
+}
+
+func (t *Terminal) readLine() (line string, err error) {
+ // t.lock must be held at this point
+
+ if t.cursorX == 0 && t.cursorY == 0 {
+ t.writeLine(t.prompt)
+ t.c.Write(t.outBuf)
+ t.outBuf = t.outBuf[:0]
+ }
+
+ lineIsPasted := t.pasteActive
+
+ for {
+ rest := t.remainder
+ lineOk := false
+ for !lineOk {
+ var key rune
+ key, rest = bytesToKey(rest, t.pasteActive)
+ if key == utf8.RuneError {
+ break
+ }
+ if !t.pasteActive {
+ if key == keyCtrlD {
+ if len(t.line) == 0 {
+ return "", io.EOF
+ }
+ }
+ if key == keyPasteStart {
+ t.pasteActive = true
+ if len(t.line) == 0 {
+ lineIsPasted = true
+ }
+ continue
+ }
+ } else if key == keyPasteEnd {
+ t.pasteActive = false
+ continue
+ }
+ if !t.pasteActive {
+ lineIsPasted = false
+ }
+ line, lineOk = t.handleKey(key)
+ }
+ if len(rest) > 0 {
+ n := copy(t.inBuf[:], rest)
+ t.remainder = t.inBuf[:n]
+ } else {
+ t.remainder = nil
+ }
+ t.c.Write(t.outBuf)
+ t.outBuf = t.outBuf[:0]
+ if lineOk {
+ if t.echo {
+ t.historyIndex = -1
+ t.history.Add(line)
+ }
+ if lineIsPasted {
+ err = ErrPasteIndicator
+ }
+ return
+ }
+
+ // t.remainder is a slice at the beginning of t.inBuf
+ // containing a partial key sequence
+ readBuf := t.inBuf[len(t.remainder):]
+ var n int
+
+ t.lock.Unlock()
+ n, err = t.c.Read(readBuf)
+ t.lock.Lock()
+
+ if err != nil {
+ return
+ }
+
+ t.remainder = t.inBuf[:n+len(t.remainder)]
+ }
+
+ panic("unreachable") // for Go 1.0.
+}
+
+// SetPrompt sets the prompt to be used when reading subsequent lines.
+func (t *Terminal) SetPrompt(prompt string) {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ t.prompt = []rune(prompt)
+}
+
+func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
+ // Move cursor to column zero at the start of the line.
+ t.move(t.cursorY, 0, t.cursorX, 0)
+ t.cursorX, t.cursorY = 0, 0
+ t.clearLineToRight()
+ for t.cursorY < numPrevLines {
+ // Move down a line
+ t.move(0, 1, 0, 0)
+ t.cursorY++
+ t.clearLineToRight()
+ }
+ // Move back to beginning.
+ t.move(t.cursorY, 0, 0, 0)
+ t.cursorX, t.cursorY = 0, 0
+
+ t.queue(t.prompt)
+ t.advanceCursor(visualLength(t.prompt))
+ t.writeLine(t.line)
+ t.moveCursorToPos(t.pos)
+}
+
+func (t *Terminal) SetSize(width, height int) error {
+ t.lock.Lock()
+ defer t.lock.Unlock()
+
+ if width == 0 {
+ width = 1
+ }
+
+ oldWidth := t.termWidth
+ t.termWidth, t.termHeight = width, height
+
+ switch {
+ case width == oldWidth:
+ // If the width didn't change then nothing else needs to be
+ // done.
+ return nil
+ case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
+ // If there is nothing on current line and no prompt printed,
+ // just do nothing
+ return nil
+ case width < oldWidth:
+ // Some terminals (e.g. xterm) will truncate lines that were
+ // too long when shinking. Others, (e.g. gnome-terminal) will
+ // attempt to wrap them. For the former, repainting t.maxLine
+ // works great, but that behaviour goes badly wrong in the case
+ // of the latter because they have doubled every full line.
+
+ // We assume that we are working on a terminal that wraps lines
+ // and adjust the cursor position based on every previous line
+ // wrapping and turning into two. This causes the prompt on
+ // xterms to move upwards, which isn't great, but it avoids a
+ // huge mess with gnome-terminal.
+ if t.cursorX >= t.termWidth {
+ t.cursorX = t.termWidth - 1
+ }
+ t.cursorY *= 2
+ t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
+ case width > oldWidth:
+ // If the terminal expands then our position calculations will
+ // be wrong in the future because we think the cursor is
+ // |t.pos| chars into the string, but there will be a gap at
+ // the end of any wrapped line.
+ //
+ // But the position will actually be correct until we move, so
+ // we can move back to the beginning and repaint everything.
+ t.clearAndRepaintLinePlusNPrevious(t.maxLine)
+ }
+
+ _, err := t.c.Write(t.outBuf)
+ t.outBuf = t.outBuf[:0]
+ return err
+}
+
+type pasteIndicatorError struct{}
+
+func (pasteIndicatorError) Error() string {
+ return "terminal: ErrPasteIndicator not correctly handled"
+}
+
+// ErrPasteIndicator may be returned from ReadLine as the error, in addition
+// to valid line data. It indicates that bracketed paste mode is enabled and
+// that the returned line consists only of pasted data. Programs may wish to
+// interpret pasted data more literally than typed data.
+var ErrPasteIndicator = pasteIndicatorError{}
+
+// SetBracketedPasteMode requests that the terminal bracket paste operations
+// with markers. Not all terminals support this but, if it is supported, then
+// enabling this mode will stop any autocomplete callback from running due to
+// pastes. Additionally, any lines that are completely pasted will be returned
+// from ReadLine with the error set to ErrPasteIndicator.
+func (t *Terminal) SetBracketedPasteMode(on bool) {
+ if on {
+ io.WriteString(t.c, "\x1b[?2004h")
+ } else {
+ io.WriteString(t.c, "\x1b[?2004l")
+ }
+}
+
+// stRingBuffer is a ring buffer of strings.
+type stRingBuffer struct {
+ // entries contains max elements.
+ entries []string
+ max int
+ // head contains the index of the element most recently added to the ring.
+ head int
+ // size contains the number of elements in the ring.
+ size int
+}
+
+func (s *stRingBuffer) Add(a string) {
+ if s.entries == nil {
+ const defaultNumEntries = 100
+ s.entries = make([]string, defaultNumEntries)
+ s.max = defaultNumEntries
+ }
+
+ s.head = (s.head + 1) % s.max
+ s.entries[s.head] = a
+ if s.size < s.max {
+ s.size++
+ }
+}
+
+// NthPreviousEntry returns the value passed to the nth previous call to Add.
+// If n is zero then the immediately prior value is returned, if one, then the
+// next most recent, and so on. If such an element doesn't exist then ok is
+// false.
+func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
+ if n >= s.size {
+ return "", false
+ }
+ index := s.head - n
+ if index < 0 {
+ index += s.max
+ }
+ return s.entries[index], true
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
new file mode 100644
index 000000000..6bdefb4ec
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/terminal_test.go
@@ -0,0 +1,291 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package terminal
+
+import (
+ "io"
+ "os"
+ "testing"
+)
+
+type MockTerminal struct {
+ toSend []byte
+ bytesPerRead int
+ received []byte
+}
+
+func (c *MockTerminal) Read(data []byte) (n int, err error) {
+ n = len(data)
+ if n == 0 {
+ return
+ }
+ if n > len(c.toSend) {
+ n = len(c.toSend)
+ }
+ if n == 0 {
+ return 0, io.EOF
+ }
+ if c.bytesPerRead > 0 && n > c.bytesPerRead {
+ n = c.bytesPerRead
+ }
+ copy(data, c.toSend[:n])
+ c.toSend = c.toSend[n:]
+ return
+}
+
+func (c *MockTerminal) Write(data []byte) (n int, err error) {
+ c.received = append(c.received, data...)
+ return len(data), nil
+}
+
+func TestClose(t *testing.T) {
+ c := &MockTerminal{}
+ ss := NewTerminal(c, "> ")
+ line, err := ss.ReadLine()
+ if line != "" {
+ t.Errorf("Expected empty line but got: %s", line)
+ }
+ if err != io.EOF {
+ t.Errorf("Error should have been EOF but got: %s", err)
+ }
+}
+
+var keyPressTests = []struct {
+ in string
+ line string
+ err error
+ throwAwayLines int
+}{
+ {
+ err: io.EOF,
+ },
+ {
+ in: "\r",
+ line: "",
+ },
+ {
+ in: "foo\r",
+ line: "foo",
+ },
+ {
+ in: "a\x1b[Cb\r", // right
+ line: "ab",
+ },
+ {
+ in: "a\x1b[Db\r", // left
+ line: "ba",
+ },
+ {
+ in: "a\177b\r", // backspace
+ line: "b",
+ },
+ {
+ in: "\x1b[A\r", // up
+ },
+ {
+ in: "\x1b[B\r", // down
+ },
+ {
+ in: "line\x1b[A\x1b[B\r", // up then down
+ line: "line",
+ },
+ {
+ in: "line1\rline2\x1b[A\r", // recall previous line.
+ line: "line1",
+ throwAwayLines: 1,
+ },
+ {
+ // recall two previous lines and append.
+ in: "line1\rline2\rline3\x1b[A\x1b[Axxx\r",
+ line: "line1xxx",
+ throwAwayLines: 2,
+ },
+ {
+ // Ctrl-A to move to beginning of line followed by ^K to kill
+ // line.
+ in: "a b \001\013\r",
+ line: "",
+ },
+ {
+ // Ctrl-A to move to beginning of line, Ctrl-E to move to end,
+ // finally ^K to kill nothing.
+ in: "a b \001\005\013\r",
+ line: "a b ",
+ },
+ {
+ in: "\027\r",
+ line: "",
+ },
+ {
+ in: "a\027\r",
+ line: "",
+ },
+ {
+ in: "a \027\r",
+ line: "",
+ },
+ {
+ in: "a b\027\r",
+ line: "a ",
+ },
+ {
+ in: "a b \027\r",
+ line: "a ",
+ },
+ {
+ in: "one two thr\x1b[D\027\r",
+ line: "one two r",
+ },
+ {
+ in: "\013\r",
+ line: "",
+ },
+ {
+ in: "a\013\r",
+ line: "a",
+ },
+ {
+ in: "ab\x1b[D\013\r",
+ line: "a",
+ },
+ {
+ in: "Ξεσκεπάζω\r",
+ line: "Ξεσκεπάζω",
+ },
+ {
+ in: "£\r\x1b[A\177\r", // non-ASCII char, enter, up, backspace.
+ line: "",
+ throwAwayLines: 1,
+ },
+ {
+ in: "£\r££\x1b[A\x1b[B\177\r", // non-ASCII char, enter, 2x non-ASCII, up, down, backspace, enter.
+ line: "£",
+ throwAwayLines: 1,
+ },
+ {
+ // Ctrl-D at the end of the line should be ignored.
+ in: "a\004\r",
+ line: "a",
+ },
+ {
+ // a, b, left, Ctrl-D should erase the b.
+ in: "ab\x1b[D\004\r",
+ line: "a",
+ },
+ {
+ // a, b, c, d, left, left, ^U should erase to the beginning of
+ // the line.
+ in: "abcd\x1b[D\x1b[D\025\r",
+ line: "cd",
+ },
+ {
+ // Bracketed paste mode: control sequences should be returned
+ // verbatim in paste mode.
+ in: "abc\x1b[200~de\177f\x1b[201~\177\r",
+ line: "abcde\177",
+ },
+ {
+ // Enter in bracketed paste mode should still work.
+ in: "abc\x1b[200~d\refg\x1b[201~h\r",
+ line: "efgh",
+ throwAwayLines: 1,
+ },
+ {
+ // Lines consisting entirely of pasted data should be indicated as such.
+ in: "\x1b[200~a\r",
+ line: "a",
+ err: ErrPasteIndicator,
+ },
+}
+
+func TestKeyPresses(t *testing.T) {
+ for i, test := range keyPressTests {
+ for j := 1; j < len(test.in); j++ {
+ c := &MockTerminal{
+ toSend: []byte(test.in),
+ bytesPerRead: j,
+ }
+ ss := NewTerminal(c, "> ")
+ for k := 0; k < test.throwAwayLines; k++ {
+ _, err := ss.ReadLine()
+ if err != nil {
+ t.Errorf("Throwaway line %d from test %d resulted in error: %s", k, i, err)
+ }
+ }
+ line, err := ss.ReadLine()
+ if line != test.line {
+ t.Errorf("Line resulting from test %d (%d bytes per read) was '%s', expected '%s'", i, j, line, test.line)
+ break
+ }
+ if err != test.err {
+ t.Errorf("Error resulting from test %d (%d bytes per read) was '%v', expected '%v'", i, j, err, test.err)
+ break
+ }
+ }
+ }
+}
+
+func TestPasswordNotSaved(t *testing.T) {
+ c := &MockTerminal{
+ toSend: []byte("password\r\x1b[A\r"),
+ bytesPerRead: 1,
+ }
+ ss := NewTerminal(c, "> ")
+ pw, _ := ss.ReadPassword("> ")
+ if pw != "password" {
+ t.Fatalf("failed to read password, got %s", pw)
+ }
+ line, _ := ss.ReadLine()
+ if len(line) > 0 {
+ t.Fatalf("password was saved in history")
+ }
+}
+
+var setSizeTests = []struct {
+ width, height int
+}{
+ {40, 13},
+ {80, 24},
+ {132, 43},
+}
+
+func TestTerminalSetSize(t *testing.T) {
+ for _, setSize := range setSizeTests {
+ c := &MockTerminal{
+ toSend: []byte("password\r\x1b[A\r"),
+ bytesPerRead: 1,
+ }
+ ss := NewTerminal(c, "> ")
+ ss.SetSize(setSize.width, setSize.height)
+ pw, _ := ss.ReadPassword("Password: ")
+ if pw != "password" {
+ t.Fatalf("failed to read password, got %s", pw)
+ }
+ if string(c.received) != "Password: \r\n" {
+ t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received)
+ }
+ }
+}
+
+func TestMakeRawState(t *testing.T) {
+ fd := int(os.Stdout.Fd())
+ if !IsTerminal(fd) {
+ t.Skip("stdout is not a terminal; skipping test")
+ }
+
+ st, err := GetState(fd)
+ if err != nil {
+ t.Fatalf("failed to get terminal state from GetState: %s", err)
+ }
+ defer Restore(fd, st)
+ raw, err := MakeRaw(fd)
+ if err != nil {
+ t.Fatalf("failed to get terminal state from MakeRaw: %s", err)
+ }
+
+ if *st != *raw {
+ t.Errorf("states do not match; was %v, expected %v", raw, st)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util.go b/vendor/golang.org/x/crypto/ssh/terminal/util.go
new file mode 100644
index 000000000..598e3df77
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util.go
@@ -0,0 +1,128 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux,!appengine netbsd openbsd
+
+// Package terminal provides support functions for dealing with terminals, as
+// commonly found on UNIX systems.
+//
+// Putting a terminal into raw mode is the most common requirement:
+//
+// oldState, err := terminal.MakeRaw(0)
+// if err != nil {
+// panic(err)
+// }
+// defer terminal.Restore(0, oldState)
+package terminal // import "golang.org/x/crypto/ssh/terminal"
+
+import (
+ "io"
+ "syscall"
+ "unsafe"
+)
+
+// State contains the state of a terminal.
+type State struct {
+ termios syscall.Termios
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+ var termios syscall.Termios
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
+ return err == 0
+}
+
+// MakeRaw put the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+func MakeRaw(fd int) (*State, error) {
+ var oldState State
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
+ return nil, err
+ }
+
+ newState := oldState.termios
+ newState.Iflag &^= syscall.ISTRIP | syscall.INLCR | syscall.ICRNL | syscall.IGNCR | syscall.IXON | syscall.IXOFF
+ newState.Lflag &^= syscall.ECHO | syscall.ICANON | syscall.ISIG
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
+ return nil, err
+ }
+
+ return &oldState, nil
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd int) (*State, error) {
+ var oldState State
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState.termios)), 0, 0, 0); err != 0 {
+ return nil, err
+ }
+
+ return &oldState, nil
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func Restore(fd int, state *State) error {
+ _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&state.termios)), 0, 0, 0)
+ return err
+}
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+ var dimensions [4]uint16
+
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&dimensions)), 0, 0, 0); err != 0 {
+ return -1, -1, err
+ }
+ return int(dimensions[1]), int(dimensions[0]), nil
+}
+
+// ReadPassword reads a line of input from a terminal without local echo. This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd int) ([]byte, error) {
+ var oldState syscall.Termios
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0); err != 0 {
+ return nil, err
+ }
+
+ newState := oldState
+ newState.Lflag &^= syscall.ECHO
+ newState.Lflag |= syscall.ICANON | syscall.ISIG
+ newState.Iflag |= syscall.ICRNL
+ if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&newState)), 0, 0, 0); err != 0 {
+ return nil, err
+ }
+
+ defer func() {
+ syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlWriteTermios, uintptr(unsafe.Pointer(&oldState)), 0, 0, 0)
+ }()
+
+ var buf [16]byte
+ var ret []byte
+ for {
+ n, err := syscall.Read(fd, buf[:])
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ if len(ret) == 0 {
+ return nil, io.EOF
+ }
+ break
+ }
+ if buf[n-1] == '\n' {
+ n--
+ }
+ ret = append(ret, buf[:n]...)
+ if n < len(buf) {
+ break
+ }
+ }
+
+ return ret, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
new file mode 100644
index 000000000..9c1ffd145
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_bsd.go
@@ -0,0 +1,12 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package terminal
+
+import "syscall"
+
+const ioctlReadTermios = syscall.TIOCGETA
+const ioctlWriteTermios = syscall.TIOCSETA
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go
new file mode 100644
index 000000000..5883b22d7
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_linux.go
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package terminal
+
+// These constants are declared here, rather than importing
+// them from the syscall package as some syscall packages, even
+// on linux, for example gccgo, do not declare them.
+const ioctlReadTermios = 0x5401 // syscall.TCGETS
+const ioctlWriteTermios = 0x5402 // syscall.TCSETS
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
new file mode 100644
index 000000000..799f049f0
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_plan9.go
@@ -0,0 +1,58 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package terminal provides support functions for dealing with terminals, as
+// commonly found on UNIX systems.
+//
+// Putting a terminal into raw mode is the most common requirement:
+//
+// oldState, err := terminal.MakeRaw(0)
+// if err != nil {
+// panic(err)
+// }
+// defer terminal.Restore(0, oldState)
+package terminal
+
+import (
+ "fmt"
+ "runtime"
+)
+
+type State struct{}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+ return false
+}
+
+// MakeRaw put the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+func MakeRaw(fd int) (*State, error) {
+ return nil, fmt.Errorf("terminal: MakeRaw not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd int) (*State, error) {
+ return nil, fmt.Errorf("terminal: GetState not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func Restore(fd int, state *State) error {
+ return fmt.Errorf("terminal: Restore not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+ return 0, 0, fmt.Errorf("terminal: GetSize not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
+
+// ReadPassword reads a line of input from a terminal without local echo. This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd int) ([]byte, error) {
+ return nil, fmt.Errorf("terminal: ReadPassword not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
+}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
new file mode 100644
index 000000000..ae9fa9ec1
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_windows.go
@@ -0,0 +1,174 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package terminal provides support functions for dealing with terminals, as
+// commonly found on UNIX systems.
+//
+// Putting a terminal into raw mode is the most common requirement:
+//
+// oldState, err := terminal.MakeRaw(0)
+// if err != nil {
+// panic(err)
+// }
+// defer terminal.Restore(0, oldState)
+package terminal
+
+import (
+ "io"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ enableLineInput = 2
+ enableEchoInput = 4
+ enableProcessedInput = 1
+ enableWindowInput = 8
+ enableMouseInput = 16
+ enableInsertMode = 32
+ enableQuickEditMode = 64
+ enableExtendedFlags = 128
+ enableAutoPosition = 256
+ enableProcessedOutput = 1
+ enableWrapAtEolOutput = 2
+)
+
+var kernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+var (
+ procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
+ procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
+ procGetConsoleScreenBufferInfo = kernel32.NewProc("GetConsoleScreenBufferInfo")
+)
+
+type (
+ short int16
+ word uint16
+
+ coord struct {
+ x short
+ y short
+ }
+ smallRect struct {
+ left short
+ top short
+ right short
+ bottom short
+ }
+ consoleScreenBufferInfo struct {
+ size coord
+ cursorPosition coord
+ attributes word
+ window smallRect
+ maximumWindowSize coord
+ }
+)
+
+type State struct {
+ mode uint32
+}
+
+// IsTerminal returns true if the given file descriptor is a terminal.
+func IsTerminal(fd int) bool {
+ var st uint32
+ r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+ return r != 0 && e == 0
+}
+
+// MakeRaw put the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+func MakeRaw(fd int) (*State, error) {
+ var st uint32
+ _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+ if e != 0 {
+ return nil, error(e)
+ }
+ raw := st &^ (enableEchoInput | enableProcessedInput | enableLineInput | enableProcessedOutput)
+ _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(raw), 0)
+ if e != 0 {
+ return nil, error(e)
+ }
+ return &State{st}, nil
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd int) (*State, error) {
+ var st uint32
+ _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+ if e != 0 {
+ return nil, error(e)
+ }
+ return &State{st}, nil
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func Restore(fd int, state *State) error {
+ _, _, err := syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(state.mode), 0)
+ return err
+}
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+ var info consoleScreenBufferInfo
+ _, _, e := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&info)), 0)
+ if e != 0 {
+ return 0, 0, error(e)
+ }
+ return int(info.size.x), int(info.size.y), nil
+}
+
+// ReadPassword reads a line of input from a terminal without local echo. This
+// is commonly used for inputting passwords and other sensitive data. The slice
+// returned does not include the \n.
+func ReadPassword(fd int) ([]byte, error) {
+ var st uint32
+ _, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0)
+ if e != 0 {
+ return nil, error(e)
+ }
+ old := st
+
+ st &^= (enableEchoInput)
+ st |= (enableProcessedInput | enableLineInput | enableProcessedOutput)
+ _, _, e = syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(st), 0)
+ if e != 0 {
+ return nil, error(e)
+ }
+
+ defer func() {
+ syscall.Syscall(procSetConsoleMode.Addr(), 2, uintptr(fd), uintptr(old), 0)
+ }()
+
+ var buf [16]byte
+ var ret []byte
+ for {
+ n, err := syscall.Read(syscall.Handle(fd), buf[:])
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ if len(ret) == 0 {
+ return nil, io.EOF
+ }
+ break
+ }
+ if buf[n-1] == '\n' {
+ n--
+ }
+ if n > 0 && buf[n-1] == '\r' {
+ n--
+ }
+ ret = append(ret, buf[:n]...)
+ if n < len(buf) {
+ break
+ }
+ }
+
+ return ret, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/test/agent_unix_test.go b/vendor/golang.org/x/crypto/ssh/test/agent_unix_test.go
new file mode 100644
index 000000000..f481253c9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/agent_unix_test.go
@@ -0,0 +1,59 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package test
+
+import (
+ "bytes"
+ "testing"
+
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/agent"
+)
+
+func TestAgentForward(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ keyring := agent.NewKeyring()
+ if err := keyring.Add(agent.AddedKey{PrivateKey: testPrivateKeys["dsa"]}); err != nil {
+ t.Fatalf("Error adding key: %s", err)
+ }
+ if err := keyring.Add(agent.AddedKey{
+ PrivateKey: testPrivateKeys["dsa"],
+ ConfirmBeforeUse: true,
+ LifetimeSecs: 3600,
+ }); err != nil {
+ t.Fatalf("Error adding key with constraints: %s", err)
+ }
+ pub := testPublicKeys["dsa"]
+
+ sess, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("NewSession: %v", err)
+ }
+ if err := agent.RequestAgentForwarding(sess); err != nil {
+ t.Fatalf("RequestAgentForwarding: %v", err)
+ }
+
+ if err := agent.ForwardToAgent(conn, keyring); err != nil {
+ t.Fatalf("SetupForwardKeyring: %v", err)
+ }
+ out, err := sess.CombinedOutput("ssh-add -L")
+ if err != nil {
+ t.Fatalf("running ssh-add: %v, out %s", err, out)
+ }
+ key, _, _, _, err := ssh.ParseAuthorizedKey(out)
+ if err != nil {
+ t.Fatalf("ParseAuthorizedKey(%q): %v", out, err)
+ }
+
+ if !bytes.Equal(key.Marshal(), pub.Marshal()) {
+ t.Fatalf("got key %s, want %s", ssh.MarshalAuthorizedKey(key), ssh.MarshalAuthorizedKey(pub))
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/test/cert_test.go b/vendor/golang.org/x/crypto/ssh/test/cert_test.go
new file mode 100644
index 000000000..364790f17
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/cert_test.go
@@ -0,0 +1,47 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package test
+
+import (
+ "crypto/rand"
+ "testing"
+
+ "golang.org/x/crypto/ssh"
+)
+
+func TestCertLogin(t *testing.T) {
+ s := newServer(t)
+ defer s.Shutdown()
+
+ // Use a key different from the default.
+ clientKey := testSigners["dsa"]
+ caAuthKey := testSigners["ecdsa"]
+ cert := &ssh.Certificate{
+ Key: clientKey.PublicKey(),
+ ValidPrincipals: []string{username()},
+ CertType: ssh.UserCert,
+ ValidBefore: ssh.CertTimeInfinity,
+ }
+ if err := cert.SignCert(rand.Reader, caAuthKey); err != nil {
+ t.Fatalf("SetSignature: %v", err)
+ }
+
+ certSigner, err := ssh.NewCertSigner(cert, clientKey)
+ if err != nil {
+ t.Fatalf("NewCertSigner: %v", err)
+ }
+
+ conf := &ssh.ClientConfig{
+ User: username(),
+ }
+ conf.Auth = append(conf.Auth, ssh.PublicKeys(certSigner))
+ client, err := s.TryDial(conf)
+ if err != nil {
+ t.Fatalf("TryDial: %v", err)
+ }
+ client.Close()
+}
diff --git a/vendor/golang.org/x/crypto/ssh/test/doc.go b/vendor/golang.org/x/crypto/ssh/test/doc.go
new file mode 100644
index 000000000..3f9b3346d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/doc.go
@@ -0,0 +1,7 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package contains integration tests for the
+// golang.org/x/crypto/ssh package.
+package test // import "golang.org/x/crypto/ssh/test"
diff --git a/vendor/golang.org/x/crypto/ssh/test/forward_unix_test.go b/vendor/golang.org/x/crypto/ssh/test/forward_unix_test.go
new file mode 100644
index 000000000..877a88cde
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/forward_unix_test.go
@@ -0,0 +1,160 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package test
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "math/rand"
+ "net"
+ "testing"
+ "time"
+)
+
+func TestPortForward(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ sshListener, err := conn.Listen("tcp", "localhost:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ go func() {
+ sshConn, err := sshListener.Accept()
+ if err != nil {
+ t.Fatalf("listen.Accept failed: %v", err)
+ }
+
+ _, err = io.Copy(sshConn, sshConn)
+ if err != nil && err != io.EOF {
+ t.Fatalf("ssh client copy: %v", err)
+ }
+ sshConn.Close()
+ }()
+
+ forwardedAddr := sshListener.Addr().String()
+ tcpConn, err := net.Dial("tcp", forwardedAddr)
+ if err != nil {
+ t.Fatalf("TCP dial failed: %v", err)
+ }
+
+ readChan := make(chan []byte)
+ go func() {
+ data, _ := ioutil.ReadAll(tcpConn)
+ readChan <- data
+ }()
+
+ // Invent some data.
+ data := make([]byte, 100*1000)
+ for i := range data {
+ data[i] = byte(i % 255)
+ }
+
+ var sent []byte
+ for len(sent) < 1000*1000 {
+ // Send random sized chunks
+ m := rand.Intn(len(data))
+ n, err := tcpConn.Write(data[:m])
+ if err != nil {
+ break
+ }
+ sent = append(sent, data[:n]...)
+ }
+ if err := tcpConn.(*net.TCPConn).CloseWrite(); err != nil {
+ t.Errorf("tcpConn.CloseWrite: %v", err)
+ }
+
+ read := <-readChan
+
+ if len(sent) != len(read) {
+ t.Fatalf("got %d bytes, want %d", len(read), len(sent))
+ }
+ if bytes.Compare(sent, read) != 0 {
+ t.Fatalf("read back data does not match")
+ }
+
+ if err := sshListener.Close(); err != nil {
+ t.Fatalf("sshListener.Close: %v", err)
+ }
+
+ // Check that the forward disappeared.
+ tcpConn, err = net.Dial("tcp", forwardedAddr)
+ if err == nil {
+ tcpConn.Close()
+ t.Errorf("still listening to %s after closing", forwardedAddr)
+ }
+}
+
+func TestAcceptClose(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+
+ sshListener, err := conn.Listen("tcp", "localhost:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ quit := make(chan error, 1)
+ go func() {
+ for {
+ c, err := sshListener.Accept()
+ if err != nil {
+ quit <- err
+ break
+ }
+ c.Close()
+ }
+ }()
+ sshListener.Close()
+
+ select {
+ case <-time.After(1 * time.Second):
+ t.Errorf("timeout: listener did not close.")
+ case err := <-quit:
+ t.Logf("quit as expected (error %v)", err)
+ }
+}
+
+// Check that listeners exit if the underlying client transport dies.
+func TestPortForwardConnectionClose(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+
+ sshListener, err := conn.Listen("tcp", "localhost:0")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ quit := make(chan error, 1)
+ go func() {
+ for {
+ c, err := sshListener.Accept()
+ if err != nil {
+ quit <- err
+ break
+ }
+ c.Close()
+ }
+ }()
+
+ // It would be even nicer if we closed the server side, but it
+ // is more involved as the fd for that side is dup()ed.
+ server.clientConn.Close()
+
+ select {
+ case <-time.After(1 * time.Second):
+ t.Errorf("timeout: listener did not close.")
+ case err := <-quit:
+ t.Logf("quit as expected (error %v)", err)
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/test/session_test.go b/vendor/golang.org/x/crypto/ssh/test/session_test.go
new file mode 100644
index 000000000..d27ade76b
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/session_test.go
@@ -0,0 +1,365 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package test
+
+// Session functional tests.
+
+import (
+ "bytes"
+ "errors"
+ "io"
+ "strings"
+ "testing"
+
+ "golang.org/x/crypto/ssh"
+)
+
+func TestRunCommandSuccess(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+ defer session.Close()
+ err = session.Run("true")
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+}
+
+func TestHostKeyCheck(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+
+ conf := clientConfig()
+ hostDB := hostKeyDB()
+ conf.HostKeyCallback = hostDB.Check
+
+ // change the keys.
+ hostDB.keys[ssh.KeyAlgoRSA][25]++
+ hostDB.keys[ssh.KeyAlgoDSA][25]++
+ hostDB.keys[ssh.KeyAlgoECDSA256][25]++
+
+ conn, err := server.TryDial(conf)
+ if err == nil {
+ conn.Close()
+ t.Fatalf("dial should have failed.")
+ } else if !strings.Contains(err.Error(), "host key mismatch") {
+ t.Fatalf("'host key mismatch' not found in %v", err)
+ }
+}
+
+func TestRunCommandStdin(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+ defer session.Close()
+
+ r, w := io.Pipe()
+ defer r.Close()
+ defer w.Close()
+ session.Stdin = r
+
+ err = session.Run("true")
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+}
+
+func TestRunCommandStdinError(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+ defer session.Close()
+
+ r, w := io.Pipe()
+ defer r.Close()
+ session.Stdin = r
+ pipeErr := errors.New("closing write end of pipe")
+ w.CloseWithError(pipeErr)
+
+ err = session.Run("true")
+ if err != pipeErr {
+ t.Fatalf("expected %v, found %v", pipeErr, err)
+ }
+}
+
+func TestRunCommandFailed(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+ defer session.Close()
+ err = session.Run(`bash -c "kill -9 $$"`)
+ if err == nil {
+ t.Fatalf("session succeeded: %v", err)
+ }
+}
+
+func TestRunCommandWeClosed(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+ err = session.Shell()
+ if err != nil {
+ t.Fatalf("shell failed: %v", err)
+ }
+ err = session.Close()
+ if err != nil {
+ t.Fatalf("shell failed: %v", err)
+ }
+}
+
+func TestFuncLargeRead(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("unable to create new session: %s", err)
+ }
+
+ stdout, err := session.StdoutPipe()
+ if err != nil {
+ t.Fatalf("unable to acquire stdout pipe: %s", err)
+ }
+
+ err = session.Start("dd if=/dev/urandom bs=2048 count=1024")
+ if err != nil {
+ t.Fatalf("unable to execute remote command: %s", err)
+ }
+
+ buf := new(bytes.Buffer)
+ n, err := io.Copy(buf, stdout)
+ if err != nil {
+ t.Fatalf("error reading from remote stdout: %s", err)
+ }
+
+ if n != 2048*1024 {
+ t.Fatalf("Expected %d bytes but read only %d from remote command", 2048, n)
+ }
+}
+
+func TestKeyChange(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conf := clientConfig()
+ hostDB := hostKeyDB()
+ conf.HostKeyCallback = hostDB.Check
+ conf.RekeyThreshold = 1024
+ conn := server.Dial(conf)
+ defer conn.Close()
+
+ for i := 0; i < 4; i++ {
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("unable to create new session: %s", err)
+ }
+
+ stdout, err := session.StdoutPipe()
+ if err != nil {
+ t.Fatalf("unable to acquire stdout pipe: %s", err)
+ }
+
+ err = session.Start("dd if=/dev/urandom bs=1024 count=1")
+ if err != nil {
+ t.Fatalf("unable to execute remote command: %s", err)
+ }
+ buf := new(bytes.Buffer)
+ n, err := io.Copy(buf, stdout)
+ if err != nil {
+ t.Fatalf("error reading from remote stdout: %s", err)
+ }
+
+ want := int64(1024)
+ if n != want {
+ t.Fatalf("Expected %d bytes but read only %d from remote command", want, n)
+ }
+ }
+
+ if changes := hostDB.checkCount; changes < 4 {
+ t.Errorf("got %d key changes, want 4", changes)
+ }
+}
+
+func TestInvalidTerminalMode(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+ defer session.Close()
+
+ if err = session.RequestPty("vt100", 80, 40, ssh.TerminalModes{255: 1984}); err == nil {
+ t.Fatalf("req-pty failed: successful request with invalid mode")
+ }
+}
+
+func TestValidTerminalMode(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ conn := server.Dial(clientConfig())
+ defer conn.Close()
+
+ session, err := conn.NewSession()
+ if err != nil {
+ t.Fatalf("session failed: %v", err)
+ }
+ defer session.Close()
+
+ stdout, err := session.StdoutPipe()
+ if err != nil {
+ t.Fatalf("unable to acquire stdout pipe: %s", err)
+ }
+
+ stdin, err := session.StdinPipe()
+ if err != nil {
+ t.Fatalf("unable to acquire stdin pipe: %s", err)
+ }
+
+ tm := ssh.TerminalModes{ssh.ECHO: 0}
+ if err = session.RequestPty("xterm", 80, 40, tm); err != nil {
+ t.Fatalf("req-pty failed: %s", err)
+ }
+
+ err = session.Shell()
+ if err != nil {
+ t.Fatalf("session failed: %s", err)
+ }
+
+ stdin.Write([]byte("stty -a && exit\n"))
+
+ var buf bytes.Buffer
+ if _, err := io.Copy(&buf, stdout); err != nil {
+ t.Fatalf("reading failed: %s", err)
+ }
+
+ if sttyOutput := buf.String(); !strings.Contains(sttyOutput, "-echo ") {
+ t.Fatalf("terminal mode failure: expected -echo in stty output, got %s", sttyOutput)
+ }
+}
+
+func TestCiphers(t *testing.T) {
+ var config ssh.Config
+ config.SetDefaults()
+ cipherOrder := config.Ciphers
+ // This cipher will not be tested when commented out in cipher.go it will
+ // fallback to the next available as per line 292.
+ cipherOrder = append(cipherOrder, "aes128-cbc")
+
+ for _, ciph := range cipherOrder {
+ server := newServer(t)
+ defer server.Shutdown()
+ conf := clientConfig()
+ conf.Ciphers = []string{ciph}
+ // Don't fail if sshd doesnt have the cipher.
+ conf.Ciphers = append(conf.Ciphers, cipherOrder...)
+ conn, err := server.TryDial(conf)
+ if err == nil {
+ conn.Close()
+ } else {
+ t.Fatalf("failed for cipher %q", ciph)
+ }
+ }
+}
+
+func TestMACs(t *testing.T) {
+ var config ssh.Config
+ config.SetDefaults()
+ macOrder := config.MACs
+
+ for _, mac := range macOrder {
+ server := newServer(t)
+ defer server.Shutdown()
+ conf := clientConfig()
+ conf.MACs = []string{mac}
+ // Don't fail if sshd doesnt have the MAC.
+ conf.MACs = append(conf.MACs, macOrder...)
+ if conn, err := server.TryDial(conf); err == nil {
+ conn.Close()
+ } else {
+ t.Fatalf("failed for MAC %q", mac)
+ }
+ }
+}
+
+func TestKeyExchanges(t *testing.T) {
+ var config ssh.Config
+ config.SetDefaults()
+ kexOrder := config.KeyExchanges
+ for _, kex := range kexOrder {
+ server := newServer(t)
+ defer server.Shutdown()
+ conf := clientConfig()
+ // Don't fail if sshd doesnt have the kex.
+ conf.KeyExchanges = append([]string{kex}, kexOrder...)
+ conn, err := server.TryDial(conf)
+ if err == nil {
+ conn.Close()
+ } else {
+ t.Errorf("failed for kex %q", kex)
+ }
+ }
+}
+
+func TestClientAuthAlgorithms(t *testing.T) {
+ for _, key := range []string{
+ "rsa",
+ "dsa",
+ "ecdsa",
+ "ed25519",
+ } {
+ server := newServer(t)
+ conf := clientConfig()
+ conf.SetDefaults()
+ conf.Auth = []ssh.AuthMethod{
+ ssh.PublicKeys(testSigners[key]),
+ }
+
+ conn, err := server.TryDial(conf)
+ if err == nil {
+ conn.Close()
+ } else {
+ t.Errorf("failed for key %q", key)
+ }
+
+ server.Shutdown()
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/test/tcpip_test.go b/vendor/golang.org/x/crypto/ssh/test/tcpip_test.go
new file mode 100644
index 000000000..a2eb9358d
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/tcpip_test.go
@@ -0,0 +1,46 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !windows
+
+package test
+
+// direct-tcpip functional tests
+
+import (
+ "io"
+ "net"
+ "testing"
+)
+
+func TestDial(t *testing.T) {
+ server := newServer(t)
+ defer server.Shutdown()
+ sshConn := server.Dial(clientConfig())
+ defer sshConn.Close()
+
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("Listen: %v", err)
+ }
+ defer l.Close()
+
+ go func() {
+ for {
+ c, err := l.Accept()
+ if err != nil {
+ break
+ }
+
+ io.WriteString(c, c.RemoteAddr().String())
+ c.Close()
+ }
+ }()
+
+ conn, err := sshConn.Dial("tcp", l.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer conn.Close()
+}
diff --git a/vendor/golang.org/x/crypto/ssh/test/test_unix_test.go b/vendor/golang.org/x/crypto/ssh/test/test_unix_test.go
new file mode 100644
index 000000000..3bfd881e4
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/test_unix_test.go
@@ -0,0 +1,268 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd plan9
+
+package test
+
+// functional test harness for unix.
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "net"
+ "os"
+ "os/exec"
+ "os/user"
+ "path/filepath"
+ "testing"
+ "text/template"
+
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/testdata"
+)
+
+const sshd_config = `
+Protocol 2
+HostKey {{.Dir}}/id_rsa
+HostKey {{.Dir}}/id_dsa
+HostKey {{.Dir}}/id_ecdsa
+Pidfile {{.Dir}}/sshd.pid
+#UsePrivilegeSeparation no
+KeyRegenerationInterval 3600
+ServerKeyBits 768
+SyslogFacility AUTH
+LogLevel DEBUG2
+LoginGraceTime 120
+PermitRootLogin no
+StrictModes no
+RSAAuthentication yes
+PubkeyAuthentication yes
+AuthorizedKeysFile {{.Dir}}/authorized_keys
+TrustedUserCAKeys {{.Dir}}/id_ecdsa.pub
+IgnoreRhosts yes
+RhostsRSAAuthentication no
+HostbasedAuthentication no
+PubkeyAcceptedKeyTypes=*
+`
+
+var configTmpl = template.Must(template.New("").Parse(sshd_config))
+
+type server struct {
+ t *testing.T
+ cleanup func() // executed during Shutdown
+ configfile string
+ cmd *exec.Cmd
+ output bytes.Buffer // holds stderr from sshd process
+
+ // Client half of the network connection.
+ clientConn net.Conn
+}
+
+func username() string {
+ var username string
+ if user, err := user.Current(); err == nil {
+ username = user.Username
+ } else {
+ // user.Current() currently requires cgo. If an error is
+ // returned attempt to get the username from the environment.
+ log.Printf("user.Current: %v; falling back on $USER", err)
+ username = os.Getenv("USER")
+ }
+ if username == "" {
+ panic("Unable to get username")
+ }
+ return username
+}
+
+type storedHostKey struct {
+ // keys map from an algorithm string to binary key data.
+ keys map[string][]byte
+
+ // checkCount counts the Check calls. Used for testing
+ // rekeying.
+ checkCount int
+}
+
+func (k *storedHostKey) Add(key ssh.PublicKey) {
+ if k.keys == nil {
+ k.keys = map[string][]byte{}
+ }
+ k.keys[key.Type()] = key.Marshal()
+}
+
+func (k *storedHostKey) Check(addr string, remote net.Addr, key ssh.PublicKey) error {
+ k.checkCount++
+ algo := key.Type()
+
+ if k.keys == nil || bytes.Compare(key.Marshal(), k.keys[algo]) != 0 {
+ return fmt.Errorf("host key mismatch. Got %q, want %q", key, k.keys[algo])
+ }
+ return nil
+}
+
+func hostKeyDB() *storedHostKey {
+ keyChecker := &storedHostKey{}
+ keyChecker.Add(testPublicKeys["ecdsa"])
+ keyChecker.Add(testPublicKeys["rsa"])
+ keyChecker.Add(testPublicKeys["dsa"])
+ return keyChecker
+}
+
+func clientConfig() *ssh.ClientConfig {
+ config := &ssh.ClientConfig{
+ User: username(),
+ Auth: []ssh.AuthMethod{
+ ssh.PublicKeys(testSigners["user"]),
+ },
+ HostKeyCallback: hostKeyDB().Check,
+ }
+ return config
+}
+
+// unixConnection creates two halves of a connected net.UnixConn. It
+// is used for connecting the Go SSH client with sshd without opening
+// ports.
+func unixConnection() (*net.UnixConn, *net.UnixConn, error) {
+ dir, err := ioutil.TempDir("", "unixConnection")
+ if err != nil {
+ return nil, nil, err
+ }
+ defer os.Remove(dir)
+
+ addr := filepath.Join(dir, "ssh")
+ listener, err := net.Listen("unix", addr)
+ if err != nil {
+ return nil, nil, err
+ }
+ defer listener.Close()
+ c1, err := net.Dial("unix", addr)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ c2, err := listener.Accept()
+ if err != nil {
+ c1.Close()
+ return nil, nil, err
+ }
+
+ return c1.(*net.UnixConn), c2.(*net.UnixConn), nil
+}
+
+func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.Client, error) {
+ sshd, err := exec.LookPath("sshd")
+ if err != nil {
+ s.t.Skipf("skipping test: %v", err)
+ }
+
+ c1, c2, err := unixConnection()
+ if err != nil {
+ s.t.Fatalf("unixConnection: %v", err)
+ }
+
+ s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e")
+ f, err := c2.File()
+ if err != nil {
+ s.t.Fatalf("UnixConn.File: %v", err)
+ }
+ defer f.Close()
+ s.cmd.Stdin = f
+ s.cmd.Stdout = f
+ s.cmd.Stderr = &s.output
+ if err := s.cmd.Start(); err != nil {
+ s.t.Fail()
+ s.Shutdown()
+ s.t.Fatalf("s.cmd.Start: %v", err)
+ }
+ s.clientConn = c1
+ conn, chans, reqs, err := ssh.NewClientConn(c1, "", config)
+ if err != nil {
+ return nil, err
+ }
+ return ssh.NewClient(conn, chans, reqs), nil
+}
+
+func (s *server) Dial(config *ssh.ClientConfig) *ssh.Client {
+ conn, err := s.TryDial(config)
+ if err != nil {
+ s.t.Fail()
+ s.Shutdown()
+ s.t.Fatalf("ssh.Client: %v", err)
+ }
+ return conn
+}
+
+func (s *server) Shutdown() {
+ if s.cmd != nil && s.cmd.Process != nil {
+ // Don't check for errors; if it fails it's most
+ // likely "os: process already finished", and we don't
+ // care about that. Use os.Interrupt, so child
+ // processes are killed too.
+ s.cmd.Process.Signal(os.Interrupt)
+ s.cmd.Wait()
+ }
+ if s.t.Failed() {
+ // log any output from sshd process
+ s.t.Logf("sshd: %s", s.output.String())
+ }
+ s.cleanup()
+}
+
+func writeFile(path string, contents []byte) {
+ f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600)
+ if err != nil {
+ panic(err)
+ }
+ defer f.Close()
+ if _, err := f.Write(contents); err != nil {
+ panic(err)
+ }
+}
+
+// newServer returns a new mock ssh server.
+func newServer(t *testing.T) *server {
+ if testing.Short() {
+ t.Skip("skipping test due to -short")
+ }
+ dir, err := ioutil.TempDir("", "sshtest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ f, err := os.Create(filepath.Join(dir, "sshd_config"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = configTmpl.Execute(f, map[string]string{
+ "Dir": dir,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ f.Close()
+
+ for k, v := range testdata.PEMBytes {
+ filename := "id_" + k
+ writeFile(filepath.Join(dir, filename), v)
+ writeFile(filepath.Join(dir, filename+".pub"), ssh.MarshalAuthorizedKey(testPublicKeys[k]))
+ }
+
+ var authkeys bytes.Buffer
+ for k, _ := range testdata.PEMBytes {
+ authkeys.Write(ssh.MarshalAuthorizedKey(testPublicKeys[k]))
+ }
+ writeFile(filepath.Join(dir, "authorized_keys"), authkeys.Bytes())
+
+ return &server{
+ t: t,
+ configfile: f.Name(),
+ cleanup: func() {
+ if err := os.RemoveAll(dir); err != nil {
+ t.Error(err)
+ }
+ },
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/test/testdata_test.go b/vendor/golang.org/x/crypto/ssh/test/testdata_test.go
new file mode 100644
index 000000000..ae48c7516
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/test/testdata_test.go
@@ -0,0 +1,64 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places:
+// ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three
+// instances.
+
+package test
+
+import (
+ "crypto/rand"
+ "fmt"
+
+ "golang.org/x/crypto/ssh"
+ "golang.org/x/crypto/ssh/testdata"
+)
+
+var (
+ testPrivateKeys map[string]interface{}
+ testSigners map[string]ssh.Signer
+ testPublicKeys map[string]ssh.PublicKey
+)
+
+func init() {
+ var err error
+
+ n := len(testdata.PEMBytes)
+ testPrivateKeys = make(map[string]interface{}, n)
+ testSigners = make(map[string]ssh.Signer, n)
+ testPublicKeys = make(map[string]ssh.PublicKey, n)
+ for t, k := range testdata.PEMBytes {
+ testPrivateKeys[t], err = ssh.ParseRawPrivateKey(k)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err))
+ }
+ testSigners[t], err = ssh.NewSignerFromKey(testPrivateKeys[t])
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err))
+ }
+ testPublicKeys[t] = testSigners[t].PublicKey()
+ }
+
+ // Create a cert and sign it for use in tests.
+ testCert := &ssh.Certificate{
+ Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
+ ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage
+ ValidAfter: 0, // unix epoch
+ ValidBefore: ssh.CertTimeInfinity, // The end of currently representable time.
+ Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
+ Key: testPublicKeys["ecdsa"],
+ SignatureKey: testPublicKeys["rsa"],
+ Permissions: ssh.Permissions{
+ CriticalOptions: map[string]string{},
+ Extensions: map[string]string{},
+ },
+ }
+ testCert.SignCert(rand.Reader, testSigners["rsa"])
+ testPrivateKeys["cert"] = testPrivateKeys["ecdsa"]
+ testSigners["cert"], err = ssh.NewCertSigner(testCert, testSigners["ecdsa"])
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create certificate signer: %v", err))
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/testdata/doc.go b/vendor/golang.org/x/crypto/ssh/testdata/doc.go
new file mode 100644
index 000000000..fcae47ca6
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/testdata/doc.go
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package contains test data shared between the various subpackages of
+// the golang.org/x/crypto/ssh package. Under no circumstance should
+// this data be used for production code.
+package testdata // import "golang.org/x/crypto/ssh/testdata"
diff --git a/vendor/golang.org/x/crypto/ssh/testdata/keys.go b/vendor/golang.org/x/crypto/ssh/testdata/keys.go
new file mode 100644
index 000000000..9b76905f2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/testdata/keys.go
@@ -0,0 +1,57 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package testdata
+
+var PEMBytes = map[string][]byte{
+ "dsa": []byte(`-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQD6PDSEyXiI9jfNs97WuM46MSDCYlOqWw80ajN16AohtBncs1YB
+lHk//dQOvCYOsYaE+gNix2jtoRjwXhDsc25/IqQbU1ahb7mB8/rsaILRGIbA5WH3
+EgFtJmXFovDz3if6F6TzvhFpHgJRmLYVR8cqsezL3hEZOvvs2iH7MorkxwIVAJHD
+nD82+lxh2fb4PMsIiaXudAsBAoGAQRf7Q/iaPRn43ZquUhd6WwvirqUj+tkIu6eV
+2nZWYmXLlqFQKEy4Tejl7Wkyzr2OSYvbXLzo7TNxLKoWor6ips0phYPPMyXld14r
+juhT24CrhOzuLMhDduMDi032wDIZG4Y+K7ElU8Oufn8Sj5Wge8r6ANmmVgmFfynr
+FhdYCngCgYEA3ucGJ93/Mx4q4eKRDxcWD3QzWyqpbRVRRV1Vmih9Ha/qC994nJFz
+DQIdjxDIT2Rk2AGzMqFEB68Zc3O+Wcsmz5eWWzEwFxaTwOGWTyDqsDRLm3fD+QYj
+nOwuxb0Kce+gWI8voWcqC9cyRm09jGzu2Ab3Bhtpg8JJ8L7gS3MRZK4CFEx4UAfY
+Fmsr0W6fHB9nhS4/UXM8
+-----END DSA PRIVATE KEY-----
+`),
+ "ecdsa": []byte(`-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINGWx0zo6fhJ/0EAfrPzVFyFC9s18lBt3cRoEDhS3ARooAoGCCqGSM49
+AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+
+6/ZOXRnPmNAlLUqjShUsUBBngG0u2fqEqA==
+-----END EC PRIVATE KEY-----
+`),
+ "rsa": []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQC8A6FGHDiWCSREAXCq6yBfNVr0xCVG2CzvktFNRpue+RXrGs/2
+a6ySEJQb3IYquw7HlJgu6fg3WIWhOmHCjfpG0PrL4CRwbqQ2LaPPXhJErWYejcD8
+Di00cF3677+G10KMZk9RXbmHtuBFZT98wxg8j+ZsBMqGM1+7yrWUvynswQIDAQAB
+AoGAJMCk5vqfSRzyXOTXLGIYCuR4Kj6pdsbNSeuuRGfYBeR1F2c/XdFAg7D/8s5R
+38p/Ih52/Ty5S8BfJtwtvgVY9ecf/JlU/rl/QzhG8/8KC0NG7KsyXklbQ7gJT8UT
+Ojmw5QpMk+rKv17ipDVkQQmPaj+gJXYNAHqImke5mm/K/h0CQQDciPmviQ+DOhOq
+2ZBqUfH8oXHgFmp7/6pXw80DpMIxgV3CwkxxIVx6a8lVH9bT/AFySJ6vXq4zTuV9
+6QmZcZzDAkEA2j/UXJPIs1fQ8z/6sONOkU/BjtoePFIWJlRxdN35cZjXnBraX5UR
+fFHkePv4YwqmXNqrBOvSu+w2WdSDci+IKwJAcsPRc/jWmsrJW1q3Ha0hSf/WG/Bu
+X7MPuXaKpP/DkzGoUmb8ks7yqj6XWnYkPNLjCc8izU5vRwIiyWBRf4mxMwJBAILa
+NDvRS0rjwt6lJGv7zPZoqDc65VfrK2aNyHx2PgFyzwrEOtuF57bu7pnvEIxpLTeM
+z26i6XVMeYXAWZMTloMCQBbpGgEERQpeUknLBqUHhg/wXF6+lFA+vEGnkY+Dwab2
+KCXFGd+SQ5GdUcEMe9isUH6DYj/6/yCDoFrXXmpQb+M=
+-----END RSA PRIVATE KEY-----
+`),
+ "ed25519": []byte(`-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
+QyNTUxOQAAACA+3f7hS7g5UWwXOGVTrMfhmxyrjqz7Sxxbx7I1j8DvvwAAAJhAFfkOQBX5
+DgAAAAtzc2gtZWQyNTUxOQAAACA+3f7hS7g5UWwXOGVTrMfhmxyrjqz7Sxxbx7I1j8Dvvw
+AAAEAaYmXltfW6nhRo3iWGglRB48lYq0z0Q3I3KyrdutEr6j7d/uFLuDlRbBc4ZVOsx+Gb
+HKuOrPtLHFvHsjWPwO+/AAAAE2dhcnRvbm1AZ2FydG9ubS14cHMBAg==
+-----END OPENSSH PRIVATE KEY-----
+`),
+ "user": []byte(`-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEILYCAeq8f7V4vSSypRw7pxy8yz3V5W4qg8kSC3zJhqpQoAoGCCqGSM49
+AwEHoUQDQgAEYcO2xNKiRUYOLEHM7VYAp57HNyKbOdYtHD83Z4hzNPVC4tM5mdGD
+PLL8IEwvYu2wq+lpXfGQnNMbzYf9gspG0w==
+-----END EC PRIVATE KEY-----
+`),
+}
diff --git a/vendor/golang.org/x/crypto/ssh/testdata_test.go b/vendor/golang.org/x/crypto/ssh/testdata_test.go
new file mode 100644
index 000000000..f2828c1b5
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/testdata_test.go
@@ -0,0 +1,63 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// IMPLEMENTOR NOTE: To avoid a package loop, this file is in three places:
+// ssh/, ssh/agent, and ssh/test/. It should be kept in sync across all three
+// instances.
+
+package ssh
+
+import (
+ "crypto/rand"
+ "fmt"
+
+ "golang.org/x/crypto/ssh/testdata"
+)
+
+var (
+ testPrivateKeys map[string]interface{}
+ testSigners map[string]Signer
+ testPublicKeys map[string]PublicKey
+)
+
+func init() {
+ var err error
+
+ n := len(testdata.PEMBytes)
+ testPrivateKeys = make(map[string]interface{}, n)
+ testSigners = make(map[string]Signer, n)
+ testPublicKeys = make(map[string]PublicKey, n)
+ for t, k := range testdata.PEMBytes {
+ testPrivateKeys[t], err = ParseRawPrivateKey(k)
+ if err != nil {
+ panic(fmt.Sprintf("Unable to parse test key %s: %v", t, err))
+ }
+ testSigners[t], err = NewSignerFromKey(testPrivateKeys[t])
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create signer for test key %s: %v", t, err))
+ }
+ testPublicKeys[t] = testSigners[t].PublicKey()
+ }
+
+ // Create a cert and sign it for use in tests.
+ testCert := &Certificate{
+ Nonce: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
+ ValidPrincipals: []string{"gopher1", "gopher2"}, // increases test coverage
+ ValidAfter: 0, // unix epoch
+ ValidBefore: CertTimeInfinity, // The end of currently representable time.
+ Reserved: []byte{}, // To pass reflect.DeepEqual after marshal & parse, this must be non-nil
+ Key: testPublicKeys["ecdsa"],
+ SignatureKey: testPublicKeys["rsa"],
+ Permissions: Permissions{
+ CriticalOptions: map[string]string{},
+ Extensions: map[string]string{},
+ },
+ }
+ testCert.SignCert(rand.Reader, testSigners["rsa"])
+ testPrivateKeys["cert"] = testPrivateKeys["ecdsa"]
+ testSigners["cert"], err = NewCertSigner(testCert, testSigners["ecdsa"])
+ if err != nil {
+ panic(fmt.Sprintf("Unable to create certificate signer: %v", err))
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go
new file mode 100644
index 000000000..bf7dd61fc
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/transport.go
@@ -0,0 +1,328 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bufio"
+ "errors"
+ "io"
+)
+
+const (
+ gcmCipherID = "aes128-gcm@openssh.com"
+ aes128cbcID = "aes128-cbc"
+)
+
+// packetConn represents a transport that implements packet based
+// operations.
+type packetConn interface {
+ // Encrypt and send a packet of data to the remote peer.
+ writePacket(packet []byte) error
+
+ // Read a packet from the connection
+ readPacket() ([]byte, error)
+
+ // Close closes the write-side of the connection.
+ Close() error
+}
+
+// transport is the keyingTransport that implements the SSH packet
+// protocol.
+type transport struct {
+ reader connectionState
+ writer connectionState
+
+ bufReader *bufio.Reader
+ bufWriter *bufio.Writer
+ rand io.Reader
+
+ io.Closer
+}
+
+// packetCipher represents a combination of SSH encryption/MAC
+// protocol. A single instance should be used for one direction only.
+type packetCipher interface {
+ // writePacket encrypts the packet and writes it to w. The
+ // contents of the packet are generally scrambled.
+ writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
+
+ // readPacket reads and decrypts a packet of data. The
+ // returned packet may be overwritten by future calls of
+ // readPacket.
+ readPacket(seqnum uint32, r io.Reader) ([]byte, error)
+}
+
+// connectionState represents one side (read or write) of the
+// connection. This is necessary because each direction has its own
+// keys, and can even have its own algorithms
+type connectionState struct {
+ packetCipher
+ seqNum uint32
+ dir direction
+ pendingKeyChange chan packetCipher
+}
+
+// prepareKeyChange sets up key material for a keychange. The key changes in
+// both directions are triggered by reading and writing a msgNewKey packet
+// respectively.
+func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error {
+ if ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult); err != nil {
+ return err
+ } else {
+ t.reader.pendingKeyChange <- ciph
+ }
+
+ if ciph, err := newPacketCipher(t.writer.dir, algs.w, kexResult); err != nil {
+ return err
+ } else {
+ t.writer.pendingKeyChange <- ciph
+ }
+
+ return nil
+}
+
+// Read and decrypt next packet.
+func (t *transport) readPacket() ([]byte, error) {
+ return t.reader.readPacket(t.bufReader)
+}
+
+func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
+ packet, err := s.packetCipher.readPacket(s.seqNum, r)
+ s.seqNum++
+ if err == nil && len(packet) == 0 {
+ err = errors.New("ssh: zero length packet")
+ }
+
+ if len(packet) > 0 {
+ switch packet[0] {
+ case msgNewKeys:
+ select {
+ case cipher := <-s.pendingKeyChange:
+ s.packetCipher = cipher
+ default:
+ return nil, errors.New("ssh: got bogus newkeys message.")
+ }
+
+ case msgDisconnect:
+ // Transform a disconnect message into an
+ // error. Since this is lowest level at which
+ // we interpret message types, doing it here
+ // ensures that we don't have to handle it
+ // elsewhere.
+ var msg disconnectMsg
+ if err := Unmarshal(packet, &msg); err != nil {
+ return nil, err
+ }
+ return nil, &msg
+ }
+ }
+
+ // The packet may point to an internal buffer, so copy the
+ // packet out here.
+ fresh := make([]byte, len(packet))
+ copy(fresh, packet)
+
+ return fresh, err
+}
+
+func (t *transport) writePacket(packet []byte) error {
+ return t.writer.writePacket(t.bufWriter, t.rand, packet)
+}
+
+func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
+ changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
+
+ err := s.packetCipher.writePacket(s.seqNum, w, rand, packet)
+ if err != nil {
+ return err
+ }
+ if err = w.Flush(); err != nil {
+ return err
+ }
+ s.seqNum++
+ if changeKeys {
+ select {
+ case cipher := <-s.pendingKeyChange:
+ s.packetCipher = cipher
+ default:
+ panic("ssh: no key material for msgNewKeys")
+ }
+ }
+ return err
+}
+
+func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport {
+ t := &transport{
+ bufReader: bufio.NewReader(rwc),
+ bufWriter: bufio.NewWriter(rwc),
+ rand: rand,
+ reader: connectionState{
+ packetCipher: &streamPacketCipher{cipher: noneCipher{}},
+ pendingKeyChange: make(chan packetCipher, 1),
+ },
+ writer: connectionState{
+ packetCipher: &streamPacketCipher{cipher: noneCipher{}},
+ pendingKeyChange: make(chan packetCipher, 1),
+ },
+ Closer: rwc,
+ }
+ if isClient {
+ t.reader.dir = serverKeys
+ t.writer.dir = clientKeys
+ } else {
+ t.reader.dir = clientKeys
+ t.writer.dir = serverKeys
+ }
+
+ return t
+}
+
+type direction struct {
+ ivTag []byte
+ keyTag []byte
+ macKeyTag []byte
+}
+
+var (
+ serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
+ clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
+)
+
+// generateKeys generates key material for IV, MAC and encryption.
+func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) {
+ cipherMode := cipherModes[algs.Cipher]
+ macMode := macModes[algs.MAC]
+
+ iv = make([]byte, cipherMode.ivSize)
+ key = make([]byte, cipherMode.keySize)
+ macKey = make([]byte, macMode.keySize)
+
+ generateKeyMaterial(iv, d.ivTag, kex)
+ generateKeyMaterial(key, d.keyTag, kex)
+ generateKeyMaterial(macKey, d.macKeyTag, kex)
+ return
+}
+
+// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
+// described in RFC 4253, section 6.4. direction should either be serverKeys
+// (to setup server->client keys) or clientKeys (for client->server keys).
+func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
+ iv, key, macKey := generateKeys(d, algs, kex)
+
+ if algs.Cipher == gcmCipherID {
+ return newGCMCipher(iv, key, macKey)
+ }
+
+ if algs.Cipher == aes128cbcID {
+ return newAESCBCCipher(iv, key, macKey, algs)
+ }
+
+ c := &streamPacketCipher{
+ mac: macModes[algs.MAC].new(macKey),
+ }
+ c.macResult = make([]byte, c.mac.Size())
+
+ var err error
+ c.cipher, err = cipherModes[algs.Cipher].createStream(key, iv)
+ if err != nil {
+ return nil, err
+ }
+
+ return c, nil
+}
+
+// generateKeyMaterial fills out with key material generated from tag, K, H
+// and sessionId, as specified in RFC 4253, section 7.2.
+func generateKeyMaterial(out, tag []byte, r *kexResult) {
+ var digestsSoFar []byte
+
+ h := r.Hash.New()
+ for len(out) > 0 {
+ h.Reset()
+ h.Write(r.K)
+ h.Write(r.H)
+
+ if len(digestsSoFar) == 0 {
+ h.Write(tag)
+ h.Write(r.SessionID)
+ } else {
+ h.Write(digestsSoFar)
+ }
+
+ digest := h.Sum(nil)
+ n := copy(out, digest)
+ out = out[n:]
+ if len(out) > 0 {
+ digestsSoFar = append(digestsSoFar, digest...)
+ }
+ }
+}
+
+const packageVersion = "SSH-2.0-Go"
+
+// Sends and receives a version line. The versionLine string should
+// be US ASCII, start with "SSH-2.0-", and should not include a
+// newline. exchangeVersions returns the other side's version line.
+func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) {
+ // Contrary to the RFC, we do not ignore lines that don't
+ // start with "SSH-2.0-" to make the library usable with
+ // nonconforming servers.
+ for _, c := range versionLine {
+ // The spec disallows non US-ASCII chars, and
+ // specifically forbids null chars.
+ if c < 32 {
+ return nil, errors.New("ssh: junk character in version line")
+ }
+ }
+ if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil {
+ return
+ }
+
+ them, err = readVersion(rw)
+ return them, err
+}
+
+// maxVersionStringBytes is the maximum number of bytes that we'll
+// accept as a version string. RFC 4253 section 4.2 limits this at 255
+// chars
+const maxVersionStringBytes = 255
+
+// Read version string as specified by RFC 4253, section 4.2.
+func readVersion(r io.Reader) ([]byte, error) {
+ versionString := make([]byte, 0, 64)
+ var ok bool
+ var buf [1]byte
+
+ for len(versionString) < maxVersionStringBytes {
+ _, err := io.ReadFull(r, buf[:])
+ if err != nil {
+ return nil, err
+ }
+ // The RFC says that the version should be terminated with \r\n
+ // but several SSH servers actually only send a \n.
+ if buf[0] == '\n' {
+ ok = true
+ break
+ }
+
+ // non ASCII chars are disallowed, but we are lenient,
+ // since Go doesn't use null-terminated strings.
+
+ // The RFC allows a comment after a space, however,
+ // all of it (version and comments) goes into the
+ // session hash.
+ versionString = append(versionString, buf[0])
+ }
+
+ if !ok {
+ return nil, errors.New("ssh: overflow reading version string")
+ }
+
+ // There might be a '\r' on the end which we should remove.
+ if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
+ versionString = versionString[:len(versionString)-1]
+ }
+ return versionString, nil
+}
diff --git a/vendor/golang.org/x/crypto/ssh/transport_test.go b/vendor/golang.org/x/crypto/ssh/transport_test.go
new file mode 100644
index 000000000..92d83abf9
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/transport_test.go
@@ -0,0 +1,109 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssh
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/binary"
+ "strings"
+ "testing"
+)
+
+func TestReadVersion(t *testing.T) {
+ longversion := strings.Repeat("SSH-2.0-bla", 50)[:253]
+ cases := map[string]string{
+ "SSH-2.0-bla\r\n": "SSH-2.0-bla",
+ "SSH-2.0-bla\n": "SSH-2.0-bla",
+ longversion + "\r\n": longversion,
+ }
+
+ for in, want := range cases {
+ result, err := readVersion(bytes.NewBufferString(in))
+ if err != nil {
+ t.Errorf("readVersion(%q): %s", in, err)
+ }
+ got := string(result)
+ if got != want {
+ t.Errorf("got %q, want %q", got, want)
+ }
+ }
+}
+
+func TestReadVersionError(t *testing.T) {
+ longversion := strings.Repeat("SSH-2.0-bla", 50)[:253]
+ cases := []string{
+ longversion + "too-long\r\n",
+ }
+ for _, in := range cases {
+ if _, err := readVersion(bytes.NewBufferString(in)); err == nil {
+ t.Errorf("readVersion(%q) should have failed", in)
+ }
+ }
+}
+
+func TestExchangeVersionsBasic(t *testing.T) {
+ v := "SSH-2.0-bla"
+ buf := bytes.NewBufferString(v + "\r\n")
+ them, err := exchangeVersions(buf, []byte("xyz"))
+ if err != nil {
+ t.Errorf("exchangeVersions: %v", err)
+ }
+
+ if want := "SSH-2.0-bla"; string(them) != want {
+ t.Errorf("got %q want %q for our version", them, want)
+ }
+}
+
+func TestExchangeVersions(t *testing.T) {
+ cases := []string{
+ "not\x000allowed",
+ "not allowed\n",
+ }
+ for _, c := range cases {
+ buf := bytes.NewBufferString("SSH-2.0-bla\r\n")
+ if _, err := exchangeVersions(buf, []byte(c)); err == nil {
+ t.Errorf("exchangeVersions(%q): should have failed", c)
+ }
+ }
+}
+
+type closerBuffer struct {
+ bytes.Buffer
+}
+
+func (b *closerBuffer) Close() error {
+ return nil
+}
+
+func TestTransportMaxPacketWrite(t *testing.T) {
+ buf := &closerBuffer{}
+ tr := newTransport(buf, rand.Reader, true)
+ huge := make([]byte, maxPacket+1)
+ err := tr.writePacket(huge)
+ if err == nil {
+ t.Errorf("transport accepted write for a huge packet.")
+ }
+}
+
+func TestTransportMaxPacketReader(t *testing.T) {
+ var header [5]byte
+ huge := make([]byte, maxPacket+128)
+ binary.BigEndian.PutUint32(header[0:], uint32(len(huge)))
+ // padding.
+ header[4] = 0
+
+ buf := &closerBuffer{}
+ buf.Write(header[:])
+ buf.Write(huge)
+
+ tr := newTransport(buf, rand.Reader, true)
+ _, err := tr.readPacket()
+ if err == nil {
+ t.Errorf("transport succeeded reading huge packet.")
+ } else if !strings.Contains(err.Error(), "large") {
+ t.Errorf("got %q, should mention %q", err.Error(), "large")
+ }
+}
diff --git a/vendor/golang.org/x/crypto/tea/cipher.go b/vendor/golang.org/x/crypto/tea/cipher.go
new file mode 100644
index 000000000..9c13d12a2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/tea/cipher.go
@@ -0,0 +1,109 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tea implements the TEA algorithm, as defined in Needham and
+// Wheeler's 1994 technical report, “TEA, a Tiny Encryption Algorithm”. See
+// http://www.cix.co.uk/~klockstone/tea.pdf for details.
+
+package tea
+
+import (
+ "crypto/cipher"
+ "encoding/binary"
+ "errors"
+)
+
+const (
+ // BlockSize is the size of a TEA block, in bytes.
+ BlockSize = 8
+
+ // KeySize is the size of a TEA key, in bytes.
+ KeySize = 16
+
+ // delta is the TEA key schedule constant.
+ delta = 0x9e3779b9
+
+ // numRounds is the standard number of rounds in TEA.
+ numRounds = 64
+)
+
+// tea is an instance of the TEA cipher with a particular key.
+type tea struct {
+ key [16]byte
+ rounds int
+}
+
+// NewCipher returns an instance of the TEA cipher with the standard number of
+// rounds. The key argument must be 16 bytes long.
+func NewCipher(key []byte) (cipher.Block, error) {
+ return NewCipherWithRounds(key, numRounds)
+}
+
+// NewCipherWithRounds returns an instance of the TEA cipher with a given
+// number of rounds, which must be even. The key argument must be 16 bytes
+// long.
+func NewCipherWithRounds(key []byte, rounds int) (cipher.Block, error) {
+ if len(key) != 16 {
+ return nil, errors.New("tea: incorrect key size")
+ }
+
+ if rounds&1 != 0 {
+ return nil, errors.New("tea: odd number of rounds specified")
+ }
+
+ c := &tea{
+ rounds: rounds,
+ }
+ copy(c.key[:], key)
+
+ return c, nil
+}
+
+// BlockSize returns the TEA block size, which is eight bytes. It is necessary
+// to satisfy the Block interface in the package "crypto/cipher".
+func (*tea) BlockSize() int {
+ return BlockSize
+}
+
+// Encrypt encrypts the 8 byte buffer src using the key in t and stores the
+// result in dst. Note that for amounts of data larger than a block, it is not
+// safe to just call Encrypt on successive blocks; instead, use an encryption
+// mode like CBC (see crypto/cipher/cbc.go).
+func (t *tea) Encrypt(dst, src []byte) {
+ e := binary.BigEndian
+ v0, v1 := e.Uint32(src), e.Uint32(src[4:])
+ k0, k1, k2, k3 := e.Uint32(t.key[0:]), e.Uint32(t.key[4:]), e.Uint32(t.key[8:]), e.Uint32(t.key[12:])
+
+ sum := uint32(0)
+ delta := uint32(delta)
+
+ for i := 0; i < t.rounds/2; i++ {
+ sum += delta
+ v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)
+ v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)
+ }
+
+ e.PutUint32(dst, v0)
+ e.PutUint32(dst[4:], v1)
+}
+
+// Decrypt decrypts the 8 byte buffer src using the key in t and stores the
+// result in dst.
+func (t *tea) Decrypt(dst, src []byte) {
+ e := binary.BigEndian
+ v0, v1 := e.Uint32(src), e.Uint32(src[4:])
+ k0, k1, k2, k3 := e.Uint32(t.key[0:]), e.Uint32(t.key[4:]), e.Uint32(t.key[8:]), e.Uint32(t.key[12:])
+
+ delta := uint32(delta)
+ sum := delta * uint32(t.rounds/2) // in general, sum = delta * n
+
+ for i := 0; i < t.rounds/2; i++ {
+ v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3)
+ v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1)
+ sum -= delta
+ }
+
+ e.PutUint32(dst, v0)
+ e.PutUint32(dst[4:], v1)
+}
diff --git a/vendor/golang.org/x/crypto/tea/tea_test.go b/vendor/golang.org/x/crypto/tea/tea_test.go
new file mode 100644
index 000000000..eb98d1e0e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/tea/tea_test.go
@@ -0,0 +1,93 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tea
+
+import (
+ "bytes"
+ "testing"
+)
+
+// A sample test key for when we just want to initialize a cipher
+var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
+
+// Test that the block size for tea is correct
+func TestBlocksize(t *testing.T) {
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Fatalf("NewCipher returned error: %s", err)
+ }
+
+ if result := c.BlockSize(); result != BlockSize {
+ t.Errorf("cipher.BlockSize returned %d, but expected %d", result, BlockSize)
+ }
+}
+
+// Test that invalid key sizes return an error
+func TestInvalidKeySize(t *testing.T) {
+ var key [KeySize + 1]byte
+
+ if _, err := NewCipher(key[:]); err == nil {
+ t.Errorf("invalid key size %d didn't result in an error.", len(key))
+ }
+
+ if _, err := NewCipher(key[:KeySize-1]); err == nil {
+ t.Errorf("invalid key size %d didn't result in an error.", KeySize-1)
+ }
+}
+
+// Test Vectors
+type teaTest struct {
+ rounds int
+ key []byte
+ plaintext []byte
+ ciphertext []byte
+}
+
+var teaTests = []teaTest{
+ // These were sourced from https://github.com/froydnj/ironclad/blob/master/testing/test-vectors/tea.testvec
+ {
+ numRounds,
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x41, 0xea, 0x3a, 0x0a, 0x94, 0xba, 0xa9, 0x40},
+ },
+ {
+ numRounds,
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x31, 0x9b, 0xbe, 0xfb, 0x01, 0x6a, 0xbd, 0xb2},
+ },
+ {
+ 16,
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xed, 0x28, 0x5d, 0xa1, 0x45, 0x5b, 0x33, 0xc1},
+ },
+}
+
+// Test encryption
+func TestCipherEncrypt(t *testing.T) {
+ // Test encryption with standard 64 rounds
+ for i, test := range teaTests {
+ c, err := NewCipherWithRounds(test.key, test.rounds)
+ if err != nil {
+ t.Fatalf("#%d: NewCipher returned error: %s", i, err)
+ }
+
+ var ciphertext [BlockSize]byte
+ c.Encrypt(ciphertext[:], test.plaintext)
+
+ if !bytes.Equal(ciphertext[:], test.ciphertext) {
+ t.Errorf("#%d: incorrect ciphertext. Got %x, wanted %x", i, ciphertext, test.ciphertext)
+ }
+
+ var plaintext2 [BlockSize]byte
+ c.Decrypt(plaintext2[:], ciphertext[:])
+
+ if !bytes.Equal(plaintext2[:], test.plaintext) {
+ t.Errorf("#%d: incorrect plaintext. Got %x, wanted %x", i, plaintext2, test.plaintext)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/twofish/twofish.go b/vendor/golang.org/x/crypto/twofish/twofish.go
new file mode 100644
index 000000000..376fa0ec2
--- /dev/null
+++ b/vendor/golang.org/x/crypto/twofish/twofish.go
@@ -0,0 +1,342 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package twofish implements Bruce Schneier's Twofish encryption algorithm.
+package twofish // import "golang.org/x/crypto/twofish"
+
+// Twofish is defined in http://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
+
+// This code is a port of the LibTom C implementation.
+// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
+// LibTomCrypt is free for all purposes under the public domain.
+// It was heavily inspired by the go blowfish package.
+
+import "strconv"
+
+// BlockSize is the constant block size of Twofish.
+const BlockSize = 16
+
+const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
+const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
+
+// A Cipher is an instance of Twofish encryption using a particular key.
+type Cipher struct {
+ s [4][256]uint32
+ k [40]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+ return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Twofish key, 16, 24 or 32 bytes.
+func NewCipher(key []byte) (*Cipher, error) {
+ keylen := len(key)
+
+ if keylen != 16 && keylen != 24 && keylen != 32 {
+ return nil, KeySizeError(keylen)
+ }
+
+ // k is the number of 64 bit words in key
+ k := keylen / 8
+
+ // Create the S[..] words
+ var S [4 * 4]byte
+ for i := 0; i < k; i++ {
+ // Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
+ for j, rsRow := range rs {
+ for k, rsVal := range rsRow {
+ S[4*i+j] ^= gfMult(key[8*i+k], rsVal, rsPolynomial)
+ }
+ }
+ }
+
+ // Calculate subkeys
+ c := new(Cipher)
+ var tmp [4]byte
+ for i := byte(0); i < 20; i++ {
+ // A = h(p * 2x, Me)
+ for j := range tmp {
+ tmp[j] = 2 * i
+ }
+ A := h(tmp[:], key, 0)
+
+ // B = rolc(h(p * (2x + 1), Mo), 8)
+ for j := range tmp {
+ tmp[j] = 2*i + 1
+ }
+ B := h(tmp[:], key, 1)
+ B = rol(B, 8)
+
+ c.k[2*i] = A + B
+
+ // K[2i+1] = (A + 2B) <<< 9
+ c.k[2*i+1] = rol(2*B+A, 9)
+ }
+
+ // Calculate sboxes
+ switch k {
+ case 2:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][byte(i)]^S[0]]^S[4]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][byte(i)]^S[1]]^S[5]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][byte(i)]^S[2]]^S[6]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][byte(i)]^S[3]]^S[7]], 3)
+ }
+ case 3:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[1]]^S[5]]^S[9]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[3]]^S[7]]^S[11]], 3)
+ }
+ default:
+ for i := range c.s[0] {
+ c.s[0][i] = mdsColumnMult(sbox[1][sbox[0][sbox[0][sbox[1][sbox[1][byte(i)]^S[0]]^S[4]]^S[8]]^S[12]], 0)
+ c.s[1][i] = mdsColumnMult(sbox[0][sbox[0][sbox[1][sbox[1][sbox[0][byte(i)]^S[1]]^S[5]]^S[9]]^S[13]], 1)
+ c.s[2][i] = mdsColumnMult(sbox[1][sbox[1][sbox[0][sbox[0][sbox[0][byte(i)]^S[2]]^S[6]]^S[10]]^S[14]], 2)
+ c.s[3][i] = mdsColumnMult(sbox[0][sbox[1][sbox[1][sbox[0][sbox[1][byte(i)]^S[3]]^S[7]]^S[11]]^S[15]], 3)
+ }
+ }
+
+ return c, nil
+}
+
+// BlockSize returns the Twofish block size, 16 bytes.
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// store32l stores src in dst in little-endian form.
+func store32l(dst []byte, src uint32) {
+ dst[0] = byte(src)
+ dst[1] = byte(src >> 8)
+ dst[2] = byte(src >> 16)
+ dst[3] = byte(src >> 24)
+ return
+}
+
+// load32l reads a little-endian uint32 from src.
+func load32l(src []byte) uint32 {
+ return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
+}
+
+// rol returns x after a left circular rotation of y bits.
+func rol(x, y uint32) uint32 {
+ return (x << (y & 31)) | (x >> (32 - (y & 31)))
+}
+
+// ror returns x after a right circular rotation of y bits.
+func ror(x, y uint32) uint32 {
+ return (x >> (y & 31)) | (x << (32 - (y & 31)))
+}
+
+// The RS matrix. See [TWOFISH] 4.3
+var rs = [4][8]byte{
+ {0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
+ {0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
+ {0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
+ {0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
+}
+
+// sbox tables
+var sbox = [2][256]byte{
+ {
+ 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
+ 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
+ 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
+ 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
+ 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
+ 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
+ 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
+ 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
+ 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
+ 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
+ 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
+ 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
+ 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
+ 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
+ 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
+ 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
+ },
+ {
+ 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
+ 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
+ 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
+ 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
+ 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
+ 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
+ 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
+ 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
+ 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
+ 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
+ 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
+ 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
+ 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
+ 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
+ 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
+ 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
+ },
+}
+
+// gfMult returns a·b in GF(2^8)/p
+func gfMult(a, b byte, p uint32) byte {
+ B := [2]uint32{0, uint32(b)}
+ P := [2]uint32{0, p}
+ var result uint32
+
+ // branchless GF multiplier
+ for i := 0; i < 7; i++ {
+ result ^= B[a&1]
+ a >>= 1
+ B[1] = P[B[1]>>7] ^ (B[1] << 1)
+ }
+ result ^= B[a&1]
+ return byte(result)
+}
+
+// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS · [x0]
+func mdsColumnMult(in byte, col int) uint32 {
+ mul01 := in
+ mul5B := gfMult(in, 0x5B, mdsPolynomial)
+ mulEF := gfMult(in, 0xEF, mdsPolynomial)
+
+ switch col {
+ case 0:
+ return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
+ case 1:
+ return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
+ case 2:
+ return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
+ case 3:
+ return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
+ }
+
+ panic("unreachable")
+}
+
+// h implements the S-box generation function. See [TWOFISH] 4.3.5
+func h(in, key []byte, offset int) uint32 {
+ var y [4]byte
+ for x := range y {
+ y[x] = in[x]
+ }
+ switch len(key) / 8 {
+ case 4:
+ y[0] = sbox[1][y[0]] ^ key[4*(6+offset)+0]
+ y[1] = sbox[0][y[1]] ^ key[4*(6+offset)+1]
+ y[2] = sbox[0][y[2]] ^ key[4*(6+offset)+2]
+ y[3] = sbox[1][y[3]] ^ key[4*(6+offset)+3]
+ fallthrough
+ case 3:
+ y[0] = sbox[1][y[0]] ^ key[4*(4+offset)+0]
+ y[1] = sbox[1][y[1]] ^ key[4*(4+offset)+1]
+ y[2] = sbox[0][y[2]] ^ key[4*(4+offset)+2]
+ y[3] = sbox[0][y[3]] ^ key[4*(4+offset)+3]
+ fallthrough
+ case 2:
+ y[0] = sbox[1][sbox[0][sbox[0][y[0]]^key[4*(2+offset)+0]]^key[4*(0+offset)+0]]
+ y[1] = sbox[0][sbox[0][sbox[1][y[1]]^key[4*(2+offset)+1]]^key[4*(0+offset)+1]]
+ y[2] = sbox[1][sbox[1][sbox[0][y[2]]^key[4*(2+offset)+2]]^key[4*(0+offset)+2]]
+ y[3] = sbox[0][sbox[1][sbox[1][y[3]]^key[4*(2+offset)+3]]^key[4*(0+offset)+3]]
+ }
+ // [y0 y1 y2 y3] = MDS . [x0 x1 x2 x3]
+ var mdsMult uint32
+ for i := range y {
+ mdsMult ^= mdsColumnMult(y[i], i)
+ }
+ return mdsMult
+}
+
+// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+ S1 := c.s[0]
+ S2 := c.s[1]
+ S3 := c.s[2]
+ S4 := c.s[3]
+
+ // Load input
+ ia := load32l(src[0:4])
+ ib := load32l(src[4:8])
+ ic := load32l(src[8:12])
+ id := load32l(src[12:16])
+
+ // Pre-whitening
+ ia ^= c.k[0]
+ ib ^= c.k[1]
+ ic ^= c.k[2]
+ id ^= c.k[3]
+
+ for i := 0; i < 8; i++ {
+ k := c.k[8+i*4 : 12+i*4]
+ t2 := S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
+ t1 := S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
+ ic = ror(ic^(t1+k[0]), 1)
+ id = rol(id, 1) ^ (t2 + t1 + k[1])
+
+ t2 = S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
+ t1 = S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
+ ia = ror(ia^(t1+k[2]), 1)
+ ib = rol(ib, 1) ^ (t2 + t1 + k[3])
+ }
+
+ // Output with "undo last swap"
+ ta := ic ^ c.k[4]
+ tb := id ^ c.k[5]
+ tc := ia ^ c.k[6]
+ td := ib ^ c.k[7]
+
+ store32l(dst[0:4], ta)
+ store32l(dst[4:8], tb)
+ store32l(dst[8:12], tc)
+ store32l(dst[12:16], td)
+}
+
+// Decrypt decrypts a 16-byte block from src to dst, which may overlap.
+func (c *Cipher) Decrypt(dst, src []byte) {
+ S1 := c.s[0]
+ S2 := c.s[1]
+ S3 := c.s[2]
+ S4 := c.s[3]
+
+ // Load input
+ ta := load32l(src[0:4])
+ tb := load32l(src[4:8])
+ tc := load32l(src[8:12])
+ td := load32l(src[12:16])
+
+ // Undo undo final swap
+ ia := tc ^ c.k[6]
+ ib := td ^ c.k[7]
+ ic := ta ^ c.k[4]
+ id := tb ^ c.k[5]
+
+ for i := 8; i > 0; i-- {
+ k := c.k[4+i*4 : 8+i*4]
+ t2 := S2[byte(id)] ^ S3[byte(id>>8)] ^ S4[byte(id>>16)] ^ S1[byte(id>>24)]
+ t1 := S1[byte(ic)] ^ S2[byte(ic>>8)] ^ S3[byte(ic>>16)] ^ S4[byte(ic>>24)] + t2
+ ia = rol(ia, 1) ^ (t1 + k[2])
+ ib = ror(ib^(t2+t1+k[3]), 1)
+
+ t2 = S2[byte(ib)] ^ S3[byte(ib>>8)] ^ S4[byte(ib>>16)] ^ S1[byte(ib>>24)]
+ t1 = S1[byte(ia)] ^ S2[byte(ia>>8)] ^ S3[byte(ia>>16)] ^ S4[byte(ia>>24)] + t2
+ ic = rol(ic, 1) ^ (t1 + k[0])
+ id = ror(id^(t2+t1+k[1]), 1)
+ }
+
+ // Undo pre-whitening
+ ia ^= c.k[0]
+ ib ^= c.k[1]
+ ic ^= c.k[2]
+ id ^= c.k[3]
+
+ store32l(dst[0:4], ia)
+ store32l(dst[4:8], ib)
+ store32l(dst[8:12], ic)
+ store32l(dst[12:16], id)
+}
diff --git a/vendor/golang.org/x/crypto/twofish/twofish_test.go b/vendor/golang.org/x/crypto/twofish/twofish_test.go
new file mode 100644
index 000000000..303081f3f
--- /dev/null
+++ b/vendor/golang.org/x/crypto/twofish/twofish_test.go
@@ -0,0 +1,129 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package twofish
+
+import (
+ "bytes"
+ "testing"
+)
+
+var qbox = [2][4][16]byte{
+ {
+ {0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4},
+ {0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD},
+ {0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1},
+ {0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA},
+ },
+ {
+ {0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5},
+ {0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8},
+ {0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF},
+ {0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA},
+ },
+}
+
+// genSbox generates the variable sbox
+func genSbox(qi int, x byte) byte {
+ a0, b0 := x/16, x%16
+ for i := 0; i < 2; i++ {
+ a1 := a0 ^ b0
+ b1 := (a0 ^ ((b0 << 3) | (b0 >> 1)) ^ (a0 << 3)) & 15
+ a0 = qbox[qi][2*i][a1]
+ b0 = qbox[qi][2*i+1][b1]
+ }
+ return (b0 << 4) + a0
+}
+
+func TestSbox(t *testing.T) {
+ for n := range sbox {
+ for m := range sbox[n] {
+ if genSbox(n, byte(m)) != sbox[n][m] {
+ t.Errorf("#%d|%d: sbox value = %d want %d", n, m, sbox[n][m], genSbox(n, byte(m)))
+ }
+ }
+ }
+}
+
+var testVectors = []struct {
+ key []byte
+ dec []byte
+ enc []byte
+}{
+ // These tests are extracted from LibTom
+ {
+ []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
+ []byte{0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19},
+ []byte{0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3},
+ },
+ {
+ []byte{0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88,
+ 0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44},
+ []byte{0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2},
+ []byte{0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65},
+ },
+ {
+ []byte{0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D,
+ 0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F},
+ []byte{0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6},
+ []byte{0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA},
+ },
+ // These test are derived from http://www.schneier.com/code/ecb_ival.txt
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ },
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xCF, 0xD1, 0xD2, 0xE5, 0xA9, 0xBE, 0x9C, 0xDF, 0x50, 0x1F, 0x13, 0xB8, 0x92, 0xBD, 0x22, 0x48},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ },
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x37, 0x52, 0x7B, 0xE0, 0x05, 0x23, 0x34, 0xB8, 0x9F, 0x0C, 0xFC, 0xCA, 0xE8, 0x7C, 0xFA, 0x20},
+ },
+}
+
+func TestCipher(t *testing.T) {
+ for n, tt := range testVectors {
+ // Test if the plaintext (dec) is encrypts to the given
+ // ciphertext (enc) using the given key. Test also if enc can
+ // be decrypted again into dec.
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("#%d: NewCipher: %v", n, err)
+ return
+ }
+
+ buf := make([]byte, 16)
+ c.Encrypt(buf, tt.dec)
+ if !bytes.Equal(buf, tt.enc) {
+ t.Errorf("#%d: encrypt = %x want %x", n, buf, tt.enc)
+ }
+ c.Decrypt(buf, tt.enc)
+ if !bytes.Equal(buf, tt.dec) {
+ t.Errorf("#%d: decrypt = %x want %x", n, buf, tt.dec)
+ }
+
+ // Test that 16 zero bytes, encrypted 1000 times then decrypted
+ // 1000 times results in zero bytes again.
+ zero := make([]byte, 16)
+ buf = make([]byte, 16)
+ for i := 0; i < 1000; i++ {
+ c.Encrypt(buf, buf)
+ }
+ for i := 0; i < 1000; i++ {
+ c.Decrypt(buf, buf)
+ }
+ if !bytes.Equal(buf, zero) {
+ t.Errorf("#%d: encrypt/decrypt 1000: have %x want %x", n, buf, zero)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/xtea/block.go b/vendor/golang.org/x/crypto/xtea/block.go
new file mode 100644
index 000000000..bf5d24599
--- /dev/null
+++ b/vendor/golang.org/x/crypto/xtea/block.go
@@ -0,0 +1,66 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+ Implementation adapted from Needham and Wheeler's paper:
+ http://www.cix.co.uk/~klockstone/xtea.pdf
+
+ A precalculated look up table is used during encryption/decryption for values that are based purely on the key.
+*/
+
+package xtea
+
+// XTEA is based on 64 rounds.
+const numRounds = 64
+
+// blockToUint32 reads an 8 byte slice into two uint32s.
+// The block is treated as big endian.
+func blockToUint32(src []byte) (uint32, uint32) {
+ r0 := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r1 := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+ return r0, r1
+}
+
+// uint32ToBlock writes two uint32s into an 8 byte data block.
+// Values are written as big endian.
+func uint32ToBlock(v0, v1 uint32, dst []byte) {
+ dst[0] = byte(v0 >> 24)
+ dst[1] = byte(v0 >> 16)
+ dst[2] = byte(v0 >> 8)
+ dst[3] = byte(v0)
+ dst[4] = byte(v1 >> 24)
+ dst[5] = byte(v1 >> 16)
+ dst[6] = byte(v1 >> 8)
+ dst[7] = byte(v1 >> 0)
+}
+
+// encryptBlock encrypts a single 8 byte block using XTEA.
+func encryptBlock(c *Cipher, dst, src []byte) {
+ v0, v1 := blockToUint32(src)
+
+ // Two rounds of XTEA applied per loop
+ for i := 0; i < numRounds; {
+ v0 += ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+ i++
+ v1 += ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+ i++
+ }
+
+ uint32ToBlock(v0, v1, dst)
+}
+
+// decryptBlock decrypt a single 8 byte block using XTEA.
+func decryptBlock(c *Cipher, dst, src []byte) {
+ v0, v1 := blockToUint32(src)
+
+ // Two rounds of XTEA applied per loop
+ for i := numRounds; i > 0; {
+ i--
+ v1 -= ((v0<<4 ^ v0>>5) + v0) ^ c.table[i]
+ i--
+ v0 -= ((v1<<4 ^ v1>>5) + v1) ^ c.table[i]
+ }
+
+ uint32ToBlock(v0, v1, dst)
+}
diff --git a/vendor/golang.org/x/crypto/xtea/cipher.go b/vendor/golang.org/x/crypto/xtea/cipher.go
new file mode 100644
index 000000000..108b42635
--- /dev/null
+++ b/vendor/golang.org/x/crypto/xtea/cipher.go
@@ -0,0 +1,82 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package xtea implements XTEA encryption, as defined in Needham and Wheeler's
+// 1997 technical report, "Tea extensions."
+package xtea // import "golang.org/x/crypto/xtea"
+
+// For details, see http://www.cix.co.uk/~klockstone/xtea.pdf
+
+import "strconv"
+
+// The XTEA block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of an XTEA cipher using a particular key.
+// table contains a series of precalculated values that are used each round.
+type Cipher struct {
+ table [64]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+ return "crypto/xtea: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher.
+// The key argument should be the XTEA key.
+// XTEA only supports 128 bit (16 byte) keys.
+func NewCipher(key []byte) (*Cipher, error) {
+ k := len(key)
+ switch k {
+ default:
+ return nil, KeySizeError(k)
+ case 16:
+ break
+ }
+
+ c := new(Cipher)
+ initCipher(c, key)
+
+ return c, nil
+}
+
+// BlockSize returns the XTEA block size, 8 bytes.
+// It is necessary to satisfy the Block interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8 byte buffer src using the key and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c, dst, src) }
+
+// Decrypt decrypts the 8 byte buffer src using the key k and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) { decryptBlock(c, dst, src) }
+
+// initCipher initializes the cipher context by creating a look up table
+// of precalculated values that are based on the key.
+func initCipher(c *Cipher, key []byte) {
+ // Load the key into four uint32s
+ var k [4]uint32
+ for i := 0; i < len(k); i++ {
+ j := i << 2 // Multiply by 4
+ k[i] = uint32(key[j+0])<<24 | uint32(key[j+1])<<16 | uint32(key[j+2])<<8 | uint32(key[j+3])
+ }
+
+ // Precalculate the table
+ const delta = 0x9E3779B9
+ var sum uint32 = 0
+
+ // Two rounds of XTEA applied per loop
+ for i := 0; i < numRounds; {
+ c.table[i] = sum + k[sum&3]
+ i++
+ sum += delta
+ c.table[i] = sum + k[(sum>>11)&3]
+ i++
+ }
+}
diff --git a/vendor/golang.org/x/crypto/xtea/xtea_test.go b/vendor/golang.org/x/crypto/xtea/xtea_test.go
new file mode 100644
index 000000000..be711bf5a
--- /dev/null
+++ b/vendor/golang.org/x/crypto/xtea/xtea_test.go
@@ -0,0 +1,229 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xtea
+
+import (
+ "testing"
+)
+
+// A sample test key for when we just want to initialize a cipher
+var testKey = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}
+
+// Test that the block size for XTEA is correct
+func TestBlocksize(t *testing.T) {
+ if BlockSize != 8 {
+ t.Errorf("BlockSize constant - expected 8, got %d", BlockSize)
+ return
+ }
+
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ result := c.BlockSize()
+ if result != 8 {
+ t.Errorf("BlockSize function - expected 8, got %d", result)
+ return
+ }
+}
+
+// A series of test values to confirm that the Cipher.table array was initialized correctly
+var testTable = []uint32{
+ 0x00112233, 0x6B1568B8, 0xE28CE030, 0xC5089E2D, 0xC5089E2D, 0x1EFBD3A2, 0xA7845C2A, 0x78EF0917,
+ 0x78EF0917, 0x172682D0, 0x5B6AC714, 0x822AC955, 0x3DE68511, 0xDC1DFECA, 0x2062430E, 0x3611343F,
+ 0xF1CCEFFB, 0x900469B4, 0xD448ADF8, 0x2E3BE36D, 0xB6C46BF5, 0x994029F2, 0x994029F2, 0xF3335F67,
+ 0x6AAAD6DF, 0x4D2694DC, 0x4D2694DC, 0xEB5E0E95, 0x2FA252D9, 0x4551440A, 0x121E10D6, 0xB0558A8F,
+ 0xE388BDC3, 0x0A48C004, 0xC6047BC0, 0x643BF579, 0xA88039BD, 0x02736F32, 0x8AFBF7BA, 0x5C66A4A7,
+ 0x5C66A4A7, 0xC76AEB2C, 0x3EE262A4, 0x215E20A1, 0x215E20A1, 0x7B515616, 0x03D9DE9E, 0x1988CFCF,
+ 0xD5448B8B, 0x737C0544, 0xB7C04988, 0xDE804BC9, 0x9A3C0785, 0x3873813E, 0x7CB7C582, 0xD6AAFAF7,
+ 0x4E22726F, 0x309E306C, 0x309E306C, 0x8A9165E1, 0x1319EE69, 0xF595AC66, 0xF595AC66, 0x4F88E1DB,
+}
+
+// Test that the cipher context is initialized correctly
+func TestCipherInit(t *testing.T) {
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ for i := 0; i < len(c.table); i++ {
+ if c.table[i] != testTable[i] {
+ t.Errorf("NewCipher() failed to initialize Cipher.table[%d] correctly. Expected %08X, got %08X", i, testTable[i], c.table[i])
+ break
+ }
+ }
+}
+
+// Test that invalid key sizes return an error
+func TestInvalidKeySize(t *testing.T) {
+ // Test a long key
+ key := []byte{
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ }
+
+ _, err := NewCipher(key)
+ if err == nil {
+ t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+ }
+
+ // Test a short key
+ key = []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}
+
+ _, err = NewCipher(key)
+ if err == nil {
+ t.Errorf("Invalid key size %d didn't result in an error.", len(key))
+ }
+}
+
+// Test that we can correctly decode some bytes we have encoded
+func TestEncodeDecode(t *testing.T) {
+ original := []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}
+ input := original
+ output := make([]byte, BlockSize)
+
+ c, err := NewCipher(testKey)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(testKey), err)
+ return
+ }
+
+ // Encrypt the input block
+ c.Encrypt(output, input)
+
+ // Check that the output does not match the input
+ differs := false
+ for i := 0; i < len(input); i++ {
+ if output[i] != input[i] {
+ differs = true
+ break
+ }
+ }
+ if differs == false {
+ t.Error("Cipher.Encrypt: Failed to encrypt the input block.")
+ return
+ }
+
+ // Decrypt the block we just encrypted
+ input = output
+ output = make([]byte, BlockSize)
+ c.Decrypt(output, input)
+
+ // Check that the output from decrypt matches our initial input
+ for i := 0; i < len(input); i++ {
+ if output[i] != original[i] {
+ t.Errorf("Decrypted byte %d differed. Expected %02X, got %02X\n", i, original[i], output[i])
+ return
+ }
+ }
+}
+
+// Test Vectors
+type CryptTest struct {
+ key []byte
+ plainText []byte
+ cipherText []byte
+}
+
+var CryptTests = []CryptTest{
+ // These were sourced from http://www.freemedialibrary.com/index.php/XTEA_test_vectors
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5},
+ },
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ []byte{0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8},
+ },
+ {
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ []byte{0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55},
+ []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41},
+ },
+
+ // These vectors are from http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation#Bouncy_Castle_C.23_API
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xDE, 0xE9, 0xD4, 0xD8, 0xF7, 0x13, 0x1E, 0xD9},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+ []byte{0x06, 0x5C, 0x1B, 0x89, 0x75, 0xC6, 0xA8, 0x16},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x1F, 0xF9, 0xA0, 0x26, 0x1A, 0xC6, 0x42, 0x64},
+ },
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78, 0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A},
+ []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
+ []byte{0x8C, 0x67, 0x15, 0x5B, 0x2E, 0xF9, 0x1E, 0xAD},
+ },
+}
+
+// Test encryption
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range CryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+ continue
+ }
+
+ out := make([]byte, len(tt.plainText))
+ c.Encrypt(out, tt.plainText)
+
+ for j := 0; j < len(out); j++ {
+ if out[j] != tt.cipherText[j] {
+ t.Errorf("Cipher.Encrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.cipherText[j])
+ break
+ }
+ }
+ }
+}
+
+// Test decryption
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range CryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes), vector %d = %s", len(tt.key), i, err)
+ continue
+ }
+
+ out := make([]byte, len(tt.cipherText))
+ c.Decrypt(out, tt.cipherText)
+
+ for j := 0; j < len(out); j++ {
+ if out[j] != tt.plainText[j] {
+ t.Errorf("Cipher.Decrypt %d: out[%d] = %02X, expected %02X", i, j, out[j], tt.plainText[j])
+ break
+ }
+ }
+ }
+}
diff --git a/vendor/golang.org/x/crypto/xts/xts.go b/vendor/golang.org/x/crypto/xts/xts.go
new file mode 100644
index 000000000..c9a283b2e
--- /dev/null
+++ b/vendor/golang.org/x/crypto/xts/xts.go
@@ -0,0 +1,138 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package xts implements the XTS cipher mode as specified in IEEE P1619/D16.
+//
+// XTS mode is typically used for disk encryption, which presents a number of
+// novel problems that make more common modes inapplicable. The disk is
+// conceptually an array of sectors and we must be able to encrypt and decrypt
+// a sector in isolation. However, an attacker must not be able to transpose
+// two sectors of plaintext by transposing their ciphertext.
+//
+// XTS wraps a block cipher with Rogaway's XEX mode in order to build a
+// tweakable block cipher. This allows each sector to have a unique tweak and
+// effectively create a unique key for each sector.
+//
+// XTS does not provide any authentication. An attacker can manipulate the
+// ciphertext and randomise a block (16 bytes) of the plaintext.
+//
+// (Note: this package does not implement ciphertext-stealing so sectors must
+// be a multiple of 16 bytes.)
+package xts // import "golang.org/x/crypto/xts"
+
+import (
+ "crypto/cipher"
+ "errors"
+)
+
+// Cipher contains an expanded key structure. It doesn't contain mutable state
+// and therefore can be used concurrently.
+type Cipher struct {
+ k1, k2 cipher.Block
+}
+
+// blockSize is the block size that the underlying cipher must have. XTS is
+// only defined for 16-byte ciphers.
+const blockSize = 16
+
+// NewCipher creates a Cipher given a function for creating the underlying
+// block cipher (which must have a block size of 16 bytes). The key must be
+// twice the length of the underlying cipher's key.
+func NewCipher(cipherFunc func([]byte) (cipher.Block, error), key []byte) (c *Cipher, err error) {
+ c = new(Cipher)
+ if c.k1, err = cipherFunc(key[:len(key)/2]); err != nil {
+ return
+ }
+ c.k2, err = cipherFunc(key[len(key)/2:])
+
+ if c.k1.BlockSize() != blockSize {
+ err = errors.New("xts: cipher does not have a block size of 16")
+ }
+
+ return
+}
+
+// Encrypt encrypts a sector of plaintext and puts the result into ciphertext.
+// Plaintext and ciphertext may be the same slice but should not overlap.
+// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
+func (c *Cipher) Encrypt(ciphertext, plaintext []byte, sectorNum uint64) {
+ if len(ciphertext) < len(plaintext) {
+ panic("xts: ciphertext is smaller than plaintext")
+ }
+ if len(plaintext)%blockSize != 0 {
+ panic("xts: plaintext is not a multiple of the block size")
+ }
+
+ var tweak [blockSize]byte
+ for i := 0; i < 8; i++ {
+ tweak[i] = byte(sectorNum)
+ sectorNum >>= 8
+ }
+
+ c.k2.Encrypt(tweak[:], tweak[:])
+
+ for i := 0; i < len(plaintext); i += blockSize {
+ for j := 0; j < blockSize; j++ {
+ ciphertext[i+j] = plaintext[i+j] ^ tweak[j]
+ }
+ c.k1.Encrypt(ciphertext[i:], ciphertext[i:])
+ for j := 0; j < blockSize; j++ {
+ ciphertext[i+j] ^= tweak[j]
+ }
+
+ mul2(&tweak)
+ }
+}
+
+// Decrypt decrypts a sector of ciphertext and puts the result into plaintext.
+// Plaintext and ciphertext may be the same slice but should not overlap.
+// Sectors must be a multiple of 16 bytes and less than 2²⁴ bytes.
+func (c *Cipher) Decrypt(plaintext, ciphertext []byte, sectorNum uint64) {
+ if len(plaintext) < len(ciphertext) {
+ panic("xts: plaintext is smaller than ciphertext")
+ }
+ if len(ciphertext)%blockSize != 0 {
+ panic("xts: ciphertext is not a multiple of the block size")
+ }
+
+ var tweak [blockSize]byte
+ for i := 0; i < 8; i++ {
+ tweak[i] = byte(sectorNum)
+ sectorNum >>= 8
+ }
+
+ c.k2.Encrypt(tweak[:], tweak[:])
+
+ for i := 0; i < len(plaintext); i += blockSize {
+ for j := 0; j < blockSize; j++ {
+ plaintext[i+j] = ciphertext[i+j] ^ tweak[j]
+ }
+ c.k1.Decrypt(plaintext[i:], plaintext[i:])
+ for j := 0; j < blockSize; j++ {
+ plaintext[i+j] ^= tweak[j]
+ }
+
+ mul2(&tweak)
+ }
+}
+
+// mul2 multiplies tweak by 2 in GF(2¹²⁸) with an irreducible polynomial of
+// x¹²⁸ + x⁷ + x² + x + 1.
+func mul2(tweak *[blockSize]byte) {
+ var carryIn byte
+ for j := range tweak {
+ carryOut := tweak[j] >> 7
+ tweak[j] = (tweak[j] << 1) + carryIn
+ carryIn = carryOut
+ }
+ if carryIn != 0 {
+ // If we have a carry bit then we need to subtract a multiple
+ // of the irreducible polynomial (x¹²⁸ + x⁷ + x² + x + 1).
+ // By dropping the carry bit, we're subtracting the x^128 term
+ // so all that remains is to subtract x⁷ + x² + x + 1.
+ // Subtraction (and addition) in this representation is just
+ // XOR.
+ tweak[0] ^= 1<<7 | 1<<2 | 1<<1 | 1
+ }
+}
diff --git a/vendor/golang.org/x/crypto/xts/xts_test.go b/vendor/golang.org/x/crypto/xts/xts_test.go
new file mode 100644
index 000000000..7a5e9fadd
--- /dev/null
+++ b/vendor/golang.org/x/crypto/xts/xts_test.go
@@ -0,0 +1,85 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xts
+
+import (
+ "bytes"
+ "crypto/aes"
+ "encoding/hex"
+ "testing"
+)
+
+// These test vectors have been taken from IEEE P1619/D16, Annex B.
+var xtsTestVectors = []struct {
+ key string
+ sector uint64
+ plaintext string
+ ciphertext string
+}{
+ {
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 0,
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "917cf69ebd68b2ec9b9fe9a3eadda692cd43d2f59598ed858c02c2652fbf922e",
+ }, {
+ "1111111111111111111111111111111122222222222222222222222222222222",
+ 0x3333333333,
+ "4444444444444444444444444444444444444444444444444444444444444444",
+ "c454185e6a16936e39334038acef838bfb186fff7480adc4289382ecd6d394f0",
+ }, {
+ "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f022222222222222222222222222222222",
+ 0x3333333333,
+ "4444444444444444444444444444444444444444444444444444444444444444",
+ "af85336b597afc1a900b2eb21ec949d292df4c047e0b21532186a5971a227a89",
+ }, {
+ "2718281828459045235360287471352631415926535897932384626433832795",
+ 0,
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568",
+ }, {
+ "2718281828459045235360287471352631415926535897932384626433832795",
+ 1,
+ "27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89cc78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad02655ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f4341332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203ebb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18deb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568",
+ "264d3ca8512194fec312c8c9891f279fefdd608d0c027b60483a3fa811d65ee59d52d9e40ec5672d81532b38b6b089ce951f0f9c35590b8b978d175213f329bb1c2fd30f2f7f30492a61a532a79f51d36f5e31a7c9a12c286082ff7d2394d18f783e1a8e72c722caaaa52d8f065657d2631fd25bfd8e5baad6e527d763517501c68c5edc3cdd55435c532d7125c8614deed9adaa3acade5888b87bef641c4c994c8091b5bcd387f3963fb5bc37aa922fbfe3df4e5b915e6eb514717bdd2a74079a5073f5c4bfd46adf7d282e7a393a52579d11a028da4d9cd9c77124f9648ee383b1ac763930e7162a8d37f350b2f74b8472cf09902063c6b32e8c2d9290cefbd7346d1c779a0df50edcde4531da07b099c638e83a755944df2aef1aa31752fd323dcb710fb4bfbb9d22b925bc3577e1b8949e729a90bbafeacf7f7879e7b1147e28ba0bae940db795a61b15ecf4df8db07b824bb062802cc98a9545bb2aaeed77cb3fc6db15dcd7d80d7d5bc406c4970a3478ada8899b329198eb61c193fb6275aa8ca340344a75a862aebe92eee1ce032fd950b47d7704a3876923b4ad62844bf4a09c4dbe8b4397184b7471360c9564880aedddb9baa4af2e75394b08cd32ff479c57a07d3eab5d54de5f9738b8d27f27a9f0ab11799d7b7ffefb2704c95c6ad12c39f1e867a4b7b1d7818a4b753dfd2a89ccb45e001a03a867b187f225dd",
+ }, {
+ "27182818284590452353602874713526624977572470936999595749669676273141592653589793238462643383279502884197169399375105820974944592",
+ 0xff,
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "1c3b3a102f770386e4836c99e370cf9bea00803f5e482357a4ae12d414a3e63b5d31e276f8fe4a8d66b317f9ac683f44680a86ac35adfc3345befecb4bb188fd5776926c49a3095eb108fd1098baec70aaa66999a72a82f27d848b21d4a741b0c5cd4d5fff9dac89aeba122961d03a757123e9870f8acf1000020887891429ca2a3e7a7d7df7b10355165c8b9a6d0a7de8b062c4500dc4cd120c0f7418dae3d0b5781c34803fa75421c790dfe1de1834f280d7667b327f6c8cd7557e12ac3a0f93ec05c52e0493ef31a12d3d9260f79a289d6a379bc70c50841473d1a8cc81ec583e9645e07b8d9670655ba5bbcfecc6dc3966380ad8fecb17b6ba02469a020a84e18e8f84252070c13e9f1f289be54fbc481457778f616015e1327a02b140f1505eb309326d68378f8374595c849d84f4c333ec4423885143cb47bd71c5edae9be69a2ffeceb1bec9de244fbe15992b11b77c040f12bd8f6a975a44a0f90c29a9abc3d4d893927284c58754cce294529f8614dcd2aba991925fedc4ae74ffac6e333b93eb4aff0479da9a410e4450e0dd7ae4c6e2910900575da401fc07059f645e8b7e9bfdef33943054ff84011493c27b3429eaedb4ed5376441a77ed43851ad77f16f541dfd269d50d6a5f14fb0aab1cbb4c1550be97f7ab4066193c4caa773dad38014bd2092fa755c824bb5e54c4f36ffda9fcea70b9c6e693e148c151",
+ },
+}
+
+func fromHex(s string) []byte {
+ ret, err := hex.DecodeString(s)
+ if err != nil {
+ panic("xts: invalid hex in test")
+ }
+ return ret
+}
+
+func TestXTS(t *testing.T) {
+ for i, test := range xtsTestVectors {
+ c, err := NewCipher(aes.NewCipher, fromHex(test.key))
+ if err != nil {
+ t.Errorf("#%d: failed to create cipher: %s", i, err)
+ continue
+ }
+ plaintext := fromHex(test.plaintext)
+ ciphertext := make([]byte, len(plaintext))
+ c.Encrypt(ciphertext, plaintext, test.sector)
+
+ expectedCiphertext := fromHex(test.ciphertext)
+ if !bytes.Equal(ciphertext, expectedCiphertext) {
+ t.Errorf("#%d: encrypted failed, got: %x, want: %x", i, ciphertext, expectedCiphertext)
+ continue
+ }
+
+ decrypted := make([]byte, len(ciphertext))
+ c.Decrypt(decrypted, ciphertext, test.sector)
+ if !bytes.Equal(decrypted, plaintext) {
+ t.Errorf("#%d: decryption failed, got: %x, want: %x", i, decrypted, plaintext)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/.gitattributes b/vendor/golang.org/x/image/.gitattributes
new file mode 100644
index 000000000..d2f212e5d
--- /dev/null
+++ b/vendor/golang.org/x/image/.gitattributes
@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text
diff --git a/vendor/golang.org/x/image/.gitignore b/vendor/golang.org/x/image/.gitignore
new file mode 100644
index 000000000..8339fd61d
--- /dev/null
+++ b/vendor/golang.org/x/image/.gitignore
@@ -0,0 +1,2 @@
+# Add no patterns to .hgignore except for files generated by the build.
+last-change
diff --git a/vendor/golang.org/x/image/AUTHORS b/vendor/golang.org/x/image/AUTHORS
new file mode 100644
index 000000000..15167cd74
--- /dev/null
+++ b/vendor/golang.org/x/image/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/vendor/golang.org/x/image/CONTRIBUTING.md b/vendor/golang.org/x/image/CONTRIBUTING.md
new file mode 100644
index 000000000..88dff59bc
--- /dev/null
+++ b/vendor/golang.org/x/image/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+
+## Filing issues
+
+When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
+
+1. What version of Go are you using (`go version`)?
+2. What operating system and processor architecture are you using?
+3. What did you do?
+4. What did you expect to see?
+5. What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+**We do not accept GitHub pull requests**
+(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.
+
diff --git a/vendor/golang.org/x/image/CONTRIBUTORS b/vendor/golang.org/x/image/CONTRIBUTORS
new file mode 100644
index 000000000..1c4577e96
--- /dev/null
+++ b/vendor/golang.org/x/image/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/vendor/golang.org/x/image/README b/vendor/golang.org/x/image/README
new file mode 100644
index 000000000..462038079
--- /dev/null
+++ b/vendor/golang.org/x/image/README
@@ -0,0 +1,3 @@
+This repository holds supplementary Go image libraries.
+
+To submit changes to this repository, see http://golang.org/doc/contribute.html.
diff --git a/vendor/golang.org/x/image/bmp/reader.go b/vendor/golang.org/x/image/bmp/reader.go
index a48cba84d..a0f2715cd 100644
--- a/vendor/golang.org/x/image/bmp/reader.go
+++ b/vendor/golang.org/x/image/bmp/reader.go
@@ -5,7 +5,7 @@
// Package bmp implements a BMP image decoder and encoder.
//
// The BMP specification is at http://www.digicamsoft.com/bmp/bmp.html.
-package bmp
+package bmp // import "golang.org/x/image/bmp"
import (
"errors"
diff --git a/vendor/golang.org/x/image/bmp/reader_test.go b/vendor/golang.org/x/image/bmp/reader_test.go
new file mode 100644
index 000000000..fd6ff64f6
--- /dev/null
+++ b/vendor/golang.org/x/image/bmp/reader_test.go
@@ -0,0 +1,75 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bmp
+
+import (
+ "fmt"
+ "image"
+ "os"
+ "testing"
+
+ _ "image/png"
+)
+
+const testdataDir = "../testdata/"
+
+func compare(t *testing.T, img0, img1 image.Image) error {
+ b := img1.Bounds()
+ if !b.Eq(img0.Bounds()) {
+ return fmt.Errorf("wrong image size: want %s, got %s", img0.Bounds(), b)
+ }
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c0 := img0.At(x, y)
+ c1 := img1.At(x, y)
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.RGBA()
+ if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
+ return fmt.Errorf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1)
+ }
+ }
+ }
+ return nil
+}
+
+// TestDecode tests that decoding a PNG image and a BMP image result in the
+// same pixel data.
+func TestDecode(t *testing.T) {
+ testCases := []string{
+ "video-001",
+ "yellow_rose-small",
+ }
+
+ for _, tc := range testCases {
+ f0, err := os.Open(testdataDir + tc + ".png")
+ if err != nil {
+ t.Errorf("%s: Open PNG: %v", tc, err)
+ continue
+ }
+ defer f0.Close()
+ img0, _, err := image.Decode(f0)
+ if err != nil {
+ t.Errorf("%s: Decode PNG: %v", tc, err)
+ continue
+ }
+
+ f1, err := os.Open(testdataDir + tc + ".bmp")
+ if err != nil {
+ t.Errorf("%s: Open BMP: %v", tc, err)
+ continue
+ }
+ defer f1.Close()
+ img1, _, err := image.Decode(f1)
+ if err != nil {
+ t.Errorf("%s: Decode BMP: %v", tc, err)
+ continue
+ }
+
+ if err := compare(t, img0, img1); err != nil {
+ t.Errorf("%s: %v", tc, err)
+ continue
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/bmp/writer_test.go b/vendor/golang.org/x/image/bmp/writer_test.go
new file mode 100644
index 000000000..9e5a32741
--- /dev/null
+++ b/vendor/golang.org/x/image/bmp/writer_test.go
@@ -0,0 +1,91 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bmp
+
+import (
+ "bytes"
+ "fmt"
+ "image"
+ "io/ioutil"
+ "os"
+ "testing"
+ "time"
+)
+
+func openImage(filename string) (image.Image, error) {
+ f, err := os.Open(testdataDir + filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return Decode(f)
+}
+
+func TestEncode(t *testing.T) {
+ img0, err := openImage("video-001.bmp")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ buf := new(bytes.Buffer)
+ err = Encode(buf, img0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ img1, err := Decode(buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ compare(t, img0, img1)
+}
+
+// TestZeroWidthVeryLargeHeight tests that encoding and decoding a degenerate
+// image with zero width but over one billion pixels in height is faster than
+// naively calling an io.Reader or io.Writer method once per row.
+func TestZeroWidthVeryLargeHeight(t *testing.T) {
+ c := make(chan error, 1)
+ go func() {
+ b := image.Rect(0, 0, 0, 0x3fffffff)
+ var buf bytes.Buffer
+ if err := Encode(&buf, image.NewRGBA(b)); err != nil {
+ c <- err
+ return
+ }
+ m, err := Decode(&buf)
+ if err != nil {
+ c <- err
+ return
+ }
+ if got := m.Bounds(); got != b {
+ c <- fmt.Errorf("bounds: got %v, want %v", got, b)
+ return
+ }
+ c <- nil
+ }()
+ select {
+ case err := <-c:
+ if err != nil {
+ t.Fatal(err)
+ }
+ case <-time.After(3 * time.Second):
+ t.Fatalf("timed out")
+ }
+}
+
+// BenchmarkEncode benchmarks the encoding of an image.
+func BenchmarkEncode(b *testing.B) {
+ img, err := openImage("video-001.bmp")
+ if err != nil {
+ b.Fatal(err)
+ }
+ s := img.Bounds().Size()
+ b.SetBytes(int64(s.X * s.Y * 4))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img)
+ }
+}
diff --git a/vendor/golang.org/x/image/cmd/webp-manual-test/main.go b/vendor/golang.org/x/image/cmd/webp-manual-test/main.go
new file mode 100644
index 000000000..acb2815eb
--- /dev/null
+++ b/vendor/golang.org/x/image/cmd/webp-manual-test/main.go
@@ -0,0 +1,215 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+//
+// This build tag means that "go install golang.org/x/image/..." doesn't
+// install this manual test. Use "go run main.go" to explicitly run it.
+
+// Program webp-manual-test checks that the Go WEBP library's decodings match
+// the C WEBP library's.
+package main // import "golang.org/x/image/cmd/webp-manual-test"
+
+import (
+ "bytes"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "image"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "golang.org/x/image/webp"
+)
+
+var (
+ dwebp = flag.String("dwebp", "/usr/bin/dwebp", "path to the dwebp program "+
+ "installed from https://developers.google.com/speed/webp/download")
+ testdata = flag.String("testdata", "", "path to the libwebp-test-data directory "+
+ "checked out from https://chromium.googlesource.com/webm/libwebp-test-data")
+)
+
+func main() {
+ flag.Parse()
+ if err := checkDwebp(); err != nil {
+ flag.Usage()
+ log.Fatal(err)
+ }
+ if *testdata == "" {
+ flag.Usage()
+ log.Fatal("testdata flag was not specified")
+ }
+
+ f, err := os.Open(*testdata)
+ if err != nil {
+ log.Fatalf("Open: %v", err)
+ }
+ defer f.Close()
+ names, err := f.Readdirnames(-1)
+ if err != nil {
+ log.Fatalf("Readdirnames: %v", err)
+ }
+ sort.Strings(names)
+
+ nFail, nPass := 0, 0
+ for _, name := range names {
+ if !strings.HasSuffix(name, "webp") {
+ continue
+ }
+ if err := test(name); err != nil {
+ fmt.Printf("FAIL\t%s\t%v\n", name, err)
+ nFail++
+ } else {
+ fmt.Printf("PASS\t%s\n", name)
+ nPass++
+ }
+ }
+ fmt.Printf("%d PASS, %d FAIL, %d TOTAL\n", nPass, nFail, nPass+nFail)
+ if nFail != 0 {
+ os.Exit(1)
+ }
+}
+
+func checkDwebp() error {
+ if *dwebp == "" {
+ return fmt.Errorf("dwebp flag was not specified")
+ }
+ if _, err := os.Stat(*dwebp); err != nil {
+ return fmt.Errorf("could not find dwebp program at %q", *dwebp)
+ }
+ b, err := exec.Command(*dwebp, "-version").Output()
+ if err != nil {
+ return fmt.Errorf("could not determine the dwebp program version for %q: %v", *dwebp, err)
+ }
+ switch s := string(bytes.TrimSpace(b)); s {
+ case "0.4.0", "0.4.1", "0.4.2":
+ return fmt.Errorf("the dwebp program version %q for %q has a known bug "+
+ "(https://bugs.chromium.org/p/webp/issues/detail?id=239). Please use a newer version.", s, *dwebp)
+ }
+ return nil
+}
+
+// test tests a single WEBP image.
+func test(name string) error {
+ filename := filepath.Join(*testdata, name)
+ f, err := os.Open(filename)
+ if err != nil {
+ return fmt.Errorf("Open: %v", err)
+ }
+ defer f.Close()
+
+ gotImage, err := webp.Decode(f)
+ if err != nil {
+ return fmt.Errorf("Decode: %v", err)
+ }
+ format, encode := "-pgm", encodePGM
+ if _, lossless := gotImage.(*image.NRGBA); lossless {
+ format, encode = "-pam", encodePAM
+ }
+ got, err := encode(gotImage)
+ if err != nil {
+ return fmt.Errorf("encode: %v", err)
+ }
+
+ stdout := new(bytes.Buffer)
+ stderr := new(bytes.Buffer)
+ c := exec.Command(*dwebp, filename, format, "-o", "/dev/stdout")
+ c.Stdout = stdout
+ c.Stderr = stderr
+ if err := c.Run(); err != nil {
+ os.Stderr.Write(stderr.Bytes())
+ return fmt.Errorf("executing dwebp: %v", err)
+ }
+ want := stdout.Bytes()
+
+ if len(got) != len(want) {
+ return fmt.Errorf("encodings have different length: got %d, want %d", len(got), len(want))
+ }
+ for i, g := range got {
+ if w := want[i]; g != w {
+ return fmt.Errorf("encodings differ at position 0x%x: got 0x%02x, want 0x%02x", i, g, w)
+ }
+ }
+ return nil
+}
+
+// encodePAM encodes gotImage in the PAM format.
+func encodePAM(gotImage image.Image) ([]byte, error) {
+ m, ok := gotImage.(*image.NRGBA)
+ if !ok {
+ return nil, fmt.Errorf("lossless image did not decode to an *image.NRGBA")
+ }
+ b := m.Bounds()
+ w, h := b.Dx(), b.Dy()
+ buf := new(bytes.Buffer)
+ fmt.Fprintf(buf, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE RGB_ALPHA\nENDHDR\n", w, h)
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ o := m.PixOffset(b.Min.X, y)
+ buf.Write(m.Pix[o : o+4*w])
+ }
+ return buf.Bytes(), nil
+}
+
+// encodePGM encodes gotImage in the PGM format in the IMC4 layout.
+func encodePGM(gotImage image.Image) ([]byte, error) {
+ var (
+ m *image.YCbCr
+ ma *image.NYCbCrA
+ )
+ switch g := gotImage.(type) {
+ case *image.YCbCr:
+ m = g
+ case *image.NYCbCrA:
+ m = &g.YCbCr
+ ma = g
+ default:
+ return nil, fmt.Errorf("lossy image did not decode to an *image.YCbCr")
+ }
+ if m.SubsampleRatio != image.YCbCrSubsampleRatio420 {
+ return nil, fmt.Errorf("lossy image did not decode to a 4:2:0 YCbCr")
+ }
+ b := m.Bounds()
+ w, h := b.Dx(), b.Dy()
+ w2, h2 := (w+1)/2, (h+1)/2
+ outW, outH := 2*w2, h+h2
+ if ma != nil {
+ outH += h
+ }
+ buf := new(bytes.Buffer)
+ fmt.Fprintf(buf, "P5\n%d %d\n255\n", outW, outH)
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ o := m.YOffset(b.Min.X, y)
+ buf.Write(m.Y[o : o+w])
+ if w&1 != 0 {
+ buf.WriteByte(0x00)
+ }
+ }
+ for y := b.Min.Y; y < b.Max.Y; y += 2 {
+ o := m.COffset(b.Min.X, y)
+ buf.Write(m.Cb[o : o+w2])
+ buf.Write(m.Cr[o : o+w2])
+ }
+ if ma != nil {
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ o := ma.AOffset(b.Min.X, y)
+ buf.Write(ma.A[o : o+w])
+ if w&1 != 0 {
+ buf.WriteByte(0x00)
+ }
+ }
+ }
+ return buf.Bytes(), nil
+}
+
+// dump can be useful for debugging.
+func dump(w io.Writer, b []byte) {
+ h := hex.Dumper(w)
+ h.Write(b)
+ h.Close()
+}
diff --git a/vendor/golang.org/x/image/codereview.cfg b/vendor/golang.org/x/image/codereview.cfg
new file mode 100644
index 000000000..3f8b14b64
--- /dev/null
+++ b/vendor/golang.org/x/image/codereview.cfg
@@ -0,0 +1 @@
+issuerepo: golang/go
diff --git a/vendor/golang.org/x/image/colornames/colornames.go b/vendor/golang.org/x/image/colornames/colornames.go
new file mode 100644
index 000000000..fa94d426a
--- /dev/null
+++ b/vendor/golang.org/x/image/colornames/colornames.go
@@ -0,0 +1,10 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go
+
+// Package colornames provides named colors as defined in the SVG 1.1 spec.
+//
+// See http://www.w3.org/TR/SVG/types.html#ColorKeywords
+package colornames
diff --git a/vendor/golang.org/x/image/colornames/colornames_test.go b/vendor/golang.org/x/image/colornames/colornames_test.go
new file mode 100644
index 000000000..5251bb816
--- /dev/null
+++ b/vendor/golang.org/x/image/colornames/colornames_test.go
@@ -0,0 +1,42 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package colornames
+
+import (
+ "image/color"
+ "testing"
+)
+
+func TestColornames(t *testing.T) {
+ if len(Map) != len(Names) {
+ t.Fatalf("Map and Names have different length: %d vs %d", len(Map), len(Names))
+ }
+
+ for name, want := range testCases {
+ got, ok := Map[name]
+ if !ok {
+ t.Errorf("Did not find %s", name)
+ continue
+ }
+ if got != want {
+ t.Errorf("%s:\ngot %v\nwant %v", name, got, want)
+ }
+ }
+}
+
+var testCases = map[string]color.RGBA{
+ "aliceblue": color.RGBA{240, 248, 255, 255},
+ "crimson": color.RGBA{220, 20, 60, 255},
+ "darkorange": color.RGBA{255, 140, 0, 255},
+ "deepskyblue": color.RGBA{0, 191, 255, 255},
+ "greenyellow": color.RGBA{173, 255, 47, 255},
+ "lightgrey": color.RGBA{211, 211, 211, 255},
+ "lightpink": color.RGBA{255, 182, 193, 255},
+ "mediumseagreen": color.RGBA{60, 179, 113, 255},
+ "olivedrab": color.RGBA{107, 142, 35, 255},
+ "purple": color.RGBA{128, 0, 128, 255},
+ "slategrey": color.RGBA{112, 128, 144, 255},
+ "yellowgreen": color.RGBA{154, 205, 50, 255},
+}
diff --git a/vendor/golang.org/x/image/colornames/gen.go b/vendor/golang.org/x/image/colornames/gen.go
new file mode 100644
index 000000000..c03404cd7
--- /dev/null
+++ b/vendor/golang.org/x/image/colornames/gen.go
@@ -0,0 +1,187 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This program generates table.go from
+// http://www.w3.org/TR/SVG/types.html#ColorKeywords
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "image/color"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+
+ "golang.org/x/net/html"
+ "golang.org/x/net/html/atom"
+)
+
+// matchFunc matches HTML nodes.
+type matchFunc func(*html.Node) bool
+
+// appendAll recursively traverses the parse tree rooted under the provided
+// node and appends all nodes matched by the matchFunc to dst.
+func appendAll(dst []*html.Node, n *html.Node, mf matchFunc) []*html.Node {
+ if mf(n) {
+ dst = append(dst, n)
+ }
+ for c := n.FirstChild; c != nil; c = c.NextSibling {
+ dst = appendAll(dst, c, mf)
+ }
+ return dst
+}
+
+// matchAtom returns a matchFunc that matches a Node with the specified Atom.
+func matchAtom(a atom.Atom) matchFunc {
+ return func(n *html.Node) bool {
+ return n.DataAtom == a
+ }
+}
+
+// matchAtomAttr returns a matchFunc that matches a Node with the specified
+// Atom and a html.Attribute's namespace, key and value.
+func matchAtomAttr(a atom.Atom, namespace, key, value string) matchFunc {
+ return func(n *html.Node) bool {
+ return n.DataAtom == a && getAttr(n, namespace, key) == value
+ }
+}
+
+// getAttr fetches the value of a html.Attribute for a given namespace and key.
+func getAttr(n *html.Node, namespace, key string) string {
+ for _, attr := range n.Attr {
+ if attr.Namespace == namespace && attr.Key == key {
+ return attr.Val
+ }
+ }
+ return ""
+}
+
+// re extracts RGB values from strings like "rgb( 0, 223, 128)".
+var re = regexp.MustCompile(`rgb\(\s*([0-9]+),\s*([0-9]+),\s*([0-9]+)\)`)
+
+// parseRGB parses a color from a string like "rgb( 0, 233, 128)". It sets
+// the alpha value of the color to full opacity.
+func parseRGB(s string) (color.RGBA, error) {
+ m := re.FindStringSubmatch(s)
+ if m == nil {
+ return color.RGBA{}, fmt.Errorf("malformed color: %q", s)
+ }
+ var rgb [3]uint8
+ for i, t := range m[1:] {
+ num, err := strconv.ParseUint(t, 10, 8)
+ if err != nil {
+ return color.RGBA{}, fmt.Errorf("malformed value %q in %q: %s", t, s, err)
+ }
+ rgb[i] = uint8(num)
+ }
+ return color.RGBA{rgb[0], rgb[1], rgb[2], 0xFF}, nil
+}
+
+// extractSVGColors extracts named colors from the parse tree of the SVG 1.1
+// spec HTML document "Chapter 4: Basic data types and interfaces".
+func extractSVGColors(tree *html.Node) (map[string]color.RGBA, error) {
+ ret := make(map[string]color.RGBA)
+
+ // Find the tables which store the color keywords in the parse tree.
+ colorTables := appendAll(nil, tree, func(n *html.Node) bool {
+ return n.DataAtom == atom.Table && strings.Contains(getAttr(n, "", "summary"), "color keywords part")
+ })
+
+ for _, table := range colorTables {
+ // Color names and values are stored in TextNodes within spans in each row.
+ for _, tr := range appendAll(nil, table, matchAtom(atom.Tr)) {
+ nameSpan := appendAll(nil, tr, matchAtomAttr(atom.Span, "", "class", "prop-value"))
+ valueSpan := appendAll(nil, tr, matchAtomAttr(atom.Span, "", "class", "color-keyword-value"))
+
+ // Since SVG 1.1 defines an odd number of colors, the last row
+ // in the second table does not have contents. We skip it.
+ if len(nameSpan) != 1 || len(valueSpan) != 1 {
+ continue
+ }
+ n, v := nameSpan[0].FirstChild, valueSpan[0].FirstChild
+ // This sanity checks for the existence of TextNodes under spans.
+ if n == nil || n.Type != html.TextNode || v == nil || v.Type != html.TextNode {
+ return nil, fmt.Errorf("extractSVGColors: couldn't find name/value text nodes")
+ }
+ val, err := parseRGB(v.Data)
+ if err != nil {
+ return nil, fmt.Errorf("extractSVGColors: couldn't parse name/value %q/%q: %s", n.Data, v.Data, err)
+ }
+ ret[n.Data] = val
+ }
+ }
+ return ret, nil
+}
+
+const preamble = `// generated by go generate; DO NOT EDIT.
+
+package colornames
+
+import "image/color"
+
+`
+
+// WriteColorNames writes table.go.
+func writeColorNames(w io.Writer, m map[string]color.RGBA) {
+ keys := make([]string, 0, len(m))
+ for k := range m {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+
+ fmt.Fprintln(w, preamble)
+ fmt.Fprintln(w, "// Map contains named colors defined in the SVG 1.1 spec.")
+ fmt.Fprintln(w, "var Map = map[string]color.RGBA{")
+ for _, k := range keys {
+ fmt.Fprintf(w, "%q:color.RGBA{%#02x, %#02x, %#02x, %#02x}, // rgb(%d, %d, %d)\n",
+ k, m[k].R, m[k].G, m[k].B, m[k].A, m[k].R, m[k].G, m[k].B)
+ }
+ fmt.Fprintln(w, "}\n")
+ fmt.Fprintln(w, "// Names contains the color names defined in the SVG 1.1 spec.")
+ fmt.Fprintln(w, "var Names = []string{")
+ for _, k := range keys {
+ fmt.Fprintf(w, "%q,\n", k)
+ }
+ fmt.Fprintln(w, "}")
+}
+
+const url = "http://www.w3.org/TR/SVG/types.html"
+
+func main() {
+ res, err := http.Get(url)
+ if err != nil {
+ log.Fatalf("Couldn't read from %s: %s\n", url, err)
+ }
+ defer res.Body.Close()
+
+ tree, err := html.Parse(res.Body)
+ if err != nil {
+ log.Fatalf("Couldn't parse %s: %s\n", url, err)
+ }
+
+ colors, err := extractSVGColors(tree)
+ if err != nil {
+ log.Fatalf("Couldn't extract colors: %s\n", err)
+ }
+
+ buf := &bytes.Buffer{}
+ writeColorNames(buf, colors)
+ fmted, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatalf("Error while formatting code: %s\n", err)
+ }
+
+ if err := ioutil.WriteFile("table.go", fmted, 0644); err != nil {
+ log.Fatalf("Error writing table.go: %s\n", err)
+ }
+}
diff --git a/vendor/golang.org/x/image/colornames/table.go b/vendor/golang.org/x/image/colornames/table.go
new file mode 100644
index 000000000..72ac9fe71
--- /dev/null
+++ b/vendor/golang.org/x/image/colornames/table.go
@@ -0,0 +1,307 @@
+// generated by go generate; DO NOT EDIT.
+
+package colornames
+
+import "image/color"
+
+// Map contains named colors defined in the SVG 1.1 spec.
+var Map = map[string]color.RGBA{
+ "aliceblue": color.RGBA{0xf0, 0xf8, 0xff, 0xff}, // rgb(240, 248, 255)
+ "antiquewhite": color.RGBA{0xfa, 0xeb, 0xd7, 0xff}, // rgb(250, 235, 215)
+ "aqua": color.RGBA{0x00, 0xff, 0xff, 0xff}, // rgb(0, 255, 255)
+ "aquamarine": color.RGBA{0x7f, 0xff, 0xd4, 0xff}, // rgb(127, 255, 212)
+ "azure": color.RGBA{0xf0, 0xff, 0xff, 0xff}, // rgb(240, 255, 255)
+ "beige": color.RGBA{0xf5, 0xf5, 0xdc, 0xff}, // rgb(245, 245, 220)
+ "bisque": color.RGBA{0xff, 0xe4, 0xc4, 0xff}, // rgb(255, 228, 196)
+ "black": color.RGBA{0x00, 0x00, 0x00, 0xff}, // rgb(0, 0, 0)
+ "blanchedalmond": color.RGBA{0xff, 0xeb, 0xcd, 0xff}, // rgb(255, 235, 205)
+ "blue": color.RGBA{0x00, 0x00, 0xff, 0xff}, // rgb(0, 0, 255)
+ "blueviolet": color.RGBA{0x8a, 0x2b, 0xe2, 0xff}, // rgb(138, 43, 226)
+ "brown": color.RGBA{0xa5, 0x2a, 0x2a, 0xff}, // rgb(165, 42, 42)
+ "burlywood": color.RGBA{0xde, 0xb8, 0x87, 0xff}, // rgb(222, 184, 135)
+ "cadetblue": color.RGBA{0x5f, 0x9e, 0xa0, 0xff}, // rgb(95, 158, 160)
+ "chartreuse": color.RGBA{0x7f, 0xff, 0x00, 0xff}, // rgb(127, 255, 0)
+ "chocolate": color.RGBA{0xd2, 0x69, 0x1e, 0xff}, // rgb(210, 105, 30)
+ "coral": color.RGBA{0xff, 0x7f, 0x50, 0xff}, // rgb(255, 127, 80)
+ "cornflowerblue": color.RGBA{0x64, 0x95, 0xed, 0xff}, // rgb(100, 149, 237)
+ "cornsilk": color.RGBA{0xff, 0xf8, 0xdc, 0xff}, // rgb(255, 248, 220)
+ "crimson": color.RGBA{0xdc, 0x14, 0x3c, 0xff}, // rgb(220, 20, 60)
+ "cyan": color.RGBA{0x00, 0xff, 0xff, 0xff}, // rgb(0, 255, 255)
+ "darkblue": color.RGBA{0x00, 0x00, 0x8b, 0xff}, // rgb(0, 0, 139)
+ "darkcyan": color.RGBA{0x00, 0x8b, 0x8b, 0xff}, // rgb(0, 139, 139)
+ "darkgoldenrod": color.RGBA{0xb8, 0x86, 0x0b, 0xff}, // rgb(184, 134, 11)
+ "darkgray": color.RGBA{0xa9, 0xa9, 0xa9, 0xff}, // rgb(169, 169, 169)
+ "darkgreen": color.RGBA{0x00, 0x64, 0x00, 0xff}, // rgb(0, 100, 0)
+ "darkgrey": color.RGBA{0xa9, 0xa9, 0xa9, 0xff}, // rgb(169, 169, 169)
+ "darkkhaki": color.RGBA{0xbd, 0xb7, 0x6b, 0xff}, // rgb(189, 183, 107)
+ "darkmagenta": color.RGBA{0x8b, 0x00, 0x8b, 0xff}, // rgb(139, 0, 139)
+ "darkolivegreen": color.RGBA{0x55, 0x6b, 0x2f, 0xff}, // rgb(85, 107, 47)
+ "darkorange": color.RGBA{0xff, 0x8c, 0x00, 0xff}, // rgb(255, 140, 0)
+ "darkorchid": color.RGBA{0x99, 0x32, 0xcc, 0xff}, // rgb(153, 50, 204)
+ "darkred": color.RGBA{0x8b, 0x00, 0x00, 0xff}, // rgb(139, 0, 0)
+ "darksalmon": color.RGBA{0xe9, 0x96, 0x7a, 0xff}, // rgb(233, 150, 122)
+ "darkseagreen": color.RGBA{0x8f, 0xbc, 0x8f, 0xff}, // rgb(143, 188, 143)
+ "darkslateblue": color.RGBA{0x48, 0x3d, 0x8b, 0xff}, // rgb(72, 61, 139)
+ "darkslategray": color.RGBA{0x2f, 0x4f, 0x4f, 0xff}, // rgb(47, 79, 79)
+ "darkslategrey": color.RGBA{0x2f, 0x4f, 0x4f, 0xff}, // rgb(47, 79, 79)
+ "darkturquoise": color.RGBA{0x00, 0xce, 0xd1, 0xff}, // rgb(0, 206, 209)
+ "darkviolet": color.RGBA{0x94, 0x00, 0xd3, 0xff}, // rgb(148, 0, 211)
+ "deeppink": color.RGBA{0xff, 0x14, 0x93, 0xff}, // rgb(255, 20, 147)
+ "deepskyblue": color.RGBA{0x00, 0xbf, 0xff, 0xff}, // rgb(0, 191, 255)
+ "dimgray": color.RGBA{0x69, 0x69, 0x69, 0xff}, // rgb(105, 105, 105)
+ "dimgrey": color.RGBA{0x69, 0x69, 0x69, 0xff}, // rgb(105, 105, 105)
+ "dodgerblue": color.RGBA{0x1e, 0x90, 0xff, 0xff}, // rgb(30, 144, 255)
+ "firebrick": color.RGBA{0xb2, 0x22, 0x22, 0xff}, // rgb(178, 34, 34)
+ "floralwhite": color.RGBA{0xff, 0xfa, 0xf0, 0xff}, // rgb(255, 250, 240)
+ "forestgreen": color.RGBA{0x22, 0x8b, 0x22, 0xff}, // rgb(34, 139, 34)
+ "fuchsia": color.RGBA{0xff, 0x00, 0xff, 0xff}, // rgb(255, 0, 255)
+ "gainsboro": color.RGBA{0xdc, 0xdc, 0xdc, 0xff}, // rgb(220, 220, 220)
+ "ghostwhite": color.RGBA{0xf8, 0xf8, 0xff, 0xff}, // rgb(248, 248, 255)
+ "gold": color.RGBA{0xff, 0xd7, 0x00, 0xff}, // rgb(255, 215, 0)
+ "goldenrod": color.RGBA{0xda, 0xa5, 0x20, 0xff}, // rgb(218, 165, 32)
+ "gray": color.RGBA{0x80, 0x80, 0x80, 0xff}, // rgb(128, 128, 128)
+ "green": color.RGBA{0x00, 0x80, 0x00, 0xff}, // rgb(0, 128, 0)
+ "greenyellow": color.RGBA{0xad, 0xff, 0x2f, 0xff}, // rgb(173, 255, 47)
+ "grey": color.RGBA{0x80, 0x80, 0x80, 0xff}, // rgb(128, 128, 128)
+ "honeydew": color.RGBA{0xf0, 0xff, 0xf0, 0xff}, // rgb(240, 255, 240)
+ "hotpink": color.RGBA{0xff, 0x69, 0xb4, 0xff}, // rgb(255, 105, 180)
+ "indianred": color.RGBA{0xcd, 0x5c, 0x5c, 0xff}, // rgb(205, 92, 92)
+ "indigo": color.RGBA{0x4b, 0x00, 0x82, 0xff}, // rgb(75, 0, 130)
+ "ivory": color.RGBA{0xff, 0xff, 0xf0, 0xff}, // rgb(255, 255, 240)
+ "khaki": color.RGBA{0xf0, 0xe6, 0x8c, 0xff}, // rgb(240, 230, 140)
+ "lavender": color.RGBA{0xe6, 0xe6, 0xfa, 0xff}, // rgb(230, 230, 250)
+ "lavenderblush": color.RGBA{0xff, 0xf0, 0xf5, 0xff}, // rgb(255, 240, 245)
+ "lawngreen": color.RGBA{0x7c, 0xfc, 0x00, 0xff}, // rgb(124, 252, 0)
+ "lemonchiffon": color.RGBA{0xff, 0xfa, 0xcd, 0xff}, // rgb(255, 250, 205)
+ "lightblue": color.RGBA{0xad, 0xd8, 0xe6, 0xff}, // rgb(173, 216, 230)
+ "lightcoral": color.RGBA{0xf0, 0x80, 0x80, 0xff}, // rgb(240, 128, 128)
+ "lightcyan": color.RGBA{0xe0, 0xff, 0xff, 0xff}, // rgb(224, 255, 255)
+ "lightgoldenrodyellow": color.RGBA{0xfa, 0xfa, 0xd2, 0xff}, // rgb(250, 250, 210)
+ "lightgray": color.RGBA{0xd3, 0xd3, 0xd3, 0xff}, // rgb(211, 211, 211)
+ "lightgreen": color.RGBA{0x90, 0xee, 0x90, 0xff}, // rgb(144, 238, 144)
+ "lightgrey": color.RGBA{0xd3, 0xd3, 0xd3, 0xff}, // rgb(211, 211, 211)
+ "lightpink": color.RGBA{0xff, 0xb6, 0xc1, 0xff}, // rgb(255, 182, 193)
+ "lightsalmon": color.RGBA{0xff, 0xa0, 0x7a, 0xff}, // rgb(255, 160, 122)
+ "lightseagreen": color.RGBA{0x20, 0xb2, 0xaa, 0xff}, // rgb(32, 178, 170)
+ "lightskyblue": color.RGBA{0x87, 0xce, 0xfa, 0xff}, // rgb(135, 206, 250)
+ "lightslategray": color.RGBA{0x77, 0x88, 0x99, 0xff}, // rgb(119, 136, 153)
+ "lightslategrey": color.RGBA{0x77, 0x88, 0x99, 0xff}, // rgb(119, 136, 153)
+ "lightsteelblue": color.RGBA{0xb0, 0xc4, 0xde, 0xff}, // rgb(176, 196, 222)
+ "lightyellow": color.RGBA{0xff, 0xff, 0xe0, 0xff}, // rgb(255, 255, 224)
+ "lime": color.RGBA{0x00, 0xff, 0x00, 0xff}, // rgb(0, 255, 0)
+ "limegreen": color.RGBA{0x32, 0xcd, 0x32, 0xff}, // rgb(50, 205, 50)
+ "linen": color.RGBA{0xfa, 0xf0, 0xe6, 0xff}, // rgb(250, 240, 230)
+ "magenta": color.RGBA{0xff, 0x00, 0xff, 0xff}, // rgb(255, 0, 255)
+ "maroon": color.RGBA{0x80, 0x00, 0x00, 0xff}, // rgb(128, 0, 0)
+ "mediumaquamarine": color.RGBA{0x66, 0xcd, 0xaa, 0xff}, // rgb(102, 205, 170)
+ "mediumblue": color.RGBA{0x00, 0x00, 0xcd, 0xff}, // rgb(0, 0, 205)
+ "mediumorchid": color.RGBA{0xba, 0x55, 0xd3, 0xff}, // rgb(186, 85, 211)
+ "mediumpurple": color.RGBA{0x93, 0x70, 0xdb, 0xff}, // rgb(147, 112, 219)
+ "mediumseagreen": color.RGBA{0x3c, 0xb3, 0x71, 0xff}, // rgb(60, 179, 113)
+ "mediumslateblue": color.RGBA{0x7b, 0x68, 0xee, 0xff}, // rgb(123, 104, 238)
+ "mediumspringgreen": color.RGBA{0x00, 0xfa, 0x9a, 0xff}, // rgb(0, 250, 154)
+ "mediumturquoise": color.RGBA{0x48, 0xd1, 0xcc, 0xff}, // rgb(72, 209, 204)
+ "mediumvioletred": color.RGBA{0xc7, 0x15, 0x85, 0xff}, // rgb(199, 21, 133)
+ "midnightblue": color.RGBA{0x19, 0x19, 0x70, 0xff}, // rgb(25, 25, 112)
+ "mintcream": color.RGBA{0xf5, 0xff, 0xfa, 0xff}, // rgb(245, 255, 250)
+ "mistyrose": color.RGBA{0xff, 0xe4, 0xe1, 0xff}, // rgb(255, 228, 225)
+ "moccasin": color.RGBA{0xff, 0xe4, 0xb5, 0xff}, // rgb(255, 228, 181)
+ "navajowhite": color.RGBA{0xff, 0xde, 0xad, 0xff}, // rgb(255, 222, 173)
+ "navy": color.RGBA{0x00, 0x00, 0x80, 0xff}, // rgb(0, 0, 128)
+ "oldlace": color.RGBA{0xfd, 0xf5, 0xe6, 0xff}, // rgb(253, 245, 230)
+ "olive": color.RGBA{0x80, 0x80, 0x00, 0xff}, // rgb(128, 128, 0)
+ "olivedrab": color.RGBA{0x6b, 0x8e, 0x23, 0xff}, // rgb(107, 142, 35)
+ "orange": color.RGBA{0xff, 0xa5, 0x00, 0xff}, // rgb(255, 165, 0)
+ "orangered": color.RGBA{0xff, 0x45, 0x00, 0xff}, // rgb(255, 69, 0)
+ "orchid": color.RGBA{0xda, 0x70, 0xd6, 0xff}, // rgb(218, 112, 214)
+ "palegoldenrod": color.RGBA{0xee, 0xe8, 0xaa, 0xff}, // rgb(238, 232, 170)
+ "palegreen": color.RGBA{0x98, 0xfb, 0x98, 0xff}, // rgb(152, 251, 152)
+ "paleturquoise": color.RGBA{0xaf, 0xee, 0xee, 0xff}, // rgb(175, 238, 238)
+ "palevioletred": color.RGBA{0xdb, 0x70, 0x93, 0xff}, // rgb(219, 112, 147)
+ "papayawhip": color.RGBA{0xff, 0xef, 0xd5, 0xff}, // rgb(255, 239, 213)
+ "peachpuff": color.RGBA{0xff, 0xda, 0xb9, 0xff}, // rgb(255, 218, 185)
+ "peru": color.RGBA{0xcd, 0x85, 0x3f, 0xff}, // rgb(205, 133, 63)
+ "pink": color.RGBA{0xff, 0xc0, 0xcb, 0xff}, // rgb(255, 192, 203)
+ "plum": color.RGBA{0xdd, 0xa0, 0xdd, 0xff}, // rgb(221, 160, 221)
+ "powderblue": color.RGBA{0xb0, 0xe0, 0xe6, 0xff}, // rgb(176, 224, 230)
+ "purple": color.RGBA{0x80, 0x00, 0x80, 0xff}, // rgb(128, 0, 128)
+ "red": color.RGBA{0xff, 0x00, 0x00, 0xff}, // rgb(255, 0, 0)
+ "rosybrown": color.RGBA{0xbc, 0x8f, 0x8f, 0xff}, // rgb(188, 143, 143)
+ "royalblue": color.RGBA{0x41, 0x69, 0xe1, 0xff}, // rgb(65, 105, 225)
+ "saddlebrown": color.RGBA{0x8b, 0x45, 0x13, 0xff}, // rgb(139, 69, 19)
+ "salmon": color.RGBA{0xfa, 0x80, 0x72, 0xff}, // rgb(250, 128, 114)
+ "sandybrown": color.RGBA{0xf4, 0xa4, 0x60, 0xff}, // rgb(244, 164, 96)
+ "seagreen": color.RGBA{0x2e, 0x8b, 0x57, 0xff}, // rgb(46, 139, 87)
+ "seashell": color.RGBA{0xff, 0xf5, 0xee, 0xff}, // rgb(255, 245, 238)
+ "sienna": color.RGBA{0xa0, 0x52, 0x2d, 0xff}, // rgb(160, 82, 45)
+ "silver": color.RGBA{0xc0, 0xc0, 0xc0, 0xff}, // rgb(192, 192, 192)
+ "skyblue": color.RGBA{0x87, 0xce, 0xeb, 0xff}, // rgb(135, 206, 235)
+ "slateblue": color.RGBA{0x6a, 0x5a, 0xcd, 0xff}, // rgb(106, 90, 205)
+ "slategray": color.RGBA{0x70, 0x80, 0x90, 0xff}, // rgb(112, 128, 144)
+ "slategrey": color.RGBA{0x70, 0x80, 0x90, 0xff}, // rgb(112, 128, 144)
+ "snow": color.RGBA{0xff, 0xfa, 0xfa, 0xff}, // rgb(255, 250, 250)
+ "springgreen": color.RGBA{0x00, 0xff, 0x7f, 0xff}, // rgb(0, 255, 127)
+ "steelblue": color.RGBA{0x46, 0x82, 0xb4, 0xff}, // rgb(70, 130, 180)
+ "tan": color.RGBA{0xd2, 0xb4, 0x8c, 0xff}, // rgb(210, 180, 140)
+ "teal": color.RGBA{0x00, 0x80, 0x80, 0xff}, // rgb(0, 128, 128)
+ "thistle": color.RGBA{0xd8, 0xbf, 0xd8, 0xff}, // rgb(216, 191, 216)
+ "tomato": color.RGBA{0xff, 0x63, 0x47, 0xff}, // rgb(255, 99, 71)
+ "turquoise": color.RGBA{0x40, 0xe0, 0xd0, 0xff}, // rgb(64, 224, 208)
+ "violet": color.RGBA{0xee, 0x82, 0xee, 0xff}, // rgb(238, 130, 238)
+ "wheat": color.RGBA{0xf5, 0xde, 0xb3, 0xff}, // rgb(245, 222, 179)
+ "white": color.RGBA{0xff, 0xff, 0xff, 0xff}, // rgb(255, 255, 255)
+ "whitesmoke": color.RGBA{0xf5, 0xf5, 0xf5, 0xff}, // rgb(245, 245, 245)
+ "yellow": color.RGBA{0xff, 0xff, 0x00, 0xff}, // rgb(255, 255, 0)
+ "yellowgreen": color.RGBA{0x9a, 0xcd, 0x32, 0xff}, // rgb(154, 205, 50)
+}
+
+// Names contains the color names defined in the SVG 1.1 spec.
+var Names = []string{
+ "aliceblue",
+ "antiquewhite",
+ "aqua",
+ "aquamarine",
+ "azure",
+ "beige",
+ "bisque",
+ "black",
+ "blanchedalmond",
+ "blue",
+ "blueviolet",
+ "brown",
+ "burlywood",
+ "cadetblue",
+ "chartreuse",
+ "chocolate",
+ "coral",
+ "cornflowerblue",
+ "cornsilk",
+ "crimson",
+ "cyan",
+ "darkblue",
+ "darkcyan",
+ "darkgoldenrod",
+ "darkgray",
+ "darkgreen",
+ "darkgrey",
+ "darkkhaki",
+ "darkmagenta",
+ "darkolivegreen",
+ "darkorange",
+ "darkorchid",
+ "darkred",
+ "darksalmon",
+ "darkseagreen",
+ "darkslateblue",
+ "darkslategray",
+ "darkslategrey",
+ "darkturquoise",
+ "darkviolet",
+ "deeppink",
+ "deepskyblue",
+ "dimgray",
+ "dimgrey",
+ "dodgerblue",
+ "firebrick",
+ "floralwhite",
+ "forestgreen",
+ "fuchsia",
+ "gainsboro",
+ "ghostwhite",
+ "gold",
+ "goldenrod",
+ "gray",
+ "green",
+ "greenyellow",
+ "grey",
+ "honeydew",
+ "hotpink",
+ "indianred",
+ "indigo",
+ "ivory",
+ "khaki",
+ "lavender",
+ "lavenderblush",
+ "lawngreen",
+ "lemonchiffon",
+ "lightblue",
+ "lightcoral",
+ "lightcyan",
+ "lightgoldenrodyellow",
+ "lightgray",
+ "lightgreen",
+ "lightgrey",
+ "lightpink",
+ "lightsalmon",
+ "lightseagreen",
+ "lightskyblue",
+ "lightslategray",
+ "lightslategrey",
+ "lightsteelblue",
+ "lightyellow",
+ "lime",
+ "limegreen",
+ "linen",
+ "magenta",
+ "maroon",
+ "mediumaquamarine",
+ "mediumblue",
+ "mediumorchid",
+ "mediumpurple",
+ "mediumseagreen",
+ "mediumslateblue",
+ "mediumspringgreen",
+ "mediumturquoise",
+ "mediumvioletred",
+ "midnightblue",
+ "mintcream",
+ "mistyrose",
+ "moccasin",
+ "navajowhite",
+ "navy",
+ "oldlace",
+ "olive",
+ "olivedrab",
+ "orange",
+ "orangered",
+ "orchid",
+ "palegoldenrod",
+ "palegreen",
+ "paleturquoise",
+ "palevioletred",
+ "papayawhip",
+ "peachpuff",
+ "peru",
+ "pink",
+ "plum",
+ "powderblue",
+ "purple",
+ "red",
+ "rosybrown",
+ "royalblue",
+ "saddlebrown",
+ "salmon",
+ "sandybrown",
+ "seagreen",
+ "seashell",
+ "sienna",
+ "silver",
+ "skyblue",
+ "slateblue",
+ "slategray",
+ "slategrey",
+ "snow",
+ "springgreen",
+ "steelblue",
+ "tan",
+ "teal",
+ "thistle",
+ "tomato",
+ "turquoise",
+ "violet",
+ "wheat",
+ "white",
+ "whitesmoke",
+ "yellow",
+ "yellowgreen",
+}
diff --git a/vendor/golang.org/x/image/draw/draw.go b/vendor/golang.org/x/image/draw/draw.go
new file mode 100644
index 000000000..b92e3c7f9
--- /dev/null
+++ b/vendor/golang.org/x/image/draw/draw.go
@@ -0,0 +1,79 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package draw provides image composition functions.
+//
+// See "The Go image/draw package" for an introduction to this package:
+// http://golang.org/doc/articles/image_draw.html
+//
+// This package is a superset of and a drop-in replacement for the image/draw
+// package in the standard library.
+package draw
+
+// This file just contains the API exported by the image/draw package in the
+// standard library. Other files in this package provide additional features.
+
+import (
+ "image"
+ "image/color"
+ "image/draw"
+)
+
+// Draw calls DrawMask with a nil mask.
+func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point, op Op) {
+ draw.Draw(dst, r, src, sp, draw.Op(op))
+}
+
+// DrawMask aligns r.Min in dst with sp in src and mp in mask and then
+// replaces the rectangle r in dst with the result of a Porter-Duff
+// composition. A nil mask is treated as opaque.
+func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+ draw.DrawMask(dst, r, src, sp, mask, mp, draw.Op(op))
+}
+
+// Drawer contains the Draw method.
+type Drawer interface {
+ // Draw aligns r.Min in dst with sp in src and then replaces the
+ // rectangle r in dst with the result of drawing src on dst.
+ Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point)
+}
+
+// FloydSteinberg is a Drawer that is the Src Op with Floyd-Steinberg error
+// diffusion.
+var FloydSteinberg Drawer = floydSteinberg{}
+
+type floydSteinberg struct{}
+
+func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
+ draw.FloydSteinberg.Draw(dst, r, src, sp)
+}
+
+// Image is an image.Image with a Set method to change a single pixel.
+type Image interface {
+ image.Image
+ Set(x, y int, c color.Color)
+}
+
+// Op is a Porter-Duff compositing operator.
+type Op int
+
+const (
+ // Over specifies ``(src in mask) over dst''.
+ Over Op = Op(draw.Over)
+ // Src specifies ``src in mask''.
+ Src Op = Op(draw.Src)
+)
+
+// Draw implements the Drawer interface by calling the Draw function with
+// this Op.
+func (op Op) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
+ (draw.Op(op)).Draw(dst, r, src, sp)
+}
+
+// Quantizer produces a palette for an image.
+type Quantizer interface {
+ // Quantize appends up to cap(p) - len(p) colors to p and returns the
+ // updated palette suitable for converting m to a paletted image.
+ Quantize(p color.Palette, m image.Image) color.Palette
+}
diff --git a/vendor/golang.org/x/image/draw/example_test.go b/vendor/golang.org/x/image/draw/example_test.go
new file mode 100644
index 000000000..bcb46629c
--- /dev/null
+++ b/vendor/golang.org/x/image/draw/example_test.go
@@ -0,0 +1,118 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw_test
+
+import (
+ "fmt"
+ "image"
+ "image/color"
+ "image/png"
+ "log"
+ "math"
+ "os"
+
+ "golang.org/x/image/draw"
+ "golang.org/x/image/math/f64"
+)
+
+func ExampleDraw() {
+ fSrc, err := os.Open("../testdata/blue-purple-pink.png")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer fSrc.Close()
+ src, err := png.Decode(fSrc)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ dst := image.NewRGBA(image.Rect(0, 0, 400, 300))
+ green := image.NewUniform(color.RGBA{0x00, 0x1f, 0x00, 0xff})
+ draw.Copy(dst, image.Point{}, green, dst.Bounds(), draw.Src, nil)
+ qs := []draw.Interpolator{
+ draw.NearestNeighbor,
+ draw.ApproxBiLinear,
+ draw.CatmullRom,
+ }
+ const cos60, sin60 = 0.5, 0.866025404
+ t := f64.Aff3{
+ +2 * cos60, -2 * sin60, 100,
+ +2 * sin60, +2 * cos60, 100,
+ }
+
+ draw.Copy(dst, image.Point{20, 30}, src, src.Bounds(), draw.Over, nil)
+ for i, q := range qs {
+ q.Scale(dst, image.Rect(200+10*i, 100*i, 600+10*i, 150+100*i), src, src.Bounds(), draw.Over, nil)
+ }
+ draw.NearestNeighbor.Transform(dst, t, src, src.Bounds(), draw.Over, nil)
+
+ red := image.NewNRGBA(image.Rect(0, 0, 16, 16))
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ red.SetNRGBA(x, y, color.NRGBA{
+ R: uint8(x * 0x11),
+ A: uint8(y * 0x11),
+ })
+ }
+ }
+ red.SetNRGBA(0, 0, color.NRGBA{0xff, 0xff, 0x00, 0xff})
+ red.SetNRGBA(15, 15, color.NRGBA{0xff, 0xff, 0x00, 0xff})
+
+ ops := []draw.Op{
+ draw.Over,
+ draw.Src,
+ }
+ for i, op := range ops {
+ dr := image.Rect(120+10*i, 150+60*i, 170+10*i, 200+60*i)
+ draw.NearestNeighbor.Scale(dst, dr, red, red.Bounds(), op, nil)
+ t := f64.Aff3{
+ +cos60, -sin60, float64(190 + 10*i),
+ +sin60, +cos60, float64(140 + 50*i),
+ }
+ draw.NearestNeighbor.Transform(dst, t, red, red.Bounds(), op, nil)
+ }
+
+ dr := image.Rect(0, 0, 128, 128)
+ checkerboard := image.NewAlpha(dr)
+ for y := dr.Min.Y; y < dr.Max.Y; y++ {
+ for x := dr.Min.X; x < dr.Max.X; x++ {
+ if (x/20)%2 == (y/20)%2 {
+ checkerboard.SetAlpha(x, y, color.Alpha{0xff})
+ }
+ }
+ }
+ sr := image.Rect(0, 0, 16, 16)
+ circle := image.NewAlpha(sr)
+ for y := sr.Min.Y; y < sr.Max.Y; y++ {
+ for x := sr.Min.X; x < sr.Max.X; x++ {
+ dx, dy := x-10, y-8
+ if d := 32 * math.Sqrt(float64(dx*dx)+float64(dy*dy)); d < 0xff {
+ circle.SetAlpha(x, y, color.Alpha{0xff - uint8(d)})
+ }
+ }
+ }
+ cyan := image.NewUniform(color.RGBA{0x00, 0xff, 0xff, 0xff})
+ draw.NearestNeighbor.Scale(dst, dr, cyan, sr, draw.Over, &draw.Options{
+ DstMask: checkerboard,
+ SrcMask: circle,
+ })
+
+ // Change false to true to write the resultant image to disk.
+ if false {
+ fDst, err := os.Create("out.png")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer fDst.Close()
+ err = png.Encode(fDst, dst)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ fmt.Printf("dst has bounds %v.\n", dst.Bounds())
+ // Output:
+ // dst has bounds (0,0)-(400,300).
+}
diff --git a/vendor/golang.org/x/image/draw/gen.go b/vendor/golang.org/x/image/draw/gen.go
new file mode 100644
index 000000000..0fed47437
--- /dev/null
+++ b/vendor/golang.org/x/image/draw/gen.go
@@ -0,0 +1,1403 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+ "os"
+ "strings"
+)
+
+var debug = flag.Bool("debug", false, "")
+
+func main() {
+ flag.Parse()
+
+ w := new(bytes.Buffer)
+ w.WriteString("// generated by \"go run gen.go\". DO NOT EDIT.\n\n" +
+ "package draw\n\nimport (\n" +
+ "\"image\"\n" +
+ "\"image/color\"\n" +
+ "\"math\"\n" +
+ "\n" +
+ "\"golang.org/x/image/math/f64\"\n" +
+ ")\n")
+
+ gen(w, "nnInterpolator", codeNNScaleLeaf, codeNNTransformLeaf)
+ gen(w, "ablInterpolator", codeABLScaleLeaf, codeABLTransformLeaf)
+ genKernel(w)
+
+ if *debug {
+ os.Stdout.Write(w.Bytes())
+ return
+ }
+ out, err := format.Source(w.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := ioutil.WriteFile("impl.go", out, 0660); err != nil {
+ log.Fatal(err)
+ }
+}
+
+var (
+ // dsTypes are the (dst image type, src image type) pairs to generate
+ // scale_DType_SType implementations for. The last element in the slice
+ // should be the fallback pair ("Image", "image.Image").
+ //
+ // TODO: add *image.CMYK src type after Go 1.5 is released.
+ // An *image.CMYK is also alwaysOpaque.
+ dsTypes = []struct{ dType, sType string }{
+ {"*image.RGBA", "*image.Gray"},
+ {"*image.RGBA", "*image.NRGBA"},
+ {"*image.RGBA", "*image.RGBA"},
+ {"*image.RGBA", "*image.YCbCr"},
+ {"*image.RGBA", "image.Image"},
+ {"Image", "image.Image"},
+ }
+ dTypes, sTypes []string
+ sTypesForDType = map[string][]string{}
+ subsampleRatios = []string{
+ "444",
+ "422",
+ "420",
+ "440",
+ }
+ ops = []string{"Over", "Src"}
+ // alwaysOpaque are those image.Image implementations that are always
+ // opaque. For these types, Over is equivalent to the faster Src, in the
+ // absence of a source mask.
+ alwaysOpaque = map[string]bool{
+ "*image.Gray": true,
+ "*image.YCbCr": true,
+ }
+)
+
+func init() {
+ dTypesSeen := map[string]bool{}
+ sTypesSeen := map[string]bool{}
+ for _, t := range dsTypes {
+ if !sTypesSeen[t.sType] {
+ sTypesSeen[t.sType] = true
+ sTypes = append(sTypes, t.sType)
+ }
+ if !dTypesSeen[t.dType] {
+ dTypesSeen[t.dType] = true
+ dTypes = append(dTypes, t.dType)
+ }
+ sTypesForDType[t.dType] = append(sTypesForDType[t.dType], t.sType)
+ }
+ sTypesForDType["anyDType"] = sTypes
+}
+
+type data struct {
+ dType string
+ sType string
+ sratio string
+ receiver string
+ op string
+}
+
+func gen(w *bytes.Buffer, receiver string, codes ...string) {
+ expn(w, codeRoot, &data{receiver: receiver})
+ for _, code := range codes {
+ for _, t := range dsTypes {
+ for _, op := range ops {
+ if op == "Over" && alwaysOpaque[t.sType] {
+ continue
+ }
+ expn(w, code, &data{
+ dType: t.dType,
+ sType: t.sType,
+ receiver: receiver,
+ op: op,
+ })
+ }
+ }
+ }
+}
+
+func genKernel(w *bytes.Buffer) {
+ expn(w, codeKernelRoot, &data{})
+ for _, sType := range sTypes {
+ expn(w, codeKernelScaleLeafX, &data{
+ sType: sType,
+ })
+ }
+ for _, dType := range dTypes {
+ for _, op := range ops {
+ expn(w, codeKernelScaleLeafY, &data{
+ dType: dType,
+ op: op,
+ })
+ }
+ }
+ for _, t := range dsTypes {
+ for _, op := range ops {
+ if op == "Over" && alwaysOpaque[t.sType] {
+ continue
+ }
+ expn(w, codeKernelTransformLeaf, &data{
+ dType: t.dType,
+ sType: t.sType,
+ op: op,
+ })
+ }
+ }
+}
+
+func expn(w *bytes.Buffer, code string, d *data) {
+ if d.sType == "*image.YCbCr" && d.sratio == "" {
+ for _, sratio := range subsampleRatios {
+ e := *d
+ e.sratio = sratio
+ expn(w, code, &e)
+ }
+ return
+ }
+
+ for _, line := range strings.Split(code, "\n") {
+ line = expnLine(line, d)
+ if line == ";" {
+ continue
+ }
+ fmt.Fprintln(w, line)
+ }
+}
+
+func expnLine(line string, d *data) string {
+ for {
+ i := strings.IndexByte(line, '$')
+ if i < 0 {
+ break
+ }
+ prefix, s := line[:i], line[i+1:]
+
+ i = len(s)
+ for j, c := range s {
+ if !('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z') {
+ i = j
+ break
+ }
+ }
+ dollar, suffix := s[:i], s[i:]
+
+ e := expnDollar(prefix, dollar, suffix, d)
+ if e == "" {
+ log.Fatalf("couldn't expand %q", line)
+ }
+ line = e
+ }
+ return line
+}
+
+// expnDollar expands a "$foo" fragment in a line of generated code. It returns
+// the empty string if there was a problem. It returns ";" if the generated
+// code is a no-op.
+func expnDollar(prefix, dollar, suffix string, d *data) string {
+ switch dollar {
+ case "dType":
+ return prefix + d.dType + suffix
+ case "dTypeRN":
+ return prefix + relName(d.dType) + suffix
+ case "sratio":
+ return prefix + d.sratio + suffix
+ case "sType":
+ return prefix + d.sType + suffix
+ case "sTypeRN":
+ return prefix + relName(d.sType) + suffix
+ case "receiver":
+ return prefix + d.receiver + suffix
+ case "op":
+ return prefix + d.op + suffix
+
+ case "switch":
+ return expnSwitch("", "", true, suffix)
+ case "switchD":
+ return expnSwitch("", "", false, suffix)
+ case "switchS":
+ return expnSwitch("", "anyDType", false, suffix)
+
+ case "preOuter":
+ switch d.dType {
+ default:
+ return ";"
+ case "Image":
+ s := ""
+ if d.sType == "image.Image" {
+ s = "srcMask, smp := opts.SrcMask, opts.SrcMaskP\n"
+ }
+ return s +
+ "dstMask, dmp := opts.DstMask, opts.DstMaskP\n" +
+ "dstColorRGBA64 := &color.RGBA64{}\n" +
+ "dstColor := color.Color(dstColorRGBA64)"
+ }
+
+ case "preInner":
+ switch d.dType {
+ default:
+ return ";"
+ case "*image.RGBA":
+ return "d := " + pixOffset("dst", "dr.Min.X+adr.Min.X", "dr.Min.Y+int(dy)", "*4", "*dst.Stride")
+ }
+
+ case "preKernelOuter":
+ switch d.sType {
+ default:
+ return ";"
+ case "image.Image":
+ return "srcMask, smp := opts.SrcMask, opts.SrcMaskP"
+ }
+
+ case "preKernelInner":
+ switch d.dType {
+ default:
+ return ";"
+ case "*image.RGBA":
+ return "d := " + pixOffset("dst", "dr.Min.X+int(dx)", "dr.Min.Y+adr.Min.Y", "*4", "*dst.Stride")
+ }
+
+ case "blend":
+ args, _ := splitArgs(suffix)
+ if len(args) != 4 {
+ return ""
+ }
+ switch d.sType {
+ default:
+ return argf(args, ""+
+ "$3r = $0*$1r + $2*$3r\n"+
+ "$3g = $0*$1g + $2*$3g\n"+
+ "$3b = $0*$1b + $2*$3b\n"+
+ "$3a = $0*$1a + $2*$3a",
+ )
+ case "*image.Gray":
+ return argf(args, ""+
+ "$3r = $0*$1r + $2*$3r",
+ )
+ case "*image.YCbCr":
+ return argf(args, ""+
+ "$3r = $0*$1r + $2*$3r\n"+
+ "$3g = $0*$1g + $2*$3g\n"+
+ "$3b = $0*$1b + $2*$3b",
+ )
+ }
+
+ case "clampToAlpha":
+ if alwaysOpaque[d.sType] {
+ return ";"
+ }
+ // Go uses alpha-premultiplied color. The naive computation can lead to
+ // invalid colors, e.g. red > alpha, when some weights are negative.
+ return `
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+ `
+
+ case "convFtou":
+ args, _ := splitArgs(suffix)
+ if len(args) != 2 {
+ return ""
+ }
+
+ switch d.sType {
+ default:
+ return argf(args, ""+
+ "$0r := uint32($1r)\n"+
+ "$0g := uint32($1g)\n"+
+ "$0b := uint32($1b)\n"+
+ "$0a := uint32($1a)",
+ )
+ case "*image.Gray":
+ return argf(args, ""+
+ "$0r := uint32($1r)",
+ )
+ case "*image.YCbCr":
+ return argf(args, ""+
+ "$0r := uint32($1r)\n"+
+ "$0g := uint32($1g)\n"+
+ "$0b := uint32($1b)",
+ )
+ }
+
+ case "outputu":
+ args, _ := splitArgs(suffix)
+ if len(args) != 3 {
+ return ""
+ }
+
+ switch d.op {
+ case "Over":
+ switch d.dType {
+ default:
+ log.Fatalf("bad dType %q", d.dType)
+ case "Image":
+ return argf(args, ""+
+ "qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
+ "if dstMask != nil {\n"+
+ " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
+ " $2r = $2r * ma / 0xffff\n"+
+ " $2g = $2g * ma / 0xffff\n"+
+ " $2b = $2b * ma / 0xffff\n"+
+ " $2a = $2a * ma / 0xffff\n"+
+ "}\n"+
+ "$2a1 := 0xffff - $2a\n"+
+ "dstColorRGBA64.R = uint16(qr*$2a1/0xffff + $2r)\n"+
+ "dstColorRGBA64.G = uint16(qg*$2a1/0xffff + $2g)\n"+
+ "dstColorRGBA64.B = uint16(qb*$2a1/0xffff + $2b)\n"+
+ "dstColorRGBA64.A = uint16(qa*$2a1/0xffff + $2a)\n"+
+ "dst.Set($0, $1, dstColor)",
+ )
+ case "*image.RGBA":
+ return argf(args, ""+
+ "$2a1 := (0xffff - $2a) * 0x101\n"+
+ "dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*$2a1/0xffff + $2r) >> 8)\n"+
+ "dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*$2a1/0xffff + $2g) >> 8)\n"+
+ "dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*$2a1/0xffff + $2b) >> 8)\n"+
+ "dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*$2a1/0xffff + $2a) >> 8)",
+ )
+ }
+
+ case "Src":
+ switch d.dType {
+ default:
+ log.Fatalf("bad dType %q", d.dType)
+ case "Image":
+ return argf(args, ""+
+ "if dstMask != nil {\n"+
+ " qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
+ " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
+ " pr = pr * ma / 0xffff\n"+
+ " pg = pg * ma / 0xffff\n"+
+ " pb = pb * ma / 0xffff\n"+
+ " pa = pa * ma / 0xffff\n"+
+ " $2a1 := 0xffff - ma\n"+ // Note that this is ma, not $2a.
+ " dstColorRGBA64.R = uint16(qr*$2a1/0xffff + $2r)\n"+
+ " dstColorRGBA64.G = uint16(qg*$2a1/0xffff + $2g)\n"+
+ " dstColorRGBA64.B = uint16(qb*$2a1/0xffff + $2b)\n"+
+ " dstColorRGBA64.A = uint16(qa*$2a1/0xffff + $2a)\n"+
+ " dst.Set($0, $1, dstColor)\n"+
+ "} else {\n"+
+ " dstColorRGBA64.R = uint16($2r)\n"+
+ " dstColorRGBA64.G = uint16($2g)\n"+
+ " dstColorRGBA64.B = uint16($2b)\n"+
+ " dstColorRGBA64.A = uint16($2a)\n"+
+ " dst.Set($0, $1, dstColor)\n"+
+ "}",
+ )
+ case "*image.RGBA":
+ switch d.sType {
+ default:
+ return argf(args, ""+
+ "dst.Pix[d+0] = uint8($2r >> 8)\n"+
+ "dst.Pix[d+1] = uint8($2g >> 8)\n"+
+ "dst.Pix[d+2] = uint8($2b >> 8)\n"+
+ "dst.Pix[d+3] = uint8($2a >> 8)",
+ )
+ case "*image.Gray":
+ return argf(args, ""+
+ "out := uint8($2r >> 8)\n"+
+ "dst.Pix[d+0] = out\n"+
+ "dst.Pix[d+1] = out\n"+
+ "dst.Pix[d+2] = out\n"+
+ "dst.Pix[d+3] = 0xff",
+ )
+ case "*image.YCbCr":
+ return argf(args, ""+
+ "dst.Pix[d+0] = uint8($2r >> 8)\n"+
+ "dst.Pix[d+1] = uint8($2g >> 8)\n"+
+ "dst.Pix[d+2] = uint8($2b >> 8)\n"+
+ "dst.Pix[d+3] = 0xff",
+ )
+ }
+ }
+ }
+
+ case "outputf":
+ args, _ := splitArgs(suffix)
+ if len(args) != 5 {
+ return ""
+ }
+ ret := ""
+
+ switch d.op {
+ case "Over":
+ switch d.dType {
+ default:
+ log.Fatalf("bad dType %q", d.dType)
+ case "Image":
+ ret = argf(args, ""+
+ "qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
+ "$3r0 := uint32($2($3r * $4))\n"+
+ "$3g0 := uint32($2($3g * $4))\n"+
+ "$3b0 := uint32($2($3b * $4))\n"+
+ "$3a0 := uint32($2($3a * $4))\n"+
+ "if dstMask != nil {\n"+
+ " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
+ " $3r0 = $3r0 * ma / 0xffff\n"+
+ " $3g0 = $3g0 * ma / 0xffff\n"+
+ " $3b0 = $3b0 * ma / 0xffff\n"+
+ " $3a0 = $3a0 * ma / 0xffff\n"+
+ "}\n"+
+ "$3a1 := 0xffff - $3a0\n"+
+ "dstColorRGBA64.R = uint16(qr*$3a1/0xffff + $3r0)\n"+
+ "dstColorRGBA64.G = uint16(qg*$3a1/0xffff + $3g0)\n"+
+ "dstColorRGBA64.B = uint16(qb*$3a1/0xffff + $3b0)\n"+
+ "dstColorRGBA64.A = uint16(qa*$3a1/0xffff + $3a0)\n"+
+ "dst.Set($0, $1, dstColor)",
+ )
+ case "*image.RGBA":
+ ret = argf(args, ""+
+ "$3r0 := uint32($2($3r * $4))\n"+
+ "$3g0 := uint32($2($3g * $4))\n"+
+ "$3b0 := uint32($2($3b * $4))\n"+
+ "$3a0 := uint32($2($3a * $4))\n"+
+ "$3a1 := (0xffff - uint32($3a0)) * 0x101\n"+
+ "dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*$3a1/0xffff + $3r0) >> 8)\n"+
+ "dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*$3a1/0xffff + $3g0) >> 8)\n"+
+ "dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*$3a1/0xffff + $3b0) >> 8)\n"+
+ "dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*$3a1/0xffff + $3a0) >> 8)",
+ )
+ }
+
+ case "Src":
+ switch d.dType {
+ default:
+ log.Fatalf("bad dType %q", d.dType)
+ case "Image":
+ ret = argf(args, ""+
+ "if dstMask != nil {\n"+
+ " qr, qg, qb, qa := dst.At($0, $1).RGBA()\n"+
+ " _, _, _, ma := dstMask.At(dmp.X + $0, dmp.Y + $1).RGBA()\n"+
+ " pr := uint32($2($3r * $4)) * ma / 0xffff\n"+
+ " pg := uint32($2($3g * $4)) * ma / 0xffff\n"+
+ " pb := uint32($2($3b * $4)) * ma / 0xffff\n"+
+ " pa := uint32($2($3a * $4)) * ma / 0xffff\n"+
+ " pa1 := 0xffff - ma\n"+ // Note that this is ma, not pa.
+ " dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)\n"+
+ " dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)\n"+
+ " dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)\n"+
+ " dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)\n"+
+ " dst.Set($0, $1, dstColor)\n"+
+ "} else {\n"+
+ " dstColorRGBA64.R = $2($3r * $4)\n"+
+ " dstColorRGBA64.G = $2($3g * $4)\n"+
+ " dstColorRGBA64.B = $2($3b * $4)\n"+
+ " dstColorRGBA64.A = $2($3a * $4)\n"+
+ " dst.Set($0, $1, dstColor)\n"+
+ "}",
+ )
+ case "*image.RGBA":
+ switch d.sType {
+ default:
+ ret = argf(args, ""+
+ "dst.Pix[d+0] = uint8($2($3r * $4) >> 8)\n"+
+ "dst.Pix[d+1] = uint8($2($3g * $4) >> 8)\n"+
+ "dst.Pix[d+2] = uint8($2($3b * $4) >> 8)\n"+
+ "dst.Pix[d+3] = uint8($2($3a * $4) >> 8)",
+ )
+ case "*image.Gray":
+ ret = argf(args, ""+
+ "out := uint8($2($3r * $4) >> 8)\n"+
+ "dst.Pix[d+0] = out\n"+
+ "dst.Pix[d+1] = out\n"+
+ "dst.Pix[d+2] = out\n"+
+ "dst.Pix[d+3] = 0xff",
+ )
+ case "*image.YCbCr":
+ ret = argf(args, ""+
+ "dst.Pix[d+0] = uint8($2($3r * $4) >> 8)\n"+
+ "dst.Pix[d+1] = uint8($2($3g * $4) >> 8)\n"+
+ "dst.Pix[d+2] = uint8($2($3b * $4) >> 8)\n"+
+ "dst.Pix[d+3] = 0xff",
+ )
+ }
+ }
+ }
+
+ return strings.Replace(ret, " * 1)", ")", -1)
+
+ case "srcf", "srcu":
+ lhs, eqOp := splitEq(prefix)
+ if lhs == "" {
+ return ""
+ }
+ args, extra := splitArgs(suffix)
+ if len(args) != 2 {
+ return ""
+ }
+
+ tmp := ""
+ if dollar == "srcf" {
+ tmp = "u"
+ }
+
+ // TODO: there's no need to multiply by 0x101 in the switch below if
+ // the next thing we're going to do is shift right by 8.
+
+ buf := new(bytes.Buffer)
+ switch d.sType {
+ default:
+ log.Fatalf("bad sType %q", d.sType)
+ case "image.Image":
+ fmt.Fprintf(buf, ""+
+ "%sr%s, %sg%s, %sb%s, %sa%s := src.At(%s, %s).RGBA()\n",
+ lhs, tmp, lhs, tmp, lhs, tmp, lhs, tmp, args[0], args[1],
+ )
+ if d.dType == "" || d.dType == "Image" {
+ fmt.Fprintf(buf, ""+
+ "if srcMask != nil {\n"+
+ " _, _, _, ma := srcMask.At(smp.X+%s, smp.Y+%s).RGBA()\n"+
+ " %sr%s = %sr%s * ma / 0xffff\n"+
+ " %sg%s = %sg%s * ma / 0xffff\n"+
+ " %sb%s = %sb%s * ma / 0xffff\n"+
+ " %sa%s = %sa%s * ma / 0xffff\n"+
+ "}\n",
+ args[0], args[1],
+ lhs, tmp, lhs, tmp,
+ lhs, tmp, lhs, tmp,
+ lhs, tmp, lhs, tmp,
+ lhs, tmp, lhs, tmp,
+ )
+ }
+ case "*image.Gray":
+ fmt.Fprintf(buf, ""+
+ "%si := %s\n"+
+ "%sr%s := uint32(src.Pix[%si]) * 0x101\n",
+ lhs, pixOffset("src", args[0], args[1], "", "*src.Stride"),
+ lhs, tmp, lhs,
+ )
+ case "*image.NRGBA":
+ fmt.Fprintf(buf, ""+
+ "%si := %s\n"+
+ "%sa%s := uint32(src.Pix[%si+3]) * 0x101\n"+
+ "%sr%s := uint32(src.Pix[%si+0]) * %sa%s / 0xff\n"+
+ "%sg%s := uint32(src.Pix[%si+1]) * %sa%s / 0xff\n"+
+ "%sb%s := uint32(src.Pix[%si+2]) * %sa%s / 0xff\n",
+ lhs, pixOffset("src", args[0], args[1], "*4", "*src.Stride"),
+ lhs, tmp, lhs,
+ lhs, tmp, lhs, lhs, tmp,
+ lhs, tmp, lhs, lhs, tmp,
+ lhs, tmp, lhs, lhs, tmp,
+ )
+ case "*image.RGBA":
+ fmt.Fprintf(buf, ""+
+ "%si := %s\n"+
+ "%sr%s := uint32(src.Pix[%si+0]) * 0x101\n"+
+ "%sg%s := uint32(src.Pix[%si+1]) * 0x101\n"+
+ "%sb%s := uint32(src.Pix[%si+2]) * 0x101\n"+
+ "%sa%s := uint32(src.Pix[%si+3]) * 0x101\n",
+ lhs, pixOffset("src", args[0], args[1], "*4", "*src.Stride"),
+ lhs, tmp, lhs,
+ lhs, tmp, lhs,
+ lhs, tmp, lhs,
+ lhs, tmp, lhs,
+ )
+ case "*image.YCbCr":
+ fmt.Fprintf(buf, ""+
+ "%si := %s\n"+
+ "%sj := %s\n"+
+ "%s\n",
+ lhs, pixOffset("src", args[0], args[1], "", "*src.YStride"),
+ lhs, cOffset(args[0], args[1], d.sratio),
+ ycbcrToRGB(lhs, tmp),
+ )
+ }
+
+ if dollar == "srcf" {
+ switch d.sType {
+ default:
+ fmt.Fprintf(buf, ""+
+ "%sr %s float64(%sru)%s\n"+
+ "%sg %s float64(%sgu)%s\n"+
+ "%sb %s float64(%sbu)%s\n"+
+ "%sa %s float64(%sau)%s\n",
+ lhs, eqOp, lhs, extra,
+ lhs, eqOp, lhs, extra,
+ lhs, eqOp, lhs, extra,
+ lhs, eqOp, lhs, extra,
+ )
+ case "*image.Gray":
+ fmt.Fprintf(buf, ""+
+ "%sr %s float64(%sru)%s\n",
+ lhs, eqOp, lhs, extra,
+ )
+ case "*image.YCbCr":
+ fmt.Fprintf(buf, ""+
+ "%sr %s float64(%sru)%s\n"+
+ "%sg %s float64(%sgu)%s\n"+
+ "%sb %s float64(%sbu)%s\n",
+ lhs, eqOp, lhs, extra,
+ lhs, eqOp, lhs, extra,
+ lhs, eqOp, lhs, extra,
+ )
+ }
+ }
+
+ return strings.TrimSpace(buf.String())
+
+ case "tweakD":
+ if d.dType == "*image.RGBA" {
+ return "d += dst.Stride"
+ }
+ return ";"
+
+ case "tweakDx":
+ if d.dType == "*image.RGBA" {
+ return strings.Replace(prefix, "dx++", "dx, d = dx+1, d+4", 1)
+ }
+ return prefix
+
+ case "tweakDy":
+ if d.dType == "*image.RGBA" {
+ return strings.Replace(prefix, "for dy, s", "for _, s", 1)
+ }
+ return prefix
+
+ case "tweakP":
+ switch d.sType {
+ case "*image.Gray":
+ if strings.HasPrefix(strings.TrimSpace(prefix), "pa * ") {
+ return "1,"
+ }
+ return "pr,"
+ case "*image.YCbCr":
+ if strings.HasPrefix(strings.TrimSpace(prefix), "pa * ") {
+ return "1,"
+ }
+ }
+ return prefix
+
+ case "tweakPr":
+ if d.sType == "*image.Gray" {
+ return "pr *= s.invTotalWeightFFFF"
+ }
+ return ";"
+
+ case "tweakVarP":
+ switch d.sType {
+ case "*image.Gray":
+ return strings.Replace(prefix, "var pr, pg, pb, pa", "var pr", 1)
+ case "*image.YCbCr":
+ return strings.Replace(prefix, "var pr, pg, pb, pa", "var pr, pg, pb", 1)
+ }
+ return prefix
+ }
+ return ""
+}
+
+func expnSwitch(op, dType string, expandBoth bool, template string) string {
+ if op == "" && dType != "anyDType" {
+ lines := []string{"switch op {"}
+ for _, op = range ops {
+ lines = append(lines,
+ fmt.Sprintf("case %s:", op),
+ expnSwitch(op, dType, expandBoth, template),
+ )
+ }
+ lines = append(lines, "}")
+ return strings.Join(lines, "\n")
+ }
+
+ switchVar := "dst"
+ if dType != "" {
+ switchVar = "src"
+ }
+ lines := []string{fmt.Sprintf("switch %s := %s.(type) {", switchVar, switchVar)}
+
+ fallback, values := "Image", dTypes
+ if dType != "" {
+ fallback, values = "image.Image", sTypesForDType[dType]
+ }
+ for _, v := range values {
+ if dType != "" {
+ // v is the sType. Skip those always-opaque sTypes, where Over is
+ // equivalent to Src.
+ if op == "Over" && alwaysOpaque[v] {
+ continue
+ }
+ }
+
+ if v == fallback {
+ lines = append(lines, "default:")
+ } else {
+ lines = append(lines, fmt.Sprintf("case %s:", v))
+ }
+
+ if dType != "" {
+ if v == "*image.YCbCr" {
+ lines = append(lines, expnSwitchYCbCr(op, dType, template))
+ } else {
+ lines = append(lines, expnLine(template, &data{dType: dType, sType: v, op: op}))
+ }
+ } else if !expandBoth {
+ lines = append(lines, expnLine(template, &data{dType: v, op: op}))
+ } else {
+ lines = append(lines, expnSwitch(op, v, false, template))
+ }
+ }
+
+ lines = append(lines, "}")
+ return strings.Join(lines, "\n")
+}
+
+func expnSwitchYCbCr(op, dType, template string) string {
+ lines := []string{
+ "switch src.SubsampleRatio {",
+ "default:",
+ expnLine(template, &data{dType: dType, sType: "image.Image", op: op}),
+ }
+ for _, sratio := range subsampleRatios {
+ lines = append(lines,
+ fmt.Sprintf("case image.YCbCrSubsampleRatio%s:", sratio),
+ expnLine(template, &data{dType: dType, sType: "*image.YCbCr", sratio: sratio, op: op}),
+ )
+ }
+ lines = append(lines, "}")
+ return strings.Join(lines, "\n")
+}
+
+func argf(args []string, s string) string {
+ if len(args) > 9 {
+ panic("too many args")
+ }
+ for i, a := range args {
+ old := fmt.Sprintf("$%d", i)
+ s = strings.Replace(s, old, a, -1)
+ }
+ return s
+}
+
+func pixOffset(m, x, y, xstride, ystride string) string {
+ return fmt.Sprintf("(%s-%s.Rect.Min.Y)%s + (%s-%s.Rect.Min.X)%s", y, m, ystride, x, m, xstride)
+}
+
+func cOffset(x, y, sratio string) string {
+ switch sratio {
+ case "444":
+ return fmt.Sprintf("( %s - src.Rect.Min.Y )*src.CStride + ( %s - src.Rect.Min.X )", y, x)
+ case "422":
+ return fmt.Sprintf("( %s - src.Rect.Min.Y )*src.CStride + ((%s)/2 - src.Rect.Min.X/2)", y, x)
+ case "420":
+ return fmt.Sprintf("((%s)/2 - src.Rect.Min.Y/2)*src.CStride + ((%s)/2 - src.Rect.Min.X/2)", y, x)
+ case "440":
+ return fmt.Sprintf("((%s)/2 - src.Rect.Min.Y/2)*src.CStride + ( %s - src.Rect.Min.X )", y, x)
+ }
+ return fmt.Sprintf("unsupported sratio %q", sratio)
+}
+
+func ycbcrToRGB(lhs, tmp string) string {
+ s := `
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ $yy1 := int(src.Y[$i]) * 0x10100
+ $cb1 := int(src.Cb[$j]) - 128
+ $cr1 := int(src.Cr[$j]) - 128
+ $r@ := ($yy1 + 91881*$cr1) >> 8
+ $g@ := ($yy1 - 22554*$cb1 - 46802*$cr1) >> 8
+ $b@ := ($yy1 + 116130*$cb1) >> 8
+ if $r@ < 0 {
+ $r@ = 0
+ } else if $r@ > 0xffff {
+ $r@ = 0xffff
+ }
+ if $g@ < 0 {
+ $g@ = 0
+ } else if $g@ > 0xffff {
+ $g@ = 0xffff
+ }
+ if $b@ < 0 {
+ $b@ = 0
+ } else if $b@ > 0xffff {
+ $b@ = 0xffff
+ }
+ `
+ s = strings.Replace(s, "$", lhs, -1)
+ s = strings.Replace(s, "@", tmp, -1)
+ return s
+}
+
+func split(s, sep string) (string, string) {
+ if i := strings.Index(s, sep); i >= 0 {
+ return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
+ }
+ return "", ""
+}
+
+func splitEq(s string) (lhs, eqOp string) {
+ s = strings.TrimSpace(s)
+ if lhs, _ = split(s, ":="); lhs != "" {
+ return lhs, ":="
+ }
+ if lhs, _ = split(s, "+="); lhs != "" {
+ return lhs, "+="
+ }
+ return "", ""
+}
+
+func splitArgs(s string) (args []string, extra string) {
+ s = strings.TrimSpace(s)
+ if s == "" || s[0] != '[' {
+ return nil, ""
+ }
+ s = s[1:]
+
+ i := strings.IndexByte(s, ']')
+ if i < 0 {
+ return nil, ""
+ }
+ args, extra = strings.Split(s[:i], ","), s[i+1:]
+ for i := range args {
+ args[i] = strings.TrimSpace(args[i])
+ }
+ return args, extra
+}
+
+func relName(s string) string {
+ if i := strings.LastIndex(s, "."); i >= 0 {
+ return s[i+1:]
+ }
+ return s
+}
+
+const (
+ codeRoot = `
+ func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ // Try to simplify a Scale to a Copy.
+ if dr.Size() == sr.Size() {
+ Copy(dst, dr.Min, src, sr, op, opts)
+ return
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
+ case Src:
+ z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
+ }
+ } else if _, ok := src.(*image.Uniform); ok {
+ Draw(dst, dr, src, src.Bounds().Min, op)
+ } else {
+ $switch z.scale_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, src, sr, &o)
+ }
+ }
+
+ func (z $receiver) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ // Try to simplify a Transform to a Copy.
+ if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
+ dx := int(s2d[2])
+ dy := int(s2d[5])
+ if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
+ Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
+ return
+ }
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ dr := transformRect(&s2d, &sr)
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ d2s := invert(&s2d)
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
+ bias := transformRect(&d2s, &adr).Min
+ bias.X--
+ bias.Y--
+ d2s[2] -= float64(bias.X)
+ d2s[5] -= float64(bias.Y)
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case Src:
+ z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ } else if u, ok := src.(*image.Uniform); ok {
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ } else {
+ $switch z.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ }
+ `
+
+ codeNNScaleLeaf = `
+ func (nnInterpolator) scale_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ $preOuter
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ $preInner
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ p := $srcu[sr.Min.X + int(sx), sr.Min.Y + int(sy)]
+ $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
+ }
+ }
+ }
+ `
+
+ codeNNTransformLeaf = `
+ func (nnInterpolator) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, opts *Options) {
+ $preOuter
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y + int(dy)) + 0.5
+ $preInner
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
+ dxf := float64(dr.Min.X + int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf + d2s[1]*dyf + d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf + d2s[4]*dyf + d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ p := $srcu[sx0, sy0]
+ $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
+ }
+ }
+ }
+ `
+
+ codeABLScaleLeaf = `
+ func (ablInterpolator) scale_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, src $sType, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw - 1, sh - 1
+ $preOuter
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ $preInner
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00 := $srcf[sr.Min.X + int(sx0), sr.Min.Y + int(sy0)]
+ s10 := $srcf[sr.Min.X + int(sx1), sr.Min.Y + int(sy0)]
+ $blend[xFrac1, s00, xFrac0, s10]
+ s01 := $srcf[sr.Min.X + int(sx0), sr.Min.Y + int(sy1)]
+ s11 := $srcf[sr.Min.X + int(sx1), sr.Min.Y + int(sy1)]
+ $blend[xFrac1, s01, xFrac0, s11]
+ $blend[yFrac1, s10, yFrac0, s11]
+ $convFtou[p, s11]
+ $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
+ }
+ }
+ }
+ `
+
+ codeABLTransformLeaf = `
+ func (ablInterpolator) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, opts *Options) {
+ $preOuter
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y + int(dy)) + 0.5
+ $preInner
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
+ dxf := float64(dr.Min.X + int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00 := $srcf[sx0, sy0]
+ s10 := $srcf[sx1, sy0]
+ $blend[xFrac1, s00, xFrac0, s10]
+ s01 := $srcf[sx0, sy1]
+ s11 := $srcf[sx1, sy1]
+ $blend[xFrac1, s01, xFrac0, s11]
+ $blend[yFrac1, s10, yFrac0, s11]
+ $convFtou[p, s11]
+ $outputu[dr.Min.X + int(dx), dr.Min.Y + int(dy), p]
+ }
+ }
+ }
+ `
+
+ codeKernelRoot = `
+ func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
+ z.kernel.Scale(dst, dr, src, sr, op, opts)
+ return
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
+ Draw(dst, dr, src, src.Bounds().Min, op)
+ return
+ }
+
+ // Create a temporary buffer:
+ // scaleX distributes the source image's columns over the temporary image.
+ // scaleY distributes the temporary image's rows over the destination image.
+ var tmp [][4]float64
+ if z.pool.New != nil {
+ tmpp := z.pool.Get().(*[][4]float64)
+ defer z.pool.Put(tmpp)
+ tmp = *tmpp
+ } else {
+ tmp = z.makeTmpBuf()
+ }
+
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.SrcMask != nil || !sr.In(src.Bounds()) {
+ z.scaleX_Image(tmp, src, sr, &o)
+ } else {
+ $switchS z.scaleX_$sTypeRN$sratio(tmp, src, sr, &o)
+ }
+
+ if o.DstMask != nil {
+ switch op {
+ case Over:
+ z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
+ case Src:
+ z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
+ }
+ } else {
+ $switchD z.scaleY_$dTypeRN_$op(dst, dr, adr, tmp, &o)
+ }
+ }
+
+ func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ dr := transformRect(&s2d, &sr)
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+ d2s := invert(&s2d)
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
+ bias := transformRect(&d2s, &adr).Min
+ bias.X--
+ bias.Y--
+ d2s[2] -= float64(bias.X)
+ d2s[5] -= float64(bias.Y)
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+
+ if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ return
+ }
+
+ xscale := abs(d2s[0])
+ if s := abs(d2s[1]); xscale < s {
+ xscale = s
+ }
+ yscale := abs(d2s[3])
+ if s := abs(d2s[4]); yscale < s {
+ yscale = s
+ }
+
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case Src:
+ q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ } else {
+ $switch q.transform_$dTypeRN_$sTypeRN$sratio_$op(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ }
+ `
+
+ codeKernelScaleLeafX = `
+ func (z *kernelScaler) scaleX_$sTypeRN$sratio(tmp [][4]float64, src $sType, sr image.Rectangle, opts *Options) {
+ t := 0
+ $preKernelOuter
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64 $tweakVarP
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ p += $srcf[sr.Min.X + int(c.coord), sr.Min.Y + int(y)] * c.weight
+ }
+ $tweakPr
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF, $tweakP
+ pg * s.invTotalWeightFFFF, $tweakP
+ pb * s.invTotalWeightFFFF, $tweakP
+ pa * s.invTotalWeightFFFF, $tweakP
+ }
+ t++
+ }
+ }
+ }
+ `
+
+ codeKernelScaleLeafY = `
+ func (z *kernelScaler) scaleY_$dTypeRN_$op(dst $dType, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
+ $preOuter
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ $preKernelInner
+ for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] { $tweakDy
+ var pr, pg, pb, pa float64
+ for _, c := range z.vertical.contribs[s.i:s.j] {
+ p := &tmp[c.coord*z.dw+dx]
+ pr += p[0] * c.weight
+ pg += p[1] * c.weight
+ pb += p[2] * c.weight
+ pa += p[3] * c.weight
+ }
+ $clampToAlpha
+ $outputf[dr.Min.X + int(dx), dr.Min.Y + int(adr.Min.Y + dy), ftou, p, s.invTotalWeight]
+ $tweakD
+ }
+ }
+ }
+ `
+
+ codeKernelTransformLeaf = `
+ func (q *Kernel) transform_$dTypeRN_$sTypeRN$sratio_$op(dst $dType, dr, adr image.Rectangle, d2s *f64.Aff3, src $sType, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1 + 2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1 + 2*int(math.Ceil(yHalfWidth)))
+
+ $preOuter
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y + int(dy)) + 0.5
+ $preInner
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ { $tweakDx
+ dxf := float64(dr.Min.X + int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx - ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky - iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64 $tweakVarP
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky - iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx - ix] * yWeight; w != 0 {
+ p += $srcf[kx, ky] * w
+ }
+ }
+ }
+ }
+ $clampToAlpha
+ $outputf[dr.Min.X + int(dx), dr.Min.Y + int(dy), fffftou, p, 1]
+ }
+ }
+ }
+ `
+)
diff --git a/vendor/golang.org/x/image/draw/impl.go b/vendor/golang.org/x/image/draw/impl.go
new file mode 100644
index 000000000..d6484d734
--- /dev/null
+++ b/vendor/golang.org/x/image/draw/impl.go
@@ -0,0 +1,6668 @@
+// generated by "go run gen.go". DO NOT EDIT.
+
+package draw
+
+import (
+ "image"
+ "image/color"
+ "math"
+
+ "golang.org/x/image/math/f64"
+)
+
+func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ // Try to simplify a Scale to a Copy.
+ if dr.Size() == sr.Size() {
+ Copy(dst, dr.Min, src, sr, op, opts)
+ return
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
+ case Src:
+ z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
+ }
+ } else if _, ok := src.(*image.Uniform); ok {
+ Draw(dst, dr, src, src.Bounds().Min, op)
+ } else {
+ switch op {
+ case Over:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.NRGBA:
+ z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o)
+ case *image.RGBA:
+ z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o)
+ default:
+ z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
+ }
+ }
+ case Src:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.Gray:
+ z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr, &o)
+ case *image.NRGBA:
+ z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr, &o)
+ case *image.RGBA:
+ z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr, &o)
+ case *image.YCbCr:
+ switch src.SubsampleRatio {
+ default:
+ z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio444:
+ z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio422:
+ z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio420:
+ z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio440:
+ z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o)
+ }
+ default:
+ z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
+ }
+ }
+ }
+ }
+}
+
+func (z nnInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ // Try to simplify a Transform to a Copy.
+ if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
+ dx := int(s2d[2])
+ dy := int(s2d[5])
+ if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
+ Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
+ return
+ }
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ dr := transformRect(&s2d, &sr)
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ d2s := invert(&s2d)
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
+ bias := transformRect(&d2s, &adr).Min
+ bias.X--
+ bias.Y--
+ d2s[2] -= float64(bias.X)
+ d2s[5] -= float64(bias.Y)
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case Src:
+ z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ } else if u, ok := src.(*image.Uniform); ok {
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ } else {
+ switch op {
+ case Over:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.NRGBA:
+ z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.RGBA:
+ z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ default:
+ z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ }
+ case Src:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.Gray:
+ z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.NRGBA:
+ z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.RGBA:
+ z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.YCbCr:
+ switch src.SubsampleRatio {
+ default:
+ z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio444:
+ z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio422:
+ z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio420:
+ z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio440:
+ z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ default:
+ z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ }
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx) - src.Rect.Min.X)
+ pr := uint32(src.Pix[pi]) * 0x101
+ out := uint8(pr >> 8)
+ dst.Pix[d+0] = out
+ dst.Pix[d+1] = out
+ dst.Pix[d+2] = out
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ pr := uint32(src.Pix[pi+0]) * pa / 0xff
+ pg := uint32(src.Pix[pi+1]) * pa / 0xff
+ pb := uint32(src.Pix[pi+2]) * pa / 0xff
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ pr := uint32(src.Pix[pi+0]) * pa / 0xff
+ pg := uint32(src.Pix[pi+1]) * pa / 0xff
+ pb := uint32(src.Pix[pi+2]) * pa / 0xff
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
+ pr := uint32(src.Pix[pi+0]) * 0x101
+ pg := uint32(src.Pix[pi+1]) * 0x101
+ pb := uint32(src.Pix[pi+2]) * 0x101
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx)-src.Rect.Min.X)*4
+ pr := uint32(src.Pix[pi+0]) * 0x101
+ pg := uint32(src.Pix[pi+1]) * 0x101
+ pb := uint32(src.Pix[pi+2]) * 0x101
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
+ pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
+ pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
+ pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pi := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
+ pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ if dstMask != nil {
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ pa1 := 0xffff - pa
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+}
+
+func (nnInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ dw2 := uint64(dr.Dx()) * 2
+ dh2 := uint64(dr.Dy()) * 2
+ sw := uint64(sr.Dx())
+ sh := uint64(sr.Dy())
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (2*uint64(dy) + 1) * sh / dh2
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ sx := (2*uint64(dx) + 1) * sw / dw2
+ pr, pg, pb, pa := src.At(sr.Min.X+int(sx), sr.Min.Y+int(sy)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx), smp.Y+sr.Min.Y+int(sy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ if dstMask != nil {
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ pa1 := 0xffff - ma
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ } else {
+ dstColorRGBA64.R = uint16(pr)
+ dstColorRGBA64.G = uint16(pg)
+ dstColorRGBA64.B = uint16(pb)
+ dstColorRGBA64.A = uint16(pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
+ pr := uint32(src.Pix[pi]) * 0x101
+ out := uint8(pr >> 8)
+ dst.Pix[d+0] = out
+ dst.Pix[d+1] = out
+ dst.Pix[d+2] = out
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ pr := uint32(src.Pix[pi+0]) * pa / 0xff
+ pg := uint32(src.Pix[pi+1]) * pa / 0xff
+ pb := uint32(src.Pix[pi+2]) * pa / 0xff
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ pr := uint32(src.Pix[pi+0]) * pa / 0xff
+ pg := uint32(src.Pix[pi+1]) * pa / 0xff
+ pb := uint32(src.Pix[pi+2]) * pa / 0xff
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ pr := uint32(src.Pix[pi+0]) * 0x101
+ pg := uint32(src.Pix[pi+1]) * 0x101
+ pb := uint32(src.Pix[pi+2]) * 0x101
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ pr := uint32(src.Pix[pi+0]) * 0x101
+ pg := uint32(src.Pix[pi+1]) * 0x101
+ pb := uint32(src.Pix[pi+2]) * 0x101
+ pa := uint32(src.Pix[pi+3]) * 0x101
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ pj := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ pj := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pi := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pr := (pyy1 + 91881*pcr1) >> 8
+ pg := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pb := (pyy1 + 116130*pcb1) >> 8
+ if pr < 0 {
+ pr = 0
+ } else if pr > 0xffff {
+ pr = 0xffff
+ }
+ if pg < 0 {
+ pg = 0
+ } else if pg > 0xffff {
+ pg = 0xffff
+ }
+ if pb < 0 {
+ pb = 0
+ } else if pb > 0xffff {
+ pb = 0xffff
+ }
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (nnInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ if dstMask != nil {
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ pa1 := 0xffff - pa
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+}
+
+func (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ pr, pg, pb, pa := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ if dstMask != nil {
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ pa1 := 0xffff - ma
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ } else {
+ dstColorRGBA64.R = uint16(pr)
+ dstColorRGBA64.G = uint16(pg)
+ dstColorRGBA64.B = uint16(pb)
+ dstColorRGBA64.A = uint16(pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+ }
+}
+
+func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ // Try to simplify a Scale to a Copy.
+ if dr.Size() == sr.Size() {
+ Copy(dst, dr.Min, src, sr, op, opts)
+ return
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
+ case Src:
+ z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
+ }
+ } else if _, ok := src.(*image.Uniform); ok {
+ Draw(dst, dr, src, src.Bounds().Min, op)
+ } else {
+ switch op {
+ case Over:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.NRGBA:
+ z.scale_RGBA_NRGBA_Over(dst, dr, adr, src, sr, &o)
+ case *image.RGBA:
+ z.scale_RGBA_RGBA_Over(dst, dr, adr, src, sr, &o)
+ default:
+ z.scale_RGBA_Image_Over(dst, dr, adr, src, sr, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.scale_Image_Image_Over(dst, dr, adr, src, sr, &o)
+ }
+ }
+ case Src:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.Gray:
+ z.scale_RGBA_Gray_Src(dst, dr, adr, src, sr, &o)
+ case *image.NRGBA:
+ z.scale_RGBA_NRGBA_Src(dst, dr, adr, src, sr, &o)
+ case *image.RGBA:
+ z.scale_RGBA_RGBA_Src(dst, dr, adr, src, sr, &o)
+ case *image.YCbCr:
+ switch src.SubsampleRatio {
+ default:
+ z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio444:
+ z.scale_RGBA_YCbCr444_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio422:
+ z.scale_RGBA_YCbCr422_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio420:
+ z.scale_RGBA_YCbCr420_Src(dst, dr, adr, src, sr, &o)
+ case image.YCbCrSubsampleRatio440:
+ z.scale_RGBA_YCbCr440_Src(dst, dr, adr, src, sr, &o)
+ }
+ default:
+ z.scale_RGBA_Image_Src(dst, dr, adr, src, sr, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.scale_Image_Image_Src(dst, dr, adr, src, sr, &o)
+ }
+ }
+ }
+ }
+}
+
+func (z ablInterpolator) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ // Try to simplify a Transform to a Copy.
+ if s2d[0] == 1 && s2d[1] == 0 && s2d[3] == 0 && s2d[4] == 1 {
+ dx := int(s2d[2])
+ dy := int(s2d[5])
+ if float64(dx) == s2d[2] && float64(dy) == s2d[5] {
+ Copy(dst, image.Point{X: sr.Min.X + dx, Y: sr.Min.X + dy}, src, sr, op, opts)
+ return
+ }
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ dr := transformRect(&s2d, &sr)
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ d2s := invert(&s2d)
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
+ bias := transformRect(&d2s, &adr).Min
+ bias.X--
+ bias.Y--
+ d2s[2] -= float64(bias.X)
+ d2s[5] -= float64(bias.Y)
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case Src:
+ z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ } else if u, ok := src.(*image.Uniform); ok {
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ } else {
+ switch op {
+ case Over:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.NRGBA:
+ z.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.RGBA:
+ z.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ default:
+ z.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ }
+ case Src:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.Gray:
+ z.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.NRGBA:
+ z.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.RGBA:
+ z.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case *image.YCbCr:
+ switch src.SubsampleRatio {
+ default:
+ z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio444:
+ z.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio422:
+ z.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio420:
+ z.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ case image.YCbCrSubsampleRatio440:
+ z.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ default:
+ z.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ z.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, &o)
+ }
+ }
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.Gray, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s00ru := uint32(src.Pix[s00i]) * 0x101
+ s00r := float64(s00ru)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s10ru := uint32(src.Pix[s10i]) * 0x101
+ s10r := float64(s10ru)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s01ru := uint32(src.Pix[s01i]) * 0x101
+ s01r := float64(s01ru)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s11ru := uint32(src.Pix[s11i]) * 0x101
+ s11r := float64(s11ru)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11r = yFrac1*s10r + yFrac0*s11r
+ pr := uint32(s11r)
+ out := uint8(pr >> 8)
+ dst.Pix[d+0] = out
+ dst.Pix[d+1] = out
+ dst.Pix[d+2] = out
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
+ s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
+ s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
+ s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
+ s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
+ s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
+ s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
+ s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
+ s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.NRGBA, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
+ s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
+ s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
+ s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
+ s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
+ s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
+ s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
+ s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
+ s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s00ru := uint32(src.Pix[s00i+0]) * 0x101
+ s00gu := uint32(src.Pix[s00i+1]) * 0x101
+ s00bu := uint32(src.Pix[s00i+2]) * 0x101
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s10ru := uint32(src.Pix[s10i+0]) * 0x101
+ s10gu := uint32(src.Pix[s10i+1]) * 0x101
+ s10bu := uint32(src.Pix[s10i+2]) * 0x101
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s01ru := uint32(src.Pix[s01i+0]) * 0x101
+ s01gu := uint32(src.Pix[s01i+1]) * 0x101
+ s01bu := uint32(src.Pix[s01i+2]) * 0x101
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s11ru := uint32(src.Pix[s11i+0]) * 0x101
+ s11gu := uint32(src.Pix[s11i+1]) * 0x101
+ s11bu := uint32(src.Pix[s11i+2]) * 0x101
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.RGBA, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s00ru := uint32(src.Pix[s00i+0]) * 0x101
+ s00gu := uint32(src.Pix[s00i+1]) * 0x101
+ s00bu := uint32(src.Pix[s00i+2]) * 0x101
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s10ru := uint32(src.Pix[s10i+0]) * 0x101
+ s10gu := uint32(src.Pix[s10i+1]) * 0x101
+ s10bu := uint32(src.Pix[s10i+2]) * 0x101
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx0)-src.Rect.Min.X)*4
+ s01ru := uint32(src.Pix[s01i+0]) * 0x101
+ s01gu := uint32(src.Pix[s01i+1]) * 0x101
+ s01bu := uint32(src.Pix[s01i+2]) * 0x101
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(sx1)-src.Rect.Min.X)*4
+ s11ru := uint32(src.Pix[s11i+0]) * 0x101
+ s11gu := uint32(src.Pix[s11i+1]) * 0x101
+ s11bu := uint32(src.Pix[s11i+2]) * 0x101
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+ s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+ s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) scale_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) scale_Image_Image_Over(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ if dstMask != nil {
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ pa1 := 0xffff - pa
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+}
+
+func (ablInterpolator) scale_Image_Image_Src(dst Image, dr, adr image.Rectangle, src image.Image, sr image.Rectangle, opts *Options) {
+ sw := int32(sr.Dx())
+ sh := int32(sr.Dy())
+ yscale := float64(sh) / float64(dr.Dy())
+ xscale := float64(sw) / float64(dr.Dx())
+ swMinus1, shMinus1 := sw-1, sh-1
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ sy := (float64(dy)+0.5)*yscale - 0.5
+ // If sy < 0, we will clamp sy0 to 0 anyway, so it doesn't matter if
+ // we say int32(sy) instead of int32(math.Floor(sy)). Similarly for
+ // sx, below.
+ sy0 := int32(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy1 := sy0 + 1
+ if sy < 0 {
+ sy0, sy1 = 0, 0
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 > shMinus1 {
+ sy0, sy1 = shMinus1, shMinus1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ sx := (float64(dx)+0.5)*xscale - 0.5
+ sx0 := int32(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx1 := sx0 + 1
+ if sx < 0 {
+ sx0, sx1 = 0, 0
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 > swMinus1 {
+ sx0, sx1 = swMinus1, swMinus1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy0)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy0)).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sr.Min.X+int(sx0), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx0), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sr.Min.X+int(sx1), sr.Min.Y+int(sy1)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(sx1), smp.Y+sr.Min.Y+int(sy1)).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ if dstMask != nil {
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ pa1 := 0xffff - ma
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ } else {
+ dstColorRGBA64.R = uint16(pr)
+ dstColorRGBA64.G = uint16(pg)
+ dstColorRGBA64.B = uint16(pb)
+ dstColorRGBA64.A = uint16(pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
+ s00ru := uint32(src.Pix[s00i]) * 0x101
+ s00r := float64(s00ru)
+ s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
+ s10ru := uint32(src.Pix[s10i]) * 0x101
+ s10r := float64(s10ru)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0 - src.Rect.Min.X)
+ s01ru := uint32(src.Pix[s01i]) * 0x101
+ s01r := float64(s01ru)
+ s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1 - src.Rect.Min.X)
+ s11ru := uint32(src.Pix[s11i]) * 0x101
+ s11r := float64(s11ru)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11r = yFrac1*s10r + yFrac0*s11r
+ pr := uint32(s11r)
+ out := uint8(pr >> 8)
+ dst.Pix[d+0] = out
+ dst.Pix[d+1] = out
+ dst.Pix[d+2] = out
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
+ s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
+ s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
+ s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
+ s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
+ s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
+ s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
+ s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
+ s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00ru := uint32(src.Pix[s00i+0]) * s00au / 0xff
+ s00gu := uint32(src.Pix[s00i+1]) * s00au / 0xff
+ s00bu := uint32(src.Pix[s00i+2]) * s00au / 0xff
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10ru := uint32(src.Pix[s10i+0]) * s10au / 0xff
+ s10gu := uint32(src.Pix[s10i+1]) * s10au / 0xff
+ s10bu := uint32(src.Pix[s10i+2]) * s10au / 0xff
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01ru := uint32(src.Pix[s01i+0]) * s01au / 0xff
+ s01gu := uint32(src.Pix[s01i+1]) * s01au / 0xff
+ s01bu := uint32(src.Pix[s01i+2]) * s01au / 0xff
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11ru := uint32(src.Pix[s11i+0]) * s11au / 0xff
+ s11gu := uint32(src.Pix[s11i+1]) * s11au / 0xff
+ s11bu := uint32(src.Pix[s11i+2]) * s11au / 0xff
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s00ru := uint32(src.Pix[s00i+0]) * 0x101
+ s00gu := uint32(src.Pix[s00i+1]) * 0x101
+ s00bu := uint32(src.Pix[s00i+2]) * 0x101
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s10ru := uint32(src.Pix[s10i+0]) * 0x101
+ s10gu := uint32(src.Pix[s10i+1]) * 0x101
+ s10bu := uint32(src.Pix[s10i+2]) * 0x101
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s01ru := uint32(src.Pix[s01i+0]) * 0x101
+ s01gu := uint32(src.Pix[s01i+1]) * 0x101
+ s01bu := uint32(src.Pix[s01i+2]) * 0x101
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s11ru := uint32(src.Pix[s11i+0]) * 0x101
+ s11gu := uint32(src.Pix[s11i+1]) * 0x101
+ s11bu := uint32(src.Pix[s11i+2]) * 0x101
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s00ru := uint32(src.Pix[s00i+0]) * 0x101
+ s00gu := uint32(src.Pix[s00i+1]) * 0x101
+ s00bu := uint32(src.Pix[s00i+2]) * 0x101
+ s00au := uint32(src.Pix[s00i+3]) * 0x101
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10i := (sy0-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s10ru := uint32(src.Pix[s10i+0]) * 0x101
+ s10gu := uint32(src.Pix[s10i+1]) * 0x101
+ s10bu := uint32(src.Pix[s10i+2]) * 0x101
+ s10au := uint32(src.Pix[s10i+3]) * 0x101
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01i := (sy1-src.Rect.Min.Y)*src.Stride + (sx0-src.Rect.Min.X)*4
+ s01ru := uint32(src.Pix[s01i+0]) * 0x101
+ s01gu := uint32(src.Pix[s01i+1]) * 0x101
+ s01bu := uint32(src.Pix[s01i+2]) * 0x101
+ s01au := uint32(src.Pix[s01i+3]) * 0x101
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11i := (sy1-src.Rect.Min.Y)*src.Stride + (sx1-src.Rect.Min.X)*4
+ s11ru := uint32(src.Pix[s11i+0]) * 0x101
+ s11gu := uint32(src.Pix[s11i+1]) * 0x101
+ s11bu := uint32(src.Pix[s11i+2]) * 0x101
+ s11au := uint32(src.Pix[s11i+3]) * 0x101
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s00j := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s10j := (sy0-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s01j := (sy1-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s11j := (sy1-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s00j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s10j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s01j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s11j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00i := (sy0-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s00yy1 := int(src.Y[s00i]) * 0x10100
+ s00cb1 := int(src.Cb[s00j]) - 128
+ s00cr1 := int(src.Cr[s00j]) - 128
+ s00ru := (s00yy1 + 91881*s00cr1) >> 8
+ s00gu := (s00yy1 - 22554*s00cb1 - 46802*s00cr1) >> 8
+ s00bu := (s00yy1 + 116130*s00cb1) >> 8
+ if s00ru < 0 {
+ s00ru = 0
+ } else if s00ru > 0xffff {
+ s00ru = 0xffff
+ }
+ if s00gu < 0 {
+ s00gu = 0
+ } else if s00gu > 0xffff {
+ s00gu = 0xffff
+ }
+ if s00bu < 0 {
+ s00bu = 0
+ } else if s00bu > 0xffff {
+ s00bu = 0xffff
+ }
+
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s10i := (sy0-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s10yy1 := int(src.Y[s10i]) * 0x10100
+ s10cb1 := int(src.Cb[s10j]) - 128
+ s10cr1 := int(src.Cr[s10j]) - 128
+ s10ru := (s10yy1 + 91881*s10cr1) >> 8
+ s10gu := (s10yy1 - 22554*s10cb1 - 46802*s10cr1) >> 8
+ s10bu := (s10yy1 + 116130*s10cb1) >> 8
+ if s10ru < 0 {
+ s10ru = 0
+ } else if s10ru > 0xffff {
+ s10ru = 0xffff
+ }
+ if s10gu < 0 {
+ s10gu = 0
+ } else if s10gu > 0xffff {
+ s10gu = 0xffff
+ }
+ if s10bu < 0 {
+ s10bu = 0
+ } else if s10bu > 0xffff {
+ s10bu = 0xffff
+ }
+
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s01i := (sy1-src.Rect.Min.Y)*src.YStride + (sx0 - src.Rect.Min.X)
+ s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s01yy1 := int(src.Y[s01i]) * 0x10100
+ s01cb1 := int(src.Cb[s01j]) - 128
+ s01cr1 := int(src.Cr[s01j]) - 128
+ s01ru := (s01yy1 + 91881*s01cr1) >> 8
+ s01gu := (s01yy1 - 22554*s01cb1 - 46802*s01cr1) >> 8
+ s01bu := (s01yy1 + 116130*s01cb1) >> 8
+ if s01ru < 0 {
+ s01ru = 0
+ } else if s01ru > 0xffff {
+ s01ru = 0xffff
+ }
+ if s01gu < 0 {
+ s01gu = 0
+ } else if s01gu > 0xffff {
+ s01gu = 0xffff
+ }
+ if s01bu < 0 {
+ s01bu = 0
+ } else if s01bu > 0xffff {
+ s01bu = 0xffff
+ }
+
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s11i := (sy1-src.Rect.Min.Y)*src.YStride + (sx1 - src.Rect.Min.X)
+ s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ s11yy1 := int(src.Y[s11i]) * 0x10100
+ s11cb1 := int(src.Cb[s11j]) - 128
+ s11cr1 := int(src.Cr[s11j]) - 128
+ s11ru := (s11yy1 + 91881*s11cr1) >> 8
+ s11gu := (s11yy1 - 22554*s11cb1 - 46802*s11cr1) >> 8
+ s11bu := (s11yy1 + 116130*s11cb1) >> 8
+ if s11ru < 0 {
+ s11ru = 0
+ } else if s11ru > 0xffff {
+ s11ru = 0xffff
+ }
+ if s11gu < 0 {
+ s11gu = 0
+ } else if s11gu > 0xffff {
+ s11gu = 0xffff
+ }
+ if s11bu < 0 {
+ s11bu = 0
+ } else if s11bu > 0xffff {
+ s11bu = 0xffff
+ }
+
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ pa1 := (0xffff - pa) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ dst.Pix[d+0] = uint8(pr >> 8)
+ dst.Pix[d+1] = uint8(pg >> 8)
+ dst.Pix[d+2] = uint8(pb >> 8)
+ dst.Pix[d+3] = uint8(pa >> 8)
+ }
+ }
+}
+
+func (ablInterpolator) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ if dstMask != nil {
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ }
+ pa1 := 0xffff - pa
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+}
+
+func (ablInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, opts *Options) {
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ sx -= 0.5
+ sx0 := int(sx)
+ xFrac0 := sx - float64(sx0)
+ xFrac1 := 1 - xFrac0
+ sx0 += bias.X
+ sx1 := sx0 + 1
+ if sx0 < sr.Min.X {
+ sx0, sx1 = sr.Min.X, sr.Min.X
+ xFrac0, xFrac1 = 0, 1
+ } else if sx1 >= sr.Max.X {
+ sx0, sx1 = sr.Max.X-1, sr.Max.X-1
+ xFrac0, xFrac1 = 1, 0
+ }
+
+ sy -= 0.5
+ sy0 := int(sy)
+ yFrac0 := sy - float64(sy0)
+ yFrac1 := 1 - yFrac0
+ sy0 += bias.Y
+ sy1 := sy0 + 1
+ if sy0 < sr.Min.Y {
+ sy0, sy1 = sr.Min.Y, sr.Min.Y
+ yFrac0, yFrac1 = 0, 1
+ } else if sy1 >= sr.Max.Y {
+ sy0, sy1 = sr.Max.Y-1, sr.Max.Y-1
+ yFrac0, yFrac1 = 1, 0
+ }
+
+ s00ru, s00gu, s00bu, s00au := src.At(sx0, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy0).RGBA()
+ s00ru = s00ru * ma / 0xffff
+ s00gu = s00gu * ma / 0xffff
+ s00bu = s00bu * ma / 0xffff
+ s00au = s00au * ma / 0xffff
+ }
+ s00r := float64(s00ru)
+ s00g := float64(s00gu)
+ s00b := float64(s00bu)
+ s00a := float64(s00au)
+ s10ru, s10gu, s10bu, s10au := src.At(sx1, sy0).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy0).RGBA()
+ s10ru = s10ru * ma / 0xffff
+ s10gu = s10gu * ma / 0xffff
+ s10bu = s10bu * ma / 0xffff
+ s10au = s10au * ma / 0xffff
+ }
+ s10r := float64(s10ru)
+ s10g := float64(s10gu)
+ s10b := float64(s10bu)
+ s10a := float64(s10au)
+ s10r = xFrac1*s00r + xFrac0*s10r
+ s10g = xFrac1*s00g + xFrac0*s10g
+ s10b = xFrac1*s00b + xFrac0*s10b
+ s10a = xFrac1*s00a + xFrac0*s10a
+ s01ru, s01gu, s01bu, s01au := src.At(sx0, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx0, smp.Y+sy1).RGBA()
+ s01ru = s01ru * ma / 0xffff
+ s01gu = s01gu * ma / 0xffff
+ s01bu = s01bu * ma / 0xffff
+ s01au = s01au * ma / 0xffff
+ }
+ s01r := float64(s01ru)
+ s01g := float64(s01gu)
+ s01b := float64(s01bu)
+ s01a := float64(s01au)
+ s11ru, s11gu, s11bu, s11au := src.At(sx1, sy1).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sx1, smp.Y+sy1).RGBA()
+ s11ru = s11ru * ma / 0xffff
+ s11gu = s11gu * ma / 0xffff
+ s11bu = s11bu * ma / 0xffff
+ s11au = s11au * ma / 0xffff
+ }
+ s11r := float64(s11ru)
+ s11g := float64(s11gu)
+ s11b := float64(s11bu)
+ s11a := float64(s11au)
+ s11r = xFrac1*s01r + xFrac0*s11r
+ s11g = xFrac1*s01g + xFrac0*s11g
+ s11b = xFrac1*s01b + xFrac0*s11b
+ s11a = xFrac1*s01a + xFrac0*s11a
+ s11r = yFrac1*s10r + yFrac0*s11r
+ s11g = yFrac1*s10g + yFrac0*s11g
+ s11b = yFrac1*s10b + yFrac0*s11b
+ s11a = yFrac1*s10a + yFrac0*s11a
+ pr := uint32(s11r)
+ pg := uint32(s11g)
+ pb := uint32(s11b)
+ pa := uint32(s11a)
+ if dstMask != nil {
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr = pr * ma / 0xffff
+ pg = pg * ma / 0xffff
+ pb = pb * ma / 0xffff
+ pa = pa * ma / 0xffff
+ pa1 := 0xffff - ma
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ } else {
+ dstColorRGBA64.R = uint16(pr)
+ dstColorRGBA64.G = uint16(pg)
+ dstColorRGBA64.B = uint16(pb)
+ dstColorRGBA64.A = uint16(pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+ }
+}
+
+func (z *kernelScaler) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ if z.dw != int32(dr.Dx()) || z.dh != int32(dr.Dy()) || z.sw != int32(sr.Dx()) || z.sh != int32(sr.Dy()) {
+ z.kernel.Scale(dst, dr, src, sr, op, opts)
+ return
+ }
+
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+
+ if _, ok := src.(*image.Uniform); ok && o.DstMask == nil && o.SrcMask == nil && sr.In(src.Bounds()) {
+ Draw(dst, dr, src, src.Bounds().Min, op)
+ return
+ }
+
+ // Create a temporary buffer:
+ // scaleX distributes the source image's columns over the temporary image.
+ // scaleY distributes the temporary image's rows over the destination image.
+ var tmp [][4]float64
+ if z.pool.New != nil {
+ tmpp := z.pool.Get().(*[][4]float64)
+ defer z.pool.Put(tmpp)
+ tmp = *tmpp
+ } else {
+ tmp = z.makeTmpBuf()
+ }
+
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.SrcMask != nil || !sr.In(src.Bounds()) {
+ z.scaleX_Image(tmp, src, sr, &o)
+ } else {
+ switch src := src.(type) {
+ case *image.Gray:
+ z.scaleX_Gray(tmp, src, sr, &o)
+ case *image.NRGBA:
+ z.scaleX_NRGBA(tmp, src, sr, &o)
+ case *image.RGBA:
+ z.scaleX_RGBA(tmp, src, sr, &o)
+ case *image.YCbCr:
+ switch src.SubsampleRatio {
+ default:
+ z.scaleX_Image(tmp, src, sr, &o)
+ case image.YCbCrSubsampleRatio444:
+ z.scaleX_YCbCr444(tmp, src, sr, &o)
+ case image.YCbCrSubsampleRatio422:
+ z.scaleX_YCbCr422(tmp, src, sr, &o)
+ case image.YCbCrSubsampleRatio420:
+ z.scaleX_YCbCr420(tmp, src, sr, &o)
+ case image.YCbCrSubsampleRatio440:
+ z.scaleX_YCbCr440(tmp, src, sr, &o)
+ }
+ default:
+ z.scaleX_Image(tmp, src, sr, &o)
+ }
+ }
+
+ if o.DstMask != nil {
+ switch op {
+ case Over:
+ z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
+ case Src:
+ z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
+ }
+ } else {
+ switch op {
+ case Over:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ z.scaleY_RGBA_Over(dst, dr, adr, tmp, &o)
+ default:
+ z.scaleY_Image_Over(dst, dr, adr, tmp, &o)
+ }
+ case Src:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ z.scaleY_RGBA_Src(dst, dr, adr, tmp, &o)
+ default:
+ z.scaleY_Image_Src(dst, dr, adr, tmp, &o)
+ }
+ }
+ }
+}
+
+func (q *Kernel) Transform(dst Image, s2d f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+
+ dr := transformRect(&s2d, &sr)
+ // adr is the affected destination pixels.
+ adr := dst.Bounds().Intersect(dr)
+ adr, o.DstMask = clipAffectedDestRect(adr, o.DstMask, o.DstMaskP)
+ if adr.Empty() || sr.Empty() {
+ return
+ }
+ if op == Over && o.SrcMask == nil && opaque(src) {
+ op = Src
+ }
+ d2s := invert(&s2d)
+ // bias is a translation of the mapping from dst coordinates to src
+ // coordinates such that the latter temporarily have non-negative X
+ // and Y coordinates. This allows us to write int(f) instead of
+ // int(math.Floor(f)), since "round to zero" and "round down" are
+ // equivalent when f >= 0, but the former is much cheaper. The X--
+ // and Y-- are because the TransformLeaf methods have a "sx -= 0.5"
+ // adjustment.
+ bias := transformRect(&d2s, &adr).Min
+ bias.X--
+ bias.Y--
+ d2s[2] -= float64(bias.X)
+ d2s[5] -= float64(bias.Y)
+ // Make adr relative to dr.Min.
+ adr = adr.Sub(dr.Min)
+
+ if u, ok := src.(*image.Uniform); ok && o.DstMask != nil && o.SrcMask != nil && sr.In(src.Bounds()) {
+ transform_Uniform(dst, dr, adr, &d2s, u, sr, bias, op)
+ return
+ }
+
+ xscale := abs(d2s[0])
+ if s := abs(d2s[1]); xscale < s {
+ xscale = s
+ }
+ yscale := abs(d2s[3])
+ if s := abs(d2s[4]); yscale < s {
+ yscale = s
+ }
+
+ // sr is the source pixels. If it extends beyond the src bounds,
+ // we cannot use the type-specific fast paths, as they access
+ // the Pix fields directly without bounds checking.
+ //
+ // Similarly, the fast paths assume that the masks are nil.
+ if o.DstMask != nil || o.SrcMask != nil || !sr.In(src.Bounds()) {
+ switch op {
+ case Over:
+ q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case Src:
+ q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ } else {
+ switch op {
+ case Over:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.NRGBA:
+ q.transform_RGBA_NRGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case *image.RGBA:
+ q.transform_RGBA_RGBA_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ default:
+ q.transform_RGBA_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ q.transform_Image_Image_Over(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ }
+ case Src:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ switch src := src.(type) {
+ case *image.Gray:
+ q.transform_RGBA_Gray_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case *image.NRGBA:
+ q.transform_RGBA_NRGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case *image.RGBA:
+ q.transform_RGBA_RGBA_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case *image.YCbCr:
+ switch src.SubsampleRatio {
+ default:
+ q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case image.YCbCrSubsampleRatio444:
+ q.transform_RGBA_YCbCr444_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case image.YCbCrSubsampleRatio422:
+ q.transform_RGBA_YCbCr422_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case image.YCbCrSubsampleRatio420:
+ q.transform_RGBA_YCbCr420_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ case image.YCbCrSubsampleRatio440:
+ q.transform_RGBA_YCbCr440_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ default:
+ q.transform_RGBA_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ default:
+ switch src := src.(type) {
+ default:
+ q.transform_Image_Image_Src(dst, dr, adr, &d2s, src, sr, bias, xscale, yscale, &o)
+ }
+ }
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_Gray(tmp [][4]float64, src *image.Gray, sr image.Rectangle, opts *Options) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
+ pru := uint32(src.Pix[pi]) * 0x101
+ pr += float64(pru) * c.weight
+ }
+ pr *= s.invTotalWeightFFFF
+ tmp[t] = [4]float64{
+ pr,
+ pr,
+ pr,
+ 1,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_NRGBA(tmp [][4]float64, src *image.NRGBA, sr image.Rectangle, opts *Options) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pru := uint32(src.Pix[pi+0]) * pau / 0xff
+ pgu := uint32(src.Pix[pi+1]) * pau / 0xff
+ pbu := uint32(src.Pix[pi+2]) * pau / 0xff
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_RGBA(tmp [][4]float64, src *image.RGBA, sr image.Rectangle, opts *Options) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.Stride + (sr.Min.X+int(c.coord)-src.Rect.Min.X)*4
+ pru := uint32(src.Pix[pi+0]) * 0x101
+ pgu := uint32(src.Pix[pi+1]) * 0x101
+ pbu := uint32(src.Pix[pi+2]) * 0x101
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr444(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
+ pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ 1,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr422(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
+ pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ 1,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr420(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
+ pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ 1,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr image.Rectangle, opts *Options) {
+ t := 0
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pi := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.YStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
+ pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ 1,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleX_Image(tmp [][4]float64, src image.Image, sr image.Rectangle, opts *Options) {
+ t := 0
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ for y := int32(0); y < z.sh; y++ {
+ for _, s := range z.horizontal.sources {
+ var pr, pg, pb, pa float64
+ for _, c := range z.horizontal.contribs[s.i:s.j] {
+ pru, pgu, pbu, pau := src.At(sr.Min.X+int(c.coord), sr.Min.Y+int(y)).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+sr.Min.X+int(c.coord), smp.Y+sr.Min.Y+int(y)).RGBA()
+ pru = pru * ma / 0xffff
+ pgu = pgu * ma / 0xffff
+ pbu = pbu * ma / 0xffff
+ pau = pau * ma / 0xffff
+ }
+ pr += float64(pru) * c.weight
+ pg += float64(pgu) * c.weight
+ pb += float64(pbu) * c.weight
+ pa += float64(pau) * c.weight
+ }
+ tmp[t] = [4]float64{
+ pr * s.invTotalWeightFFFF,
+ pg * s.invTotalWeightFFFF,
+ pb * s.invTotalWeightFFFF,
+ pa * s.invTotalWeightFFFF,
+ }
+ t++
+ }
+ }
+}
+
+func (z *kernelScaler) scaleY_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
+ for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
+ var pr, pg, pb, pa float64
+ for _, c := range z.vertical.contribs[s.i:s.j] {
+ p := &tmp[c.coord*z.dw+dx]
+ pr += p[0] * c.weight
+ pg += p[1] * c.weight
+ pb += p[2] * c.weight
+ pa += p[3] * c.weight
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ pr0 := uint32(ftou(pr * s.invTotalWeight))
+ pg0 := uint32(ftou(pg * s.invTotalWeight))
+ pb0 := uint32(ftou(pb * s.invTotalWeight))
+ pa0 := uint32(ftou(pa * s.invTotalWeight))
+ pa1 := (0xffff - uint32(pa0)) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
+ d += dst.Stride
+ }
+ }
+}
+
+func (z *kernelScaler) scaleY_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ d := (dr.Min.Y+adr.Min.Y-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+int(dx)-dst.Rect.Min.X)*4
+ for _, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
+ var pr, pg, pb, pa float64
+ for _, c := range z.vertical.contribs[s.i:s.j] {
+ p := &tmp[c.coord*z.dw+dx]
+ pr += p[0] * c.weight
+ pg += p[1] * c.weight
+ pb += p[2] * c.weight
+ pa += p[3] * c.weight
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ dst.Pix[d+0] = uint8(ftou(pr*s.invTotalWeight) >> 8)
+ dst.Pix[d+1] = uint8(ftou(pg*s.invTotalWeight) >> 8)
+ dst.Pix[d+2] = uint8(ftou(pb*s.invTotalWeight) >> 8)
+ dst.Pix[d+3] = uint8(ftou(pa*s.invTotalWeight) >> 8)
+ d += dst.Stride
+ }
+ }
+}
+
+func (z *kernelScaler) scaleY_Image_Over(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
+ var pr, pg, pb, pa float64
+ for _, c := range z.vertical.contribs[s.i:s.j] {
+ p := &tmp[c.coord*z.dw+dx]
+ pr += p[0] * c.weight
+ pg += p[1] * c.weight
+ pb += p[2] * c.weight
+ pa += p[3] * c.weight
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
+ pr0 := uint32(ftou(pr * s.invTotalWeight))
+ pg0 := uint32(ftou(pg * s.invTotalWeight))
+ pb0 := uint32(ftou(pb * s.invTotalWeight))
+ pa0 := uint32(ftou(pa * s.invTotalWeight))
+ if dstMask != nil {
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
+ pr0 = pr0 * ma / 0xffff
+ pg0 = pg0 * ma / 0xffff
+ pb0 = pb0 * ma / 0xffff
+ pa0 = pa0 * ma / 0xffff
+ }
+ pa1 := 0xffff - pa0
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
+ }
+ }
+}
+
+func (z *kernelScaler) scaleY_Image_Src(dst Image, dr, adr image.Rectangle, tmp [][4]float64, opts *Options) {
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ for dy, s := range z.vertical.sources[adr.Min.Y:adr.Max.Y] {
+ var pr, pg, pb, pa float64
+ for _, c := range z.vertical.contribs[s.i:s.j] {
+ p := &tmp[c.coord*z.dw+dx]
+ pr += p[0] * c.weight
+ pg += p[1] * c.weight
+ pb += p[2] * c.weight
+ pa += p[3] * c.weight
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ if dstMask != nil {
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(adr.Min.Y+dy)).RGBA()
+ pr := uint32(ftou(pr*s.invTotalWeight)) * ma / 0xffff
+ pg := uint32(ftou(pg*s.invTotalWeight)) * ma / 0xffff
+ pb := uint32(ftou(pb*s.invTotalWeight)) * ma / 0xffff
+ pa := uint32(ftou(pa*s.invTotalWeight)) * ma / 0xffff
+ pa1 := 0xffff - ma
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
+ } else {
+ dstColorRGBA64.R = ftou(pr * s.invTotalWeight)
+ dstColorRGBA64.G = ftou(pg * s.invTotalWeight)
+ dstColorRGBA64.B = ftou(pb * s.invTotalWeight)
+ dstColorRGBA64.A = ftou(pa * s.invTotalWeight)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(adr.Min.Y+dy), dstColor)
+ }
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_Gray_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Gray, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.Stride + (kx - src.Rect.Min.X)
+ pru := uint32(src.Pix[pi]) * 0x101
+ pr += float64(pru) * w
+ }
+ }
+ }
+ }
+ out := uint8(fffftou(pr) >> 8)
+ dst.Pix[d+0] = out
+ dst.Pix[d+1] = out
+ dst.Pix[d+2] = out
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_NRGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pru := uint32(src.Pix[pi+0]) * pau / 0xff
+ pgu := uint32(src.Pix[pi+1]) * pau / 0xff
+ pbu := uint32(src.Pix[pi+2]) * pau / 0xff
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ pr0 := uint32(fffftou(pr))
+ pg0 := uint32(fffftou(pg))
+ pb0 := uint32(fffftou(pb))
+ pa0 := uint32(fffftou(pa))
+ pa1 := (0xffff - uint32(pa0)) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_NRGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.NRGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pru := uint32(src.Pix[pi+0]) * pau / 0xff
+ pgu := uint32(src.Pix[pi+1]) * pau / 0xff
+ pbu := uint32(src.Pix[pi+2]) * pau / 0xff
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_RGBA_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
+ pru := uint32(src.Pix[pi+0]) * 0x101
+ pgu := uint32(src.Pix[pi+1]) * 0x101
+ pbu := uint32(src.Pix[pi+2]) * 0x101
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ pr0 := uint32(fffftou(pr))
+ pg0 := uint32(fffftou(pg))
+ pb0 := uint32(fffftou(pb))
+ pa0 := uint32(fffftou(pa))
+ pa1 := (0xffff - uint32(pa0)) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_RGBA_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.RGBA, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.Stride + (kx-src.Rect.Min.X)*4
+ pru := uint32(src.Pix[pi+0]) * 0x101
+ pgu := uint32(src.Pix[pi+1]) * 0x101
+ pbu := uint32(src.Pix[pi+2]) * 0x101
+ pau := uint32(src.Pix[pi+3]) * 0x101
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
+ pj := (ky-src.Rect.Min.Y)*src.CStride + (kx - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ }
+ }
+ }
+ }
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
+ pj := (ky-src.Rect.Min.Y)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ }
+ }
+ }
+ }
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
+ pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ }
+ }
+ }
+ }
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.YCbCr, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pi := (ky-src.Rect.Min.Y)*src.YStride + (kx - src.Rect.Min.X)
+ pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + (kx - src.Rect.Min.X)
+
+ // This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
+ pyy1 := int(src.Y[pi]) * 0x10100
+ pcb1 := int(src.Cb[pj]) - 128
+ pcr1 := int(src.Cr[pj]) - 128
+ pru := (pyy1 + 91881*pcr1) >> 8
+ pgu := (pyy1 - 22554*pcb1 - 46802*pcr1) >> 8
+ pbu := (pyy1 + 116130*pcb1) >> 8
+ if pru < 0 {
+ pru = 0
+ } else if pru > 0xffff {
+ pru = 0xffff
+ }
+ if pgu < 0 {
+ pgu = 0
+ } else if pgu > 0xffff {
+ pgu = 0xffff
+ }
+ if pbu < 0 {
+ pbu = 0
+ } else if pbu > 0xffff {
+ pbu = 0xffff
+ }
+
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ }
+ }
+ }
+ }
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = 0xff
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_Image_Over(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ pr0 := uint32(fffftou(pr))
+ pg0 := uint32(fffftou(pg))
+ pb0 := uint32(fffftou(pb))
+ pa0 := uint32(fffftou(pa))
+ pa1 := (0xffff - uint32(pa0)) * 0x101
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr0) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg0) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb0) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa0) >> 8)
+ }
+ }
+}
+
+func (q *Kernel) transform_RGBA_Image_Src(dst *image.RGBA, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := (dr.Min.Y+int(dy)-dst.Rect.Min.Y)*dst.Stride + (dr.Min.X+adr.Min.X-dst.Rect.Min.X)*4
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ dst.Pix[d+0] = uint8(fffftou(pr) >> 8)
+ dst.Pix[d+1] = uint8(fffftou(pg) >> 8)
+ dst.Pix[d+2] = uint8(fffftou(pb) >> 8)
+ dst.Pix[d+3] = uint8(fffftou(pa) >> 8)
+ }
+ }
+}
+
+func (q *Kernel) transform_Image_Image_Over(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
+ pru = pru * ma / 0xffff
+ pgu = pgu * ma / 0xffff
+ pbu = pbu * ma / 0xffff
+ pau = pau * ma / 0xffff
+ }
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ pr0 := uint32(fffftou(pr))
+ pg0 := uint32(fffftou(pg))
+ pb0 := uint32(fffftou(pb))
+ pa0 := uint32(fffftou(pa))
+ if dstMask != nil {
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr0 = pr0 * ma / 0xffff
+ pg0 = pg0 * ma / 0xffff
+ pb0 = pb0 * ma / 0xffff
+ pa0 = pa0 * ma / 0xffff
+ }
+ pa1 := 0xffff - pa0
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr0)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg0)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb0)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa0)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+}
+
+func (q *Kernel) transform_Image_Image_Src(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src image.Image, sr image.Rectangle, bias image.Point, xscale, yscale float64, opts *Options) {
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ xHalfWidth, xKernelArgScale := q.Support, 1.0
+ if xscale > 1 {
+ xHalfWidth *= xscale
+ xKernelArgScale = 1 / xscale
+ }
+ yHalfWidth, yKernelArgScale := q.Support, 1.0
+ if yscale > 1 {
+ yHalfWidth *= yscale
+ yKernelArgScale = 1 / yscale
+ }
+
+ xWeights := make([]float64, 1+2*int(math.Ceil(xHalfWidth)))
+ yWeights := make([]float64, 1+2*int(math.Ceil(yHalfWidth)))
+
+ srcMask, smp := opts.SrcMask, opts.SrcMaskP
+ dstMask, dmp := opts.DstMask, opts.DstMaskP
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx := d2s[0]*dxf + d2s[1]*dyf + d2s[2]
+ sy := d2s[3]*dxf + d2s[4]*dyf + d2s[5]
+ if !(image.Point{int(sx) + bias.X, int(sy) + bias.Y}).In(sr) {
+ continue
+ }
+
+ // TODO: adjust the bias so that we can use int(f) instead
+ // of math.Floor(f) and math.Ceil(f).
+ sx += float64(bias.X)
+ sx -= 0.5
+ ix := int(math.Floor(sx - xHalfWidth))
+ if ix < sr.Min.X {
+ ix = sr.Min.X
+ }
+ jx := int(math.Ceil(sx + xHalfWidth))
+ if jx > sr.Max.X {
+ jx = sr.Max.X
+ }
+
+ totalXWeight := 0.0
+ for kx := ix; kx < jx; kx++ {
+ xWeight := 0.0
+ if t := abs((sx - float64(kx)) * xKernelArgScale); t < q.Support {
+ xWeight = q.At(t)
+ }
+ xWeights[kx-ix] = xWeight
+ totalXWeight += xWeight
+ }
+ for x := range xWeights[:jx-ix] {
+ xWeights[x] /= totalXWeight
+ }
+
+ sy += float64(bias.Y)
+ sy -= 0.5
+ iy := int(math.Floor(sy - yHalfWidth))
+ if iy < sr.Min.Y {
+ iy = sr.Min.Y
+ }
+ jy := int(math.Ceil(sy + yHalfWidth))
+ if jy > sr.Max.Y {
+ jy = sr.Max.Y
+ }
+
+ totalYWeight := 0.0
+ for ky := iy; ky < jy; ky++ {
+ yWeight := 0.0
+ if t := abs((sy - float64(ky)) * yKernelArgScale); t < q.Support {
+ yWeight = q.At(t)
+ }
+ yWeights[ky-iy] = yWeight
+ totalYWeight += yWeight
+ }
+ for y := range yWeights[:jy-iy] {
+ yWeights[y] /= totalYWeight
+ }
+
+ var pr, pg, pb, pa float64
+ for ky := iy; ky < jy; ky++ {
+ if yWeight := yWeights[ky-iy]; yWeight != 0 {
+ for kx := ix; kx < jx; kx++ {
+ if w := xWeights[kx-ix] * yWeight; w != 0 {
+ pru, pgu, pbu, pau := src.At(kx, ky).RGBA()
+ if srcMask != nil {
+ _, _, _, ma := srcMask.At(smp.X+kx, smp.Y+ky).RGBA()
+ pru = pru * ma / 0xffff
+ pgu = pgu * ma / 0xffff
+ pbu = pbu * ma / 0xffff
+ pau = pau * ma / 0xffff
+ }
+ pr += float64(pru) * w
+ pg += float64(pgu) * w
+ pb += float64(pbu) * w
+ pa += float64(pau) * w
+ }
+ }
+ }
+ }
+
+ if pr > pa {
+ pr = pa
+ }
+ if pg > pa {
+ pg = pa
+ }
+ if pb > pa {
+ pb = pa
+ }
+
+ if dstMask != nil {
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ _, _, _, ma := dstMask.At(dmp.X+dr.Min.X+int(dx), dmp.Y+dr.Min.Y+int(dy)).RGBA()
+ pr := uint32(fffftou(pr)) * ma / 0xffff
+ pg := uint32(fffftou(pg)) * ma / 0xffff
+ pb := uint32(fffftou(pb)) * ma / 0xffff
+ pa := uint32(fffftou(pa)) * ma / 0xffff
+ pa1 := 0xffff - ma
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ } else {
+ dstColorRGBA64.R = fffftou(pr)
+ dstColorRGBA64.G = fffftou(pg)
+ dstColorRGBA64.B = fffftou(pb)
+ dstColorRGBA64.A = fffftou(pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/draw/scale.go b/vendor/golang.org/x/image/draw/scale.go
new file mode 100644
index 000000000..98ab404eb
--- /dev/null
+++ b/vendor/golang.org/x/image/draw/scale.go
@@ -0,0 +1,527 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go
+
+package draw
+
+import (
+ "image"
+ "image/color"
+ "math"
+ "sync"
+
+ "golang.org/x/image/math/f64"
+)
+
+// Copy copies the part of the source image defined by src and sr and writes
+// the result of a Porter-Duff composition to the part of the destination image
+// defined by dst and the translation of sr so that sr.Min translates to dp.
+func Copy(dst Image, dp image.Point, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ var o Options
+ if opts != nil {
+ o = *opts
+ }
+ dr := sr.Add(dp.Sub(sr.Min))
+ if o.DstMask == nil {
+ DrawMask(dst, dr, src, sr.Min, o.SrcMask, o.SrcMaskP.Add(sr.Min), op)
+ } else {
+ NearestNeighbor.Scale(dst, dr, src, sr, op, opts)
+ }
+}
+
+// Scaler scales the part of the source image defined by src and sr and writes
+// the result of a Porter-Duff composition to the part of the destination image
+// defined by dst and dr.
+//
+// A Scaler is safe to use concurrently.
+type Scaler interface {
+ Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options)
+}
+
+// Transformer transforms the part of the source image defined by src and sr
+// and writes the result of a Porter-Duff composition to the part of the
+// destination image defined by dst and the affine transform m applied to sr.
+//
+// For example, if m is the matrix
+//
+// m00 m01 m02
+// m10 m11 m12
+//
+// then the src-space point (sx, sy) maps to the dst-space point
+// (m00*sx + m01*sy + m02, m10*sx + m11*sy + m12).
+//
+// A Transformer is safe to use concurrently.
+type Transformer interface {
+ Transform(dst Image, m f64.Aff3, src image.Image, sr image.Rectangle, op Op, opts *Options)
+}
+
+// Options are optional parameters to Copy, Scale and Transform.
+//
+// A nil *Options means to use the default (zero) values of each field.
+type Options struct {
+ // Masks limit what parts of the dst image are drawn to and what parts of
+ // the src image are drawn from.
+ //
+ // A dst or src mask image having a zero alpha (transparent) pixel value in
+ // the respective coordinate space means that that dst pixel is entirely
+ // unaffected or that src pixel is considered transparent black. A full
+ // alpha (opaque) value means that the dst pixel is maximally affected or
+ // the src pixel contributes maximally. The default values, nil, are
+ // equivalent to fully opaque, infinitely large mask images.
+ //
+ // The DstMask is otherwise known as a clip mask, and its pixels map 1:1 to
+ // the dst image's pixels. DstMaskP in DstMask space corresponds to
+ // image.Point{X:0, Y:0} in dst space. For example, when limiting
+ // repainting to a 'dirty rectangle', use that image.Rectangle and a zero
+ // image.Point as the DstMask and DstMaskP.
+ //
+ // The SrcMask's pixels map 1:1 to the src image's pixels. SrcMaskP in
+ // SrcMask space corresponds to image.Point{X:0, Y:0} in src space. For
+ // example, when drawing font glyphs in a uniform color, use an
+ // *image.Uniform as the src, and use the glyph atlas image and the
+ // per-glyph offset as SrcMask and SrcMaskP:
+ // Copy(dst, dp, image.NewUniform(color), image.Rect(0, 0, glyphWidth, glyphHeight), &Options{
+ // SrcMask: glyphAtlas,
+ // SrcMaskP: glyphOffset,
+ // })
+ DstMask image.Image
+ DstMaskP image.Point
+ SrcMask image.Image
+ SrcMaskP image.Point
+
+ // TODO: a smooth vs sharp edges option, for arbitrary rotations?
+}
+
+// Interpolator is an interpolation algorithm, when dst and src pixels don't
+// have a 1:1 correspondence.
+//
+// Of the interpolators provided by this package:
+// - NearestNeighbor is fast but usually looks worst.
+// - CatmullRom is slow but usually looks best.
+// - ApproxBiLinear has reasonable speed and quality.
+//
+// The time taken depends on the size of dr. For kernel interpolators, the
+// speed also depends on the size of sr, and so are often slower than
+// non-kernel interpolators, especially when scaling down.
+type Interpolator interface {
+ Scaler
+ Transformer
+}
+
+// Kernel is an interpolator that blends source pixels weighted by a symmetric
+// kernel function.
+type Kernel struct {
+ // Support is the kernel support and must be >= 0. At(t) is assumed to be
+ // zero when t >= Support.
+ Support float64
+ // At is the kernel function. It will only be called with t in the
+ // range [0, Support).
+ At func(t float64) float64
+}
+
+// Scale implements the Scaler interface.
+func (q *Kernel) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) {
+ q.newScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy(), false).Scale(dst, dr, src, sr, op, opts)
+}
+
+// NewScaler returns a Scaler that is optimized for scaling multiple times with
+// the same fixed destination and source width and height.
+func (q *Kernel) NewScaler(dw, dh, sw, sh int) Scaler {
+ return q.newScaler(dw, dh, sw, sh, true)
+}
+
+func (q *Kernel) newScaler(dw, dh, sw, sh int, usePool bool) Scaler {
+ z := &kernelScaler{
+ kernel: q,
+ dw: int32(dw),
+ dh: int32(dh),
+ sw: int32(sw),
+ sh: int32(sh),
+ horizontal: newDistrib(q, int32(dw), int32(sw)),
+ vertical: newDistrib(q, int32(dh), int32(sh)),
+ }
+ if usePool {
+ z.pool.New = func() interface{} {
+ tmp := z.makeTmpBuf()
+ return &tmp
+ }
+ }
+ return z
+}
+
+var (
+ // NearestNeighbor is the nearest neighbor interpolator. It is very fast,
+ // but usually gives very low quality results. When scaling up, the result
+ // will look 'blocky'.
+ NearestNeighbor = Interpolator(nnInterpolator{})
+
+ // ApproxBiLinear is a mixture of the nearest neighbor and bi-linear
+ // interpolators. It is fast, but usually gives medium quality results.
+ //
+ // It implements bi-linear interpolation when upscaling and a bi-linear
+ // blend of the 4 nearest neighbor pixels when downscaling. This yields
+ // nicer quality than nearest neighbor interpolation when upscaling, but
+ // the time taken is independent of the number of source pixels, unlike the
+ // bi-linear interpolator. When downscaling a large image, the performance
+ // difference can be significant.
+ ApproxBiLinear = Interpolator(ablInterpolator{})
+
+ // BiLinear is the tent kernel. It is slow, but usually gives high quality
+ // results.
+ BiLinear = &Kernel{1, func(t float64) float64 {
+ return 1 - t
+ }}
+
+ // CatmullRom is the Catmull-Rom kernel. It is very slow, but usually gives
+ // very high quality results.
+ //
+ // It is an instance of the more general cubic BC-spline kernel with parameters
+ // B=0 and C=0.5. See Mitchell and Netravali, "Reconstruction Filters in
+ // Computer Graphics", Computer Graphics, Vol. 22, No. 4, pp. 221-228.
+ CatmullRom = &Kernel{2, func(t float64) float64 {
+ if t < 1 {
+ return (1.5*t-2.5)*t*t + 1
+ }
+ return ((-0.5*t+2.5)*t-4)*t + 2
+ }}
+
+ // TODO: a Kaiser-Bessel kernel?
+)
+
+type nnInterpolator struct{}
+
+type ablInterpolator struct{}
+
+type kernelScaler struct {
+ kernel *Kernel
+ dw, dh, sw, sh int32
+ horizontal, vertical distrib
+ pool sync.Pool
+}
+
+func (z *kernelScaler) makeTmpBuf() [][4]float64 {
+ return make([][4]float64, z.dw*z.sh)
+}
+
+// source is a range of contribs, their inverse total weight, and that ITW
+// divided by 0xffff.
+type source struct {
+ i, j int32
+ invTotalWeight float64
+ invTotalWeightFFFF float64
+}
+
+// contrib is the weight of a column or row.
+type contrib struct {
+ coord int32
+ weight float64
+}
+
+// distrib measures how source pixels are distributed over destination pixels.
+type distrib struct {
+ // sources are what contribs each column or row in the source image owns,
+ // and the total weight of those contribs.
+ sources []source
+ // contribs are the contributions indexed by sources[s].i and sources[s].j.
+ contribs []contrib
+}
+
+// newDistrib returns a distrib that distributes sw source columns (or rows)
+// over dw destination columns (or rows).
+func newDistrib(q *Kernel, dw, sw int32) distrib {
+ scale := float64(sw) / float64(dw)
+ halfWidth, kernelArgScale := q.Support, 1.0
+ // When shrinking, broaden the effective kernel support so that we still
+ // visit every source pixel.
+ if scale > 1 {
+ halfWidth *= scale
+ kernelArgScale = 1 / scale
+ }
+
+ // Make the sources slice, one source for each column or row, and temporarily
+ // appropriate its elements' fields so that invTotalWeight is the scaled
+ // coordinate of the source column or row, and i and j are the lower and
+ // upper bounds of the range of destination columns or rows affected by the
+ // source column or row.
+ n, sources := int32(0), make([]source, dw)
+ for x := range sources {
+ center := (float64(x)+0.5)*scale - 0.5
+ i := int32(math.Floor(center - halfWidth))
+ if i < 0 {
+ i = 0
+ }
+ j := int32(math.Ceil(center + halfWidth))
+ if j > sw {
+ j = sw
+ if j < i {
+ j = i
+ }
+ }
+ sources[x] = source{i: i, j: j, invTotalWeight: center}
+ n += j - i
+ }
+
+ contribs := make([]contrib, 0, n)
+ for k, b := range sources {
+ totalWeight := 0.0
+ l := int32(len(contribs))
+ for coord := b.i; coord < b.j; coord++ {
+ t := abs((b.invTotalWeight - float64(coord)) * kernelArgScale)
+ if t >= q.Support {
+ continue
+ }
+ weight := q.At(t)
+ if weight == 0 {
+ continue
+ }
+ totalWeight += weight
+ contribs = append(contribs, contrib{coord, weight})
+ }
+ totalWeight = 1 / totalWeight
+ sources[k] = source{
+ i: l,
+ j: int32(len(contribs)),
+ invTotalWeight: totalWeight,
+ invTotalWeightFFFF: totalWeight / 0xffff,
+ }
+ }
+
+ return distrib{sources, contribs}
+}
+
+// abs is like math.Abs, but it doesn't care about negative zero, infinities or
+// NaNs.
+func abs(f float64) float64 {
+ if f < 0 {
+ f = -f
+ }
+ return f
+}
+
+// ftou converts the range [0.0, 1.0] to [0, 0xffff].
+func ftou(f float64) uint16 {
+ i := int32(0xffff*f + 0.5)
+ if i > 0xffff {
+ return 0xffff
+ }
+ if i > 0 {
+ return uint16(i)
+ }
+ return 0
+}
+
+// fffftou converts the range [0.0, 65535.0] to [0, 0xffff].
+func fffftou(f float64) uint16 {
+ i := int32(f + 0.5)
+ if i > 0xffff {
+ return 0xffff
+ }
+ if i > 0 {
+ return uint16(i)
+ }
+ return 0
+}
+
+// invert returns the inverse of m.
+//
+// TODO: move this into the f64 package, once we work out the convention for
+// matrix methods in that package: do they modify the receiver, take a dst
+// pointer argument, or return a new value?
+func invert(m *f64.Aff3) f64.Aff3 {
+ m00 := +m[3*1+1]
+ m01 := -m[3*0+1]
+ m02 := +m[3*1+2]*m[3*0+1] - m[3*1+1]*m[3*0+2]
+ m10 := -m[3*1+0]
+ m11 := +m[3*0+0]
+ m12 := +m[3*1+0]*m[3*0+2] - m[3*1+2]*m[3*0+0]
+
+ det := m00*m11 - m10*m01
+
+ return f64.Aff3{
+ m00 / det,
+ m01 / det,
+ m02 / det,
+ m10 / det,
+ m11 / det,
+ m12 / det,
+ }
+}
+
+func matMul(p, q *f64.Aff3) f64.Aff3 {
+ return f64.Aff3{
+ p[3*0+0]*q[3*0+0] + p[3*0+1]*q[3*1+0],
+ p[3*0+0]*q[3*0+1] + p[3*0+1]*q[3*1+1],
+ p[3*0+0]*q[3*0+2] + p[3*0+1]*q[3*1+2] + p[3*0+2],
+ p[3*1+0]*q[3*0+0] + p[3*1+1]*q[3*1+0],
+ p[3*1+0]*q[3*0+1] + p[3*1+1]*q[3*1+1],
+ p[3*1+0]*q[3*0+2] + p[3*1+1]*q[3*1+2] + p[3*1+2],
+ }
+}
+
+// transformRect returns a rectangle dr that contains sr transformed by s2d.
+func transformRect(s2d *f64.Aff3, sr *image.Rectangle) (dr image.Rectangle) {
+ ps := [...]image.Point{
+ {sr.Min.X, sr.Min.Y},
+ {sr.Max.X, sr.Min.Y},
+ {sr.Min.X, sr.Max.Y},
+ {sr.Max.X, sr.Max.Y},
+ }
+ for i, p := range ps {
+ sxf := float64(p.X)
+ syf := float64(p.Y)
+ dx := int(math.Floor(s2d[0]*sxf + s2d[1]*syf + s2d[2]))
+ dy := int(math.Floor(s2d[3]*sxf + s2d[4]*syf + s2d[5]))
+
+ // The +1 adjustments below are because an image.Rectangle is inclusive
+ // on the low end but exclusive on the high end.
+
+ if i == 0 {
+ dr = image.Rectangle{
+ Min: image.Point{dx + 0, dy + 0},
+ Max: image.Point{dx + 1, dy + 1},
+ }
+ continue
+ }
+
+ if dr.Min.X > dx {
+ dr.Min.X = dx
+ }
+ dx++
+ if dr.Max.X < dx {
+ dr.Max.X = dx
+ }
+
+ if dr.Min.Y > dy {
+ dr.Min.Y = dy
+ }
+ dy++
+ if dr.Max.Y < dy {
+ dr.Max.Y = dy
+ }
+ }
+ return dr
+}
+
+func clipAffectedDestRect(adr image.Rectangle, dstMask image.Image, dstMaskP image.Point) (image.Rectangle, image.Image) {
+ if dstMask == nil {
+ return adr, nil
+ }
+ // TODO: enable this fast path once Go 1.5 is released, where an
+ // image.Rectangle implements image.Image.
+ // if r, ok := dstMask.(image.Rectangle); ok {
+ // return adr.Intersect(r.Sub(dstMaskP)), nil
+ // }
+ // TODO: clip to dstMask.Bounds() if the color model implies that out-of-bounds means 0 alpha?
+ return adr, dstMask
+}
+
+func transform_Uniform(dst Image, dr, adr image.Rectangle, d2s *f64.Aff3, src *image.Uniform, sr image.Rectangle, bias image.Point, op Op) {
+ switch op {
+ case Over:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ pr, pg, pb, pa := src.C.RGBA()
+ pa1 := (0xffff - pa) * 0x101
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ dst.Pix[d+0] = uint8((uint32(dst.Pix[d+0])*pa1/0xffff + pr) >> 8)
+ dst.Pix[d+1] = uint8((uint32(dst.Pix[d+1])*pa1/0xffff + pg) >> 8)
+ dst.Pix[d+2] = uint8((uint32(dst.Pix[d+2])*pa1/0xffff + pb) >> 8)
+ dst.Pix[d+3] = uint8((uint32(dst.Pix[d+3])*pa1/0xffff + pa) >> 8)
+ }
+ }
+
+ default:
+ pr, pg, pb, pa := src.C.RGBA()
+ pa1 := 0xffff - pa
+ dstColorRGBA64 := &color.RGBA64{}
+ dstColor := color.Color(dstColorRGBA64)
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ qr, qg, qb, qa := dst.At(dr.Min.X+int(dx), dr.Min.Y+int(dy)).RGBA()
+ dstColorRGBA64.R = uint16(qr*pa1/0xffff + pr)
+ dstColorRGBA64.G = uint16(qg*pa1/0xffff + pg)
+ dstColorRGBA64.B = uint16(qb*pa1/0xffff + pb)
+ dstColorRGBA64.A = uint16(qa*pa1/0xffff + pa)
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+ }
+
+ case Src:
+ switch dst := dst.(type) {
+ case *image.RGBA:
+ pr, pg, pb, pa := src.C.RGBA()
+ pr8 := uint8(pr >> 8)
+ pg8 := uint8(pg >> 8)
+ pb8 := uint8(pb >> 8)
+ pa8 := uint8(pa >> 8)
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ d := dst.PixOffset(dr.Min.X+adr.Min.X, dr.Min.Y+int(dy))
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx, d = dx+1, d+4 {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ dst.Pix[d+0] = pr8
+ dst.Pix[d+1] = pg8
+ dst.Pix[d+2] = pb8
+ dst.Pix[d+3] = pa8
+ }
+ }
+
+ default:
+ pr, pg, pb, pa := src.C.RGBA()
+ dstColorRGBA64 := &color.RGBA64{
+ uint16(pr),
+ uint16(pg),
+ uint16(pb),
+ uint16(pa),
+ }
+ dstColor := color.Color(dstColorRGBA64)
+
+ for dy := int32(adr.Min.Y); dy < int32(adr.Max.Y); dy++ {
+ dyf := float64(dr.Min.Y+int(dy)) + 0.5
+ for dx := int32(adr.Min.X); dx < int32(adr.Max.X); dx++ {
+ dxf := float64(dr.Min.X+int(dx)) + 0.5
+ sx0 := int(d2s[0]*dxf+d2s[1]*dyf+d2s[2]) + bias.X
+ sy0 := int(d2s[3]*dxf+d2s[4]*dyf+d2s[5]) + bias.Y
+ if !(image.Point{sx0, sy0}).In(sr) {
+ continue
+ }
+ dst.Set(dr.Min.X+int(dx), dr.Min.Y+int(dy), dstColor)
+ }
+ }
+ }
+ }
+}
+
+func opaque(m image.Image) bool {
+ o, ok := m.(interface {
+ Opaque() bool
+ })
+ return ok && o.Opaque()
+}
diff --git a/vendor/golang.org/x/image/draw/scale_test.go b/vendor/golang.org/x/image/draw/scale_test.go
new file mode 100644
index 000000000..5e184c24e
--- /dev/null
+++ b/vendor/golang.org/x/image/draw/scale_test.go
@@ -0,0 +1,731 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package draw
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "image"
+ "image/color"
+ "image/png"
+ "math/rand"
+ "os"
+ "reflect"
+ "testing"
+
+ "golang.org/x/image/math/f64"
+
+ _ "image/jpeg"
+)
+
+var genGoldenFiles = flag.Bool("gen_golden_files", false, "whether to generate the TestXxx golden files.")
+
+var transformMatrix = func(scale, tx, ty float64) f64.Aff3 {
+ const cos30, sin30 = 0.866025404, 0.5
+ return f64.Aff3{
+ +scale * cos30, -scale * sin30, tx,
+ +scale * sin30, +scale * cos30, ty,
+ }
+}
+
+func encode(filename string, m image.Image) error {
+ f, err := os.Create(filename)
+ if err != nil {
+ return fmt.Errorf("Create: %v", err)
+ }
+ defer f.Close()
+ if err := png.Encode(f, m); err != nil {
+ return fmt.Errorf("Encode: %v", err)
+ }
+ return nil
+}
+
+// testInterp tests that interpolating the source image gives the exact
+// destination image. This is to ensure that any refactoring or optimization of
+// the interpolation code doesn't change the behavior. Changing the actual
+// algorithm or kernel used by any particular quality setting will obviously
+// change the resultant pixels. In such a case, use the gen_golden_files flag
+// to regenerate the golden files.
+func testInterp(t *testing.T, w int, h int, direction, prefix, suffix string) {
+ f, err := os.Open("../testdata/" + prefix + suffix)
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
+ defer f.Close()
+ src, _, err := image.Decode(f)
+ if err != nil {
+ t.Fatalf("Decode: %v", err)
+ }
+
+ op, scale := Src, 3.75
+ if prefix == "tux" {
+ op, scale = Over, 0.125
+ }
+ green := image.NewUniform(color.RGBA{0x00, 0x22, 0x11, 0xff})
+
+ testCases := map[string]Interpolator{
+ "nn": NearestNeighbor,
+ "ab": ApproxBiLinear,
+ "bl": BiLinear,
+ "cr": CatmullRom,
+ }
+ for name, q := range testCases {
+ goldenFilename := fmt.Sprintf("../testdata/%s-%s-%s.png", prefix, direction, name)
+
+ got := image.NewRGBA(image.Rect(0, 0, w, h))
+ Copy(got, image.Point{}, green, got.Bounds(), Src, nil)
+ if direction == "rotate" {
+ q.Transform(got, transformMatrix(scale, 40, 10), src, src.Bounds(), op, nil)
+ } else {
+ q.Scale(got, got.Bounds(), src, src.Bounds(), op, nil)
+ }
+
+ if *genGoldenFiles {
+ if err := encode(goldenFilename, got); err != nil {
+ t.Error(err)
+ }
+ continue
+ }
+
+ g, err := os.Open(goldenFilename)
+ if err != nil {
+ t.Errorf("Open: %v", err)
+ continue
+ }
+ defer g.Close()
+ wantRaw, err := png.Decode(g)
+ if err != nil {
+ t.Errorf("Decode: %v", err)
+ continue
+ }
+ // convert wantRaw to RGBA.
+ want, ok := wantRaw.(*image.RGBA)
+ if !ok {
+ b := wantRaw.Bounds()
+ want = image.NewRGBA(b)
+ Draw(want, b, wantRaw, b.Min, Src)
+ }
+
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("%s: actual image differs from golden image", goldenFilename)
+ continue
+ }
+ }
+}
+
+func TestScaleDown(t *testing.T) { testInterp(t, 100, 100, "down", "go-turns-two", "-280x360.jpeg") }
+func TestScaleUp(t *testing.T) { testInterp(t, 75, 100, "up", "go-turns-two", "-14x18.png") }
+func TestTformSrc(t *testing.T) { testInterp(t, 100, 100, "rotate", "go-turns-two", "-14x18.png") }
+func TestTformOver(t *testing.T) { testInterp(t, 100, 100, "rotate", "tux", ".png") }
+
+// TestSimpleTransforms tests Scale and Transform calls that simplify to Copy
+// or Scale calls.
+func TestSimpleTransforms(t *testing.T) {
+ f, err := os.Open("../testdata/testpattern.png") // A 100x100 image.
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
+ defer f.Close()
+ src, _, err := image.Decode(f)
+ if err != nil {
+ t.Fatalf("Decode: %v", err)
+ }
+
+ dst0 := image.NewRGBA(image.Rect(0, 0, 120, 150))
+ dst1 := image.NewRGBA(image.Rect(0, 0, 120, 150))
+ for _, op := range []string{"scale/copy", "tform/copy", "tform/scale"} {
+ for _, epsilon := range []float64{0, 1e-50, 1e-1} {
+ Copy(dst0, image.Point{}, image.Transparent, dst0.Bounds(), Src, nil)
+ Copy(dst1, image.Point{}, image.Transparent, dst1.Bounds(), Src, nil)
+
+ switch op {
+ case "scale/copy":
+ dr := image.Rect(10, 30, 10+100, 30+100)
+ if epsilon > 1e-10 {
+ dr.Max.X++
+ }
+ Copy(dst0, image.Point{10, 30}, src, src.Bounds(), Src, nil)
+ ApproxBiLinear.Scale(dst1, dr, src, src.Bounds(), Src, nil)
+ case "tform/copy":
+ Copy(dst0, image.Point{10, 30}, src, src.Bounds(), Src, nil)
+ ApproxBiLinear.Transform(dst1, f64.Aff3{
+ 1, 0 + epsilon, 10,
+ 0, 1, 30,
+ }, src, src.Bounds(), Src, nil)
+ case "tform/scale":
+ ApproxBiLinear.Scale(dst0, image.Rect(10, 50, 10+50, 50+50), src, src.Bounds(), Src, nil)
+ ApproxBiLinear.Transform(dst1, f64.Aff3{
+ 0.5, 0.0 + epsilon, 10,
+ 0.0, 0.5, 50,
+ }, src, src.Bounds(), Src, nil)
+ }
+
+ differ := !bytes.Equal(dst0.Pix, dst1.Pix)
+ if epsilon > 1e-10 {
+ if !differ {
+ t.Errorf("%s yielded same pixels, want different pixels: epsilon=%v", op, epsilon)
+ }
+ } else {
+ if differ {
+ t.Errorf("%s yielded different pixels, want same pixels: epsilon=%v", op, epsilon)
+ }
+ }
+ }
+ }
+}
+
+func BenchmarkSimpleScaleCopy(b *testing.B) {
+ dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
+ src := image.NewRGBA(image.Rect(0, 0, 400, 300))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ApproxBiLinear.Scale(dst, image.Rect(10, 20, 10+400, 20+300), src, src.Bounds(), Src, nil)
+ }
+}
+
+func BenchmarkSimpleTransformCopy(b *testing.B) {
+ dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
+ src := image.NewRGBA(image.Rect(0, 0, 400, 300))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ApproxBiLinear.Transform(dst, f64.Aff3{
+ 1, 0, 10,
+ 0, 1, 20,
+ }, src, src.Bounds(), Src, nil)
+ }
+}
+
+func BenchmarkSimpleTransformScale(b *testing.B) {
+ dst := image.NewRGBA(image.Rect(0, 0, 640, 480))
+ src := image.NewRGBA(image.Rect(0, 0, 400, 300))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ ApproxBiLinear.Transform(dst, f64.Aff3{
+ 0.5, 0.0, 10,
+ 0.0, 0.5, 20,
+ }, src, src.Bounds(), Src, nil)
+ }
+}
+
+func TestOps(t *testing.T) {
+ blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
+ testCases := map[Op]color.RGBA{
+ Over: color.RGBA{0x7f, 0x00, 0x80, 0xff},
+ Src: color.RGBA{0x7f, 0x00, 0x00, 0x7f},
+ }
+ for op, want := range testCases {
+ dst := image.NewRGBA(image.Rect(0, 0, 2, 2))
+ Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
+
+ src := image.NewRGBA(image.Rect(0, 0, 1, 1))
+ src.SetRGBA(0, 0, color.RGBA{0x7f, 0x00, 0x00, 0x7f})
+
+ NearestNeighbor.Scale(dst, dst.Bounds(), src, src.Bounds(), op, nil)
+
+ if got := dst.RGBAAt(0, 0); got != want {
+ t.Errorf("op=%v: got %v, want %v", op, got, want)
+ }
+ }
+}
+
+// TestNegativeWeights tests that scaling by a kernel that produces negative
+// weights, such as the Catmull-Rom kernel, doesn't produce an invalid color
+// according to Go's alpha-premultiplied model.
+func TestNegativeWeights(t *testing.T) {
+ check := func(m *image.RGBA) error {
+ b := m.Bounds()
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if c := m.RGBAAt(x, y); c.R > c.A || c.G > c.A || c.B > c.A {
+ return fmt.Errorf("invalid color.RGBA at (%d, %d): %v", x, y, c)
+ }
+ }
+ }
+ return nil
+ }
+
+ src := image.NewRGBA(image.Rect(0, 0, 16, 16))
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ a := y * 0x11
+ src.Set(x, y, color.RGBA{
+ R: uint8(x * 0x11 * a / 0xff),
+ A: uint8(a),
+ })
+ }
+ }
+ if err := check(src); err != nil {
+ t.Fatalf("src image: %v", err)
+ }
+
+ dst := image.NewRGBA(image.Rect(0, 0, 32, 32))
+ CatmullRom.Scale(dst, dst.Bounds(), src, src.Bounds(), Over, nil)
+ if err := check(dst); err != nil {
+ t.Fatalf("dst image: %v", err)
+ }
+}
+
+func fillPix(r *rand.Rand, pixs ...[]byte) {
+ for _, pix := range pixs {
+ for i := range pix {
+ pix[i] = uint8(r.Intn(256))
+ }
+ }
+}
+
+func TestInterpClipCommute(t *testing.T) {
+ src := image.NewNRGBA(image.Rect(0, 0, 20, 20))
+ fillPix(rand.New(rand.NewSource(0)), src.Pix)
+
+ outer := image.Rect(1, 1, 8, 5)
+ inner := image.Rect(2, 3, 6, 5)
+ qs := []Interpolator{
+ NearestNeighbor,
+ ApproxBiLinear,
+ CatmullRom,
+ }
+ for _, transform := range []bool{false, true} {
+ for _, q := range qs {
+ dst0 := image.NewRGBA(image.Rect(1, 1, 10, 10))
+ dst1 := image.NewRGBA(image.Rect(1, 1, 10, 10))
+ for i := range dst0.Pix {
+ dst0.Pix[i] = uint8(i / 4)
+ dst1.Pix[i] = uint8(i / 4)
+ }
+
+ var interp func(dst *image.RGBA)
+ if transform {
+ interp = func(dst *image.RGBA) {
+ q.Transform(dst, transformMatrix(3.75, 2, 1), src, src.Bounds(), Over, nil)
+ }
+ } else {
+ interp = func(dst *image.RGBA) {
+ q.Scale(dst, outer, src, src.Bounds(), Over, nil)
+ }
+ }
+
+ // Interpolate then clip.
+ interp(dst0)
+ dst0 = dst0.SubImage(inner).(*image.RGBA)
+
+ // Clip then interpolate.
+ dst1 = dst1.SubImage(inner).(*image.RGBA)
+ interp(dst1)
+
+ loop:
+ for y := inner.Min.Y; y < inner.Max.Y; y++ {
+ for x := inner.Min.X; x < inner.Max.X; x++ {
+ if c0, c1 := dst0.RGBAAt(x, y), dst1.RGBAAt(x, y); c0 != c1 {
+ t.Errorf("q=%T: at (%d, %d): c0=%v, c1=%v", q, x, y, c0, c1)
+ break loop
+ }
+ }
+ }
+ }
+ }
+}
+
+// translatedImage is an image m translated by t.
+type translatedImage struct {
+ m image.Image
+ t image.Point
+}
+
+func (t *translatedImage) At(x, y int) color.Color { return t.m.At(x-t.t.X, y-t.t.Y) }
+func (t *translatedImage) Bounds() image.Rectangle { return t.m.Bounds().Add(t.t) }
+func (t *translatedImage) ColorModel() color.Model { return t.m.ColorModel() }
+
+// TestSrcTranslationInvariance tests that Scale and Transform are invariant
+// under src translations. Specifically, when some source pixels are not in the
+// bottom-right quadrant of src coordinate space, we consistently round down,
+// not round towards zero.
+func TestSrcTranslationInvariance(t *testing.T) {
+ f, err := os.Open("../testdata/testpattern.png")
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
+ defer f.Close()
+ src, _, err := image.Decode(f)
+ if err != nil {
+ t.Fatalf("Decode: %v", err)
+ }
+ sr := image.Rect(2, 3, 16, 12)
+ if !sr.In(src.Bounds()) {
+ t.Fatalf("src bounds too small: got %v", src.Bounds())
+ }
+ qs := []Interpolator{
+ NearestNeighbor,
+ ApproxBiLinear,
+ CatmullRom,
+ }
+ deltas := []image.Point{
+ {+0, +0},
+ {+0, +5},
+ {+0, -5},
+ {+5, +0},
+ {-5, +0},
+ {+8, +8},
+ {+8, -8},
+ {-8, +8},
+ {-8, -8},
+ }
+ m00 := transformMatrix(3.75, 0, 0)
+
+ for _, transform := range []bool{false, true} {
+ for _, q := range qs {
+ want := image.NewRGBA(image.Rect(0, 0, 20, 20))
+ if transform {
+ q.Transform(want, m00, src, sr, Over, nil)
+ } else {
+ q.Scale(want, want.Bounds(), src, sr, Over, nil)
+ }
+ for _, delta := range deltas {
+ tsrc := &translatedImage{src, delta}
+ got := image.NewRGBA(image.Rect(0, 0, 20, 20))
+ if transform {
+ m := matMul(&m00, &f64.Aff3{
+ 1, 0, -float64(delta.X),
+ 0, 1, -float64(delta.Y),
+ })
+ q.Transform(got, m, tsrc, sr.Add(delta), Over, nil)
+ } else {
+ q.Scale(got, got.Bounds(), tsrc, sr.Add(delta), Over, nil)
+ }
+ if !bytes.Equal(got.Pix, want.Pix) {
+ t.Errorf("pix differ for delta=%v, transform=%t, q=%T", delta, transform, q)
+ }
+ }
+ }
+ }
+}
+
+func TestSrcMask(t *testing.T) {
+ srcMask := image.NewRGBA(image.Rect(0, 0, 23, 1))
+ srcMask.SetRGBA(19, 0, color.RGBA{0x00, 0x00, 0x00, 0x7f})
+ srcMask.SetRGBA(20, 0, color.RGBA{0x00, 0x00, 0x00, 0xff})
+ srcMask.SetRGBA(21, 0, color.RGBA{0x00, 0x00, 0x00, 0x3f})
+ srcMask.SetRGBA(22, 0, color.RGBA{0x00, 0x00, 0x00, 0x00})
+ red := image.NewUniform(color.RGBA{0xff, 0x00, 0x00, 0xff})
+ blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
+ dst := image.NewRGBA(image.Rect(0, 0, 6, 1))
+ Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
+ NearestNeighbor.Scale(dst, dst.Bounds(), red, image.Rect(0, 0, 3, 1), Over, &Options{
+ SrcMask: srcMask,
+ SrcMaskP: image.Point{20, 0},
+ })
+ got := [6]color.RGBA{
+ dst.RGBAAt(0, 0),
+ dst.RGBAAt(1, 0),
+ dst.RGBAAt(2, 0),
+ dst.RGBAAt(3, 0),
+ dst.RGBAAt(4, 0),
+ dst.RGBAAt(5, 0),
+ }
+ want := [6]color.RGBA{
+ {0xff, 0x00, 0x00, 0xff},
+ {0xff, 0x00, 0x00, 0xff},
+ {0x3f, 0x00, 0xc0, 0xff},
+ {0x3f, 0x00, 0xc0, 0xff},
+ {0x00, 0x00, 0xff, 0xff},
+ {0x00, 0x00, 0xff, 0xff},
+ }
+ if got != want {
+ t.Errorf("\ngot %v\nwant %v", got, want)
+ }
+}
+
+func TestDstMask(t *testing.T) {
+ dstMask := image.NewRGBA(image.Rect(0, 0, 23, 1))
+ dstMask.SetRGBA(19, 0, color.RGBA{0x00, 0x00, 0x00, 0x7f})
+ dstMask.SetRGBA(20, 0, color.RGBA{0x00, 0x00, 0x00, 0xff})
+ dstMask.SetRGBA(21, 0, color.RGBA{0x00, 0x00, 0x00, 0x3f})
+ dstMask.SetRGBA(22, 0, color.RGBA{0x00, 0x00, 0x00, 0x00})
+ red := image.NewRGBA(image.Rect(0, 0, 1, 1))
+ red.SetRGBA(0, 0, color.RGBA{0xff, 0x00, 0x00, 0xff})
+ blue := image.NewUniform(color.RGBA{0x00, 0x00, 0xff, 0xff})
+ qs := []Interpolator{
+ NearestNeighbor,
+ ApproxBiLinear,
+ CatmullRom,
+ }
+ for _, q := range qs {
+ dst := image.NewRGBA(image.Rect(0, 0, 3, 1))
+ Copy(dst, image.Point{}, blue, dst.Bounds(), Src, nil)
+ q.Scale(dst, dst.Bounds(), red, red.Bounds(), Over, &Options{
+ DstMask: dstMask,
+ DstMaskP: image.Point{20, 0},
+ })
+ got := [3]color.RGBA{
+ dst.RGBAAt(0, 0),
+ dst.RGBAAt(1, 0),
+ dst.RGBAAt(2, 0),
+ }
+ want := [3]color.RGBA{
+ {0xff, 0x00, 0x00, 0xff},
+ {0x3f, 0x00, 0xc0, 0xff},
+ {0x00, 0x00, 0xff, 0xff},
+ }
+ if got != want {
+ t.Errorf("q=%T:\ngot %v\nwant %v", q, got, want)
+ }
+ }
+}
+
+func TestRectDstMask(t *testing.T) {
+ f, err := os.Open("../testdata/testpattern.png")
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
+ defer f.Close()
+ src, _, err := image.Decode(f)
+ if err != nil {
+ t.Fatalf("Decode: %v", err)
+ }
+ m00 := transformMatrix(1, 0, 0)
+
+ bounds := image.Rect(0, 0, 50, 50)
+ dstOutside := image.NewRGBA(bounds)
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ dstOutside.SetRGBA(x, y, color.RGBA{uint8(5 * x), uint8(5 * y), 0x00, 0xff})
+ }
+ }
+
+ mk := func(q Transformer, dstMask image.Image, dstMaskP image.Point) *image.RGBA {
+ m := image.NewRGBA(bounds)
+ Copy(m, bounds.Min, dstOutside, bounds, Src, nil)
+ q.Transform(m, m00, src, src.Bounds(), Over, &Options{
+ DstMask: dstMask,
+ DstMaskP: dstMaskP,
+ })
+ return m
+ }
+
+ qs := []Interpolator{
+ NearestNeighbor,
+ ApproxBiLinear,
+ CatmullRom,
+ }
+ dstMaskPs := []image.Point{
+ {0, 0},
+ {5, 7},
+ {-3, 0},
+ }
+ rect := image.Rect(10, 10, 30, 40)
+ for _, q := range qs {
+ for _, dstMaskP := range dstMaskPs {
+ dstInside := mk(q, nil, image.Point{})
+ for _, wrap := range []bool{false, true} {
+ // TODO: replace "rectImage(rect)" with "rect" once Go 1.5 is
+ // released, where an image.Rectangle implements image.Image.
+ dstMask := image.Image(rectImage(rect))
+ if wrap {
+ dstMask = srcWrapper{dstMask}
+ }
+ dst := mk(q, dstMask, dstMaskP)
+
+ nError := 0
+ loop:
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ which := dstOutside
+ if (image.Point{x, y}).Add(dstMaskP).In(rect) {
+ which = dstInside
+ }
+ if got, want := dst.RGBAAt(x, y), which.RGBAAt(x, y); got != want {
+ if nError == 10 {
+ t.Errorf("q=%T dmp=%v wrap=%v: ...and more errors", q, dstMaskP, wrap)
+ break loop
+ }
+ nError++
+ t.Errorf("q=%T dmp=%v wrap=%v: x=%3d y=%3d: got %v, want %v",
+ q, dstMaskP, wrap, x, y, got, want)
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// TODO: delete this wrapper type once Go 1.5 is released, where an
+// image.Rectangle implements image.Image.
+type rectImage image.Rectangle
+
+func (r rectImage) ColorModel() color.Model { return color.Alpha16Model }
+func (r rectImage) Bounds() image.Rectangle { return image.Rectangle(r) }
+func (r rectImage) At(x, y int) color.Color {
+ if (image.Point{x, y}).In(image.Rectangle(r)) {
+ return color.Opaque
+ }
+ return color.Transparent
+}
+
+// The fooWrapper types wrap the dst or src image to avoid triggering the
+// type-specific fast path implementations.
+type (
+ dstWrapper struct{ Image }
+ srcWrapper struct{ image.Image }
+)
+
+func srcGray(boundsHint image.Rectangle) (image.Image, error) {
+ m := image.NewGray(boundsHint)
+ fillPix(rand.New(rand.NewSource(0)), m.Pix)
+ return m, nil
+}
+
+func srcNRGBA(boundsHint image.Rectangle) (image.Image, error) {
+ m := image.NewNRGBA(boundsHint)
+ fillPix(rand.New(rand.NewSource(1)), m.Pix)
+ return m, nil
+}
+
+func srcRGBA(boundsHint image.Rectangle) (image.Image, error) {
+ m := image.NewRGBA(boundsHint)
+ fillPix(rand.New(rand.NewSource(2)), m.Pix)
+ // RGBA is alpha-premultiplied, so the R, G and B values should
+ // be <= the A values.
+ for i := 0; i < len(m.Pix); i += 4 {
+ m.Pix[i+0] = uint8(uint32(m.Pix[i+0]) * uint32(m.Pix[i+3]) / 0xff)
+ m.Pix[i+1] = uint8(uint32(m.Pix[i+1]) * uint32(m.Pix[i+3]) / 0xff)
+ m.Pix[i+2] = uint8(uint32(m.Pix[i+2]) * uint32(m.Pix[i+3]) / 0xff)
+ }
+ return m, nil
+}
+
+func srcUnif(boundsHint image.Rectangle) (image.Image, error) {
+ return image.NewUniform(color.RGBA64{0x1234, 0x5555, 0x9181, 0xbeef}), nil
+}
+
+func srcYCbCr(boundsHint image.Rectangle) (image.Image, error) {
+ m := image.NewYCbCr(boundsHint, image.YCbCrSubsampleRatio420)
+ fillPix(rand.New(rand.NewSource(3)), m.Y, m.Cb, m.Cr)
+ return m, nil
+}
+
+func srcLarge(boundsHint image.Rectangle) (image.Image, error) {
+ // 3072 x 2304 is over 7 million pixels at 4:3, comparable to a
+ // 2015 smart-phone camera's output.
+ return srcYCbCr(image.Rect(0, 0, 3072, 2304))
+}
+
+func srcTux(boundsHint image.Rectangle) (image.Image, error) {
+ // tux.png is a 386 x 395 image.
+ f, err := os.Open("../testdata/tux.png")
+ if err != nil {
+ return nil, fmt.Errorf("Open: %v", err)
+ }
+ defer f.Close()
+ src, err := png.Decode(f)
+ if err != nil {
+ return nil, fmt.Errorf("Decode: %v", err)
+ }
+ return src, nil
+}
+
+func benchScale(b *testing.B, w int, h int, op Op, srcf func(image.Rectangle) (image.Image, error), q Interpolator) {
+ dst := image.NewRGBA(image.Rect(0, 0, w, h))
+ src, err := srcf(image.Rect(0, 0, 1024, 768))
+ if err != nil {
+ b.Fatal(err)
+ }
+ dr, sr := dst.Bounds(), src.Bounds()
+ scaler := Scaler(q)
+ if n, ok := q.(interface {
+ NewScaler(int, int, int, int) Scaler
+ }); ok {
+ scaler = n.NewScaler(dr.Dx(), dr.Dy(), sr.Dx(), sr.Dy())
+ }
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ scaler.Scale(dst, dr, src, sr, op, nil)
+ }
+}
+
+func benchTform(b *testing.B, w int, h int, op Op, srcf func(image.Rectangle) (image.Image, error), q Interpolator) {
+ dst := image.NewRGBA(image.Rect(0, 0, w, h))
+ src, err := srcf(image.Rect(0, 0, 1024, 768))
+ if err != nil {
+ b.Fatal(err)
+ }
+ sr := src.Bounds()
+ m := transformMatrix(3.75, 40, 10)
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ q.Transform(dst, m, src, sr, op, nil)
+ }
+}
+
+func BenchmarkScaleNNLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, NearestNeighbor) }
+func BenchmarkScaleABLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, ApproxBiLinear) }
+func BenchmarkScaleBLLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, BiLinear) }
+func BenchmarkScaleCRLargeDown(b *testing.B) { benchScale(b, 200, 150, Src, srcLarge, CatmullRom) }
+
+func BenchmarkScaleNNDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, NearestNeighbor) }
+func BenchmarkScaleABDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, ApproxBiLinear) }
+func BenchmarkScaleBLDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, BiLinear) }
+func BenchmarkScaleCRDown(b *testing.B) { benchScale(b, 120, 80, Src, srcTux, CatmullRom) }
+
+func BenchmarkScaleNNUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, NearestNeighbor) }
+func BenchmarkScaleABUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, ApproxBiLinear) }
+func BenchmarkScaleBLUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, BiLinear) }
+func BenchmarkScaleCRUp(b *testing.B) { benchScale(b, 800, 600, Src, srcTux, CatmullRom) }
+
+func BenchmarkScaleNNSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
+func BenchmarkScaleNNSrcUnif(b *testing.B) { benchScale(b, 200, 150, Src, srcUnif, NearestNeighbor) }
+
+func BenchmarkScaleNNOverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, NearestNeighbor) }
+func BenchmarkScaleNNOverUnif(b *testing.B) { benchScale(b, 200, 150, Over, srcUnif, NearestNeighbor) }
+
+func BenchmarkTformNNSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, NearestNeighbor) }
+func BenchmarkTformNNSrcUnif(b *testing.B) { benchTform(b, 200, 150, Src, srcUnif, NearestNeighbor) }
+
+func BenchmarkTformNNOverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, NearestNeighbor) }
+func BenchmarkTformNNOverUnif(b *testing.B) { benchTform(b, 200, 150, Over, srcUnif, NearestNeighbor) }
+
+func BenchmarkScaleABSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, ApproxBiLinear) }
+func BenchmarkScaleABSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
+func BenchmarkScaleABSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
+func BenchmarkScaleABSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) }
+
+func BenchmarkScaleABOverGray(b *testing.B) { benchScale(b, 200, 150, Over, srcGray, ApproxBiLinear) }
+func BenchmarkScaleABOverNRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcNRGBA, ApproxBiLinear) }
+func BenchmarkScaleABOverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, ApproxBiLinear) }
+func BenchmarkScaleABOverYCbCr(b *testing.B) { benchScale(b, 200, 150, Over, srcYCbCr, ApproxBiLinear) }
+
+func BenchmarkTformABSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, ApproxBiLinear) }
+func BenchmarkTformABSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, ApproxBiLinear) }
+func BenchmarkTformABSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, ApproxBiLinear) }
+func BenchmarkTformABSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, ApproxBiLinear) }
+
+func BenchmarkTformABOverGray(b *testing.B) { benchTform(b, 200, 150, Over, srcGray, ApproxBiLinear) }
+func BenchmarkTformABOverNRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcNRGBA, ApproxBiLinear) }
+func BenchmarkTformABOverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, ApproxBiLinear) }
+func BenchmarkTformABOverYCbCr(b *testing.B) { benchTform(b, 200, 150, Over, srcYCbCr, ApproxBiLinear) }
+
+func BenchmarkScaleCRSrcGray(b *testing.B) { benchScale(b, 200, 150, Src, srcGray, CatmullRom) }
+func BenchmarkScaleCRSrcNRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcNRGBA, CatmullRom) }
+func BenchmarkScaleCRSrcRGBA(b *testing.B) { benchScale(b, 200, 150, Src, srcRGBA, CatmullRom) }
+func BenchmarkScaleCRSrcYCbCr(b *testing.B) { benchScale(b, 200, 150, Src, srcYCbCr, CatmullRom) }
+
+func BenchmarkScaleCROverGray(b *testing.B) { benchScale(b, 200, 150, Over, srcGray, CatmullRom) }
+func BenchmarkScaleCROverNRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcNRGBA, CatmullRom) }
+func BenchmarkScaleCROverRGBA(b *testing.B) { benchScale(b, 200, 150, Over, srcRGBA, CatmullRom) }
+func BenchmarkScaleCROverYCbCr(b *testing.B) { benchScale(b, 200, 150, Over, srcYCbCr, CatmullRom) }
+
+func BenchmarkTformCRSrcGray(b *testing.B) { benchTform(b, 200, 150, Src, srcGray, CatmullRom) }
+func BenchmarkTformCRSrcNRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcNRGBA, CatmullRom) }
+func BenchmarkTformCRSrcRGBA(b *testing.B) { benchTform(b, 200, 150, Src, srcRGBA, CatmullRom) }
+func BenchmarkTformCRSrcYCbCr(b *testing.B) { benchTform(b, 200, 150, Src, srcYCbCr, CatmullRom) }
+
+func BenchmarkTformCROverGray(b *testing.B) { benchTform(b, 200, 150, Over, srcGray, CatmullRom) }
+func BenchmarkTformCROverNRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcNRGBA, CatmullRom) }
+func BenchmarkTformCROverRGBA(b *testing.B) { benchTform(b, 200, 150, Over, srcRGBA, CatmullRom) }
+func BenchmarkTformCROverYCbCr(b *testing.B) { benchTform(b, 200, 150, Over, srcYCbCr, CatmullRom) }
diff --git a/vendor/golang.org/x/image/draw/stdlib_test.go b/vendor/golang.org/x/image/draw/stdlib_test.go
new file mode 100644
index 000000000..c45f78c2e
--- /dev/null
+++ b/vendor/golang.org/x/image/draw/stdlib_test.go
@@ -0,0 +1,96 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.5
+
+package draw
+
+// This file contains tests that depend on the exact behavior of the
+// image/color package in the standard library. The color conversion formula
+// from YCbCr to RGBA changed between Go 1.4 and Go 1.5, so this file's tests
+// are only enabled for Go 1.5 and above.
+
+import (
+ "bytes"
+ "image"
+ "image/color"
+ "testing"
+)
+
+// TestFastPaths tests that the fast path implementations produce identical
+// results to the generic implementation.
+func TestFastPaths(t *testing.T) {
+ drs := []image.Rectangle{
+ image.Rect(0, 0, 10, 10), // The dst bounds.
+ image.Rect(3, 4, 8, 6), // A strict subset of the dst bounds.
+ image.Rect(-3, -5, 2, 4), // Partial out-of-bounds #0.
+ image.Rect(4, -2, 6, 12), // Partial out-of-bounds #1.
+ image.Rect(12, 14, 23, 45), // Complete out-of-bounds.
+ image.Rect(5, 5, 5, 5), // Empty.
+ }
+ srs := []image.Rectangle{
+ image.Rect(0, 0, 12, 9), // The src bounds.
+ image.Rect(2, 2, 10, 8), // A strict subset of the src bounds.
+ image.Rect(10, 5, 20, 20), // Partial out-of-bounds #0.
+ image.Rect(-40, 0, 40, 8), // Partial out-of-bounds #1.
+ image.Rect(-8, -8, -4, -4), // Complete out-of-bounds.
+ image.Rect(5, 5, 5, 5), // Empty.
+ }
+ srcfs := []func(image.Rectangle) (image.Image, error){
+ srcGray,
+ srcNRGBA,
+ srcRGBA,
+ srcUnif,
+ srcYCbCr,
+ }
+ var srcs []image.Image
+ for _, srcf := range srcfs {
+ src, err := srcf(srs[0])
+ if err != nil {
+ t.Fatal(err)
+ }
+ srcs = append(srcs, src)
+ }
+ qs := []Interpolator{
+ NearestNeighbor,
+ ApproxBiLinear,
+ CatmullRom,
+ }
+ ops := []Op{
+ Over,
+ Src,
+ }
+ blue := image.NewUniform(color.RGBA{0x11, 0x22, 0x44, 0x7f})
+
+ for _, dr := range drs {
+ for _, src := range srcs {
+ for _, sr := range srs {
+ for _, transform := range []bool{false, true} {
+ for _, q := range qs {
+ for _, op := range ops {
+ dst0 := image.NewRGBA(drs[0])
+ dst1 := image.NewRGBA(drs[0])
+ Draw(dst0, dst0.Bounds(), blue, image.Point{}, Src)
+ Draw(dstWrapper{dst1}, dst1.Bounds(), srcWrapper{blue}, image.Point{}, Src)
+
+ if transform {
+ m := transformMatrix(3.75, 2, 1)
+ q.Transform(dst0, m, src, sr, op, nil)
+ q.Transform(dstWrapper{dst1}, m, srcWrapper{src}, sr, op, nil)
+ } else {
+ q.Scale(dst0, dr, src, sr, op, nil)
+ q.Scale(dstWrapper{dst1}, dr, srcWrapper{src}, sr, op, nil)
+ }
+
+ if !bytes.Equal(dst0.Pix, dst1.Pix) {
+ t.Errorf("pix differ for dr=%v, src=%T, sr=%v, transform=%t, q=%T",
+ dr, src, sr, transform, q)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/example/font/main.go b/vendor/golang.org/x/image/example/font/main.go
new file mode 100644
index 000000000..78fd112f8
--- /dev/null
+++ b/vendor/golang.org/x/image/example/font/main.go
@@ -0,0 +1,106 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build example
+//
+// This build tag means that "go install golang.org/x/image/..." doesn't
+// install this example program. Use "go run main.go" to run it or "go install
+// -tags=example" to install it.
+
+// Font is a basic example of using fonts.
+package main
+
+import (
+ "flag"
+ "image"
+ "image/color"
+ "image/draw"
+ "image/png"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/font/plan9font"
+ "golang.org/x/image/math/fixed"
+)
+
+var (
+ fontFlag = flag.String("font", "",
+ `filename of the Plan 9 font or subfont file, such as "lucsans/unicode.8.font" or "lucsans/lsr.14"`)
+ firstRuneFlag = flag.Int("firstrune", 0, "the Unicode code point of the first rune in the subfont file")
+)
+
+func pt(p fixed.Point26_6) image.Point {
+ return image.Point{
+ X: int(p.X+32) >> 6,
+ Y: int(p.Y+32) >> 6,
+ }
+}
+
+func main() {
+ flag.Parse()
+
+ // TODO: mmap the files.
+ if *fontFlag == "" {
+ flag.Usage()
+ log.Fatal("no font specified")
+ }
+ var face font.Face
+ if strings.HasSuffix(*fontFlag, ".font") {
+ fontData, err := ioutil.ReadFile(*fontFlag)
+ if err != nil {
+ log.Fatal(err)
+ }
+ dir := filepath.Dir(*fontFlag)
+ face, err = plan9font.ParseFont(fontData, func(name string) ([]byte, error) {
+ return ioutil.ReadFile(filepath.Join(dir, filepath.FromSlash(name)))
+ })
+ if err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ fontData, err := ioutil.ReadFile(*fontFlag)
+ if err != nil {
+ log.Fatal(err)
+ }
+ face, err = plan9font.ParseSubfont(fontData, rune(*firstRuneFlag))
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ dst := image.NewRGBA(image.Rect(0, 0, 800, 300))
+ draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src)
+
+ d := &font.Drawer{
+ Dst: dst,
+ Src: image.White,
+ Face: face,
+ }
+ ss := []string{
+ "The quick brown fox jumps over the lazy dog.",
+ "Hello, 世界.",
+ "U+FFFD is \ufffd.",
+ }
+ for i, s := range ss {
+ d.Dot = fixed.P(20, 100*i+80)
+ dot0 := pt(d.Dot)
+ d.DrawString(s)
+ dot1 := pt(d.Dot)
+ dst.SetRGBA(dot0.X, dot0.Y, color.RGBA{0xff, 0x00, 0x00, 0xff})
+ dst.SetRGBA(dot1.X, dot1.Y, color.RGBA{0x00, 0x00, 0xff, 0xff})
+ }
+
+ out, err := os.Create("out.png")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer out.Close()
+ if err := png.Encode(out, dst); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/vendor/golang.org/x/image/font/basicfont/basicfont.go b/vendor/golang.org/x/image/font/basicfont/basicfont.go
new file mode 100644
index 000000000..c6b2b68c4
--- /dev/null
+++ b/vendor/golang.org/x/image/font/basicfont/basicfont.go
@@ -0,0 +1,122 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go
+
+// Package basicfont provides fixed-size font faces.
+package basicfont // import "golang.org/x/image/font/basicfont"
+
+import (
+ "image"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/math/fixed"
+)
+
+// Range maps a contiguous range of runes to vertically adjacent sub-images of
+// a Face's Mask image. The rune range is inclusive on the low end and
+// exclusive on the high end.
+//
+// If Low <= r && r < High, then the rune r is mapped to the sub-image of
+// Face.Mask whose bounds are image.Rect(0, y, Face.Width, y+Face.Height),
+// where y equals (int(r-Low) + Offset) * Face.Height.
+type Range struct {
+ Low, High rune
+ Offset int
+}
+
+// Face7x13 is a Face derived from the public domain X11 misc-fixed font files.
+//
+// At the moment, it holds the printable characters in ASCII starting with
+// space, and the Unicode replacement character U+FFFD.
+//
+// Its data is entirely self-contained and does not require loading from
+// separate files.
+var Face7x13 = &Face{
+ Advance: 7,
+ Width: 6,
+ Height: 13,
+ Ascent: 11,
+ Mask: mask7x13,
+ Ranges: []Range{
+ {'\u0020', '\u007f', 0},
+ {'\ufffd', '\ufffe', 95},
+ },
+}
+
+// Face is a basic font face whose glyphs all have the same metrics.
+//
+// It is safe to use concurrently.
+type Face struct {
+ // Advance is the glyph advance, in pixels.
+ Advance int
+ // Width is the glyph width, in pixels.
+ Width int
+ // Height is the glyph height, in pixels.
+ Height int
+ // Ascent is the glyph ascent, in pixels.
+ Ascent int
+
+ // TODO: do we also need Top and Left fields?
+
+ // Mask contains all of the glyph masks. Its width is typically the Face's
+ // Width, and its height a multiple of the Face's Height.
+ Mask image.Image
+ // Ranges map runes to sub-images of Mask. The rune ranges must not
+ // overlap, and must be in increasing rune order.
+ Ranges []Range
+}
+
+func (f *Face) Close() error { return nil }
+func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
+
+func (f *Face) Metrics() font.Metrics {
+ return font.Metrics{
+ Height: fixed.I(f.Height),
+ Ascent: fixed.I(f.Ascent),
+ Descent: fixed.I(f.Height - f.Ascent),
+ }
+}
+
+func (f *Face) Glyph(dot fixed.Point26_6, r rune) (
+ dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
+
+loop:
+ for _, rr := range [2]rune{r, '\ufffd'} {
+ for _, rng := range f.Ranges {
+ if rr < rng.Low || rng.High <= rr {
+ continue
+ }
+ maskp.Y = (int(rr-rng.Low) + rng.Offset) * f.Height
+ ok = true
+ break loop
+ }
+ }
+ if !ok {
+ return image.Rectangle{}, nil, image.Point{}, 0, false
+ }
+
+ minX := int(dot.X+32) >> 6
+ minY := int(dot.Y+32)>>6 - f.Ascent
+ dr = image.Rectangle{
+ Min: image.Point{
+ X: minX,
+ Y: minY,
+ },
+ Max: image.Point{
+ X: minX + f.Width,
+ Y: minY + f.Height,
+ },
+ }
+
+ return dr, f.Mask, maskp, fixed.I(f.Advance), true
+}
+
+func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
+ return fixed.R(0, -f.Ascent, f.Width, -f.Ascent+f.Height), fixed.I(f.Advance), true
+}
+
+func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
+ return fixed.I(f.Advance), true
+}
diff --git a/vendor/golang.org/x/image/font/basicfont/data.go b/vendor/golang.org/x/image/font/basicfont/data.go
new file mode 100644
index 000000000..883532117
--- /dev/null
+++ b/vendor/golang.org/x/image/font/basicfont/data.go
@@ -0,0 +1,1456 @@
+// generated by go generate; DO NOT EDIT.
+
+package basicfont
+
+// This data is derived from files in the font/fixed directory of the Plan 9
+// Port source code (https://github.com/9fans/plan9port) which were originally
+// based on the public domain X11 misc-fixed font files.
+
+import "image"
+
+// mask7x13 contains 96 6×13 glyphs in 7488 Pix bytes.
+var mask7x13 = &image.Alpha{
+ Stride: 6,
+ Rect: image.Rectangle{Max: image.Point{6, 96 * 13}},
+ Pix: []byte{
+ // 0x20 ' '
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x21 '!'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x22 '"'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x23 '#'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x24 '$'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x25 '%'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x26 '&'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x27 '\''
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x28 '('
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x29 ')'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x2a '*'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x2b '+'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x2c ','
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x2d '-'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x2e '.'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x2f '/'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x30 '0'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x31 '1'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x32 '2'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x33 '3'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x34 '4'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x35 '5'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x36 '6'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x37 '7'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x38 '8'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x39 '9'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x3a ':'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x3b ';'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x3c '<'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x3d '='
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x3e '>'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x3f '?'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x40 '@'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x41 'A'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x42 'B'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x43 'C'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x44 'D'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x45 'E'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x46 'F'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x47 'G'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x48 'H'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x49 'I'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x4a 'J'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x4b 'K'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x4c 'L'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x4d 'M'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x4e 'N'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x4f 'O'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x50 'P'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x51 'Q'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x52 'R'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x53 'S'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x54 'T'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x55 'U'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x56 'V'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x57 'W'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x58 'X'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x59 'Y'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x5a 'Z'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x5b '['
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x5c '\\'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x5d ']'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x5e '^'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x5f '_'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x60 '`'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x61 'a'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x62 'b'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x63 'c'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x64 'd'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x65 'e'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x66 'f'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x67 'g'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+
+ // 0x68 'h'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x69 'i'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x6a 'j'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+
+ // 0x6b 'k'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x6c 'l'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x6d 'm'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x6e 'n'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x6f 'o'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x70 'p'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x71 'q'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+
+ // 0x72 'r'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x73 's'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x74 't'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x75 'u'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x76 'v'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x77 'w'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x78 'x'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x79 'y'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0xff, 0x00, 0x00, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+
+ // 0x7a 'z'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x7b '{'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x7c '|'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x7d '}'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // 0x7e '~'
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0x00, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // U+FFFD REPLACEMENT CHARACTER
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0x00, 0xff,
+ 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0xff, 0xff, 0x00, 0xff, 0xff,
+ 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+}
diff --git a/vendor/golang.org/x/image/font/basicfont/gen.go b/vendor/golang.org/x/image/font/basicfont/gen.go
new file mode 100644
index 000000000..67a21a74a
--- /dev/null
+++ b/vendor/golang.org/x/image/font/basicfont/gen.go
@@ -0,0 +1,115 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build ignore
+
+// This program generates data.go.
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "image"
+ "image/draw"
+ "io/ioutil"
+ "log"
+ "path"
+ "path/filepath"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/font/plan9font"
+ "golang.org/x/image/math/fixed"
+)
+
+func main() {
+ // nGlyphs is the number of glyphs to generate: 95 characters in the range
+ // [0x20, 0x7e], plus the replacement character.
+ const nGlyphs = 95 + 1
+ // The particular font (unicode.7x13.font) leaves the right-most column
+ // empty in its ASCII glyphs. We don't have to include that column in the
+ // generated glyphs, so we subtract one off the effective width.
+ const width, height, ascent = 7 - 1, 13, 11
+
+ readFile := func(name string) ([]byte, error) {
+ return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name)))
+ }
+ fontData, err := readFile("unicode.7x13.font")
+ if err != nil {
+ log.Fatalf("readFile: %v", err)
+ }
+ face, err := plan9font.ParseFont(fontData, readFile)
+ if err != nil {
+ log.Fatalf("plan9font.ParseFont: %v", err)
+ }
+
+ dst := image.NewRGBA(image.Rect(0, 0, width, nGlyphs*height))
+ draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src)
+ d := &font.Drawer{
+ Dst: dst,
+ Src: image.White,
+ Face: face,
+ }
+ for i := 0; i < nGlyphs; i++ {
+ r := '\ufffd'
+ if i < nGlyphs-1 {
+ r = 0x20 + rune(i)
+ }
+ d.Dot = fixed.P(0, height*i+ascent)
+ d.DrawString(string(r))
+ }
+
+ w := bytes.NewBuffer(nil)
+ w.WriteString(preamble)
+ fmt.Fprintf(w, "// mask7x13 contains %d %d×%d glyphs in %d Pix bytes.\n", nGlyphs, width, height, nGlyphs*width*height)
+ fmt.Fprintf(w, "var mask7x13 = &image.Alpha{\n")
+ fmt.Fprintf(w, " Stride: %d,\n", width)
+ fmt.Fprintf(w, " Rect: image.Rectangle{Max: image.Point{%d, %d*%d}},\n", width, nGlyphs, height)
+ fmt.Fprintf(w, " Pix: []byte{\n")
+ b := dst.Bounds()
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ if y%height == 0 {
+ if y != 0 {
+ w.WriteByte('\n')
+ }
+ i := y / height
+ if i < nGlyphs-1 {
+ i += 0x20
+ fmt.Fprintf(w, "// %#2x %q\n", i, rune(i))
+ } else {
+ fmt.Fprintf(w, "// U+FFFD REPLACEMENT CHARACTER\n")
+ }
+ }
+
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if dst.RGBAAt(x, y).R > 0 {
+ w.WriteString("0xff,")
+ } else {
+ w.WriteString("0x00,")
+ }
+ }
+ w.WriteByte('\n')
+ }
+ w.WriteString("},\n}\n")
+
+ fmted, err := format.Source(w.Bytes())
+ if err != nil {
+ log.Fatalf("format.Source: %v", err)
+ }
+ if err := ioutil.WriteFile("data.go", fmted, 0644); err != nil {
+ log.Fatalf("ioutil.WriteFile: %v", err)
+ }
+}
+
+const preamble = `// generated by go generate; DO NOT EDIT.
+
+package basicfont
+
+// This data is derived from files in the font/fixed directory of the Plan 9
+// Port source code (https://github.com/9fans/plan9port) which were originally
+// based on the public domain X11 misc-fixed font files.
+
+import "image"
+
+`
diff --git a/vendor/golang.org/x/image/font/font.go b/vendor/golang.org/x/image/font/font.go
index 57fd61bdc..a089e7798 100644
--- a/vendor/golang.org/x/image/font/font.go
+++ b/vendor/golang.org/x/image/font/font.go
@@ -7,7 +7,7 @@
//
// Other packages provide font face implementations. For example, a truetype
// package would provide one based on .ttf font files.
-package font
+package font // import "golang.org/x/image/font"
import (
"image"
diff --git a/vendor/golang.org/x/image/font/plan9font/example_test.go b/vendor/golang.org/x/image/font/plan9font/example_test.go
new file mode 100644
index 000000000..c3e8f8917
--- /dev/null
+++ b/vendor/golang.org/x/image/font/plan9font/example_test.go
@@ -0,0 +1,92 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package plan9font_test
+
+import (
+ "image"
+ "image/draw"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/font/plan9font"
+ "golang.org/x/image/math/fixed"
+)
+
+func ExampleParseFont() {
+ readFile := func(name string) ([]byte, error) {
+ return ioutil.ReadFile(filepath.FromSlash(path.Join("../testdata/fixed", name)))
+ }
+ fontData, err := readFile("unicode.7x13.font")
+ if err != nil {
+ log.Fatal(err)
+ }
+ face, err := plan9font.ParseFont(fontData, readFile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ ascent := face.Metrics().Ascent.Ceil()
+
+ dst := image.NewRGBA(image.Rect(0, 0, 4*7, 13))
+ draw.Draw(dst, dst.Bounds(), image.Black, image.Point{}, draw.Src)
+ d := &font.Drawer{
+ Dst: dst,
+ Src: image.White,
+ Face: face,
+ Dot: fixed.P(0, ascent),
+ }
+ // Draw:
+ // - U+0053 LATIN CAPITAL LETTER S
+ // - U+03A3 GREEK CAPITAL LETTER SIGMA
+ // - U+222B INTEGRAL
+ // - U+3055 HIRAGANA LETTER SA
+ // The testdata does not contain the CJK subfont files, so U+3055 HIRAGANA
+ // LETTER SA (さ) should be rendered as U+FFFD REPLACEMENT CHARACTER (�).
+ //
+ // The missing subfont file will trigger an "open
+ // ../testdata/shinonome/k12.3000: no such file or directory" log message.
+ // This is expected and can be ignored.
+ d.DrawString("SΣ∫さ")
+
+ // Convert the dst image to ASCII art.
+ var out []byte
+ b := dst.Bounds()
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ out = append(out, '0'+byte(y%10), ' ')
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if dst.RGBAAt(x, y).R > 0 {
+ out = append(out, 'X')
+ } else {
+ out = append(out, '.')
+ }
+ }
+ // Highlight the last row before the baseline. Glyphs like 'S' without
+ // descenders should not affect any pixels whose Y coordinate is >= the
+ // baseline.
+ if y == ascent-1 {
+ out = append(out, '_')
+ }
+ out = append(out, '\n')
+ }
+ os.Stdout.Write(out)
+
+ // Output:
+ // 0 ..................X.........
+ // 1 .................X.X........
+ // 2 .XXXX..XXXXXX....X.....XXX..
+ // 3 X....X.X.........X....XX.XX.
+ // 4 X.......X........X....X.X.X.
+ // 5 X........X.......X....XXX.X.
+ // 6 .XXXX.....X......X....XX.XX.
+ // 7 .....X...X.......X....XX.XX.
+ // 8 .....X..X........X....XXXXX.
+ // 9 X....X.X.........X....XX.XX.
+ // 0 .XXXX..XXXXXX....X.....XXX.._
+ // 1 ...............X.X..........
+ // 2 ................X...........
+}
diff --git a/vendor/golang.org/x/image/font/plan9font/plan9font.go b/vendor/golang.org/x/image/font/plan9font/plan9font.go
new file mode 100644
index 000000000..af57c55e1
--- /dev/null
+++ b/vendor/golang.org/x/image/font/plan9font/plan9font.go
@@ -0,0 +1,585 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package plan9font implements font faces for the Plan 9 font and subfont file
+// formats. These formats are described at
+// http://plan9.bell-labs.com/magic/man2html/6/font
+package plan9font // import "golang.org/x/image/font/plan9font"
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "image"
+ "image/color"
+ "log"
+ "strconv"
+ "strings"
+
+ "golang.org/x/image/font"
+ "golang.org/x/image/math/fixed"
+)
+
+// fontchar describes one character glyph in a subfont.
+//
+// For more detail, look for "struct Fontchar" in
+// http://plan9.bell-labs.com/magic/man2html/2/cachechars
+type fontchar struct {
+ x uint32 // X position in the image holding the glyphs.
+ top uint8 // First non-zero scan line.
+ bottom uint8 // Last non-zero scan line.
+ left int8 // Offset of baseline.
+ width uint8 // Width of baseline.
+}
+
+func parseFontchars(p []byte) []fontchar {
+ fc := make([]fontchar, len(p)/6)
+ for i := range fc {
+ fc[i] = fontchar{
+ x: uint32(p[0]) | uint32(p[1])<<8,
+ top: uint8(p[2]),
+ bottom: uint8(p[3]),
+ left: int8(p[4]),
+ width: uint8(p[5]),
+ }
+ p = p[6:]
+ }
+ return fc
+}
+
+// subface implements font.Face for a Plan 9 subfont.
+type subface struct {
+ firstRune rune // First rune in the subfont.
+ n int // Number of characters in the subfont.
+ height int // Inter-line spacing.
+ ascent int // Height above the baseline.
+ fontchars []fontchar // Character descriptions.
+ img *image.Alpha // Image holding the glyphs.
+}
+
+func (f *subface) Close() error { return nil }
+func (f *subface) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
+
+func (f *subface) Metrics() font.Metrics {
+ return font.Metrics{
+ Height: fixed.I(f.height),
+ Ascent: fixed.I(f.ascent),
+ Descent: fixed.I(f.height - f.ascent),
+ }
+}
+
+func (f *subface) Glyph(dot fixed.Point26_6, r rune) (
+ dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
+
+ r -= f.firstRune
+ if r < 0 || f.n <= int(r) {
+ return image.Rectangle{}, nil, image.Point{}, 0, false
+ }
+ i := &f.fontchars[r+0]
+ j := &f.fontchars[r+1]
+
+ minX := int(dot.X+32)>>6 + int(i.left)
+ minY := int(dot.Y+32)>>6 + int(i.top) - f.ascent
+ dr = image.Rectangle{
+ Min: image.Point{
+ X: minX,
+ Y: minY,
+ },
+ Max: image.Point{
+ X: minX + int(j.x-i.x),
+ Y: minY + int(i.bottom) - int(i.top),
+ },
+ }
+ return dr, f.img, image.Point{int(i.x), int(i.top)}, fixed.Int26_6(i.width) << 6, true
+}
+
+func (f *subface) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
+ r -= f.firstRune
+ if r < 0 || f.n <= int(r) {
+ return fixed.Rectangle26_6{}, 0, false
+ }
+ i := &f.fontchars[r+0]
+ j := &f.fontchars[r+1]
+
+ bounds = fixed.R(
+ int(i.left),
+ int(i.top)-f.ascent,
+ int(i.left)+int(j.x-i.x),
+ int(i.bottom)-f.ascent,
+ )
+ return bounds, fixed.Int26_6(i.width) << 6, true
+}
+
+func (f *subface) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
+ r -= f.firstRune
+ if r < 0 || f.n <= int(r) {
+ return 0, false
+ }
+ return fixed.Int26_6(f.fontchars[r].width) << 6, true
+}
+
+// runeRange maps a single rune range [lo, hi] to a lazily loaded subface. Both
+// ends of the range are inclusive.
+type runeRange struct {
+ lo, hi rune
+ offset rune // subfont index that the lo rune maps to.
+ relFilename string
+ subface *subface
+ bad bool
+}
+
+// face implements font.Face for a Plan 9 font.
+//
+// It maps multiple rune ranges to *subface values. Rune ranges may overlap;
+// the first match wins.
+type face struct {
+ height int
+ ascent int
+ readFile func(relFilename string) ([]byte, error)
+ runeRanges []runeRange
+}
+
+func (f *face) Close() error { return nil }
+func (f *face) Kern(r0, r1 rune) fixed.Int26_6 { return 0 }
+
+func (f *face) Metrics() font.Metrics {
+ return font.Metrics{
+ Height: fixed.I(f.height),
+ Ascent: fixed.I(f.ascent),
+ Descent: fixed.I(f.height - f.ascent),
+ }
+}
+
+func (f *face) Glyph(dot fixed.Point26_6, r rune) (
+ dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
+
+ if s, rr := f.subface(r); s != nil {
+ return s.Glyph(dot, rr)
+ }
+ return image.Rectangle{}, nil, image.Point{}, 0, false
+}
+
+func (f *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
+ if s, rr := f.subface(r); s != nil {
+ return s.GlyphBounds(rr)
+ }
+ return fixed.Rectangle26_6{}, 0, false
+}
+
+func (f *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
+ if s, rr := f.subface(r); s != nil {
+ return s.GlyphAdvance(rr)
+ }
+ return 0, false
+}
+
+func (f *face) subface(r rune) (*subface, rune) {
+ // Fall back on U+FFFD if we can't find r.
+ for _, rr := range [2]rune{r, '\ufffd'} {
+ // We have to do linear, not binary search. plan9port's
+ // lucsans/unicode.8.font says:
+ // 0x2591 0x2593 ../luc/Altshades.7.0
+ // 0x2500 0x25ee ../luc/FormBlock.7.0
+ // and the rune ranges overlap.
+ for i := range f.runeRanges {
+ x := &f.runeRanges[i]
+ if rr < x.lo || x.hi < rr || x.bad {
+ continue
+ }
+ if x.subface == nil {
+ data, err := f.readFile(x.relFilename)
+ if err != nil {
+ log.Printf("plan9font: couldn't read subfont %q: %v", x.relFilename, err)
+ x.bad = true
+ continue
+ }
+ sub, err := ParseSubfont(data, x.lo-x.offset)
+ if err != nil {
+ log.Printf("plan9font: couldn't parse subfont %q: %v", x.relFilename, err)
+ x.bad = true
+ continue
+ }
+ x.subface = sub.(*subface)
+ }
+ return x.subface, rr
+ }
+ }
+ return nil, 0
+}
+
+// ParseFont parses a Plan 9 font file. data is the contents of that font file,
+// which gives relative filenames for subfont files. readFile returns the
+// contents of those subfont files. It is similar to io/ioutil's ReadFile
+// function, except that it takes a relative filename instead of an absolute
+// one.
+func ParseFont(data []byte, readFile func(relFilename string) ([]byte, error)) (font.Face, error) {
+ f := &face{
+ readFile: readFile,
+ }
+ // TODO: don't use strconv, to avoid the conversions from []byte to string?
+ for first := true; len(data) > 0; first = false {
+ i := bytes.IndexByte(data, '\n')
+ if i < 0 {
+ return nil, errors.New("plan9font: invalid font: no final newline")
+ }
+ row := string(data[:i])
+ data = data[i+1:]
+ if first {
+ height, s, ok := nextInt32(row)
+ if !ok {
+ return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
+ }
+ ascent, s, ok := nextInt32(s)
+ if !ok {
+ return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
+ }
+ if height < 0 || 0xffff < height || ascent < 0 || 0xffff < ascent {
+ return nil, fmt.Errorf("plan9font: invalid font: invalid header %q", row)
+ }
+ f.height, f.ascent = int(height), int(ascent)
+ continue
+ }
+ lo, s, ok := nextInt32(row)
+ if !ok {
+ return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
+ }
+ hi, s, ok := nextInt32(s)
+ if !ok {
+ return nil, fmt.Errorf("plan9font: invalid font: invalid row %q", row)
+ }
+ offset, s, _ := nextInt32(s)
+
+ f.runeRanges = append(f.runeRanges, runeRange{
+ lo: lo,
+ hi: hi,
+ offset: offset,
+ relFilename: s,
+ })
+ }
+ return f, nil
+}
+
+func nextInt32(s string) (ret int32, remaining string, ok bool) {
+ i := 0
+ for ; i < len(s) && s[i] <= ' '; i++ {
+ }
+ j := i
+ for ; j < len(s) && s[j] > ' '; j++ {
+ }
+ n, err := strconv.ParseInt(s[i:j], 0, 32)
+ if err != nil {
+ return 0, s, false
+ }
+ for ; j < len(s) && s[j] <= ' '; j++ {
+ }
+ return int32(n), s[j:], true
+}
+
+// ParseSubfont parses a Plan 9 subfont file.
+//
+// firstRune is the first rune in the subfont file. For example, the
+// Phonetic.6.0 subfont, containing glyphs in the range U+0250 to U+02E9, would
+// set firstRune to '\u0250'.
+func ParseSubfont(data []byte, firstRune rune) (font.Face, error) {
+ data, m, err := parseImage(data)
+ if err != nil {
+ return nil, err
+ }
+ if len(data) < 3*12 {
+ return nil, errors.New("plan9font: invalid subfont: header too short")
+ }
+ n := atoi(data[0*12:])
+ height := atoi(data[1*12:])
+ ascent := atoi(data[2*12:])
+ data = data[3*12:]
+ if len(data) != 6*(n+1) {
+ return nil, errors.New("plan9font: invalid subfont: data length mismatch")
+ }
+
+ // Convert from plan9Image to image.Alpha, as the standard library's
+ // image/draw package works best when glyph masks are of that type.
+ img := image.NewAlpha(m.Bounds())
+ for y := img.Rect.Min.Y; y < img.Rect.Max.Y; y++ {
+ i := img.PixOffset(img.Rect.Min.X, y)
+ for x := img.Rect.Min.X; x < img.Rect.Max.X; x++ {
+ img.Pix[i] = m.at(x, y)
+ i++
+ }
+ }
+
+ return &subface{
+ firstRune: firstRune,
+ n: n,
+ height: height,
+ ascent: ascent,
+ fontchars: parseFontchars(data),
+ img: img,
+ }, nil
+}
+
+// plan9Image implements that subset of the Plan 9 image feature set that is
+// used by this font file format.
+//
+// Some features, such as the repl bit and a clip rectangle, are omitted for
+// simplicity.
+type plan9Image struct {
+ depth int // Depth of the pixels in bits.
+ width int // Width in bytes of a single scan line.
+ rect image.Rectangle // Extent of the image.
+ pix []byte // Pixel bits.
+}
+
+func (m *plan9Image) byteoffset(x, y int) int {
+ a := y * m.width
+ if m.depth < 8 {
+ // We need to always round down, but Go rounds toward zero.
+ np := 8 / m.depth
+ if x < 0 {
+ return a + (x-np+1)/np
+ }
+ return a + x/np
+ }
+ return a + x*(m.depth/8)
+}
+
+func (m *plan9Image) Bounds() image.Rectangle { return m.rect }
+func (m *plan9Image) ColorModel() color.Model { return color.AlphaModel }
+
+func (m *plan9Image) At(x, y int) color.Color {
+ if (image.Point{x, y}).In(m.rect) {
+ return color.Alpha{m.at(x, y)}
+ }
+ return color.Alpha{0x00}
+}
+
+func (m *plan9Image) at(x, y int) uint8 {
+ b := m.pix[m.byteoffset(x, y)]
+ switch m.depth {
+ case 1:
+ // CGrey, 1.
+ mask := uint8(1 << uint8(7-x&7))
+ if (b & mask) != 0 {
+ return 0xff
+ }
+ return 0
+ case 2:
+ // CGrey, 2.
+ shift := uint(x&3) << 1
+ // Place pixel at top of word.
+ y := b << shift
+ y &= 0xc0
+ // Replicate throughout.
+ y |= y >> 2
+ y |= y >> 4
+ return y
+ }
+ return 0
+}
+
+var compressed = []byte("compressed\n")
+
+func parseImage(data []byte) (remainingData []byte, m *plan9Image, retErr error) {
+ if !bytes.HasPrefix(data, compressed) {
+ return nil, nil, errors.New("plan9font: unsupported uncompressed format")
+ }
+ data = data[len(compressed):]
+
+ const hdrSize = 5 * 12
+ if len(data) < hdrSize {
+ return nil, nil, errors.New("plan9font: invalid image: header too short")
+ }
+ hdr, data := data[:hdrSize], data[hdrSize:]
+
+ // Distinguish new channel descriptor from old ldepth. Channel descriptors
+ // have letters as well as numbers, while ldepths are a single digit
+ // formatted as %-11d.
+ new := false
+ for m := 0; m < 10; m++ {
+ if hdr[m] != ' ' {
+ new = true
+ break
+ }
+ }
+ if hdr[11] != ' ' {
+ return nil, nil, errors.New("plan9font: invalid image: bad header")
+ }
+ if !new {
+ return nil, nil, errors.New("plan9font: unsupported ldepth format")
+ }
+
+ depth := 0
+ switch s := strings.TrimSpace(string(hdr[:1*12])); s {
+ default:
+ return nil, nil, fmt.Errorf("plan9font: unsupported pixel format %q", s)
+ case "k1":
+ depth = 1
+ case "k2":
+ depth = 2
+ }
+ r := ator(hdr[1*12:])
+ if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
+ return nil, nil, errors.New("plan9font: invalid image: bad rectangle")
+ }
+
+ width := bytesPerLine(r, depth)
+ m = &plan9Image{
+ depth: depth,
+ width: width,
+ rect: r,
+ pix: make([]byte, width*r.Dy()),
+ }
+
+ miny := r.Min.Y
+ for miny != r.Max.Y {
+ if len(data) < 2*12 {
+ return nil, nil, errors.New("plan9font: invalid image: data band too short")
+ }
+ maxy := atoi(data[0*12:])
+ nb := atoi(data[1*12:])
+ data = data[2*12:]
+
+ if len(data) < nb {
+ return nil, nil, errors.New("plan9font: invalid image: data band length mismatch")
+ }
+ buf := data[:nb]
+ data = data[nb:]
+
+ if maxy <= miny || r.Max.Y < maxy {
+ return nil, nil, fmt.Errorf("plan9font: bad maxy %d", maxy)
+ }
+ // An old-format image would flip the bits here, but we don't support
+ // the old format.
+ rr := r
+ rr.Min.Y = miny
+ rr.Max.Y = maxy
+ if err := decompress(m, rr, buf); err != nil {
+ return nil, nil, err
+ }
+ miny = maxy
+ }
+ return data, m, nil
+}
+
+// Compressed data are sequences of byte codes. If the first byte b has the
+// 0x80 bit set, the next (b^0x80)+1 bytes are data. Otherwise, these two bytes
+// specify a previous string to repeat.
+const (
+ compShortestMatch = 3 // shortest match possible.
+ compWindowSize = 1024 // window size.
+)
+
+var (
+ errDecompressBufferTooSmall = errors.New("plan9font: decompress: buffer too small")
+ errDecompressPhaseError = errors.New("plan9font: decompress: phase error")
+)
+
+func decompress(m *plan9Image, r image.Rectangle, data []byte) error {
+ if !r.In(m.rect) {
+ return errors.New("plan9font: decompress: bad rectangle")
+ }
+ bpl := bytesPerLine(r, m.depth)
+ mem := make([]byte, compWindowSize)
+ memi := 0
+ omemi := -1
+ y := r.Min.Y
+ linei := m.byteoffset(r.Min.X, y)
+ eline := linei + bpl
+ datai := 0
+ for {
+ if linei == eline {
+ y++
+ if y == r.Max.Y {
+ break
+ }
+ linei = m.byteoffset(r.Min.X, y)
+ eline = linei + bpl
+ }
+ if datai == len(data) {
+ return errDecompressBufferTooSmall
+ }
+ c := data[datai]
+ datai++
+ if c >= 128 {
+ for cnt := c - 128 + 1; cnt != 0; cnt-- {
+ if datai == len(data) {
+ return errDecompressBufferTooSmall
+ }
+ if linei == eline {
+ return errDecompressPhaseError
+ }
+ m.pix[linei] = data[datai]
+ linei++
+ mem[memi] = data[datai]
+ memi++
+ datai++
+ if memi == len(mem) {
+ memi = 0
+ }
+ }
+ } else {
+ if datai == len(data) {
+ return errDecompressBufferTooSmall
+ }
+ offs := int(data[datai]) + ((int(c) & 3) << 8) + 1
+ datai++
+ if memi < offs {
+ omemi = memi + (compWindowSize - offs)
+ } else {
+ omemi = memi - offs
+ }
+ for cnt := (c >> 2) + compShortestMatch; cnt != 0; cnt-- {
+ if linei == eline {
+ return errDecompressPhaseError
+ }
+ m.pix[linei] = mem[omemi]
+ linei++
+ mem[memi] = mem[omemi]
+ memi++
+ omemi++
+ if omemi == len(mem) {
+ omemi = 0
+ }
+ if memi == len(mem) {
+ memi = 0
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func ator(b []byte) image.Rectangle {
+ return image.Rectangle{atop(b), atop(b[2*12:])}
+}
+
+func atop(b []byte) image.Point {
+ return image.Pt(atoi(b), atoi(b[12:]))
+}
+
+func atoi(b []byte) int {
+ i := 0
+ for ; i < len(b) && b[i] == ' '; i++ {
+ }
+ n := 0
+ for ; i < len(b) && '0' <= b[i] && b[i] <= '9'; i++ {
+ n = n*10 + int(b[i]) - '0'
+ }
+ return n
+}
+
+func bytesPerLine(r image.Rectangle, depth int) int {
+ if depth <= 0 || 32 < depth {
+ panic("invalid depth")
+ }
+ var l int
+ if r.Min.X >= 0 {
+ l = (r.Max.X*depth + 7) / 8
+ l -= (r.Min.X * depth) / 8
+ } else {
+ // Make positive before divide.
+ t := (-r.Min.X*depth + 7) / 8
+ l = t + (r.Max.X*depth+7)/8
+ }
+ return l
+}
diff --git a/vendor/golang.org/x/image/font/plan9font/plan9font_test.go b/vendor/golang.org/x/image/font/plan9font/plan9font_test.go
new file mode 100644
index 000000000..23393a176
--- /dev/null
+++ b/vendor/golang.org/x/image/font/plan9font/plan9font_test.go
@@ -0,0 +1,24 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package plan9font
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+)
+
+func BenchmarkParseSubfont(b *testing.B) {
+ subfontData, err := ioutil.ReadFile(filepath.FromSlash("../testdata/fixed/7x13.0000"))
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ if _, err := ParseSubfont(subfontData, 0); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.0000 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0000
new file mode 100644
index 000000000..9509cdf97
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0000
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.0100 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0100
new file mode 100644
index 000000000..0a79f555c
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0100
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.0200 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0200
new file mode 100644
index 000000000..e25247ecc
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0200
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.0300 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0300
new file mode 100644
index 000000000..86eb33f42
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0300
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.0400 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0400
new file mode 100644
index 000000000..43300ad95
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0400
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.0500 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0500
new file mode 100644
index 000000000..2d9326708
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0500
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.0E00 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0E00
new file mode 100644
index 000000000..7c51a1e51
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.0E00
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.1000 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1000
new file mode 100644
index 000000000..019698c8d
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1000
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.1600 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1600
new file mode 100644
index 000000000..f69a97745
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1600
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.1E00 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1E00
new file mode 100644
index 000000000..3bc5068cf
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1E00
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.1F00 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1F00
new file mode 100644
index 000000000..43b320be1
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.1F00
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2000 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2000
new file mode 100644
index 000000000..f9244e1cf
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2000
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2100 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2100
new file mode 100644
index 000000000..c565abb7d
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2100
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2200 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2200
new file mode 100644
index 000000000..a992d3521
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2200
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2300 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2300
new file mode 100644
index 000000000..8ff099d19
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2300
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2400 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2400
new file mode 100644
index 000000000..99927a11f
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2400
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2500 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2500
new file mode 100644
index 000000000..60dc224cd
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2500
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2600 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2600
new file mode 100644
index 000000000..1b393c28b
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2600
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2700 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2700
new file mode 100644
index 000000000..c39a57206
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2700
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2800 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2800
new file mode 100644
index 000000000..c7572de47
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2800
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.2A00 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2A00
new file mode 100644
index 000000000..71791ace6
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.2A00
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.3000 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.3000
new file mode 100644
index 000000000..fb830f4fb
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.3000
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.FB00 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.FB00
new file mode 100644
index 000000000..3a0b30a99
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.FB00
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.FE00 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.FE00
new file mode 100644
index 000000000..3989d2673
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.FE00
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/7x13.FF00 b/vendor/golang.org/x/image/font/testdata/fixed/7x13.FF00
new file mode 100644
index 000000000..78ed39865
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/7x13.FF00
Binary files differ
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/README b/vendor/golang.org/x/image/font/testdata/fixed/README
new file mode 100644
index 000000000..a39f8a5e2
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/README
@@ -0,0 +1,9 @@
+These font files were copied from the Plan 9 Port's font/fixed directory. The
+README in that directory states that: "These fonts are converted from the BDFs
+in the XFree86 distribution. They were all marked as public domain."
+
+The Plan 9 Port is at https://github.com/9fans/plan9port and the copy was made
+from commit a78b1841 (2015-08-18).
+
+The unicode.7x13.font file also refers to a ../shinonome directory, but this
+testdata does not include those subfont files.
diff --git a/vendor/golang.org/x/image/font/testdata/fixed/unicode.7x13.font b/vendor/golang.org/x/image/font/testdata/fixed/unicode.7x13.font
new file mode 100644
index 000000000..f1dc0e539
--- /dev/null
+++ b/vendor/golang.org/x/image/font/testdata/fixed/unicode.7x13.font
@@ -0,0 +1,68 @@
+13 11
+0x0000 0x001F 7x13.2400
+0x0000 0x00FF 7x13.0000
+0x0100 0x01FF 7x13.0100
+0x0200 0x02FF 7x13.0200
+0x0300 0x03FF 7x13.0300
+0x0400 0x04FF 7x13.0400
+0x0500 0x05FF 7x13.0500
+0x0E00 0x0EFF 7x13.0E00
+0x1000 0x10FF 7x13.1000
+0x1600 0x16FF 7x13.1600
+0x1E00 0x1EFF 7x13.1E00
+0x1F00 0x1FFF 7x13.1F00
+0x2000 0x20FF 7x13.2000
+0x2100 0x21FF 7x13.2100
+0x2200 0x22FF 7x13.2200
+0x2300 0x23FF 7x13.2300
+0x2400 0x24FF 7x13.2400
+0x2500 0x25FF 7x13.2500
+0x2600 0x26FF 7x13.2600
+0x2700 0x27FF 7x13.2700
+0x2800 0x28FF 7x13.2800
+0x2A00 0x2AFF 7x13.2A00
+0x3000 0x30fe ../shinonome/k12.3000
+0x4e00 0x4ffe ../shinonome/k12.4e00
+0x5005 0x51fe ../shinonome/k12.5005
+0x5200 0x53fa ../shinonome/k12.5200
+0x5401 0x55fe ../shinonome/k12.5401
+0x5606 0x57fc ../shinonome/k12.5606
+0x5800 0x59ff ../shinonome/k12.5800
+0x5a01 0x5bff ../shinonome/k12.5a01
+0x5c01 0x5dfe ../shinonome/k12.5c01
+0x5e02 0x5fff ../shinonome/k12.5e02
+0x600e 0x61ff ../shinonome/k12.600e
+0x6200 0x63fa ../shinonome/k12.6200
+0x6406 0x65fb ../shinonome/k12.6406
+0x6602 0x67ff ../shinonome/k12.6602
+0x6802 0x69ff ../shinonome/k12.6802
+0x6a02 0x6bf3 ../shinonome/k12.6a02
+0x6c08 0x6dfb ../shinonome/k12.6c08
+0x6e05 0x6ffe ../shinonome/k12.6e05
+0x7001 0x71ff ../shinonome/k12.7001
+0x7206 0x73fe ../shinonome/k12.7206
+0x7403 0x75ff ../shinonome/k12.7403
+0x7601 0x77fc ../shinonome/k12.7601
+0x7802 0x79fb ../shinonome/k12.7802
+0x7a00 0x7bf7 ../shinonome/k12.7a00
+0x7c00 0x7dfb ../shinonome/k12.7c00
+0x7e01 0x7ffc ../shinonome/k12.7e01
+0x8000 0x81fe ../shinonome/k12.8000
+0x8201 0x83fd ../shinonome/k12.8201
+0x8403 0x85fe ../shinonome/k12.8403
+0x8602 0x87fe ../shinonome/k12.8602
+0x8805 0x89f8 ../shinonome/k12.8805
+0x8a00 0x8b9a ../shinonome/k12.8a00
+0x8c37 0x8dff ../shinonome/k12.8c37
+0x8e08 0x8ffd ../shinonome/k12.8e08
+0x9000 0x91ff ../shinonome/k12.9000
+0x920d 0x93e8 ../shinonome/k12.920d
+0x9403 0x95e5 ../shinonome/k12.9403
+0x961c 0x97ff ../shinonome/k12.961c
+0x9801 0x99ff ../shinonome/k12.9801
+0x9a01 0x9bf5 ../shinonome/k12.9a01
+0x9c04 0x9dfd ../shinonome/k12.9c04
+0x9e1a 0x9fa0 ../shinonome/k12.9e1a
+0xFB00 0xFBFF 7x13.FB00
+0xFE00 0xFEFF 7x13.FE00
+0xFF00 0xFFFF 7x13.FF00
diff --git a/vendor/golang.org/x/image/math/f32/f32.go b/vendor/golang.org/x/image/math/f32/f32.go
new file mode 100644
index 000000000..4ca1eb47d
--- /dev/null
+++ b/vendor/golang.org/x/image/math/f32/f32.go
@@ -0,0 +1,37 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package f32 implements float32 vector and matrix types.
+package f32 // import "golang.org/x/image/math/f32"
+
+// Vec2 is a 2-element vector.
+type Vec2 [2]float32
+
+// Vec3 is a 3-element vector.
+type Vec3 [3]float32
+
+// Vec4 is a 4-element vector.
+type Vec4 [4]float32
+
+// Mat3 is a 3x3 matrix in row major order.
+//
+// m[3*r + c] is the element in the r'th row and c'th column.
+type Mat3 [9]float32
+
+// Mat4 is a 4x4 matrix in row major order.
+//
+// m[4*r + c] is the element in the r'th row and c'th column.
+type Mat4 [16]float32
+
+// Aff3 is a 3x3 affine transformation matrix in row major order, where the
+// bottom row is implicitly [0 0 1].
+//
+// m[3*r + c] is the element in the r'th row and c'th column.
+type Aff3 [6]float32
+
+// Aff4 is a 4x4 affine transformation matrix in row major order, where the
+// bottom row is implicitly [0 0 0 1].
+//
+// m[4*r + c] is the element in the r'th row and c'th column.
+type Aff4 [12]float32
diff --git a/vendor/golang.org/x/image/math/f64/f64.go b/vendor/golang.org/x/image/math/f64/f64.go
new file mode 100644
index 000000000..a1f7fc0ef
--- /dev/null
+++ b/vendor/golang.org/x/image/math/f64/f64.go
@@ -0,0 +1,37 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package f64 implements float64 vector and matrix types.
+package f64 // import "golang.org/x/image/math/f64"
+
+// Vec2 is a 2-element vector.
+type Vec2 [2]float64
+
+// Vec3 is a 3-element vector.
+type Vec3 [3]float64
+
+// Vec4 is a 4-element vector.
+type Vec4 [4]float64
+
+// Mat3 is a 3x3 matrix in row major order.
+//
+// m[3*r + c] is the element in the r'th row and c'th column.
+type Mat3 [9]float64
+
+// Mat4 is a 4x4 matrix in row major order.
+//
+// m[4*r + c] is the element in the r'th row and c'th column.
+type Mat4 [16]float64
+
+// Aff3 is a 3x3 affine transformation matrix in row major order, where the
+// bottom row is implicitly [0 0 1].
+//
+// m[3*r + c] is the element in the r'th row and c'th column.
+type Aff3 [6]float64
+
+// Aff4 is a 4x4 affine transformation matrix in row major order, where the
+// bottom row is implicitly [0 0 0 1].
+//
+// m[4*r + c] is the element in the r'th row and c'th column.
+type Aff4 [12]float64
diff --git a/vendor/golang.org/x/image/math/fixed/fixed.go b/vendor/golang.org/x/image/math/fixed/fixed.go
index cc7bac79e..df3540a3a 100644
--- a/vendor/golang.org/x/image/math/fixed/fixed.go
+++ b/vendor/golang.org/x/image/math/fixed/fixed.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package fixed implements fixed-point integer types.
-package fixed
+package fixed // import "golang.org/x/image/math/fixed"
import (
"fmt"
diff --git a/vendor/golang.org/x/image/math/fixed/fixed_test.go b/vendor/golang.org/x/image/math/fixed/fixed_test.go
new file mode 100644
index 000000000..065ab00b0
--- /dev/null
+++ b/vendor/golang.org/x/image/math/fixed/fixed_test.go
@@ -0,0 +1,110 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fixed
+
+import (
+ "testing"
+)
+
+var testCases = []struct {
+ x float64
+ s26_6 string
+ s52_12 string
+ floor int
+ round int
+ ceil int
+}{{
+ x: 0,
+ s26_6: "0:00",
+ s52_12: "0:0000",
+ floor: 0,
+ round: 0,
+ ceil: 0,
+}, {
+ x: 1,
+ s26_6: "1:00",
+ s52_12: "1:0000",
+ floor: 1,
+ round: 1,
+ ceil: 1,
+}, {
+ x: 1.25,
+ s26_6: "1:16",
+ s52_12: "1:1024",
+ floor: 1,
+ round: 1,
+ ceil: 2,
+}, {
+ x: 2.5,
+ s26_6: "2:32",
+ s52_12: "2:2048",
+ floor: 2,
+ round: 3,
+ ceil: 3,
+}, {
+ x: 63 / 64.0,
+ s26_6: "0:63",
+ s52_12: "0:4032",
+ floor: 0,
+ round: 1,
+ ceil: 1,
+}, {
+ x: -0.5,
+ s26_6: "-0:32",
+ s52_12: "-0:2048",
+ floor: -1,
+ round: +0,
+ ceil: +0,
+}, {
+ x: -4.125,
+ s26_6: "-4:08",
+ s52_12: "-4:0512",
+ floor: -5,
+ round: -4,
+ ceil: -4,
+}, {
+ x: -7.75,
+ s26_6: "-7:48",
+ s52_12: "-7:3072",
+ floor: -8,
+ round: -8,
+ ceil: -7,
+}}
+
+func TestInt26_6(t *testing.T) {
+ for _, tc := range testCases {
+ x := Int26_6(tc.x * (1 << 6))
+ if got, want := x.String(), tc.s26_6; got != want {
+ t.Errorf("tc.x=%v: String: got %q, want %q", tc.x, got, want)
+ }
+ if got, want := x.Floor(), tc.floor; got != want {
+ t.Errorf("tc.x=%v: Floor: got %v, want %v", tc.x, got, want)
+ }
+ if got, want := x.Round(), tc.round; got != want {
+ t.Errorf("tc.x=%v: Round: got %v, want %v", tc.x, got, want)
+ }
+ if got, want := x.Ceil(), tc.ceil; got != want {
+ t.Errorf("tc.x=%v: Ceil: got %v, want %v", tc.x, got, want)
+ }
+ }
+}
+
+func TestInt52_12(t *testing.T) {
+ for _, tc := range testCases {
+ x := Int52_12(tc.x * (1 << 12))
+ if got, want := x.String(), tc.s52_12; got != want {
+ t.Errorf("tc.x=%v: String: got %q, want %q", tc.x, got, want)
+ }
+ if got, want := x.Floor(), tc.floor; got != want {
+ t.Errorf("tc.x=%v: Floor: got %v, want %v", tc.x, got, want)
+ }
+ if got, want := x.Round(), tc.round; got != want {
+ t.Errorf("tc.x=%v: Round: got %v, want %v", tc.x, got, want)
+ }
+ if got, want := x.Ceil(), tc.ceil; got != want {
+ t.Errorf("tc.x=%v: Ceil: got %v, want %v", tc.x, got, want)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/riff/example_test.go b/vendor/golang.org/x/image/riff/example_test.go
new file mode 100644
index 000000000..93c72b095
--- /dev/null
+++ b/vendor/golang.org/x/image/riff/example_test.go
@@ -0,0 +1,113 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package riff_test
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "strings"
+
+ "golang.org/x/image/riff"
+)
+
+func ExampleReader() {
+ formType, r, err := riff.NewReader(strings.NewReader(data))
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("RIFF(%s)\n", formType)
+ if err := dump(r, ".\t"); err != nil {
+ log.Fatal(err)
+ }
+ // Output:
+ // RIFF(ROOT)
+ // . ZERO ""
+ // . ONE "a"
+ // . LIST(META)
+ // . . LIST(GOOD)
+ // . . . ONE "a"
+ // . . . FIVE "klmno"
+ // . . ZERO ""
+ // . . LIST(BAD )
+ // . . . THRE "def"
+ // . TWO "bc"
+ // . LIST(UGLY)
+ // . . FOUR "ghij"
+ // . . SIX "pqrstu"
+}
+
+func dump(r *riff.Reader, indent string) error {
+ for {
+ chunkID, chunkLen, chunkData, err := r.Next()
+ if err == io.EOF {
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ if chunkID == riff.LIST {
+ listType, list, err := riff.NewListReader(chunkLen, chunkData)
+ if err != nil {
+ return err
+ }
+ fmt.Printf("%sLIST(%s)\n", indent, listType)
+ if err := dump(list, indent+".\t"); err != nil {
+ return err
+ }
+ continue
+ }
+ b, err := ioutil.ReadAll(chunkData)
+ if err != nil {
+ return err
+ }
+ fmt.Printf("%s%s %q\n", indent, chunkID, b)
+ }
+}
+
+func encodeU32(u uint32) string {
+ return string([]byte{
+ byte(u >> 0),
+ byte(u >> 8),
+ byte(u >> 16),
+ byte(u >> 24),
+ })
+}
+
+func encode(chunkID, contents string) string {
+ n := len(contents)
+ if n&1 == 1 {
+ contents += "\x00"
+ }
+ return chunkID + encodeU32(uint32(n)) + contents
+}
+
+func encodeMulti(typ0, typ1 string, chunks ...string) string {
+ n := 4
+ for _, c := range chunks {
+ n += len(c)
+ }
+ s := typ0 + encodeU32(uint32(n)) + typ1
+ for _, c := range chunks {
+ s += c
+ }
+ return s
+}
+
+var (
+ d0 = encode("ZERO", "")
+ d1 = encode("ONE ", "a")
+ d2 = encode("TWO ", "bc")
+ d3 = encode("THRE", "def")
+ d4 = encode("FOUR", "ghij")
+ d5 = encode("FIVE", "klmno")
+ d6 = encode("SIX ", "pqrstu")
+ l0 = encodeMulti("LIST", "GOOD", d1, d5)
+ l1 = encodeMulti("LIST", "BAD ", d3)
+ l2 = encodeMulti("LIST", "UGLY", d4, d6)
+ l01 = encodeMulti("LIST", "META", l0, d0, l1)
+ data = encodeMulti("RIFF", "ROOT", d0, d1, l01, d2, l2)
+)
diff --git a/vendor/golang.org/x/image/riff/riff.go b/vendor/golang.org/x/image/riff/riff.go
new file mode 100644
index 000000000..9b9f71d81
--- /dev/null
+++ b/vendor/golang.org/x/image/riff/riff.go
@@ -0,0 +1,179 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package riff implements the Resource Interchange File Format, used by media
+// formats such as AVI, WAVE and WEBP.
+//
+// A RIFF stream contains a sequence of chunks. Each chunk consists of an 8-byte
+// header (containing a 4-byte chunk type and a 4-byte chunk length), the chunk
+// data (presented as an io.Reader), and some padding bytes.
+//
+// A detailed description of the format is at
+// http://www.tactilemedia.com/info/MCI_Control_Info.html
+package riff // import "golang.org/x/image/riff"
+
+import (
+ "errors"
+ "io"
+ "io/ioutil"
+ "math"
+)
+
+var (
+ errMissingPaddingByte = errors.New("riff: missing padding byte")
+ errMissingRIFFChunkHeader = errors.New("riff: missing RIFF chunk header")
+ errShortChunkData = errors.New("riff: short chunk data")
+ errShortChunkHeader = errors.New("riff: short chunk header")
+ errStaleReader = errors.New("riff: stale reader")
+)
+
+// u32 decodes the first four bytes of b as a little-endian integer.
+func u32(b []byte) uint32 {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+const chunkHeaderSize = 8
+
+// FourCC is a four character code.
+type FourCC [4]byte
+
+// LIST is the "LIST" FourCC.
+var LIST = FourCC{'L', 'I', 'S', 'T'}
+
+// NewReader returns the RIFF stream's form type, such as "AVI " or "WAVE", and
+// its chunks as a *Reader.
+func NewReader(r io.Reader) (formType FourCC, data *Reader, err error) {
+ var buf [chunkHeaderSize]byte
+ if _, err := io.ReadFull(r, buf[:]); err != nil {
+ if err == io.EOF || err == io.ErrUnexpectedEOF {
+ err = errMissingRIFFChunkHeader
+ }
+ return FourCC{}, nil, err
+ }
+ if buf[0] != 'R' || buf[1] != 'I' || buf[2] != 'F' || buf[3] != 'F' {
+ return FourCC{}, nil, errMissingRIFFChunkHeader
+ }
+ return NewListReader(u32(buf[4:]), r)
+}
+
+// NewListReader returns a LIST chunk's list type, such as "movi" or "wavl",
+// and its chunks as a *Reader.
+func NewListReader(chunkLen uint32, chunkData io.Reader) (listType FourCC, data *Reader, err error) {
+ if chunkLen < 4 {
+ return FourCC{}, nil, errShortChunkData
+ }
+ z := &Reader{r: chunkData}
+ if _, err := io.ReadFull(chunkData, z.buf[:4]); err != nil {
+ if err == io.EOF || err == io.ErrUnexpectedEOF {
+ err = errShortChunkData
+ }
+ return FourCC{}, nil, err
+ }
+ z.totalLen = chunkLen - 4
+ return FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}, z, nil
+}
+
+// Reader reads chunks from an underlying io.Reader.
+type Reader struct {
+ r io.Reader
+ err error
+
+ totalLen uint32
+ chunkLen uint32
+
+ chunkReader *chunkReader
+ buf [chunkHeaderSize]byte
+ padded bool
+}
+
+// Next returns the next chunk's ID, length and data. It returns io.EOF if there
+// are no more chunks. The io.Reader returned becomes stale after the next Next
+// call, and should no longer be used.
+//
+// It is valid to call Next even if all of the previous chunk's data has not
+// been read.
+func (z *Reader) Next() (chunkID FourCC, chunkLen uint32, chunkData io.Reader, err error) {
+ if z.err != nil {
+ return FourCC{}, 0, nil, z.err
+ }
+
+ // Drain the rest of the previous chunk.
+ if z.chunkLen != 0 {
+ _, z.err = io.Copy(ioutil.Discard, z.chunkReader)
+ if z.err != nil {
+ return FourCC{}, 0, nil, z.err
+ }
+ }
+ z.chunkReader = nil
+ if z.padded {
+ _, z.err = io.ReadFull(z.r, z.buf[:1])
+ if z.err != nil {
+ if z.err == io.EOF {
+ z.err = errMissingPaddingByte
+ }
+ return FourCC{}, 0, nil, z.err
+ }
+ z.totalLen--
+ }
+
+ // We are done if we have no more data.
+ if z.totalLen == 0 {
+ z.err = io.EOF
+ return FourCC{}, 0, nil, z.err
+ }
+
+ // Read the next chunk header.
+ if z.totalLen < chunkHeaderSize {
+ z.err = errShortChunkHeader
+ return FourCC{}, 0, nil, z.err
+ }
+ z.totalLen -= chunkHeaderSize
+ if _, err = io.ReadFull(z.r, z.buf[:chunkHeaderSize]); err != nil {
+ if z.err == io.EOF || z.err == io.ErrUnexpectedEOF {
+ z.err = errShortChunkHeader
+ }
+ return FourCC{}, 0, nil, z.err
+ }
+ chunkID = FourCC{z.buf[0], z.buf[1], z.buf[2], z.buf[3]}
+ z.chunkLen = u32(z.buf[4:])
+ z.padded = z.chunkLen&1 == 1
+ z.chunkReader = &chunkReader{z}
+ return chunkID, z.chunkLen, z.chunkReader, nil
+}
+
+type chunkReader struct {
+ z *Reader
+}
+
+func (c *chunkReader) Read(p []byte) (int, error) {
+ if c != c.z.chunkReader {
+ return 0, errStaleReader
+ }
+ z := c.z
+ if z.err != nil {
+ if z.err == io.EOF {
+ return 0, errStaleReader
+ }
+ return 0, z.err
+ }
+
+ n := int(z.chunkLen)
+ if n == 0 {
+ return 0, io.EOF
+ }
+ if n < 0 {
+ // Converting uint32 to int overflowed.
+ n = math.MaxInt32
+ }
+ if n > len(p) {
+ n = len(p)
+ }
+ n, err := z.r.Read(p[:n])
+ z.totalLen -= uint32(n)
+ z.chunkLen -= uint32(n)
+ if err != io.EOF {
+ z.err = err
+ }
+ return n, err
+}
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.lossless.webp b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.lossless.webp
new file mode 100644
index 000000000..d00c81fb0
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webp b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webp
new file mode 100644
index 000000000..9067f4df3
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webp.ycbcr.png b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webp.ycbcr.png
new file mode 100644
index 000000000..2e32c281b
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.no-filter.lossy.webp.ycbcr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webp b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webp
new file mode 100644
index 000000000..a4ccc1a2d
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webp.ycbcr.png b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webp.ycbcr.png
new file mode 100644
index 000000000..5f7ec42de
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.normal-filter.lossy.webp.ycbcr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.png b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.png
new file mode 100644
index 000000000..97555050a
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webp b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webp
new file mode 100644
index 000000000..09fdb94b8
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webp.ycbcr.png b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webp.ycbcr.png
new file mode 100644
index 000000000..946b3afac
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink-large.simple-filter.lossy.webp.ycbcr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink.lossless.webp b/vendor/golang.org/x/image/testdata/blue-purple-pink.lossless.webp
new file mode 100644
index 000000000..b16a50ddf
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webp b/vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webp
new file mode 100644
index 000000000..d5143c0af
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webp.ycbcr.png b/vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webp.ycbcr.png
new file mode 100644
index 000000000..eb51560cd
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink.lossy.webp.ycbcr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink.lzwcompressed.tiff b/vendor/golang.org/x/image/testdata/blue-purple-pink.lzwcompressed.tiff
new file mode 100644
index 000000000..5978f7a7c
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink.lzwcompressed.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/blue-purple-pink.png b/vendor/golang.org/x/image/testdata/blue-purple-pink.png
new file mode 100644
index 000000000..d4fbf6b37
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/blue-purple-pink.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/bw-deflate.tiff b/vendor/golang.org/x/image/testdata/bw-deflate.tiff
new file mode 100644
index 000000000..137a0c3ef
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/bw-deflate.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/bw-packbits.tiff b/vendor/golang.org/x/image/testdata/bw-packbits.tiff
new file mode 100644
index 000000000..d59fa4aee
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/bw-packbits.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/bw-uncompressed.tiff b/vendor/golang.org/x/image/testdata/bw-uncompressed.tiff
new file mode 100644
index 000000000..8390f1135
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/bw-uncompressed.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-14x18.png b/vendor/golang.org/x/image/testdata/go-turns-two-14x18.png
new file mode 100644
index 000000000..b6494b6be
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-14x18.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-280x360.jpeg b/vendor/golang.org/x/image/testdata/go-turns-two-280x360.jpeg
new file mode 100644
index 000000000..b56e492a6
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-280x360.jpeg
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-down-ab.png b/vendor/golang.org/x/image/testdata/go-turns-two-down-ab.png
new file mode 100644
index 000000000..317c3afa1
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-down-ab.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-down-bl.png b/vendor/golang.org/x/image/testdata/go-turns-two-down-bl.png
new file mode 100644
index 000000000..597d3628d
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-down-bl.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-down-cr.png b/vendor/golang.org/x/image/testdata/go-turns-two-down-cr.png
new file mode 100644
index 000000000..ad1c20a2f
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-down-cr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-down-nn.png b/vendor/golang.org/x/image/testdata/go-turns-two-down-nn.png
new file mode 100644
index 000000000..166841a76
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-down-nn.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-rotate-ab.png b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-ab.png
new file mode 100644
index 000000000..04fceaa77
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-ab.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-rotate-bl.png b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-bl.png
new file mode 100644
index 000000000..c8b717e22
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-bl.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-rotate-cr.png b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-cr.png
new file mode 100644
index 000000000..7e5cd9f62
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-cr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-rotate-nn.png b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-nn.png
new file mode 100644
index 000000000..702c86352
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-rotate-nn.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-up-ab.png b/vendor/golang.org/x/image/testdata/go-turns-two-up-ab.png
new file mode 100644
index 000000000..072446dc9
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-up-ab.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-up-bl.png b/vendor/golang.org/x/image/testdata/go-turns-two-up-bl.png
new file mode 100644
index 000000000..c1bf630f4
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-up-bl.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-up-cr.png b/vendor/golang.org/x/image/testdata/go-turns-two-up-cr.png
new file mode 100644
index 000000000..0ac83002f
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-up-cr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/go-turns-two-up-nn.png b/vendor/golang.org/x/image/testdata/go-turns-two-up-nn.png
new file mode 100644
index 000000000..eb63cb91e
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/go-turns-two-up-nn.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.1bpp.lossless.webp b/vendor/golang.org/x/image/testdata/gopher-doc.1bpp.lossless.webp
new file mode 100644
index 000000000..fcca02873
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.1bpp.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.1bpp.png b/vendor/golang.org/x/image/testdata/gopher-doc.1bpp.png
new file mode 100644
index 000000000..9c5bb64f2
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.1bpp.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.2bpp.lossless.webp b/vendor/golang.org/x/image/testdata/gopher-doc.2bpp.lossless.webp
new file mode 100644
index 000000000..d683d47fc
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.2bpp.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.2bpp.png b/vendor/golang.org/x/image/testdata/gopher-doc.2bpp.png
new file mode 100644
index 000000000..af96769c5
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.2bpp.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.4bpp.lossless.webp b/vendor/golang.org/x/image/testdata/gopher-doc.4bpp.lossless.webp
new file mode 100644
index 000000000..11d8ef19b
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.4bpp.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.4bpp.png b/vendor/golang.org/x/image/testdata/gopher-doc.4bpp.png
new file mode 100644
index 000000000..fc1813778
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.4bpp.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.8bpp.lossless.webp b/vendor/golang.org/x/image/testdata/gopher-doc.8bpp.lossless.webp
new file mode 100644
index 000000000..b6468e9b5
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.8bpp.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/gopher-doc.8bpp.png b/vendor/golang.org/x/image/testdata/gopher-doc.8bpp.png
new file mode 100644
index 000000000..b877c5411
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/gopher-doc.8bpp.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/no_compress.tiff b/vendor/golang.org/x/image/testdata/no_compress.tiff
new file mode 100644
index 000000000..3f72b29ae
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/no_compress.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/no_rps.tiff b/vendor/golang.org/x/image/testdata/no_rps.tiff
new file mode 100644
index 000000000..3280cf8e3
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/no_rps.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/testpattern.png b/vendor/golang.org/x/image/testdata/testpattern.png
new file mode 100644
index 000000000..ec87bb56a
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/testpattern.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/tux-rotate-ab.png b/vendor/golang.org/x/image/testdata/tux-rotate-ab.png
new file mode 100644
index 000000000..181966cae
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/tux-rotate-ab.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/tux-rotate-bl.png b/vendor/golang.org/x/image/testdata/tux-rotate-bl.png
new file mode 100644
index 000000000..af3f4b0d5
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/tux-rotate-bl.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/tux-rotate-cr.png b/vendor/golang.org/x/image/testdata/tux-rotate-cr.png
new file mode 100644
index 000000000..e5cff31f1
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/tux-rotate-cr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/tux-rotate-nn.png b/vendor/golang.org/x/image/testdata/tux-rotate-nn.png
new file mode 100644
index 000000000..c775c61dc
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/tux-rotate-nn.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/tux.lossless.webp b/vendor/golang.org/x/image/testdata/tux.lossless.webp
new file mode 100644
index 000000000..3b32c02a7
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/tux.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/tux.png b/vendor/golang.org/x/image/testdata/tux.png
new file mode 100644
index 000000000..2567fe7ca
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/tux.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001-16bit.tiff b/vendor/golang.org/x/image/testdata/video-001-16bit.tiff
new file mode 100644
index 000000000..3b05ef018
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001-16bit.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001-gray-16bit.tiff b/vendor/golang.org/x/image/testdata/video-001-gray-16bit.tiff
new file mode 100644
index 000000000..356882a56
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001-gray-16bit.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001-gray.tiff b/vendor/golang.org/x/image/testdata/video-001-gray.tiff
new file mode 100644
index 000000000..38fc9d2d1
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001-gray.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001-paletted.tiff b/vendor/golang.org/x/image/testdata/video-001-paletted.tiff
new file mode 100644
index 000000000..5db84bc93
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001-paletted.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001-strip-64.tiff b/vendor/golang.org/x/image/testdata/video-001-strip-64.tiff
new file mode 100644
index 000000000..9cf6c3266
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001-strip-64.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001-tile-64x64.tiff b/vendor/golang.org/x/image/testdata/video-001-tile-64x64.tiff
new file mode 100644
index 000000000..fa5671306
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001-tile-64x64.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001-uncompressed.tiff b/vendor/golang.org/x/image/testdata/video-001-uncompressed.tiff
new file mode 100644
index 000000000..fad147107
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001-uncompressed.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001.bmp b/vendor/golang.org/x/image/testdata/video-001.bmp
new file mode 100644
index 000000000..ca3dd42a7
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001.bmp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001.lossy.webp b/vendor/golang.org/x/image/testdata/video-001.lossy.webp
new file mode 100644
index 000000000..302198eca
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001.lossy.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001.lossy.webp.ycbcr.png b/vendor/golang.org/x/image/testdata/video-001.lossy.webp.ycbcr.png
new file mode 100644
index 000000000..dc5f8cfc3
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001.lossy.webp.ycbcr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001.png b/vendor/golang.org/x/image/testdata/video-001.png
new file mode 100644
index 000000000..d3468bbe8
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/video-001.tiff b/vendor/golang.org/x/image/testdata/video-001.tiff
new file mode 100644
index 000000000..0dd6cd931
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/video-001.tiff
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose-small.bmp b/vendor/golang.org/x/image/testdata/yellow_rose-small.bmp
new file mode 100644
index 000000000..866fc7a86
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose-small.bmp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose-small.png b/vendor/golang.org/x/image/testdata/yellow_rose-small.png
new file mode 100644
index 000000000..772c239fe
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose-small.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose.lossless.webp b/vendor/golang.org/x/image/testdata/yellow_rose.lossless.webp
new file mode 100644
index 000000000..0c028f45f
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose.lossless.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webp b/vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webp
new file mode 100644
index 000000000..64d3b5d30
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webp.nycbcra.png b/vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webp.nycbcra.png
new file mode 100644
index 000000000..44453158c
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose.lossy-with-alpha.webp.nycbcra.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose.lossy.webp b/vendor/golang.org/x/image/testdata/yellow_rose.lossy.webp
new file mode 100644
index 000000000..57a845e2b
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose.lossy.webp
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose.lossy.webp.ycbcr.png b/vendor/golang.org/x/image/testdata/yellow_rose.lossy.webp.ycbcr.png
new file mode 100644
index 000000000..5e3bcd897
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose.lossy.webp.ycbcr.png
Binary files differ
diff --git a/vendor/golang.org/x/image/testdata/yellow_rose.png b/vendor/golang.org/x/image/testdata/yellow_rose.png
new file mode 100644
index 000000000..bbaefa88b
--- /dev/null
+++ b/vendor/golang.org/x/image/testdata/yellow_rose.png
Binary files differ
diff --git a/vendor/golang.org/x/image/tiff/buffer_test.go b/vendor/golang.org/x/image/tiff/buffer_test.go
new file mode 100644
index 000000000..e13afb361
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/buffer_test.go
@@ -0,0 +1,36 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "io"
+ "strings"
+ "testing"
+)
+
+var readAtTests = []struct {
+ n int
+ off int64
+ s string
+ err error
+}{
+ {2, 0, "ab", nil},
+ {6, 0, "abcdef", nil},
+ {3, 3, "def", nil},
+ {3, 5, "f", io.EOF},
+ {3, 6, "", io.EOF},
+}
+
+func TestReadAt(t *testing.T) {
+ r := newReaderAt(strings.NewReader("abcdef"))
+ b := make([]byte, 10)
+ for _, test := range readAtTests {
+ n, err := r.ReadAt(b[:test.n], test.off)
+ s := string(b[:n])
+ if s != test.s || err != test.err {
+ t.Errorf("buffer.ReadAt(<%v bytes>, %v): got %v, %q; want %v, %q", test.n, test.off, err, s, test.err, test.s)
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/tiff/lzw/reader.go b/vendor/golang.org/x/image/tiff/lzw/reader.go
index dc9f7dd1d..ad35819f5 100644
--- a/vendor/golang.org/x/image/tiff/lzw/reader.go
+++ b/vendor/golang.org/x/image/tiff/lzw/reader.go
@@ -8,7 +8,7 @@
//
// In particular, it implements LZW as used by the TIFF file format, including
// an "off by one" algorithmic difference when compared to standard LZW.
-package lzw
+package lzw // import "golang.org/x/image/tiff/lzw"
/*
This file was branched from src/pkg/compress/lzw/reader.go in the
diff --git a/vendor/golang.org/x/image/tiff/reader.go b/vendor/golang.org/x/image/tiff/reader.go
index 714e3dda7..df39e8284 100644
--- a/vendor/golang.org/x/image/tiff/reader.go
+++ b/vendor/golang.org/x/image/tiff/reader.go
@@ -5,7 +5,7 @@
// Package tiff implements a TIFF image decoder and encoder.
//
// The TIFF specification is at http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
-package tiff
+package tiff // import "golang.org/x/image/tiff"
import (
"compress/zlib"
diff --git a/vendor/golang.org/x/image/tiff/reader_test.go b/vendor/golang.org/x/image/tiff/reader_test.go
new file mode 100644
index 000000000..f5c02e697
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/reader_test.go
@@ -0,0 +1,377 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "errors"
+ "image"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+
+ _ "image/png"
+)
+
+const testdataDir = "../testdata/"
+
+// Read makes *buffer implements io.Reader, so that we can pass one to Decode.
+func (*buffer) Read([]byte) (int, error) {
+ panic("unimplemented")
+}
+
+func load(name string) (image.Image, error) {
+ f, err := os.Open(testdataDir + name)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ img, _, err := image.Decode(f)
+ if err != nil {
+ return nil, err
+ }
+ return img, nil
+}
+
+// TestNoRPS tests decoding an image that has no RowsPerStrip tag. The tag is
+// mandatory according to the spec but some software omits it in the case of a
+// single strip.
+func TestNoRPS(t *testing.T) {
+ _, err := load("no_rps.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// TestNoCompression tests decoding an image that has no Compression tag. This
+// tag is mandatory, but most tools interpret a missing value as no
+// compression.
+func TestNoCompression(t *testing.T) {
+ _, err := load("no_compress.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+// TestUnpackBits tests the decoding of PackBits-encoded data.
+func TestUnpackBits(t *testing.T) {
+ var unpackBitsTests = []struct {
+ compressed string
+ uncompressed string
+ }{{
+ // Example data from Wikipedia.
+ "\xfe\xaa\x02\x80\x00\x2a\xfd\xaa\x03\x80\x00\x2a\x22\xf7\xaa",
+ "\xaa\xaa\xaa\x80\x00\x2a\xaa\xaa\xaa\xaa\x80\x00\x2a\x22\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+ }}
+ for _, u := range unpackBitsTests {
+ buf, err := unpackBits(strings.NewReader(u.compressed))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if string(buf) != u.uncompressed {
+ t.Fatalf("unpackBits: want %x, got %x", u.uncompressed, buf)
+ }
+ }
+}
+
+func TestShortBlockData(t *testing.T) {
+ b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+ // The bw-uncompressed.tiff image is a 153x55 bi-level image. This is 1 bit
+ // per pixel, or 20 bytes per row, times 55 rows, or 1100 bytes of pixel
+ // data. 1100 in hex is 0x44c, or "\x4c\x04" in little-endian. We replace
+ // that byte count (StripByteCounts-tagged data) by something less than
+ // that, so that there is not enough pixel data.
+ old := []byte{0x4c, 0x04}
+ new := []byte{0x01, 0x01}
+ i := bytes.Index(b, old)
+ if i < 0 {
+ t.Fatal(`could not find "\x4c\x04" byte count`)
+ }
+ if bytes.Contains(b[i+len(old):], old) {
+ t.Fatal(`too many occurrences of "\x4c\x04"`)
+ }
+ b[i+0] = new[0]
+ b[i+1] = new[1]
+ if _, err = Decode(bytes.NewReader(b)); err == nil {
+ t.Fatal("got nil error, want non-nil")
+ }
+}
+
+func TestDecodeInvalidDataType(t *testing.T) {
+ b, err := ioutil.ReadFile("../testdata/bw-uncompressed.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // off is the offset of the ImageWidth tag. It is the offset of the overall
+ // IFD block (0x00000454), plus 2 for the uint16 number of IFD entries, plus 12
+ // to skip the first entry.
+ const off = 0x00000454 + 2 + 12*1
+
+ if v := binary.LittleEndian.Uint16(b[off : off+2]); v != tImageWidth {
+ t.Fatal(`could not find ImageWidth tag`)
+ }
+ binary.LittleEndian.PutUint16(b[off+2:], uint16(len(lengths))) // invalid datatype
+
+ if _, err = Decode(bytes.NewReader(b)); err == nil {
+ t.Fatal("got nil error, want non-nil")
+ }
+}
+
+func compare(t *testing.T, img0, img1 image.Image) {
+ b0 := img0.Bounds()
+ b1 := img1.Bounds()
+ if b0.Dx() != b1.Dx() || b0.Dy() != b1.Dy() {
+ t.Fatalf("wrong image size: want %s, got %s", b0, b1)
+ }
+ x1 := b1.Min.X - b0.Min.X
+ y1 := b1.Min.Y - b0.Min.Y
+ for y := b0.Min.Y; y < b0.Max.Y; y++ {
+ for x := b0.Min.X; x < b0.Max.X; x++ {
+ c0 := img0.At(x, y)
+ c1 := img1.At(x+x1, y+y1)
+ r0, g0, b0, a0 := c0.RGBA()
+ r1, g1, b1, a1 := c1.RGBA()
+ if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
+ t.Fatalf("pixel at (%d, %d) has wrong color: want %v, got %v", x, y, c0, c1)
+ }
+ }
+ }
+}
+
+// TestDecode tests that decoding a PNG image and a TIFF image result in the
+// same pixel data.
+func TestDecode(t *testing.T) {
+ img0, err := load("video-001.png")
+ if err != nil {
+ t.Fatal(err)
+ }
+ img1, err := load("video-001.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+ img2, err := load("video-001-strip-64.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+ img3, err := load("video-001-tile-64x64.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+ img4, err := load("video-001-16bit.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ compare(t, img0, img1)
+ compare(t, img0, img2)
+ compare(t, img0, img3)
+ compare(t, img0, img4)
+}
+
+// TestDecodeLZW tests that decoding a PNG image and a LZW-compressed TIFF
+// image result in the same pixel data.
+func TestDecodeLZW(t *testing.T) {
+ img0, err := load("blue-purple-pink.png")
+ if err != nil {
+ t.Fatal(err)
+ }
+ img1, err := load("blue-purple-pink.lzwcompressed.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ compare(t, img0, img1)
+}
+
+// TestDecompress tests that decoding some TIFF images that use different
+// compression formats result in the same pixel data.
+func TestDecompress(t *testing.T) {
+ var decompressTests = []string{
+ "bw-uncompressed.tiff",
+ "bw-deflate.tiff",
+ "bw-packbits.tiff",
+ }
+ var img0 image.Image
+ for _, name := range decompressTests {
+ img1, err := load(name)
+ if err != nil {
+ t.Fatalf("decoding %s: %v", name, err)
+ }
+ if img0 == nil {
+ img0 = img1
+ continue
+ }
+ compare(t, img0, img1)
+ }
+}
+
+func replace(src []byte, find, repl string) ([]byte, error) {
+ removeSpaces := func(r rune) rune {
+ if r != ' ' {
+ return r
+ }
+ return -1
+ }
+
+ f, err := hex.DecodeString(strings.Map(removeSpaces, find))
+ if err != nil {
+ return nil, err
+ }
+ r, err := hex.DecodeString(strings.Map(removeSpaces, repl))
+ if err != nil {
+ return nil, err
+ }
+ dst := bytes.Replace(src, f, r, 1)
+ if bytes.Equal(dst, src) {
+ return nil, errors.New("replacement failed")
+ }
+ return dst, nil
+}
+
+// TestZeroBitsPerSample tests that an IFD with a bitsPerSample of 0 does not
+// cause a crash.
+// Issue 10711.
+func TestZeroBitsPerSample(t *testing.T) {
+ b0, err := ioutil.ReadFile(testdataDir + "bw-deflate.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Mutate the loaded image to have the problem.
+ // 02 01: tag number (tBitsPerSample)
+ // 03 00: data type (short, or uint16)
+ // 01 00 00 00: count
+ // ?? 00 00 00: value (1 -> 0)
+ b1, err := replace(b0,
+ "02 01 03 00 01 00 00 00 01 00 00 00",
+ "02 01 03 00 01 00 00 00 00 00 00 00",
+ )
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = Decode(bytes.NewReader(b1))
+ if err == nil {
+ t.Fatal("Decode with 0 bits per sample: got nil error, want non-nil")
+ }
+}
+
+// TestTileTooBig tests that we do not panic when a tile is too big compared to
+// the data available.
+// Issue 10712
+func TestTileTooBig(t *testing.T) {
+ b0, err := ioutil.ReadFile(testdataDir + "video-001-tile-64x64.tiff")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Mutate the loaded image to have the problem.
+ //
+ // 42 01: tag number (tTileWidth)
+ // 03 00: data type (short, or uint16)
+ // 01 00 00 00: count
+ // xx 00 00 00: value (0x40 -> 0x44: a wider tile consumes more data
+ // than is available)
+ b1, err := replace(b0,
+ "42 01 03 00 01 00 00 00 40 00 00 00",
+ "42 01 03 00 01 00 00 00 44 00 00 00",
+ )
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Turn off the predictor, which makes it possible to hit the
+ // place with the defect. Without this patch to the image, we run
+ // out of data too early, and do not hit the part of the code where
+ // the original panic was.
+ //
+ // 3d 01: tag number (tPredictor)
+ // 03 00: data type (short, or uint16)
+ // 01 00 00 00: count
+ // xx 00 00 00: value (2 -> 1: 2 = horizontal, 1 = none)
+ b2, err := replace(b1,
+ "3d 01 03 00 01 00 00 00 02 00 00 00",
+ "3d 01 03 00 01 00 00 00 01 00 00 00",
+ )
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ _, err = Decode(bytes.NewReader(b2))
+ if err == nil {
+ t.Fatal("did not expect nil error")
+ }
+}
+
+// TestZeroSizedImages tests that decoding does not panic when image dimensions
+// are zero, and returns a zero-sized image instead.
+// Issue 10393.
+func TestZeroSizedImages(t *testing.T) {
+ testsizes := []struct {
+ w, h int
+ }{
+ {0, 0},
+ {1, 0},
+ {0, 1},
+ {1, 1},
+ }
+ for _, r := range testsizes {
+ img := image.NewRGBA(image.Rect(0, 0, r.w, r.h))
+ var buf bytes.Buffer
+ if err := Encode(&buf, img, nil); err != nil {
+ t.Errorf("encode w=%d h=%d: %v", r.w, r.h, err)
+ continue
+ }
+ if _, err := Decode(&buf); err != nil {
+ t.Errorf("decode w=%d h=%d: %v", r.w, r.h, err)
+ }
+ }
+}
+
+// TestLargeIFDEntry tests that a large IFD entry does not cause Decode to
+// panic.
+// Issue 10596.
+func TestLargeIFDEntry(t *testing.T) {
+ testdata := "II*\x00\x08\x00\x00\x00\f\x000000000000" +
+ "00000000000000000000" +
+ "00000000000000000000" +
+ "00000000000000000000" +
+ "00000000000000\x17\x01\x04\x00\x01\x00" +
+ "\x00\xc0000000000000000000" +
+ "00000000000000000000" +
+ "00000000000000000000" +
+ "000000"
+ _, err := Decode(strings.NewReader(testdata))
+ if err == nil {
+ t.Fatal("Decode with large IFD entry: got nil error, want non-nil")
+ }
+}
+
+// benchmarkDecode benchmarks the decoding of an image.
+func benchmarkDecode(b *testing.B, filename string) {
+ b.StopTimer()
+ contents, err := ioutil.ReadFile(testdataDir + filename)
+ if err != nil {
+ b.Fatal(err)
+ }
+ r := &buffer{buf: contents}
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := Decode(r)
+ if err != nil {
+ b.Fatal("Decode:", err)
+ }
+ }
+}
+
+func BenchmarkDecodeCompressed(b *testing.B) { benchmarkDecode(b, "video-001.tiff") }
+func BenchmarkDecodeUncompressed(b *testing.B) { benchmarkDecode(b, "video-001-uncompressed.tiff") }
diff --git a/vendor/golang.org/x/image/tiff/writer_test.go b/vendor/golang.org/x/image/tiff/writer_test.go
new file mode 100644
index 000000000..c8fb7bf37
--- /dev/null
+++ b/vendor/golang.org/x/image/tiff/writer_test.go
@@ -0,0 +1,95 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tiff
+
+import (
+ "bytes"
+ "image"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+var roundtripTests = []struct {
+ filename string
+ opts *Options
+}{
+ {"video-001.tiff", nil},
+ {"video-001-16bit.tiff", nil},
+ {"video-001-gray.tiff", nil},
+ {"video-001-gray-16bit.tiff", nil},
+ {"video-001-paletted.tiff", nil},
+ {"bw-packbits.tiff", nil},
+ {"video-001.tiff", &Options{Predictor: true}},
+ {"video-001.tiff", &Options{Compression: Deflate}},
+ {"video-001.tiff", &Options{Predictor: true, Compression: Deflate}},
+}
+
+func openImage(filename string) (image.Image, error) {
+ f, err := os.Open(testdataDir + filename)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return Decode(f)
+}
+
+func TestRoundtrip(t *testing.T) {
+ for _, rt := range roundtripTests {
+ img, err := openImage(rt.filename)
+ if err != nil {
+ t.Fatal(err)
+ }
+ out := new(bytes.Buffer)
+ err = Encode(out, img, rt.opts)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ img2, err := Decode(&buffer{buf: out.Bytes()})
+ if err != nil {
+ t.Fatal(err)
+ }
+ compare(t, img, img2)
+ }
+}
+
+// TestRoundtrip2 tests that encoding and decoding an image whose
+// origin is not (0, 0) gives the same thing.
+func TestRoundtrip2(t *testing.T) {
+ m0 := image.NewRGBA(image.Rect(3, 4, 9, 8))
+ for i := range m0.Pix {
+ m0.Pix[i] = byte(i)
+ }
+ out := new(bytes.Buffer)
+ if err := Encode(out, m0, nil); err != nil {
+ t.Fatal(err)
+ }
+ m1, err := Decode(&buffer{buf: out.Bytes()})
+ if err != nil {
+ t.Fatal(err)
+ }
+ compare(t, m0, m1)
+}
+
+func benchmarkEncode(b *testing.B, name string, pixelSize int) {
+ img, err := openImage(name)
+ if err != nil {
+ b.Fatal(err)
+ }
+ s := img.Bounds().Size()
+ b.SetBytes(int64(s.X * s.Y * pixelSize))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Encode(ioutil.Discard, img, nil)
+ }
+}
+
+func BenchmarkEncode(b *testing.B) { benchmarkEncode(b, "video-001.tiff", 4) }
+func BenchmarkEncodePaletted(b *testing.B) { benchmarkEncode(b, "video-001-paletted.tiff", 1) }
+func BenchmarkEncodeGray(b *testing.B) { benchmarkEncode(b, "video-001-gray.tiff", 1) }
+func BenchmarkEncodeGray16(b *testing.B) { benchmarkEncode(b, "video-001-gray-16bit.tiff", 2) }
+func BenchmarkEncodeRGBA(b *testing.B) { benchmarkEncode(b, "video-001.tiff", 4) }
+func BenchmarkEncodeRGBA64(b *testing.B) { benchmarkEncode(b, "video-001-16bit.tiff", 8) }
diff --git a/vendor/golang.org/x/image/vp8/decode.go b/vendor/golang.org/x/image/vp8/decode.go
new file mode 100644
index 000000000..1bb50284b
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/decode.go
@@ -0,0 +1,403 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package vp8 implements a decoder for the VP8 lossy image format.
+//
+// The VP8 specification is RFC 6386.
+package vp8 // import "golang.org/x/image/vp8"
+
+// This file implements the top-level decoding algorithm.
+
+import (
+ "errors"
+ "image"
+ "io"
+)
+
+// limitReader wraps an io.Reader to read at most n bytes from it.
+type limitReader struct {
+ r io.Reader
+ n int
+}
+
+// ReadFull reads exactly len(p) bytes into p.
+func (r *limitReader) ReadFull(p []byte) error {
+ if len(p) > r.n {
+ return io.ErrUnexpectedEOF
+ }
+ n, err := io.ReadFull(r.r, p)
+ r.n -= n
+ return err
+}
+
+// FrameHeader is a frame header, as specified in section 9.1.
+type FrameHeader struct {
+ KeyFrame bool
+ VersionNumber uint8
+ ShowFrame bool
+ FirstPartitionLen uint32
+ Width int
+ Height int
+ XScale uint8
+ YScale uint8
+}
+
+const (
+ nSegment = 4
+ nSegmentProb = 3
+)
+
+// segmentHeader holds segment-related header information.
+type segmentHeader struct {
+ useSegment bool
+ updateMap bool
+ relativeDelta bool
+ quantizer [nSegment]int8
+ filterStrength [nSegment]int8
+ prob [nSegmentProb]uint8
+}
+
+const (
+ nRefLFDelta = 4
+ nModeLFDelta = 4
+)
+
+// filterHeader holds filter-related header information.
+type filterHeader struct {
+ simple bool
+ level int8
+ sharpness uint8
+ useLFDelta bool
+ refLFDelta [nRefLFDelta]int8
+ modeLFDelta [nModeLFDelta]int8
+ perSegmentLevel [nSegment]int8
+}
+
+// mb is the per-macroblock decode state. A decoder maintains mbw+1 of these
+// as it is decoding macroblocks left-to-right and top-to-bottom: mbw for the
+// macroblocks in the row above, and one for the macroblock to the left.
+type mb struct {
+ // pred is the predictor mode for the 4 bottom or right 4x4 luma regions.
+ pred [4]uint8
+ // nzMask is a mask of 8 bits: 4 for the bottom or right 4x4 luma regions,
+ // and 2 + 2 for the bottom or right 4x4 chroma regions. A 1 bit indicates
+ // that that region has non-zero coefficients.
+ nzMask uint8
+ // nzY16 is a 0/1 value that is 1 if the macroblock used Y16 prediction and
+ // had non-zero coefficients.
+ nzY16 uint8
+}
+
+// Decoder decodes VP8 bitstreams into frames. Decoding one frame consists of
+// calling Init, DecodeFrameHeader and then DecodeFrame in that order.
+// A Decoder can be re-used to decode multiple frames.
+type Decoder struct {
+ // r is the input bitsream.
+ r limitReader
+ // scratch is a scratch buffer.
+ scratch [8]byte
+ // img is the YCbCr image to decode into.
+ img *image.YCbCr
+ // mbw and mbh are the number of 16x16 macroblocks wide and high the image is.
+ mbw, mbh int
+ // frameHeader is the frame header. When decoding multiple frames,
+ // frames that aren't key frames will inherit the Width, Height,
+ // XScale and YScale of the most recent key frame.
+ frameHeader FrameHeader
+ // Other headers.
+ segmentHeader segmentHeader
+ filterHeader filterHeader
+ // The image data is divided into a number of independent partitions.
+ // There is 1 "first partition" and between 1 and 8 "other partitions"
+ // for coefficient data.
+ fp partition
+ op [8]partition
+ nOP int
+ // Quantization factors.
+ quant [nSegment]quant
+ // DCT/WHT coefficient decoding probabilities.
+ tokenProb [nPlane][nBand][nContext][nProb]uint8
+ useSkipProb bool
+ skipProb uint8
+ // Loop filter parameters.
+ filterParams [nSegment][2]filterParam
+ perMBFilterParams []filterParam
+
+ // The eight fields below relate to the current macroblock being decoded.
+ //
+ // Segment-based adjustments.
+ segment int
+ // Per-macroblock state for the macroblock immediately left of and those
+ // macroblocks immediately above the current macroblock.
+ leftMB mb
+ upMB []mb
+ // Bitmasks for which 4x4 regions of coeff contain non-zero coefficients.
+ nzDCMask, nzACMask uint32
+ // Predictor modes.
+ usePredY16 bool // The libwebp C code calls this !is_i4x4_.
+ predY16 uint8
+ predC8 uint8
+ predY4 [4][4]uint8
+
+ // The two fields below form a workspace for reconstructing a macroblock.
+ // Their specific sizes are documented in reconstruct.go.
+ coeff [1*16*16 + 2*8*8 + 1*4*4]int16
+ ybr [1 + 16 + 1 + 8][32]uint8
+}
+
+// NewDecoder returns a new Decoder.
+func NewDecoder() *Decoder {
+ return &Decoder{}
+}
+
+// Init initializes the decoder to read at most n bytes from r.
+func (d *Decoder) Init(r io.Reader, n int) {
+ d.r = limitReader{r, n}
+}
+
+// DecodeFrameHeader decodes the frame header.
+func (d *Decoder) DecodeFrameHeader() (fh FrameHeader, err error) {
+ // All frame headers are at least 3 bytes long.
+ b := d.scratch[:3]
+ if err = d.r.ReadFull(b); err != nil {
+ return
+ }
+ d.frameHeader.KeyFrame = (b[0] & 1) == 0
+ d.frameHeader.VersionNumber = (b[0] >> 1) & 7
+ d.frameHeader.ShowFrame = (b[0]>>4)&1 == 1
+ d.frameHeader.FirstPartitionLen = uint32(b[0])>>5 | uint32(b[1])<<3 | uint32(b[2])<<11
+ if !d.frameHeader.KeyFrame {
+ return d.frameHeader, nil
+ }
+ // Frame headers for key frames are an additional 7 bytes long.
+ b = d.scratch[:7]
+ if err = d.r.ReadFull(b); err != nil {
+ return
+ }
+ // Check the magic sync code.
+ if b[0] != 0x9d || b[1] != 0x01 || b[2] != 0x2a {
+ err = errors.New("vp8: invalid format")
+ return
+ }
+ d.frameHeader.Width = int(b[4]&0x3f)<<8 | int(b[3])
+ d.frameHeader.Height = int(b[6]&0x3f)<<8 | int(b[5])
+ d.frameHeader.XScale = b[4] >> 6
+ d.frameHeader.YScale = b[6] >> 6
+ d.mbw = (d.frameHeader.Width + 0x0f) >> 4
+ d.mbh = (d.frameHeader.Height + 0x0f) >> 4
+ d.segmentHeader = segmentHeader{
+ prob: [3]uint8{0xff, 0xff, 0xff},
+ }
+ d.tokenProb = defaultTokenProb
+ d.segment = 0
+ return d.frameHeader, nil
+}
+
+// ensureImg ensures that d.img is large enough to hold the decoded frame.
+func (d *Decoder) ensureImg() {
+ if d.img != nil {
+ p0, p1 := d.img.Rect.Min, d.img.Rect.Max
+ if p0.X == 0 && p0.Y == 0 && p1.X >= 16*d.mbw && p1.Y >= 16*d.mbh {
+ return
+ }
+ }
+ m := image.NewYCbCr(image.Rect(0, 0, 16*d.mbw, 16*d.mbh), image.YCbCrSubsampleRatio420)
+ d.img = m.SubImage(image.Rect(0, 0, d.frameHeader.Width, d.frameHeader.Height)).(*image.YCbCr)
+ d.perMBFilterParams = make([]filterParam, d.mbw*d.mbh)
+ d.upMB = make([]mb, d.mbw)
+}
+
+// parseSegmentHeader parses the segment header, as specified in section 9.3.
+func (d *Decoder) parseSegmentHeader() {
+ d.segmentHeader.useSegment = d.fp.readBit(uniformProb)
+ if !d.segmentHeader.useSegment {
+ d.segmentHeader.updateMap = false
+ return
+ }
+ d.segmentHeader.updateMap = d.fp.readBit(uniformProb)
+ if d.fp.readBit(uniformProb) {
+ d.segmentHeader.relativeDelta = !d.fp.readBit(uniformProb)
+ for i := range d.segmentHeader.quantizer {
+ d.segmentHeader.quantizer[i] = int8(d.fp.readOptionalInt(uniformProb, 7))
+ }
+ for i := range d.segmentHeader.filterStrength {
+ d.segmentHeader.filterStrength[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
+ }
+ }
+ if !d.segmentHeader.updateMap {
+ return
+ }
+ for i := range d.segmentHeader.prob {
+ if d.fp.readBit(uniformProb) {
+ d.segmentHeader.prob[i] = uint8(d.fp.readUint(uniformProb, 8))
+ } else {
+ d.segmentHeader.prob[i] = 0xff
+ }
+ }
+}
+
+// parseFilterHeader parses the filter header, as specified in section 9.4.
+func (d *Decoder) parseFilterHeader() {
+ d.filterHeader.simple = d.fp.readBit(uniformProb)
+ d.filterHeader.level = int8(d.fp.readUint(uniformProb, 6))
+ d.filterHeader.sharpness = uint8(d.fp.readUint(uniformProb, 3))
+ d.filterHeader.useLFDelta = d.fp.readBit(uniformProb)
+ if d.filterHeader.useLFDelta && d.fp.readBit(uniformProb) {
+ for i := range d.filterHeader.refLFDelta {
+ d.filterHeader.refLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
+ }
+ for i := range d.filterHeader.modeLFDelta {
+ d.filterHeader.modeLFDelta[i] = int8(d.fp.readOptionalInt(uniformProb, 6))
+ }
+ }
+ if d.filterHeader.level == 0 {
+ return
+ }
+ if d.segmentHeader.useSegment {
+ for i := range d.filterHeader.perSegmentLevel {
+ strength := d.segmentHeader.filterStrength[i]
+ if d.segmentHeader.relativeDelta {
+ strength += d.filterHeader.level
+ }
+ d.filterHeader.perSegmentLevel[i] = strength
+ }
+ } else {
+ d.filterHeader.perSegmentLevel[0] = d.filterHeader.level
+ }
+ d.computeFilterParams()
+}
+
+// parseOtherPartitions parses the other partitions, as specified in section 9.5.
+func (d *Decoder) parseOtherPartitions() error {
+ const maxNOP = 1 << 3
+ var partLens [maxNOP]int
+ d.nOP = 1 << d.fp.readUint(uniformProb, 2)
+
+ // The final partition length is implied by the the remaining chunk data
+ // (d.r.n) and the other d.nOP-1 partition lengths. Those d.nOP-1 partition
+ // lengths are stored as 24-bit uints, i.e. up to 16 MiB per partition.
+ n := 3 * (d.nOP - 1)
+ partLens[d.nOP-1] = d.r.n - n
+ if partLens[d.nOP-1] < 0 {
+ return io.ErrUnexpectedEOF
+ }
+ if n > 0 {
+ buf := make([]byte, n)
+ if err := d.r.ReadFull(buf); err != nil {
+ return err
+ }
+ for i := 0; i < d.nOP-1; i++ {
+ pl := int(buf[3*i+0]) | int(buf[3*i+1])<<8 | int(buf[3*i+2])<<16
+ if pl > partLens[d.nOP-1] {
+ return io.ErrUnexpectedEOF
+ }
+ partLens[i] = pl
+ partLens[d.nOP-1] -= pl
+ }
+ }
+
+ // We check if the final partition length can also fit into a 24-bit uint.
+ // Strictly speaking, this isn't part of the spec, but it guards against a
+ // malicious WEBP image that is too large to ReadFull the encoded DCT
+ // coefficients into memory, whether that's because the actual WEBP file is
+ // too large, or whether its RIFF metadata lists too large a chunk.
+ if 1<<24 <= partLens[d.nOP-1] {
+ return errors.New("vp8: too much data to decode")
+ }
+
+ buf := make([]byte, d.r.n)
+ if err := d.r.ReadFull(buf); err != nil {
+ return err
+ }
+ for i, pl := range partLens {
+ if i == d.nOP {
+ break
+ }
+ d.op[i].init(buf[:pl])
+ buf = buf[pl:]
+ }
+ return nil
+}
+
+// parseOtherHeaders parses header information other than the frame header.
+func (d *Decoder) parseOtherHeaders() error {
+ // Initialize and parse the first partition.
+ firstPartition := make([]byte, d.frameHeader.FirstPartitionLen)
+ if err := d.r.ReadFull(firstPartition); err != nil {
+ return err
+ }
+ d.fp.init(firstPartition)
+ if d.frameHeader.KeyFrame {
+ // Read and ignore the color space and pixel clamp values. They are
+ // specified in section 9.2, but are unimplemented.
+ d.fp.readBit(uniformProb)
+ d.fp.readBit(uniformProb)
+ }
+ d.parseSegmentHeader()
+ d.parseFilterHeader()
+ if err := d.parseOtherPartitions(); err != nil {
+ return err
+ }
+ d.parseQuant()
+ if !d.frameHeader.KeyFrame {
+ // Golden and AltRef frames are specified in section 9.7.
+ // TODO(nigeltao): implement. Note that they are only used for video, not still images.
+ return errors.New("vp8: Golden / AltRef frames are not implemented")
+ }
+ // Read and ignore the refreshLastFrameBuffer bit, specified in section 9.8.
+ // It applies only to video, and not still images.
+ d.fp.readBit(uniformProb)
+ d.parseTokenProb()
+ d.useSkipProb = d.fp.readBit(uniformProb)
+ if d.useSkipProb {
+ d.skipProb = uint8(d.fp.readUint(uniformProb, 8))
+ }
+ if d.fp.unexpectedEOF {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
+}
+
+// DecodeFrame decodes the frame and returns it as an YCbCr image.
+// The image's contents are valid up until the next call to Decoder.Init.
+func (d *Decoder) DecodeFrame() (*image.YCbCr, error) {
+ d.ensureImg()
+ if err := d.parseOtherHeaders(); err != nil {
+ return nil, err
+ }
+ // Reconstruct the rows.
+ for mbx := 0; mbx < d.mbw; mbx++ {
+ d.upMB[mbx] = mb{}
+ }
+ for mby := 0; mby < d.mbh; mby++ {
+ d.leftMB = mb{}
+ for mbx := 0; mbx < d.mbw; mbx++ {
+ skip := d.reconstruct(mbx, mby)
+ fs := d.filterParams[d.segment][btou(!d.usePredY16)]
+ fs.inner = fs.inner || !skip
+ d.perMBFilterParams[d.mbw*mby+mbx] = fs
+ }
+ }
+ if d.fp.unexpectedEOF {
+ return nil, io.ErrUnexpectedEOF
+ }
+ for i := 0; i < d.nOP; i++ {
+ if d.op[i].unexpectedEOF {
+ return nil, io.ErrUnexpectedEOF
+ }
+ }
+ // Apply the loop filter.
+ //
+ // Even if we are using per-segment levels, section 15 says that "loop
+ // filtering must be skipped entirely if loop_filter_level at either the
+ // frame header level or macroblock override level is 0".
+ if d.filterHeader.level != 0 {
+ if d.filterHeader.simple {
+ d.simpleFilter()
+ } else {
+ d.normalFilter()
+ }
+ }
+ return d.img, nil
+}
diff --git a/vendor/golang.org/x/image/vp8/filter.go b/vendor/golang.org/x/image/vp8/filter.go
new file mode 100644
index 000000000..e34a811b1
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/filter.go
@@ -0,0 +1,273 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// filter2 modifies a 2-pixel wide or 2-pixel high band along an edge.
+func filter2(pix []byte, level, index, iStep, jStep int) {
+ for n := 16; n > 0; n, index = n-1, index+iStep {
+ p1 := int(pix[index-2*jStep])
+ p0 := int(pix[index-1*jStep])
+ q0 := int(pix[index+0*jStep])
+ q1 := int(pix[index+1*jStep])
+ if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
+ continue
+ }
+ a := 3*(q0-p0) + clamp127(p1-q1)
+ a1 := clamp15((a + 4) >> 3)
+ a2 := clamp15((a + 3) >> 3)
+ pix[index-1*jStep] = clamp255(p0 + a2)
+ pix[index+0*jStep] = clamp255(q0 - a1)
+ }
+}
+
+// filter246 modifies a 2-, 4- or 6-pixel wide or high band along an edge.
+func filter246(pix []byte, n, level, ilevel, hlevel, index, iStep, jStep int, fourNotSix bool) {
+ for ; n > 0; n, index = n-1, index+iStep {
+ p3 := int(pix[index-4*jStep])
+ p2 := int(pix[index-3*jStep])
+ p1 := int(pix[index-2*jStep])
+ p0 := int(pix[index-1*jStep])
+ q0 := int(pix[index+0*jStep])
+ q1 := int(pix[index+1*jStep])
+ q2 := int(pix[index+2*jStep])
+ q3 := int(pix[index+3*jStep])
+ if abs(p0-q0)<<1+abs(p1-q1)>>1 > level {
+ continue
+ }
+ if abs(p3-p2) > ilevel ||
+ abs(p2-p1) > ilevel ||
+ abs(p1-p0) > ilevel ||
+ abs(q1-q0) > ilevel ||
+ abs(q2-q1) > ilevel ||
+ abs(q3-q2) > ilevel {
+ continue
+ }
+ if abs(p1-p0) > hlevel || abs(q1-q0) > hlevel {
+ // Filter 2 pixels.
+ a := 3*(q0-p0) + clamp127(p1-q1)
+ a1 := clamp15((a + 4) >> 3)
+ a2 := clamp15((a + 3) >> 3)
+ pix[index-1*jStep] = clamp255(p0 + a2)
+ pix[index+0*jStep] = clamp255(q0 - a1)
+ } else if fourNotSix {
+ // Filter 4 pixels.
+ a := 3 * (q0 - p0)
+ a1 := clamp15((a + 4) >> 3)
+ a2 := clamp15((a + 3) >> 3)
+ a3 := (a1 + 1) >> 1
+ pix[index-2*jStep] = clamp255(p1 + a3)
+ pix[index-1*jStep] = clamp255(p0 + a2)
+ pix[index+0*jStep] = clamp255(q0 - a1)
+ pix[index+1*jStep] = clamp255(q1 - a3)
+ } else {
+ // Filter 6 pixels.
+ a := clamp127(3*(q0-p0) + clamp127(p1-q1))
+ a1 := (27*a + 63) >> 7
+ a2 := (18*a + 63) >> 7
+ a3 := (9*a + 63) >> 7
+ pix[index-3*jStep] = clamp255(p2 + a3)
+ pix[index-2*jStep] = clamp255(p1 + a2)
+ pix[index-1*jStep] = clamp255(p0 + a1)
+ pix[index+0*jStep] = clamp255(q0 - a1)
+ pix[index+1*jStep] = clamp255(q1 - a2)
+ pix[index+2*jStep] = clamp255(q2 - a3)
+ }
+ }
+}
+
+// simpleFilter implements the simple filter, as specified in section 15.2.
+func (d *Decoder) simpleFilter() {
+ for mby := 0; mby < d.mbh; mby++ {
+ for mbx := 0; mbx < d.mbw; mbx++ {
+ f := d.perMBFilterParams[d.mbw*mby+mbx]
+ if f.level == 0 {
+ continue
+ }
+ l := int(f.level)
+ yIndex := (mby*d.img.YStride + mbx) * 16
+ if mbx > 0 {
+ filter2(d.img.Y, l+4, yIndex, d.img.YStride, 1)
+ }
+ if f.inner {
+ filter2(d.img.Y, l, yIndex+0x4, d.img.YStride, 1)
+ filter2(d.img.Y, l, yIndex+0x8, d.img.YStride, 1)
+ filter2(d.img.Y, l, yIndex+0xc, d.img.YStride, 1)
+ }
+ if mby > 0 {
+ filter2(d.img.Y, l+4, yIndex, 1, d.img.YStride)
+ }
+ if f.inner {
+ filter2(d.img.Y, l, yIndex+d.img.YStride*0x4, 1, d.img.YStride)
+ filter2(d.img.Y, l, yIndex+d.img.YStride*0x8, 1, d.img.YStride)
+ filter2(d.img.Y, l, yIndex+d.img.YStride*0xc, 1, d.img.YStride)
+ }
+ }
+ }
+}
+
+// normalFilter implements the normal filter, as specified in section 15.3.
+func (d *Decoder) normalFilter() {
+ for mby := 0; mby < d.mbh; mby++ {
+ for mbx := 0; mbx < d.mbw; mbx++ {
+ f := d.perMBFilterParams[d.mbw*mby+mbx]
+ if f.level == 0 {
+ continue
+ }
+ l, il, hl := int(f.level), int(f.ilevel), int(f.hlevel)
+ yIndex := (mby*d.img.YStride + mbx) * 16
+ cIndex := (mby*d.img.CStride + mbx) * 8
+ if mbx > 0 {
+ filter246(d.img.Y, 16, l+4, il, hl, yIndex, d.img.YStride, 1, false)
+ filter246(d.img.Cb, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
+ filter246(d.img.Cr, 8, l+4, il, hl, cIndex, d.img.CStride, 1, false)
+ }
+ if f.inner {
+ filter246(d.img.Y, 16, l, il, hl, yIndex+0x4, d.img.YStride, 1, true)
+ filter246(d.img.Y, 16, l, il, hl, yIndex+0x8, d.img.YStride, 1, true)
+ filter246(d.img.Y, 16, l, il, hl, yIndex+0xc, d.img.YStride, 1, true)
+ filter246(d.img.Cb, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
+ filter246(d.img.Cr, 8, l, il, hl, cIndex+0x4, d.img.CStride, 1, true)
+ }
+ if mby > 0 {
+ filter246(d.img.Y, 16, l+4, il, hl, yIndex, 1, d.img.YStride, false)
+ filter246(d.img.Cb, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
+ filter246(d.img.Cr, 8, l+4, il, hl, cIndex, 1, d.img.CStride, false)
+ }
+ if f.inner {
+ filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x4, 1, d.img.YStride, true)
+ filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0x8, 1, d.img.YStride, true)
+ filter246(d.img.Y, 16, l, il, hl, yIndex+d.img.YStride*0xc, 1, d.img.YStride, true)
+ filter246(d.img.Cb, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
+ filter246(d.img.Cr, 8, l, il, hl, cIndex+d.img.CStride*0x4, 1, d.img.CStride, true)
+ }
+ }
+ }
+}
+
+// filterParam holds the loop filter parameters for a macroblock.
+type filterParam struct {
+ // The first three fields are thresholds used by the loop filter to smooth
+ // over the edges and interior of a macroblock. level is used by both the
+ // simple and normal filters. The inner level and high edge variance level
+ // are only used by the normal filter.
+ level, ilevel, hlevel uint8
+ // inner is whether the inner loop filter cannot be optimized out as a
+ // no-op for this particular macroblock.
+ inner bool
+}
+
+// computeFilterParams computes the loop filter parameters, as specified in
+// section 15.4.
+func (d *Decoder) computeFilterParams() {
+ for i := range d.filterParams {
+ baseLevel := d.filterHeader.level
+ if d.segmentHeader.useSegment {
+ baseLevel = d.segmentHeader.filterStrength[i]
+ if d.segmentHeader.relativeDelta {
+ baseLevel += d.filterHeader.level
+ }
+ }
+
+ for j := range d.filterParams[i] {
+ p := &d.filterParams[i][j]
+ p.inner = j != 0
+ level := baseLevel
+ if d.filterHeader.useLFDelta {
+ // The libwebp C code has a "TODO: only CURRENT is handled for now."
+ level += d.filterHeader.refLFDelta[0]
+ if j != 0 {
+ level += d.filterHeader.modeLFDelta[0]
+ }
+ }
+ if level <= 0 {
+ p.level = 0
+ continue
+ }
+ if level > 63 {
+ level = 63
+ }
+ ilevel := level
+ if d.filterHeader.sharpness > 0 {
+ if d.filterHeader.sharpness > 4 {
+ ilevel >>= 2
+ } else {
+ ilevel >>= 1
+ }
+ if x := int8(9 - d.filterHeader.sharpness); ilevel > x {
+ ilevel = x
+ }
+ }
+ if ilevel < 1 {
+ ilevel = 1
+ }
+ p.ilevel = uint8(ilevel)
+ p.level = uint8(2*level + ilevel)
+ if d.frameHeader.KeyFrame {
+ if level < 15 {
+ p.hlevel = 0
+ } else if level < 40 {
+ p.hlevel = 1
+ } else {
+ p.hlevel = 2
+ }
+ } else {
+ if level < 15 {
+ p.hlevel = 0
+ } else if level < 20 {
+ p.hlevel = 1
+ } else if level < 40 {
+ p.hlevel = 2
+ } else {
+ p.hlevel = 3
+ }
+ }
+ }
+ }
+}
+
+// intSize is either 32 or 64.
+const intSize = 32 << (^uint(0) >> 63)
+
+func abs(x int) int {
+ // m := -1 if x < 0. m := 0 otherwise.
+ m := x >> (intSize - 1)
+
+ // In two's complement representation, the negative number
+ // of any number (except the smallest one) can be computed
+ // by flipping all the bits and add 1. This is faster than
+ // code with a branch.
+ // See Hacker's Delight, section 2-4.
+ return (x ^ m) - m
+}
+
+func clamp15(x int) int {
+ if x < -16 {
+ return -16
+ }
+ if x > 15 {
+ return 15
+ }
+ return x
+}
+
+func clamp127(x int) int {
+ if x < -128 {
+ return -128
+ }
+ if x > 127 {
+ return 127
+ }
+ return x
+}
+
+func clamp255(x int) uint8 {
+ if x < 0 {
+ return 0
+ }
+ if x > 255 {
+ return 255
+ }
+ return uint8(x)
+}
diff --git a/vendor/golang.org/x/image/vp8/idct.go b/vendor/golang.org/x/image/vp8/idct.go
new file mode 100644
index 000000000..929af2cc9
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/idct.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// This file implements the inverse Discrete Cosine Transform and the inverse
+// Walsh Hadamard Transform (WHT), as specified in sections 14.3 and 14.4.
+
+func clip8(i int32) uint8 {
+ if i < 0 {
+ return 0
+ }
+ if i > 255 {
+ return 255
+ }
+ return uint8(i)
+}
+
+func (z *Decoder) inverseDCT4(y, x, coeffBase int) {
+ const (
+ c1 = 85627 // 65536 * cos(pi/8) * sqrt(2).
+ c2 = 35468 // 65536 * sin(pi/8) * sqrt(2).
+ )
+ var m [4][4]int32
+ for i := 0; i < 4; i++ {
+ a := int32(z.coeff[coeffBase+0]) + int32(z.coeff[coeffBase+8])
+ b := int32(z.coeff[coeffBase+0]) - int32(z.coeff[coeffBase+8])
+ c := (int32(z.coeff[coeffBase+4])*c2)>>16 - (int32(z.coeff[coeffBase+12])*c1)>>16
+ d := (int32(z.coeff[coeffBase+4])*c1)>>16 + (int32(z.coeff[coeffBase+12])*c2)>>16
+ m[i][0] = a + d
+ m[i][1] = b + c
+ m[i][2] = b - c
+ m[i][3] = a - d
+ coeffBase++
+ }
+ for j := 0; j < 4; j++ {
+ dc := m[0][j] + 4
+ a := dc + m[2][j]
+ b := dc - m[2][j]
+ c := (m[1][j]*c2)>>16 - (m[3][j]*c1)>>16
+ d := (m[1][j]*c1)>>16 + (m[3][j]*c2)>>16
+ z.ybr[y+j][x+0] = clip8(int32(z.ybr[y+j][x+0]) + (a+d)>>3)
+ z.ybr[y+j][x+1] = clip8(int32(z.ybr[y+j][x+1]) + (b+c)>>3)
+ z.ybr[y+j][x+2] = clip8(int32(z.ybr[y+j][x+2]) + (b-c)>>3)
+ z.ybr[y+j][x+3] = clip8(int32(z.ybr[y+j][x+3]) + (a-d)>>3)
+ }
+}
+
+func (z *Decoder) inverseDCT4DCOnly(y, x, coeffBase int) {
+ dc := (int32(z.coeff[coeffBase+0]) + 4) >> 3
+ for j := 0; j < 4; j++ {
+ for i := 0; i < 4; i++ {
+ z.ybr[y+j][x+i] = clip8(int32(z.ybr[y+j][x+i]) + dc)
+ }
+ }
+}
+
+func (z *Decoder) inverseDCT8(y, x, coeffBase int) {
+ z.inverseDCT4(y+0, x+0, coeffBase+0*16)
+ z.inverseDCT4(y+0, x+4, coeffBase+1*16)
+ z.inverseDCT4(y+4, x+0, coeffBase+2*16)
+ z.inverseDCT4(y+4, x+4, coeffBase+3*16)
+}
+
+func (z *Decoder) inverseDCT8DCOnly(y, x, coeffBase int) {
+ z.inverseDCT4DCOnly(y+0, x+0, coeffBase+0*16)
+ z.inverseDCT4DCOnly(y+0, x+4, coeffBase+1*16)
+ z.inverseDCT4DCOnly(y+4, x+0, coeffBase+2*16)
+ z.inverseDCT4DCOnly(y+4, x+4, coeffBase+3*16)
+}
+
+func (d *Decoder) inverseWHT16() {
+ var m [16]int32
+ for i := 0; i < 4; i++ {
+ a0 := int32(d.coeff[384+0+i]) + int32(d.coeff[384+12+i])
+ a1 := int32(d.coeff[384+4+i]) + int32(d.coeff[384+8+i])
+ a2 := int32(d.coeff[384+4+i]) - int32(d.coeff[384+8+i])
+ a3 := int32(d.coeff[384+0+i]) - int32(d.coeff[384+12+i])
+ m[0+i] = a0 + a1
+ m[8+i] = a0 - a1
+ m[4+i] = a3 + a2
+ m[12+i] = a3 - a2
+ }
+ out := 0
+ for i := 0; i < 4; i++ {
+ dc := m[0+i*4] + 3
+ a0 := dc + m[3+i*4]
+ a1 := m[1+i*4] + m[2+i*4]
+ a2 := m[1+i*4] - m[2+i*4]
+ a3 := dc - m[3+i*4]
+ d.coeff[out+0] = int16((a0 + a1) >> 3)
+ d.coeff[out+16] = int16((a3 + a2) >> 3)
+ d.coeff[out+32] = int16((a0 - a1) >> 3)
+ d.coeff[out+48] = int16((a3 - a2) >> 3)
+ out += 64
+ }
+}
diff --git a/vendor/golang.org/x/image/vp8/partition.go b/vendor/golang.org/x/image/vp8/partition.go
new file mode 100644
index 000000000..72288bdeb
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/partition.go
@@ -0,0 +1,129 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// Each VP8 frame consists of between 2 and 9 bitstream partitions.
+// Each partition is byte-aligned and is independently arithmetic-encoded.
+//
+// This file implements decoding a partition's bitstream, as specified in
+// chapter 7. The implementation follows libwebp's approach instead of the
+// specification's reference C implementation. For example, we use a look-up
+// table instead of a for loop to recalibrate the encoded range.
+
+var (
+ lutShift = [127]uint8{
+ 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ }
+ lutRangeM1 = [127]uint8{
+ 127,
+ 127, 191,
+ 127, 159, 191, 223,
+ 127, 143, 159, 175, 191, 207, 223, 239,
+ 127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239, 247,
+ 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179, 183, 187,
+ 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251,
+ 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157,
+ 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189,
+ 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221,
+ 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253,
+ }
+)
+
+// uniformProb represents a 50% probability that the next bit is 0.
+const uniformProb = 128
+
+// partition holds arithmetic-coded bits.
+type partition struct {
+ // buf is the input bytes.
+ buf []byte
+ // r is how many of buf's bytes have been consumed.
+ r int
+ // rangeM1 is range minus 1, where range is in the arithmetic coding sense,
+ // not the Go language sense.
+ rangeM1 uint32
+ // bits and nBits hold those bits shifted out of buf but not yet consumed.
+ bits uint32
+ nBits uint8
+ // unexpectedEOF tells whether we tried to read past buf.
+ unexpectedEOF bool
+}
+
+// init initializes the partition.
+func (p *partition) init(buf []byte) {
+ p.buf = buf
+ p.r = 0
+ p.rangeM1 = 254
+ p.bits = 0
+ p.nBits = 0
+ p.unexpectedEOF = false
+}
+
+// readBit returns the next bit.
+func (p *partition) readBit(prob uint8) bool {
+ if p.nBits < 8 {
+ if p.r >= len(p.buf) {
+ p.unexpectedEOF = true
+ return false
+ }
+ // Expression split for 386 compiler.
+ x := uint32(p.buf[p.r])
+ p.bits |= x << (8 - p.nBits)
+ p.r++
+ p.nBits += 8
+ }
+ split := (p.rangeM1*uint32(prob))>>8 + 1
+ bit := p.bits >= split<<8
+ if bit {
+ p.rangeM1 -= split
+ p.bits -= split << 8
+ } else {
+ p.rangeM1 = split - 1
+ }
+ if p.rangeM1 < 127 {
+ shift := lutShift[p.rangeM1]
+ p.rangeM1 = uint32(lutRangeM1[p.rangeM1])
+ p.bits <<= shift
+ p.nBits -= shift
+ }
+ return bit
+}
+
+// readUint returns the next n-bit unsigned integer.
+func (p *partition) readUint(prob, n uint8) uint32 {
+ var u uint32
+ for n > 0 {
+ n--
+ if p.readBit(prob) {
+ u |= 1 << n
+ }
+ }
+ return u
+}
+
+// readInt returns the next n-bit signed integer.
+func (p *partition) readInt(prob, n uint8) int32 {
+ u := p.readUint(prob, n)
+ b := p.readBit(prob)
+ if b {
+ return -int32(u)
+ }
+ return int32(u)
+}
+
+// readOptionalInt returns the next n-bit signed integer in an encoding
+// where the likely result is zero.
+func (p *partition) readOptionalInt(prob, n uint8) int32 {
+ if !p.readBit(prob) {
+ return 0
+ }
+ return p.readInt(prob, n)
+}
diff --git a/vendor/golang.org/x/image/vp8/pred.go b/vendor/golang.org/x/image/vp8/pred.go
new file mode 100644
index 000000000..58c2689ea
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/pred.go
@@ -0,0 +1,201 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// This file implements parsing the predictor modes, as specified in chapter
+// 11.
+
+func (d *Decoder) parsePredModeY16(mbx int) {
+ var p uint8
+ if !d.fp.readBit(156) {
+ if !d.fp.readBit(163) {
+ p = predDC
+ } else {
+ p = predVE
+ }
+ } else if !d.fp.readBit(128) {
+ p = predHE
+ } else {
+ p = predTM
+ }
+ for i := 0; i < 4; i++ {
+ d.upMB[mbx].pred[i] = p
+ d.leftMB.pred[i] = p
+ }
+ d.predY16 = p
+}
+
+func (d *Decoder) parsePredModeC8() {
+ if !d.fp.readBit(142) {
+ d.predC8 = predDC
+ } else if !d.fp.readBit(114) {
+ d.predC8 = predVE
+ } else if !d.fp.readBit(183) {
+ d.predC8 = predHE
+ } else {
+ d.predC8 = predTM
+ }
+}
+
+func (d *Decoder) parsePredModeY4(mbx int) {
+ for j := 0; j < 4; j++ {
+ p := d.leftMB.pred[j]
+ for i := 0; i < 4; i++ {
+ prob := &predProb[d.upMB[mbx].pred[i]][p]
+ if !d.fp.readBit(prob[0]) {
+ p = predDC
+ } else if !d.fp.readBit(prob[1]) {
+ p = predTM
+ } else if !d.fp.readBit(prob[2]) {
+ p = predVE
+ } else if !d.fp.readBit(prob[3]) {
+ if !d.fp.readBit(prob[4]) {
+ p = predHE
+ } else if !d.fp.readBit(prob[5]) {
+ p = predRD
+ } else {
+ p = predVR
+ }
+ } else if !d.fp.readBit(prob[6]) {
+ p = predLD
+ } else if !d.fp.readBit(prob[7]) {
+ p = predVL
+ } else if !d.fp.readBit(prob[8]) {
+ p = predHD
+ } else {
+ p = predHU
+ }
+ d.predY4[j][i] = p
+ d.upMB[mbx].pred[i] = p
+ }
+ d.leftMB.pred[j] = p
+ }
+}
+
+// predProb are the probabilities to decode a 4x4 region's predictor mode given
+// the predictor modes of the regions above and left of it.
+// These values are specified in section 11.5.
+var predProb = [nPred][nPred][9]uint8{
+ {
+ {231, 120, 48, 89, 115, 113, 120, 152, 112},
+ {152, 179, 64, 126, 170, 118, 46, 70, 95},
+ {175, 69, 143, 80, 85, 82, 72, 155, 103},
+ {56, 58, 10, 171, 218, 189, 17, 13, 152},
+ {114, 26, 17, 163, 44, 195, 21, 10, 173},
+ {121, 24, 80, 195, 26, 62, 44, 64, 85},
+ {144, 71, 10, 38, 171, 213, 144, 34, 26},
+ {170, 46, 55, 19, 136, 160, 33, 206, 71},
+ {63, 20, 8, 114, 114, 208, 12, 9, 226},
+ {81, 40, 11, 96, 182, 84, 29, 16, 36},
+ },
+ {
+ {134, 183, 89, 137, 98, 101, 106, 165, 148},
+ {72, 187, 100, 130, 157, 111, 32, 75, 80},
+ {66, 102, 167, 99, 74, 62, 40, 234, 128},
+ {41, 53, 9, 178, 241, 141, 26, 8, 107},
+ {74, 43, 26, 146, 73, 166, 49, 23, 157},
+ {65, 38, 105, 160, 51, 52, 31, 115, 128},
+ {104, 79, 12, 27, 217, 255, 87, 17, 7},
+ {87, 68, 71, 44, 114, 51, 15, 186, 23},
+ {47, 41, 14, 110, 182, 183, 21, 17, 194},
+ {66, 45, 25, 102, 197, 189, 23, 18, 22},
+ },
+ {
+ {88, 88, 147, 150, 42, 46, 45, 196, 205},
+ {43, 97, 183, 117, 85, 38, 35, 179, 61},
+ {39, 53, 200, 87, 26, 21, 43, 232, 171},
+ {56, 34, 51, 104, 114, 102, 29, 93, 77},
+ {39, 28, 85, 171, 58, 165, 90, 98, 64},
+ {34, 22, 116, 206, 23, 34, 43, 166, 73},
+ {107, 54, 32, 26, 51, 1, 81, 43, 31},
+ {68, 25, 106, 22, 64, 171, 36, 225, 114},
+ {34, 19, 21, 102, 132, 188, 16, 76, 124},
+ {62, 18, 78, 95, 85, 57, 50, 48, 51},
+ },
+ {
+ {193, 101, 35, 159, 215, 111, 89, 46, 111},
+ {60, 148, 31, 172, 219, 228, 21, 18, 111},
+ {112, 113, 77, 85, 179, 255, 38, 120, 114},
+ {40, 42, 1, 196, 245, 209, 10, 25, 109},
+ {88, 43, 29, 140, 166, 213, 37, 43, 154},
+ {61, 63, 30, 155, 67, 45, 68, 1, 209},
+ {100, 80, 8, 43, 154, 1, 51, 26, 71},
+ {142, 78, 78, 16, 255, 128, 34, 197, 171},
+ {41, 40, 5, 102, 211, 183, 4, 1, 221},
+ {51, 50, 17, 168, 209, 192, 23, 25, 82},
+ },
+ {
+ {138, 31, 36, 171, 27, 166, 38, 44, 229},
+ {67, 87, 58, 169, 82, 115, 26, 59, 179},
+ {63, 59, 90, 180, 59, 166, 93, 73, 154},
+ {40, 40, 21, 116, 143, 209, 34, 39, 175},
+ {47, 15, 16, 183, 34, 223, 49, 45, 183},
+ {46, 17, 33, 183, 6, 98, 15, 32, 183},
+ {57, 46, 22, 24, 128, 1, 54, 17, 37},
+ {65, 32, 73, 115, 28, 128, 23, 128, 205},
+ {40, 3, 9, 115, 51, 192, 18, 6, 223},
+ {87, 37, 9, 115, 59, 77, 64, 21, 47},
+ },
+ {
+ {104, 55, 44, 218, 9, 54, 53, 130, 226},
+ {64, 90, 70, 205, 40, 41, 23, 26, 57},
+ {54, 57, 112, 184, 5, 41, 38, 166, 213},
+ {30, 34, 26, 133, 152, 116, 10, 32, 134},
+ {39, 19, 53, 221, 26, 114, 32, 73, 255},
+ {31, 9, 65, 234, 2, 15, 1, 118, 73},
+ {75, 32, 12, 51, 192, 255, 160, 43, 51},
+ {88, 31, 35, 67, 102, 85, 55, 186, 85},
+ {56, 21, 23, 111, 59, 205, 45, 37, 192},
+ {55, 38, 70, 124, 73, 102, 1, 34, 98},
+ },
+ {
+ {125, 98, 42, 88, 104, 85, 117, 175, 82},
+ {95, 84, 53, 89, 128, 100, 113, 101, 45},
+ {75, 79, 123, 47, 51, 128, 81, 171, 1},
+ {57, 17, 5, 71, 102, 57, 53, 41, 49},
+ {38, 33, 13, 121, 57, 73, 26, 1, 85},
+ {41, 10, 67, 138, 77, 110, 90, 47, 114},
+ {115, 21, 2, 10, 102, 255, 166, 23, 6},
+ {101, 29, 16, 10, 85, 128, 101, 196, 26},
+ {57, 18, 10, 102, 102, 213, 34, 20, 43},
+ {117, 20, 15, 36, 163, 128, 68, 1, 26},
+ },
+ {
+ {102, 61, 71, 37, 34, 53, 31, 243, 192},
+ {69, 60, 71, 38, 73, 119, 28, 222, 37},
+ {68, 45, 128, 34, 1, 47, 11, 245, 171},
+ {62, 17, 19, 70, 146, 85, 55, 62, 70},
+ {37, 43, 37, 154, 100, 163, 85, 160, 1},
+ {63, 9, 92, 136, 28, 64, 32, 201, 85},
+ {75, 15, 9, 9, 64, 255, 184, 119, 16},
+ {86, 6, 28, 5, 64, 255, 25, 248, 1},
+ {56, 8, 17, 132, 137, 255, 55, 116, 128},
+ {58, 15, 20, 82, 135, 57, 26, 121, 40},
+ },
+ {
+ {164, 50, 31, 137, 154, 133, 25, 35, 218},
+ {51, 103, 44, 131, 131, 123, 31, 6, 158},
+ {86, 40, 64, 135, 148, 224, 45, 183, 128},
+ {22, 26, 17, 131, 240, 154, 14, 1, 209},
+ {45, 16, 21, 91, 64, 222, 7, 1, 197},
+ {56, 21, 39, 155, 60, 138, 23, 102, 213},
+ {83, 12, 13, 54, 192, 255, 68, 47, 28},
+ {85, 26, 85, 85, 128, 128, 32, 146, 171},
+ {18, 11, 7, 63, 144, 171, 4, 4, 246},
+ {35, 27, 10, 146, 174, 171, 12, 26, 128},
+ },
+ {
+ {190, 80, 35, 99, 180, 80, 126, 54, 45},
+ {85, 126, 47, 87, 176, 51, 41, 20, 32},
+ {101, 75, 128, 139, 118, 146, 116, 128, 85},
+ {56, 41, 15, 176, 236, 85, 37, 9, 62},
+ {71, 30, 17, 119, 118, 255, 17, 18, 138},
+ {101, 38, 60, 138, 55, 70, 43, 26, 142},
+ {146, 36, 19, 30, 171, 255, 97, 27, 20},
+ {138, 45, 61, 62, 219, 1, 81, 188, 64},
+ {32, 41, 20, 117, 151, 142, 20, 21, 163},
+ {112, 19, 12, 61, 195, 128, 48, 4, 24},
+ },
+}
diff --git a/vendor/golang.org/x/image/vp8/predfunc.go b/vendor/golang.org/x/image/vp8/predfunc.go
new file mode 100644
index 000000000..f8999582b
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/predfunc.go
@@ -0,0 +1,553 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// This file implements the predicition functions, as specified in chapter 12.
+//
+// For each macroblock (of 1x16x16 luma and 2x8x8 chroma coefficients), the
+// luma values are either predicted as one large 16x16 region or 16 separate
+// 4x4 regions. The chroma values are always predicted as one 8x8 region.
+//
+// For 4x4 regions, the target block's predicted values (Xs) are a function of
+// its previously-decoded top and left border values, as well as a number of
+// pixels from the top-right:
+//
+// a b c d e f g h
+// p X X X X
+// q X X X X
+// r X X X X
+// s X X X X
+//
+// The predictor modes are:
+// - DC: all Xs = (b + c + d + e + p + q + r + s + 4) / 8.
+// - TM: the first X = (b + p - a), the second X = (c + p - a), and so on.
+// - VE: each X = the weighted average of its column's top value and that
+// value's neighbors, i.e. averages of abc, bcd, cde or def.
+// - HE: similar to VE except rows instead of columns, and the final row is
+// an average of r, s and s.
+// - RD, VR, LD, VL, HD, HU: these diagonal modes ("Right Down", "Vertical
+// Right", etc) are more complicated and are described in section 12.3.
+// All Xs are clipped to the range [0, 255].
+//
+// For 8x8 and 16x16 regions, the target block's predicted values are a
+// function of the top and left border values without the top-right overhang,
+// i.e. without the 8x8 or 16x16 equivalent of f, g and h. Furthermore:
+// - There are no diagonal predictor modes, only DC, TM, VE and HE.
+// - The DC mode has variants for macroblocks in the top row and/or left
+// column, i.e. for macroblocks with mby == 0 || mbx == 0.
+// - The VE and HE modes take only the column top or row left values; they do
+// not smooth that top/left value with its neighbors.
+
+// nPred is the number of predictor modes, not including the Top/Left versions
+// of the DC predictor mode.
+const nPred = 10
+
+const (
+ predDC = iota
+ predTM
+ predVE
+ predHE
+ predRD
+ predVR
+ predLD
+ predVL
+ predHD
+ predHU
+ predDCTop
+ predDCLeft
+ predDCTopLeft
+)
+
+func checkTopLeftPred(mbx, mby int, p uint8) uint8 {
+ if p != predDC {
+ return p
+ }
+ if mbx == 0 {
+ if mby == 0 {
+ return predDCTopLeft
+ }
+ return predDCLeft
+ }
+ if mby == 0 {
+ return predDCTop
+ }
+ return predDC
+}
+
+var predFunc4 = [...]func(*Decoder, int, int){
+ predFunc4DC,
+ predFunc4TM,
+ predFunc4VE,
+ predFunc4HE,
+ predFunc4RD,
+ predFunc4VR,
+ predFunc4LD,
+ predFunc4VL,
+ predFunc4HD,
+ predFunc4HU,
+ nil,
+ nil,
+ nil,
+}
+
+var predFunc8 = [...]func(*Decoder, int, int){
+ predFunc8DC,
+ predFunc8TM,
+ predFunc8VE,
+ predFunc8HE,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ predFunc8DCTop,
+ predFunc8DCLeft,
+ predFunc8DCTopLeft,
+}
+
+var predFunc16 = [...]func(*Decoder, int, int){
+ predFunc16DC,
+ predFunc16TM,
+ predFunc16VE,
+ predFunc16HE,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ nil,
+ predFunc16DCTop,
+ predFunc16DCLeft,
+ predFunc16DCTopLeft,
+}
+
+func predFunc4DC(z *Decoder, y, x int) {
+ sum := uint32(4)
+ for i := 0; i < 4; i++ {
+ sum += uint32(z.ybr[y-1][x+i])
+ }
+ for j := 0; j < 4; j++ {
+ sum += uint32(z.ybr[y+j][x-1])
+ }
+ avg := uint8(sum / 8)
+ for j := 0; j < 4; j++ {
+ for i := 0; i < 4; i++ {
+ z.ybr[y+j][x+i] = avg
+ }
+ }
+}
+
+func predFunc4TM(z *Decoder, y, x int) {
+ delta0 := -int32(z.ybr[y-1][x-1])
+ for j := 0; j < 4; j++ {
+ delta1 := delta0 + int32(z.ybr[y+j][x-1])
+ for i := 0; i < 4; i++ {
+ delta2 := delta1 + int32(z.ybr[y-1][x+i])
+ z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
+ }
+ }
+}
+
+func predFunc4VE(z *Decoder, y, x int) {
+ a := int32(z.ybr[y-1][x-1])
+ b := int32(z.ybr[y-1][x+0])
+ c := int32(z.ybr[y-1][x+1])
+ d := int32(z.ybr[y-1][x+2])
+ e := int32(z.ybr[y-1][x+3])
+ f := int32(z.ybr[y-1][x+4])
+ abc := uint8((a + 2*b + c + 2) / 4)
+ bcd := uint8((b + 2*c + d + 2) / 4)
+ cde := uint8((c + 2*d + e + 2) / 4)
+ def := uint8((d + 2*e + f + 2) / 4)
+ for j := 0; j < 4; j++ {
+ z.ybr[y+j][x+0] = abc
+ z.ybr[y+j][x+1] = bcd
+ z.ybr[y+j][x+2] = cde
+ z.ybr[y+j][x+3] = def
+ }
+}
+
+func predFunc4HE(z *Decoder, y, x int) {
+ s := int32(z.ybr[y+3][x-1])
+ r := int32(z.ybr[y+2][x-1])
+ q := int32(z.ybr[y+1][x-1])
+ p := int32(z.ybr[y+0][x-1])
+ a := int32(z.ybr[y-1][x-1])
+ ssr := uint8((s + 2*s + r + 2) / 4)
+ srq := uint8((s + 2*r + q + 2) / 4)
+ rqp := uint8((r + 2*q + p + 2) / 4)
+ apq := uint8((a + 2*p + q + 2) / 4)
+ for i := 0; i < 4; i++ {
+ z.ybr[y+0][x+i] = apq
+ z.ybr[y+1][x+i] = rqp
+ z.ybr[y+2][x+i] = srq
+ z.ybr[y+3][x+i] = ssr
+ }
+}
+
+func predFunc4RD(z *Decoder, y, x int) {
+ s := int32(z.ybr[y+3][x-1])
+ r := int32(z.ybr[y+2][x-1])
+ q := int32(z.ybr[y+1][x-1])
+ p := int32(z.ybr[y+0][x-1])
+ a := int32(z.ybr[y-1][x-1])
+ b := int32(z.ybr[y-1][x+0])
+ c := int32(z.ybr[y-1][x+1])
+ d := int32(z.ybr[y-1][x+2])
+ e := int32(z.ybr[y-1][x+3])
+ srq := uint8((s + 2*r + q + 2) / 4)
+ rqp := uint8((r + 2*q + p + 2) / 4)
+ qpa := uint8((q + 2*p + a + 2) / 4)
+ pab := uint8((p + 2*a + b + 2) / 4)
+ abc := uint8((a + 2*b + c + 2) / 4)
+ bcd := uint8((b + 2*c + d + 2) / 4)
+ cde := uint8((c + 2*d + e + 2) / 4)
+ z.ybr[y+0][x+0] = pab
+ z.ybr[y+0][x+1] = abc
+ z.ybr[y+0][x+2] = bcd
+ z.ybr[y+0][x+3] = cde
+ z.ybr[y+1][x+0] = qpa
+ z.ybr[y+1][x+1] = pab
+ z.ybr[y+1][x+2] = abc
+ z.ybr[y+1][x+3] = bcd
+ z.ybr[y+2][x+0] = rqp
+ z.ybr[y+2][x+1] = qpa
+ z.ybr[y+2][x+2] = pab
+ z.ybr[y+2][x+3] = abc
+ z.ybr[y+3][x+0] = srq
+ z.ybr[y+3][x+1] = rqp
+ z.ybr[y+3][x+2] = qpa
+ z.ybr[y+3][x+3] = pab
+}
+
+func predFunc4VR(z *Decoder, y, x int) {
+ r := int32(z.ybr[y+2][x-1])
+ q := int32(z.ybr[y+1][x-1])
+ p := int32(z.ybr[y+0][x-1])
+ a := int32(z.ybr[y-1][x-1])
+ b := int32(z.ybr[y-1][x+0])
+ c := int32(z.ybr[y-1][x+1])
+ d := int32(z.ybr[y-1][x+2])
+ e := int32(z.ybr[y-1][x+3])
+ ab := uint8((a + b + 1) / 2)
+ bc := uint8((b + c + 1) / 2)
+ cd := uint8((c + d + 1) / 2)
+ de := uint8((d + e + 1) / 2)
+ rqp := uint8((r + 2*q + p + 2) / 4)
+ qpa := uint8((q + 2*p + a + 2) / 4)
+ pab := uint8((p + 2*a + b + 2) / 4)
+ abc := uint8((a + 2*b + c + 2) / 4)
+ bcd := uint8((b + 2*c + d + 2) / 4)
+ cde := uint8((c + 2*d + e + 2) / 4)
+ z.ybr[y+0][x+0] = ab
+ z.ybr[y+0][x+1] = bc
+ z.ybr[y+0][x+2] = cd
+ z.ybr[y+0][x+3] = de
+ z.ybr[y+1][x+0] = pab
+ z.ybr[y+1][x+1] = abc
+ z.ybr[y+1][x+2] = bcd
+ z.ybr[y+1][x+3] = cde
+ z.ybr[y+2][x+0] = qpa
+ z.ybr[y+2][x+1] = ab
+ z.ybr[y+2][x+2] = bc
+ z.ybr[y+2][x+3] = cd
+ z.ybr[y+3][x+0] = rqp
+ z.ybr[y+3][x+1] = pab
+ z.ybr[y+3][x+2] = abc
+ z.ybr[y+3][x+3] = bcd
+}
+
+func predFunc4LD(z *Decoder, y, x int) {
+ a := int32(z.ybr[y-1][x+0])
+ b := int32(z.ybr[y-1][x+1])
+ c := int32(z.ybr[y-1][x+2])
+ d := int32(z.ybr[y-1][x+3])
+ e := int32(z.ybr[y-1][x+4])
+ f := int32(z.ybr[y-1][x+5])
+ g := int32(z.ybr[y-1][x+6])
+ h := int32(z.ybr[y-1][x+7])
+ abc := uint8((a + 2*b + c + 2) / 4)
+ bcd := uint8((b + 2*c + d + 2) / 4)
+ cde := uint8((c + 2*d + e + 2) / 4)
+ def := uint8((d + 2*e + f + 2) / 4)
+ efg := uint8((e + 2*f + g + 2) / 4)
+ fgh := uint8((f + 2*g + h + 2) / 4)
+ ghh := uint8((g + 2*h + h + 2) / 4)
+ z.ybr[y+0][x+0] = abc
+ z.ybr[y+0][x+1] = bcd
+ z.ybr[y+0][x+2] = cde
+ z.ybr[y+0][x+3] = def
+ z.ybr[y+1][x+0] = bcd
+ z.ybr[y+1][x+1] = cde
+ z.ybr[y+1][x+2] = def
+ z.ybr[y+1][x+3] = efg
+ z.ybr[y+2][x+0] = cde
+ z.ybr[y+2][x+1] = def
+ z.ybr[y+2][x+2] = efg
+ z.ybr[y+2][x+3] = fgh
+ z.ybr[y+3][x+0] = def
+ z.ybr[y+3][x+1] = efg
+ z.ybr[y+3][x+2] = fgh
+ z.ybr[y+3][x+3] = ghh
+}
+
+func predFunc4VL(z *Decoder, y, x int) {
+ a := int32(z.ybr[y-1][x+0])
+ b := int32(z.ybr[y-1][x+1])
+ c := int32(z.ybr[y-1][x+2])
+ d := int32(z.ybr[y-1][x+3])
+ e := int32(z.ybr[y-1][x+4])
+ f := int32(z.ybr[y-1][x+5])
+ g := int32(z.ybr[y-1][x+6])
+ h := int32(z.ybr[y-1][x+7])
+ ab := uint8((a + b + 1) / 2)
+ bc := uint8((b + c + 1) / 2)
+ cd := uint8((c + d + 1) / 2)
+ de := uint8((d + e + 1) / 2)
+ abc := uint8((a + 2*b + c + 2) / 4)
+ bcd := uint8((b + 2*c + d + 2) / 4)
+ cde := uint8((c + 2*d + e + 2) / 4)
+ def := uint8((d + 2*e + f + 2) / 4)
+ efg := uint8((e + 2*f + g + 2) / 4)
+ fgh := uint8((f + 2*g + h + 2) / 4)
+ z.ybr[y+0][x+0] = ab
+ z.ybr[y+0][x+1] = bc
+ z.ybr[y+0][x+2] = cd
+ z.ybr[y+0][x+3] = de
+ z.ybr[y+1][x+0] = abc
+ z.ybr[y+1][x+1] = bcd
+ z.ybr[y+1][x+2] = cde
+ z.ybr[y+1][x+3] = def
+ z.ybr[y+2][x+0] = bc
+ z.ybr[y+2][x+1] = cd
+ z.ybr[y+2][x+2] = de
+ z.ybr[y+2][x+3] = efg
+ z.ybr[y+3][x+0] = bcd
+ z.ybr[y+3][x+1] = cde
+ z.ybr[y+3][x+2] = def
+ z.ybr[y+3][x+3] = fgh
+}
+
+func predFunc4HD(z *Decoder, y, x int) {
+ s := int32(z.ybr[y+3][x-1])
+ r := int32(z.ybr[y+2][x-1])
+ q := int32(z.ybr[y+1][x-1])
+ p := int32(z.ybr[y+0][x-1])
+ a := int32(z.ybr[y-1][x-1])
+ b := int32(z.ybr[y-1][x+0])
+ c := int32(z.ybr[y-1][x+1])
+ d := int32(z.ybr[y-1][x+2])
+ sr := uint8((s + r + 1) / 2)
+ rq := uint8((r + q + 1) / 2)
+ qp := uint8((q + p + 1) / 2)
+ pa := uint8((p + a + 1) / 2)
+ srq := uint8((s + 2*r + q + 2) / 4)
+ rqp := uint8((r + 2*q + p + 2) / 4)
+ qpa := uint8((q + 2*p + a + 2) / 4)
+ pab := uint8((p + 2*a + b + 2) / 4)
+ abc := uint8((a + 2*b + c + 2) / 4)
+ bcd := uint8((b + 2*c + d + 2) / 4)
+ z.ybr[y+0][x+0] = pa
+ z.ybr[y+0][x+1] = pab
+ z.ybr[y+0][x+2] = abc
+ z.ybr[y+0][x+3] = bcd
+ z.ybr[y+1][x+0] = qp
+ z.ybr[y+1][x+1] = qpa
+ z.ybr[y+1][x+2] = pa
+ z.ybr[y+1][x+3] = pab
+ z.ybr[y+2][x+0] = rq
+ z.ybr[y+2][x+1] = rqp
+ z.ybr[y+2][x+2] = qp
+ z.ybr[y+2][x+3] = qpa
+ z.ybr[y+3][x+0] = sr
+ z.ybr[y+3][x+1] = srq
+ z.ybr[y+3][x+2] = rq
+ z.ybr[y+3][x+3] = rqp
+}
+
+func predFunc4HU(z *Decoder, y, x int) {
+ s := int32(z.ybr[y+3][x-1])
+ r := int32(z.ybr[y+2][x-1])
+ q := int32(z.ybr[y+1][x-1])
+ p := int32(z.ybr[y+0][x-1])
+ pq := uint8((p + q + 1) / 2)
+ qr := uint8((q + r + 1) / 2)
+ rs := uint8((r + s + 1) / 2)
+ pqr := uint8((p + 2*q + r + 2) / 4)
+ qrs := uint8((q + 2*r + s + 2) / 4)
+ rss := uint8((r + 2*s + s + 2) / 4)
+ sss := uint8(s)
+ z.ybr[y+0][x+0] = pq
+ z.ybr[y+0][x+1] = pqr
+ z.ybr[y+0][x+2] = qr
+ z.ybr[y+0][x+3] = qrs
+ z.ybr[y+1][x+0] = qr
+ z.ybr[y+1][x+1] = qrs
+ z.ybr[y+1][x+2] = rs
+ z.ybr[y+1][x+3] = rss
+ z.ybr[y+2][x+0] = rs
+ z.ybr[y+2][x+1] = rss
+ z.ybr[y+2][x+2] = sss
+ z.ybr[y+2][x+3] = sss
+ z.ybr[y+3][x+0] = sss
+ z.ybr[y+3][x+1] = sss
+ z.ybr[y+3][x+2] = sss
+ z.ybr[y+3][x+3] = sss
+}
+
+func predFunc8DC(z *Decoder, y, x int) {
+ sum := uint32(8)
+ for i := 0; i < 8; i++ {
+ sum += uint32(z.ybr[y-1][x+i])
+ }
+ for j := 0; j < 8; j++ {
+ sum += uint32(z.ybr[y+j][x-1])
+ }
+ avg := uint8(sum / 16)
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ z.ybr[y+j][x+i] = avg
+ }
+ }
+}
+
+func predFunc8TM(z *Decoder, y, x int) {
+ delta0 := -int32(z.ybr[y-1][x-1])
+ for j := 0; j < 8; j++ {
+ delta1 := delta0 + int32(z.ybr[y+j][x-1])
+ for i := 0; i < 8; i++ {
+ delta2 := delta1 + int32(z.ybr[y-1][x+i])
+ z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
+ }
+ }
+}
+
+func predFunc8VE(z *Decoder, y, x int) {
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ z.ybr[y+j][x+i] = z.ybr[y-1][x+i]
+ }
+ }
+}
+
+func predFunc8HE(z *Decoder, y, x int) {
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ z.ybr[y+j][x+i] = z.ybr[y+j][x-1]
+ }
+ }
+}
+
+func predFunc8DCTop(z *Decoder, y, x int) {
+ sum := uint32(4)
+ for j := 0; j < 8; j++ {
+ sum += uint32(z.ybr[y+j][x-1])
+ }
+ avg := uint8(sum / 8)
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ z.ybr[y+j][x+i] = avg
+ }
+ }
+}
+
+func predFunc8DCLeft(z *Decoder, y, x int) {
+ sum := uint32(4)
+ for i := 0; i < 8; i++ {
+ sum += uint32(z.ybr[y-1][x+i])
+ }
+ avg := uint8(sum / 8)
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ z.ybr[y+j][x+i] = avg
+ }
+ }
+}
+
+func predFunc8DCTopLeft(z *Decoder, y, x int) {
+ for j := 0; j < 8; j++ {
+ for i := 0; i < 8; i++ {
+ z.ybr[y+j][x+i] = 0x80
+ }
+ }
+}
+
+func predFunc16DC(z *Decoder, y, x int) {
+ sum := uint32(16)
+ for i := 0; i < 16; i++ {
+ sum += uint32(z.ybr[y-1][x+i])
+ }
+ for j := 0; j < 16; j++ {
+ sum += uint32(z.ybr[y+j][x-1])
+ }
+ avg := uint8(sum / 32)
+ for j := 0; j < 16; j++ {
+ for i := 0; i < 16; i++ {
+ z.ybr[y+j][x+i] = avg
+ }
+ }
+}
+
+func predFunc16TM(z *Decoder, y, x int) {
+ delta0 := -int32(z.ybr[y-1][x-1])
+ for j := 0; j < 16; j++ {
+ delta1 := delta0 + int32(z.ybr[y+j][x-1])
+ for i := 0; i < 16; i++ {
+ delta2 := delta1 + int32(z.ybr[y-1][x+i])
+ z.ybr[y+j][x+i] = uint8(clip(delta2, 0, 255))
+ }
+ }
+}
+
+func predFunc16VE(z *Decoder, y, x int) {
+ for j := 0; j < 16; j++ {
+ for i := 0; i < 16; i++ {
+ z.ybr[y+j][x+i] = z.ybr[y-1][x+i]
+ }
+ }
+}
+
+func predFunc16HE(z *Decoder, y, x int) {
+ for j := 0; j < 16; j++ {
+ for i := 0; i < 16; i++ {
+ z.ybr[y+j][x+i] = z.ybr[y+j][x-1]
+ }
+ }
+}
+
+func predFunc16DCTop(z *Decoder, y, x int) {
+ sum := uint32(8)
+ for j := 0; j < 16; j++ {
+ sum += uint32(z.ybr[y+j][x-1])
+ }
+ avg := uint8(sum / 16)
+ for j := 0; j < 16; j++ {
+ for i := 0; i < 16; i++ {
+ z.ybr[y+j][x+i] = avg
+ }
+ }
+}
+
+func predFunc16DCLeft(z *Decoder, y, x int) {
+ sum := uint32(8)
+ for i := 0; i < 16; i++ {
+ sum += uint32(z.ybr[y-1][x+i])
+ }
+ avg := uint8(sum / 16)
+ for j := 0; j < 16; j++ {
+ for i := 0; i < 16; i++ {
+ z.ybr[y+j][x+i] = avg
+ }
+ }
+}
+
+func predFunc16DCTopLeft(z *Decoder, y, x int) {
+ for j := 0; j < 16; j++ {
+ for i := 0; i < 16; i++ {
+ z.ybr[y+j][x+i] = 0x80
+ }
+ }
+}
diff --git a/vendor/golang.org/x/image/vp8/quant.go b/vendor/golang.org/x/image/vp8/quant.go
new file mode 100644
index 000000000..da4361604
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/quant.go
@@ -0,0 +1,98 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// This file implements parsing the quantization factors.
+
+// quant are DC/AC quantization factors.
+type quant struct {
+ y1 [2]uint16
+ y2 [2]uint16
+ uv [2]uint16
+}
+
+// clip clips x to the range [min, max] inclusive.
+func clip(x, min, max int32) int32 {
+ if x < min {
+ return min
+ }
+ if x > max {
+ return max
+ }
+ return x
+}
+
+// parseQuant parses the quantization factors, as specified in section 9.6.
+func (d *Decoder) parseQuant() {
+ baseQ0 := d.fp.readUint(uniformProb, 7)
+ dqy1DC := d.fp.readOptionalInt(uniformProb, 4)
+ const dqy1AC = 0
+ dqy2DC := d.fp.readOptionalInt(uniformProb, 4)
+ dqy2AC := d.fp.readOptionalInt(uniformProb, 4)
+ dquvDC := d.fp.readOptionalInt(uniformProb, 4)
+ dquvAC := d.fp.readOptionalInt(uniformProb, 4)
+ for i := 0; i < nSegment; i++ {
+ q := int32(baseQ0)
+ if d.segmentHeader.useSegment {
+ if d.segmentHeader.relativeDelta {
+ q += int32(d.segmentHeader.quantizer[i])
+ } else {
+ q = int32(d.segmentHeader.quantizer[i])
+ }
+ }
+ d.quant[i].y1[0] = dequantTableDC[clip(q+dqy1DC, 0, 127)]
+ d.quant[i].y1[1] = dequantTableAC[clip(q+dqy1AC, 0, 127)]
+ d.quant[i].y2[0] = dequantTableDC[clip(q+dqy2DC, 0, 127)] * 2
+ d.quant[i].y2[1] = dequantTableAC[clip(q+dqy2AC, 0, 127)] * 155 / 100
+ if d.quant[i].y2[1] < 8 {
+ d.quant[i].y2[1] = 8
+ }
+ // The 117 is not a typo. The dequant_init function in the spec's Reference
+ // Decoder Source Code (http://tools.ietf.org/html/rfc6386#section-9.6 Page 145)
+ // says to clamp the LHS value at 132, which is equal to dequantTableDC[117].
+ d.quant[i].uv[0] = dequantTableDC[clip(q+dquvDC, 0, 117)]
+ d.quant[i].uv[1] = dequantTableAC[clip(q+dquvAC, 0, 127)]
+ }
+}
+
+// The dequantization tables are specified in section 14.1.
+var (
+ dequantTableDC = [128]uint16{
+ 4, 5, 6, 7, 8, 9, 10, 10,
+ 11, 12, 13, 14, 15, 16, 17, 17,
+ 18, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 25, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89,
+ 91, 93, 95, 96, 98, 100, 101, 102,
+ 104, 106, 108, 110, 112, 114, 116, 118,
+ 122, 124, 126, 128, 130, 132, 134, 136,
+ 138, 140, 143, 145, 148, 151, 154, 157,
+ }
+ dequantTableAC = [128]uint16{
+ 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 60,
+ 62, 64, 66, 68, 70, 72, 74, 76,
+ 78, 80, 82, 84, 86, 88, 90, 92,
+ 94, 96, 98, 100, 102, 104, 106, 108,
+ 110, 112, 114, 116, 119, 122, 125, 128,
+ 131, 134, 137, 140, 143, 146, 149, 152,
+ 155, 158, 161, 164, 167, 170, 173, 177,
+ 181, 185, 189, 193, 197, 201, 205, 209,
+ 213, 217, 221, 225, 229, 234, 239, 245,
+ 249, 254, 259, 264, 269, 274, 279, 284,
+ }
+)
diff --git a/vendor/golang.org/x/image/vp8/reconstruct.go b/vendor/golang.org/x/image/vp8/reconstruct.go
new file mode 100644
index 000000000..c1cc4b532
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/reconstruct.go
@@ -0,0 +1,442 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// This file implements decoding DCT/WHT residual coefficients and
+// reconstructing YCbCr data equal to predicted values plus residuals.
+//
+// There are 1*16*16 + 2*8*8 + 1*4*4 coefficients per macroblock:
+// - 1*16*16 luma DCT coefficients,
+// - 2*8*8 chroma DCT coefficients, and
+// - 1*4*4 luma WHT coefficients.
+// Coefficients are read in lots of 16, and the later coefficients in each lot
+// are often zero.
+//
+// The YCbCr data consists of 1*16*16 luma values and 2*8*8 chroma values,
+// plus previously decoded values along the top and left borders. The combined
+// values are laid out as a [1+16+1+8][32]uint8 so that vertically adjacent
+// samples are 32 bytes apart. In detail, the layout is:
+//
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// . . . . . . . a b b b b b b b b b b b b b b b b c c c c . . . . 0
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 1
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 2
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 3
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 4
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 5
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 6
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 7
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 8
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 9
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 10
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 11
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y c c c c . . . . 12
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 13
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 14
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 15
+// . . . . . . . d Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y . . . . . . . . 16
+// . . . . . . . e f f f f f f f f . . . . . . . g h h h h h h h h 17
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 18
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 19
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 20
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 21
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 22
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 23
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 24
+// . . . . . . . i B B B B B B B B . . . . . . . j R R R R R R R R 25
+//
+// Y, B and R are the reconstructed luma (Y) and chroma (B, R) values.
+// The Y values are predicted (either as one 16x16 region or 16 4x4 regions)
+// based on the row above's Y values (some combination of {abc} or {dYC}) and
+// the column left's Y values (either {ad} or {bY}). Similarly, B and R values
+// are predicted on the row above and column left of their respective 8x8
+// region: {efi} for B, {ghj} for R.
+//
+// For uppermost macroblocks (i.e. those with mby == 0), the {abcefgh} values
+// are initialized to 0x81. Otherwise, they are copied from the bottom row of
+// the macroblock above. The {c} values are then duplicated from row 0 to rows
+// 4, 8 and 12 of the ybr workspace.
+// Similarly, for leftmost macroblocks (i.e. those with mbx == 0), the {adeigj}
+// values are initialized to 0x7f. Otherwise, they are copied from the right
+// column of the macroblock to the left.
+// For the top-left macroblock (with mby == 0 && mbx == 0), {aeg} is 0x81.
+//
+// When moving from one macroblock to the next horizontally, the {adeigj}
+// values can simply be copied from the workspace to itself, shifted by 8 or
+// 16 columns. When moving from one macroblock to the next vertically,
+// filtering can occur and hence the row values have to be copied from the
+// post-filtered image instead of the pre-filtered workspace.
+
+const (
+ bCoeffBase = 1*16*16 + 0*8*8
+ rCoeffBase = 1*16*16 + 1*8*8
+ whtCoeffBase = 1*16*16 + 2*8*8
+)
+
+const (
+ ybrYX = 8
+ ybrYY = 1
+ ybrBX = 8
+ ybrBY = 18
+ ybrRX = 24
+ ybrRY = 18
+)
+
+// prepareYBR prepares the {abcdefghij} elements of ybr.
+func (d *Decoder) prepareYBR(mbx, mby int) {
+ if mbx == 0 {
+ for y := 0; y < 17; y++ {
+ d.ybr[y][7] = 0x81
+ }
+ for y := 17; y < 26; y++ {
+ d.ybr[y][7] = 0x81
+ d.ybr[y][23] = 0x81
+ }
+ } else {
+ for y := 0; y < 17; y++ {
+ d.ybr[y][7] = d.ybr[y][7+16]
+ }
+ for y := 17; y < 26; y++ {
+ d.ybr[y][7] = d.ybr[y][15]
+ d.ybr[y][23] = d.ybr[y][31]
+ }
+ }
+ if mby == 0 {
+ for x := 7; x < 28; x++ {
+ d.ybr[0][x] = 0x7f
+ }
+ for x := 7; x < 16; x++ {
+ d.ybr[17][x] = 0x7f
+ }
+ for x := 23; x < 32; x++ {
+ d.ybr[17][x] = 0x7f
+ }
+ } else {
+ for i := 0; i < 16; i++ {
+ d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+i]
+ }
+ for i := 0; i < 8; i++ {
+ d.ybr[17][8+i] = d.img.Cb[(8*mby-1)*d.img.CStride+8*mbx+i]
+ }
+ for i := 0; i < 8; i++ {
+ d.ybr[17][24+i] = d.img.Cr[(8*mby-1)*d.img.CStride+8*mbx+i]
+ }
+ if mbx == d.mbw-1 {
+ for i := 16; i < 20; i++ {
+ d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+15]
+ }
+ } else {
+ for i := 16; i < 20; i++ {
+ d.ybr[0][8+i] = d.img.Y[(16*mby-1)*d.img.YStride+16*mbx+i]
+ }
+ }
+ }
+ for y := 4; y < 16; y += 4 {
+ d.ybr[y][24] = d.ybr[0][24]
+ d.ybr[y][25] = d.ybr[0][25]
+ d.ybr[y][26] = d.ybr[0][26]
+ d.ybr[y][27] = d.ybr[0][27]
+ }
+}
+
+// btou converts a bool to a 0/1 value.
+func btou(b bool) uint8 {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+// pack packs four 0/1 values into four bits of a uint32.
+func pack(x [4]uint8, shift int) uint32 {
+ u := uint32(x[0])<<0 | uint32(x[1])<<1 | uint32(x[2])<<2 | uint32(x[3])<<3
+ return u << uint(shift)
+}
+
+// unpack unpacks four 0/1 values from a four-bit value.
+var unpack = [16][4]uint8{
+ {0, 0, 0, 0},
+ {1, 0, 0, 0},
+ {0, 1, 0, 0},
+ {1, 1, 0, 0},
+ {0, 0, 1, 0},
+ {1, 0, 1, 0},
+ {0, 1, 1, 0},
+ {1, 1, 1, 0},
+ {0, 0, 0, 1},
+ {1, 0, 0, 1},
+ {0, 1, 0, 1},
+ {1, 1, 0, 1},
+ {0, 0, 1, 1},
+ {1, 0, 1, 1},
+ {0, 1, 1, 1},
+ {1, 1, 1, 1},
+}
+
+var (
+ // The mapping from 4x4 region position to band is specified in section 13.3.
+ bands = [17]uint8{0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 0}
+ // Category probabilties are specified in section 13.2.
+ // Decoding categories 1 and 2 are done inline.
+ cat3456 = [4][12]uint8{
+ {173, 148, 140, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {176, 155, 140, 135, 0, 0, 0, 0, 0, 0, 0, 0},
+ {180, 157, 141, 134, 130, 0, 0, 0, 0, 0, 0, 0},
+ {254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0},
+ }
+ // The zigzag order is:
+ // 0 1 5 6
+ // 2 4 7 12
+ // 3 8 11 13
+ // 9 10 14 15
+ zigzag = [16]uint8{0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15}
+)
+
+// parseResiduals4 parses a 4x4 region of residual coefficients, as specified
+// in section 13.3, and returns a 0/1 value indicating whether there was at
+// least one non-zero coefficient.
+// r is the partition to read bits from.
+// plane and context describe which token probability table to use. context is
+// either 0, 1 or 2, and equals how many of the macroblock left and macroblock
+// above have non-zero coefficients.
+// quant are the DC/AC quantization factors.
+// skipFirstCoeff is whether the DC coefficient has already been parsed.
+// coeffBase is the base index of d.coeff to write to.
+func (d *Decoder) parseResiduals4(r *partition, plane int, context uint8, quant [2]uint16, skipFirstCoeff bool, coeffBase int) uint8 {
+ prob, n := &d.tokenProb[plane], 0
+ if skipFirstCoeff {
+ n = 1
+ }
+ p := prob[bands[n]][context]
+ if !r.readBit(p[0]) {
+ return 0
+ }
+ for n != 16 {
+ n++
+ if !r.readBit(p[1]) {
+ p = prob[bands[n]][0]
+ continue
+ }
+ var v uint32
+ if !r.readBit(p[2]) {
+ v = 1
+ p = prob[bands[n]][1]
+ } else {
+ if !r.readBit(p[3]) {
+ if !r.readBit(p[4]) {
+ v = 2
+ } else {
+ v = 3 + r.readUint(p[5], 1)
+ }
+ } else if !r.readBit(p[6]) {
+ if !r.readBit(p[7]) {
+ // Category 1.
+ v = 5 + r.readUint(159, 1)
+ } else {
+ // Category 2.
+ v = 7 + 2*r.readUint(165, 1) + r.readUint(145, 1)
+ }
+ } else {
+ // Categories 3, 4, 5 or 6.
+ b1 := r.readUint(p[8], 1)
+ b0 := r.readUint(p[9+b1], 1)
+ cat := 2*b1 + b0
+ tab := &cat3456[cat]
+ v = 0
+ for i := 0; tab[i] != 0; i++ {
+ v *= 2
+ v += r.readUint(tab[i], 1)
+ }
+ v += 3 + (8 << cat)
+ }
+ p = prob[bands[n]][2]
+ }
+ z := zigzag[n-1]
+ c := int32(v) * int32(quant[btou(z > 0)])
+ if r.readBit(uniformProb) {
+ c = -c
+ }
+ d.coeff[coeffBase+int(z)] = int16(c)
+ if n == 16 || !r.readBit(p[0]) {
+ return 1
+ }
+ }
+ return 1
+}
+
+// parseResiduals parses the residuals and returns whether inner loop filtering
+// should be skipped for this macroblock.
+func (d *Decoder) parseResiduals(mbx, mby int) (skip bool) {
+ partition := &d.op[mby&(d.nOP-1)]
+ plane := planeY1SansY2
+ quant := &d.quant[d.segment]
+
+ // Parse the DC coefficient of each 4x4 luma region.
+ if d.usePredY16 {
+ nz := d.parseResiduals4(partition, planeY2, d.leftMB.nzY16+d.upMB[mbx].nzY16, quant.y2, false, whtCoeffBase)
+ d.leftMB.nzY16 = nz
+ d.upMB[mbx].nzY16 = nz
+ d.inverseWHT16()
+ plane = planeY1WithY2
+ }
+
+ var (
+ nzDC, nzAC [4]uint8
+ nzDCMask, nzACMask uint32
+ coeffBase int
+ )
+
+ // Parse the luma coefficients.
+ lnz := unpack[d.leftMB.nzMask&0x0f]
+ unz := unpack[d.upMB[mbx].nzMask&0x0f]
+ for y := 0; y < 4; y++ {
+ nz := lnz[y]
+ for x := 0; x < 4; x++ {
+ nz = d.parseResiduals4(partition, plane, nz+unz[x], quant.y1, d.usePredY16, coeffBase)
+ unz[x] = nz
+ nzAC[x] = nz
+ nzDC[x] = btou(d.coeff[coeffBase] != 0)
+ coeffBase += 16
+ }
+ lnz[y] = nz
+ nzDCMask |= pack(nzDC, y*4)
+ nzACMask |= pack(nzAC, y*4)
+ }
+ lnzMask := pack(lnz, 0)
+ unzMask := pack(unz, 0)
+
+ // Parse the chroma coefficients.
+ lnz = unpack[d.leftMB.nzMask>>4]
+ unz = unpack[d.upMB[mbx].nzMask>>4]
+ for c := 0; c < 4; c += 2 {
+ for y := 0; y < 2; y++ {
+ nz := lnz[y+c]
+ for x := 0; x < 2; x++ {
+ nz = d.parseResiduals4(partition, planeUV, nz+unz[x+c], quant.uv, false, coeffBase)
+ unz[x+c] = nz
+ nzAC[y*2+x] = nz
+ nzDC[y*2+x] = btou(d.coeff[coeffBase] != 0)
+ coeffBase += 16
+ }
+ lnz[y+c] = nz
+ }
+ nzDCMask |= pack(nzDC, 16+c*2)
+ nzACMask |= pack(nzAC, 16+c*2)
+ }
+ lnzMask |= pack(lnz, 4)
+ unzMask |= pack(unz, 4)
+
+ // Save decoder state.
+ d.leftMB.nzMask = uint8(lnzMask)
+ d.upMB[mbx].nzMask = uint8(unzMask)
+ d.nzDCMask = nzDCMask
+ d.nzACMask = nzACMask
+
+ // Section 15.1 of the spec says that "Steps 2 and 4 [of the loop filter]
+ // are skipped... [if] there is no DCT coefficient coded for the whole
+ // macroblock."
+ return nzDCMask == 0 && nzACMask == 0
+}
+
+// reconstructMacroblock applies the predictor functions and adds the inverse-
+// DCT transformed residuals to recover the YCbCr data.
+func (d *Decoder) reconstructMacroblock(mbx, mby int) {
+ if d.usePredY16 {
+ p := checkTopLeftPred(mbx, mby, d.predY16)
+ predFunc16[p](d, 1, 8)
+ for j := 0; j < 4; j++ {
+ for i := 0; i < 4; i++ {
+ n := 4*j + i
+ y := 4*j + 1
+ x := 4*i + 8
+ mask := uint32(1) << uint(n)
+ if d.nzACMask&mask != 0 {
+ d.inverseDCT4(y, x, 16*n)
+ } else if d.nzDCMask&mask != 0 {
+ d.inverseDCT4DCOnly(y, x, 16*n)
+ }
+ }
+ }
+ } else {
+ for j := 0; j < 4; j++ {
+ for i := 0; i < 4; i++ {
+ n := 4*j + i
+ y := 4*j + 1
+ x := 4*i + 8
+ predFunc4[d.predY4[j][i]](d, y, x)
+ mask := uint32(1) << uint(n)
+ if d.nzACMask&mask != 0 {
+ d.inverseDCT4(y, x, 16*n)
+ } else if d.nzDCMask&mask != 0 {
+ d.inverseDCT4DCOnly(y, x, 16*n)
+ }
+ }
+ }
+ }
+ p := checkTopLeftPred(mbx, mby, d.predC8)
+ predFunc8[p](d, ybrBY, ybrBX)
+ if d.nzACMask&0x0f0000 != 0 {
+ d.inverseDCT8(ybrBY, ybrBX, bCoeffBase)
+ } else if d.nzDCMask&0x0f0000 != 0 {
+ d.inverseDCT8DCOnly(ybrBY, ybrBX, bCoeffBase)
+ }
+ predFunc8[p](d, ybrRY, ybrRX)
+ if d.nzACMask&0xf00000 != 0 {
+ d.inverseDCT8(ybrRY, ybrRX, rCoeffBase)
+ } else if d.nzDCMask&0xf00000 != 0 {
+ d.inverseDCT8DCOnly(ybrRY, ybrRX, rCoeffBase)
+ }
+}
+
+// reconstruct reconstructs one macroblock and returns whether inner loop
+// filtering should be skipped for it.
+func (d *Decoder) reconstruct(mbx, mby int) (skip bool) {
+ if d.segmentHeader.updateMap {
+ if !d.fp.readBit(d.segmentHeader.prob[0]) {
+ d.segment = int(d.fp.readUint(d.segmentHeader.prob[1], 1))
+ } else {
+ d.segment = int(d.fp.readUint(d.segmentHeader.prob[2], 1)) + 2
+ }
+ }
+ if d.useSkipProb {
+ skip = d.fp.readBit(d.skipProb)
+ }
+ // Prepare the workspace.
+ for i := range d.coeff {
+ d.coeff[i] = 0
+ }
+ d.prepareYBR(mbx, mby)
+ // Parse the predictor modes.
+ d.usePredY16 = d.fp.readBit(145)
+ if d.usePredY16 {
+ d.parsePredModeY16(mbx)
+ } else {
+ d.parsePredModeY4(mbx)
+ }
+ d.parsePredModeC8()
+ // Parse the residuals.
+ if !skip {
+ skip = d.parseResiduals(mbx, mby)
+ } else {
+ if d.usePredY16 {
+ d.leftMB.nzY16 = 0
+ d.upMB[mbx].nzY16 = 0
+ }
+ d.leftMB.nzMask = 0
+ d.upMB[mbx].nzMask = 0
+ d.nzDCMask = 0
+ d.nzACMask = 0
+ }
+ // Reconstruct the YCbCr data and copy it to the image.
+ d.reconstructMacroblock(mbx, mby)
+ for i, y := (mby*d.img.YStride+mbx)*16, 0; y < 16; i, y = i+d.img.YStride, y+1 {
+ copy(d.img.Y[i:i+16], d.ybr[ybrYY+y][ybrYX:ybrYX+16])
+ }
+ for i, y := (mby*d.img.CStride+mbx)*8, 0; y < 8; i, y = i+d.img.CStride, y+1 {
+ copy(d.img.Cb[i:i+8], d.ybr[ybrBY+y][ybrBX:ybrBX+8])
+ copy(d.img.Cr[i:i+8], d.ybr[ybrRY+y][ybrRX:ybrRX+8])
+ }
+ return skip
+}
diff --git a/vendor/golang.org/x/image/vp8/token.go b/vendor/golang.org/x/image/vp8/token.go
new file mode 100644
index 000000000..da99cf0f9
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8/token.go
@@ -0,0 +1,381 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8
+
+// This file contains token probabilities for decoding DCT/WHT coefficients, as
+// specified in chapter 13.
+
+func (d *Decoder) parseTokenProb() {
+ for i := range d.tokenProb {
+ for j := range d.tokenProb[i] {
+ for k := range d.tokenProb[i][j] {
+ for l := range d.tokenProb[i][j][k] {
+ if d.fp.readBit(tokenProbUpdateProb[i][j][k][l]) {
+ d.tokenProb[i][j][k][l] = uint8(d.fp.readUint(uniformProb, 8))
+ }
+ }
+ }
+ }
+ }
+}
+
+// The plane enumeration is specified in section 13.3.
+const (
+ planeY1WithY2 = iota
+ planeY2
+ planeUV
+ planeY1SansY2
+ nPlane
+)
+
+const (
+ nBand = 8
+ nContext = 3
+ nProb = 11
+)
+
+// Token probability update probabilities are specified in section 13.4.
+var tokenProbUpdateProb = [nPlane][nBand][nContext][nProb]uint8{
+ {
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255},
+ {249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255},
+ {234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255},
+ {250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ },
+ {
+ {
+ {217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255},
+ {234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255},
+ },
+ {
+ {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ },
+ {
+ {
+ {186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255},
+ {234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255},
+ {251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255},
+ },
+ {
+ {255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ },
+ {
+ {
+ {248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255},
+ {248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255},
+ {248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255},
+ {250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ {
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ },
+}
+
+// Default token probabilities are specified in section 13.5.
+var defaultTokenProb = [nPlane][nBand][nContext][nProb]uint8{
+ {
+ {
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ },
+ {
+ {253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128},
+ {189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128},
+ {106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128},
+ },
+ {
+ {1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128},
+ {181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128},
+ {78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128},
+ },
+ {
+ {1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128},
+ {184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128},
+ {77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128},
+ },
+ {
+ {1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128},
+ {170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128},
+ {37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128},
+ },
+ {
+ {1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128},
+ {207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128},
+ {102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128},
+ },
+ {
+ {1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128},
+ {177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128},
+ {80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128},
+ },
+ {
+ {1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ },
+ },
+ {
+ {
+ {198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62},
+ {131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1},
+ {68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128},
+ },
+ {
+ {1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128},
+ {184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128},
+ {81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128},
+ },
+ {
+ {1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128},
+ {99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128},
+ {23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128},
+ },
+ {
+ {1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128},
+ {109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128},
+ {44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128},
+ },
+ {
+ {1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128},
+ {94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128},
+ {22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128},
+ },
+ {
+ {1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128},
+ {124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128},
+ {35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128},
+ },
+ {
+ {1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128},
+ {121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128},
+ {45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128},
+ },
+ {
+ {1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128},
+ {203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128},
+ {137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128},
+ },
+ },
+ {
+ {
+ {253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128},
+ {175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128},
+ {73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128},
+ },
+ {
+ {1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128},
+ {239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128},
+ {155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128},
+ },
+ {
+ {1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128},
+ {201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128},
+ {69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128},
+ },
+ {
+ {1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128},
+ {223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128},
+ {141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128},
+ },
+ {
+ {1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128},
+ {190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128},
+ {149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ },
+ {
+ {1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ },
+ {
+ {1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128},
+ {213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128},
+ {55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ },
+ {
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ {128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128},
+ },
+ },
+ {
+ {
+ {202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255},
+ {126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128},
+ {61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128},
+ },
+ {
+ {1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128},
+ {166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128},
+ {39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128},
+ },
+ {
+ {1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128},
+ {124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128},
+ {24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128},
+ },
+ {
+ {1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128},
+ {149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128},
+ {28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128},
+ },
+ {
+ {1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128},
+ {123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128},
+ {20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128},
+ },
+ {
+ {1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128},
+ {168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128},
+ {47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128},
+ },
+ {
+ {1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128},
+ {141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128},
+ {42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128},
+ },
+ {
+ {1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ {238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128},
+ },
+ },
+}
diff --git a/vendor/golang.org/x/image/vp8l/decode.go b/vendor/golang.org/x/image/vp8l/decode.go
new file mode 100644
index 000000000..431948701
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8l/decode.go
@@ -0,0 +1,603 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package vp8l implements a decoder for the VP8L lossless image format.
+//
+// The VP8L specification is at:
+// https://developers.google.com/speed/webp/docs/riff_container
+package vp8l // import "golang.org/x/image/vp8l"
+
+import (
+ "bufio"
+ "errors"
+ "image"
+ "image/color"
+ "io"
+)
+
+var (
+ errInvalidCodeLengths = errors.New("vp8l: invalid code lengths")
+ errInvalidHuffmanTree = errors.New("vp8l: invalid Huffman tree")
+)
+
+// colorCacheMultiplier is the multiplier used for the color cache hash
+// function, specified in section 4.2.3.
+const colorCacheMultiplier = 0x1e35a7bd
+
+// distanceMapTable is the look-up table for distanceMap.
+var distanceMapTable = [120]uint8{
+ 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
+ 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
+ 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
+ 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
+ 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
+ 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
+ 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
+ 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
+ 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
+ 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
+ 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
+ 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70,
+}
+
+// distanceMap maps a LZ77 backwards reference distance to a two-dimensional
+// pixel offset, specified in section 4.2.2.
+func distanceMap(w int32, code uint32) int32 {
+ if int32(code) > int32(len(distanceMapTable)) {
+ return int32(code) - int32(len(distanceMapTable))
+ }
+ distCode := int32(distanceMapTable[code-1])
+ yOffset := distCode >> 4
+ xOffset := 8 - distCode&0xf
+ if d := yOffset*w + xOffset; d >= 1 {
+ return d
+ }
+ return 1
+}
+
+// decoder holds the bit-stream for a VP8L image.
+type decoder struct {
+ r io.ByteReader
+ bits uint32
+ nBits uint32
+}
+
+// read reads the next n bits from the decoder's bit-stream.
+func (d *decoder) read(n uint32) (uint32, error) {
+ for d.nBits < n {
+ c, err := d.r.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ d.bits |= uint32(c) << d.nBits
+ d.nBits += 8
+ }
+ u := d.bits & (1<<n - 1)
+ d.bits >>= n
+ d.nBits -= n
+ return u, nil
+}
+
+// decodeTransform decodes the next transform and the width of the image after
+// transformation (or equivalently, before inverse transformation), specified
+// in section 3.
+func (d *decoder) decodeTransform(w int32, h int32) (t transform, newWidth int32, err error) {
+ t.oldWidth = w
+ t.transformType, err = d.read(2)
+ if err != nil {
+ return transform{}, 0, err
+ }
+ switch t.transformType {
+ case transformTypePredictor, transformTypeCrossColor:
+ t.bits, err = d.read(3)
+ if err != nil {
+ return transform{}, 0, err
+ }
+ t.bits += 2
+ t.pix, err = d.decodePix(nTiles(w, t.bits), nTiles(h, t.bits), 0, false)
+ if err != nil {
+ return transform{}, 0, err
+ }
+ case transformTypeSubtractGreen:
+ // No-op.
+ case transformTypeColorIndexing:
+ nColors, err := d.read(8)
+ if err != nil {
+ return transform{}, 0, err
+ }
+ nColors++
+ t.bits = 0
+ switch {
+ case nColors <= 2:
+ t.bits = 3
+ case nColors <= 4:
+ t.bits = 2
+ case nColors <= 16:
+ t.bits = 1
+ }
+ w = nTiles(w, t.bits)
+ pix, err := d.decodePix(int32(nColors), 1, 4*256, false)
+ if err != nil {
+ return transform{}, 0, err
+ }
+ for p := 4; p < len(pix); p += 4 {
+ pix[p+0] += pix[p-4]
+ pix[p+1] += pix[p-3]
+ pix[p+2] += pix[p-2]
+ pix[p+3] += pix[p-1]
+ }
+ // The spec says that "if the index is equal or larger than color_table_size,
+ // the argb color value should be set to 0x00000000 (transparent black)."
+ // We re-slice up to 256 4-byte pixels.
+ t.pix = pix[:4*256]
+ }
+ return t, w, nil
+}
+
+// repeatsCodeLength is the minimum code length for repeated codes.
+const repeatsCodeLength = 16
+
+// These magic numbers are specified at the end of section 5.2.2.
+// The 3-length arrays apply to code lengths >= repeatsCodeLength.
+var (
+ codeLengthCodeOrder = [19]uint8{
+ 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ }
+ repeatBits = [3]uint8{2, 3, 7}
+ repeatOffsets = [3]uint8{3, 3, 11}
+)
+
+// decodeCodeLengths decodes a Huffman tree's code lengths which are themselves
+// encoded via a Huffman tree, specified in section 5.2.2.
+func (d *decoder) decodeCodeLengths(dst []uint32, codeLengthCodeLengths []uint32) error {
+ h := hTree{}
+ if err := h.build(codeLengthCodeLengths); err != nil {
+ return err
+ }
+
+ maxSymbol := len(dst)
+ useLength, err := d.read(1)
+ if err != nil {
+ return err
+ }
+ if useLength != 0 {
+ n, err := d.read(3)
+ if err != nil {
+ return err
+ }
+ n = 2 + 2*n
+ ms, err := d.read(n)
+ if err != nil {
+ return err
+ }
+ maxSymbol = int(ms) + 2
+ if maxSymbol > len(dst) {
+ return errInvalidCodeLengths
+ }
+ }
+
+ // The spec says that "if code 16 [meaning repeat] is used before
+ // a non-zero value has been emitted, a value of 8 is repeated."
+ prevCodeLength := uint32(8)
+
+ for symbol := 0; symbol < len(dst); {
+ if maxSymbol == 0 {
+ break
+ }
+ maxSymbol--
+ codeLength, err := h.next(d)
+ if err != nil {
+ return err
+ }
+ if codeLength < repeatsCodeLength {
+ dst[symbol] = codeLength
+ symbol++
+ if codeLength != 0 {
+ prevCodeLength = codeLength
+ }
+ continue
+ }
+
+ repeat, err := d.read(uint32(repeatBits[codeLength-repeatsCodeLength]))
+ if err != nil {
+ return err
+ }
+ repeat += uint32(repeatOffsets[codeLength-repeatsCodeLength])
+ if symbol+int(repeat) > len(dst) {
+ return errInvalidCodeLengths
+ }
+ // A code length of 16 repeats the previous non-zero code.
+ // A code length of 17 or 18 repeats zeroes.
+ cl := uint32(0)
+ if codeLength == 16 {
+ cl = prevCodeLength
+ }
+ for ; repeat > 0; repeat-- {
+ dst[symbol] = cl
+ symbol++
+ }
+ }
+ return nil
+}
+
+// decodeHuffmanTree decodes a Huffman tree into h.
+func (d *decoder) decodeHuffmanTree(h *hTree, alphabetSize uint32) error {
+ useSimple, err := d.read(1)
+ if err != nil {
+ return err
+ }
+ if useSimple != 0 {
+ nSymbols, err := d.read(1)
+ if err != nil {
+ return err
+ }
+ nSymbols++
+ firstSymbolLengthCode, err := d.read(1)
+ if err != nil {
+ return err
+ }
+ firstSymbolLengthCode = 7*firstSymbolLengthCode + 1
+ var symbols [2]uint32
+ symbols[0], err = d.read(firstSymbolLengthCode)
+ if err != nil {
+ return err
+ }
+ if nSymbols == 2 {
+ symbols[1], err = d.read(8)
+ if err != nil {
+ return err
+ }
+ }
+ return h.buildSimple(nSymbols, symbols, alphabetSize)
+ }
+
+ nCodes, err := d.read(4)
+ if err != nil {
+ return err
+ }
+ nCodes += 4
+ if int(nCodes) > len(codeLengthCodeOrder) {
+ return errInvalidHuffmanTree
+ }
+ codeLengthCodeLengths := [len(codeLengthCodeOrder)]uint32{}
+ for i := uint32(0); i < nCodes; i++ {
+ codeLengthCodeLengths[codeLengthCodeOrder[i]], err = d.read(3)
+ if err != nil {
+ return err
+ }
+ }
+ codeLengths := make([]uint32, alphabetSize)
+ if err = d.decodeCodeLengths(codeLengths, codeLengthCodeLengths[:]); err != nil {
+ return err
+ }
+ return h.build(codeLengths)
+}
+
+const (
+ huffGreen = 0
+ huffRed = 1
+ huffBlue = 2
+ huffAlpha = 3
+ huffDistance = 4
+ nHuff = 5
+)
+
+// hGroup is an array of 5 Huffman trees.
+type hGroup [nHuff]hTree
+
+// decodeHuffmanGroups decodes the one or more hGroups used to decode the pixel
+// data. If one hGroup is used for the entire image, then hPix and hBits will
+// be zero. If more than one hGroup is used, then hPix contains the meta-image
+// that maps tiles to hGroup index, and hBits contains the log-2 tile size.
+func (d *decoder) decodeHuffmanGroups(w int32, h int32, topLevel bool, ccBits uint32) (
+ hGroups []hGroup, hPix []byte, hBits uint32, err error) {
+
+ maxHGroupIndex := 0
+ if topLevel {
+ useMeta, err := d.read(1)
+ if err != nil {
+ return nil, nil, 0, err
+ }
+ if useMeta != 0 {
+ hBits, err = d.read(3)
+ if err != nil {
+ return nil, nil, 0, err
+ }
+ hBits += 2
+ hPix, err = d.decodePix(nTiles(w, hBits), nTiles(h, hBits), 0, false)
+ if err != nil {
+ return nil, nil, 0, err
+ }
+ for p := 0; p < len(hPix); p += 4 {
+ i := int(hPix[p])<<8 | int(hPix[p+1])
+ if maxHGroupIndex < i {
+ maxHGroupIndex = i
+ }
+ }
+ }
+ }
+ hGroups = make([]hGroup, maxHGroupIndex+1)
+ for i := range hGroups {
+ for j, alphabetSize := range alphabetSizes {
+ if j == 0 && ccBits > 0 {
+ alphabetSize += 1 << ccBits
+ }
+ if err := d.decodeHuffmanTree(&hGroups[i][j], alphabetSize); err != nil {
+ return nil, nil, 0, err
+ }
+ }
+ }
+ return hGroups, hPix, hBits, nil
+}
+
+const (
+ nLiteralCodes = 256
+ nLengthCodes = 24
+ nDistanceCodes = 40
+)
+
+var alphabetSizes = [nHuff]uint32{
+ nLiteralCodes + nLengthCodes,
+ nLiteralCodes,
+ nLiteralCodes,
+ nLiteralCodes,
+ nDistanceCodes,
+}
+
+// decodePix decodes pixel data, specified in section 5.2.2.
+func (d *decoder) decodePix(w int32, h int32, minCap int32, topLevel bool) ([]byte, error) {
+ // Decode the color cache parameters.
+ ccBits, ccShift, ccEntries := uint32(0), uint32(0), ([]uint32)(nil)
+ useColorCache, err := d.read(1)
+ if err != nil {
+ return nil, err
+ }
+ if useColorCache != 0 {
+ ccBits, err = d.read(4)
+ if err != nil {
+ return nil, err
+ }
+ if ccBits < 1 || 11 < ccBits {
+ return nil, errors.New("vp8l: invalid color cache parameters")
+ }
+ ccShift = 32 - ccBits
+ ccEntries = make([]uint32, 1<<ccBits)
+ }
+
+ // Decode the Huffman groups.
+ hGroups, hPix, hBits, err := d.decodeHuffmanGroups(w, h, topLevel, ccBits)
+ if err != nil {
+ return nil, err
+ }
+ hMask, tilesPerRow := int32(0), int32(0)
+ if hBits != 0 {
+ hMask, tilesPerRow = 1<<hBits-1, nTiles(w, hBits)
+ }
+
+ // Decode the pixels.
+ if minCap < 4*w*h {
+ minCap = 4 * w * h
+ }
+ pix := make([]byte, 4*w*h, minCap)
+ p, cachedP := 0, 0
+ x, y := int32(0), int32(0)
+ hg, lookupHG := &hGroups[0], hMask != 0
+ for p < len(pix) {
+ if lookupHG {
+ i := 4 * (tilesPerRow*(y>>hBits) + (x >> hBits))
+ hg = &hGroups[uint32(hPix[i])<<8|uint32(hPix[i+1])]
+ }
+
+ green, err := hg[huffGreen].next(d)
+ if err != nil {
+ return nil, err
+ }
+ switch {
+ case green < nLiteralCodes:
+ // We have a literal pixel.
+ red, err := hg[huffRed].next(d)
+ if err != nil {
+ return nil, err
+ }
+ blue, err := hg[huffBlue].next(d)
+ if err != nil {
+ return nil, err
+ }
+ alpha, err := hg[huffAlpha].next(d)
+ if err != nil {
+ return nil, err
+ }
+ pix[p+0] = uint8(red)
+ pix[p+1] = uint8(green)
+ pix[p+2] = uint8(blue)
+ pix[p+3] = uint8(alpha)
+ p += 4
+
+ x++
+ if x == w {
+ x, y = 0, y+1
+ }
+ lookupHG = hMask != 0 && x&hMask == 0
+
+ case green < nLiteralCodes+nLengthCodes:
+ // We have a LZ77 backwards reference.
+ length, err := d.lz77Param(green - nLiteralCodes)
+ if err != nil {
+ return nil, err
+ }
+ distSym, err := hg[huffDistance].next(d)
+ if err != nil {
+ return nil, err
+ }
+ distCode, err := d.lz77Param(distSym)
+ if err != nil {
+ return nil, err
+ }
+ dist := distanceMap(w, distCode)
+ pEnd := p + 4*int(length)
+ q := p - 4*int(dist)
+ qEnd := pEnd - 4*int(dist)
+ if p < 0 || len(pix) < pEnd || q < 0 || len(pix) < qEnd {
+ return nil, errors.New("vp8l: invalid LZ77 parameters")
+ }
+ for ; p < pEnd; p, q = p+1, q+1 {
+ pix[p] = pix[q]
+ }
+
+ x += int32(length)
+ for x >= w {
+ x, y = x-w, y+1
+ }
+ lookupHG = hMask != 0
+
+ default:
+ // We have a color cache lookup. First, insert previous pixels
+ // into the cache. Note that VP8L assumes ARGB order, but the
+ // Go image.RGBA type is in RGBA order.
+ for ; cachedP < p; cachedP += 4 {
+ argb := uint32(pix[cachedP+0])<<16 |
+ uint32(pix[cachedP+1])<<8 |
+ uint32(pix[cachedP+2])<<0 |
+ uint32(pix[cachedP+3])<<24
+ ccEntries[(argb*colorCacheMultiplier)>>ccShift] = argb
+ }
+ green -= nLiteralCodes + nLengthCodes
+ if int(green) >= len(ccEntries) {
+ return nil, errors.New("vp8l: invalid color cache index")
+ }
+ argb := ccEntries[green]
+ pix[p+0] = uint8(argb >> 16)
+ pix[p+1] = uint8(argb >> 8)
+ pix[p+2] = uint8(argb >> 0)
+ pix[p+3] = uint8(argb >> 24)
+ p += 4
+
+ x++
+ if x == w {
+ x, y = 0, y+1
+ }
+ lookupHG = hMask != 0 && x&hMask == 0
+ }
+ }
+ return pix, nil
+}
+
+// lz77Param returns the next LZ77 parameter: a length or a distance, specified
+// in section 4.2.2.
+func (d *decoder) lz77Param(symbol uint32) (uint32, error) {
+ if symbol < 4 {
+ return symbol + 1, nil
+ }
+ extraBits := (symbol - 2) >> 1
+ offset := (2 + symbol&1) << extraBits
+ n, err := d.read(extraBits)
+ if err != nil {
+ return 0, err
+ }
+ return offset + n + 1, nil
+}
+
+// decodeHeader decodes the VP8L header from r.
+func decodeHeader(r io.Reader) (d *decoder, w int32, h int32, err error) {
+ rr, ok := r.(io.ByteReader)
+ if !ok {
+ rr = bufio.NewReader(r)
+ }
+ d = &decoder{r: rr}
+ magic, err := d.read(8)
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ if magic != 0x2f {
+ return nil, 0, 0, errors.New("vp8l: invalid header")
+ }
+ width, err := d.read(14)
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ width++
+ height, err := d.read(14)
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ height++
+ _, err = d.read(1) // Read and ignore the hasAlpha hint.
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ version, err := d.read(3)
+ if err != nil {
+ return nil, 0, 0, err
+ }
+ if version != 0 {
+ return nil, 0, 0, errors.New("vp8l: invalid version")
+ }
+ return d, int32(width), int32(height), nil
+}
+
+// DecodeConfig decodes the color model and dimensions of a VP8L image from r.
+func DecodeConfig(r io.Reader) (image.Config, error) {
+ _, w, h, err := decodeHeader(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ return image.Config{
+ ColorModel: color.NRGBAModel,
+ Width: int(w),
+ Height: int(h),
+ }, nil
+}
+
+// Decode decodes a VP8L image from r.
+func Decode(r io.Reader) (image.Image, error) {
+ d, w, h, err := decodeHeader(r)
+ if err != nil {
+ return nil, err
+ }
+ // Decode the transforms.
+ var (
+ nTransforms int
+ transforms [nTransformTypes]transform
+ transformsSeen [nTransformTypes]bool
+ originalW = w
+ )
+ for {
+ more, err := d.read(1)
+ if err != nil {
+ return nil, err
+ }
+ if more == 0 {
+ break
+ }
+ var t transform
+ t, w, err = d.decodeTransform(w, h)
+ if err != nil {
+ return nil, err
+ }
+ if transformsSeen[t.transformType] {
+ return nil, errors.New("vp8l: repeated transform")
+ }
+ transformsSeen[t.transformType] = true
+ transforms[nTransforms] = t
+ nTransforms++
+ }
+ // Decode the transformed pixels.
+ pix, err := d.decodePix(w, h, 0, true)
+ if err != nil {
+ return nil, err
+ }
+ // Apply the inverse transformations.
+ for i := nTransforms - 1; i >= 0; i-- {
+ t := &transforms[i]
+ pix = inverseTransforms[t.transformType](t, pix, h)
+ }
+ return &image.NRGBA{
+ Pix: pix,
+ Stride: 4 * int(originalW),
+ Rect: image.Rect(0, 0, int(originalW), int(h)),
+ }, nil
+}
diff --git a/vendor/golang.org/x/image/vp8l/huffman.go b/vendor/golang.org/x/image/vp8l/huffman.go
new file mode 100644
index 000000000..36368a872
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8l/huffman.go
@@ -0,0 +1,245 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8l
+
+import (
+ "io"
+)
+
+// reverseBits reverses the bits in a byte.
+var reverseBits = [256]uint8{
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+// hNode is a node in a Huffman tree.
+type hNode struct {
+ // symbol is the symbol held by this node.
+ symbol uint32
+ // children, if positive, is the hTree.nodes index of the first of
+ // this node's two children. Zero means an uninitialized node,
+ // and -1 means a leaf node.
+ children int32
+}
+
+const leafNode = -1
+
+// lutSize is the log-2 size of an hTree's look-up table.
+const lutSize, lutMask = 7, 1<<7 - 1
+
+// hTree is a Huffman tree.
+type hTree struct {
+ // nodes are the nodes of the Huffman tree. During construction,
+ // len(nodes) grows from 1 up to cap(nodes) by steps of two.
+ // After construction, len(nodes) == cap(nodes), and both equal
+ // 2*theNumberOfSymbols - 1.
+ nodes []hNode
+ // lut is a look-up table for walking the nodes. The x in lut[x] is
+ // the next lutSize bits in the bit-stream. The low 8 bits of lut[x]
+ // equals 1 plus the number of bits in the next code, or 0 if the
+ // next code requires more than lutSize bits. The high 24 bits are:
+ // - the symbol, if the code requires lutSize or fewer bits, or
+ // - the hTree.nodes index to start the tree traversal from, if
+ // the next code requires more than lutSize bits.
+ lut [1 << lutSize]uint32
+}
+
+// insert inserts into the hTree a symbol whose encoding is the least
+// significant codeLength bits of code.
+func (h *hTree) insert(symbol uint32, code uint32, codeLength uint32) error {
+ if symbol > 0xffff || codeLength > 0xfe {
+ return errInvalidHuffmanTree
+ }
+ baseCode := uint32(0)
+ if codeLength > lutSize {
+ baseCode = uint32(reverseBits[(code>>(codeLength-lutSize))&0xff]) >> (8 - lutSize)
+ } else {
+ baseCode = uint32(reverseBits[code&0xff]) >> (8 - codeLength)
+ for i := 0; i < 1<<(lutSize-codeLength); i++ {
+ h.lut[baseCode|uint32(i)<<codeLength] = symbol<<8 | (codeLength + 1)
+ }
+ }
+
+ n := uint32(0)
+ for jump := lutSize; codeLength > 0; {
+ codeLength--
+ if int(n) > len(h.nodes) {
+ return errInvalidHuffmanTree
+ }
+ switch h.nodes[n].children {
+ case leafNode:
+ return errInvalidHuffmanTree
+ case 0:
+ if len(h.nodes) == cap(h.nodes) {
+ return errInvalidHuffmanTree
+ }
+ // Create two empty child nodes.
+ h.nodes[n].children = int32(len(h.nodes))
+ h.nodes = h.nodes[:len(h.nodes)+2]
+ }
+ n = uint32(h.nodes[n].children) + 1&(code>>codeLength)
+ jump--
+ if jump == 0 && h.lut[baseCode] == 0 {
+ h.lut[baseCode] = n << 8
+ }
+ }
+
+ switch h.nodes[n].children {
+ case leafNode:
+ // No-op.
+ case 0:
+ // Turn the uninitialized node into a leaf.
+ h.nodes[n].children = leafNode
+ default:
+ return errInvalidHuffmanTree
+ }
+ h.nodes[n].symbol = symbol
+ return nil
+}
+
+// codeLengthsToCodes returns the canonical Huffman codes implied by the
+// sequence of code lengths.
+func codeLengthsToCodes(codeLengths []uint32) ([]uint32, error) {
+ maxCodeLength := uint32(0)
+ for _, cl := range codeLengths {
+ if maxCodeLength < cl {
+ maxCodeLength = cl
+ }
+ }
+ const maxAllowedCodeLength = 15
+ if len(codeLengths) == 0 || maxCodeLength > maxAllowedCodeLength {
+ return nil, errInvalidHuffmanTree
+ }
+ histogram := [maxAllowedCodeLength + 1]uint32{}
+ for _, cl := range codeLengths {
+ histogram[cl]++
+ }
+ currCode, nextCodes := uint32(0), [maxAllowedCodeLength + 1]uint32{}
+ for cl := 1; cl < len(nextCodes); cl++ {
+ currCode = (currCode + histogram[cl-1]) << 1
+ nextCodes[cl] = currCode
+ }
+ codes := make([]uint32, len(codeLengths))
+ for symbol, cl := range codeLengths {
+ if cl > 0 {
+ codes[symbol] = nextCodes[cl]
+ nextCodes[cl]++
+ }
+ }
+ return codes, nil
+}
+
+// build builds a canonical Huffman tree from the given code lengths.
+func (h *hTree) build(codeLengths []uint32) error {
+ // Calculate the number of symbols.
+ var nSymbols, lastSymbol uint32
+ for symbol, cl := range codeLengths {
+ if cl != 0 {
+ nSymbols++
+ lastSymbol = uint32(symbol)
+ }
+ }
+ if nSymbols == 0 {
+ return errInvalidHuffmanTree
+ }
+ h.nodes = make([]hNode, 1, 2*nSymbols-1)
+ // Handle the trivial case.
+ if nSymbols == 1 {
+ if len(codeLengths) <= int(lastSymbol) {
+ return errInvalidHuffmanTree
+ }
+ return h.insert(lastSymbol, 0, 0)
+ }
+ // Handle the non-trivial case.
+ codes, err := codeLengthsToCodes(codeLengths)
+ if err != nil {
+ return err
+ }
+ for symbol, cl := range codeLengths {
+ if cl > 0 {
+ if err := h.insert(uint32(symbol), codes[symbol], cl); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+// buildSimple builds a Huffman tree with 1 or 2 symbols.
+func (h *hTree) buildSimple(nSymbols uint32, symbols [2]uint32, alphabetSize uint32) error {
+ h.nodes = make([]hNode, 1, 2*nSymbols-1)
+ for i := uint32(0); i < nSymbols; i++ {
+ if symbols[i] >= alphabetSize {
+ return errInvalidHuffmanTree
+ }
+ if err := h.insert(symbols[i], i, nSymbols-1); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// next returns the next Huffman-encoded symbol from the bit-stream d.
+func (h *hTree) next(d *decoder) (uint32, error) {
+ var n uint32
+ // Read enough bits so that we can use the look-up table.
+ if d.nBits < lutSize {
+ c, err := d.r.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ // There are no more bytes of data, but we may still be able
+ // to read the next symbol out of the previously read bits.
+ goto slowPath
+ }
+ return 0, err
+ }
+ d.bits |= uint32(c) << d.nBits
+ d.nBits += 8
+ }
+ // Use the look-up table.
+ n = h.lut[d.bits&lutMask]
+ if b := n & 0xff; b != 0 {
+ b--
+ d.bits >>= b
+ d.nBits -= b
+ return n >> 8, nil
+ }
+ n >>= 8
+ d.bits >>= lutSize
+ d.nBits -= lutSize
+
+slowPath:
+ for h.nodes[n].children != leafNode {
+ if d.nBits == 0 {
+ c, err := d.r.ReadByte()
+ if err != nil {
+ if err == io.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ return 0, err
+ }
+ d.bits = uint32(c)
+ d.nBits = 8
+ }
+ n = uint32(h.nodes[n].children) + 1&d.bits
+ d.bits >>= 1
+ d.nBits--
+ }
+ return h.nodes[n].symbol, nil
+}
diff --git a/vendor/golang.org/x/image/vp8l/transform.go b/vendor/golang.org/x/image/vp8l/transform.go
new file mode 100644
index 000000000..06543dacb
--- /dev/null
+++ b/vendor/golang.org/x/image/vp8l/transform.go
@@ -0,0 +1,299 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package vp8l
+
+// This file deals with image transforms, specified in section 3.
+
+// nTiles returns the number of tiles needed to cover size pixels, where each
+// tile's side is 1<<bits pixels long.
+func nTiles(size int32, bits uint32) int32 {
+ return (size + 1<<bits - 1) >> bits
+}
+
+const (
+ transformTypePredictor = 0
+ transformTypeCrossColor = 1
+ transformTypeSubtractGreen = 2
+ transformTypeColorIndexing = 3
+ nTransformTypes = 4
+)
+
+// transform holds the parameters for an invertible transform.
+type transform struct {
+ // transformType is the type of the transform.
+ transformType uint32
+ // oldWidth is the width of the image before transformation (or
+ // equivalently, after inverse transformation). The color-indexing
+ // transform can reduce the width. For example, a 50-pixel-wide
+ // image that only needs 4 bits (half a byte) per color index can
+ // be transformed into a 25-pixel-wide image.
+ oldWidth int32
+ // bits is the log-2 size of the transform's tiles, for the predictor
+ // and cross-color transforms. 8>>bits is the number of bits per
+ // color index, for the color-index transform.
+ bits uint32
+ // pix is the tile values, for the predictor and cross-color
+ // transforms, and the color palette, for the color-index transform.
+ pix []byte
+}
+
+var inverseTransforms = [nTransformTypes]func(*transform, []byte, int32) []byte{
+ transformTypePredictor: inversePredictor,
+ transformTypeCrossColor: inverseCrossColor,
+ transformTypeSubtractGreen: inverseSubtractGreen,
+ transformTypeColorIndexing: inverseColorIndexing,
+}
+
+func inversePredictor(t *transform, pix []byte, h int32) []byte {
+ if t.oldWidth == 0 || h == 0 {
+ return pix
+ }
+ // The first pixel's predictor is mode 0 (opaque black).
+ pix[3] += 0xff
+ p, mask := int32(4), int32(1)<<t.bits-1
+ for x := int32(1); x < t.oldWidth; x++ {
+ // The rest of the first row's predictor is mode 1 (L).
+ pix[p+0] += pix[p-4]
+ pix[p+1] += pix[p-3]
+ pix[p+2] += pix[p-2]
+ pix[p+3] += pix[p-1]
+ p += 4
+ }
+ top, tilesPerRow := 0, nTiles(t.oldWidth, t.bits)
+ for y := int32(1); y < h; y++ {
+ // The first column's predictor is mode 2 (T).
+ pix[p+0] += pix[top+0]
+ pix[p+1] += pix[top+1]
+ pix[p+2] += pix[top+2]
+ pix[p+3] += pix[top+3]
+ p, top = p+4, top+4
+
+ q := 4 * (y >> t.bits) * tilesPerRow
+ predictorMode := t.pix[q+1] & 0x0f
+ q += 4
+ for x := int32(1); x < t.oldWidth; x++ {
+ if x&mask == 0 {
+ predictorMode = t.pix[q+1] & 0x0f
+ q += 4
+ }
+ switch predictorMode {
+ case 0: // Opaque black.
+ pix[p+3] += 0xff
+
+ case 1: // L.
+ pix[p+0] += pix[p-4]
+ pix[p+1] += pix[p-3]
+ pix[p+2] += pix[p-2]
+ pix[p+3] += pix[p-1]
+
+ case 2: // T.
+ pix[p+0] += pix[top+0]
+ pix[p+1] += pix[top+1]
+ pix[p+2] += pix[top+2]
+ pix[p+3] += pix[top+3]
+
+ case 3: // TR.
+ pix[p+0] += pix[top+4]
+ pix[p+1] += pix[top+5]
+ pix[p+2] += pix[top+6]
+ pix[p+3] += pix[top+7]
+
+ case 4: // TL.
+ pix[p+0] += pix[top-4]
+ pix[p+1] += pix[top-3]
+ pix[p+2] += pix[top-2]
+ pix[p+3] += pix[top-1]
+
+ case 5: // Average2(Average2(L, TR), T).
+ pix[p+0] += avg2(avg2(pix[p-4], pix[top+4]), pix[top+0])
+ pix[p+1] += avg2(avg2(pix[p-3], pix[top+5]), pix[top+1])
+ pix[p+2] += avg2(avg2(pix[p-2], pix[top+6]), pix[top+2])
+ pix[p+3] += avg2(avg2(pix[p-1], pix[top+7]), pix[top+3])
+
+ case 6: // Average2(L, TL).
+ pix[p+0] += avg2(pix[p-4], pix[top-4])
+ pix[p+1] += avg2(pix[p-3], pix[top-3])
+ pix[p+2] += avg2(pix[p-2], pix[top-2])
+ pix[p+3] += avg2(pix[p-1], pix[top-1])
+
+ case 7: // Average2(L, T).
+ pix[p+0] += avg2(pix[p-4], pix[top+0])
+ pix[p+1] += avg2(pix[p-3], pix[top+1])
+ pix[p+2] += avg2(pix[p-2], pix[top+2])
+ pix[p+3] += avg2(pix[p-1], pix[top+3])
+
+ case 8: // Average2(TL, T).
+ pix[p+0] += avg2(pix[top-4], pix[top+0])
+ pix[p+1] += avg2(pix[top-3], pix[top+1])
+ pix[p+2] += avg2(pix[top-2], pix[top+2])
+ pix[p+3] += avg2(pix[top-1], pix[top+3])
+
+ case 9: // Average2(T, TR).
+ pix[p+0] += avg2(pix[top+0], pix[top+4])
+ pix[p+1] += avg2(pix[top+1], pix[top+5])
+ pix[p+2] += avg2(pix[top+2], pix[top+6])
+ pix[p+3] += avg2(pix[top+3], pix[top+7])
+
+ case 10: // Average2(Average2(L, TL), Average2(T, TR)).
+ pix[p+0] += avg2(avg2(pix[p-4], pix[top-4]), avg2(pix[top+0], pix[top+4]))
+ pix[p+1] += avg2(avg2(pix[p-3], pix[top-3]), avg2(pix[top+1], pix[top+5]))
+ pix[p+2] += avg2(avg2(pix[p-2], pix[top-2]), avg2(pix[top+2], pix[top+6]))
+ pix[p+3] += avg2(avg2(pix[p-1], pix[top-1]), avg2(pix[top+3], pix[top+7]))
+
+ case 11: // Select(L, T, TL).
+ l0 := int32(pix[p-4])
+ l1 := int32(pix[p-3])
+ l2 := int32(pix[p-2])
+ l3 := int32(pix[p-1])
+ c0 := int32(pix[top-4])
+ c1 := int32(pix[top-3])
+ c2 := int32(pix[top-2])
+ c3 := int32(pix[top-1])
+ t0 := int32(pix[top+0])
+ t1 := int32(pix[top+1])
+ t2 := int32(pix[top+2])
+ t3 := int32(pix[top+3])
+ l := abs(c0-t0) + abs(c1-t1) + abs(c2-t2) + abs(c3-t3)
+ t := abs(c0-l0) + abs(c1-l1) + abs(c2-l2) + abs(c3-l3)
+ if l < t {
+ pix[p+0] += uint8(l0)
+ pix[p+1] += uint8(l1)
+ pix[p+2] += uint8(l2)
+ pix[p+3] += uint8(l3)
+ } else {
+ pix[p+0] += uint8(t0)
+ pix[p+1] += uint8(t1)
+ pix[p+2] += uint8(t2)
+ pix[p+3] += uint8(t3)
+ }
+
+ case 12: // ClampAddSubtractFull(L, T, TL).
+ pix[p+0] += clampAddSubtractFull(pix[p-4], pix[top+0], pix[top-4])
+ pix[p+1] += clampAddSubtractFull(pix[p-3], pix[top+1], pix[top-3])
+ pix[p+2] += clampAddSubtractFull(pix[p-2], pix[top+2], pix[top-2])
+ pix[p+3] += clampAddSubtractFull(pix[p-1], pix[top+3], pix[top-1])
+
+ case 13: // ClampAddSubtractHalf(Average2(L, T), TL).
+ pix[p+0] += clampAddSubtractHalf(avg2(pix[p-4], pix[top+0]), pix[top-4])
+ pix[p+1] += clampAddSubtractHalf(avg2(pix[p-3], pix[top+1]), pix[top-3])
+ pix[p+2] += clampAddSubtractHalf(avg2(pix[p-2], pix[top+2]), pix[top-2])
+ pix[p+3] += clampAddSubtractHalf(avg2(pix[p-1], pix[top+3]), pix[top-1])
+ }
+ p, top = p+4, top+4
+ }
+ }
+ return pix
+}
+
+func inverseCrossColor(t *transform, pix []byte, h int32) []byte {
+ var greenToRed, greenToBlue, redToBlue int32
+ p, mask, tilesPerRow := int32(0), int32(1)<<t.bits-1, nTiles(t.oldWidth, t.bits)
+ for y := int32(0); y < h; y++ {
+ q := 4 * (y >> t.bits) * tilesPerRow
+ for x := int32(0); x < t.oldWidth; x++ {
+ if x&mask == 0 {
+ redToBlue = int32(int8(t.pix[q+0]))
+ greenToBlue = int32(int8(t.pix[q+1]))
+ greenToRed = int32(int8(t.pix[q+2]))
+ q += 4
+ }
+ red := pix[p+0]
+ green := pix[p+1]
+ blue := pix[p+2]
+ red += uint8(uint32(greenToRed*int32(int8(green))) >> 5)
+ blue += uint8(uint32(greenToBlue*int32(int8(green))) >> 5)
+ blue += uint8(uint32(redToBlue*int32(int8(red))) >> 5)
+ pix[p+0] = red
+ pix[p+2] = blue
+ p += 4
+ }
+ }
+ return pix
+}
+
+func inverseSubtractGreen(t *transform, pix []byte, h int32) []byte {
+ for p := 0; p < len(pix); p += 4 {
+ green := pix[p+1]
+ pix[p+0] += green
+ pix[p+2] += green
+ }
+ return pix
+}
+
+func inverseColorIndexing(t *transform, pix []byte, h int32) []byte {
+ if t.bits == 0 {
+ for p := 0; p < len(pix); p += 4 {
+ i := 4 * uint32(pix[p+1])
+ pix[p+0] = t.pix[i+0]
+ pix[p+1] = t.pix[i+1]
+ pix[p+2] = t.pix[i+2]
+ pix[p+3] = t.pix[i+3]
+ }
+ return pix
+ }
+
+ vMask, xMask, bitsPerPixel := uint32(0), int32(0), uint32(8>>t.bits)
+ switch t.bits {
+ case 1:
+ vMask, xMask = 0x0f, 0x01
+ case 2:
+ vMask, xMask = 0x03, 0x03
+ case 3:
+ vMask, xMask = 0x01, 0x07
+ }
+
+ d, p, v, dst := 0, 0, uint32(0), make([]byte, 4*t.oldWidth*h)
+ for y := int32(0); y < h; y++ {
+ for x := int32(0); x < t.oldWidth; x++ {
+ if x&xMask == 0 {
+ v = uint32(pix[p+1])
+ p += 4
+ }
+
+ i := 4 * (v & vMask)
+ dst[d+0] = t.pix[i+0]
+ dst[d+1] = t.pix[i+1]
+ dst[d+2] = t.pix[i+2]
+ dst[d+3] = t.pix[i+3]
+ d += 4
+
+ v >>= bitsPerPixel
+ }
+ }
+ return dst
+}
+
+func abs(x int32) int32 {
+ if x < 0 {
+ return -x
+ }
+ return x
+}
+
+func avg2(a, b uint8) uint8 {
+ return uint8((int32(a) + int32(b)) / 2)
+}
+
+func clampAddSubtractFull(a, b, c uint8) uint8 {
+ x := int32(a) + int32(b) - int32(c)
+ if x < 0 {
+ return 0
+ }
+ if x > 255 {
+ return 255
+ }
+ return uint8(x)
+}
+
+func clampAddSubtractHalf(a, b uint8) uint8 {
+ x := int32(a) + (int32(a)-int32(b))/2
+ if x < 0 {
+ return 0
+ }
+ if x > 255 {
+ return 255
+ }
+ return uint8(x)
+}
diff --git a/vendor/golang.org/x/image/webp/decode.go b/vendor/golang.org/x/image/webp/decode.go
new file mode 100644
index 000000000..134307e41
--- /dev/null
+++ b/vendor/golang.org/x/image/webp/decode.go
@@ -0,0 +1,274 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package webp implements a decoder for WEBP images.
+//
+// WEBP is defined at:
+// https://developers.google.com/speed/webp/docs/riff_container
+package webp // import "golang.org/x/image/webp"
+
+import (
+ "bytes"
+ "errors"
+ "image"
+ "image/color"
+ "io"
+
+ "golang.org/x/image/riff"
+ "golang.org/x/image/vp8"
+ "golang.org/x/image/vp8l"
+)
+
+var errInvalidFormat = errors.New("webp: invalid format")
+
+var (
+ fccALPH = riff.FourCC{'A', 'L', 'P', 'H'}
+ fccVP8 = riff.FourCC{'V', 'P', '8', ' '}
+ fccVP8L = riff.FourCC{'V', 'P', '8', 'L'}
+ fccVP8X = riff.FourCC{'V', 'P', '8', 'X'}
+ fccWEBP = riff.FourCC{'W', 'E', 'B', 'P'}
+)
+
+func decode(r io.Reader, configOnly bool) (image.Image, image.Config, error) {
+ formType, riffReader, err := riff.NewReader(r)
+ if err != nil {
+ return nil, image.Config{}, err
+ }
+ if formType != fccWEBP {
+ return nil, image.Config{}, errInvalidFormat
+ }
+
+ var (
+ alpha []byte
+ alphaStride int
+ wantAlpha bool
+ widthMinusOne uint32
+ heightMinusOne uint32
+ buf [10]byte
+ )
+ for {
+ chunkID, chunkLen, chunkData, err := riffReader.Next()
+ if err == io.EOF {
+ err = errInvalidFormat
+ }
+ if err != nil {
+ return nil, image.Config{}, err
+ }
+
+ switch chunkID {
+ case fccALPH:
+ if !wantAlpha {
+ return nil, image.Config{}, errInvalidFormat
+ }
+ wantAlpha = false
+ // Read the Pre-processing | Filter | Compression byte.
+ if _, err := io.ReadFull(chunkData, buf[:1]); err != nil {
+ if err == io.EOF {
+ err = errInvalidFormat
+ }
+ return nil, image.Config{}, err
+ }
+ alpha, alphaStride, err = readAlpha(chunkData, widthMinusOne, heightMinusOne, buf[0]&0x03)
+ if err != nil {
+ return nil, image.Config{}, err
+ }
+ unfilterAlpha(alpha, alphaStride, (buf[0]>>2)&0x03)
+
+ case fccVP8:
+ if wantAlpha || int32(chunkLen) < 0 {
+ return nil, image.Config{}, errInvalidFormat
+ }
+ d := vp8.NewDecoder()
+ d.Init(chunkData, int(chunkLen))
+ fh, err := d.DecodeFrameHeader()
+ if err != nil {
+ return nil, image.Config{}, err
+ }
+ if configOnly {
+ return nil, image.Config{
+ ColorModel: color.YCbCrModel,
+ Width: fh.Width,
+ Height: fh.Height,
+ }, nil
+ }
+ m, err := d.DecodeFrame()
+ if err != nil {
+ return nil, image.Config{}, err
+ }
+ if alpha != nil {
+ return &image.NYCbCrA{
+ YCbCr: *m,
+ A: alpha,
+ AStride: alphaStride,
+ }, image.Config{}, nil
+ }
+ return m, image.Config{}, nil
+
+ case fccVP8L:
+ if wantAlpha || alpha != nil {
+ return nil, image.Config{}, errInvalidFormat
+ }
+ if configOnly {
+ c, err := vp8l.DecodeConfig(chunkData)
+ return nil, c, err
+ }
+ m, err := vp8l.Decode(chunkData)
+ return m, image.Config{}, err
+
+ case fccVP8X:
+ if chunkLen != 10 {
+ return nil, image.Config{}, errInvalidFormat
+ }
+ if _, err := io.ReadFull(chunkData, buf[:10]); err != nil {
+ return nil, image.Config{}, err
+ }
+ const (
+ animationBit = 1 << 1
+ xmpMetadataBit = 1 << 2
+ exifMetadataBit = 1 << 3
+ alphaBit = 1 << 4
+ iccProfileBit = 1 << 5
+ )
+ if buf[0] != alphaBit {
+ return nil, image.Config{}, errors.New("webp: non-Alpha VP8X is not implemented")
+ }
+ widthMinusOne = uint32(buf[4]) | uint32(buf[5])<<8 | uint32(buf[6])<<16
+ heightMinusOne = uint32(buf[7]) | uint32(buf[8])<<8 | uint32(buf[9])<<16
+ if configOnly {
+ return nil, image.Config{
+ ColorModel: color.NYCbCrAModel,
+ Width: int(widthMinusOne) + 1,
+ Height: int(heightMinusOne) + 1,
+ }, nil
+ }
+ wantAlpha = true
+
+ default:
+ return nil, image.Config{}, errInvalidFormat
+ }
+ }
+}
+
+func readAlpha(chunkData io.Reader, widthMinusOne, heightMinusOne uint32, compression byte) (
+ alpha []byte, alphaStride int, err error) {
+
+ switch compression {
+ case 0:
+ w := int(widthMinusOne) + 1
+ h := int(heightMinusOne) + 1
+ alpha = make([]byte, w*h)
+ if _, err := io.ReadFull(chunkData, alpha); err != nil {
+ return nil, 0, err
+ }
+ return alpha, w, nil
+
+ case 1:
+ // Read the VP8L-compressed alpha values. First, synthesize a 5-byte VP8L header:
+ // a 1-byte magic number, a 14-bit widthMinusOne, a 14-bit heightMinusOne,
+ // a 1-bit (ignored, zero) alphaIsUsed and a 3-bit (zero) version.
+ // TODO(nigeltao): be more efficient than decoding an *image.NRGBA just to
+ // extract the green values to a separately allocated []byte. Fixing this
+ // will require changes to the vp8l package's API.
+ if widthMinusOne > 0x3fff || heightMinusOne > 0x3fff {
+ return nil, 0, errors.New("webp: invalid format")
+ }
+ alphaImage, err := vp8l.Decode(io.MultiReader(
+ bytes.NewReader([]byte{
+ 0x2f, // VP8L magic number.
+ uint8(widthMinusOne),
+ uint8(widthMinusOne>>8) | uint8(heightMinusOne<<6),
+ uint8(heightMinusOne >> 2),
+ uint8(heightMinusOne >> 10),
+ }),
+ chunkData,
+ ))
+ if err != nil {
+ return nil, 0, err
+ }
+ // The green values of the inner NRGBA image are the alpha values of the
+ // outer NYCbCrA image.
+ pix := alphaImage.(*image.NRGBA).Pix
+ alpha = make([]byte, len(pix)/4)
+ for i := range alpha {
+ alpha[i] = pix[4*i+1]
+ }
+ return alpha, int(widthMinusOne) + 1, nil
+ }
+ return nil, 0, errInvalidFormat
+}
+
+func unfilterAlpha(alpha []byte, alphaStride int, filter byte) {
+ if len(alpha) == 0 || alphaStride == 0 {
+ return
+ }
+ switch filter {
+ case 1: // Horizontal filter.
+ for i := 1; i < alphaStride; i++ {
+ alpha[i] += alpha[i-1]
+ }
+ for i := alphaStride; i < len(alpha); i += alphaStride {
+ // The first column is equivalent to the vertical filter.
+ alpha[i] += alpha[i-alphaStride]
+
+ for j := 1; j < alphaStride; j++ {
+ alpha[i+j] += alpha[i+j-1]
+ }
+ }
+
+ case 2: // Vertical filter.
+ // The first row is equivalent to the horizontal filter.
+ for i := 1; i < alphaStride; i++ {
+ alpha[i] += alpha[i-1]
+ }
+
+ for i := alphaStride; i < len(alpha); i++ {
+ alpha[i] += alpha[i-alphaStride]
+ }
+
+ case 3: // Gradient filter.
+ // The first row is equivalent to the horizontal filter.
+ for i := 1; i < alphaStride; i++ {
+ alpha[i] += alpha[i-1]
+ }
+
+ for i := alphaStride; i < len(alpha); i += alphaStride {
+ // The first column is equivalent to the vertical filter.
+ alpha[i] += alpha[i-alphaStride]
+
+ // The interior is predicted on the three top/left pixels.
+ for j := 1; j < alphaStride; j++ {
+ c := int(alpha[i+j-alphaStride-1])
+ b := int(alpha[i+j-alphaStride])
+ a := int(alpha[i+j-1])
+ x := a + b - c
+ if x < 0 {
+ x = 0
+ } else if x > 255 {
+ x = 255
+ }
+ alpha[i+j] += uint8(x)
+ }
+ }
+ }
+}
+
+// Decode reads a WEBP image from r and returns it as an image.Image.
+func Decode(r io.Reader) (image.Image, error) {
+ m, _, err := decode(r, false)
+ if err != nil {
+ return nil, err
+ }
+ return m, err
+}
+
+// DecodeConfig returns the color model and dimensions of a WEBP image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, error) {
+ _, c, err := decode(r, true)
+ return c, err
+}
+
+func init() {
+ image.RegisterFormat("webp", "RIFF????WEBPVP8", Decode, DecodeConfig)
+}
diff --git a/vendor/golang.org/x/image/webp/decode_test.go b/vendor/golang.org/x/image/webp/decode_test.go
new file mode 100644
index 000000000..ad65b1088
--- /dev/null
+++ b/vendor/golang.org/x/image/webp/decode_test.go
@@ -0,0 +1,294 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package webp
+
+import (
+ "bytes"
+ "fmt"
+ "image"
+ "image/png"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+)
+
+// hex is like fmt.Sprintf("% x", x) but also inserts dots every 16 bytes, to
+// delineate VP8 macroblock boundaries.
+func hex(x []byte) string {
+ buf := new(bytes.Buffer)
+ for len(x) > 0 {
+ n := len(x)
+ if n > 16 {
+ n = 16
+ }
+ fmt.Fprintf(buf, " . % x", x[:n])
+ x = x[n:]
+ }
+ return buf.String()
+}
+
+func testDecodeLossy(t *testing.T, tc string, withAlpha bool) {
+ webpFilename := "../testdata/" + tc + ".lossy.webp"
+ pngFilename := webpFilename + ".ycbcr.png"
+ if withAlpha {
+ webpFilename = "../testdata/" + tc + ".lossy-with-alpha.webp"
+ pngFilename = webpFilename + ".nycbcra.png"
+ }
+
+ f0, err := os.Open(webpFilename)
+ if err != nil {
+ t.Errorf("%s: Open WEBP: %v", tc, err)
+ return
+ }
+ defer f0.Close()
+ img0, err := Decode(f0)
+ if err != nil {
+ t.Errorf("%s: Decode WEBP: %v", tc, err)
+ return
+ }
+
+ var (
+ m0 *image.YCbCr
+ a0 *image.NYCbCrA
+ ok bool
+ )
+ if withAlpha {
+ a0, ok = img0.(*image.NYCbCrA)
+ if ok {
+ m0 = &a0.YCbCr
+ }
+ } else {
+ m0, ok = img0.(*image.YCbCr)
+ }
+ if !ok || m0.SubsampleRatio != image.YCbCrSubsampleRatio420 {
+ t.Errorf("%s: decoded WEBP image is not a 4:2:0 YCbCr or 4:2:0 NYCbCrA", tc)
+ return
+ }
+ // w2 and h2 are the half-width and half-height, rounded up.
+ w, h := m0.Bounds().Dx(), m0.Bounds().Dy()
+ w2, h2 := int((w+1)/2), int((h+1)/2)
+
+ f1, err := os.Open(pngFilename)
+ if err != nil {
+ t.Errorf("%s: Open PNG: %v", tc, err)
+ return
+ }
+ defer f1.Close()
+ img1, err := png.Decode(f1)
+ if err != nil {
+ t.Errorf("%s: Open PNG: %v", tc, err)
+ return
+ }
+
+ // The split-into-YCbCr-planes golden image is a 2*w2 wide and h+h2 high
+ // (or 2*h+h2 high, if with Alpha) gray image arranged in IMC4 format:
+ // YYYY
+ // YYYY
+ // BBRR
+ // AAAA
+ // See http://www.fourcc.org/yuv.php#IMC4
+ pngW, pngH := 2*w2, h+h2
+ if withAlpha {
+ pngH += h
+ }
+ if got, want := img1.Bounds(), image.Rect(0, 0, pngW, pngH); got != want {
+ t.Errorf("%s: bounds0: got %v, want %v", tc, got, want)
+ return
+ }
+ m1, ok := img1.(*image.Gray)
+ if !ok {
+ t.Errorf("%s: decoded PNG image is not a Gray", tc)
+ return
+ }
+
+ type plane struct {
+ name string
+ m0Pix []uint8
+ m0Stride int
+ m1Rect image.Rectangle
+ }
+ planes := []plane{
+ {"Y", m0.Y, m0.YStride, image.Rect(0, 0, w, h)},
+ {"Cb", m0.Cb, m0.CStride, image.Rect(0*w2, h, 1*w2, h+h2)},
+ {"Cr", m0.Cr, m0.CStride, image.Rect(1*w2, h, 2*w2, h+h2)},
+ }
+ if withAlpha {
+ planes = append(planes, plane{
+ "A", a0.A, a0.AStride, image.Rect(0, h+h2, w, 2*h+h2),
+ })
+ }
+
+ for _, plane := range planes {
+ dx := plane.m1Rect.Dx()
+ nDiff, diff := 0, make([]byte, dx)
+ for j, y := 0, plane.m1Rect.Min.Y; y < plane.m1Rect.Max.Y; j, y = j+1, y+1 {
+ got := plane.m0Pix[j*plane.m0Stride:][:dx]
+ want := m1.Pix[y*m1.Stride+plane.m1Rect.Min.X:][:dx]
+ if bytes.Equal(got, want) {
+ continue
+ }
+ nDiff++
+ if nDiff > 10 {
+ t.Errorf("%s: %s plane: more rows differ", tc, plane.name)
+ break
+ }
+ for i := range got {
+ diff[i] = got[i] - want[i]
+ }
+ t.Errorf("%s: %s plane: m0 row %d, m1 row %d\ngot %s\nwant%s\ndiff%s",
+ tc, plane.name, j, y, hex(got), hex(want), hex(diff))
+ }
+ }
+}
+
+func TestDecodeVP8(t *testing.T) {
+ testCases := []string{
+ "blue-purple-pink",
+ "blue-purple-pink-large.no-filter",
+ "blue-purple-pink-large.simple-filter",
+ "blue-purple-pink-large.normal-filter",
+ "video-001",
+ "yellow_rose",
+ }
+
+ for _, tc := range testCases {
+ testDecodeLossy(t, tc, false)
+ }
+}
+
+func TestDecodeVP8XAlpha(t *testing.T) {
+ testCases := []string{
+ "yellow_rose",
+ }
+
+ for _, tc := range testCases {
+ testDecodeLossy(t, tc, true)
+ }
+}
+
+func TestDecodeVP8L(t *testing.T) {
+ testCases := []string{
+ "blue-purple-pink",
+ "blue-purple-pink-large",
+ "gopher-doc.1bpp",
+ "gopher-doc.2bpp",
+ "gopher-doc.4bpp",
+ "gopher-doc.8bpp",
+ "tux",
+ "yellow_rose",
+ }
+
+loop:
+ for _, tc := range testCases {
+ f0, err := os.Open("../testdata/" + tc + ".lossless.webp")
+ if err != nil {
+ t.Errorf("%s: Open WEBP: %v", tc, err)
+ continue
+ }
+ defer f0.Close()
+ img0, err := Decode(f0)
+ if err != nil {
+ t.Errorf("%s: Decode WEBP: %v", tc, err)
+ continue
+ }
+ m0, ok := img0.(*image.NRGBA)
+ if !ok {
+ t.Errorf("%s: WEBP image is %T, want *image.NRGBA", tc, img0)
+ continue
+ }
+
+ f1, err := os.Open("../testdata/" + tc + ".png")
+ if err != nil {
+ t.Errorf("%s: Open PNG: %v", tc, err)
+ continue
+ }
+ defer f1.Close()
+ img1, err := png.Decode(f1)
+ if err != nil {
+ t.Errorf("%s: Decode PNG: %v", tc, err)
+ continue
+ }
+ m1, ok := img1.(*image.NRGBA)
+ if !ok {
+ rgba1, ok := img1.(*image.RGBA)
+ if !ok {
+ t.Fatalf("%s: PNG image is %T, want *image.NRGBA", tc, img1)
+ continue
+ }
+ if !rgba1.Opaque() {
+ t.Fatalf("%s: PNG image is non-opaque *image.RGBA, want *image.NRGBA", tc)
+ continue
+ }
+ // The image is fully opaque, so we can re-interpret the RGBA pixels
+ // as NRGBA pixels.
+ m1 = &image.NRGBA{
+ Pix: rgba1.Pix,
+ Stride: rgba1.Stride,
+ Rect: rgba1.Rect,
+ }
+ }
+
+ b0, b1 := m0.Bounds(), m1.Bounds()
+ if b0 != b1 {
+ t.Errorf("%s: bounds: got %v, want %v", tc, b0, b1)
+ continue
+ }
+ for i := range m0.Pix {
+ if m0.Pix[i] != m1.Pix[i] {
+ y := i / m0.Stride
+ x := (i - y*m0.Stride) / 4
+ i = 4 * (y*m0.Stride + x)
+ t.Errorf("%s: at (%d, %d):\ngot %02x %02x %02x %02x\nwant %02x %02x %02x %02x",
+ tc, x, y,
+ m0.Pix[i+0], m0.Pix[i+1], m0.Pix[i+2], m0.Pix[i+3],
+ m1.Pix[i+0], m1.Pix[i+1], m1.Pix[i+2], m1.Pix[i+3],
+ )
+ continue loop
+ }
+ }
+ }
+}
+
+// TestDecodePartitionTooLarge tests that decoding a malformed WEBP image
+// doesn't try to allocate an unreasonable amount of memory. This WEBP image
+// claims a RIFF chunk length of 0x12345678 bytes (291 MiB) compressed,
+// independent of the actual image size (0 pixels wide * 0 pixels high).
+//
+// This is based on golang.org/issue/10790.
+func TestDecodePartitionTooLarge(t *testing.T) {
+ data := "RIFF\xff\xff\xff\x7fWEBPVP8 " +
+ "\x78\x56\x34\x12" + // RIFF chunk length.
+ "\xbd\x01\x00\x14\x00\x00\xb2\x34\x0a\x9d\x01\x2a\x96\x00\x67\x00"
+ _, err := Decode(strings.NewReader(data))
+ if err == nil {
+ t.Fatal("got nil error, want non-nil")
+ }
+ if got, want := err.Error(), "too much data"; !strings.Contains(got, want) {
+ t.Fatalf("got error %q, want something containing %q", got, want)
+ }
+}
+
+func benchmarkDecode(b *testing.B, filename string) {
+ data, err := ioutil.ReadFile("../testdata/blue-purple-pink-large." + filename + ".webp")
+ if err != nil {
+ b.Fatal(err)
+ }
+ s := string(data)
+ cfg, err := DecodeConfig(strings.NewReader(s))
+ if err != nil {
+ b.Fatal(err)
+ }
+ b.SetBytes(int64(cfg.Width * cfg.Height * 4))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Decode(strings.NewReader(s))
+ }
+}
+
+func BenchmarkDecodeVP8NoFilter(b *testing.B) { benchmarkDecode(b, "no-filter.lossy") }
+func BenchmarkDecodeVP8SimpleFilter(b *testing.B) { benchmarkDecode(b, "simple-filter.lossy") }
+func BenchmarkDecodeVP8NormalFilter(b *testing.B) { benchmarkDecode(b, "normal-filter.lossy") }
+func BenchmarkDecodeVP8L(b *testing.B) { benchmarkDecode(b, "lossless") }
diff --git a/vendor/golang.org/x/image/webp/nycbcra/nycbcra.go b/vendor/golang.org/x/image/webp/nycbcra/nycbcra.go
new file mode 100644
index 000000000..101c41fcf
--- /dev/null
+++ b/vendor/golang.org/x/image/webp/nycbcra/nycbcra.go
@@ -0,0 +1,194 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package nycbcra provides non-alpha-premultiplied Y'CbCr-with-alpha image and
+// color types.
+//
+// Deprecated: as of Go 1.6. Use the standard image and image/color packages
+// instead.
+package nycbcra // import "golang.org/x/image/webp/nycbcra"
+
+import (
+ "image"
+ "image/color"
+)
+
+func init() {
+ println("The golang.org/x/image/webp/nycbcra package is deprecated, as of Go 1.6. " +
+ "Use the standard image and image/color packages instead.")
+}
+
+// TODO: move this to the standard image and image/color packages, so that the
+// image/draw package can have fast-path code. Moving would rename:
+// nycbcra.Color to color.NYCbCrA
+// nycbcra.ColorModel to color.NYCbCrAModel
+// nycbcra.Image to image.NYCbCrA
+
+// Color represents a non-alpha-premultiplied Y'CbCr-with-alpha color, having
+// 8 bits each for one luma, two chroma and one alpha component.
+type Color struct {
+ color.YCbCr
+ A uint8
+}
+
+func (c Color) RGBA() (r, g, b, a uint32) {
+ r8, g8, b8 := color.YCbCrToRGB(c.Y, c.Cb, c.Cr)
+ a = uint32(c.A) * 0x101
+ r = uint32(r8) * 0x101 * a / 0xffff
+ g = uint32(g8) * 0x101 * a / 0xffff
+ b = uint32(b8) * 0x101 * a / 0xffff
+ return
+}
+
+// ColorModel is the Model for non-alpha-premultiplied Y'CbCr-with-alpha colors.
+var ColorModel color.Model = color.ModelFunc(nYCbCrAModel)
+
+func nYCbCrAModel(c color.Color) color.Color {
+ switch c := c.(type) {
+ case Color:
+ return c
+ case color.YCbCr:
+ return Color{c, 0xff}
+ }
+ r, g, b, a := c.RGBA()
+
+ // Convert from alpha-premultiplied to non-alpha-premultiplied.
+ if a != 0 {
+ r = (r * 0xffff) / a
+ g = (g * 0xffff) / a
+ b = (b * 0xffff) / a
+ }
+
+ y, u, v := color.RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+ return Color{color.YCbCr{Y: y, Cb: u, Cr: v}, uint8(a >> 8)}
+}
+
+// Image is an in-memory image of non-alpha-premultiplied Y'CbCr-with-alpha
+// colors. A and AStride are analogous to the Y and YStride fields of the
+// embedded YCbCr.
+type Image struct {
+ image.YCbCr
+ A []uint8
+ AStride int
+}
+
+func (p *Image) ColorModel() color.Model {
+ return ColorModel
+}
+
+func (p *Image) At(x, y int) color.Color {
+ return p.NYCbCrAAt(x, y)
+}
+
+func (p *Image) NYCbCrAAt(x, y int) Color {
+ if !(image.Point{X: x, Y: y}.In(p.Rect)) {
+ return Color{}
+ }
+ yi := p.YOffset(x, y)
+ ci := p.COffset(x, y)
+ ai := p.AOffset(x, y)
+ return Color{
+ color.YCbCr{
+ Y: p.Y[yi],
+ Cb: p.Cb[ci],
+ Cr: p.Cr[ci],
+ },
+ p.A[ai],
+ }
+}
+
+// AOffset returns the index of the first element of A that corresponds to
+// the pixel at (x, y).
+func (p *Image) AOffset(x, y int) int {
+ return (y-p.Rect.Min.Y)*p.AStride + (x - p.Rect.Min.X)
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *Image) SubImage(r image.Rectangle) image.Image {
+ // TODO: share code with image.NewYCbCr when this type moves into the
+ // standard image package.
+ r = r.Intersect(p.Rect)
+ // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+ // either r1 or r2 if the intersection is empty. Without explicitly checking for
+ // this, the Pix[i:] expression below can panic.
+ if r.Empty() {
+ return &Image{
+ YCbCr: image.YCbCr{
+ SubsampleRatio: p.SubsampleRatio,
+ },
+ }
+ }
+ yi := p.YOffset(r.Min.X, r.Min.Y)
+ ci := p.COffset(r.Min.X, r.Min.Y)
+ ai := p.AOffset(r.Min.X, r.Min.Y)
+ return &Image{
+ YCbCr: image.YCbCr{
+ Y: p.Y[yi:],
+ Cb: p.Cb[ci:],
+ Cr: p.Cr[ci:],
+ SubsampleRatio: p.SubsampleRatio,
+ YStride: p.YStride,
+ CStride: p.CStride,
+ Rect: r,
+ },
+ A: p.A[ai:],
+ AStride: p.AStride,
+ }
+}
+
+// Opaque scans the entire image and reports whether it is fully opaque.
+func (p *Image) Opaque() bool {
+ if p.Rect.Empty() {
+ return true
+ }
+ i0, i1 := 0, p.Rect.Dx()
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, a := range p.A[i0:i1] {
+ if a != 0xff {
+ return false
+ }
+ }
+ i0 += p.AStride
+ i1 += p.AStride
+ }
+ return true
+}
+
+// New returns a new Image with the given bounds and subsample ratio.
+func New(r image.Rectangle, subsampleRatio image.YCbCrSubsampleRatio) *Image {
+ // TODO: share code with image.NewYCbCr when this type moves into the
+ // standard image package.
+ w, h, cw, ch := r.Dx(), r.Dy(), 0, 0
+ switch subsampleRatio {
+ case image.YCbCrSubsampleRatio422:
+ cw = (r.Max.X+1)/2 - r.Min.X/2
+ ch = h
+ case image.YCbCrSubsampleRatio420:
+ cw = (r.Max.X+1)/2 - r.Min.X/2
+ ch = (r.Max.Y+1)/2 - r.Min.Y/2
+ case image.YCbCrSubsampleRatio440:
+ cw = w
+ ch = (r.Max.Y+1)/2 - r.Min.Y/2
+ default:
+ // Default to 4:4:4 subsampling.
+ cw = w
+ ch = h
+ }
+ b := make([]byte, 2*w*h+2*cw*ch)
+ // TODO: use s[i:j:k] notation to set the cap.
+ return &Image{
+ YCbCr: image.YCbCr{
+ Y: b[:w*h],
+ Cb: b[w*h+0*cw*ch : w*h+1*cw*ch],
+ Cr: b[w*h+1*cw*ch : w*h+2*cw*ch],
+ SubsampleRatio: subsampleRatio,
+ YStride: w,
+ CStride: cw,
+ Rect: r,
+ },
+ A: b[w*h+2*cw*ch:],
+ AStride: w,
+ }
+}
diff --git a/vendor/golang.org/x/sys/.gitattributes b/vendor/golang.org/x/sys/.gitattributes
new file mode 100644
index 000000000..d2f212e5d
--- /dev/null
+++ b/vendor/golang.org/x/sys/.gitattributes
@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text
diff --git a/vendor/golang.org/x/sys/.gitignore b/vendor/golang.org/x/sys/.gitignore
new file mode 100644
index 000000000..8339fd61d
--- /dev/null
+++ b/vendor/golang.org/x/sys/.gitignore
@@ -0,0 +1,2 @@
+# Add no patterns to .hgignore except for files generated by the build.
+last-change
diff --git a/vendor/golang.org/x/sys/AUTHORS b/vendor/golang.org/x/sys/AUTHORS
new file mode 100644
index 000000000..15167cd74
--- /dev/null
+++ b/vendor/golang.org/x/sys/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/vendor/golang.org/x/sys/CONTRIBUTING.md b/vendor/golang.org/x/sys/CONTRIBUTING.md
new file mode 100644
index 000000000..88dff59bc
--- /dev/null
+++ b/vendor/golang.org/x/sys/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+
+## Filing issues
+
+When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
+
+1. What version of Go are you using (`go version`)?
+2. What operating system and processor architecture are you using?
+3. What did you do?
+4. What did you expect to see?
+5. What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+**We do not accept GitHub pull requests**
+(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.
+
diff --git a/vendor/golang.org/x/sys/CONTRIBUTORS b/vendor/golang.org/x/sys/CONTRIBUTORS
new file mode 100644
index 000000000..1c4577e96
--- /dev/null
+++ b/vendor/golang.org/x/sys/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/vendor/golang.org/x/sys/README b/vendor/golang.org/x/sys/README
new file mode 100644
index 000000000..bd422b40c
--- /dev/null
+++ b/vendor/golang.org/x/sys/README
@@ -0,0 +1,3 @@
+This repository holds supplemental Go packages for low-level interactions with the operating system.
+
+To submit changes to this repository, see http://golang.org/doc/contribute.html.
diff --git a/vendor/golang.org/x/sys/codereview.cfg b/vendor/golang.org/x/sys/codereview.cfg
new file mode 100644
index 000000000..3f8b14b64
--- /dev/null
+++ b/vendor/golang.org/x/sys/codereview.cfg
@@ -0,0 +1 @@
+issuerepo: golang/go
diff --git a/vendor/golang.org/x/sys/plan9/asm.s b/vendor/golang.org/x/sys/plan9/asm.s
new file mode 100644
index 000000000..d4ca868f1
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/asm.s
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT ·use(SB),NOSPLIT,$0
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_dragonfly_386.s b/vendor/golang.org/x/sys/plan9/asm_plan9_386.s
index 7e55e0d31..bc5cab1f3 100644
--- a/vendor/golang.org/x/sys/unix/asm_dragonfly_386.s
+++ b/vendor/golang.org/x/sys/plan9/asm_plan9_386.s
@@ -2,12 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !gccgo
-
#include "textflag.h"
//
-// System call support for 386, FreeBSD
+// System call support for 386, Plan 9
//
// Just jump to package syscall's implementation for all these functions.
@@ -19,11 +17,14 @@ TEXT ·Syscall(SB),NOSPLIT,$0-32
TEXT ·Syscall6(SB),NOSPLIT,$0-44
JMP syscall·Syscall6(SB)
-TEXT ·Syscall9(SB),NOSPLIT,$0-56
- JMP syscall·Syscall9(SB)
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-44
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
+
+TEXT ·seek(SB),NOSPLIT,$0-36
+ JMP syscall·seek(SB)
+
+TEXT ·exit(SB),NOSPLIT,$4-4
+ JMP syscall·exit(SB)
diff --git a/vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s b/vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s
new file mode 100644
index 000000000..d3448e675
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/asm_plan9_amd64.s
@@ -0,0 +1,30 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+//
+// System call support for amd64, Plan 9
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-64
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-88
+ JMP syscall·Syscall6(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·seek(SB),NOSPLIT,$0-56
+ JMP syscall·seek(SB)
+
+TEXT ·exit(SB),NOSPLIT,$8-8
+ JMP syscall·exit(SB)
diff --git a/vendor/golang.org/x/sys/plan9/const_plan9.go b/vendor/golang.org/x/sys/plan9/const_plan9.go
new file mode 100644
index 000000000..b4e85a3a9
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/const_plan9.go
@@ -0,0 +1,70 @@
+package plan9
+
+// Plan 9 Constants
+
+// Open modes
+const (
+ O_RDONLY = 0
+ O_WRONLY = 1
+ O_RDWR = 2
+ O_TRUNC = 16
+ O_CLOEXEC = 32
+ O_EXCL = 0x1000
+)
+
+// Rfork flags
+const (
+ RFNAMEG = 1 << 0
+ RFENVG = 1 << 1
+ RFFDG = 1 << 2
+ RFNOTEG = 1 << 3
+ RFPROC = 1 << 4
+ RFMEM = 1 << 5
+ RFNOWAIT = 1 << 6
+ RFCNAMEG = 1 << 10
+ RFCENVG = 1 << 11
+ RFCFDG = 1 << 12
+ RFREND = 1 << 13
+ RFNOMNT = 1 << 14
+)
+
+// Qid.Type bits
+const (
+ QTDIR = 0x80
+ QTAPPEND = 0x40
+ QTEXCL = 0x20
+ QTMOUNT = 0x10
+ QTAUTH = 0x08
+ QTTMP = 0x04
+ QTFILE = 0x00
+)
+
+// Dir.Mode bits
+const (
+ DMDIR = 0x80000000
+ DMAPPEND = 0x40000000
+ DMEXCL = 0x20000000
+ DMMOUNT = 0x10000000
+ DMAUTH = 0x08000000
+ DMTMP = 0x04000000
+ DMREAD = 0x4
+ DMWRITE = 0x2
+ DMEXEC = 0x1
+)
+
+const (
+ STATMAX = 65535
+ ERRMAX = 128
+ STATFIXLEN = 49
+)
+
+// Mount and bind flags
+const (
+ MREPL = 0x0000
+ MBEFORE = 0x0001
+ MAFTER = 0x0002
+ MORDER = 0x0003
+ MCREATE = 0x0004
+ MCACHE = 0x0010
+ MMASK = 0x0017
+)
diff --git a/vendor/golang.org/x/sys/plan9/dir_plan9.go b/vendor/golang.org/x/sys/plan9/dir_plan9.go
new file mode 100644
index 000000000..0955e0c53
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/dir_plan9.go
@@ -0,0 +1,212 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Plan 9 directory marshalling. See intro(5).
+
+package plan9
+
+import "errors"
+
+var (
+ ErrShortStat = errors.New("stat buffer too short")
+ ErrBadStat = errors.New("malformed stat buffer")
+ ErrBadName = errors.New("bad character in file name")
+)
+
+// A Qid represents a 9P server's unique identification for a file.
+type Qid struct {
+ Path uint64 // the file server's unique identification for the file
+ Vers uint32 // version number for given Path
+ Type uint8 // the type of the file (plan9.QTDIR for example)
+}
+
+// A Dir contains the metadata for a file.
+type Dir struct {
+ // system-modified data
+ Type uint16 // server type
+ Dev uint32 // server subtype
+
+ // file data
+ Qid Qid // unique id from server
+ Mode uint32 // permissions
+ Atime uint32 // last read time
+ Mtime uint32 // last write time
+ Length int64 // file length
+ Name string // last element of path
+ Uid string // owner name
+ Gid string // group name
+ Muid string // last modifier name
+}
+
+var nullDir = Dir{
+ Type: ^uint16(0),
+ Dev: ^uint32(0),
+ Qid: Qid{
+ Path: ^uint64(0),
+ Vers: ^uint32(0),
+ Type: ^uint8(0),
+ },
+ Mode: ^uint32(0),
+ Atime: ^uint32(0),
+ Mtime: ^uint32(0),
+ Length: ^int64(0),
+}
+
+// Null assigns special "don't touch" values to members of d to
+// avoid modifying them during plan9.Wstat.
+func (d *Dir) Null() { *d = nullDir }
+
+// Marshal encodes a 9P stat message corresponding to d into b
+//
+// If there isn't enough space in b for a stat message, ErrShortStat is returned.
+func (d *Dir) Marshal(b []byte) (n int, err error) {
+ n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid)
+ if n > len(b) {
+ return n, ErrShortStat
+ }
+
+ for _, c := range d.Name {
+ if c == '/' {
+ return n, ErrBadName
+ }
+ }
+
+ b = pbit16(b, uint16(n)-2)
+ b = pbit16(b, d.Type)
+ b = pbit32(b, d.Dev)
+ b = pbit8(b, d.Qid.Type)
+ b = pbit32(b, d.Qid.Vers)
+ b = pbit64(b, d.Qid.Path)
+ b = pbit32(b, d.Mode)
+ b = pbit32(b, d.Atime)
+ b = pbit32(b, d.Mtime)
+ b = pbit64(b, uint64(d.Length))
+ b = pstring(b, d.Name)
+ b = pstring(b, d.Uid)
+ b = pstring(b, d.Gid)
+ b = pstring(b, d.Muid)
+
+ return n, nil
+}
+
+// UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir.
+//
+// If b is too small to hold a valid stat message, ErrShortStat is returned.
+//
+// If the stat message itself is invalid, ErrBadStat is returned.
+func UnmarshalDir(b []byte) (*Dir, error) {
+ if len(b) < STATFIXLEN {
+ return nil, ErrShortStat
+ }
+ size, buf := gbit16(b)
+ if len(b) != int(size)+2 {
+ return nil, ErrBadStat
+ }
+ b = buf
+
+ var d Dir
+ d.Type, b = gbit16(b)
+ d.Dev, b = gbit32(b)
+ d.Qid.Type, b = gbit8(b)
+ d.Qid.Vers, b = gbit32(b)
+ d.Qid.Path, b = gbit64(b)
+ d.Mode, b = gbit32(b)
+ d.Atime, b = gbit32(b)
+ d.Mtime, b = gbit32(b)
+
+ n, b := gbit64(b)
+ d.Length = int64(n)
+
+ var ok bool
+ if d.Name, b, ok = gstring(b); !ok {
+ return nil, ErrBadStat
+ }
+ if d.Uid, b, ok = gstring(b); !ok {
+ return nil, ErrBadStat
+ }
+ if d.Gid, b, ok = gstring(b); !ok {
+ return nil, ErrBadStat
+ }
+ if d.Muid, b, ok = gstring(b); !ok {
+ return nil, ErrBadStat
+ }
+
+ return &d, nil
+}
+
+// pbit8 copies the 8-bit number v to b and returns the remaining slice of b.
+func pbit8(b []byte, v uint8) []byte {
+ b[0] = byte(v)
+ return b[1:]
+}
+
+// pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b.
+func pbit16(b []byte, v uint16) []byte {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ return b[2:]
+}
+
+// pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b.
+func pbit32(b []byte, v uint32) []byte {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ return b[4:]
+}
+
+// pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b.
+func pbit64(b []byte, v uint64) []byte {
+ b[0] = byte(v)
+ b[1] = byte(v >> 8)
+ b[2] = byte(v >> 16)
+ b[3] = byte(v >> 24)
+ b[4] = byte(v >> 32)
+ b[5] = byte(v >> 40)
+ b[6] = byte(v >> 48)
+ b[7] = byte(v >> 56)
+ return b[8:]
+}
+
+// pstring copies the string s to b, prepending it with a 16-bit length in little-endian order, and
+// returning the remaining slice of b..
+func pstring(b []byte, s string) []byte {
+ b = pbit16(b, uint16(len(s)))
+ n := copy(b, s)
+ return b[n:]
+}
+
+// gbit8 reads an 8-bit number from b and returns it with the remaining slice of b.
+func gbit8(b []byte) (uint8, []byte) {
+ return uint8(b[0]), b[1:]
+}
+
+// gbit16 reads a 16-bit number in little-endian order from b and returns it with the remaining slice of b.
+func gbit16(b []byte) (uint16, []byte) {
+ return uint16(b[0]) | uint16(b[1])<<8, b[2:]
+}
+
+// gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b.
+func gbit32(b []byte) (uint32, []byte) {
+ return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:]
+}
+
+// gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b.
+func gbit64(b []byte) (uint64, []byte) {
+ lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+ hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24
+ return uint64(lo) | uint64(hi)<<32, b[8:]
+}
+
+// gstring reads a string from b, prefixed with a 16-bit length in little-endian order.
+// It returns the string with the remaining slice of b and a boolean. If the length is
+// greater than the number of bytes in b, the boolean will be false.
+func gstring(b []byte) (string, []byte, bool) {
+ n, b := gbit16(b)
+ if int(n) > len(b) {
+ return "", b, false
+ }
+ return string(b[:n]), b[n:], true
+}
diff --git a/vendor/golang.org/x/sys/plan9/env_plan9.go b/vendor/golang.org/x/sys/plan9/env_plan9.go
new file mode 100644
index 000000000..25a96e7ea
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/env_plan9.go
@@ -0,0 +1,27 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Plan 9 environment variables.
+
+package plan9
+
+import (
+ "syscall"
+)
+
+func Getenv(key string) (value string, found bool) {
+ return syscall.Getenv(key)
+}
+
+func Setenv(key, value string) error {
+ return syscall.Setenv(key, value)
+}
+
+func Clearenv() {
+ syscall.Clearenv()
+}
+
+func Environ() []string {
+ return syscall.Environ()
+}
diff --git a/vendor/golang.org/x/sys/plan9/env_unset.go b/vendor/golang.org/x/sys/plan9/env_unset.go
new file mode 100644
index 000000000..c37fc26e4
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/env_unset.go
@@ -0,0 +1,14 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.4
+
+package plan9
+
+import "syscall"
+
+func Unsetenv(key string) error {
+ // This was added in Go 1.4.
+ return syscall.Unsetenv(key)
+}
diff --git a/vendor/golang.org/x/sys/plan9/errors_plan9.go b/vendor/golang.org/x/sys/plan9/errors_plan9.go
new file mode 100644
index 000000000..110cf6a30
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/errors_plan9.go
@@ -0,0 +1,50 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package plan9
+
+import "syscall"
+
+// Constants
+const (
+ // Invented values to support what package os expects.
+ O_CREAT = 0x02000
+ O_APPEND = 0x00400
+ O_NOCTTY = 0x00000
+ O_NONBLOCK = 0x00000
+ O_SYNC = 0x00000
+ O_ASYNC = 0x00000
+
+ S_IFMT = 0x1f000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+)
+
+// Errors
+var (
+ EINVAL = syscall.NewError("bad arg in system call")
+ ENOTDIR = syscall.NewError("not a directory")
+ EISDIR = syscall.NewError("file is a directory")
+ ENOENT = syscall.NewError("file does not exist")
+ EEXIST = syscall.NewError("file already exists")
+ EMFILE = syscall.NewError("no free file descriptors")
+ EIO = syscall.NewError("i/o error")
+ ENAMETOOLONG = syscall.NewError("file name too long")
+ EINTR = syscall.NewError("interrupted")
+ EPERM = syscall.NewError("permission denied")
+ EBUSY = syscall.NewError("no free devices")
+ ETIMEDOUT = syscall.NewError("connection timed out")
+ EPLAN9 = syscall.NewError("not supported by plan 9")
+
+ // The following errors do not correspond to any
+ // Plan 9 system messages. Invented to support
+ // what package os and others expect.
+ EACCES = syscall.NewError("access permission denied")
+ EAFNOSUPPORT = syscall.NewError("address family not supported by protocol")
+)
diff --git a/vendor/golang.org/x/sys/plan9/mkall.sh b/vendor/golang.org/x/sys/plan9/mkall.sh
new file mode 100755
index 000000000..9f73c6066
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/mkall.sh
@@ -0,0 +1,138 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# The plan9 package provides access to the raw system call
+# interface of the underlying operating system. Porting Go to
+# a new architecture/operating system combination requires
+# some manual effort, though there are tools that automate
+# much of the process. The auto-generated files have names
+# beginning with z.
+#
+# This script runs or (given -n) prints suggested commands to generate z files
+# for the current system. Running those commands is not automatic.
+# This script is documentation more than anything else.
+#
+# * asm_${GOOS}_${GOARCH}.s
+#
+# This hand-written assembly file implements system call dispatch.
+# There are three entry points:
+#
+# func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
+# func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
+# func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr);
+#
+# The first and second are the standard ones; they differ only in
+# how many arguments can be passed to the kernel.
+# The third is for low-level use by the ForkExec wrapper;
+# unlike the first two, it does not call into the scheduler to
+# let it know that a system call is running.
+#
+# * syscall_${GOOS}.go
+#
+# This hand-written Go file implements system calls that need
+# special handling and lists "//sys" comments giving prototypes
+# for ones that can be auto-generated. Mksyscall reads those
+# comments to generate the stubs.
+#
+# * syscall_${GOOS}_${GOARCH}.go
+#
+# Same as syscall_${GOOS}.go except that it contains code specific
+# to ${GOOS} on one particular architecture.
+#
+# * types_${GOOS}.c
+#
+# This hand-written C file includes standard C headers and then
+# creates typedef or enum names beginning with a dollar sign
+# (use of $ in variable names is a gcc extension). The hardest
+# part about preparing this file is figuring out which headers to
+# include and which symbols need to be #defined to get the
+# actual data structures that pass through to the kernel system calls.
+# Some C libraries present alternate versions for binary compatibility
+# and translate them on the way in and out of system calls, but
+# there is almost always a #define that can get the real ones.
+# See types_darwin.c and types_linux.c for examples.
+#
+# * zerror_${GOOS}_${GOARCH}.go
+#
+# This machine-generated file defines the system's error numbers,
+# error strings, and signal numbers. The generator is "mkerrors.sh".
+# Usually no arguments are needed, but mkerrors.sh will pass its
+# arguments on to godefs.
+#
+# * zsyscall_${GOOS}_${GOARCH}.go
+#
+# Generated by mksyscall.pl; see syscall_${GOOS}.go above.
+#
+# * zsysnum_${GOOS}_${GOARCH}.go
+#
+# Generated by mksysnum_${GOOS}.
+#
+# * ztypes_${GOOS}_${GOARCH}.go
+#
+# Generated by godefs; see types_${GOOS}.c above.
+
+GOOSARCH="${GOOS}_${GOARCH}"
+
+# defaults
+mksyscall="./mksyscall.pl"
+mkerrors="./mkerrors.sh"
+zerrors="zerrors_$GOOSARCH.go"
+mksysctl=""
+zsysctl="zsysctl_$GOOSARCH.go"
+mksysnum=
+mktypes=
+run="sh"
+
+case "$1" in
+-syscalls)
+ for i in zsyscall*go
+ do
+ sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
+ rm _$i
+ done
+ exit 0
+ ;;
+-n)
+ run="cat"
+ shift
+esac
+
+case "$#" in
+0)
+ ;;
+*)
+ echo 'usage: mkall.sh [-n]' 1>&2
+ exit 2
+esac
+
+case "$GOOSARCH" in
+_* | *_ | _)
+ echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+plan9_386)
+ mkerrors=
+ mksyscall="./mksyscall.pl -l32 -plan9"
+ mksysnum="./mksysnum_plan9.sh /n/sources/plan9/sys/src/libc/9syscall/sys.h"
+ mktypes="XXX"
+ ;;
+*)
+ echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
+ exit 1
+ ;;
+esac
+
+(
+ if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
+ case "$GOOS" in
+ plan9)
+ syscall_goos="syscall_$GOOS.go"
+ if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
+ ;;
+ esac
+ if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
+ if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
+ if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
+) | $run
diff --git a/vendor/golang.org/x/sys/plan9/mkerrors.sh b/vendor/golang.org/x/sys/plan9/mkerrors.sh
new file mode 100755
index 000000000..052c86d94
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/mkerrors.sh
@@ -0,0 +1,246 @@
+#!/usr/bin/env bash
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Generate Go code listing errors and other #defined constant
+# values (ENAMETOOLONG etc.), by asking the preprocessor
+# about the definitions.
+
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+CC=${CC:-gcc}
+
+uname=$(uname)
+
+includes='
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <errno.h>
+#include <sys/signal.h>
+#include <signal.h>
+#include <sys/resource.h>
+'
+
+ccflags="$@"
+
+# Write go tool cgo -godefs input.
+(
+ echo package plan9
+ echo
+ echo '/*'
+ indirect="includes_$(uname)"
+ echo "${!indirect} $includes"
+ echo '*/'
+ echo 'import "C"'
+ echo
+ echo 'const ('
+
+ # The gcc command line prints all the #defines
+ # it encounters while processing the input
+ echo "${!indirect} $includes" | $CC -x c - -E -dM $ccflags |
+ awk '
+ $1 != "#define" || $2 ~ /\(/ || $3 == "" {next}
+
+ $2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers
+ $2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
+ $2 ~ /^(SCM_SRCRT)$/ {next}
+ $2 ~ /^(MAP_FAILED)$/ {next}
+
+ $2 !~ /^ETH_/ &&
+ $2 !~ /^EPROC_/ &&
+ $2 !~ /^EQUIV_/ &&
+ $2 !~ /^EXPR_/ &&
+ $2 ~ /^E[A-Z0-9_]+$/ ||
+ $2 ~ /^B[0-9_]+$/ ||
+ $2 ~ /^V[A-Z0-9]+$/ ||
+ $2 ~ /^CS[A-Z0-9]/ ||
+ $2 ~ /^I(SIG|CANON|CRNL|EXTEN|MAXBEL|STRIP|UTF8)$/ ||
+ $2 ~ /^IGN/ ||
+ $2 ~ /^IX(ON|ANY|OFF)$/ ||
+ $2 ~ /^IN(LCR|PCK)$/ ||
+ $2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
+ $2 ~ /^C(LOCAL|READ)$/ ||
+ $2 == "BRKINT" ||
+ $2 == "HUPCL" ||
+ $2 == "PENDIN" ||
+ $2 == "TOSTOP" ||
+ $2 ~ /^PAR/ ||
+ $2 ~ /^SIG[^_]/ ||
+ $2 ~ /^O[CNPFP][A-Z]+[^_][A-Z]+$/ ||
+ $2 ~ /^IN_/ ||
+ $2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
+ $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
+ $2 == "ICMPV6_FILTER" ||
+ $2 == "SOMAXCONN" ||
+ $2 == "NAME_MAX" ||
+ $2 == "IFNAMSIZ" ||
+ $2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ ||
+ $2 ~ /^SYSCTL_VERS/ ||
+ $2 ~ /^(MS|MNT)_/ ||
+ $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
+ $2 ~ /^(O|F|FD|NAME|S|PTRACE|PT)_/ ||
+ $2 ~ /^LINUX_REBOOT_CMD_/ ||
+ $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
+ $2 !~ "NLA_TYPE_MASK" &&
+ $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
+ $2 ~ /^SIOC/ ||
+ $2 ~ /^TIOC/ ||
+ $2 !~ "RTF_BITS" &&
+ $2 ~ /^(IFF|IFT|NET_RT|RTM|RTF|RTV|RTA|RTAX)_/ ||
+ $2 ~ /^BIOC/ ||
+ $2 ~ /^RUSAGE_(SELF|CHILDREN|THREAD)/ ||
+ $2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|NOFILE|STACK)|RLIM_INFINITY/ ||
+ $2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
+ $2 ~ /^CLONE_[A-Z_]+/ ||
+ $2 !~ /^(BPF_TIMEVAL)$/ &&
+ $2 ~ /^(BPF|DLT)_/ ||
+ $2 !~ "WMESGLEN" &&
+ $2 ~ /^W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", $2, $2)}
+ $2 ~ /^__WCOREFLAG$/ {next}
+ $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
+
+ {next}
+ ' | sort
+
+ echo ')'
+) >_const.go
+
+# Pull out the error names for later.
+errors=$(
+ echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print $2 }' |
+ sort
+)
+
+# Pull out the signal names for later.
+signals=$(
+ echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
+ egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
+ sort
+)
+
+# Again, writing regexps to a file.
+echo '#include <errno.h>' | $CC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^E[A-Z0-9_]+$/ { print "^\t" $2 "[ \t]*=" }' |
+ sort >_error.grep
+echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
+ awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
+ egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
+ sort >_signal.grep
+
+echo '// mkerrors.sh' "$@"
+echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
+echo
+go tool cgo -godefs -- "$@" _const.go >_error.out
+cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
+echo
+echo '// Errors'
+echo 'const ('
+cat _error.out | grep -f _error.grep | sed 's/=\(.*\)/= Errno(\1)/'
+echo ')'
+
+echo
+echo '// Signals'
+echo 'const ('
+cat _error.out | grep -f _signal.grep | sed 's/=\(.*\)/= Signal(\1)/'
+echo ')'
+
+# Run C program to print error and syscall strings.
+(
+ echo -E "
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <signal.h>
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
+
+int errors[] = {
+"
+ for i in $errors
+ do
+ echo -E ' '$i,
+ done
+
+ echo -E "
+};
+
+int signals[] = {
+"
+ for i in $signals
+ do
+ echo -E ' '$i,
+ done
+
+ # Use -E because on some systems bash builtin interprets \n itself.
+ echo -E '
+};
+
+static int
+intcmp(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
+int
+main(void)
+{
+ int i, j, e;
+ char buf[1024], *p;
+
+ printf("\n\n// Error table\n");
+ printf("var errors = [...]string {\n");
+ qsort(errors, nelem(errors), sizeof errors[0], intcmp);
+ for(i=0; i<nelem(errors); i++) {
+ e = errors[i];
+ if(i > 0 && errors[i-1] == e)
+ continue;
+ strcpy(buf, strerror(e));
+ // lowercase first letter: Bad -> bad, but STREAM -> STREAM.
+ if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
+ buf[0] += a - A;
+ printf("\t%d: \"%s\",\n", e, buf);
+ }
+ printf("}\n\n");
+
+ printf("\n\n// Signal table\n");
+ printf("var signals = [...]string {\n");
+ qsort(signals, nelem(signals), sizeof signals[0], intcmp);
+ for(i=0; i<nelem(signals); i++) {
+ e = signals[i];
+ if(i > 0 && signals[i-1] == e)
+ continue;
+ strcpy(buf, strsignal(e));
+ // lowercase first letter: Bad -> bad, but STREAM -> STREAM.
+ if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
+ buf[0] += a - A;
+ // cut trailing : number.
+ p = strrchr(buf, ":"[0]);
+ if(p)
+ *p = '\0';
+ printf("\t%d: \"%s\",\n", e, buf);
+ }
+ printf("}\n\n");
+
+ return 0;
+}
+
+'
+) >_errors.c
+
+$CC $ccflags -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors _const.go _error.grep _signal.grep _error.out
diff --git a/vendor/golang.org/x/sys/plan9/mksyscall.pl b/vendor/golang.org/x/sys/plan9/mksyscall.pl
new file mode 100755
index 000000000..ce8e1e4f3
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/mksyscall.pl
@@ -0,0 +1,319 @@
+#!/usr/bin/env perl
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This program reads a file containing function prototypes
+# (like syscall_plan9.go) and generates system call bodies.
+# The prototypes are marked by lines beginning with "//sys"
+# and read like func declarations if //sys is replaced by func, but:
+# * The parameter lists must give a name for each argument.
+# This includes return parameters.
+# * The parameter lists must give a type for each argument:
+# the (x, y, z int) shorthand is not allowed.
+# * If the return parameter is an error number, it must be named errno.
+
+# A line beginning with //sysnb is like //sys, except that the
+# goroutine will not be suspended during the execution of the system
+# call. This must only be used for system calls which can never
+# block, as otherwise the system call could cause all goroutines to
+# hang.
+
+use strict;
+
+my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
+my $errors = 0;
+my $_32bit = "";
+my $plan9 = 0;
+my $openbsd = 0;
+my $netbsd = 0;
+my $dragonfly = 0;
+my $nacl = 0;
+my $arm = 0; # 64-bit value should use (even, odd)-pair
+
+if($ARGV[0] eq "-b32") {
+ $_32bit = "big-endian";
+ shift;
+} elsif($ARGV[0] eq "-l32") {
+ $_32bit = "little-endian";
+ shift;
+}
+if($ARGV[0] eq "-plan9") {
+ $plan9 = 1;
+ shift;
+}
+if($ARGV[0] eq "-openbsd") {
+ $openbsd = 1;
+ shift;
+}
+if($ARGV[0] eq "-netbsd") {
+ $netbsd = 1;
+ shift;
+}
+if($ARGV[0] eq "-dragonfly") {
+ $dragonfly = 1;
+ shift;
+}
+if($ARGV[0] eq "-nacl") {
+ $nacl = 1;
+ shift;
+}
+if($ARGV[0] eq "-arm") {
+ $arm = 1;
+ shift;
+}
+
+if($ARGV[0] =~ /^-/) {
+ print STDERR "usage: mksyscall.pl [-b32 | -l32] [file ...]\n";
+ exit 1;
+}
+
+sub parseparamlist($) {
+ my ($list) = @_;
+ $list =~ s/^\s*//;
+ $list =~ s/\s*$//;
+ if($list eq "") {
+ return ();
+ }
+ return split(/\s*,\s*/, $list);
+}
+
+sub parseparam($) {
+ my ($p) = @_;
+ if($p !~ /^(\S*) (\S*)$/) {
+ print STDERR "$ARGV:$.: malformed parameter: $p\n";
+ $errors = 1;
+ return ("xx", "int");
+ }
+ return ($1, $2);
+}
+
+my $text = "";
+while(<>) {
+ chomp;
+ s/\s+/ /g;
+ s/^\s+//;
+ s/\s+$//;
+ my $nonblock = /^\/\/sysnb /;
+ next if !/^\/\/sys / && !$nonblock;
+
+ # Line must be of the form
+ # func Open(path string, mode int, perm int) (fd int, errno error)
+ # Split into name, in params, out params.
+ if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
+ print STDERR "$ARGV:$.: malformed //sys declaration\n";
+ $errors = 1;
+ next;
+ }
+ my ($func, $in, $out, $sysname) = ($2, $3, $4, $5);
+
+ # Split argument lists on comma.
+ my @in = parseparamlist($in);
+ my @out = parseparamlist($out);
+
+ # Try in vain to keep people from editing this file.
+ # The theory is that they jump into the middle of the file
+ # without reading the header.
+ $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
+
+ # Go function header.
+ my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
+ $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
+
+ # Check if err return available
+ my $errvar = "";
+ foreach my $p (@out) {
+ my ($name, $type) = parseparam($p);
+ if($type eq "error") {
+ $errvar = $name;
+ last;
+ }
+ }
+
+ # Prepare arguments to Syscall.
+ my @args = ();
+ my @uses = ();
+ my $n = 0;
+ foreach my $p (@in) {
+ my ($name, $type) = parseparam($p);
+ if($type =~ /^\*/) {
+ push @args, "uintptr(unsafe.Pointer($name))";
+ } elsif($type eq "string" && $errvar ne "") {
+ $text .= "\tvar _p$n *byte\n";
+ $text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
+ $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
+ push @args, "uintptr(unsafe.Pointer(_p$n))";
+ push @uses, "use(unsafe.Pointer(_p$n))";
+ $n++;
+ } elsif($type eq "string") {
+ print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
+ $text .= "\tvar _p$n *byte\n";
+ $text .= "\t_p$n, _ = BytePtrFromString($name)\n";
+ push @args, "uintptr(unsafe.Pointer(_p$n))";
+ push @uses, "use(unsafe.Pointer(_p$n))";
+ $n++;
+ } elsif($type =~ /^\[\](.*)/) {
+ # Convert slice into pointer, length.
+ # Have to be careful not to take address of &a[0] if len == 0:
+ # pass dummy pointer in that case.
+ # Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
+ $text .= "\tvar _p$n unsafe.Pointer\n";
+ $text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
+ $text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}";
+ $text .= "\n";
+ push @args, "uintptr(_p$n)", "uintptr(len($name))";
+ $n++;
+ } elsif($type eq "int64" && ($openbsd || $netbsd)) {
+ push @args, "0";
+ if($_32bit eq "big-endian") {
+ push @args, "uintptr($name>>32)", "uintptr($name)";
+ } elsif($_32bit eq "little-endian") {
+ push @args, "uintptr($name)", "uintptr($name>>32)";
+ } else {
+ push @args, "uintptr($name)";
+ }
+ } elsif($type eq "int64" && $dragonfly) {
+ if ($func !~ /^extp(read|write)/i) {
+ push @args, "0";
+ }
+ if($_32bit eq "big-endian") {
+ push @args, "uintptr($name>>32)", "uintptr($name)";
+ } elsif($_32bit eq "little-endian") {
+ push @args, "uintptr($name)", "uintptr($name>>32)";
+ } else {
+ push @args, "uintptr($name)";
+ }
+ } elsif($type eq "int64" && $_32bit ne "") {
+ if(@args % 2 && $arm) {
+ # arm abi specifies 64-bit argument uses
+ # (even, odd) pair
+ push @args, "0"
+ }
+ if($_32bit eq "big-endian") {
+ push @args, "uintptr($name>>32)", "uintptr($name)";
+ } else {
+ push @args, "uintptr($name)", "uintptr($name>>32)";
+ }
+ } else {
+ push @args, "uintptr($name)";
+ }
+ }
+
+ # Determine which form to use; pad args with zeros.
+ my $asm = "Syscall";
+ if ($nonblock) {
+ $asm = "RawSyscall";
+ }
+ if(@args <= 3) {
+ while(@args < 3) {
+ push @args, "0";
+ }
+ } elsif(@args <= 6) {
+ $asm .= "6";
+ while(@args < 6) {
+ push @args, "0";
+ }
+ } elsif(@args <= 9) {
+ $asm .= "9";
+ while(@args < 9) {
+ push @args, "0";
+ }
+ } else {
+ print STDERR "$ARGV:$.: too many arguments to system call\n";
+ }
+
+ # System call number.
+ if($sysname eq "") {
+ $sysname = "SYS_$func";
+ $sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
+ $sysname =~ y/a-z/A-Z/;
+ if($nacl) {
+ $sysname =~ y/A-Z/a-z/;
+ }
+ }
+
+ # Actual call.
+ my $args = join(', ', @args);
+ my $call = "$asm($sysname, $args)";
+
+ # Assign return values.
+ my $body = "";
+ my @ret = ("_", "_", "_");
+ my $do_errno = 0;
+ for(my $i=0; $i<@out; $i++) {
+ my $p = $out[$i];
+ my ($name, $type) = parseparam($p);
+ my $reg = "";
+ if($name eq "err" && !$plan9) {
+ $reg = "e1";
+ $ret[2] = $reg;
+ $do_errno = 1;
+ } elsif($name eq "err" && $plan9) {
+ $ret[0] = "r0";
+ $ret[2] = "e1";
+ next;
+ } else {
+ $reg = sprintf("r%d", $i);
+ $ret[$i] = $reg;
+ }
+ if($type eq "bool") {
+ $reg = "$reg != 0";
+ }
+ if($type eq "int64" && $_32bit ne "") {
+ # 64-bit number in r1:r0 or r0:r1.
+ if($i+2 > @out) {
+ print STDERR "$ARGV:$.: not enough registers for int64 return\n";
+ }
+ if($_32bit eq "big-endian") {
+ $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
+ } else {
+ $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
+ }
+ $ret[$i] = sprintf("r%d", $i);
+ $ret[$i+1] = sprintf("r%d", $i+1);
+ }
+ if($reg ne "e1" || $plan9) {
+ $body .= "\t$name = $type($reg)\n";
+ }
+ }
+ if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
+ $text .= "\t$call\n";
+ } else {
+ $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
+ }
+ foreach my $use (@uses) {
+ $text .= "\t$use\n";
+ }
+ $text .= $body;
+
+ if ($plan9 && $ret[2] eq "e1") {
+ $text .= "\tif int32(r0) == -1 {\n";
+ $text .= "\t\terr = e1\n";
+ $text .= "\t}\n";
+ } elsif ($do_errno) {
+ $text .= "\tif e1 != 0 {\n";
+ $text .= "\t\terr = e1\n";
+ $text .= "\t}\n";
+ }
+ $text .= "\treturn\n";
+ $text .= "}\n\n";
+}
+
+chomp $text;
+chomp $text;
+
+if($errors) {
+ exit 1;
+}
+
+print <<EOF;
+// $cmdline
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package plan9
+
+import "unsafe"
+
+$text
+EOF
+exit 0;
diff --git a/vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh b/vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh
new file mode 100755
index 000000000..3c3ab0581
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/mksysnum_plan9.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+COMMAND="mksysnum_plan9.sh $@"
+
+cat <<EOF
+// $COMMAND
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package plan9
+
+const(
+EOF
+
+SP='[ ]' # space or tab
+sed "s/^#define${SP}\\([A-Z0-9_][A-Z0-9_]*\\)${SP}${SP}*\\([0-9][0-9]*\\)/SYS_\\1=\\2/g" \
+ < $1 | grep -v SYS__
+
+cat <<EOF
+)
+EOF
diff --git a/vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go b/vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go
new file mode 100644
index 000000000..87ae9d2a3
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/pwd_go15_plan9.go
@@ -0,0 +1,21 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build go1.5
+
+package plan9
+
+import "syscall"
+
+func fixwd() {
+ syscall.Fixwd()
+}
+
+func Getwd() (wd string, err error) {
+ return syscall.Getwd()
+}
+
+func Chdir(path string) error {
+ return syscall.Chdir(path)
+}
diff --git a/vendor/golang.org/x/sys/plan9/pwd_plan9.go b/vendor/golang.org/x/sys/plan9/pwd_plan9.go
new file mode 100644
index 000000000..c07c798bc
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/pwd_plan9.go
@@ -0,0 +1,23 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !go1.5
+
+package plan9
+
+func fixwd() {
+}
+
+func Getwd() (wd string, err error) {
+ fd, err := open(".", O_RDONLY)
+ if err != nil {
+ return "", err
+ }
+ defer Close(fd)
+ return Fd2path(fd)
+}
+
+func Chdir(path string) error {
+ return chdir(path)
+}
diff --git a/vendor/golang.org/x/sys/plan9/race.go b/vendor/golang.org/x/sys/plan9/race.go
new file mode 100644
index 000000000..c7ff5df2e
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/race.go
@@ -0,0 +1,30 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9,race
+
+package plan9
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+const raceenabled = true
+
+func raceAcquire(addr unsafe.Pointer) {
+ runtime.RaceAcquire(addr)
+}
+
+func raceReleaseMerge(addr unsafe.Pointer) {
+ runtime.RaceReleaseMerge(addr)
+}
+
+func raceReadRange(addr unsafe.Pointer, len int) {
+ runtime.RaceReadRange(addr, len)
+}
+
+func raceWriteRange(addr unsafe.Pointer, len int) {
+ runtime.RaceWriteRange(addr, len)
+}
diff --git a/vendor/golang.org/x/sys/plan9/race0.go b/vendor/golang.org/x/sys/plan9/race0.go
new file mode 100644
index 000000000..06cabcc76
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/race0.go
@@ -0,0 +1,25 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9,!race
+
+package plan9
+
+import (
+ "unsafe"
+)
+
+const raceenabled = false
+
+func raceAcquire(addr unsafe.Pointer) {
+}
+
+func raceReleaseMerge(addr unsafe.Pointer) {
+}
+
+func raceReadRange(addr unsafe.Pointer, len int) {
+}
+
+func raceWriteRange(addr unsafe.Pointer, len int) {
+}
diff --git a/vendor/golang.org/x/sys/plan9/str.go b/vendor/golang.org/x/sys/plan9/str.go
new file mode 100644
index 000000000..4f7f9ad7c
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/str.go
@@ -0,0 +1,22 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9
+
+package plan9
+
+func itoa(val int) string { // do it here rather than with fmt to avoid dependency
+ if val < 0 {
+ return "-" + itoa(-val)
+ }
+ var buf [32]byte // big enough for int64
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return string(buf[i:])
+}
diff --git a/vendor/golang.org/x/sys/plan9/syscall.go b/vendor/golang.org/x/sys/plan9/syscall.go
new file mode 100644
index 000000000..df6f8c5b9
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/syscall.go
@@ -0,0 +1,74 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9
+
+// Package plan9 contains an interface to the low-level operating system
+// primitives. OS details vary depending on the underlying system, and
+// by default, godoc will display the OS-specific documentation for the current
+// system. If you want godoc to display documentation for another
+// system, set $GOOS and $GOARCH to the desired system. For example, if
+// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
+// to freebsd and $GOARCH to arm.
+// The primary use of this package is inside other packages that provide a more
+// portable interface to the system, such as "os", "time" and "net". Use
+// those packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+// These calls return err == nil to indicate success; otherwise
+// err represents an operating system error describing the failure and
+// holds a value of type syscall.ErrorString.
+package plan9 // import "golang.org/x/sys/plan9"
+
+import "unsafe"
+
+// ByteSliceFromString returns a NUL-terminated slice of bytes
+// containing the text of s. If s contains a NUL byte at any
+// location, it returns (nil, EINVAL).
+func ByteSliceFromString(s string) ([]byte, error) {
+ for i := 0; i < len(s); i++ {
+ if s[i] == 0 {
+ return nil, EINVAL
+ }
+ }
+ a := make([]byte, len(s)+1)
+ copy(a, s)
+ return a, nil
+}
+
+// BytePtrFromString returns a pointer to a NUL-terminated array of
+// bytes containing the text of s. If s contains a NUL byte at any
+// location, it returns (nil, EINVAL).
+func BytePtrFromString(s string) (*byte, error) {
+ a, err := ByteSliceFromString(s)
+ if err != nil {
+ return nil, err
+ }
+ return &a[0], nil
+}
+
+// Single-word zero for use when we need a valid pointer to 0 bytes.
+// See mksyscall.pl.
+var _zero uintptr
+
+func (ts *Timespec) Unix() (sec int64, nsec int64) {
+ return int64(ts.Sec), int64(ts.Nsec)
+}
+
+func (tv *Timeval) Unix() (sec int64, nsec int64) {
+ return int64(tv.Sec), int64(tv.Usec) * 1000
+}
+
+func (ts *Timespec) Nano() int64 {
+ return int64(ts.Sec)*1e9 + int64(ts.Nsec)
+}
+
+func (tv *Timeval) Nano() int64 {
+ return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
+}
+
+// use is a no-op, but the compiler cannot see that it is.
+// Calling use(p) ensures that p is kept live until that point.
+//go:noescape
+func use(p unsafe.Pointer)
diff --git a/vendor/golang.org/x/sys/plan9/syscall_plan9.go b/vendor/golang.org/x/sys/plan9/syscall_plan9.go
new file mode 100644
index 000000000..d39d07de1
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/syscall_plan9.go
@@ -0,0 +1,349 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Plan 9 system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and
+// wrap it in our own nicer implementation.
+
+package plan9
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+// A Note is a string describing a process note.
+// It implements the os.Signal interface.
+type Note string
+
+func (n Note) Signal() {}
+
+func (n Note) String() string {
+ return string(n)
+}
+
+var (
+ Stdin = 0
+ Stdout = 1
+ Stderr = 2
+)
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+
+func atoi(b []byte) (n uint) {
+ n = 0
+ for i := 0; i < len(b); i++ {
+ n = n*10 + uint(b[i]-'0')
+ }
+ return
+}
+
+func cstring(s []byte) string {
+ for i := range s {
+ if s[i] == 0 {
+ return string(s[0:i])
+ }
+ }
+ return string(s)
+}
+
+func errstr() string {
+ var buf [ERRMAX]byte
+
+ RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
+
+ buf[len(buf)-1] = 0
+ return cstring(buf[:])
+}
+
+// Implemented in assembly to import from runtime.
+func exit(code int)
+
+func Exit(code int) { exit(code) }
+
+func readnum(path string) (uint, error) {
+ var b [12]byte
+
+ fd, e := Open(path, O_RDONLY)
+ if e != nil {
+ return 0, e
+ }
+ defer Close(fd)
+
+ n, e := Pread(fd, b[:], 0)
+
+ if e != nil {
+ return 0, e
+ }
+
+ m := 0
+ for ; m < n && b[m] == ' '; m++ {
+ }
+
+ return atoi(b[m : n-1]), nil
+}
+
+func Getpid() (pid int) {
+ n, _ := readnum("#c/pid")
+ return int(n)
+}
+
+func Getppid() (ppid int) {
+ n, _ := readnum("#c/ppid")
+ return int(n)
+}
+
+func Read(fd int, p []byte) (n int, err error) {
+ return Pread(fd, p, -1)
+}
+
+func Write(fd int, p []byte) (n int, err error) {
+ return Pwrite(fd, p, -1)
+}
+
+var ioSync int64
+
+//sys fd2path(fd int, buf []byte) (err error)
+func Fd2path(fd int) (path string, err error) {
+ var buf [512]byte
+
+ e := fd2path(fd, buf[:])
+ if e != nil {
+ return "", e
+ }
+ return cstring(buf[:]), nil
+}
+
+//sys pipe(p *[2]int32) (err error)
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return syscall.ErrorString("bad arg in system call")
+ }
+ var pp [2]int32
+ err = pipe(&pp)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+ newoffset, e := seek(0, fd, offset, whence)
+
+ if newoffset == -1 {
+ err = syscall.ErrorString(e)
+ }
+ return
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+ fd, err := Create(path, O_RDONLY, DMDIR|mode)
+
+ if fd != -1 {
+ Close(fd)
+ }
+
+ return
+}
+
+type Waitmsg struct {
+ Pid int
+ Time [3]uint32
+ Msg string
+}
+
+func (w Waitmsg) Exited() bool { return true }
+func (w Waitmsg) Signaled() bool { return false }
+
+func (w Waitmsg) ExitStatus() int {
+ if len(w.Msg) == 0 {
+ // a normal exit returns no message
+ return 0
+ }
+ return 1
+}
+
+//sys await(s []byte) (n int, err error)
+func Await(w *Waitmsg) (err error) {
+ var buf [512]byte
+ var f [5][]byte
+
+ n, err := await(buf[:])
+
+ if err != nil || w == nil {
+ return
+ }
+
+ nf := 0
+ p := 0
+ for i := 0; i < n && nf < len(f)-1; i++ {
+ if buf[i] == ' ' {
+ f[nf] = buf[p:i]
+ p = i + 1
+ nf++
+ }
+ }
+ f[nf] = buf[p:]
+ nf++
+
+ if nf != len(f) {
+ return syscall.ErrorString("invalid wait message")
+ }
+ w.Pid = int(atoi(f[0]))
+ w.Time[0] = uint32(atoi(f[1]))
+ w.Time[1] = uint32(atoi(f[2]))
+ w.Time[2] = uint32(atoi(f[3]))
+ w.Msg = cstring(f[4])
+ if w.Msg == "''" {
+ // await() returns '' for no error
+ w.Msg = ""
+ }
+ return
+}
+
+func Unmount(name, old string) (err error) {
+ fixwd()
+ oldp, err := BytePtrFromString(old)
+ if err != nil {
+ return err
+ }
+ oldptr := uintptr(unsafe.Pointer(oldp))
+
+ var r0 uintptr
+ var e syscall.ErrorString
+
+ // bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
+ if name == "" {
+ r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
+ } else {
+ namep, err := BytePtrFromString(name)
+ if err != nil {
+ return err
+ }
+ r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
+ }
+
+ if int32(r0) == -1 {
+ err = e
+ }
+ return
+}
+
+func Fchdir(fd int) (err error) {
+ path, err := Fd2path(fd)
+
+ if err != nil {
+ return
+ }
+
+ return Chdir(path)
+}
+
+type Timespec struct {
+ Sec int32
+ Nsec int32
+}
+
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ nsec += 999 // round up to microsecond
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ tv.Sec = int32(nsec / 1e9)
+ return
+}
+
+func nsec() int64 {
+ var scratch int64
+
+ r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
+ // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
+ if r0 == 0 {
+ return scratch
+ }
+ return int64(r0)
+}
+
+func Gettimeofday(tv *Timeval) error {
+ nsec := nsec()
+ *tv = NsecToTimeval(nsec)
+ return nil
+}
+
+func Getpagesize() int { return 0x1000 }
+
+func Getegid() (egid int) { return -1 }
+func Geteuid() (euid int) { return -1 }
+func Getgid() (gid int) { return -1 }
+func Getuid() (uid int) { return -1 }
+
+func Getgroups() (gids []int, err error) {
+ return make([]int, 0), nil
+}
+
+//sys open(path string, mode int) (fd int, err error)
+func Open(path string, mode int) (fd int, err error) {
+ fixwd()
+ return open(path, mode)
+}
+
+//sys create(path string, mode int, perm uint32) (fd int, err error)
+func Create(path string, mode int, perm uint32) (fd int, err error) {
+ fixwd()
+ return create(path, mode, perm)
+}
+
+//sys remove(path string) (err error)
+func Remove(path string) error {
+ fixwd()
+ return remove(path)
+}
+
+//sys stat(path string, edir []byte) (n int, err error)
+func Stat(path string, edir []byte) (n int, err error) {
+ fixwd()
+ return stat(path, edir)
+}
+
+//sys bind(name string, old string, flag int) (err error)
+func Bind(name string, old string, flag int) (err error) {
+ fixwd()
+ return bind(name, old, flag)
+}
+
+//sys mount(fd int, afd int, old string, flag int, aname string) (err error)
+func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
+ fixwd()
+ return mount(fd, afd, old, flag, aname)
+}
+
+//sys wstat(path string, edir []byte) (err error)
+func Wstat(path string, edir []byte) (err error) {
+ fixwd()
+ return wstat(path, edir)
+}
+
+//sys chdir(path string) (err error)
+//sys Dup(oldfd int, newfd int) (fd int, err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error)
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
+//sys Close(fd int) (err error)
+//sys Fstat(fd int, edir []byte) (n int, err error)
+//sys Fwstat(fd int, edir []byte) (err error)
diff --git a/vendor/golang.org/x/sys/plan9/syscall_test.go b/vendor/golang.org/x/sys/plan9/syscall_test.go
new file mode 100644
index 000000000..8f829bad0
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/syscall_test.go
@@ -0,0 +1,33 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build plan9
+
+package plan9_test
+
+import (
+ "testing"
+
+ "golang.org/x/sys/plan9"
+)
+
+func testSetGetenv(t *testing.T, key, value string) {
+ err := plan9.Setenv(key, value)
+ if err != nil {
+ t.Fatalf("Setenv failed to set %q: %v", value, err)
+ }
+ newvalue, found := plan9.Getenv(key)
+ if !found {
+ t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value)
+ }
+ if newvalue != value {
+ t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value)
+ }
+}
+
+func TestEnv(t *testing.T) {
+ testSetGetenv(t, "TESTENV", "AVALUE")
+ // make sure TESTENV gets set to "", not deleted
+ testSetGetenv(t, "TESTENV", "")
+}
diff --git a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go b/vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go
new file mode 100644
index 000000000..b35598ad9
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/zsyscall_plan9_386.go
@@ -0,0 +1,292 @@
+// mksyscall.pl -l32 -plan9 syscall_plan9.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package plan9
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fd2path(fd int, buf []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]int32) (err error) {
+ r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func await(s []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(s) > 0 {
+ _p0 = unsafe.Pointer(&s[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func open(path string, mode int) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ use(unsafe.Pointer(_p0))
+ fd = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func create(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+ use(unsafe.Pointer(_p0))
+ fd = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func remove(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func stat(path string, edir []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(edir) > 0 {
+ _p1 = unsafe.Pointer(&edir[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+ use(unsafe.Pointer(_p0))
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(name string, old string, flag int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(name)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(old)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(fd int, afd int, old string, flag int, aname string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(old)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(aname)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wstat(path string, edir []byte) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(edir) > 0 {
+ _p1 = unsafe.Pointer(&edir[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+ use(unsafe.Pointer(_p0))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int, newfd int) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+ fd = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, edir []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fwstat(fd int, edir []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
diff --git a/vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go b/vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go
new file mode 100644
index 000000000..b35598ad9
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/zsyscall_plan9_amd64.go
@@ -0,0 +1,292 @@
+// mksyscall.pl -l32 -plan9 syscall_plan9.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package plan9
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fd2path(fd int, buf []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(buf) > 0 {
+ _p0 = unsafe.Pointer(&buf[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FD2PATH, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]int32) (err error) {
+ r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func await(s []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(s) > 0 {
+ _p0 = unsafe.Pointer(&s[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_AWAIT, uintptr(_p0), uintptr(len(s)), 0)
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func open(path string, mode int) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+ use(unsafe.Pointer(_p0))
+ fd = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func create(path string, mode int, perm uint32) (fd int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_CREATE, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+ use(unsafe.Pointer(_p0))
+ fd = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func remove(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_REMOVE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func stat(path string, edir []byte) (n int, err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(edir) > 0 {
+ _p1 = unsafe.Pointer(&edir[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+ use(unsafe.Pointer(_p0))
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(name string, old string, flag int) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(name)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(old)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_BIND, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(flag))
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(fd int, afd int, old string, flag int, aname string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(old)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = BytePtrFromString(aname)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall6(SYS_MOUNT, uintptr(fd), uintptr(afd), uintptr(unsafe.Pointer(_p0)), uintptr(flag), uintptr(unsafe.Pointer(_p1)), 0)
+ use(unsafe.Pointer(_p0))
+ use(unsafe.Pointer(_p1))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wstat(path string, edir []byte) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ var _p1 unsafe.Pointer
+ if len(edir) > 0 {
+ _p1 = unsafe.Pointer(&edir[0])
+ } else {
+ _p1 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+ use(unsafe.Pointer(_p0))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func chdir(path string) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+ use(unsafe.Pointer(_p0))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int, newfd int) (fd int, err error) {
+ r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+ fd = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(p) > 0 {
+ _p0 = unsafe.Pointer(&p[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+ r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, edir []byte) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+ n = int(r0)
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fwstat(fd int, edir []byte) (err error) {
+ var _p0 unsafe.Pointer
+ if len(edir) > 0 {
+ _p0 = unsafe.Pointer(&edir[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall(SYS_FWSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+ if int32(r0) == -1 {
+ err = e1
+ }
+ return
+}
diff --git a/vendor/golang.org/x/sys/plan9/zsysnum_plan9.go b/vendor/golang.org/x/sys/plan9/zsysnum_plan9.go
new file mode 100644
index 000000000..22e8abd43
--- /dev/null
+++ b/vendor/golang.org/x/sys/plan9/zsysnum_plan9.go
@@ -0,0 +1,49 @@
+// mksysnum_plan9.sh /opt/plan9/sys/src/libc/9syscall/sys.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package plan9
+
+const (
+ SYS_SYSR1 = 0
+ SYS_BIND = 2
+ SYS_CHDIR = 3
+ SYS_CLOSE = 4
+ SYS_DUP = 5
+ SYS_ALARM = 6
+ SYS_EXEC = 7
+ SYS_EXITS = 8
+ SYS_FAUTH = 10
+ SYS_SEGBRK = 12
+ SYS_OPEN = 14
+ SYS_OSEEK = 16
+ SYS_SLEEP = 17
+ SYS_RFORK = 19
+ SYS_PIPE = 21
+ SYS_CREATE = 22
+ SYS_FD2PATH = 23
+ SYS_BRK_ = 24
+ SYS_REMOVE = 25
+ SYS_NOTIFY = 28
+ SYS_NOTED = 29
+ SYS_SEGATTACH = 30
+ SYS_SEGDETACH = 31
+ SYS_SEGFREE = 32
+ SYS_SEGFLUSH = 33
+ SYS_RENDEZVOUS = 34
+ SYS_UNMOUNT = 35
+ SYS_SEMACQUIRE = 37
+ SYS_SEMRELEASE = 38
+ SYS_SEEK = 39
+ SYS_FVERSION = 40
+ SYS_ERRSTR = 41
+ SYS_STAT = 42
+ SYS_FSTAT = 43
+ SYS_WSTAT = 44
+ SYS_FWSTAT = 45
+ SYS_MOUNT = 46
+ SYS_AWAIT = 47
+ SYS_PREAD = 50
+ SYS_PWRITE = 51
+ SYS_TSEMACQUIRE = 52
+ SYS_NSEC = 53
+)
diff --git a/vendor/golang.org/x/sys/unix/creds_test.go b/vendor/golang.org/x/sys/unix/creds_test.go
new file mode 100644
index 000000000..eaae7c367
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/creds_test.go
@@ -0,0 +1,121 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package unix_test
+
+import (
+ "bytes"
+ "net"
+ "os"
+ "syscall"
+ "testing"
+
+ "golang.org/x/sys/unix"
+)
+
+// TestSCMCredentials tests the sending and receiving of credentials
+// (PID, UID, GID) in an ancillary message between two UNIX
+// sockets. The SO_PASSCRED socket option is enabled on the sending
+// socket for this to work.
+func TestSCMCredentials(t *testing.T) {
+ fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
+ if err != nil {
+ t.Fatalf("Socketpair: %v", err)
+ }
+ defer unix.Close(fds[0])
+ defer unix.Close(fds[1])
+
+ err = unix.SetsockoptInt(fds[0], unix.SOL_SOCKET, unix.SO_PASSCRED, 1)
+ if err != nil {
+ t.Fatalf("SetsockoptInt: %v", err)
+ }
+
+ srvFile := os.NewFile(uintptr(fds[0]), "server")
+ defer srvFile.Close()
+ srv, err := net.FileConn(srvFile)
+ if err != nil {
+ t.Errorf("FileConn: %v", err)
+ return
+ }
+ defer srv.Close()
+
+ cliFile := os.NewFile(uintptr(fds[1]), "client")
+ defer cliFile.Close()
+ cli, err := net.FileConn(cliFile)
+ if err != nil {
+ t.Errorf("FileConn: %v", err)
+ return
+ }
+ defer cli.Close()
+
+ var ucred unix.Ucred
+ if os.Getuid() != 0 {
+ ucred.Pid = int32(os.Getpid())
+ ucred.Uid = 0
+ ucred.Gid = 0
+ oob := unix.UnixCredentials(&ucred)
+ _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
+ if op, ok := err.(*net.OpError); ok {
+ err = op.Err
+ }
+ if sys, ok := err.(*os.SyscallError); ok {
+ err = sys.Err
+ }
+ if err != syscall.EPERM {
+ t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
+ }
+ }
+
+ ucred.Pid = int32(os.Getpid())
+ ucred.Uid = uint32(os.Getuid())
+ ucred.Gid = uint32(os.Getgid())
+ oob := unix.UnixCredentials(&ucred)
+
+ // this is going to send a dummy byte
+ n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
+ if err != nil {
+ t.Fatalf("WriteMsgUnix: %v", err)
+ }
+ if n != 0 {
+ t.Fatalf("WriteMsgUnix n = %d, want 0", n)
+ }
+ if oobn != len(oob) {
+ t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob))
+ }
+
+ oob2 := make([]byte, 10*len(oob))
+ n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2)
+ if err != nil {
+ t.Fatalf("ReadMsgUnix: %v", err)
+ }
+ if flags != 0 {
+ t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags)
+ }
+ if n != 1 {
+ t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n)
+ }
+ if oobn2 != oobn {
+ // without SO_PASSCRED set on the socket, ReadMsgUnix will
+ // return zero oob bytes
+ t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn)
+ }
+ oob2 = oob2[:oobn2]
+ if !bytes.Equal(oob, oob2) {
+ t.Fatal("ReadMsgUnix oob bytes don't match")
+ }
+
+ scm, err := unix.ParseSocketControlMessage(oob2)
+ if err != nil {
+ t.Fatalf("ParseSocketControlMessage: %v", err)
+ }
+ newUcred, err := unix.ParseUnixCredentials(&scm[0])
+ if err != nil {
+ t.Fatalf("ParseUnixCredentials: %v", err)
+ }
+ if *newUcred != ucred {
+ t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred)
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/export_test.go b/vendor/golang.org/x/sys/unix/export_test.go
new file mode 100644
index 000000000..b4fdd970b
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix
+
+var Itoa = itoa
diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh
index de95a4bbc..de95a4bbc 100644..100755
--- a/vendor/golang.org/x/sys/unix/mkall.sh
+++ b/vendor/golang.org/x/sys/unix/mkall.sh
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
index c40d788c4..c40d788c4 100644..100755
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
diff --git a/vendor/golang.org/x/sys/unix/mksyscall.pl b/vendor/golang.org/x/sys/unix/mksyscall.pl
index b1e7766da..b1e7766da 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksyscall.pl
+++ b/vendor/golang.org/x/sys/unix/mksyscall.pl
diff --git a/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl b/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl
index 06bade768..06bade768 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl
+++ b/vendor/golang.org/x/sys/unix/mksyscall_solaris.pl
diff --git a/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl b/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl
index be67afa41..be67afa41 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl
+++ b/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl
diff --git a/vendor/golang.org/x/sys/unix/mksysnum_darwin.pl b/vendor/golang.org/x/sys/unix/mksysnum_darwin.pl
index d3e5147fc..d3e5147fc 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksysnum_darwin.pl
+++ b/vendor/golang.org/x/sys/unix/mksysnum_darwin.pl
diff --git a/vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl b/vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl
index 266a248c7..266a248c7 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl
+++ b/vendor/golang.org/x/sys/unix/mksysnum_dragonfly.pl
diff --git a/vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl b/vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl
index b767e124c..b767e124c 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl
+++ b/vendor/golang.org/x/sys/unix/mksysnum_freebsd.pl
diff --git a/vendor/golang.org/x/sys/unix/mksysnum_linux.pl b/vendor/golang.org/x/sys/unix/mksysnum_linux.pl
index 4d4017deb..4d4017deb 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksysnum_linux.pl
+++ b/vendor/golang.org/x/sys/unix/mksysnum_linux.pl
diff --git a/vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl b/vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl
index e74616a65..e74616a65 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl
+++ b/vendor/golang.org/x/sys/unix/mksysnum_netbsd.pl
diff --git a/vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl b/vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl
index ae5aad586..ae5aad586 100644..100755
--- a/vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl
+++ b/vendor/golang.org/x/sys/unix/mksysnum_openbsd.pl
diff --git a/vendor/golang.org/x/sys/unix/mmap_unix_test.go b/vendor/golang.org/x/sys/unix/mmap_unix_test.go
new file mode 100644
index 000000000..18ccec05f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/mmap_unix_test.go
@@ -0,0 +1,23 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix_test
+
+import (
+ "testing"
+
+ "golang.org/x/sys/unix"
+)
+
+func TestMmap(t *testing.T) {
+ b, err := unix.Mmap(-1, 0, unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
+ if err != nil {
+ t.Fatalf("Mmap: %v", err)
+ }
+ if err := unix.Munmap(b); err != nil {
+ t.Fatalf("Munmap: %v", err)
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall.go b/vendor/golang.org/x/sys/unix/syscall.go
index 571e6993c..a0bcf842c 100644
--- a/vendor/golang.org/x/sys/unix/syscall.go
+++ b/vendor/golang.org/x/sys/unix/syscall.go
@@ -19,7 +19,7 @@
// These calls return err == nil to indicate success; otherwise
// err represents an operating system error describing the failure and
// holds a value of type syscall.Errno.
-package unix
+package unix // import "golang.org/x/sys/unix"
import "unsafe"
diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd_test.go b/vendor/golang.org/x/sys/unix/syscall_bsd_test.go
new file mode 100644
index 000000000..2ad51290c
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_bsd_test.go
@@ -0,0 +1,47 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd openbsd
+
+package unix_test
+
+import (
+ "runtime"
+ "testing"
+
+ "golang.org/x/sys/unix"
+)
+
+const MNT_WAIT = 1
+
+func TestGetfsstat(t *testing.T) {
+ n, err := unix.Getfsstat(nil, MNT_WAIT)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ data := make([]unix.Statfs_t, n)
+ n, err = unix.Getfsstat(data, MNT_WAIT)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ empty := unix.Statfs_t{}
+ for _, stat := range data {
+ if stat == empty {
+ t.Fatal("an empty Statfs_t struct was returned")
+ }
+ }
+}
+
+func TestSysctlRaw(t *testing.T) {
+ if runtime.GOOS == "openbsd" {
+ t.Skip("kern.proc.pid does not exist on OpenBSD")
+ }
+
+ _, err := unix.SysctlRaw("kern.proc.pid", unix.Getpid())
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly_386.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly_386.go
deleted file mode 100644
index 60fec8cec..000000000
--- a/vendor/golang.org/x/sys/unix/syscall_dragonfly_386.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build 386,dragonfly
-
-package unix
-
-import (
- "syscall"
- "unsafe"
-)
-
-func Getpagesize() int { return 4096 }
-
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
-}
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
- return
-}
-
-func SetKevent(k *Kevent_t, fd, mode, flags int) {
- k.Ident = uint32(fd)
- k.Filter = int16(mode)
- k.Flags = uint16(flags)
-}
-
-func (iov *Iovec) SetLen(length int) {
- iov.Len = uint32(length)
-}
-
-func (msghdr *Msghdr) SetControllen(length int) {
- msghdr.Controllen = uint32(length)
-}
-
-func (cmsg *Cmsghdr) SetLen(length int) {
- cmsg.Len = uint32(length)
-}
-
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- var writtenOut uint64 = 0
- _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
-
- written = int(writtenOut)
-
- if e1 != 0 {
- err = e1
- }
- return
-}
-
-func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_test.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_test.go
new file mode 100644
index 000000000..cd13080ad
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_test.go
@@ -0,0 +1,24 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd
+
+package unix_test
+
+import (
+ "os"
+ "testing"
+
+ "golang.org/x/sys/unix"
+)
+
+func TestSysctUint64(t *testing.T) {
+ _, err := unix.SysctlUint64("vm.max_kernel_address")
+ if err != nil {
+ if os.Getenv("GO_BUILDER_NAME") == "freebsd-386-gce101" {
+ t.Skipf("Ignoring known failing test (golang.org/issue/15186). Failed with: %v", err)
+ }
+ t.Fatal(err)
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_test.go b/vendor/golang.org/x/sys/unix/syscall_linux_test.go
new file mode 100644
index 000000000..2238b658d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_test.go
@@ -0,0 +1,110 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package unix_test
+
+import (
+ "io/ioutil"
+ "os"
+ "testing"
+ "time"
+
+ "golang.org/x/sys/unix"
+)
+
+func TestTime(t *testing.T) {
+ var ut unix.Time_t
+ ut2, err := unix.Time(&ut)
+ if err != nil {
+ t.Fatalf("Time: %v", err)
+ }
+ if ut != ut2 {
+ t.Errorf("Time: return value %v should be equal to argument %v", ut2, ut)
+ }
+
+ var now time.Time
+
+ for i := 0; i < 10; i++ {
+ ut, err = unix.Time(nil)
+ if err != nil {
+ t.Fatalf("Time: %v", err)
+ }
+
+ now = time.Now()
+
+ if int64(ut) == now.Unix() {
+ return
+ }
+ }
+
+ t.Errorf("Time: return value %v should be nearly equal to time.Now().Unix() %v", ut, now.Unix())
+}
+
+func TestUtime(t *testing.T) {
+ defer chtmpdir(t)()
+
+ touch(t, "file1")
+
+ buf := &unix.Utimbuf{
+ Modtime: 12345,
+ }
+
+ err := unix.Utime("file1", buf)
+ if err != nil {
+ t.Fatalf("Utime: %v", err)
+ }
+
+ fi, err := os.Stat("file1")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if fi.ModTime().Unix() != 12345 {
+ t.Errorf("Utime: failed to change modtime: expected %v, got %v", 12345, fi.ModTime().Unix())
+ }
+}
+
+func TestGetrlimit(t *testing.T) {
+ var rlim unix.Rlimit
+ err := unix.Getrlimit(unix.RLIMIT_AS, &rlim)
+ if err != nil {
+ t.Fatalf("Getrlimit: %v", err)
+ }
+}
+
+// utilities taken from os/os_test.go
+
+func touch(t *testing.T, name string) {
+ f, err := os.Create(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// chtmpdir changes the working directory to a new temporary directory and
+// provides a cleanup function. Used when PWD is read-only.
+func chtmpdir(t *testing.T) func() {
+ oldwd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ d, err := ioutil.TempDir("", "test")
+ if err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ if err := os.Chdir(d); err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ return func() {
+ if err := os.Chdir(oldwd); err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ os.RemoveAll(d)
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_test.go b/vendor/golang.org/x/sys/unix/syscall_test.go
new file mode 100644
index 000000000..95eac92ac
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_test.go
@@ -0,0 +1,50 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix_test
+
+import (
+ "fmt"
+ "testing"
+
+ "golang.org/x/sys/unix"
+)
+
+func testSetGetenv(t *testing.T, key, value string) {
+ err := unix.Setenv(key, value)
+ if err != nil {
+ t.Fatalf("Setenv failed to set %q: %v", value, err)
+ }
+ newvalue, found := unix.Getenv(key)
+ if !found {
+ t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value)
+ }
+ if newvalue != value {
+ t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value)
+ }
+}
+
+func TestEnv(t *testing.T) {
+ testSetGetenv(t, "TESTENV", "AVALUE")
+ // make sure TESTENV gets set to "", not deleted
+ testSetGetenv(t, "TESTENV", "")
+}
+
+func TestItoa(t *testing.T) {
+ // Make most negative integer: 0x8000...
+ i := 1
+ for i<<1 != 0 {
+ i <<= 1
+ }
+ if i >= 0 {
+ t.Fatal("bad math")
+ }
+ s := unix.Itoa(i)
+ f := fmt.Sprint(i)
+ if s != f {
+ t.Fatalf("itoa(%d) = %s, want %s", i, s, f)
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_test.go b/vendor/golang.org/x/sys/unix/syscall_unix_test.go
new file mode 100644
index 000000000..49208a000
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_unix_test.go
@@ -0,0 +1,353 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix_test
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "testing"
+ "time"
+
+ "golang.org/x/sys/unix"
+)
+
+// Tests that below functions, structures and constants are consistent
+// on all Unix-like systems.
+func _() {
+ // program scheduling priority functions and constants
+ var (
+ _ func(int, int, int) error = unix.Setpriority
+ _ func(int, int) (int, error) = unix.Getpriority
+ )
+ const (
+ _ int = unix.PRIO_USER
+ _ int = unix.PRIO_PROCESS
+ _ int = unix.PRIO_PGRP
+ )
+
+ // termios constants
+ const (
+ _ int = unix.TCIFLUSH
+ _ int = unix.TCIOFLUSH
+ _ int = unix.TCOFLUSH
+ )
+
+ // fcntl file locking structure and constants
+ var (
+ _ = unix.Flock_t{
+ Type: int16(0),
+ Whence: int16(0),
+ Start: int64(0),
+ Len: int64(0),
+ Pid: int32(0),
+ }
+ )
+ const (
+ _ = unix.F_GETLK
+ _ = unix.F_SETLK
+ _ = unix.F_SETLKW
+ )
+}
+
+// TestFcntlFlock tests whether the file locking structure matches
+// the calling convention of each kernel.
+func TestFcntlFlock(t *testing.T) {
+ name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+ fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0)
+ if err != nil {
+ t.Fatalf("Open failed: %v", err)
+ }
+ defer unix.Unlink(name)
+ defer unix.Close(fd)
+ flock := unix.Flock_t{
+ Type: unix.F_RDLCK,
+ Start: 0, Len: 0, Whence: 1,
+ }
+ if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil {
+ t.Fatalf("FcntlFlock failed: %v", err)
+ }
+}
+
+// TestPassFD tests passing a file descriptor over a Unix socket.
+//
+// This test involved both a parent and child process. The parent
+// process is invoked as a normal test, with "go test", which then
+// runs the child process by running the current test binary with args
+// "-test.run=^TestPassFD$" and an environment variable used to signal
+// that the test should become the child process instead.
+func TestPassFD(t *testing.T) {
+ switch runtime.GOOS {
+ case "dragonfly":
+ // TODO(jsing): Figure out why sendmsg is returning EINVAL.
+ t.Skip("skipping test on dragonfly")
+ case "solaris":
+ // TODO(aram): Figure out why ReadMsgUnix is returning empty message.
+ t.Skip("skipping test on solaris, see issue 7402")
+ }
+ if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+ passFDChild()
+ return
+ }
+
+ tempDir, err := ioutil.TempDir("", "TestPassFD")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tempDir)
+
+ fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
+ if err != nil {
+ t.Fatalf("Socketpair: %v", err)
+ }
+ defer unix.Close(fds[0])
+ defer unix.Close(fds[1])
+ writeFile := os.NewFile(uintptr(fds[0]), "child-writes")
+ readFile := os.NewFile(uintptr(fds[1]), "parent-reads")
+ defer writeFile.Close()
+ defer readFile.Close()
+
+ cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" {
+ cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp)
+ }
+ cmd.ExtraFiles = []*os.File{writeFile}
+
+ out, err := cmd.CombinedOutput()
+ if len(out) > 0 || err != nil {
+ t.Fatalf("child process: %q, %v", out, err)
+ }
+
+ c, err := net.FileConn(readFile)
+ if err != nil {
+ t.Fatalf("FileConn: %v", err)
+ }
+ defer c.Close()
+
+ uc, ok := c.(*net.UnixConn)
+ if !ok {
+ t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c)
+ }
+
+ buf := make([]byte, 32) // expect 1 byte
+ oob := make([]byte, 32) // expect 24 bytes
+ closeUnix := time.AfterFunc(5*time.Second, func() {
+ t.Logf("timeout reading from unix socket")
+ uc.Close()
+ })
+ _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
+ closeUnix.Stop()
+
+ scms, err := unix.ParseSocketControlMessage(oob[:oobn])
+ if err != nil {
+ t.Fatalf("ParseSocketControlMessage: %v", err)
+ }
+ if len(scms) != 1 {
+ t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms)
+ }
+ scm := scms[0]
+ gotFds, err := unix.ParseUnixRights(&scm)
+ if err != nil {
+ t.Fatalf("unix.ParseUnixRights: %v", err)
+ }
+ if len(gotFds) != 1 {
+ t.Fatalf("wanted 1 fd; got %#v", gotFds)
+ }
+
+ f := os.NewFile(uintptr(gotFds[0]), "fd-from-child")
+ defer f.Close()
+
+ got, err := ioutil.ReadAll(f)
+ want := "Hello from child process!\n"
+ if string(got) != want {
+ t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want)
+ }
+}
+
+// passFDChild is the child process used by TestPassFD.
+func passFDChild() {
+ defer os.Exit(0)
+
+ // Look for our fd. It should be fd 3, but we work around an fd leak
+ // bug here (http://golang.org/issue/2603) to let it be elsewhere.
+ var uc *net.UnixConn
+ for fd := uintptr(3); fd <= 10; fd++ {
+ f := os.NewFile(fd, "unix-conn")
+ var ok bool
+ netc, _ := net.FileConn(f)
+ uc, ok = netc.(*net.UnixConn)
+ if ok {
+ break
+ }
+ }
+ if uc == nil {
+ fmt.Println("failed to find unix fd")
+ return
+ }
+
+ // Make a file f to send to our parent process on uc.
+ // We make it in tempDir, which our parent will clean up.
+ flag.Parse()
+ tempDir := flag.Arg(0)
+ f, err := ioutil.TempFile(tempDir, "")
+ if err != nil {
+ fmt.Printf("TempFile: %v", err)
+ return
+ }
+
+ f.Write([]byte("Hello from child process!\n"))
+ f.Seek(0, 0)
+
+ rights := unix.UnixRights(int(f.Fd()))
+ dummyByte := []byte("x")
+ n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil)
+ if err != nil {
+ fmt.Printf("WriteMsgUnix: %v", err)
+ return
+ }
+ if n != 1 || oobn != len(rights) {
+ fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights))
+ return
+ }
+}
+
+// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
+// and ParseUnixRights are able to successfully round-trip lists of file descriptors.
+func TestUnixRightsRoundtrip(t *testing.T) {
+ testCases := [...][][]int{
+ {{42}},
+ {{1, 2}},
+ {{3, 4, 5}},
+ {{}},
+ {{1, 2}, {3, 4, 5}, {}, {7}},
+ }
+ for _, testCase := range testCases {
+ b := []byte{}
+ var n int
+ for _, fds := range testCase {
+ // Last assignment to n wins
+ n = len(b) + unix.CmsgLen(4*len(fds))
+ b = append(b, unix.UnixRights(fds...)...)
+ }
+ // Truncate b
+ b = b[:n]
+
+ scms, err := unix.ParseSocketControlMessage(b)
+ if err != nil {
+ t.Fatalf("ParseSocketControlMessage: %v", err)
+ }
+ if len(scms) != len(testCase) {
+ t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
+ }
+ for i, scm := range scms {
+ gotFds, err := unix.ParseUnixRights(&scm)
+ if err != nil {
+ t.Fatalf("ParseUnixRights: %v", err)
+ }
+ wantFds := testCase[i]
+ if len(gotFds) != len(wantFds) {
+ t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds)
+ }
+ for j, fd := range gotFds {
+ if fd != wantFds[j] {
+ t.Fatalf("expected fd %v, got %v", wantFds[j], fd)
+ }
+ }
+ }
+ }
+}
+
+func TestRlimit(t *testing.T) {
+ var rlimit, zero unix.Rlimit
+ err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Getrlimit: save failed: %v", err)
+ }
+ if zero == rlimit {
+ t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
+ }
+ set := rlimit
+ set.Cur = set.Max - 1
+ err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set)
+ if err != nil {
+ t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
+ }
+ var get unix.Rlimit
+ err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get)
+ if err != nil {
+ t.Fatalf("Getrlimit: get failed: %v", err)
+ }
+ set = rlimit
+ set.Cur = set.Max - 1
+ if set != get {
+ // Seems like Darwin requires some privilege to
+ // increase the soft limit of rlimit sandbox, though
+ // Setrlimit never reports an error.
+ switch runtime.GOOS {
+ case "darwin":
+ default:
+ t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
+ }
+ }
+ err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit)
+ if err != nil {
+ t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
+ }
+}
+
+func TestSeekFailure(t *testing.T) {
+ _, err := unix.Seek(-1, 0, 0)
+ if err == nil {
+ t.Fatalf("Seek(-1, 0, 0) did not fail")
+ }
+ str := err.Error() // used to crash on Linux
+ t.Logf("Seek: %v", str)
+ if str == "" {
+ t.Fatalf("Seek(-1, 0, 0) return error with empty message")
+ }
+}
+
+func TestDup(t *testing.T) {
+ file, err := ioutil.TempFile("", "TestDup")
+ if err != nil {
+ t.Fatalf("Tempfile failed: %v", err)
+ }
+ defer os.Remove(file.Name())
+ defer file.Close()
+ f := int(file.Fd())
+
+ newFd, err := unix.Dup(f)
+ if err != nil {
+ t.Fatalf("Dup: %v", err)
+ }
+
+ err = unix.Dup2(newFd, newFd+1)
+ if err != nil {
+ t.Fatalf("Dup2: %v", err)
+ }
+
+ b1 := []byte("Test123")
+ b2 := make([]byte, 7)
+ _, err = unix.Write(newFd+1, b1)
+ if err != nil {
+ t.Fatalf("Write to dup2 fd failed: %v", err)
+ }
+ _, err = unix.Seek(f, 0, 0)
+ _, err = unix.Read(f, b2)
+ if err != nil {
+ t.Fatalf("Read back failed: %v", err)
+ }
+ if string(b1) != string(b2) {
+ t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2))
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/zerrors_dragonfly_386.go b/vendor/golang.org/x/sys/unix/zerrors_dragonfly_386.go
deleted file mode 100644
index 2a329f06e..000000000
--- a/vendor/golang.org/x/sys/unix/zerrors_dragonfly_386.go
+++ /dev/null
@@ -1,1530 +0,0 @@
-// mkerrors.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-// +build 386,dragonfly
-
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs -- -m32 _const.go
-
-package unix
-
-import "syscall"
-
-const (
- AF_APPLETALK = 0x10
- AF_ATM = 0x1e
- AF_BLUETOOTH = 0x21
- AF_CCITT = 0xa
- AF_CHAOS = 0x5
- AF_CNT = 0x15
- AF_COIP = 0x14
- AF_DATAKIT = 0x9
- AF_DECnet = 0xc
- AF_DLI = 0xd
- AF_E164 = 0x1a
- AF_ECMA = 0x8
- AF_HYLINK = 0xf
- AF_IEEE80211 = 0x23
- AF_IMPLINK = 0x3
- AF_INET = 0x2
- AF_INET6 = 0x1c
- AF_IPX = 0x17
- AF_ISDN = 0x1a
- AF_ISO = 0x7
- AF_LAT = 0xe
- AF_LINK = 0x12
- AF_LOCAL = 0x1
- AF_MAX = 0x24
- AF_MPLS = 0x22
- AF_NATM = 0x1d
- AF_NETGRAPH = 0x20
- AF_NS = 0x6
- AF_OSI = 0x7
- AF_PUP = 0x4
- AF_ROUTE = 0x11
- AF_SIP = 0x18
- AF_SNA = 0xb
- AF_UNIX = 0x1
- AF_UNSPEC = 0x0
- B0 = 0x0
- B110 = 0x6e
- B115200 = 0x1c200
- B1200 = 0x4b0
- B134 = 0x86
- B14400 = 0x3840
- B150 = 0x96
- B1800 = 0x708
- B19200 = 0x4b00
- B200 = 0xc8
- B230400 = 0x38400
- B2400 = 0x960
- B28800 = 0x7080
- B300 = 0x12c
- B38400 = 0x9600
- B4800 = 0x12c0
- B50 = 0x32
- B57600 = 0xe100
- B600 = 0x258
- B7200 = 0x1c20
- B75 = 0x4b
- B76800 = 0x12c00
- B9600 = 0x2580
- BIOCFLUSH = 0x20004268
- BIOCGBLEN = 0x40044266
- BIOCGDLT = 0x4004426a
- BIOCGDLTLIST = 0xc0084279
- BIOCGETIF = 0x4020426b
- BIOCGHDRCMPLT = 0x40044274
- BIOCGRSIG = 0x40044272
- BIOCGRTIMEOUT = 0x4008426e
- BIOCGSEESENT = 0x40044276
- BIOCGSTATS = 0x4008426f
- BIOCIMMEDIATE = 0x80044270
- BIOCLOCK = 0x2000427a
- BIOCPROMISC = 0x20004269
- BIOCSBLEN = 0xc0044266
- BIOCSDLT = 0x80044278
- BIOCSETF = 0x80084267
- BIOCSETIF = 0x8020426c
- BIOCSETWF = 0x8008427b
- BIOCSHDRCMPLT = 0x80044275
- BIOCSRSIG = 0x80044273
- BIOCSRTIMEOUT = 0x8008426d
- BIOCSSEESENT = 0x80044277
- BIOCVERSION = 0x40044271
- BPF_A = 0x10
- BPF_ABS = 0x20
- BPF_ADD = 0x0
- BPF_ALIGNMENT = 0x4
- BPF_ALU = 0x4
- BPF_AND = 0x50
- BPF_B = 0x10
- BPF_DEFAULTBUFSIZE = 0x1000
- BPF_DIV = 0x30
- BPF_H = 0x8
- BPF_IMM = 0x0
- BPF_IND = 0x40
- BPF_JA = 0x0
- BPF_JEQ = 0x10
- BPF_JGE = 0x30
- BPF_JGT = 0x20
- BPF_JMP = 0x5
- BPF_JSET = 0x40
- BPF_K = 0x0
- BPF_LD = 0x0
- BPF_LDX = 0x1
- BPF_LEN = 0x80
- BPF_LSH = 0x60
- BPF_MAJOR_VERSION = 0x1
- BPF_MAXBUFSIZE = 0x80000
- BPF_MAXINSNS = 0x200
- BPF_MAX_CLONES = 0x80
- BPF_MEM = 0x60
- BPF_MEMWORDS = 0x10
- BPF_MINBUFSIZE = 0x20
- BPF_MINOR_VERSION = 0x1
- BPF_MISC = 0x7
- BPF_MSH = 0xa0
- BPF_MUL = 0x20
- BPF_NEG = 0x80
- BPF_OR = 0x40
- BPF_RELEASE = 0x30bb6
- BPF_RET = 0x6
- BPF_RSH = 0x70
- BPF_ST = 0x2
- BPF_STX = 0x3
- BPF_SUB = 0x10
- BPF_TAX = 0x0
- BPF_TXA = 0x80
- BPF_W = 0x0
- BPF_X = 0x8
- BRKINT = 0x2
- CFLUSH = 0xf
- CLOCAL = 0x8000
- CREAD = 0x800
- CS5 = 0x0
- CS6 = 0x100
- CS7 = 0x200
- CS8 = 0x300
- CSIZE = 0x300
- CSTART = 0x11
- CSTATUS = 0x14
- CSTOP = 0x13
- CSTOPB = 0x400
- CSUSP = 0x1a
- CTL_MAXNAME = 0xc
- CTL_NET = 0x4
- DLT_A429 = 0xb8
- DLT_A653_ICM = 0xb9
- DLT_AIRONET_HEADER = 0x78
- DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
- DLT_ARCNET = 0x7
- DLT_ARCNET_LINUX = 0x81
- DLT_ATM_CLIP = 0x13
- DLT_ATM_RFC1483 = 0xb
- DLT_AURORA = 0x7e
- DLT_AX25 = 0x3
- DLT_AX25_KISS = 0xca
- DLT_BACNET_MS_TP = 0xa5
- DLT_BLUETOOTH_HCI_H4 = 0xbb
- DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9
- DLT_CAN20B = 0xbe
- DLT_CHAOS = 0x5
- DLT_CHDLC = 0x68
- DLT_CISCO_IOS = 0x76
- DLT_C_HDLC = 0x68
- DLT_C_HDLC_WITH_DIR = 0xcd
- DLT_DOCSIS = 0x8f
- DLT_ECONET = 0x73
- DLT_EN10MB = 0x1
- DLT_EN3MB = 0x2
- DLT_ENC = 0x6d
- DLT_ERF = 0xc5
- DLT_ERF_ETH = 0xaf
- DLT_ERF_POS = 0xb0
- DLT_FDDI = 0xa
- DLT_FLEXRAY = 0xd2
- DLT_FRELAY = 0x6b
- DLT_FRELAY_WITH_DIR = 0xce
- DLT_GCOM_SERIAL = 0xad
- DLT_GCOM_T1E1 = 0xac
- DLT_GPF_F = 0xab
- DLT_GPF_T = 0xaa
- DLT_GPRS_LLC = 0xa9
- DLT_HHDLC = 0x79
- DLT_IBM_SN = 0x92
- DLT_IBM_SP = 0x91
- DLT_IEEE802 = 0x6
- DLT_IEEE802_11 = 0x69
- DLT_IEEE802_11_RADIO = 0x7f
- DLT_IEEE802_11_RADIO_AVS = 0xa3
- DLT_IEEE802_15_4 = 0xc3
- DLT_IEEE802_15_4_LINUX = 0xbf
- DLT_IEEE802_15_4_NONASK_PHY = 0xd7
- DLT_IEEE802_16_MAC_CPS = 0xbc
- DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1
- DLT_IPFILTER = 0x74
- DLT_IPMB = 0xc7
- DLT_IPMB_LINUX = 0xd1
- DLT_IP_OVER_FC = 0x7a
- DLT_JUNIPER_ATM1 = 0x89
- DLT_JUNIPER_ATM2 = 0x87
- DLT_JUNIPER_CHDLC = 0xb5
- DLT_JUNIPER_ES = 0x84
- DLT_JUNIPER_ETHER = 0xb2
- DLT_JUNIPER_FRELAY = 0xb4
- DLT_JUNIPER_GGSN = 0x85
- DLT_JUNIPER_ISM = 0xc2
- DLT_JUNIPER_MFR = 0x86
- DLT_JUNIPER_MLFR = 0x83
- DLT_JUNIPER_MLPPP = 0x82
- DLT_JUNIPER_MONITOR = 0xa4
- DLT_JUNIPER_PIC_PEER = 0xae
- DLT_JUNIPER_PPP = 0xb3
- DLT_JUNIPER_PPPOE = 0xa7
- DLT_JUNIPER_PPPOE_ATM = 0xa8
- DLT_JUNIPER_SERVICES = 0x88
- DLT_JUNIPER_ST = 0xc8
- DLT_JUNIPER_VP = 0xb7
- DLT_LAPB_WITH_DIR = 0xcf
- DLT_LAPD = 0xcb
- DLT_LIN = 0xd4
- DLT_LINUX_IRDA = 0x90
- DLT_LINUX_LAPD = 0xb1
- DLT_LINUX_SLL = 0x71
- DLT_LOOP = 0x6c
- DLT_LTALK = 0x72
- DLT_MFR = 0xb6
- DLT_MOST = 0xd3
- DLT_MTP2 = 0x8c
- DLT_MTP2_WITH_PHDR = 0x8b
- DLT_MTP3 = 0x8d
- DLT_NULL = 0x0
- DLT_PCI_EXP = 0x7d
- DLT_PFLOG = 0x75
- DLT_PFSYNC = 0x12
- DLT_PPI = 0xc0
- DLT_PPP = 0x9
- DLT_PPP_BSDOS = 0x10
- DLT_PPP_ETHER = 0x33
- DLT_PPP_PPPD = 0xa6
- DLT_PPP_SERIAL = 0x32
- DLT_PPP_WITH_DIR = 0xcc
- DLT_PRISM_HEADER = 0x77
- DLT_PRONET = 0x4
- DLT_RAIF1 = 0xc6
- DLT_RAW = 0xc
- DLT_REDBACK_SMARTEDGE = 0x20
- DLT_RIO = 0x7c
- DLT_SCCP = 0x8e
- DLT_SITA = 0xc4
- DLT_SLIP = 0x8
- DLT_SLIP_BSDOS = 0xf
- DLT_SUNATM = 0x7b
- DLT_SYMANTEC_FIREWALL = 0x63
- DLT_TZSP = 0x80
- DLT_USB = 0xba
- DLT_USB_LINUX = 0xbd
- DLT_X2E_SERIAL = 0xd5
- DLT_X2E_XORAYA = 0xd6
- DT_BLK = 0x6
- DT_CHR = 0x2
- DT_DBF = 0xf
- DT_DIR = 0x4
- DT_FIFO = 0x1
- DT_LNK = 0xa
- DT_REG = 0x8
- DT_SOCK = 0xc
- DT_UNKNOWN = 0x0
- DT_WHT = 0xe
- ECHO = 0x8
- ECHOCTL = 0x40
- ECHOE = 0x2
- ECHOK = 0x4
- ECHOKE = 0x1
- ECHONL = 0x10
- ECHOPRT = 0x20
- EVFILT_AIO = -0x3
- EVFILT_EXCEPT = -0x8
- EVFILT_MARKER = 0xf
- EVFILT_PROC = -0x5
- EVFILT_READ = -0x1
- EVFILT_SIGNAL = -0x6
- EVFILT_SYSCOUNT = 0x8
- EVFILT_TIMER = -0x7
- EVFILT_VNODE = -0x4
- EVFILT_WRITE = -0x2
- EV_ADD = 0x1
- EV_CLEAR = 0x20
- EV_DELETE = 0x2
- EV_DISABLE = 0x8
- EV_ENABLE = 0x4
- EV_EOF = 0x8000
- EV_ERROR = 0x4000
- EV_FLAG1 = 0x2000
- EV_NODATA = 0x1000
- EV_ONESHOT = 0x10
- EV_SYSFLAGS = 0xf000
- EXTA = 0x4b00
- EXTB = 0x9600
- EXTEXIT_LWP = 0x10000
- EXTEXIT_PROC = 0x0
- EXTEXIT_SETINT = 0x1
- EXTEXIT_SIMPLE = 0x0
- EXTPROC = 0x800
- FD_CLOEXEC = 0x1
- FD_SETSIZE = 0x400
- FLUSHO = 0x800000
- F_DUP2FD = 0xa
- F_DUP2FD_CLOEXEC = 0x12
- F_DUPFD = 0x0
- F_DUPFD_CLOEXEC = 0x11
- F_GETFD = 0x1
- F_GETFL = 0x3
- F_GETLK = 0x7
- F_GETOWN = 0x5
- F_OK = 0x0
- F_RDLCK = 0x1
- F_SETFD = 0x2
- F_SETFL = 0x4
- F_SETLK = 0x8
- F_SETLKW = 0x9
- F_SETOWN = 0x6
- F_UNLCK = 0x2
- F_WRLCK = 0x3
- HUPCL = 0x4000
- ICANON = 0x100
- ICMP6_FILTER = 0x12
- ICRNL = 0x100
- IEXTEN = 0x400
- IFAN_ARRIVAL = 0x0
- IFAN_DEPARTURE = 0x1
- IFF_ALLMULTI = 0x200
- IFF_ALTPHYS = 0x4000
- IFF_BROADCAST = 0x2
- IFF_CANTCHANGE = 0x118e72
- IFF_DEBUG = 0x4
- IFF_LINK0 = 0x1000
- IFF_LINK1 = 0x2000
- IFF_LINK2 = 0x4000
- IFF_LOOPBACK = 0x8
- IFF_MONITOR = 0x40000
- IFF_MULTICAST = 0x8000
- IFF_NOARP = 0x80
- IFF_NPOLLING = 0x100000
- IFF_OACTIVE = 0x400
- IFF_OACTIVE_COMPAT = 0x400
- IFF_POINTOPOINT = 0x10
- IFF_POLLING = 0x10000
- IFF_POLLING_COMPAT = 0x10000
- IFF_PPROMISC = 0x20000
- IFF_PROMISC = 0x100
- IFF_RUNNING = 0x40
- IFF_SIMPLEX = 0x800
- IFF_SMART = 0x20
- IFF_STATICARP = 0x80000
- IFF_UP = 0x1
- IFNAMSIZ = 0x10
- IFT_1822 = 0x2
- IFT_A12MPPSWITCH = 0x82
- IFT_AAL2 = 0xbb
- IFT_AAL5 = 0x31
- IFT_ADSL = 0x5e
- IFT_AFLANE8023 = 0x3b
- IFT_AFLANE8025 = 0x3c
- IFT_ARAP = 0x58
- IFT_ARCNET = 0x23
- IFT_ARCNETPLUS = 0x24
- IFT_ASYNC = 0x54
- IFT_ATM = 0x25
- IFT_ATMDXI = 0x69
- IFT_ATMFUNI = 0x6a
- IFT_ATMIMA = 0x6b
- IFT_ATMLOGICAL = 0x50
- IFT_ATMRADIO = 0xbd
- IFT_ATMSUBINTERFACE = 0x86
- IFT_ATMVCIENDPT = 0xc2
- IFT_ATMVIRTUAL = 0x95
- IFT_BGPPOLICYACCOUNTING = 0xa2
- IFT_BRIDGE = 0xd1
- IFT_BSC = 0x53
- IFT_CARP = 0xf8
- IFT_CCTEMUL = 0x3d
- IFT_CEPT = 0x13
- IFT_CES = 0x85
- IFT_CHANNEL = 0x46
- IFT_CNR = 0x55
- IFT_COFFEE = 0x84
- IFT_COMPOSITELINK = 0x9b
- IFT_DCN = 0x8d
- IFT_DIGITALPOWERLINE = 0x8a
- IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
- IFT_DLSW = 0x4a
- IFT_DOCSCABLEDOWNSTREAM = 0x80
- IFT_DOCSCABLEMACLAYER = 0x7f
- IFT_DOCSCABLEUPSTREAM = 0x81
- IFT_DS0 = 0x51
- IFT_DS0BUNDLE = 0x52
- IFT_DS1FDL = 0xaa
- IFT_DS3 = 0x1e
- IFT_DTM = 0x8c
- IFT_DVBASILN = 0xac
- IFT_DVBASIOUT = 0xad
- IFT_DVBRCCDOWNSTREAM = 0x93
- IFT_DVBRCCMACLAYER = 0x92
- IFT_DVBRCCUPSTREAM = 0x94
- IFT_ENC = 0xf4
- IFT_EON = 0x19
- IFT_EPLRS = 0x57
- IFT_ESCON = 0x49
- IFT_ETHER = 0x6
- IFT_FAITH = 0xf2
- IFT_FAST = 0x7d
- IFT_FASTETHER = 0x3e
- IFT_FASTETHERFX = 0x45
- IFT_FDDI = 0xf
- IFT_FIBRECHANNEL = 0x38
- IFT_FRAMERELAYINTERCONNECT = 0x3a
- IFT_FRAMERELAYMPI = 0x5c
- IFT_FRDLCIENDPT = 0xc1
- IFT_FRELAY = 0x20
- IFT_FRELAYDCE = 0x2c
- IFT_FRF16MFRBUNDLE = 0xa3
- IFT_FRFORWARD = 0x9e
- IFT_G703AT2MB = 0x43
- IFT_G703AT64K = 0x42
- IFT_GIF = 0xf0
- IFT_GIGABITETHERNET = 0x75
- IFT_GR303IDT = 0xb2
- IFT_GR303RDT = 0xb1
- IFT_H323GATEKEEPER = 0xa4
- IFT_H323PROXY = 0xa5
- IFT_HDH1822 = 0x3
- IFT_HDLC = 0x76
- IFT_HDSL2 = 0xa8
- IFT_HIPERLAN2 = 0xb7
- IFT_HIPPI = 0x2f
- IFT_HIPPIINTERFACE = 0x39
- IFT_HOSTPAD = 0x5a
- IFT_HSSI = 0x2e
- IFT_HY = 0xe
- IFT_IBM370PARCHAN = 0x48
- IFT_IDSL = 0x9a
- IFT_IEEE1394 = 0x90
- IFT_IEEE80211 = 0x47
- IFT_IEEE80212 = 0x37
- IFT_IEEE8023ADLAG = 0xa1
- IFT_IFGSN = 0x91
- IFT_IMT = 0xbe
- IFT_INTERLEAVE = 0x7c
- IFT_IP = 0x7e
- IFT_IPFORWARD = 0x8e
- IFT_IPOVERATM = 0x72
- IFT_IPOVERCDLC = 0x6d
- IFT_IPOVERCLAW = 0x6e
- IFT_IPSWITCH = 0x4e
- IFT_ISDN = 0x3f
- IFT_ISDNBASIC = 0x14
- IFT_ISDNPRIMARY = 0x15
- IFT_ISDNS = 0x4b
- IFT_ISDNU = 0x4c
- IFT_ISO88022LLC = 0x29
- IFT_ISO88023 = 0x7
- IFT_ISO88024 = 0x8
- IFT_ISO88025 = 0x9
- IFT_ISO88025CRFPINT = 0x62
- IFT_ISO88025DTR = 0x56
- IFT_ISO88025FIBER = 0x73
- IFT_ISO88026 = 0xa
- IFT_ISUP = 0xb3
- IFT_L2VLAN = 0x87
- IFT_L3IPVLAN = 0x88
- IFT_L3IPXVLAN = 0x89
- IFT_LAPB = 0x10
- IFT_LAPD = 0x4d
- IFT_LAPF = 0x77
- IFT_LOCALTALK = 0x2a
- IFT_LOOP = 0x18
- IFT_MEDIAMAILOVERIP = 0x8b
- IFT_MFSIGLINK = 0xa7
- IFT_MIOX25 = 0x26
- IFT_MODEM = 0x30
- IFT_MPC = 0x71
- IFT_MPLS = 0xa6
- IFT_MPLSTUNNEL = 0x96
- IFT_MSDSL = 0x8f
- IFT_MVL = 0xbf
- IFT_MYRINET = 0x63
- IFT_NFAS = 0xaf
- IFT_NSIP = 0x1b
- IFT_OPTICALCHANNEL = 0xc3
- IFT_OPTICALTRANSPORT = 0xc4
- IFT_OTHER = 0x1
- IFT_P10 = 0xc
- IFT_P80 = 0xd
- IFT_PARA = 0x22
- IFT_PFLOG = 0xf5
- IFT_PFSYNC = 0xf6
- IFT_PLC = 0xae
- IFT_POS = 0xab
- IFT_PPP = 0x17
- IFT_PPPMULTILINKBUNDLE = 0x6c
- IFT_PROPBWAP2MP = 0xb8
- IFT_PROPCNLS = 0x59
- IFT_PROPDOCSWIRELESSDOWNSTREAM = 0xb5
- IFT_PROPDOCSWIRELESSMACLAYER = 0xb4
- IFT_PROPDOCSWIRELESSUPSTREAM = 0xb6
- IFT_PROPMUX = 0x36
- IFT_PROPVIRTUAL = 0x35
- IFT_PROPWIRELESSP2P = 0x9d
- IFT_PTPSERIAL = 0x16
- IFT_PVC = 0xf1
- IFT_QLLC = 0x44
- IFT_RADIOMAC = 0xbc
- IFT_RADSL = 0x5f
- IFT_REACHDSL = 0xc0
- IFT_RFC1483 = 0x9f
- IFT_RS232 = 0x21
- IFT_RSRB = 0x4f
- IFT_SDLC = 0x11
- IFT_SDSL = 0x60
- IFT_SHDSL = 0xa9
- IFT_SIP = 0x1f
- IFT_SLIP = 0x1c
- IFT_SMDSDXI = 0x2b
- IFT_SMDSICIP = 0x34
- IFT_SONET = 0x27
- IFT_SONETOVERHEADCHANNEL = 0xb9
- IFT_SONETPATH = 0x32
- IFT_SONETVT = 0x33
- IFT_SRP = 0x97
- IFT_SS7SIGLINK = 0x9c
- IFT_STACKTOSTACK = 0x6f
- IFT_STARLAN = 0xb
- IFT_STF = 0xf3
- IFT_T1 = 0x12
- IFT_TDLC = 0x74
- IFT_TERMPAD = 0x5b
- IFT_TR008 = 0xb0
- IFT_TRANSPHDLC = 0x7b
- IFT_TUNNEL = 0x83
- IFT_ULTRA = 0x1d
- IFT_USB = 0xa0
- IFT_V11 = 0x40
- IFT_V35 = 0x2d
- IFT_V36 = 0x41
- IFT_V37 = 0x78
- IFT_VDSL = 0x61
- IFT_VIRTUALIPADDRESS = 0x70
- IFT_VOICEEM = 0x64
- IFT_VOICEENCAP = 0x67
- IFT_VOICEFXO = 0x65
- IFT_VOICEFXS = 0x66
- IFT_VOICEOVERATM = 0x98
- IFT_VOICEOVERFRAMERELAY = 0x99
- IFT_VOICEOVERIP = 0x68
- IFT_X213 = 0x5d
- IFT_X25 = 0x5
- IFT_X25DDN = 0x4
- IFT_X25HUNTGROUP = 0x7a
- IFT_X25MLP = 0x79
- IFT_X25PLE = 0x28
- IFT_XETHER = 0x1a
- IGNBRK = 0x1
- IGNCR = 0x80
- IGNPAR = 0x4
- IMAXBEL = 0x2000
- INLCR = 0x40
- INPCK = 0x10
- IN_CLASSA_HOST = 0xffffff
- IN_CLASSA_MAX = 0x80
- IN_CLASSA_NET = 0xff000000
- IN_CLASSA_NSHIFT = 0x18
- IN_CLASSB_HOST = 0xffff
- IN_CLASSB_MAX = 0x10000
- IN_CLASSB_NET = 0xffff0000
- IN_CLASSB_NSHIFT = 0x10
- IN_CLASSC_HOST = 0xff
- IN_CLASSC_NET = 0xffffff00
- IN_CLASSC_NSHIFT = 0x8
- IN_CLASSD_HOST = 0xfffffff
- IN_CLASSD_NET = 0xf0000000
- IN_CLASSD_NSHIFT = 0x1c
- IN_LOOPBACKNET = 0x7f
- IPPROTO_3PC = 0x22
- IPPROTO_ADFS = 0x44
- IPPROTO_AH = 0x33
- IPPROTO_AHIP = 0x3d
- IPPROTO_APES = 0x63
- IPPROTO_ARGUS = 0xd
- IPPROTO_AX25 = 0x5d
- IPPROTO_BHA = 0x31
- IPPROTO_BLT = 0x1e
- IPPROTO_BRSATMON = 0x4c
- IPPROTO_CARP = 0x70
- IPPROTO_CFTP = 0x3e
- IPPROTO_CHAOS = 0x10
- IPPROTO_CMTP = 0x26
- IPPROTO_CPHB = 0x49
- IPPROTO_CPNX = 0x48
- IPPROTO_DDP = 0x25
- IPPROTO_DGP = 0x56
- IPPROTO_DIVERT = 0xfe
- IPPROTO_DONE = 0x101
- IPPROTO_DSTOPTS = 0x3c
- IPPROTO_EGP = 0x8
- IPPROTO_EMCON = 0xe
- IPPROTO_ENCAP = 0x62
- IPPROTO_EON = 0x50
- IPPROTO_ESP = 0x32
- IPPROTO_ETHERIP = 0x61
- IPPROTO_FRAGMENT = 0x2c
- IPPROTO_GGP = 0x3
- IPPROTO_GMTP = 0x64
- IPPROTO_GRE = 0x2f
- IPPROTO_HELLO = 0x3f
- IPPROTO_HMP = 0x14
- IPPROTO_HOPOPTS = 0x0
- IPPROTO_ICMP = 0x1
- IPPROTO_ICMPV6 = 0x3a
- IPPROTO_IDP = 0x16
- IPPROTO_IDPR = 0x23
- IPPROTO_IDRP = 0x2d
- IPPROTO_IGMP = 0x2
- IPPROTO_IGP = 0x55
- IPPROTO_IGRP = 0x58
- IPPROTO_IL = 0x28
- IPPROTO_INLSP = 0x34
- IPPROTO_INP = 0x20
- IPPROTO_IP = 0x0
- IPPROTO_IPCOMP = 0x6c
- IPPROTO_IPCV = 0x47
- IPPROTO_IPEIP = 0x5e
- IPPROTO_IPIP = 0x4
- IPPROTO_IPPC = 0x43
- IPPROTO_IPV4 = 0x4
- IPPROTO_IPV6 = 0x29
- IPPROTO_IRTP = 0x1c
- IPPROTO_KRYPTOLAN = 0x41
- IPPROTO_LARP = 0x5b
- IPPROTO_LEAF1 = 0x19
- IPPROTO_LEAF2 = 0x1a
- IPPROTO_MAX = 0x100
- IPPROTO_MAXID = 0x34
- IPPROTO_MEAS = 0x13
- IPPROTO_MHRP = 0x30
- IPPROTO_MICP = 0x5f
- IPPROTO_MOBILE = 0x37
- IPPROTO_MTP = 0x5c
- IPPROTO_MUX = 0x12
- IPPROTO_ND = 0x4d
- IPPROTO_NHRP = 0x36
- IPPROTO_NONE = 0x3b
- IPPROTO_NSP = 0x1f
- IPPROTO_NVPII = 0xb
- IPPROTO_OSPFIGP = 0x59
- IPPROTO_PFSYNC = 0xf0
- IPPROTO_PGM = 0x71
- IPPROTO_PIGP = 0x9
- IPPROTO_PIM = 0x67
- IPPROTO_PRM = 0x15
- IPPROTO_PUP = 0xc
- IPPROTO_PVP = 0x4b
- IPPROTO_RAW = 0xff
- IPPROTO_RCCMON = 0xa
- IPPROTO_RDP = 0x1b
- IPPROTO_ROUTING = 0x2b
- IPPROTO_RSVP = 0x2e
- IPPROTO_RVD = 0x42
- IPPROTO_SATEXPAK = 0x40
- IPPROTO_SATMON = 0x45
- IPPROTO_SCCSP = 0x60
- IPPROTO_SCTP = 0x84
- IPPROTO_SDRP = 0x2a
- IPPROTO_SEP = 0x21
- IPPROTO_SKIP = 0x39
- IPPROTO_SRPC = 0x5a
- IPPROTO_ST = 0x7
- IPPROTO_SVMTP = 0x52
- IPPROTO_SWIPE = 0x35
- IPPROTO_TCF = 0x57
- IPPROTO_TCP = 0x6
- IPPROTO_TLSP = 0x38
- IPPROTO_TP = 0x1d
- IPPROTO_TPXX = 0x27
- IPPROTO_TRUNK1 = 0x17
- IPPROTO_TRUNK2 = 0x18
- IPPROTO_TTP = 0x54
- IPPROTO_UDP = 0x11
- IPPROTO_UNKNOWN = 0x102
- IPPROTO_VINES = 0x53
- IPPROTO_VISA = 0x46
- IPPROTO_VMTP = 0x51
- IPPROTO_WBEXPAK = 0x4f
- IPPROTO_WBMON = 0x4e
- IPPROTO_WSN = 0x4a
- IPPROTO_XNET = 0xf
- IPPROTO_XTP = 0x24
- IPV6_AUTOFLOWLABEL = 0x3b
- IPV6_BINDV6ONLY = 0x1b
- IPV6_CHECKSUM = 0x1a
- IPV6_DEFAULT_MULTICAST_HOPS = 0x1
- IPV6_DEFAULT_MULTICAST_LOOP = 0x1
- IPV6_DEFHLIM = 0x40
- IPV6_DONTFRAG = 0x3e
- IPV6_DSTOPTS = 0x32
- IPV6_FAITH = 0x1d
- IPV6_FLOWINFO_MASK = 0xffffff0f
- IPV6_FLOWLABEL_MASK = 0xffff0f00
- IPV6_FRAGTTL = 0x78
- IPV6_FW_ADD = 0x1e
- IPV6_FW_DEL = 0x1f
- IPV6_FW_FLUSH = 0x20
- IPV6_FW_GET = 0x22
- IPV6_FW_ZERO = 0x21
- IPV6_HLIMDEC = 0x1
- IPV6_HOPLIMIT = 0x2f
- IPV6_HOPOPTS = 0x31
- IPV6_IPSEC_POLICY = 0x1c
- IPV6_JOIN_GROUP = 0xc
- IPV6_LEAVE_GROUP = 0xd
- IPV6_MAXHLIM = 0xff
- IPV6_MAXPACKET = 0xffff
- IPV6_MMTU = 0x500
- IPV6_MSFILTER = 0x4a
- IPV6_MULTICAST_HOPS = 0xa
- IPV6_MULTICAST_IF = 0x9
- IPV6_MULTICAST_LOOP = 0xb
- IPV6_NEXTHOP = 0x30
- IPV6_PATHMTU = 0x2c
- IPV6_PKTINFO = 0x2e
- IPV6_PKTOPTIONS = 0x34
- IPV6_PORTRANGE = 0xe
- IPV6_PORTRANGE_DEFAULT = 0x0
- IPV6_PORTRANGE_HIGH = 0x1
- IPV6_PORTRANGE_LOW = 0x2
- IPV6_PREFER_TEMPADDR = 0x3f
- IPV6_RECVDSTOPTS = 0x28
- IPV6_RECVHOPLIMIT = 0x25
- IPV6_RECVHOPOPTS = 0x27
- IPV6_RECVPATHMTU = 0x2b
- IPV6_RECVPKTINFO = 0x24
- IPV6_RECVRTHDR = 0x26
- IPV6_RECVTCLASS = 0x39
- IPV6_RTHDR = 0x33
- IPV6_RTHDRDSTOPTS = 0x23
- IPV6_RTHDR_LOOSE = 0x0
- IPV6_RTHDR_STRICT = 0x1
- IPV6_RTHDR_TYPE_0 = 0x0
- IPV6_SOCKOPT_RESERVED1 = 0x3
- IPV6_TCLASS = 0x3d
- IPV6_UNICAST_HOPS = 0x4
- IPV6_USE_MIN_MTU = 0x2a
- IPV6_V6ONLY = 0x1b
- IPV6_VERSION = 0x60
- IPV6_VERSION_MASK = 0xf0
- IP_ADD_MEMBERSHIP = 0xc
- IP_DEFAULT_MULTICAST_LOOP = 0x1
- IP_DEFAULT_MULTICAST_TTL = 0x1
- IP_DF = 0x4000
- IP_DROP_MEMBERSHIP = 0xd
- IP_DUMMYNET_CONFIGURE = 0x3c
- IP_DUMMYNET_DEL = 0x3d
- IP_DUMMYNET_FLUSH = 0x3e
- IP_DUMMYNET_GET = 0x40
- IP_FAITH = 0x16
- IP_FW_ADD = 0x32
- IP_FW_DEL = 0x33
- IP_FW_FLUSH = 0x34
- IP_FW_GET = 0x36
- IP_FW_RESETLOG = 0x37
- IP_FW_ZERO = 0x35
- IP_HDRINCL = 0x2
- IP_IPSEC_POLICY = 0x15
- IP_MAXPACKET = 0xffff
- IP_MAX_MEMBERSHIPS = 0x14
- IP_MF = 0x2000
- IP_MINTTL = 0x42
- IP_MSS = 0x240
- IP_MULTICAST_IF = 0x9
- IP_MULTICAST_LOOP = 0xb
- IP_MULTICAST_TTL = 0xa
- IP_MULTICAST_VIF = 0xe
- IP_OFFMASK = 0x1fff
- IP_OPTIONS = 0x1
- IP_PORTRANGE = 0x13
- IP_PORTRANGE_DEFAULT = 0x0
- IP_PORTRANGE_HIGH = 0x1
- IP_PORTRANGE_LOW = 0x2
- IP_RECVDSTADDR = 0x7
- IP_RECVIF = 0x14
- IP_RECVOPTS = 0x5
- IP_RECVRETOPTS = 0x6
- IP_RECVTTL = 0x41
- IP_RETOPTS = 0x8
- IP_RF = 0x8000
- IP_RSVP_OFF = 0x10
- IP_RSVP_ON = 0xf
- IP_RSVP_VIF_OFF = 0x12
- IP_RSVP_VIF_ON = 0x11
- IP_TOS = 0x3
- IP_TTL = 0x4
- ISIG = 0x80
- ISTRIP = 0x20
- IXANY = 0x800
- IXOFF = 0x400
- IXON = 0x200
- LOCK_EX = 0x2
- LOCK_NB = 0x4
- LOCK_SH = 0x1
- LOCK_UN = 0x8
- MADV_AUTOSYNC = 0x7
- MADV_CONTROL_END = 0xb
- MADV_CONTROL_START = 0xa
- MADV_CORE = 0x9
- MADV_DONTNEED = 0x4
- MADV_FREE = 0x5
- MADV_INVAL = 0xa
- MADV_NOCORE = 0x8
- MADV_NORMAL = 0x0
- MADV_NOSYNC = 0x6
- MADV_RANDOM = 0x1
- MADV_SEQUENTIAL = 0x2
- MADV_SETMAP = 0xb
- MADV_WILLNEED = 0x3
- MAP_ANON = 0x1000
- MAP_COPY = 0x2
- MAP_FILE = 0x0
- MAP_FIXED = 0x10
- MAP_HASSEMAPHORE = 0x200
- MAP_INHERIT = 0x80
- MAP_NOCORE = 0x20000
- MAP_NOEXTEND = 0x100
- MAP_NORESERVE = 0x40
- MAP_NOSYNC = 0x800
- MAP_PRIVATE = 0x2
- MAP_RENAME = 0x20
- MAP_SHARED = 0x1
- MAP_SIZEALIGN = 0x40000
- MAP_STACK = 0x400
- MAP_TRYFIXED = 0x10000
- MAP_VPAGETABLE = 0x2000
- MCL_CURRENT = 0x1
- MCL_FUTURE = 0x2
- MSG_CTRUNC = 0x20
- MSG_DONTROUTE = 0x4
- MSG_DONTWAIT = 0x80
- MSG_EOF = 0x100
- MSG_EOR = 0x8
- MSG_FBLOCKING = 0x10000
- MSG_FMASK = 0xffff0000
- MSG_FNONBLOCKING = 0x20000
- MSG_NOSIGNAL = 0x400
- MSG_NOTIFICATION = 0x200
- MSG_OOB = 0x1
- MSG_PEEK = 0x2
- MSG_SYNC = 0x800
- MSG_TRUNC = 0x10
- MSG_WAITALL = 0x40
- MS_ASYNC = 0x1
- MS_INVALIDATE = 0x2
- MS_SYNC = 0x0
- NAME_MAX = 0xff
- NET_RT_DUMP = 0x1
- NET_RT_FLAGS = 0x2
- NET_RT_IFLIST = 0x3
- NET_RT_MAXID = 0x4
- NOFLSH = 0x80000000
- NOTE_ATTRIB = 0x8
- NOTE_CHILD = 0x4
- NOTE_DELETE = 0x1
- NOTE_EXEC = 0x20000000
- NOTE_EXIT = 0x80000000
- NOTE_EXTEND = 0x4
- NOTE_FORK = 0x40000000
- NOTE_LINK = 0x10
- NOTE_LOWAT = 0x1
- NOTE_OOB = 0x2
- NOTE_PCTRLMASK = 0xf0000000
- NOTE_PDATAMASK = 0xfffff
- NOTE_RENAME = 0x20
- NOTE_REVOKE = 0x40
- NOTE_TRACK = 0x1
- NOTE_TRACKERR = 0x2
- NOTE_WRITE = 0x2
- OCRNL = 0x10
- ONLCR = 0x2
- ONLRET = 0x40
- ONOCR = 0x20
- ONOEOT = 0x8
- OPOST = 0x1
- O_ACCMODE = 0x3
- O_APPEND = 0x8
- O_ASYNC = 0x40
- O_CLOEXEC = 0x20000
- O_CREAT = 0x200
- O_DIRECT = 0x10000
- O_DIRECTORY = 0x8000000
- O_EXCL = 0x800
- O_EXLOCK = 0x20
- O_FAPPEND = 0x100000
- O_FASYNCWRITE = 0x800000
- O_FBLOCKING = 0x40000
- O_FBUFFERED = 0x2000000
- O_FMASK = 0x7fc0000
- O_FNONBLOCKING = 0x80000
- O_FOFFSET = 0x200000
- O_FSYNC = 0x80
- O_FSYNCWRITE = 0x400000
- O_FUNBUFFERED = 0x1000000
- O_MAPONREAD = 0x4000000
- O_NDELAY = 0x4
- O_NOCTTY = 0x8000
- O_NOFOLLOW = 0x100
- O_NONBLOCK = 0x4
- O_RDONLY = 0x0
- O_RDWR = 0x2
- O_SHLOCK = 0x10
- O_SYNC = 0x80
- O_TRUNC = 0x400
- O_WRONLY = 0x1
- PARENB = 0x1000
- PARMRK = 0x8
- PARODD = 0x2000
- PENDIN = 0x20000000
- PRIO_PGRP = 0x1
- PRIO_PROCESS = 0x0
- PRIO_USER = 0x2
- PROT_EXEC = 0x4
- PROT_NONE = 0x0
- PROT_READ = 0x1
- PROT_WRITE = 0x2
- RLIMIT_AS = 0xa
- RLIMIT_CORE = 0x4
- RLIMIT_CPU = 0x0
- RLIMIT_DATA = 0x2
- RLIMIT_FSIZE = 0x1
- RLIMIT_NOFILE = 0x8
- RLIMIT_STACK = 0x3
- RLIM_INFINITY = 0x7fffffffffffffff
- RTAX_AUTHOR = 0x6
- RTAX_BRD = 0x7
- RTAX_DST = 0x0
- RTAX_GATEWAY = 0x1
- RTAX_GENMASK = 0x3
- RTAX_IFA = 0x5
- RTAX_IFP = 0x4
- RTAX_MAX = 0xb
- RTAX_MPLS1 = 0x8
- RTAX_MPLS2 = 0x9
- RTAX_MPLS3 = 0xa
- RTAX_NETMASK = 0x2
- RTA_AUTHOR = 0x40
- RTA_BRD = 0x80
- RTA_DST = 0x1
- RTA_GATEWAY = 0x2
- RTA_GENMASK = 0x8
- RTA_IFA = 0x20
- RTA_IFP = 0x10
- RTA_MPLS1 = 0x100
- RTA_MPLS2 = 0x200
- RTA_MPLS3 = 0x400
- RTA_NETMASK = 0x4
- RTF_BLACKHOLE = 0x1000
- RTF_BROADCAST = 0x400000
- RTF_CLONING = 0x100
- RTF_DONE = 0x40
- RTF_DYNAMIC = 0x10
- RTF_GATEWAY = 0x2
- RTF_HOST = 0x4
- RTF_LLINFO = 0x400
- RTF_LOCAL = 0x200000
- RTF_MODIFIED = 0x20
- RTF_MPLSOPS = 0x1000000
- RTF_MULTICAST = 0x800000
- RTF_PINNED = 0x100000
- RTF_PRCLONING = 0x10000
- RTF_PROTO1 = 0x8000
- RTF_PROTO2 = 0x4000
- RTF_PROTO3 = 0x40000
- RTF_REJECT = 0x8
- RTF_STATIC = 0x800
- RTF_UP = 0x1
- RTF_WASCLONED = 0x20000
- RTF_XRESOLVE = 0x200
- RTM_ADD = 0x1
- RTM_CHANGE = 0x3
- RTM_DELADDR = 0xd
- RTM_DELETE = 0x2
- RTM_DELMADDR = 0x10
- RTM_GET = 0x4
- RTM_IEEE80211 = 0x12
- RTM_IFANNOUNCE = 0x11
- RTM_IFINFO = 0xe
- RTM_LOCK = 0x8
- RTM_LOSING = 0x5
- RTM_MISS = 0x7
- RTM_NEWADDR = 0xc
- RTM_NEWMADDR = 0xf
- RTM_OLDADD = 0x9
- RTM_OLDDEL = 0xa
- RTM_REDIRECT = 0x6
- RTM_RESOLVE = 0xb
- RTM_RTTUNIT = 0xf4240
- RTM_VERSION = 0x6
- RTV_EXPIRE = 0x4
- RTV_HOPCOUNT = 0x2
- RTV_IWCAPSEGS = 0x400
- RTV_IWMAXSEGS = 0x200
- RTV_MSL = 0x100
- RTV_MTU = 0x1
- RTV_RPIPE = 0x8
- RTV_RTT = 0x40
- RTV_RTTVAR = 0x80
- RTV_SPIPE = 0x10
- RTV_SSTHRESH = 0x20
- RUSAGE_CHILDREN = -0x1
- RUSAGE_SELF = 0x0
- SCM_CREDS = 0x3
- SCM_RIGHTS = 0x1
- SCM_TIMESTAMP = 0x2
- SHUT_RD = 0x0
- SHUT_RDWR = 0x2
- SHUT_WR = 0x1
- SIOCADDMULTI = 0x80206931
- SIOCADDRT = 0x8030720a
- SIOCAIFADDR = 0x8040691a
- SIOCALIFADDR = 0x8118691b
- SIOCATMARK = 0x40047307
- SIOCDELMULTI = 0x80206932
- SIOCDELRT = 0x8030720b
- SIOCDIFADDR = 0x80206919
- SIOCDIFPHYADDR = 0x80206949
- SIOCDLIFADDR = 0x8118691d
- SIOCGDRVSPEC = 0xc01c697b
- SIOCGETSGCNT = 0xc0147210
- SIOCGETVIFCNT = 0xc014720f
- SIOCGHIWAT = 0x40047301
- SIOCGIFADDR = 0xc0206921
- SIOCGIFBRDADDR = 0xc0206923
- SIOCGIFCAP = 0xc020691f
- SIOCGIFCONF = 0xc0086924
- SIOCGIFDATA = 0xc0206926
- SIOCGIFDSTADDR = 0xc0206922
- SIOCGIFFLAGS = 0xc0206911
- SIOCGIFGENERIC = 0xc020693a
- SIOCGIFGMEMB = 0xc024698a
- SIOCGIFINDEX = 0xc0206920
- SIOCGIFMEDIA = 0xc0286938
- SIOCGIFMETRIC = 0xc0206917
- SIOCGIFMTU = 0xc0206933
- SIOCGIFNETMASK = 0xc0206925
- SIOCGIFPDSTADDR = 0xc0206948
- SIOCGIFPHYS = 0xc0206935
- SIOCGIFPOLLCPU = 0xc020697e
- SIOCGIFPSRCADDR = 0xc0206947
- SIOCGIFSTATUS = 0xc331693b
- SIOCGIFTSOLEN = 0xc0206980
- SIOCGLIFADDR = 0xc118691c
- SIOCGLIFPHYADDR = 0xc118694b
- SIOCGLOWAT = 0x40047303
- SIOCGPGRP = 0x40047309
- SIOCGPRIVATE_0 = 0xc0206950
- SIOCGPRIVATE_1 = 0xc0206951
- SIOCIFCREATE = 0xc020697a
- SIOCIFCREATE2 = 0xc020697c
- SIOCIFDESTROY = 0x80206979
- SIOCIFGCLONERS = 0xc00c6978
- SIOCSDRVSPEC = 0x801c697b
- SIOCSHIWAT = 0x80047300
- SIOCSIFADDR = 0x8020690c
- SIOCSIFBRDADDR = 0x80206913
- SIOCSIFCAP = 0x8020691e
- SIOCSIFDSTADDR = 0x8020690e
- SIOCSIFFLAGS = 0x80206910
- SIOCSIFGENERIC = 0x80206939
- SIOCSIFLLADDR = 0x8020693c
- SIOCSIFMEDIA = 0xc0206937
- SIOCSIFMETRIC = 0x80206918
- SIOCSIFMTU = 0x80206934
- SIOCSIFNAME = 0x80206928
- SIOCSIFNETMASK = 0x80206916
- SIOCSIFPHYADDR = 0x80406946
- SIOCSIFPHYS = 0x80206936
- SIOCSIFPOLLCPU = 0x8020697d
- SIOCSIFTSOLEN = 0x8020697f
- SIOCSLIFPHYADDR = 0x8118694a
- SIOCSLOWAT = 0x80047302
- SIOCSPGRP = 0x80047308
- SOCK_DGRAM = 0x2
- SOCK_MAXADDRLEN = 0xff
- SOCK_RAW = 0x3
- SOCK_RDM = 0x4
- SOCK_SEQPACKET = 0x5
- SOCK_STREAM = 0x1
- SOL_SOCKET = 0xffff
- SOMAXCONN = 0x80
- SO_ACCEPTCONN = 0x2
- SO_ACCEPTFILTER = 0x1000
- SO_BROADCAST = 0x20
- SO_DEBUG = 0x1
- SO_DONTROUTE = 0x10
- SO_ERROR = 0x1007
- SO_KEEPALIVE = 0x8
- SO_LINGER = 0x80
- SO_NOSIGPIPE = 0x800
- SO_OOBINLINE = 0x100
- SO_RCVBUF = 0x1002
- SO_RCVLOWAT = 0x1004
- SO_RCVTIMEO = 0x1006
- SO_REUSEADDR = 0x4
- SO_REUSEPORT = 0x200
- SO_SNDBUF = 0x1001
- SO_SNDLOWAT = 0x1003
- SO_SNDSPACE = 0x100a
- SO_SNDTIMEO = 0x1005
- SO_TIMESTAMP = 0x400
- SO_TYPE = 0x1008
- SO_USELOOPBACK = 0x40
- TCIFLUSH = 0x1
- TCIOFLUSH = 0x3
- TCOFLUSH = 0x2
- TCP_FASTKEEP = 0x80
- TCP_KEEPCNT = 0x400
- TCP_KEEPIDLE = 0x100
- TCP_KEEPINIT = 0x20
- TCP_KEEPINTVL = 0x200
- TCP_MAXBURST = 0x4
- TCP_MAXHLEN = 0x3c
- TCP_MAXOLEN = 0x28
- TCP_MAXSEG = 0x2
- TCP_MAXWIN = 0xffff
- TCP_MAX_WINSHIFT = 0xe
- TCP_MINMSS = 0x100
- TCP_MIN_WINSHIFT = 0x5
- TCP_MSS = 0x200
- TCP_NODELAY = 0x1
- TCP_NOOPT = 0x8
- TCP_NOPUSH = 0x4
- TCP_SIGNATURE_ENABLE = 0x10
- TCSAFLUSH = 0x2
- TIOCCBRK = 0x2000747a
- TIOCCDTR = 0x20007478
- TIOCCONS = 0x80047462
- TIOCDCDTIMESTAMP = 0x40087458
- TIOCDRAIN = 0x2000745e
- TIOCEXCL = 0x2000740d
- TIOCEXT = 0x80047460
- TIOCFLUSH = 0x80047410
- TIOCGDRAINWAIT = 0x40047456
- TIOCGETA = 0x402c7413
- TIOCGETD = 0x4004741a
- TIOCGPGRP = 0x40047477
- TIOCGSID = 0x40047463
- TIOCGSIZE = 0x40087468
- TIOCGWINSZ = 0x40087468
- TIOCISPTMASTER = 0x20007455
- TIOCMBIC = 0x8004746b
- TIOCMBIS = 0x8004746c
- TIOCMGDTRWAIT = 0x4004745a
- TIOCMGET = 0x4004746a
- TIOCMODG = 0x40047403
- TIOCMODS = 0x80047404
- TIOCMSDTRWAIT = 0x8004745b
- TIOCMSET = 0x8004746d
- TIOCM_CAR = 0x40
- TIOCM_CD = 0x40
- TIOCM_CTS = 0x20
- TIOCM_DSR = 0x100
- TIOCM_DTR = 0x2
- TIOCM_LE = 0x1
- TIOCM_RI = 0x80
- TIOCM_RNG = 0x80
- TIOCM_RTS = 0x4
- TIOCM_SR = 0x10
- TIOCM_ST = 0x8
- TIOCNOTTY = 0x20007471
- TIOCNXCL = 0x2000740e
- TIOCOUTQ = 0x40047473
- TIOCPKT = 0x80047470
- TIOCPKT_DATA = 0x0
- TIOCPKT_DOSTOP = 0x20
- TIOCPKT_FLUSHREAD = 0x1
- TIOCPKT_FLUSHWRITE = 0x2
- TIOCPKT_IOCTL = 0x40
- TIOCPKT_NOSTOP = 0x10
- TIOCPKT_START = 0x8
- TIOCPKT_STOP = 0x4
- TIOCREMOTE = 0x80047469
- TIOCSBRK = 0x2000747b
- TIOCSCTTY = 0x20007461
- TIOCSDRAINWAIT = 0x80047457
- TIOCSDTR = 0x20007479
- TIOCSETA = 0x802c7414
- TIOCSETAF = 0x802c7416
- TIOCSETAW = 0x802c7415
- TIOCSETD = 0x8004741b
- TIOCSIG = 0x2000745f
- TIOCSPGRP = 0x80047476
- TIOCSSIZE = 0x80087467
- TIOCSTART = 0x2000746e
- TIOCSTAT = 0x20007465
- TIOCSTI = 0x80017472
- TIOCSTOP = 0x2000746f
- TIOCSWINSZ = 0x80087467
- TIOCTIMESTAMP = 0x40087459
- TIOCUCNTL = 0x80047466
- TOSTOP = 0x400000
- VCHECKPT = 0x13
- VDISCARD = 0xf
- VDSUSP = 0xb
- VEOF = 0x0
- VEOL = 0x1
- VEOL2 = 0x2
- VERASE = 0x3
- VERASE2 = 0x7
- VINTR = 0x8
- VKILL = 0x5
- VLNEXT = 0xe
- VMIN = 0x10
- VQUIT = 0x9
- VREPRINT = 0x6
- VSTART = 0xc
- VSTATUS = 0x12
- VSTOP = 0xd
- VSUSP = 0xa
- VTIME = 0x11
- VWERASE = 0x4
- WCONTINUED = 0x4
- WCOREFLAG = 0x80
- WLINUXCLONE = 0x80000000
- WNOHANG = 0x1
- WSTOPPED = 0x7f
- WUNTRACED = 0x2
-)
-
-// Errors
-const (
- E2BIG = syscall.Errno(0x7)
- EACCES = syscall.Errno(0xd)
- EADDRINUSE = syscall.Errno(0x30)
- EADDRNOTAVAIL = syscall.Errno(0x31)
- EAFNOSUPPORT = syscall.Errno(0x2f)
- EAGAIN = syscall.Errno(0x23)
- EALREADY = syscall.Errno(0x25)
- EASYNC = syscall.Errno(0x63)
- EAUTH = syscall.Errno(0x50)
- EBADF = syscall.Errno(0x9)
- EBADMSG = syscall.Errno(0x59)
- EBADRPC = syscall.Errno(0x48)
- EBUSY = syscall.Errno(0x10)
- ECANCELED = syscall.Errno(0x55)
- ECHILD = syscall.Errno(0xa)
- ECONNABORTED = syscall.Errno(0x35)
- ECONNREFUSED = syscall.Errno(0x3d)
- ECONNRESET = syscall.Errno(0x36)
- EDEADLK = syscall.Errno(0xb)
- EDESTADDRREQ = syscall.Errno(0x27)
- EDOM = syscall.Errno(0x21)
- EDOOFUS = syscall.Errno(0x58)
- EDQUOT = syscall.Errno(0x45)
- EEXIST = syscall.Errno(0x11)
- EFAULT = syscall.Errno(0xe)
- EFBIG = syscall.Errno(0x1b)
- EFTYPE = syscall.Errno(0x4f)
- EHOSTDOWN = syscall.Errno(0x40)
- EHOSTUNREACH = syscall.Errno(0x41)
- EIDRM = syscall.Errno(0x52)
- EILSEQ = syscall.Errno(0x56)
- EINPROGRESS = syscall.Errno(0x24)
- EINTR = syscall.Errno(0x4)
- EINVAL = syscall.Errno(0x16)
- EIO = syscall.Errno(0x5)
- EISCONN = syscall.Errno(0x38)
- EISDIR = syscall.Errno(0x15)
- ELAST = syscall.Errno(0x63)
- ELOOP = syscall.Errno(0x3e)
- EMFILE = syscall.Errno(0x18)
- EMLINK = syscall.Errno(0x1f)
- EMSGSIZE = syscall.Errno(0x28)
- EMULTIHOP = syscall.Errno(0x5a)
- ENAMETOOLONG = syscall.Errno(0x3f)
- ENEEDAUTH = syscall.Errno(0x51)
- ENETDOWN = syscall.Errno(0x32)
- ENETRESET = syscall.Errno(0x34)
- ENETUNREACH = syscall.Errno(0x33)
- ENFILE = syscall.Errno(0x17)
- ENOATTR = syscall.Errno(0x57)
- ENOBUFS = syscall.Errno(0x37)
- ENODEV = syscall.Errno(0x13)
- ENOENT = syscall.Errno(0x2)
- ENOEXEC = syscall.Errno(0x8)
- ENOLCK = syscall.Errno(0x4d)
- ENOLINK = syscall.Errno(0x5b)
- ENOMEDIUM = syscall.Errno(0x5d)
- ENOMEM = syscall.Errno(0xc)
- ENOMSG = syscall.Errno(0x53)
- ENOPROTOOPT = syscall.Errno(0x2a)
- ENOSPC = syscall.Errno(0x1c)
- ENOSYS = syscall.Errno(0x4e)
- ENOTBLK = syscall.Errno(0xf)
- ENOTCONN = syscall.Errno(0x39)
- ENOTDIR = syscall.Errno(0x14)
- ENOTEMPTY = syscall.Errno(0x42)
- ENOTSOCK = syscall.Errno(0x26)
- ENOTSUP = syscall.Errno(0x2d)
- ENOTTY = syscall.Errno(0x19)
- ENXIO = syscall.Errno(0x6)
- EOPNOTSUPP = syscall.Errno(0x2d)
- EOVERFLOW = syscall.Errno(0x54)
- EPERM = syscall.Errno(0x1)
- EPFNOSUPPORT = syscall.Errno(0x2e)
- EPIPE = syscall.Errno(0x20)
- EPROCLIM = syscall.Errno(0x43)
- EPROCUNAVAIL = syscall.Errno(0x4c)
- EPROGMISMATCH = syscall.Errno(0x4b)
- EPROGUNAVAIL = syscall.Errno(0x4a)
- EPROTO = syscall.Errno(0x5c)
- EPROTONOSUPPORT = syscall.Errno(0x2b)
- EPROTOTYPE = syscall.Errno(0x29)
- ERANGE = syscall.Errno(0x22)
- EREMOTE = syscall.Errno(0x47)
- EROFS = syscall.Errno(0x1e)
- ERPCMISMATCH = syscall.Errno(0x49)
- ESHUTDOWN = syscall.Errno(0x3a)
- ESOCKTNOSUPPORT = syscall.Errno(0x2c)
- ESPIPE = syscall.Errno(0x1d)
- ESRCH = syscall.Errno(0x3)
- ESTALE = syscall.Errno(0x46)
- ETIMEDOUT = syscall.Errno(0x3c)
- ETOOMANYREFS = syscall.Errno(0x3b)
- ETXTBSY = syscall.Errno(0x1a)
- EUNUSED94 = syscall.Errno(0x5e)
- EUNUSED95 = syscall.Errno(0x5f)
- EUNUSED96 = syscall.Errno(0x60)
- EUNUSED97 = syscall.Errno(0x61)
- EUNUSED98 = syscall.Errno(0x62)
- EUSERS = syscall.Errno(0x44)
- EWOULDBLOCK = syscall.Errno(0x23)
- EXDEV = syscall.Errno(0x12)
-)
-
-// Signals
-const (
- SIGABRT = syscall.Signal(0x6)
- SIGALRM = syscall.Signal(0xe)
- SIGBUS = syscall.Signal(0xa)
- SIGCHLD = syscall.Signal(0x14)
- SIGCKPT = syscall.Signal(0x21)
- SIGCKPTEXIT = syscall.Signal(0x22)
- SIGCONT = syscall.Signal(0x13)
- SIGEMT = syscall.Signal(0x7)
- SIGFPE = syscall.Signal(0x8)
- SIGHUP = syscall.Signal(0x1)
- SIGILL = syscall.Signal(0x4)
- SIGINFO = syscall.Signal(0x1d)
- SIGINT = syscall.Signal(0x2)
- SIGIO = syscall.Signal(0x17)
- SIGIOT = syscall.Signal(0x6)
- SIGKILL = syscall.Signal(0x9)
- SIGPIPE = syscall.Signal(0xd)
- SIGPROF = syscall.Signal(0x1b)
- SIGQUIT = syscall.Signal(0x3)
- SIGSEGV = syscall.Signal(0xb)
- SIGSTOP = syscall.Signal(0x11)
- SIGSYS = syscall.Signal(0xc)
- SIGTERM = syscall.Signal(0xf)
- SIGTHR = syscall.Signal(0x20)
- SIGTRAP = syscall.Signal(0x5)
- SIGTSTP = syscall.Signal(0x12)
- SIGTTIN = syscall.Signal(0x15)
- SIGTTOU = syscall.Signal(0x16)
- SIGURG = syscall.Signal(0x10)
- SIGUSR1 = syscall.Signal(0x1e)
- SIGUSR2 = syscall.Signal(0x1f)
- SIGVTALRM = syscall.Signal(0x1a)
- SIGWINCH = syscall.Signal(0x1c)
- SIGXCPU = syscall.Signal(0x18)
- SIGXFSZ = syscall.Signal(0x19)
-)
-
-// Error table
-var errors = [...]string{
- 1: "operation not permitted",
- 2: "no such file or directory",
- 3: "no such process",
- 4: "interrupted system call",
- 5: "input/output error",
- 6: "device not configured",
- 7: "argument list too long",
- 8: "exec format error",
- 9: "bad file descriptor",
- 10: "no child processes",
- 11: "resource deadlock avoided",
- 12: "cannot allocate memory",
- 13: "permission denied",
- 14: "bad address",
- 15: "block device required",
- 16: "device busy",
- 17: "file exists",
- 18: "cross-device link",
- 19: "operation not supported by device",
- 20: "not a directory",
- 21: "is a directory",
- 22: "invalid argument",
- 23: "too many open files in system",
- 24: "too many open files",
- 25: "inappropriate ioctl for device",
- 26: "text file busy",
- 27: "file too large",
- 28: "no space left on device",
- 29: "illegal seek",
- 30: "read-only file system",
- 31: "too many links",
- 32: "broken pipe",
- 33: "numerical argument out of domain",
- 34: "result too large",
- 35: "resource temporarily unavailable",
- 36: "operation now in progress",
- 37: "operation already in progress",
- 38: "socket operation on non-socket",
- 39: "destination address required",
- 40: "message too long",
- 41: "protocol wrong type for socket",
- 42: "protocol not available",
- 43: "protocol not supported",
- 44: "socket type not supported",
- 45: "operation not supported",
- 46: "protocol family not supported",
- 47: "address family not supported by protocol family",
- 48: "address already in use",
- 49: "can't assign requested address",
- 50: "network is down",
- 51: "network is unreachable",
- 52: "network dropped connection on reset",
- 53: "software caused connection abort",
- 54: "connection reset by peer",
- 55: "no buffer space available",
- 56: "socket is already connected",
- 57: "socket is not connected",
- 58: "can't send after socket shutdown",
- 59: "too many references: can't splice",
- 60: "operation timed out",
- 61: "connection refused",
- 62: "too many levels of symbolic links",
- 63: "file name too long",
- 64: "host is down",
- 65: "no route to host",
- 66: "directory not empty",
- 67: "too many processes",
- 68: "too many users",
- 69: "disc quota exceeded",
- 70: "stale NFS file handle",
- 71: "too many levels of remote in path",
- 72: "RPC struct is bad",
- 73: "RPC version wrong",
- 74: "RPC prog. not avail",
- 75: "program version wrong",
- 76: "bad procedure for program",
- 77: "no locks available",
- 78: "function not implemented",
- 79: "inappropriate file type or format",
- 80: "authentication error",
- 81: "need authenticator",
- 82: "identifier removed",
- 83: "no message of desired type",
- 84: "value too large to be stored in data type",
- 85: "operation canceled",
- 86: "illegal byte sequence",
- 87: "attribute not found",
- 88: "programming error",
- 89: "bad message",
- 90: "multihop attempted",
- 91: "link has been severed",
- 92: "protocol error",
- 93: "no medium found",
- 94: "unknown error: 94",
- 95: "unknown error: 95",
- 96: "unknown error: 96",
- 97: "unknown error: 97",
- 98: "unknown error: 98",
- 99: "unknown error: 99",
-}
-
-// Signal table
-var signals = [...]string{
- 1: "hangup",
- 2: "interrupt",
- 3: "quit",
- 4: "illegal instruction",
- 5: "trace/BPT trap",
- 6: "abort trap",
- 7: "EMT trap",
- 8: "floating point exception",
- 9: "killed",
- 10: "bus error",
- 11: "segmentation fault",
- 12: "bad system call",
- 13: "broken pipe",
- 14: "alarm clock",
- 15: "terminated",
- 16: "urgent I/O condition",
- 17: "suspended (signal)",
- 18: "suspended",
- 19: "continued",
- 20: "child exited",
- 21: "stopped (tty input)",
- 22: "stopped (tty output)",
- 23: "I/O possible",
- 24: "cputime limit exceeded",
- 25: "filesize limit exceeded",
- 26: "virtual timer expired",
- 27: "profiling timer expired",
- 28: "window size changes",
- 29: "information request",
- 30: "user defined signal 1",
- 31: "user defined signal 2",
- 32: "thread Scheduler",
- 33: "checkPoint",
- 34: "checkPointExit",
-}
diff --git a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_386.go b/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_386.go
deleted file mode 100644
index 32e46af60..000000000
--- a/vendor/golang.org/x/sys/unix/zsyscall_dragonfly_386.go
+++ /dev/null
@@ -1,1412 +0,0 @@
-// mksyscall.pl -l32 -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-// +build 386,dragonfly
-
-package unix
-
-import (
- "syscall"
- "unsafe"
-)
-
-var _ syscall.Errno
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
- r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func setgroups(ngid int, gid *_Gid_t) (err error) {
- _, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
- r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
- wpid = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
- r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- fd = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
- _, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
- _, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func socket(domain int, typ int, proto int) (fd int, err error) {
- r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
- fd = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
- _, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
- _, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
- _, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
- _, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Shutdown(s int, how int) (err error) {
- _, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
- _, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
- r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
- var _p0 unsafe.Pointer
- if len(mib) > 0 {
- _p0 = unsafe.Pointer(&mib[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func utimes(path string, timeval *[2]Timeval) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func futimes(fd int, timeval *[2]Timeval) (err error) {
- _, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func fcntl(fd int, cmd int, arg int) (val int, err error) {
- r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
- val = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe() (r int, w int, err error) {
- r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
- r = int(r0)
- w = int(r1)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func extpread(fd int, p []byte, flags int, offset int64) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EXTPREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), uintptr(offset>>32))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_EXTPWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), uintptr(offset>>32))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Access(path string, mode uint32) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
- _, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chdir(path string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chmod(path string, mode uint32) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chown(path string, uid int, gid int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chroot(path string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Close(fd int) (err error) {
- _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Dup(fd int) (nfd int, err error) {
- r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
- nfd = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Dup2(from int, to int) (err error) {
- _, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Exit(code int) {
- Syscall(SYS_EXIT, uintptr(code), 0, 0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fchdir(fd int) (err error) {
- _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fchflags(fd int, flags int) (err error) {
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fchmod(fd int, mode uint32) (err error) {
- _, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fchown(fd int, uid int, gid int) (err error) {
- _, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Flock(fd int, how int) (err error) {
- _, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fpathconf(fd int, name int) (val int, err error) {
- r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
- val = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fstat(fd int, stat *Stat_t) (err error) {
- _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fstatfs(fd int, stat *Statfs_t) (err error) {
- _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fsync(fd int) (err error) {
- _, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Ftruncate(fd int, length int64) (err error) {
- _, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getdtablesize() (size int) {
- r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
- size = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getegid() (egid int) {
- r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
- egid = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Geteuid() (uid int) {
- r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
- uid = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getgid() (gid int) {
- r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
- gid = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getpgid(pid int) (pgid int, err error) {
- r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
- pgid = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getpgrp() (pgrp int) {
- r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
- pgrp = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getpid() (pid int) {
- r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
- pid = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getppid() (ppid int) {
- r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
- ppid = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getpriority(which int, who int) (prio int, err error) {
- r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
- prio = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getrusage(who int, rusage *Rusage) (err error) {
- _, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getsid(pid int) (sid int, err error) {
- r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
- sid = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Gettimeofday(tv *Timeval) (err error) {
- _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getuid() (uid int) {
- r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
- uid = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Issetugid() (tainted bool) {
- r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
- tainted = bool(r0 != 0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Kill(pid int, signum syscall.Signal) (err error) {
- _, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Kqueue() (fd int, err error) {
- r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
- fd = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Lchown(path string, uid int, gid int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Link(path string, link string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- var _p1 *byte
- _p1, err = BytePtrFromString(link)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
- use(unsafe.Pointer(_p0))
- use(unsafe.Pointer(_p1))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Listen(s int, backlog int) (err error) {
- _, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Lstat(path string, stat *Stat_t) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mkdir(path string, mode uint32) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mkfifo(path string, mode uint32) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mknod(path string, mode uint32, dev int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mlock(b []byte) (err error) {
- var _p0 unsafe.Pointer
- if len(b) > 0 {
- _p0 = unsafe.Pointer(&b[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- _, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mlockall(flags int) (err error) {
- _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mprotect(b []byte, prot int) (err error) {
- var _p0 unsafe.Pointer
- if len(b) > 0 {
- _p0 = unsafe.Pointer(&b[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- _, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Munlock(b []byte) (err error) {
- var _p0 unsafe.Pointer
- if len(b) > 0 {
- _p0 = unsafe.Pointer(&b[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Munlockall() (err error) {
- _, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
- _, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Open(path string, mode int, perm uint32) (fd int, err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
- use(unsafe.Pointer(_p0))
- fd = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Pathconf(path string, name int) (val int, err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
- use(unsafe.Pointer(_p0))
- val = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func read(fd int, p []byte) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Readlink(path string, buf []byte) (n int, err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- var _p1 unsafe.Pointer
- if len(buf) > 0 {
- _p1 = unsafe.Pointer(&buf[0])
- } else {
- _p1 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
- use(unsafe.Pointer(_p0))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rename(from string, to string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(from)
- if err != nil {
- return
- }
- var _p1 *byte
- _p1, err = BytePtrFromString(to)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
- use(unsafe.Pointer(_p0))
- use(unsafe.Pointer(_p1))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Revoke(path string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rmdir(path string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
- r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
- newoffset = int64(int64(r1)<<32 | int64(r0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
- _, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setegid(egid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Seteuid(euid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setgid(gid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setlogin(name string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(name)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setpgid(pid int, pgid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setpriority(which int, who int, prio int) (err error) {
- _, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setregid(rgid int, egid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setreuid(ruid int, euid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setresgid(rgid int, egid int, sgid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setresuid(ruid int, euid int, suid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setrlimit(which int, lim *Rlimit) (err error) {
- _, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setsid() (pid int, err error) {
- r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
- pid = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Settimeofday(tp *Timeval) (err error) {
- _, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setuid(uid int) (err error) {
- _, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Stat(path string, stat *Stat_t) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Statfs(path string, stat *Statfs_t) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Symlink(path string, link string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- var _p1 *byte
- _p1, err = BytePtrFromString(link)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
- use(unsafe.Pointer(_p0))
- use(unsafe.Pointer(_p1))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Sync() (err error) {
- _, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Truncate(path string, length int64) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Umask(newmask int) (oldmask int) {
- r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
- oldmask = int(r0)
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Undelete(path string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Unlink(path string) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Unmount(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
- use(unsafe.Pointer(_p0))
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func write(fd int, p []byte) (n int, err error) {
- var _p0 unsafe.Pointer
- if len(p) > 0 {
- _p0 = unsafe.Pointer(&p[0])
- } else {
- _p0 = unsafe.Pointer(&_zero)
- }
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
- r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
- ret = uintptr(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func munmap(addr uintptr, length uintptr) (err error) {
- _, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
- n = int(r0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
diff --git a/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_386.go b/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_386.go
deleted file mode 100644
index 785240a75..000000000
--- a/vendor/golang.org/x/sys/unix/zsysnum_dragonfly_386.go
+++ /dev/null
@@ -1,304 +0,0 @@
-// mksysnum_dragonfly.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
-
-// +build 386,dragonfly
-
-package unix
-
-const (
- // SYS_NOSYS = 0; // { int nosys(void); } syscall nosys_args int
- SYS_EXIT = 1 // { void exit(int rval); }
- SYS_FORK = 2 // { int fork(void); }
- SYS_READ = 3 // { ssize_t read(int fd, void *buf, size_t nbyte); }
- SYS_WRITE = 4 // { ssize_t write(int fd, const void *buf, size_t nbyte); }
- SYS_OPEN = 5 // { int open(char *path, int flags, int mode); }
- SYS_CLOSE = 6 // { int close(int fd); }
- SYS_WAIT4 = 7 // { int wait4(int pid, int *status, int options, \
- SYS_LINK = 9 // { int link(char *path, char *link); }
- SYS_UNLINK = 10 // { int unlink(char *path); }
- SYS_CHDIR = 12 // { int chdir(char *path); }
- SYS_FCHDIR = 13 // { int fchdir(int fd); }
- SYS_MKNOD = 14 // { int mknod(char *path, int mode, int dev); }
- SYS_CHMOD = 15 // { int chmod(char *path, int mode); }
- SYS_CHOWN = 16 // { int chown(char *path, int uid, int gid); }
- SYS_OBREAK = 17 // { int obreak(char *nsize); } break obreak_args int
- SYS_GETFSSTAT = 18 // { int getfsstat(struct statfs *buf, long bufsize, \
- SYS_GETPID = 20 // { pid_t getpid(void); }
- SYS_MOUNT = 21 // { int mount(char *type, char *path, int flags, \
- SYS_UNMOUNT = 22 // { int unmount(char *path, int flags); }
- SYS_SETUID = 23 // { int setuid(uid_t uid); }
- SYS_GETUID = 24 // { uid_t getuid(void); }
- SYS_GETEUID = 25 // { uid_t geteuid(void); }
- SYS_PTRACE = 26 // { int ptrace(int req, pid_t pid, caddr_t addr, \
- SYS_RECVMSG = 27 // { int recvmsg(int s, struct msghdr *msg, int flags); }
- SYS_SENDMSG = 28 // { int sendmsg(int s, caddr_t msg, int flags); }
- SYS_RECVFROM = 29 // { int recvfrom(int s, caddr_t buf, size_t len, \
- SYS_ACCEPT = 30 // { int accept(int s, caddr_t name, int *anamelen); }
- SYS_GETPEERNAME = 31 // { int getpeername(int fdes, caddr_t asa, int *alen); }
- SYS_GETSOCKNAME = 32 // { int getsockname(int fdes, caddr_t asa, int *alen); }
- SYS_ACCESS = 33 // { int access(char *path, int flags); }
- SYS_CHFLAGS = 34 // { int chflags(char *path, int flags); }
- SYS_FCHFLAGS = 35 // { int fchflags(int fd, int flags); }
- SYS_SYNC = 36 // { int sync(void); }
- SYS_KILL = 37 // { int kill(int pid, int signum); }
- SYS_GETPPID = 39 // { pid_t getppid(void); }
- SYS_DUP = 41 // { int dup(u_int fd); }
- SYS_PIPE = 42 // { int pipe(void); }
- SYS_GETEGID = 43 // { gid_t getegid(void); }
- SYS_PROFIL = 44 // { int profil(caddr_t samples, size_t size, \
- SYS_KTRACE = 45 // { int ktrace(const char *fname, int ops, int facs, \
- SYS_GETGID = 47 // { gid_t getgid(void); }
- SYS_GETLOGIN = 49 // { int getlogin(char *namebuf, u_int namelen); }
- SYS_SETLOGIN = 50 // { int setlogin(char *namebuf); }
- SYS_ACCT = 51 // { int acct(char *path); }
- SYS_SIGALTSTACK = 53 // { int sigaltstack(stack_t *ss, stack_t *oss); }
- SYS_IOCTL = 54 // { int ioctl(int fd, u_long com, caddr_t data); }
- SYS_REBOOT = 55 // { int reboot(int opt); }
- SYS_REVOKE = 56 // { int revoke(char *path); }
- SYS_SYMLINK = 57 // { int symlink(char *path, char *link); }
- SYS_READLINK = 58 // { int readlink(char *path, char *buf, int count); }
- SYS_EXECVE = 59 // { int execve(char *fname, char **argv, char **envv); }
- SYS_UMASK = 60 // { int umask(int newmask); } umask umask_args int
- SYS_CHROOT = 61 // { int chroot(char *path); }
- SYS_MSYNC = 65 // { int msync(void *addr, size_t len, int flags); }
- SYS_VFORK = 66 // { pid_t vfork(void); }
- SYS_SBRK = 69 // { int sbrk(int incr); }
- SYS_SSTK = 70 // { int sstk(int incr); }
- SYS_MUNMAP = 73 // { int munmap(void *addr, size_t len); }
- SYS_MPROTECT = 74 // { int mprotect(void *addr, size_t len, int prot); }
- SYS_MADVISE = 75 // { int madvise(void *addr, size_t len, int behav); }
- SYS_MINCORE = 78 // { int mincore(const void *addr, size_t len, \
- SYS_GETGROUPS = 79 // { int getgroups(u_int gidsetsize, gid_t *gidset); }
- SYS_SETGROUPS = 80 // { int setgroups(u_int gidsetsize, gid_t *gidset); }
- SYS_GETPGRP = 81 // { int getpgrp(void); }
- SYS_SETPGID = 82 // { int setpgid(int pid, int pgid); }
- SYS_SETITIMER = 83 // { int setitimer(u_int which, struct itimerval *itv, \
- SYS_SWAPON = 85 // { int swapon(char *name); }
- SYS_GETITIMER = 86 // { int getitimer(u_int which, struct itimerval *itv); }
- SYS_GETDTABLESIZE = 89 // { int getdtablesize(void); }
- SYS_DUP2 = 90 // { int dup2(u_int from, u_int to); }
- SYS_FCNTL = 92 // { int fcntl(int fd, int cmd, long arg); }
- SYS_SELECT = 93 // { int select(int nd, fd_set *in, fd_set *ou, \
- SYS_FSYNC = 95 // { int fsync(int fd); }
- SYS_SETPRIORITY = 96 // { int setpriority(int which, int who, int prio); }
- SYS_SOCKET = 97 // { int socket(int domain, int type, int protocol); }
- SYS_CONNECT = 98 // { int connect(int s, caddr_t name, int namelen); }
- SYS_GETPRIORITY = 100 // { int getpriority(int which, int who); }
- SYS_BIND = 104 // { int bind(int s, caddr_t name, int namelen); }
- SYS_SETSOCKOPT = 105 // { int setsockopt(int s, int level, int name, \
- SYS_LISTEN = 106 // { int listen(int s, int backlog); }
- SYS_GETTIMEOFDAY = 116 // { int gettimeofday(struct timeval *tp, \
- SYS_GETRUSAGE = 117 // { int getrusage(int who, struct rusage *rusage); }
- SYS_GETSOCKOPT = 118 // { int getsockopt(int s, int level, int name, \
- SYS_READV = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); }
- SYS_WRITEV = 121 // { int writev(int fd, struct iovec *iovp, \
- SYS_SETTIMEOFDAY = 122 // { int settimeofday(struct timeval *tv, \
- SYS_FCHOWN = 123 // { int fchown(int fd, int uid, int gid); }
- SYS_FCHMOD = 124 // { int fchmod(int fd, int mode); }
- SYS_SETREUID = 126 // { int setreuid(int ruid, int euid); }
- SYS_SETREGID = 127 // { int setregid(int rgid, int egid); }
- SYS_RENAME = 128 // { int rename(char *from, char *to); }
- SYS_FLOCK = 131 // { int flock(int fd, int how); }
- SYS_MKFIFO = 132 // { int mkfifo(char *path, int mode); }
- SYS_SENDTO = 133 // { int sendto(int s, caddr_t buf, size_t len, \
- SYS_SHUTDOWN = 134 // { int shutdown(int s, int how); }
- SYS_SOCKETPAIR = 135 // { int socketpair(int domain, int type, int protocol, \
- SYS_MKDIR = 136 // { int mkdir(char *path, int mode); }
- SYS_RMDIR = 137 // { int rmdir(char *path); }
- SYS_UTIMES = 138 // { int utimes(char *path, struct timeval *tptr); }
- SYS_ADJTIME = 140 // { int adjtime(struct timeval *delta, \
- SYS_SETSID = 147 // { int setsid(void); }
- SYS_QUOTACTL = 148 // { int quotactl(char *path, int cmd, int uid, \
- SYS_STATFS = 157 // { int statfs(char *path, struct statfs *buf); }
- SYS_FSTATFS = 158 // { int fstatfs(int fd, struct statfs *buf); }
- SYS_GETFH = 161 // { int getfh(char *fname, struct fhandle *fhp); }
- SYS_GETDOMAINNAME = 162 // { int getdomainname(char *domainname, int len); }
- SYS_SETDOMAINNAME = 163 // { int setdomainname(char *domainname, int len); }
- SYS_UNAME = 164 // { int uname(struct utsname *name); }
- SYS_SYSARCH = 165 // { int sysarch(int op, char *parms); }
- SYS_RTPRIO = 166 // { int rtprio(int function, pid_t pid, \
- SYS_EXTPREAD = 173 // { ssize_t extpread(int fd, void *buf, \
- SYS_EXTPWRITE = 174 // { ssize_t extpwrite(int fd, const void *buf, \
- SYS_NTP_ADJTIME = 176 // { int ntp_adjtime(struct timex *tp); }
- SYS_SETGID = 181 // { int setgid(gid_t gid); }
- SYS_SETEGID = 182 // { int setegid(gid_t egid); }
- SYS_SETEUID = 183 // { int seteuid(uid_t euid); }
- SYS_PATHCONF = 191 // { int pathconf(char *path, int name); }
- SYS_FPATHCONF = 192 // { int fpathconf(int fd, int name); }
- SYS_GETRLIMIT = 194 // { int getrlimit(u_int which, \
- SYS_SETRLIMIT = 195 // { int setrlimit(u_int which, \
- SYS_MMAP = 197 // { caddr_t mmap(caddr_t addr, size_t len, int prot, \
- // SYS_NOSYS = 198; // { int nosys(void); } __syscall __syscall_args int
- SYS_LSEEK = 199 // { off_t lseek(int fd, int pad, off_t offset, \
- SYS_TRUNCATE = 200 // { int truncate(char *path, int pad, off_t length); }
- SYS_FTRUNCATE = 201 // { int ftruncate(int fd, int pad, off_t length); }
- SYS___SYSCTL = 202 // { int __sysctl(int *name, u_int namelen, void *old, \
- SYS_MLOCK = 203 // { int mlock(const void *addr, size_t len); }
- SYS_MUNLOCK = 204 // { int munlock(const void *addr, size_t len); }
- SYS_UNDELETE = 205 // { int undelete(char *path); }
- SYS_FUTIMES = 206 // { int futimes(int fd, struct timeval *tptr); }
- SYS_GETPGID = 207 // { int getpgid(pid_t pid); }
- SYS_POLL = 209 // { int poll(struct pollfd *fds, u_int nfds, \
- SYS___SEMCTL = 220 // { int __semctl(int semid, int semnum, int cmd, \
- SYS_SEMGET = 221 // { int semget(key_t key, int nsems, int semflg); }
- SYS_SEMOP = 222 // { int semop(int semid, struct sembuf *sops, \
- SYS_MSGCTL = 224 // { int msgctl(int msqid, int cmd, \
- SYS_MSGGET = 225 // { int msgget(key_t key, int msgflg); }
- SYS_MSGSND = 226 // { int msgsnd(int msqid, void *msgp, size_t msgsz, \
- SYS_MSGRCV = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, \
- SYS_SHMAT = 228 // { caddr_t shmat(int shmid, const void *shmaddr, \
- SYS_SHMCTL = 229 // { int shmctl(int shmid, int cmd, \
- SYS_SHMDT = 230 // { int shmdt(const void *shmaddr); }
- SYS_SHMGET = 231 // { int shmget(key_t key, size_t size, int shmflg); }
- SYS_CLOCK_GETTIME = 232 // { int clock_gettime(clockid_t clock_id, \
- SYS_CLOCK_SETTIME = 233 // { int clock_settime(clockid_t clock_id, \
- SYS_CLOCK_GETRES = 234 // { int clock_getres(clockid_t clock_id, \
- SYS_NANOSLEEP = 240 // { int nanosleep(const struct timespec *rqtp, \
- SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, int inherit); }
- SYS_RFORK = 251 // { int rfork(int flags); }
- SYS_OPENBSD_POLL = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, \
- SYS_ISSETUGID = 253 // { int issetugid(void); }
- SYS_LCHOWN = 254 // { int lchown(char *path, int uid, int gid); }
- SYS_LCHMOD = 274 // { int lchmod(char *path, mode_t mode); }
- SYS_LUTIMES = 276 // { int lutimes(char *path, struct timeval *tptr); }
- SYS_EXTPREADV = 289 // { ssize_t extpreadv(int fd, struct iovec *iovp, \
- SYS_EXTPWRITEV = 290 // { ssize_t extpwritev(int fd, struct iovec *iovp,\
- SYS_FHSTATFS = 297 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); }
- SYS_FHOPEN = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); }
- SYS_MODNEXT = 300 // { int modnext(int modid); }
- SYS_MODSTAT = 301 // { int modstat(int modid, struct module_stat* stat); }
- SYS_MODFNEXT = 302 // { int modfnext(int modid); }
- SYS_MODFIND = 303 // { int modfind(const char *name); }
- SYS_KLDLOAD = 304 // { int kldload(const char *file); }
- SYS_KLDUNLOAD = 305 // { int kldunload(int fileid); }
- SYS_KLDFIND = 306 // { int kldfind(const char *file); }
- SYS_KLDNEXT = 307 // { int kldnext(int fileid); }
- SYS_KLDSTAT = 308 // { int kldstat(int fileid, struct kld_file_stat* stat); }
- SYS_KLDFIRSTMOD = 309 // { int kldfirstmod(int fileid); }
- SYS_GETSID = 310 // { int getsid(pid_t pid); }
- SYS_SETRESUID = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); }
- SYS_SETRESGID = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); }
- SYS_AIO_RETURN = 314 // { int aio_return(struct aiocb *aiocbp); }
- SYS_AIO_SUSPEND = 315 // { int aio_suspend(struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); }
- SYS_AIO_CANCEL = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); }
- SYS_AIO_ERROR = 317 // { int aio_error(struct aiocb *aiocbp); }
- SYS_AIO_READ = 318 // { int aio_read(struct aiocb *aiocbp); }
- SYS_AIO_WRITE = 319 // { int aio_write(struct aiocb *aiocbp); }
- SYS_LIO_LISTIO = 320 // { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); }
- SYS_YIELD = 321 // { int yield(void); }
- SYS_MLOCKALL = 324 // { int mlockall(int how); }
- SYS_MUNLOCKALL = 325 // { int munlockall(void); }
- SYS___GETCWD = 326 // { int __getcwd(u_char *buf, u_int buflen); }
- SYS_SCHED_SETPARAM = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); }
- SYS_SCHED_GETPARAM = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); }
- SYS_SCHED_SETSCHEDULER = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); }
- SYS_SCHED_GETSCHEDULER = 330 // { int sched_getscheduler (pid_t pid); }
- SYS_SCHED_YIELD = 331 // { int sched_yield (void); }
- SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); }
- SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); }
- SYS_SCHED_RR_GET_INTERVAL = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); }
- SYS_UTRACE = 335 // { int utrace(const void *addr, size_t len); }
- SYS_KLDSYM = 337 // { int kldsym(int fileid, int cmd, void *data); }
- SYS_JAIL = 338 // { int jail(struct jail *jail); }
- SYS_SIGPROCMASK = 340 // { int sigprocmask(int how, const sigset_t *set, \
- SYS_SIGSUSPEND = 341 // { int sigsuspend(const sigset_t *sigmask); }
- SYS_SIGACTION = 342 // { int sigaction(int sig, const struct sigaction *act, \
- SYS_SIGPENDING = 343 // { int sigpending(sigset_t *set); }
- SYS_SIGRETURN = 344 // { int sigreturn(ucontext_t *sigcntxp); }
- SYS_SIGTIMEDWAIT = 345 // { int sigtimedwait(const sigset_t *set,\
- SYS_SIGWAITINFO = 346 // { int sigwaitinfo(const sigset_t *set,\
- SYS___ACL_GET_FILE = 347 // { int __acl_get_file(const char *path, \
- SYS___ACL_SET_FILE = 348 // { int __acl_set_file(const char *path, \
- SYS___ACL_GET_FD = 349 // { int __acl_get_fd(int filedes, acl_type_t type, \
- SYS___ACL_SET_FD = 350 // { int __acl_set_fd(int filedes, acl_type_t type, \
- SYS___ACL_DELETE_FILE = 351 // { int __acl_delete_file(const char *path, \
- SYS___ACL_DELETE_FD = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); }
- SYS___ACL_ACLCHECK_FILE = 353 // { int __acl_aclcheck_file(const char *path, \
- SYS___ACL_ACLCHECK_FD = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, \
- SYS_EXTATTRCTL = 355 // { int extattrctl(const char *path, int cmd, \
- SYS_EXTATTR_SET_FILE = 356 // { int extattr_set_file(const char *path, \
- SYS_EXTATTR_GET_FILE = 357 // { int extattr_get_file(const char *path, \
- SYS_EXTATTR_DELETE_FILE = 358 // { int extattr_delete_file(const char *path, \
- SYS_AIO_WAITCOMPLETE = 359 // { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); }
- SYS_GETRESUID = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
- SYS_GETRESGID = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }
- SYS_KQUEUE = 362 // { int kqueue(void); }
- SYS_KEVENT = 363 // { int kevent(int fd, \
- SYS_SCTP_PEELOFF = 364 // { int sctp_peeloff(int sd, caddr_t name ); }
- SYS_LCHFLAGS = 391 // { int lchflags(char *path, int flags); }
- SYS_UUIDGEN = 392 // { int uuidgen(struct uuid *store, int count); }
- SYS_SENDFILE = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, \
- SYS_VARSYM_SET = 450 // { int varsym_set(int level, const char *name, const char *data); }
- SYS_VARSYM_GET = 451 // { int varsym_get(int mask, const char *wild, char *buf, int bufsize); }
- SYS_VARSYM_LIST = 452 // { int varsym_list(int level, char *buf, int maxsize, int *marker); }
- SYS_EXEC_SYS_REGISTER = 465 // { int exec_sys_register(void *entry); }
- SYS_EXEC_SYS_UNREGISTER = 466 // { int exec_sys_unregister(int id); }
- SYS_SYS_CHECKPOINT = 467 // { int sys_checkpoint(int type, int fd, pid_t pid, int retval); }
- SYS_MOUNTCTL = 468 // { int mountctl(const char *path, int op, int fd, const void *ctl, int ctllen, void *buf, int buflen); }
- SYS_UMTX_SLEEP = 469 // { int umtx_sleep(volatile const int *ptr, int value, int timeout); }
- SYS_UMTX_WAKEUP = 470 // { int umtx_wakeup(volatile const int *ptr, int count); }
- SYS_JAIL_ATTACH = 471 // { int jail_attach(int jid); }
- SYS_SET_TLS_AREA = 472 // { int set_tls_area(int which, struct tls_info *info, size_t infosize); }
- SYS_GET_TLS_AREA = 473 // { int get_tls_area(int which, struct tls_info *info, size_t infosize); }
- SYS_CLOSEFROM = 474 // { int closefrom(int fd); }
- SYS_STAT = 475 // { int stat(const char *path, struct stat *ub); }
- SYS_FSTAT = 476 // { int fstat(int fd, struct stat *sb); }
- SYS_LSTAT = 477 // { int lstat(const char *path, struct stat *ub); }
- SYS_FHSTAT = 478 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); }
- SYS_GETDIRENTRIES = 479 // { int getdirentries(int fd, char *buf, u_int count, \
- SYS_GETDENTS = 480 // { int getdents(int fd, char *buf, size_t count); }
- SYS_USCHED_SET = 481 // { int usched_set(pid_t pid, int cmd, void *data, \
- SYS_EXTACCEPT = 482 // { int extaccept(int s, int flags, caddr_t name, int *anamelen); }
- SYS_EXTCONNECT = 483 // { int extconnect(int s, int flags, caddr_t name, int namelen); }
- SYS_MCONTROL = 485 // { int mcontrol(void *addr, size_t len, int behav, off_t value); }
- SYS_VMSPACE_CREATE = 486 // { int vmspace_create(void *id, int type, void *data); }
- SYS_VMSPACE_DESTROY = 487 // { int vmspace_destroy(void *id); }
- SYS_VMSPACE_CTL = 488 // { int vmspace_ctl(void *id, int cmd, \
- SYS_VMSPACE_MMAP = 489 // { int vmspace_mmap(void *id, void *addr, size_t len, \
- SYS_VMSPACE_MUNMAP = 490 // { int vmspace_munmap(void *id, void *addr, \
- SYS_VMSPACE_MCONTROL = 491 // { int vmspace_mcontrol(void *id, void *addr, \
- SYS_VMSPACE_PREAD = 492 // { ssize_t vmspace_pread(void *id, void *buf, \
- SYS_VMSPACE_PWRITE = 493 // { ssize_t vmspace_pwrite(void *id, const void *buf, \
- SYS_EXTEXIT = 494 // { void extexit(int how, int status, void *addr); }
- SYS_LWP_CREATE = 495 // { int lwp_create(struct lwp_params *params); }
- SYS_LWP_GETTID = 496 // { lwpid_t lwp_gettid(void); }
- SYS_LWP_KILL = 497 // { int lwp_kill(pid_t pid, lwpid_t tid, int signum); }
- SYS_LWP_RTPRIO = 498 // { int lwp_rtprio(int function, pid_t pid, lwpid_t tid, struct rtprio *rtp); }
- SYS_PSELECT = 499 // { int pselect(int nd, fd_set *in, fd_set *ou, \
- SYS_STATVFS = 500 // { int statvfs(const char *path, struct statvfs *buf); }
- SYS_FSTATVFS = 501 // { int fstatvfs(int fd, struct statvfs *buf); }
- SYS_FHSTATVFS = 502 // { int fhstatvfs(const struct fhandle *u_fhp, struct statvfs *buf); }
- SYS_GETVFSSTAT = 503 // { int getvfsstat(struct statfs *buf, \
- SYS_OPENAT = 504 // { int openat(int fd, char *path, int flags, int mode); }
- SYS_FSTATAT = 505 // { int fstatat(int fd, char *path, \
- SYS_FCHMODAT = 506 // { int fchmodat(int fd, char *path, int mode, \
- SYS_FCHOWNAT = 507 // { int fchownat(int fd, char *path, int uid, int gid, \
- SYS_UNLINKAT = 508 // { int unlinkat(int fd, char *path, int flags); }
- SYS_FACCESSAT = 509 // { int faccessat(int fd, char *path, int amode, \
- SYS_MQ_OPEN = 510 // { mqd_t mq_open(const char * name, int oflag, \
- SYS_MQ_CLOSE = 511 // { int mq_close(mqd_t mqdes); }
- SYS_MQ_UNLINK = 512 // { int mq_unlink(const char *name); }
- SYS_MQ_GETATTR = 513 // { int mq_getattr(mqd_t mqdes, \
- SYS_MQ_SETATTR = 514 // { int mq_setattr(mqd_t mqdes, \
- SYS_MQ_NOTIFY = 515 // { int mq_notify(mqd_t mqdes, \
- SYS_MQ_SEND = 516 // { int mq_send(mqd_t mqdes, const char *msg_ptr, \
- SYS_MQ_RECEIVE = 517 // { ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, \
- SYS_MQ_TIMEDSEND = 518 // { int mq_timedsend(mqd_t mqdes, \
- SYS_MQ_TIMEDRECEIVE = 519 // { ssize_t mq_timedreceive(mqd_t mqdes, \
- SYS_IOPRIO_SET = 520 // { int ioprio_set(int which, int who, int prio); }
- SYS_IOPRIO_GET = 521 // { int ioprio_get(int which, int who); }
- SYS_CHROOT_KERNEL = 522 // { int chroot_kernel(char *path); }
- SYS_RENAMEAT = 523 // { int renameat(int oldfd, char *old, int newfd, \
- SYS_MKDIRAT = 524 // { int mkdirat(int fd, char *path, mode_t mode); }
- SYS_MKFIFOAT = 525 // { int mkfifoat(int fd, char *path, mode_t mode); }
- SYS_MKNODAT = 526 // { int mknodat(int fd, char *path, mode_t mode, \
- SYS_READLINKAT = 527 // { int readlinkat(int fd, char *path, char *buf, \
- SYS_SYMLINKAT = 528 // { int symlinkat(char *path1, int fd, char *path2); }
- SYS_SWAPOFF = 529 // { int swapoff(char *name); }
- SYS_VQUOTACTL = 530 // { int vquotactl(const char *path, \
- SYS_LINKAT = 531 // { int linkat(int fd1, char *path1, int fd2, \
- SYS_EACCESS = 532 // { int eaccess(char *path, int flags); }
- SYS_LPATHCONF = 533 // { int lpathconf(char *path, int name); }
- SYS_VMM_GUEST_CTL = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
- SYS_VMM_GUEST_SYNC_ADDR = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
-)
diff --git a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_386.go b/vendor/golang.org/x/sys/unix/ztypes_dragonfly_386.go
deleted file mode 100644
index b7e7ff088..000000000
--- a/vendor/golang.org/x/sys/unix/ztypes_dragonfly_386.go
+++ /dev/null
@@ -1,437 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs types_dragonfly.go
-
-// +build 386,dragonfly
-
-package unix
-
-const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
-)
-
-type (
- _C_short int16
- _C_int int32
- _C_long int32
- _C_long_long int64
-)
-
-type Timespec struct {
- Sec int32
- Nsec int32
-}
-
-type Timeval struct {
- Sec int32
- Usec int32
-}
-
-type Rusage struct {
- Utime Timeval
- Stime Timeval
- Maxrss int32
- Ixrss int32
- Idrss int32
- Isrss int32
- Minflt int32
- Majflt int32
- Nswap int32
- Inblock int32
- Oublock int32
- Msgsnd int32
- Msgrcv int32
- Nsignals int32
- Nvcsw int32
- Nivcsw int32
-}
-
-type Rlimit struct {
- Cur int64
- Max int64
-}
-
-type _Gid_t uint32
-
-const (
- S_IFMT = 0xf000
- S_IFIFO = 0x1000
- S_IFCHR = 0x2000
- S_IFDIR = 0x4000
- S_IFBLK = 0x6000
- S_IFREG = 0x8000
- S_IFLNK = 0xa000
- S_IFSOCK = 0xc000
- S_ISUID = 0x800
- S_ISGID = 0x400
- S_ISVTX = 0x200
- S_IRUSR = 0x100
- S_IWUSR = 0x80
- S_IXUSR = 0x40
-)
-
-type Stat_t struct {
- Ino uint64
- Nlink uint32
- Dev uint32
- Mode uint16
- Padding1 uint16
- Uid uint32
- Gid uint32
- Rdev uint32
- Atim Timespec
- Mtim Timespec
- Ctim Timespec
- Size int64
- Blocks int64
- Blksize uint32
- Flags uint32
- Gen uint32
- Lspare int32
- Qspare1 int64
- Qspare2 int64
-}
-
-type Statfs_t struct {
- Spare2 int32
- Bsize int32
- Iosize int32
- Blocks int32
- Bfree int32
- Bavail int32
- Files int32
- Ffree int32
- Fsid Fsid
- Owner uint32
- Type int32
- Flags int32
- Syncwrites int32
- Asyncwrites int32
- Fstypename [16]int8
- Mntonname [80]int8
- Syncreads int32
- Asyncreads int32
- Spares1 int16
- Mntfromname [80]int8
- Spares2 int16
- Spare [2]int32
-}
-
-type Flock_t struct {
- Start int64
- Len int64
- Pid int32
- Type int16
- Whence int16
-}
-
-type Dirent struct {
- Fileno uint64
- Namlen uint16
- Type uint8
- Unused1 uint8
- Unused2 uint32
- Name [256]int8
-}
-
-type Fsid struct {
- Val [2]int32
-}
-
-type RawSockaddrInet4 struct {
- Len uint8
- Family uint8
- Port uint16
- Addr [4]byte /* in_addr */
- Zero [8]int8
-}
-
-type RawSockaddrInet6 struct {
- Len uint8
- Family uint8
- Port uint16
- Flowinfo uint32
- Addr [16]byte /* in6_addr */
- Scope_id uint32
-}
-
-type RawSockaddrUnix struct {
- Len uint8
- Family uint8
- Path [104]int8
-}
-
-type RawSockaddrDatalink struct {
- Len uint8
- Family uint8
- Index uint16
- Type uint8
- Nlen uint8
- Alen uint8
- Slen uint8
- Data [12]int8
- Rcf uint16
- Route [16]uint16
-}
-
-type RawSockaddr struct {
- Len uint8
- Family uint8
- Data [14]int8
-}
-
-type RawSockaddrAny struct {
- Addr RawSockaddr
- Pad [92]int8
-}
-
-type _Socklen uint32
-
-type Linger struct {
- Onoff int32
- Linger int32
-}
-
-type Iovec struct {
- Base *byte
- Len uint32
-}
-
-type IPMreq struct {
- Multiaddr [4]byte /* in_addr */
- Interface [4]byte /* in_addr */
-}
-
-type IPv6Mreq struct {
- Multiaddr [16]byte /* in6_addr */
- Interface uint32
-}
-
-type Msghdr struct {
- Name *byte
- Namelen uint32
- Iov *Iovec
- Iovlen int32
- Control *byte
- Controllen uint32
- Flags int32
-}
-
-type Cmsghdr struct {
- Len uint32
- Level int32
- Type int32
-}
-
-type Inet6Pktinfo struct {
- Addr [16]byte /* in6_addr */
- Ifindex uint32
-}
-
-type IPv6MTUInfo struct {
- Addr RawSockaddrInet6
- Mtu uint32
-}
-
-type ICMPv6Filter struct {
- Filt [8]uint32
-}
-
-const (
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x6c
- SizeofSockaddrUnix = 0x6a
- SizeofSockaddrDatalink = 0x36
- SizeofLinger = 0x8
- SizeofIPMreq = 0x8
- SizeofIPv6Mreq = 0x14
- SizeofMsghdr = 0x1c
- SizeofCmsghdr = 0xc
- SizeofInet6Pktinfo = 0x14
- SizeofIPv6MTUInfo = 0x20
- SizeofICMPv6Filter = 0x20
-)
-
-const (
- PTRACE_TRACEME = 0x0
- PTRACE_CONT = 0x7
- PTRACE_KILL = 0x8
-)
-
-type Kevent_t struct {
- Ident uint32
- Filter int16
- Flags uint16
- Fflags uint32
- Data int32
- Udata *byte
-}
-
-type FdSet struct {
- Bits [32]uint32
-}
-
-const (
- SizeofIfMsghdr = 0x68
- SizeofIfData = 0x58
- SizeofIfaMsghdr = 0x14
- SizeofIfmaMsghdr = 0x10
- SizeofIfAnnounceMsghdr = 0x18
- SizeofRtMsghdr = 0x5c
- SizeofRtMetrics = 0x38
-)
-
-type IfMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_cgo_0 [2]byte
- Data IfData
-}
-
-type IfData struct {
- Type uint8
- Physical uint8
- Addrlen uint8
- Hdrlen uint8
- Recvquota uint8
- Xmitquota uint8
- Pad_cgo_0 [2]byte
- Mtu uint32
- Metric uint32
- Link_state uint32
- Baudrate uint64
- Ipackets uint32
- Ierrors uint32
- Opackets uint32
- Oerrors uint32
- Collisions uint32
- Ibytes uint32
- Obytes uint32
- Imcasts uint32
- Omcasts uint32
- Iqdrops uint32
- Noproto uint32
- Hwassist uint32
- Unused uint32
- Lastchange Timeval
-}
-
-type IfaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_cgo_0 [2]byte
- Metric int32
-}
-
-type IfmaMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Addrs int32
- Flags int32
- Index uint16
- Pad_cgo_0 [2]byte
-}
-
-type IfAnnounceMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Index uint16
- Name [16]int8
- What uint16
-}
-
-type RtMsghdr struct {
- Msglen uint16
- Version uint8
- Type uint8
- Index uint16
- Pad_cgo_0 [2]byte
- Flags int32
- Addrs int32
- Pid int32
- Seq int32
- Errno int32
- Use int32
- Inits uint32
- Rmx RtMetrics
-}
-
-type RtMetrics struct {
- Locks uint32
- Mtu uint32
- Pksent uint32
- Expire uint32
- Sendpipe uint32
- Ssthresh uint32
- Rtt uint32
- Rttvar uint32
- Recvpipe uint32
- Hopcount uint32
- Mssopt uint16
- Pad uint16
- Msl uint32
- Iwmaxsegs uint32
- Iwcapsegs uint32
-}
-
-const (
- SizeofBpfVersion = 0x4
- SizeofBpfStat = 0x8
- SizeofBpfProgram = 0x8
- SizeofBpfInsn = 0x8
- SizeofBpfHdr = 0x14
-)
-
-type BpfVersion struct {
- Major uint16
- Minor uint16
-}
-
-type BpfStat struct {
- Recv uint32
- Drop uint32
-}
-
-type BpfProgram struct {
- Len uint32
- Insns *BpfInsn
-}
-
-type BpfInsn struct {
- Code uint16
- Jt uint8
- Jf uint8
- K uint32
-}
-
-type BpfHdr struct {
- Tstamp Timeval
- Caplen uint32
- Datalen uint32
- Hdrlen uint16
- Pad_cgo_0 [2]byte
-}
-
-type Termios struct {
- Iflag uint32
- Oflag uint32
- Cflag uint32
- Lflag uint32
- Cc [20]uint8
- Ispeed uint32
- Ospeed uint32
-}
diff --git a/vendor/golang.org/x/sys/windows/asm_windows_386.s b/vendor/golang.org/x/sys/windows/asm_windows_386.s
new file mode 100644
index 000000000..1c20dd2f8
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/asm_windows_386.s
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for 386, Windows are implemented in runtime/syscall_windows.goc
+//
+
+TEXT ·getprocaddress(SB), 7, $0-8
+ JMP syscall·getprocaddress(SB)
+
+TEXT ·loadlibrary(SB), 7, $0-4
+ JMP syscall·loadlibrary(SB)
diff --git a/vendor/golang.org/x/sys/windows/asm_windows_amd64.s b/vendor/golang.org/x/sys/windows/asm_windows_amd64.s
new file mode 100644
index 000000000..4d025ab55
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/asm_windows_amd64.s
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//
+// System calls for amd64, Windows are implemented in runtime/syscall_windows.goc
+//
+
+TEXT ·getprocaddress(SB), 7, $0-32
+ JMP syscall·getprocaddress(SB)
+
+TEXT ·loadlibrary(SB), 7, $0-8
+ JMP syscall·loadlibrary(SB)
diff --git a/vendor/golang.org/x/sys/windows/dll_windows.go b/vendor/golang.org/x/sys/windows/dll_windows.go
new file mode 100644
index 000000000..5f110679e
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/dll_windows.go
@@ -0,0 +1,374 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+import (
+ "sync"
+ "sync/atomic"
+ "syscall"
+ "unsafe"
+)
+
+// DLLError describes reasons for DLL load failures.
+type DLLError struct {
+ Err error
+ ObjName string
+ Msg string
+}
+
+func (e *DLLError) Error() string { return e.Msg }
+
+// Implemented in runtime/syscall_windows.goc; we provide jumps to them in our assembly file.
+func loadlibrary(filename *uint16) (handle uintptr, err syscall.Errno)
+func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err syscall.Errno)
+
+// A DLL implements access to a single DLL.
+type DLL struct {
+ Name string
+ Handle Handle
+}
+
+// LoadDLL loads DLL file into memory.
+//
+// Warning: using LoadDLL without an absolute path name is subject to
+// DLL preloading attacks. To safely load a system DLL, use LazyDLL
+// with System set to true, or use LoadLibraryEx directly.
+func LoadDLL(name string) (dll *DLL, err error) {
+ namep, err := UTF16PtrFromString(name)
+ if err != nil {
+ return nil, err
+ }
+ h, e := loadlibrary(namep)
+ if e != 0 {
+ return nil, &DLLError{
+ Err: e,
+ ObjName: name,
+ Msg: "Failed to load " + name + ": " + e.Error(),
+ }
+ }
+ d := &DLL{
+ Name: name,
+ Handle: Handle(h),
+ }
+ return d, nil
+}
+
+// MustLoadDLL is like LoadDLL but panics if load operation failes.
+func MustLoadDLL(name string) *DLL {
+ d, e := LoadDLL(name)
+ if e != nil {
+ panic(e)
+ }
+ return d
+}
+
+// FindProc searches DLL d for procedure named name and returns *Proc
+// if found. It returns an error if search fails.
+func (d *DLL) FindProc(name string) (proc *Proc, err error) {
+ namep, err := BytePtrFromString(name)
+ if err != nil {
+ return nil, err
+ }
+ a, e := getprocaddress(uintptr(d.Handle), namep)
+ if e != 0 {
+ return nil, &DLLError{
+ Err: e,
+ ObjName: name,
+ Msg: "Failed to find " + name + " procedure in " + d.Name + ": " + e.Error(),
+ }
+ }
+ p := &Proc{
+ Dll: d,
+ Name: name,
+ addr: a,
+ }
+ return p, nil
+}
+
+// MustFindProc is like FindProc but panics if search fails.
+func (d *DLL) MustFindProc(name string) *Proc {
+ p, e := d.FindProc(name)
+ if e != nil {
+ panic(e)
+ }
+ return p
+}
+
+// Release unloads DLL d from memory.
+func (d *DLL) Release() (err error) {
+ return FreeLibrary(d.Handle)
+}
+
+// A Proc implements access to a procedure inside a DLL.
+type Proc struct {
+ Dll *DLL
+ Name string
+ addr uintptr
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *Proc) Addr() uintptr {
+ return p.addr
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
+// are supplied.
+//
+// The returned error is always non-nil, constructed from the result of GetLastError.
+// Callers must inspect the primary return value to decide whether an error occurred
+// (according to the semantics of the specific function being called) before consulting
+// the error. The error will be guaranteed to contain windows.Errno.
+func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+ switch len(a) {
+ case 0:
+ return syscall.Syscall(p.Addr(), uintptr(len(a)), 0, 0, 0)
+ case 1:
+ return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], 0, 0)
+ case 2:
+ return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], 0)
+ case 3:
+ return syscall.Syscall(p.Addr(), uintptr(len(a)), a[0], a[1], a[2])
+ case 4:
+ return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
+ case 5:
+ return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
+ case 6:
+ return syscall.Syscall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
+ case 7:
+ return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], 0, 0)
+ case 8:
+ return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], 0)
+ case 9:
+ return syscall.Syscall9(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8])
+ case 10:
+ return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], 0, 0)
+ case 11:
+ return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], 0)
+ case 12:
+ return syscall.Syscall12(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11])
+ case 13:
+ return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], 0, 0)
+ case 14:
+ return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], 0)
+ case 15:
+ return syscall.Syscall15(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14])
+ default:
+ panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
+ }
+ return
+}
+
+// A LazyDLL implements access to a single DLL.
+// It will delay the load of the DLL until the first
+// call to its Handle method or to one of its
+// LazyProc's Addr method.
+type LazyDLL struct {
+ Name string
+
+ // System determines whether the DLL must be loaded from the
+ // Windows System directory, bypassing the normal DLL search
+ // path.
+ System bool
+
+ mu sync.Mutex
+ dll *DLL // non nil once DLL is loaded
+}
+
+// Load loads DLL file d.Name into memory. It returns an error if fails.
+// Load will not try to load DLL, if it is already loaded into memory.
+func (d *LazyDLL) Load() error {
+ // Non-racy version of:
+ // if d.dll != nil {
+ if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll))) != nil {
+ return nil
+ }
+ d.mu.Lock()
+ defer d.mu.Unlock()
+ if d.dll != nil {
+ return nil
+ }
+
+ // kernel32.dll is special, since it's where LoadLibraryEx comes from.
+ // The kernel already special-cases its name, so it's always
+ // loaded from system32.
+ var dll *DLL
+ var err error
+ if d.Name == "kernel32.dll" {
+ dll, err = LoadDLL(d.Name)
+ } else {
+ dll, err = loadLibraryEx(d.Name, d.System)
+ }
+ if err != nil {
+ return err
+ }
+
+ // Non-racy version of:
+ // d.dll = dll
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.dll)), unsafe.Pointer(dll))
+ return nil
+}
+
+// mustLoad is like Load but panics if search fails.
+func (d *LazyDLL) mustLoad() {
+ e := d.Load()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Handle returns d's module handle.
+func (d *LazyDLL) Handle() uintptr {
+ d.mustLoad()
+ return uintptr(d.dll.Handle)
+}
+
+// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
+func (d *LazyDLL) NewProc(name string) *LazyProc {
+ return &LazyProc{l: d, Name: name}
+}
+
+// NewLazyDLL creates new LazyDLL associated with DLL file.
+func NewLazyDLL(name string) *LazyDLL {
+ return &LazyDLL{Name: name}
+}
+
+// NewLazySystemDLL is like NewLazyDLL, but will only
+// search Windows System directory for the DLL if name is
+// a base name (like "advapi32.dll").
+func NewLazySystemDLL(name string) *LazyDLL {
+ return &LazyDLL{Name: name, System: true}
+}
+
+// A LazyProc implements access to a procedure inside a LazyDLL.
+// It delays the lookup until the Addr method is called.
+type LazyProc struct {
+ Name string
+
+ mu sync.Mutex
+ l *LazyDLL
+ proc *Proc
+}
+
+// Find searches DLL for procedure named p.Name. It returns
+// an error if search fails. Find will not search procedure,
+// if it is already found and loaded into memory.
+func (p *LazyProc) Find() error {
+ // Non-racy version of:
+ // if p.proc == nil {
+ if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
+ p.mu.Lock()
+ defer p.mu.Unlock()
+ if p.proc == nil {
+ e := p.l.Load()
+ if e != nil {
+ return e
+ }
+ proc, e := p.l.dll.FindProc(p.Name)
+ if e != nil {
+ return e
+ }
+ // Non-racy version of:
+ // p.proc = proc
+ atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
+ }
+ }
+ return nil
+}
+
+// mustFind is like Find but panics if search fails.
+func (p *LazyProc) mustFind() {
+ e := p.Find()
+ if e != nil {
+ panic(e)
+ }
+}
+
+// Addr returns the address of the procedure represented by p.
+// The return value can be passed to Syscall to run the procedure.
+func (p *LazyProc) Addr() uintptr {
+ p.mustFind()
+ return p.proc.Addr()
+}
+
+// Call executes procedure p with arguments a. It will panic, if more then 15 arguments
+// are supplied.
+//
+// The returned error is always non-nil, constructed from the result of GetLastError.
+// Callers must inspect the primary return value to decide whether an error occurred
+// (according to the semantics of the specific function being called) before consulting
+// the error. The error will be guaranteed to contain windows.Errno.
+func (p *LazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
+ p.mustFind()
+ return p.proc.Call(a...)
+}
+
+var canDoSearchSystem32Once struct {
+ sync.Once
+ v bool
+}
+
+func initCanDoSearchSystem32() {
+ // https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says:
+ // "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows
+ // Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on
+ // systems that have KB2533623 installed. To determine whether the
+ // flags are available, use GetProcAddress to get the address of the
+ // AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories
+ // function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_*
+ // flags can be used with LoadLibraryEx."
+ canDoSearchSystem32Once.v = (modkernel32.NewProc("AddDllDirectory").Find() == nil)
+}
+
+func canDoSearchSystem32() bool {
+ canDoSearchSystem32Once.Do(initCanDoSearchSystem32)
+ return canDoSearchSystem32Once.v
+}
+
+func isBaseName(name string) bool {
+ for _, c := range name {
+ if c == ':' || c == '/' || c == '\\' {
+ return false
+ }
+ }
+ return true
+}
+
+// loadLibraryEx wraps the Windows LoadLibraryEx function.
+//
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684179(v=vs.85).aspx
+//
+// If name is not an absolute path, LoadLibraryEx searches for the DLL
+// in a variety of automatic locations unless constrained by flags.
+// See: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
+func loadLibraryEx(name string, system bool) (*DLL, error) {
+ loadDLL := name
+ var flags uintptr
+ if system {
+ if canDoSearchSystem32() {
+ const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
+ flags = LOAD_LIBRARY_SEARCH_SYSTEM32
+ } else if isBaseName(name) {
+ // WindowsXP or unpatched Windows machine
+ // trying to load "foo.dll" out of the system
+ // folder, but LoadLibraryEx doesn't support
+ // that yet on their system, so emulate it.
+ windir, _ := Getenv("WINDIR") // old var; apparently works on XP
+ if windir == "" {
+ return nil, errString("%WINDIR% not defined")
+ }
+ loadDLL = windir + "\\System32\\" + name
+ }
+ }
+ h, err := LoadLibraryEx(loadDLL, 0, flags)
+ if err != nil {
+ return nil, err
+ }
+ return &DLL{Name: name, Handle: h}, nil
+}
+
+type errString string
+
+func (s errString) Error() string { return string(s) }
diff --git a/vendor/golang.org/x/sys/windows/env_unset.go b/vendor/golang.org/x/sys/windows/env_unset.go
new file mode 100644
index 000000000..4ed03aeef
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/env_unset.go
@@ -0,0 +1,15 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+// +build go1.4
+
+package windows
+
+import "syscall"
+
+func Unsetenv(key string) error {
+ // This was added in Go 1.4.
+ return syscall.Unsetenv(key)
+}
diff --git a/vendor/golang.org/x/sys/windows/env_windows.go b/vendor/golang.org/x/sys/windows/env_windows.go
new file mode 100644
index 000000000..a9d8ef4b7
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/env_windows.go
@@ -0,0 +1,25 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows environment variables.
+
+package windows
+
+import "syscall"
+
+func Getenv(key string) (value string, found bool) {
+ return syscall.Getenv(key)
+}
+
+func Setenv(key, value string) error {
+ return syscall.Setenv(key, value)
+}
+
+func Clearenv() {
+ syscall.Clearenv()
+}
+
+func Environ() []string {
+ return syscall.Environ()
+}
diff --git a/vendor/golang.org/x/sys/windows/eventlog.go b/vendor/golang.org/x/sys/windows/eventlog.go
new file mode 100644
index 000000000..40af946e1
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/eventlog.go
@@ -0,0 +1,20 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package windows
+
+const (
+ EVENTLOG_SUCCESS = 0
+ EVENTLOG_ERROR_TYPE = 1
+ EVENTLOG_WARNING_TYPE = 2
+ EVENTLOG_INFORMATION_TYPE = 4
+ EVENTLOG_AUDIT_SUCCESS = 8
+ EVENTLOG_AUDIT_FAILURE = 16
+)
+
+//sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW
+//sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource
+//sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW
diff --git a/vendor/golang.org/x/sys/windows/exec_windows.go b/vendor/golang.org/x/sys/windows/exec_windows.go
new file mode 100644
index 000000000..3606c3a8b
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/exec_windows.go
@@ -0,0 +1,97 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Fork, exec, wait, etc.
+
+package windows
+
+// EscapeArg rewrites command line argument s as prescribed
+// in http://msdn.microsoft.com/en-us/library/ms880421.
+// This function returns "" (2 double quotes) if s is empty.
+// Alternatively, these transformations are done:
+// - every back slash (\) is doubled, but only if immediately
+// followed by double quote (");
+// - every double quote (") is escaped by back slash (\);
+// - finally, s is wrapped with double quotes (arg -> "arg"),
+// but only if there is space or tab inside s.
+func EscapeArg(s string) string {
+ if len(s) == 0 {
+ return "\"\""
+ }
+ n := len(s)
+ hasSpace := false
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '"', '\\':
+ n++
+ case ' ', '\t':
+ hasSpace = true
+ }
+ }
+ if hasSpace {
+ n += 2
+ }
+ if n == len(s) {
+ return s
+ }
+
+ qs := make([]byte, n)
+ j := 0
+ if hasSpace {
+ qs[j] = '"'
+ j++
+ }
+ slashes := 0
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ default:
+ slashes = 0
+ qs[j] = s[i]
+ case '\\':
+ slashes++
+ qs[j] = s[i]
+ case '"':
+ for ; slashes > 0; slashes-- {
+ qs[j] = '\\'
+ j++
+ }
+ qs[j] = '\\'
+ j++
+ qs[j] = s[i]
+ }
+ j++
+ }
+ if hasSpace {
+ for ; slashes > 0; slashes-- {
+ qs[j] = '\\'
+ j++
+ }
+ qs[j] = '"'
+ j++
+ }
+ return string(qs[:j])
+}
+
+func CloseOnExec(fd Handle) {
+ SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
+}
+
+// FullPath retrieves the full path of the specified file.
+func FullPath(name string) (path string, err error) {
+ p, err := UTF16PtrFromString(name)
+ if err != nil {
+ return "", err
+ }
+ n := uint32(100)
+ for {
+ buf := make([]uint16, n)
+ n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
+ if err != nil {
+ return "", err
+ }
+ if n <= uint32(len(buf)) {
+ return UTF16ToString(buf[:n]), nil
+ }
+ }
+}
diff --git a/vendor/golang.org/x/sys/windows/race.go b/vendor/golang.org/x/sys/windows/race.go
new file mode 100644
index 000000000..343e18ab6
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/race.go
@@ -0,0 +1,30 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows,race
+
+package windows
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+const raceenabled = true
+
+func raceAcquire(addr unsafe.Pointer) {
+ runtime.RaceAcquire(addr)
+}
+
+func raceReleaseMerge(addr unsafe.Pointer) {
+ runtime.RaceReleaseMerge(addr)
+}
+
+func raceReadRange(addr unsafe.Pointer, len int) {
+ runtime.RaceReadRange(addr, len)
+}
+
+func raceWriteRange(addr unsafe.Pointer, len int) {
+ runtime.RaceWriteRange(addr, len)
+}
diff --git a/vendor/golang.org/x/sys/windows/race0.go b/vendor/golang.org/x/sys/windows/race0.go
new file mode 100644
index 000000000..17af843b9
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/race0.go
@@ -0,0 +1,25 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows,!race
+
+package windows
+
+import (
+ "unsafe"
+)
+
+const raceenabled = false
+
+func raceAcquire(addr unsafe.Pointer) {
+}
+
+func raceReleaseMerge(addr unsafe.Pointer) {
+}
+
+func raceReadRange(addr unsafe.Pointer, len int) {
+}
+
+func raceWriteRange(addr unsafe.Pointer, len int) {
+}
diff --git a/vendor/golang.org/x/sys/windows/registry/export_test.go b/vendor/golang.org/x/sys/windows/registry/export_test.go
new file mode 100644
index 000000000..8badf6fdc
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/registry/export_test.go
@@ -0,0 +1,11 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package registry
+
+func (k Key) SetValue(name string, valtype uint32, data []byte) error {
+ return k.setValue(name, valtype, data)
+}
diff --git a/vendor/golang.org/x/sys/windows/registry/key.go b/vendor/golang.org/x/sys/windows/registry/key.go
new file mode 100644
index 000000000..f087ce5ad
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/registry/key.go
@@ -0,0 +1,178 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package registry provides access to the Windows registry.
+//
+// Here is a simple example, opening a registry key and reading a string value from it.
+//
+// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
+// if err != nil {
+// log.Fatal(err)
+// }
+// defer k.Close()
+//
+// s, _, err := k.GetStringValue("SystemRoot")
+// if err != nil {
+// log.Fatal(err)
+// }
+// fmt.Printf("Windows system root is %q\n", s)
+//
+package registry
+
+import (
+ "io"
+ "syscall"
+ "time"
+)
+
+const (
+ // Registry key security and access rights.
+ // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx
+ // for details.
+ ALL_ACCESS = 0xf003f
+ CREATE_LINK = 0x00020
+ CREATE_SUB_KEY = 0x00004
+ ENUMERATE_SUB_KEYS = 0x00008
+ EXECUTE = 0x20019
+ NOTIFY = 0x00010
+ QUERY_VALUE = 0x00001
+ READ = 0x20019
+ SET_VALUE = 0x00002
+ WOW64_32KEY = 0x00200
+ WOW64_64KEY = 0x00100
+ WRITE = 0x20006
+)
+
+// Key is a handle to an open Windows registry key.
+// Keys can be obtained by calling OpenKey; there are
+// also some predefined root keys such as CURRENT_USER.
+// Keys can be used directly in the Windows API.
+type Key syscall.Handle
+
+const (
+ // Windows defines some predefined root keys that are always open.
+ // An application can use these keys as entry points to the registry.
+ // Normally these keys are used in OpenKey to open new keys,
+ // but they can also be used anywhere a Key is required.
+ CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT)
+ CURRENT_USER = Key(syscall.HKEY_CURRENT_USER)
+ LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE)
+ USERS = Key(syscall.HKEY_USERS)
+ CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG)
+)
+
+// Close closes open key k.
+func (k Key) Close() error {
+ return syscall.RegCloseKey(syscall.Handle(k))
+}
+
+// OpenKey opens a new key with path name relative to key k.
+// It accepts any open key, including CURRENT_USER and others,
+// and returns the new key and an error.
+// The access parameter specifies desired access rights to the
+// key to be opened.
+func OpenKey(k Key, path string, access uint32) (Key, error) {
+ p, err := syscall.UTF16PtrFromString(path)
+ if err != nil {
+ return 0, err
+ }
+ var subkey syscall.Handle
+ err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey)
+ if err != nil {
+ return 0, err
+ }
+ return Key(subkey), nil
+}
+
+// ReadSubKeyNames returns the names of subkeys of key k.
+// The parameter n controls the number of returned names,
+// analogous to the way os.File.Readdirnames works.
+func (k Key) ReadSubKeyNames(n int) ([]string, error) {
+ ki, err := k.Stat()
+ if err != nil {
+ return nil, err
+ }
+ names := make([]string, 0, ki.SubKeyCount)
+ buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte
+loopItems:
+ for i := uint32(0); ; i++ {
+ if n > 0 {
+ if len(names) == n {
+ return names, nil
+ }
+ }
+ l := uint32(len(buf))
+ for {
+ err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
+ if err == nil {
+ break
+ }
+ if err == syscall.ERROR_MORE_DATA {
+ // Double buffer size and try again.
+ l = uint32(2 * len(buf))
+ buf = make([]uint16, l)
+ continue
+ }
+ if err == _ERROR_NO_MORE_ITEMS {
+ break loopItems
+ }
+ return names, err
+ }
+ names = append(names, syscall.UTF16ToString(buf[:l]))
+ }
+ if n > len(names) {
+ return names, io.EOF
+ }
+ return names, nil
+}
+
+// CreateKey creates a key named path under open key k.
+// CreateKey returns the new key and a boolean flag that reports
+// whether the key already existed.
+// The access parameter specifies the access rights for the key
+// to be created.
+func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
+ var h syscall.Handle
+ var d uint32
+ err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
+ 0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
+ if err != nil {
+ return 0, false, err
+ }
+ return Key(h), d == _REG_OPENED_EXISTING_KEY, nil
+}
+
+// DeleteKey deletes the subkey path of key k and its values.
+func DeleteKey(k Key, path string) error {
+ return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
+}
+
+// A KeyInfo describes the statistics of a key. It is returned by Stat.
+type KeyInfo struct {
+ SubKeyCount uint32
+ MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte
+ ValueCount uint32
+ MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte
+ MaxValueLen uint32 // longest data component among the key's values, in bytes
+ lastWriteTime syscall.Filetime
+}
+
+// ModTime returns the key's last write time.
+func (ki *KeyInfo) ModTime() time.Time {
+ return time.Unix(0, ki.lastWriteTime.Nanoseconds())
+}
+
+// Stat retrieves information about the open key k.
+func (k Key) Stat() (*KeyInfo, error) {
+ var ki KeyInfo
+ err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil,
+ &ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount,
+ &ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime)
+ if err != nil {
+ return nil, err
+ }
+ return &ki, nil
+}
diff --git a/vendor/golang.org/x/sys/windows/registry/registry_test.go b/vendor/golang.org/x/sys/windows/registry/registry_test.go
new file mode 100644
index 000000000..9c1b7820e
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/registry/registry_test.go
@@ -0,0 +1,756 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package registry_test
+
+import (
+ "bytes"
+ "crypto/rand"
+ "os"
+ "syscall"
+ "testing"
+ "time"
+ "unsafe"
+
+ "golang.org/x/sys/windows/registry"
+)
+
+func randKeyName(prefix string) string {
+ const numbers = "0123456789"
+ buf := make([]byte, 10)
+ rand.Read(buf)
+ for i, b := range buf {
+ buf[i] = numbers[b%byte(len(numbers))]
+ }
+ return prefix + string(buf)
+}
+
+func TestReadSubKeyNames(t *testing.T) {
+ k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer k.Close()
+
+ names, err := k.ReadSubKeyNames(-1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var foundStdOle bool
+ for _, name := range names {
+ // Every PC has "stdole 2.0 OLE Automation" library installed.
+ if name == "{00020430-0000-0000-C000-000000000046}" {
+ foundStdOle = true
+ }
+ }
+ if !foundStdOle {
+ t.Fatal("could not find stdole 2.0 OLE Automation")
+ }
+}
+
+func TestCreateOpenDeleteKey(t *testing.T) {
+ k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer k.Close()
+
+ testKName := randKeyName("TestCreateOpenDeleteKey_")
+
+ testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer testK.Close()
+
+ if exist {
+ t.Fatalf("key %q already exists", testKName)
+ }
+
+ testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer testKAgain.Close()
+
+ if !exist {
+ t.Fatalf("key %q should already exist", testKName)
+ }
+
+ testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer testKOpened.Close()
+
+ err = registry.DeleteKey(k, testKName)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
+ if err == nil {
+ defer testKOpenedAgain.Close()
+ t.Fatalf("key %q should already been deleted", testKName)
+ }
+ if err != registry.ErrNotExist {
+ t.Fatalf(`unexpected error ("not exist" expected): %v`, err)
+ }
+}
+
+func equalStringSlice(a, b []string) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ if a == nil {
+ return true
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
+
+type ValueTest struct {
+ Type uint32
+ Name string
+ Value interface{}
+ WillFail bool
+}
+
+var ValueTests = []ValueTest{
+ {Type: registry.SZ, Name: "String1", Value: ""},
+ {Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true},
+ {Type: registry.SZ, Name: "String3", Value: "Hello World"},
+ {Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true},
+ {Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""},
+ {Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true},
+ {Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"},
+ {Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true},
+ {Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"},
+ {Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"},
+ {Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."},
+ {Type: registry.BINARY, Name: "Binary1", Value: []byte{}},
+ {Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}},
+ {Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}},
+ {Type: registry.DWORD, Name: "Dword1", Value: uint64(0)},
+ {Type: registry.DWORD, Name: "Dword2", Value: uint64(1)},
+ {Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)},
+ {Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)},
+ {Type: registry.QWORD, Name: "Qword1", Value: uint64(0)},
+ {Type: registry.QWORD, Name: "Qword2", Value: uint64(1)},
+ {Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)},
+ {Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)},
+ {Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)},
+ {Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)},
+ {Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}},
+ {Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}},
+ {Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}},
+ {Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}},
+ {Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true},
+ {Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true},
+ {Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true},
+ {Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true},
+ {Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true},
+}
+
+func setValues(t *testing.T, k registry.Key) {
+ for _, test := range ValueTests {
+ var err error
+ switch test.Type {
+ case registry.SZ:
+ err = k.SetStringValue(test.Name, test.Value.(string))
+ case registry.EXPAND_SZ:
+ err = k.SetExpandStringValue(test.Name, test.Value.(string))
+ case registry.MULTI_SZ:
+ err = k.SetStringsValue(test.Name, test.Value.([]string))
+ case registry.BINARY:
+ err = k.SetBinaryValue(test.Name, test.Value.([]byte))
+ case registry.DWORD:
+ err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64)))
+ case registry.QWORD:
+ err = k.SetQWordValue(test.Name, test.Value.(uint64))
+ default:
+ t.Fatalf("unsupported type %d for %s value", test.Type, test.Name)
+ }
+ if test.WillFail {
+ if err == nil {
+ t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value)
+ }
+ } else {
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+}
+
+func enumerateValues(t *testing.T, k registry.Key) {
+ names, err := k.ReadValueNames(-1)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ haveNames := make(map[string]bool)
+ for _, n := range names {
+ haveNames[n] = false
+ }
+ for _, test := range ValueTests {
+ wantFound := !test.WillFail
+ _, haveFound := haveNames[test.Name]
+ if wantFound && !haveFound {
+ t.Errorf("value %s is not found while enumerating", test.Name)
+ }
+ if haveFound && !wantFound {
+ t.Errorf("value %s is found while enumerating, but expected to fail", test.Name)
+ }
+ if haveFound {
+ delete(haveNames, test.Name)
+ }
+ }
+ for n, v := range haveNames {
+ t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v)
+ }
+}
+
+func testErrNotExist(t *testing.T, name string, err error) {
+ if err == nil {
+ t.Errorf("%s value should not exist", name)
+ return
+ }
+ if err != registry.ErrNotExist {
+ t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err)
+ return
+ }
+}
+
+func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) {
+ if err == nil {
+ t.Errorf("GetXValue(%q) should not succeed", test.Name)
+ return
+ }
+ if err != registry.ErrUnexpectedType {
+ t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+}
+
+func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) {
+ got, gottype, err := k.GetStringValue(test.Name)
+ if err != nil {
+ t.Errorf("GetStringValue(%s) failed: %v", test.Name, err)
+ return
+ }
+ if got != test.Value {
+ t.Errorf("want %s value %q, got %q", test.Name, test.Value, got)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+ if gottype == registry.EXPAND_SZ {
+ _, err = registry.ExpandString(got)
+ if err != nil {
+ t.Errorf("ExpandString(%s) failed: %v", got, err)
+ return
+ }
+ }
+}
+
+func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) {
+ got, gottype, err := k.GetIntegerValue(test.Name)
+ if err != nil {
+ t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err)
+ return
+ }
+ if got != test.Value.(uint64) {
+ t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+}
+
+func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) {
+ got, gottype, err := k.GetBinaryValue(test.Name)
+ if err != nil {
+ t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err)
+ return
+ }
+ if !bytes.Equal(got, test.Value.([]byte)) {
+ t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+}
+
+func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) {
+ got, gottype, err := k.GetStringsValue(test.Name)
+ if err != nil {
+ t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err)
+ return
+ }
+ if !equalStringSlice(got, test.Value.([]string)) {
+ t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+}
+
+func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) {
+ if size <= 0 {
+ return
+ }
+ // read data with no buffer
+ gotsize, gottype, err := k.GetValue(test.Name, nil)
+ if err != nil {
+ t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
+ return
+ }
+ if gotsize != size {
+ t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+ // read data with short buffer
+ gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1))
+ if err == nil {
+ t.Errorf("GetValue(%s, [%d]byte) should fail, but suceeded", test.Name, size-1)
+ return
+ }
+ if err != registry.ErrShortBuffer {
+ t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err)
+ return
+ }
+ if gotsize != size {
+ t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+ // read full data
+ gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size))
+ if err != nil {
+ t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
+ return
+ }
+ if gotsize != size {
+ t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+ return
+ }
+ if gottype != test.Type {
+ t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+ return
+ }
+ // check GetValue returns ErrNotExist as required
+ _, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size))
+ if err == nil {
+ t.Errorf("GetValue(%q) should not succeed", test.Name)
+ return
+ }
+ if err != registry.ErrNotExist {
+ t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err)
+ return
+ }
+}
+
+func testValues(t *testing.T, k registry.Key) {
+ for _, test := range ValueTests {
+ switch test.Type {
+ case registry.SZ, registry.EXPAND_SZ:
+ if test.WillFail {
+ _, _, err := k.GetStringValue(test.Name)
+ testErrNotExist(t, test.Name, err)
+ } else {
+ testGetStringValue(t, k, test)
+ _, gottype, err := k.GetIntegerValue(test.Name)
+ testErrUnexpectedType(t, test, gottype, err)
+ // Size of utf16 string in bytes is not perfect,
+ // but correct for current test values.
+ // Size also includes terminating 0.
+ testGetValue(t, k, test, (len(test.Value.(string))+1)*2)
+ }
+ _, _, err := k.GetStringValue(test.Name + "_string_not_created")
+ testErrNotExist(t, test.Name+"_string_not_created", err)
+ case registry.DWORD, registry.QWORD:
+ testGetIntegerValue(t, k, test)
+ _, gottype, err := k.GetBinaryValue(test.Name)
+ testErrUnexpectedType(t, test, gottype, err)
+ _, _, err = k.GetIntegerValue(test.Name + "_int_not_created")
+ testErrNotExist(t, test.Name+"_int_not_created", err)
+ size := 8
+ if test.Type == registry.DWORD {
+ size = 4
+ }
+ testGetValue(t, k, test, size)
+ case registry.BINARY:
+ testGetBinaryValue(t, k, test)
+ _, gottype, err := k.GetStringsValue(test.Name)
+ testErrUnexpectedType(t, test, gottype, err)
+ _, _, err = k.GetBinaryValue(test.Name + "_byte_not_created")
+ testErrNotExist(t, test.Name+"_byte_not_created", err)
+ testGetValue(t, k, test, len(test.Value.([]byte)))
+ case registry.MULTI_SZ:
+ if test.WillFail {
+ _, _, err := k.GetStringsValue(test.Name)
+ testErrNotExist(t, test.Name, err)
+ } else {
+ testGetStringsValue(t, k, test)
+ _, gottype, err := k.GetStringValue(test.Name)
+ testErrUnexpectedType(t, test, gottype, err)
+ size := 0
+ for _, s := range test.Value.([]string) {
+ size += len(s) + 1 // nil terminated
+ }
+ size += 1 // extra nil at the end
+ size *= 2 // count bytes, not uint16
+ testGetValue(t, k, test, size)
+ }
+ _, _, err := k.GetStringsValue(test.Name + "_strings_not_created")
+ testErrNotExist(t, test.Name+"_strings_not_created", err)
+ default:
+ t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
+ continue
+ }
+ }
+}
+
+func testStat(t *testing.T, k registry.Key) {
+ subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer subk.Close()
+
+ defer registry.DeleteKey(k, "subkey")
+
+ ki, err := k.Stat()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if ki.SubKeyCount != 1 {
+ t.Error("key must have 1 subkey")
+ }
+ if ki.MaxSubKeyLen != 6 {
+ t.Error("key max subkey name length must be 6")
+ }
+ if ki.ValueCount != 24 {
+ t.Errorf("key must have 24 values, but is %d", ki.ValueCount)
+ }
+ if ki.MaxValueNameLen != 12 {
+ t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen)
+ }
+ if ki.MaxValueLen != 38 {
+ t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen)
+ }
+ if mt, ct := ki.ModTime(), time.Now(); ct.Sub(mt) > 100*time.Millisecond {
+ t.Errorf("key mod time is not close to current time: mtime=%v current=%v delta=%v", mt, ct, ct.Sub(mt))
+ }
+}
+
+func deleteValues(t *testing.T, k registry.Key) {
+ for _, test := range ValueTests {
+ if test.WillFail {
+ continue
+ }
+ err := k.DeleteValue(test.Name)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ }
+ names, err := k.ReadValueNames(-1)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if len(names) != 0 {
+ t.Errorf("some values remain after deletion: %v", names)
+ }
+}
+
+func TestValues(t *testing.T) {
+ softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer softwareK.Close()
+
+ testKName := randKeyName("TestValues_")
+
+ k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer k.Close()
+
+ if exist {
+ t.Fatalf("key %q already exists", testKName)
+ }
+
+ defer registry.DeleteKey(softwareK, testKName)
+
+ setValues(t, k)
+
+ enumerateValues(t, k)
+
+ testValues(t, k)
+
+ testStat(t, k)
+
+ deleteValues(t, k)
+}
+
+func walkKey(t *testing.T, k registry.Key, kname string) {
+ names, err := k.ReadValueNames(-1)
+ if err != nil {
+ t.Fatalf("reading value names of %s failed: %v", kname, err)
+ }
+ for _, name := range names {
+ _, valtype, err := k.GetValue(name, nil)
+ if err != nil {
+ t.Fatalf("reading value type of %s of %s failed: %v", name, kname, err)
+ }
+ switch valtype {
+ case registry.NONE:
+ case registry.SZ:
+ _, _, err := k.GetStringValue(name)
+ if err != nil {
+ t.Error(err)
+ }
+ case registry.EXPAND_SZ:
+ s, _, err := k.GetStringValue(name)
+ if err != nil {
+ t.Error(err)
+ }
+ _, err = registry.ExpandString(s)
+ if err != nil {
+ t.Error(err)
+ }
+ case registry.DWORD, registry.QWORD:
+ _, _, err := k.GetIntegerValue(name)
+ if err != nil {
+ t.Error(err)
+ }
+ case registry.BINARY:
+ _, _, err := k.GetBinaryValue(name)
+ if err != nil {
+ t.Error(err)
+ }
+ case registry.MULTI_SZ:
+ _, _, err := k.GetStringsValue(name)
+ if err != nil {
+ t.Error(err)
+ }
+ case registry.FULL_RESOURCE_DESCRIPTOR, registry.RESOURCE_LIST, registry.RESOURCE_REQUIREMENTS_LIST:
+ // TODO: not implemented
+ default:
+ t.Fatalf("value type %d of %s of %s failed: %v", valtype, name, kname, err)
+ }
+ }
+
+ names, err = k.ReadSubKeyNames(-1)
+ if err != nil {
+ t.Fatalf("reading sub-keys of %s failed: %v", kname, err)
+ }
+ for _, name := range names {
+ func() {
+ subk, err := registry.OpenKey(k, name, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
+ if err != nil {
+ if err == syscall.ERROR_ACCESS_DENIED {
+ // ignore error, if we are not allowed to access this key
+ return
+ }
+ t.Fatalf("opening sub-keys %s of %s failed: %v", name, kname, err)
+ }
+ defer subk.Close()
+
+ walkKey(t, subk, kname+`\`+name)
+ }()
+ }
+}
+
+func TestWalkFullRegistry(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping long running test in short mode")
+ }
+ walkKey(t, registry.CLASSES_ROOT, "CLASSES_ROOT")
+ walkKey(t, registry.CURRENT_USER, "CURRENT_USER")
+ walkKey(t, registry.LOCAL_MACHINE, "LOCAL_MACHINE")
+ walkKey(t, registry.USERS, "USERS")
+ walkKey(t, registry.CURRENT_CONFIG, "CURRENT_CONFIG")
+}
+
+func TestExpandString(t *testing.T) {
+ got, err := registry.ExpandString("%PATH%")
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := os.Getenv("PATH")
+ if got != want {
+ t.Errorf("want %q string expanded, got %q", want, got)
+ }
+}
+
+func TestInvalidValues(t *testing.T) {
+ softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer softwareK.Close()
+
+ testKName := randKeyName("TestInvalidValues_")
+
+ k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer k.Close()
+
+ if exist {
+ t.Fatalf("key %q already exists", testKName)
+ }
+
+ defer registry.DeleteKey(softwareK, testKName)
+
+ var tests = []struct {
+ Type uint32
+ Name string
+ Data []byte
+ }{
+ {registry.DWORD, "Dword1", nil},
+ {registry.DWORD, "Dword2", []byte{1, 2, 3}},
+ {registry.QWORD, "Qword1", nil},
+ {registry.QWORD, "Qword2", []byte{1, 2, 3}},
+ {registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}},
+ {registry.MULTI_SZ, "MultiString1", nil},
+ {registry.MULTI_SZ, "MultiString2", []byte{0}},
+ {registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}},
+ {registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}},
+ {registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}},
+ }
+
+ for _, test := range tests {
+ err := k.SetValue(test.Name, test.Type, test.Data)
+ if err != nil {
+ t.Fatalf("SetValue for %q failed: %v", test.Name, err)
+ }
+ }
+
+ for _, test := range tests {
+ switch test.Type {
+ case registry.DWORD, registry.QWORD:
+ value, valType, err := k.GetIntegerValue(test.Name)
+ if err == nil {
+ t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
+ }
+ case registry.MULTI_SZ:
+ value, valType, err := k.GetStringsValue(test.Name)
+ if err == nil {
+ if len(value) != 0 {
+ t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
+ }
+ }
+ default:
+ t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
+ }
+ }
+}
+
+func TestGetMUIStringValue(t *testing.T) {
+ if err := registry.LoadRegLoadMUIString(); err != nil {
+ t.Skip("regLoadMUIString not supported; skipping")
+ }
+ if err := procGetDynamicTimeZoneInformation.Find(); err != nil {
+ t.Skipf("%s not supported; skipping", procGetDynamicTimeZoneInformation.Name)
+ }
+ var dtzi DynamicTimezoneinformation
+ if _, err := GetDynamicTimeZoneInformation(&dtzi); err != nil {
+ t.Fatal(err)
+ }
+ tzKeyName := syscall.UTF16ToString(dtzi.TimeZoneKeyName[:])
+ timezoneK, err := registry.OpenKey(registry.LOCAL_MACHINE,
+ `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+tzKeyName, registry.READ)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer timezoneK.Close()
+
+ type testType struct {
+ name string
+ want string
+ }
+ var tests = []testType{
+ {"MUI_Std", syscall.UTF16ToString(dtzi.StandardName[:])},
+ }
+ if dtzi.DynamicDaylightTimeDisabled == 0 {
+ tests = append(tests, testType{"MUI_Dlt", syscall.UTF16ToString(dtzi.DaylightName[:])})
+ }
+
+ for _, test := range tests {
+ got, err := timezoneK.GetMUIStringValue(test.name)
+ if err != nil {
+ t.Error("GetMUIStringValue:", err)
+ }
+
+ if got != test.want {
+ t.Errorf("GetMUIStringValue: %s: Got %q, want %q", test.name, got, test.want)
+ }
+ }
+}
+
+type DynamicTimezoneinformation struct {
+ Bias int32
+ StandardName [32]uint16
+ StandardDate syscall.Systemtime
+ StandardBias int32
+ DaylightName [32]uint16
+ DaylightDate syscall.Systemtime
+ DaylightBias int32
+ TimeZoneKeyName [128]uint16
+ DynamicDaylightTimeDisabled uint8
+}
+
+var (
+ kernel32DLL = syscall.NewLazyDLL("kernel32")
+
+ procGetDynamicTimeZoneInformation = kernel32DLL.NewProc("GetDynamicTimeZoneInformation")
+)
+
+func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetDynamicTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(dtzi)), 0, 0)
+ rc = uint32(r0)
+ if rc == 0xffffffff {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
diff --git a/vendor/golang.org/x/sys/windows/registry/syscall.go b/vendor/golang.org/x/sys/windows/registry/syscall.go
new file mode 100644
index 000000000..5426cae90
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/registry/syscall.go
@@ -0,0 +1,33 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package registry
+
+import "syscall"
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
+
+const (
+ _REG_OPTION_NON_VOLATILE = 0
+
+ _REG_CREATED_NEW_KEY = 1
+ _REG_OPENED_EXISTING_KEY = 2
+
+ _ERROR_NO_MORE_ITEMS syscall.Errno = 259
+)
+
+func LoadRegLoadMUIString() error {
+ return procRegLoadMUIStringW.Find()
+}
+
+//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
+//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
+//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
+//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
+//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
+//sys regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) = advapi32.RegLoadMUIStringW
+
+//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW
diff --git a/vendor/golang.org/x/sys/windows/registry/value.go b/vendor/golang.org/x/sys/windows/registry/value.go
new file mode 100644
index 000000000..71d4e15ba
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/registry/value.go
@@ -0,0 +1,384 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package registry
+
+import (
+ "errors"
+ "io"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+const (
+ // Registry value types.
+ NONE = 0
+ SZ = 1
+ EXPAND_SZ = 2
+ BINARY = 3
+ DWORD = 4
+ DWORD_BIG_ENDIAN = 5
+ LINK = 6
+ MULTI_SZ = 7
+ RESOURCE_LIST = 8
+ FULL_RESOURCE_DESCRIPTOR = 9
+ RESOURCE_REQUIREMENTS_LIST = 10
+ QWORD = 11
+)
+
+var (
+ // ErrShortBuffer is returned when the buffer was too short for the operation.
+ ErrShortBuffer = syscall.ERROR_MORE_DATA
+
+ // ErrNotExist is returned when a registry key or value does not exist.
+ ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
+
+ // ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
+ ErrUnexpectedType = errors.New("unexpected key value type")
+)
+
+// GetValue retrieves the type and data for the specified value associated
+// with an open key k. It fills up buffer buf and returns the retrieved
+// byte count n. If buf is too small to fit the stored value it returns
+// ErrShortBuffer error along with the required buffer size n.
+// If no buffer is provided, it returns true and actual buffer size n.
+// If no buffer is provided, GetValue returns the value's type only.
+// If the value does not exist, the error returned is ErrNotExist.
+//
+// GetValue is a low level function. If value's type is known, use the appropriate
+// Get*Value function instead.
+func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
+ pname, err := syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return 0, 0, err
+ }
+ var pbuf *byte
+ if len(buf) > 0 {
+ pbuf = (*byte)(unsafe.Pointer(&buf[0]))
+ }
+ l := uint32(len(buf))
+ err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
+ if err != nil {
+ return int(l), valtype, err
+ }
+ return int(l), valtype, nil
+}
+
+func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) {
+ p, err := syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return nil, 0, err
+ }
+ var t uint32
+ n := uint32(len(buf))
+ for {
+ err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
+ if err == nil {
+ return buf[:n], t, nil
+ }
+ if err != syscall.ERROR_MORE_DATA {
+ return nil, 0, err
+ }
+ if n <= uint32(len(buf)) {
+ return nil, 0, err
+ }
+ buf = make([]byte, n)
+ }
+}
+
+// GetStringValue retrieves the string value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetStringValue returns ErrNotExist.
+// If value is not SZ or EXPAND_SZ, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
+ data, typ, err2 := k.getValue(name, make([]byte, 64))
+ if err2 != nil {
+ return "", typ, err2
+ }
+ switch typ {
+ case SZ, EXPAND_SZ:
+ default:
+ return "", typ, ErrUnexpectedType
+ }
+ if len(data) == 0 {
+ return "", typ, nil
+ }
+ u := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:]
+ return syscall.UTF16ToString(u), typ, nil
+}
+
+// GetMUIStringValue retrieves the localized string value for
+// the specified value name associated with an open key k.
+// If the value name doesn't exist or the localized string value
+// can't be resolved, GetMUIStringValue returns ErrNotExist.
+// GetMUIStringValue panics if the system doesn't support
+// regLoadMUIString; use LoadRegLoadMUIString to check if
+// regLoadMUIString is supported before calling this function.
+func (k Key) GetMUIStringValue(name string) (string, error) {
+ pname, err := syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return "", err
+ }
+
+ buf := make([]uint16, 1024)
+ var buflen uint32
+ var pdir *uint16
+
+ err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
+ if err == syscall.ERROR_FILE_NOT_FOUND { // Try fallback path
+
+ // Try to resolve the string value using the system directory as
+ // a DLL search path; this assumes the string value is of the form
+ // @[path]\dllname,-strID but with no path given, e.g. @tzres.dll,-320.
+
+ // This approach works with tzres.dll but may have to be revised
+ // in the future to allow callers to provide custom search paths.
+
+ var s string
+ s, err = ExpandString("%SystemRoot%\\system32\\")
+ if err != nil {
+ return "", err
+ }
+ pdir, err = syscall.UTF16PtrFromString(s)
+ if err != nil {
+ return "", err
+ }
+
+ err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
+ }
+
+ for err == syscall.ERROR_MORE_DATA { // Grow buffer if needed
+ if buflen <= uint32(len(buf)) {
+ break // Buffer not growing, assume race; break
+ }
+ buf = make([]uint16, buflen)
+ err = regLoadMUIString(syscall.Handle(k), pname, &buf[0], uint32(len(buf)), &buflen, 0, pdir)
+ }
+
+ if err != nil {
+ return "", err
+ }
+
+ return syscall.UTF16ToString(buf), nil
+}
+
+// ExpandString expands environment-variable strings and replaces
+// them with the values defined for the current user.
+// Use ExpandString to expand EXPAND_SZ strings.
+func ExpandString(value string) (string, error) {
+ if value == "" {
+ return "", nil
+ }
+ p, err := syscall.UTF16PtrFromString(value)
+ if err != nil {
+ return "", err
+ }
+ r := make([]uint16, 100)
+ for {
+ n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
+ if err != nil {
+ return "", err
+ }
+ if n <= uint32(len(r)) {
+ u := (*[1 << 29]uint16)(unsafe.Pointer(&r[0]))[:]
+ return syscall.UTF16ToString(u), nil
+ }
+ r = make([]uint16, n)
+ }
+}
+
+// GetStringsValue retrieves the []string value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetStringsValue returns ErrNotExist.
+// If value is not MULTI_SZ, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
+ data, typ, err2 := k.getValue(name, make([]byte, 64))
+ if err2 != nil {
+ return nil, typ, err2
+ }
+ if typ != MULTI_SZ {
+ return nil, typ, ErrUnexpectedType
+ }
+ if len(data) == 0 {
+ return nil, typ, nil
+ }
+ p := (*[1 << 29]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
+ if len(p) == 0 {
+ return nil, typ, nil
+ }
+ if p[len(p)-1] == 0 {
+ p = p[:len(p)-1] // remove terminating null
+ }
+ val = make([]string, 0, 5)
+ from := 0
+ for i, c := range p {
+ if c == 0 {
+ val = append(val, string(utf16.Decode(p[from:i])))
+ from = i + 1
+ }
+ }
+ return val, typ, nil
+}
+
+// GetIntegerValue retrieves the integer value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetIntegerValue returns ErrNotExist.
+// If value is not DWORD or QWORD, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
+ data, typ, err2 := k.getValue(name, make([]byte, 8))
+ if err2 != nil {
+ return 0, typ, err2
+ }
+ switch typ {
+ case DWORD:
+ if len(data) != 4 {
+ return 0, typ, errors.New("DWORD value is not 4 bytes long")
+ }
+ return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
+ case QWORD:
+ if len(data) != 8 {
+ return 0, typ, errors.New("QWORD value is not 8 bytes long")
+ }
+ return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
+ default:
+ return 0, typ, ErrUnexpectedType
+ }
+}
+
+// GetBinaryValue retrieves the binary value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetBinaryValue returns ErrNotExist.
+// If value is not BINARY, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
+ data, typ, err2 := k.getValue(name, make([]byte, 64))
+ if err2 != nil {
+ return nil, typ, err2
+ }
+ if typ != BINARY {
+ return nil, typ, ErrUnexpectedType
+ }
+ return data, typ, nil
+}
+
+func (k Key) setValue(name string, valtype uint32, data []byte) error {
+ p, err := syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return err
+ }
+ if len(data) == 0 {
+ return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
+ }
+ return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
+}
+
+// SetDWordValue sets the data and type of a name value
+// under key k to value and DWORD.
+func (k Key) SetDWordValue(name string, value uint32) error {
+ return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
+}
+
+// SetQWordValue sets the data and type of a name value
+// under key k to value and QWORD.
+func (k Key) SetQWordValue(name string, value uint64) error {
+ return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
+}
+
+func (k Key) setStringValue(name string, valtype uint32, value string) error {
+ v, err := syscall.UTF16FromString(value)
+ if err != nil {
+ return err
+ }
+ buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+ return k.setValue(name, valtype, buf)
+}
+
+// SetStringValue sets the data and type of a name value
+// under key k to value and SZ. The value must not contain a zero byte.
+func (k Key) SetStringValue(name, value string) error {
+ return k.setStringValue(name, SZ, value)
+}
+
+// SetExpandStringValue sets the data and type of a name value
+// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
+func (k Key) SetExpandStringValue(name, value string) error {
+ return k.setStringValue(name, EXPAND_SZ, value)
+}
+
+// SetStringsValue sets the data and type of a name value
+// under key k to value and MULTI_SZ. The value strings
+// must not contain a zero byte.
+func (k Key) SetStringsValue(name string, value []string) error {
+ ss := ""
+ for _, s := range value {
+ for i := 0; i < len(s); i++ {
+ if s[i] == 0 {
+ return errors.New("string cannot have 0 inside")
+ }
+ }
+ ss += s + "\x00"
+ }
+ v := utf16.Encode([]rune(ss + "\x00"))
+ buf := (*[1 << 29]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+ return k.setValue(name, MULTI_SZ, buf)
+}
+
+// SetBinaryValue sets the data and type of a name value
+// under key k to value and BINARY.
+func (k Key) SetBinaryValue(name string, value []byte) error {
+ return k.setValue(name, BINARY, value)
+}
+
+// DeleteValue removes a named value from the key k.
+func (k Key) DeleteValue(name string) error {
+ return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
+}
+
+// ReadValueNames returns the value names of key k.
+// The parameter n controls the number of returned names,
+// analogous to the way os.File.Readdirnames works.
+func (k Key) ReadValueNames(n int) ([]string, error) {
+ ki, err := k.Stat()
+ if err != nil {
+ return nil, err
+ }
+ names := make([]string, 0, ki.ValueCount)
+ buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
+loopItems:
+ for i := uint32(0); ; i++ {
+ if n > 0 {
+ if len(names) == n {
+ return names, nil
+ }
+ }
+ l := uint32(len(buf))
+ for {
+ err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
+ if err == nil {
+ break
+ }
+ if err == syscall.ERROR_MORE_DATA {
+ // Double buffer size and try again.
+ l = uint32(2 * len(buf))
+ buf = make([]uint16, l)
+ continue
+ }
+ if err == _ERROR_NO_MORE_ITEMS {
+ break loopItems
+ }
+ return names, err
+ }
+ names = append(names, syscall.UTF16ToString(buf[:l]))
+ }
+ if n > len(names) {
+ return names, io.EOF
+ }
+ return names, nil
+}
diff --git a/vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go
new file mode 100644
index 000000000..0fa24c6db
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/registry/zsyscall_windows.go
@@ -0,0 +1,85 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package registry
+
+import (
+ "golang.org/x/sys/windows"
+ "syscall"
+ "unsafe"
+)
+
+var _ unsafe.Pointer
+
+var (
+ modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
+ modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
+
+ procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW")
+ procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW")
+ procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW")
+ procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
+ procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW")
+ procRegLoadMUIStringW = modadvapi32.NewProc("RegLoadMUIStringW")
+ procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
+)
+
+func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
+ r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
+ r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0)
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
+ r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
+ r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0)
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
+ r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func regLoadMUIString(key syscall.Handle, name *uint16, buf *uint16, buflen uint32, buflenCopied *uint32, flags uint32, dir *uint16) (regerrno error) {
+ r0, _, _ := syscall.Syscall9(procRegLoadMUIStringW.Addr(), 7, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(unsafe.Pointer(buflenCopied)), uintptr(flags), uintptr(unsafe.Pointer(dir)), 0, 0)
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
diff --git a/vendor/golang.org/x/sys/windows/security_windows.go b/vendor/golang.org/x/sys/windows/security_windows.go
new file mode 100644
index 000000000..ca09bdd70
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/security_windows.go
@@ -0,0 +1,435 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+const (
+ STANDARD_RIGHTS_REQUIRED = 0xf0000
+ STANDARD_RIGHTS_READ = 0x20000
+ STANDARD_RIGHTS_WRITE = 0x20000
+ STANDARD_RIGHTS_EXECUTE = 0x20000
+ STANDARD_RIGHTS_ALL = 0x1F0000
+)
+
+const (
+ NameUnknown = 0
+ NameFullyQualifiedDN = 1
+ NameSamCompatible = 2
+ NameDisplay = 3
+ NameUniqueId = 6
+ NameCanonical = 7
+ NameUserPrincipal = 8
+ NameCanonicalEx = 9
+ NameServicePrincipal = 10
+ NameDnsDomain = 12
+)
+
+// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
+// http://blogs.msdn.com/b/drnick/archive/2007/12/19/windows-and-upn-format-credentials.aspx
+//sys TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.TranslateNameW
+//sys GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) [failretval&0xff==0] = secur32.GetUserNameExW
+
+// TranslateAccountName converts a directory service
+// object name from one format to another.
+func TranslateAccountName(username string, from, to uint32, initSize int) (string, error) {
+ u, e := UTF16PtrFromString(username)
+ if e != nil {
+ return "", e
+ }
+ n := uint32(50)
+ for {
+ b := make([]uint16, n)
+ e = TranslateName(u, from, to, &b[0], &n)
+ if e == nil {
+ return UTF16ToString(b[:n]), nil
+ }
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return "", e
+ }
+ if n <= uint32(len(b)) {
+ return "", e
+ }
+ }
+}
+
+const (
+ // do not reorder
+ NetSetupUnknownStatus = iota
+ NetSetupUnjoined
+ NetSetupWorkgroupName
+ NetSetupDomainName
+)
+
+type UserInfo10 struct {
+ Name *uint16
+ Comment *uint16
+ UsrComment *uint16
+ FullName *uint16
+}
+
+//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
+//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
+//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
+
+const (
+ // do not reorder
+ SidTypeUser = 1 + iota
+ SidTypeGroup
+ SidTypeDomain
+ SidTypeAlias
+ SidTypeWellKnownGroup
+ SidTypeDeletedAccount
+ SidTypeInvalid
+ SidTypeUnknown
+ SidTypeComputer
+ SidTypeLabel
+)
+
+type SidIdentifierAuthority struct {
+ Value [6]byte
+}
+
+var (
+ SECURITY_NULL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 0}}
+ SECURITY_WORLD_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 1}}
+ SECURITY_LOCAL_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 2}}
+ SECURITY_CREATOR_SID_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 3}}
+ SECURITY_NON_UNIQUE_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 4}}
+ SECURITY_NT_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 5}}
+ SECURITY_MANDATORY_LABEL_AUTHORITY = SidIdentifierAuthority{[6]byte{0, 0, 0, 0, 0, 16}}
+)
+
+const (
+ SECURITY_NULL_RID = 0
+ SECURITY_WORLD_RID = 0
+ SECURITY_LOCAL_RID = 0
+ SECURITY_CREATOR_OWNER_RID = 0
+ SECURITY_CREATOR_GROUP_RID = 1
+ SECURITY_DIALUP_RID = 1
+ SECURITY_NETWORK_RID = 2
+ SECURITY_BATCH_RID = 3
+ SECURITY_INTERACTIVE_RID = 4
+ SECURITY_LOGON_IDS_RID = 5
+ SECURITY_SERVICE_RID = 6
+ SECURITY_LOCAL_SYSTEM_RID = 18
+ SECURITY_BUILTIN_DOMAIN_RID = 32
+ SECURITY_PRINCIPAL_SELF_RID = 10
+ SECURITY_CREATOR_OWNER_SERVER_RID = 0x2
+ SECURITY_CREATOR_GROUP_SERVER_RID = 0x3
+ SECURITY_LOGON_IDS_RID_COUNT = 0x3
+ SECURITY_ANONYMOUS_LOGON_RID = 0x7
+ SECURITY_PROXY_RID = 0x8
+ SECURITY_ENTERPRISE_CONTROLLERS_RID = 0x9
+ SECURITY_SERVER_LOGON_RID = SECURITY_ENTERPRISE_CONTROLLERS_RID
+ SECURITY_AUTHENTICATED_USER_RID = 0xb
+ SECURITY_RESTRICTED_CODE_RID = 0xc
+ SECURITY_NT_NON_UNIQUE_RID = 0x15
+)
+
+//sys LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountSidW
+//sys LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) = advapi32.LookupAccountNameW
+//sys ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) = advapi32.ConvertSidToStringSidW
+//sys ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) = advapi32.ConvertStringSidToSidW
+//sys GetLengthSid(sid *SID) (len uint32) = advapi32.GetLengthSid
+//sys CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) = advapi32.CopySid
+//sys AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) = advapi32.AllocateAndInitializeSid
+//sys FreeSid(sid *SID) (err error) [failretval!=0] = advapi32.FreeSid
+//sys EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) = advapi32.EqualSid
+
+// The security identifier (SID) structure is a variable-length
+// structure used to uniquely identify users or groups.
+type SID struct{}
+
+// StringToSid converts a string-format security identifier
+// sid into a valid, functional sid.
+func StringToSid(s string) (*SID, error) {
+ var sid *SID
+ p, e := UTF16PtrFromString(s)
+ if e != nil {
+ return nil, e
+ }
+ e = ConvertStringSidToSid(p, &sid)
+ if e != nil {
+ return nil, e
+ }
+ defer LocalFree((Handle)(unsafe.Pointer(sid)))
+ return sid.Copy()
+}
+
+// LookupSID retrieves a security identifier sid for the account
+// and the name of the domain on which the account was found.
+// System specify target computer to search.
+func LookupSID(system, account string) (sid *SID, domain string, accType uint32, err error) {
+ if len(account) == 0 {
+ return nil, "", 0, syscall.EINVAL
+ }
+ acc, e := UTF16PtrFromString(account)
+ if e != nil {
+ return nil, "", 0, e
+ }
+ var sys *uint16
+ if len(system) > 0 {
+ sys, e = UTF16PtrFromString(system)
+ if e != nil {
+ return nil, "", 0, e
+ }
+ }
+ n := uint32(50)
+ dn := uint32(50)
+ for {
+ b := make([]byte, n)
+ db := make([]uint16, dn)
+ sid = (*SID)(unsafe.Pointer(&b[0]))
+ e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+ if e == nil {
+ return sid, UTF16ToString(db), accType, nil
+ }
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return nil, "", 0, e
+ }
+ if n <= uint32(len(b)) {
+ return nil, "", 0, e
+ }
+ }
+}
+
+// String converts sid to a string format
+// suitable for display, storage, or transmission.
+func (sid *SID) String() (string, error) {
+ var s *uint16
+ e := ConvertSidToStringSid(sid, &s)
+ if e != nil {
+ return "", e
+ }
+ defer LocalFree((Handle)(unsafe.Pointer(s)))
+ return UTF16ToString((*[256]uint16)(unsafe.Pointer(s))[:]), nil
+}
+
+// Len returns the length, in bytes, of a valid security identifier sid.
+func (sid *SID) Len() int {
+ return int(GetLengthSid(sid))
+}
+
+// Copy creates a duplicate of security identifier sid.
+func (sid *SID) Copy() (*SID, error) {
+ b := make([]byte, sid.Len())
+ sid2 := (*SID)(unsafe.Pointer(&b[0]))
+ e := CopySid(uint32(len(b)), sid2, sid)
+ if e != nil {
+ return nil, e
+ }
+ return sid2, nil
+}
+
+// LookupAccount retrieves the name of the account for this sid
+// and the name of the first domain on which this sid is found.
+// System specify target computer to search for.
+func (sid *SID) LookupAccount(system string) (account, domain string, accType uint32, err error) {
+ var sys *uint16
+ if len(system) > 0 {
+ sys, err = UTF16PtrFromString(system)
+ if err != nil {
+ return "", "", 0, err
+ }
+ }
+ n := uint32(50)
+ dn := uint32(50)
+ for {
+ b := make([]uint16, n)
+ db := make([]uint16, dn)
+ e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+ if e == nil {
+ return UTF16ToString(b), UTF16ToString(db), accType, nil
+ }
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return "", "", 0, e
+ }
+ if n <= uint32(len(b)) {
+ return "", "", 0, e
+ }
+ }
+}
+
+const (
+ // do not reorder
+ TOKEN_ASSIGN_PRIMARY = 1 << iota
+ TOKEN_DUPLICATE
+ TOKEN_IMPERSONATE
+ TOKEN_QUERY
+ TOKEN_QUERY_SOURCE
+ TOKEN_ADJUST_PRIVILEGES
+ TOKEN_ADJUST_GROUPS
+ TOKEN_ADJUST_DEFAULT
+
+ TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
+ TOKEN_ASSIGN_PRIMARY |
+ TOKEN_DUPLICATE |
+ TOKEN_IMPERSONATE |
+ TOKEN_QUERY |
+ TOKEN_QUERY_SOURCE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT
+ TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
+ TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT
+ TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE
+)
+
+const (
+ // do not reorder
+ TokenUser = 1 + iota
+ TokenGroups
+ TokenPrivileges
+ TokenOwner
+ TokenPrimaryGroup
+ TokenDefaultDacl
+ TokenSource
+ TokenType
+ TokenImpersonationLevel
+ TokenStatistics
+ TokenRestrictedSids
+ TokenSessionId
+ TokenGroupsAndPrivileges
+ TokenSessionReference
+ TokenSandBoxInert
+ TokenAuditPolicy
+ TokenOrigin
+ TokenElevationType
+ TokenLinkedToken
+ TokenElevation
+ TokenHasRestrictions
+ TokenAccessInformation
+ TokenVirtualizationAllowed
+ TokenVirtualizationEnabled
+ TokenIntegrityLevel
+ TokenUIAccess
+ TokenMandatoryPolicy
+ TokenLogonSid
+ MaxTokenInfoClass
+)
+
+type SIDAndAttributes struct {
+ Sid *SID
+ Attributes uint32
+}
+
+type Tokenuser struct {
+ User SIDAndAttributes
+}
+
+type Tokenprimarygroup struct {
+ PrimaryGroup *SID
+}
+
+type Tokengroups struct {
+ GroupCount uint32
+ Groups [1]SIDAndAttributes
+}
+
+//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken
+//sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation
+//sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW
+
+// An access token contains the security information for a logon session.
+// The system creates an access token when a user logs on, and every
+// process executed on behalf of the user has a copy of the token.
+// The token identifies the user, the user's groups, and the user's
+// privileges. The system uses the token to control access to securable
+// objects and to control the ability of the user to perform various
+// system-related operations on the local computer.
+type Token Handle
+
+// OpenCurrentProcessToken opens the access token
+// associated with current process.
+func OpenCurrentProcessToken() (Token, error) {
+ p, e := GetCurrentProcess()
+ if e != nil {
+ return 0, e
+ }
+ var t Token
+ e = OpenProcessToken(p, TOKEN_QUERY, &t)
+ if e != nil {
+ return 0, e
+ }
+ return t, nil
+}
+
+// Close releases access to access token.
+func (t Token) Close() error {
+ return CloseHandle(Handle(t))
+}
+
+// getInfo retrieves a specified type of information about an access token.
+func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
+ n := uint32(initSize)
+ for {
+ b := make([]byte, n)
+ e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+ if e == nil {
+ return unsafe.Pointer(&b[0]), nil
+ }
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return nil, e
+ }
+ if n <= uint32(len(b)) {
+ return nil, e
+ }
+ }
+}
+
+// GetTokenUser retrieves access token t user account information.
+func (t Token) GetTokenUser() (*Tokenuser, error) {
+ i, e := t.getInfo(TokenUser, 50)
+ if e != nil {
+ return nil, e
+ }
+ return (*Tokenuser)(i), nil
+}
+
+// GetTokenGroups retrieves group accounts associated with access token t.
+func (t Token) GetTokenGroups() (*Tokengroups, error) {
+ i, e := t.getInfo(TokenGroups, 50)
+ if e != nil {
+ return nil, e
+ }
+ return (*Tokengroups)(i), nil
+}
+
+// GetTokenPrimaryGroup retrieves access token t primary group information.
+// A pointer to a SID structure representing a group that will become
+// the primary group of any objects created by a process using this access token.
+func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
+ i, e := t.getInfo(TokenPrimaryGroup, 50)
+ if e != nil {
+ return nil, e
+ }
+ return (*Tokenprimarygroup)(i), nil
+}
+
+// GetUserProfileDirectory retrieves path to the
+// root directory of the access token t user's profile.
+func (t Token) GetUserProfileDirectory() (string, error) {
+ n := uint32(100)
+ for {
+ b := make([]uint16, n)
+ e := GetUserProfileDirectory(t, &b[0], &n)
+ if e == nil {
+ return UTF16ToString(b), nil
+ }
+ if e != ERROR_INSUFFICIENT_BUFFER {
+ return "", e
+ }
+ if n <= uint32(len(b)) {
+ return "", e
+ }
+ }
+}
diff --git a/vendor/golang.org/x/sys/windows/service.go b/vendor/golang.org/x/sys/windows/service.go
new file mode 100644
index 000000000..1c11d392f
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/service.go
@@ -0,0 +1,143 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package windows
+
+const (
+ SC_MANAGER_CONNECT = 1
+ SC_MANAGER_CREATE_SERVICE = 2
+ SC_MANAGER_ENUMERATE_SERVICE = 4
+ SC_MANAGER_LOCK = 8
+ SC_MANAGER_QUERY_LOCK_STATUS = 16
+ SC_MANAGER_MODIFY_BOOT_CONFIG = 32
+ SC_MANAGER_ALL_ACCESS = 0xf003f
+)
+
+//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW
+
+const (
+ SERVICE_KERNEL_DRIVER = 1
+ SERVICE_FILE_SYSTEM_DRIVER = 2
+ SERVICE_ADAPTER = 4
+ SERVICE_RECOGNIZER_DRIVER = 8
+ SERVICE_WIN32_OWN_PROCESS = 16
+ SERVICE_WIN32_SHARE_PROCESS = 32
+ SERVICE_WIN32 = SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS
+ SERVICE_INTERACTIVE_PROCESS = 256
+ SERVICE_DRIVER = SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER | SERVICE_RECOGNIZER_DRIVER
+ SERVICE_TYPE_ALL = SERVICE_WIN32 | SERVICE_ADAPTER | SERVICE_DRIVER | SERVICE_INTERACTIVE_PROCESS
+
+ SERVICE_BOOT_START = 0
+ SERVICE_SYSTEM_START = 1
+ SERVICE_AUTO_START = 2
+ SERVICE_DEMAND_START = 3
+ SERVICE_DISABLED = 4
+
+ SERVICE_ERROR_IGNORE = 0
+ SERVICE_ERROR_NORMAL = 1
+ SERVICE_ERROR_SEVERE = 2
+ SERVICE_ERROR_CRITICAL = 3
+
+ SC_STATUS_PROCESS_INFO = 0
+
+ SERVICE_STOPPED = 1
+ SERVICE_START_PENDING = 2
+ SERVICE_STOP_PENDING = 3
+ SERVICE_RUNNING = 4
+ SERVICE_CONTINUE_PENDING = 5
+ SERVICE_PAUSE_PENDING = 6
+ SERVICE_PAUSED = 7
+ SERVICE_NO_CHANGE = 0xffffffff
+
+ SERVICE_ACCEPT_STOP = 1
+ SERVICE_ACCEPT_PAUSE_CONTINUE = 2
+ SERVICE_ACCEPT_SHUTDOWN = 4
+ SERVICE_ACCEPT_PARAMCHANGE = 8
+ SERVICE_ACCEPT_NETBINDCHANGE = 16
+ SERVICE_ACCEPT_HARDWAREPROFILECHANGE = 32
+ SERVICE_ACCEPT_POWEREVENT = 64
+ SERVICE_ACCEPT_SESSIONCHANGE = 128
+
+ SERVICE_CONTROL_STOP = 1
+ SERVICE_CONTROL_PAUSE = 2
+ SERVICE_CONTROL_CONTINUE = 3
+ SERVICE_CONTROL_INTERROGATE = 4
+ SERVICE_CONTROL_SHUTDOWN = 5
+ SERVICE_CONTROL_PARAMCHANGE = 6
+ SERVICE_CONTROL_NETBINDADD = 7
+ SERVICE_CONTROL_NETBINDREMOVE = 8
+ SERVICE_CONTROL_NETBINDENABLE = 9
+ SERVICE_CONTROL_NETBINDDISABLE = 10
+ SERVICE_CONTROL_DEVICEEVENT = 11
+ SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12
+ SERVICE_CONTROL_POWEREVENT = 13
+ SERVICE_CONTROL_SESSIONCHANGE = 14
+
+ SERVICE_ACTIVE = 1
+ SERVICE_INACTIVE = 2
+ SERVICE_STATE_ALL = 3
+
+ SERVICE_QUERY_CONFIG = 1
+ SERVICE_CHANGE_CONFIG = 2
+ SERVICE_QUERY_STATUS = 4
+ SERVICE_ENUMERATE_DEPENDENTS = 8
+ SERVICE_START = 16
+ SERVICE_STOP = 32
+ SERVICE_PAUSE_CONTINUE = 64
+ SERVICE_INTERROGATE = 128
+ SERVICE_USER_DEFINED_CONTROL = 256
+ SERVICE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL
+ SERVICE_RUNS_IN_SYSTEM_PROCESS = 1
+ SERVICE_CONFIG_DESCRIPTION = 1
+ SERVICE_CONFIG_FAILURE_ACTIONS = 2
+
+ NO_ERROR = 0
+)
+
+type SERVICE_STATUS struct {
+ ServiceType uint32
+ CurrentState uint32
+ ControlsAccepted uint32
+ Win32ExitCode uint32
+ ServiceSpecificExitCode uint32
+ CheckPoint uint32
+ WaitHint uint32
+}
+
+type SERVICE_TABLE_ENTRY struct {
+ ServiceName *uint16
+ ServiceProc uintptr
+}
+
+type QUERY_SERVICE_CONFIG struct {
+ ServiceType uint32
+ StartType uint32
+ ErrorControl uint32
+ BinaryPathName *uint16
+ LoadOrderGroup *uint16
+ TagId uint32
+ Dependencies *uint16
+ ServiceStartName *uint16
+ DisplayName *uint16
+}
+
+type SERVICE_DESCRIPTION struct {
+ Description *uint16
+}
+
+//sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle
+//sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW
+//sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW
+//sys DeleteService(service Handle) (err error) = advapi32.DeleteService
+//sys StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) = advapi32.StartServiceW
+//sys QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus
+//sys ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) = advapi32.ControlService
+//sys StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) = advapi32.StartServiceCtrlDispatcherW
+//sys SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) = advapi32.SetServiceStatus
+//sys ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) = advapi32.ChangeServiceConfigW
+//sys QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfigW
+//sys ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) = advapi32.ChangeServiceConfig2W
+//sys QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) = advapi32.QueryServiceConfig2W
diff --git a/vendor/golang.org/x/sys/windows/str.go b/vendor/golang.org/x/sys/windows/str.go
new file mode 100644
index 000000000..917cc2aae
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/str.go
@@ -0,0 +1,22 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package windows
+
+func itoa(val int) string { // do it here rather than with fmt to avoid dependency
+ if val < 0 {
+ return "-" + itoa(-val)
+ }
+ var buf [32]byte // big enough for int64
+ i := len(buf) - 1
+ for val >= 10 {
+ buf[i] = byte(val%10 + '0')
+ i--
+ val /= 10
+ }
+ buf[i] = byte(val + '0')
+ return string(buf[i:])
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/debug/log.go b/vendor/golang.org/x/sys/windows/svc/debug/log.go
new file mode 100644
index 000000000..e51ab42a1
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/debug/log.go
@@ -0,0 +1,56 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package debug
+
+import (
+ "os"
+ "strconv"
+)
+
+// Log interface allows different log implementations to be used.
+type Log interface {
+ Close() error
+ Info(eid uint32, msg string) error
+ Warning(eid uint32, msg string) error
+ Error(eid uint32, msg string) error
+}
+
+// ConsoleLog provides access to the console.
+type ConsoleLog struct {
+ Name string
+}
+
+// New creates new ConsoleLog.
+func New(source string) *ConsoleLog {
+ return &ConsoleLog{Name: source}
+}
+
+// Close closes console log l.
+func (l *ConsoleLog) Close() error {
+ return nil
+}
+
+func (l *ConsoleLog) report(kind string, eid uint32, msg string) error {
+ s := l.Name + "." + kind + "(" + strconv.Itoa(int(eid)) + "): " + msg + "\n"
+ _, err := os.Stdout.Write([]byte(s))
+ return err
+}
+
+// Info writes an information event msg with event id eid to the console l.
+func (l *ConsoleLog) Info(eid uint32, msg string) error {
+ return l.report("info", eid, msg)
+}
+
+// Warning writes an warning event msg with event id eid to the console l.
+func (l *ConsoleLog) Warning(eid uint32, msg string) error {
+ return l.report("warn", eid, msg)
+}
+
+// Error writes an error event msg with event id eid to the console l.
+func (l *ConsoleLog) Error(eid uint32, msg string) error {
+ return l.report("error", eid, msg)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/debug/service.go b/vendor/golang.org/x/sys/windows/svc/debug/service.go
new file mode 100644
index 000000000..d5ab94b2c
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/debug/service.go
@@ -0,0 +1,45 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package debug provides facilities to execute svc.Handler on console.
+//
+package debug
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+
+ "golang.org/x/sys/windows/svc"
+)
+
+// Run executes service name by calling appropriate handler function.
+// The process is running on console, unlike real service. Use Ctrl+C to
+// send "Stop" command to your service.
+func Run(name string, handler svc.Handler) error {
+ cmds := make(chan svc.ChangeRequest)
+ changes := make(chan svc.Status)
+
+ sig := make(chan os.Signal)
+ signal.Notify(sig)
+
+ go func() {
+ status := svc.Status{State: svc.Stopped}
+ for {
+ select {
+ case <-sig:
+ cmds <- svc.ChangeRequest{svc.Stop, status}
+ case status = <-changes:
+ }
+ }
+ }()
+
+ _, errno := handler.Execute([]string{name}, cmds, changes)
+ if errno != 0 {
+ return syscall.Errno(errno)
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/event.go b/vendor/golang.org/x/sys/windows/svc/event.go
new file mode 100644
index 000000000..0508e2288
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/event.go
@@ -0,0 +1,48 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package svc
+
+import (
+ "errors"
+
+ "golang.org/x/sys/windows"
+)
+
+// event represents auto-reset, initially non-signaled Windows event.
+// It is used to communicate between go and asm parts of this package.
+type event struct {
+ h windows.Handle
+}
+
+func newEvent() (*event, error) {
+ h, err := windows.CreateEvent(nil, 0, 0, nil)
+ if err != nil {
+ return nil, err
+ }
+ return &event{h: h}, nil
+}
+
+func (e *event) Close() error {
+ return windows.CloseHandle(e.h)
+}
+
+func (e *event) Set() error {
+ return windows.SetEvent(e.h)
+}
+
+func (e *event) Wait() error {
+ s, err := windows.WaitForSingleObject(e.h, windows.INFINITE)
+ switch s {
+ case windows.WAIT_OBJECT_0:
+ break
+ case windows.WAIT_FAILED:
+ return err
+ default:
+ return errors.New("unexpected result from WaitForSingleObject")
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/eventlog/install.go b/vendor/golang.org/x/sys/windows/svc/eventlog/install.go
new file mode 100644
index 000000000..c76a3760a
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/eventlog/install.go
@@ -0,0 +1,80 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package eventlog
+
+import (
+ "errors"
+
+ "golang.org/x/sys/windows"
+ "golang.org/x/sys/windows/registry"
+)
+
+const (
+ // Log levels.
+ Info = windows.EVENTLOG_INFORMATION_TYPE
+ Warning = windows.EVENTLOG_WARNING_TYPE
+ Error = windows.EVENTLOG_ERROR_TYPE
+)
+
+const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
+
+// Install modifies PC registry to allow logging with an event source src.
+// It adds all required keys and values to the event log registry key.
+// Install uses msgFile as the event message file. If useExpandKey is true,
+// the event message file is installed as REG_EXPAND_SZ value,
+// otherwise as REG_SZ. Use bitwise of log.Error, log.Warning and
+// log.Info to specify events supported by the new event source.
+func Install(src, msgFile string, useExpandKey bool, eventsSupported uint32) error {
+ appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.CREATE_SUB_KEY)
+ if err != nil {
+ return err
+ }
+ defer appkey.Close()
+
+ sk, alreadyExist, err := registry.CreateKey(appkey, src, registry.SET_VALUE)
+ if err != nil {
+ return err
+ }
+ defer sk.Close()
+ if alreadyExist {
+ return errors.New(addKeyName + `\` + src + " registry key already exists")
+ }
+
+ err = sk.SetDWordValue("CustomSource", 1)
+ if err != nil {
+ return err
+ }
+ if useExpandKey {
+ err = sk.SetExpandStringValue("EventMessageFile", msgFile)
+ } else {
+ err = sk.SetStringValue("EventMessageFile", msgFile)
+ }
+ if err != nil {
+ return err
+ }
+ err = sk.SetDWordValue("TypesSupported", eventsSupported)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// InstallAsEventCreate is the same as Install, but uses
+// %SystemRoot%\System32\EventCreate.exe as the event message file.
+func InstallAsEventCreate(src string, eventsSupported uint32) error {
+ return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", true, eventsSupported)
+}
+
+// Remove deletes all registry elements installed by the correspondent Install.
+func Remove(src string) error {
+ appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.SET_VALUE)
+ if err != nil {
+ return err
+ }
+ defer appkey.Close()
+ return registry.DeleteKey(appkey, src)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/eventlog/log.go b/vendor/golang.org/x/sys/windows/svc/eventlog/log.go
new file mode 100644
index 000000000..46e5153d0
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/eventlog/log.go
@@ -0,0 +1,70 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package eventlog implements access to Windows event log.
+//
+package eventlog
+
+import (
+ "errors"
+ "syscall"
+
+ "golang.org/x/sys/windows"
+)
+
+// Log provides access to the system log.
+type Log struct {
+ Handle windows.Handle
+}
+
+// Open retrieves a handle to the specified event log.
+func Open(source string) (*Log, error) {
+ return OpenRemote("", source)
+}
+
+// OpenRemote does the same as Open, but on different computer host.
+func OpenRemote(host, source string) (*Log, error) {
+ if source == "" {
+ return nil, errors.New("Specify event log source")
+ }
+ var s *uint16
+ if host != "" {
+ s = syscall.StringToUTF16Ptr(host)
+ }
+ h, err := windows.RegisterEventSource(s, syscall.StringToUTF16Ptr(source))
+ if err != nil {
+ return nil, err
+ }
+ return &Log{Handle: h}, nil
+}
+
+// Close closes event log l.
+func (l *Log) Close() error {
+ return windows.DeregisterEventSource(l.Handle)
+}
+
+func (l *Log) report(etype uint16, eid uint32, msg string) error {
+ ss := []*uint16{syscall.StringToUTF16Ptr(msg)}
+ return windows.ReportEvent(l.Handle, etype, 0, eid, 0, 1, 0, &ss[0], nil)
+}
+
+// Info writes an information event msg with event id eid to the end of event log l.
+// When EventCreate.exe is used, eid must be between 1 and 1000.
+func (l *Log) Info(eid uint32, msg string) error {
+ return l.report(windows.EVENTLOG_INFORMATION_TYPE, eid, msg)
+}
+
+// Warning writes an warning event msg with event id eid to the end of event log l.
+// When EventCreate.exe is used, eid must be between 1 and 1000.
+func (l *Log) Warning(eid uint32, msg string) error {
+ return l.report(windows.EVENTLOG_WARNING_TYPE, eid, msg)
+}
+
+// Error writes an error event msg with event id eid to the end of event log l.
+// When EventCreate.exe is used, eid must be between 1 and 1000.
+func (l *Log) Error(eid uint32, msg string) error {
+ return l.report(windows.EVENTLOG_ERROR_TYPE, eid, msg)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go b/vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go
new file mode 100644
index 000000000..4dd8ad9e7
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/eventlog/log_test.go
@@ -0,0 +1,51 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package eventlog_test
+
+import (
+ "testing"
+
+ "golang.org/x/sys/windows/svc/eventlog"
+)
+
+func TestLog(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode - it modifies system logs")
+ }
+
+ const name = "mylog"
+ const supports = eventlog.Error | eventlog.Warning | eventlog.Info
+ err := eventlog.InstallAsEventCreate(name, supports)
+ if err != nil {
+ t.Fatalf("Install failed: %s", err)
+ }
+ defer func() {
+ err = eventlog.Remove(name)
+ if err != nil {
+ t.Fatalf("Remove failed: %s", err)
+ }
+ }()
+
+ l, err := eventlog.Open(name)
+ if err != nil {
+ t.Fatalf("Open failed: %s", err)
+ }
+ defer l.Close()
+
+ err = l.Info(1, "info")
+ if err != nil {
+ t.Fatalf("Info failed: %s", err)
+ }
+ err = l.Warning(2, "warning")
+ if err != nil {
+ t.Fatalf("Warning failed: %s", err)
+ }
+ err = l.Error(3, "error")
+ if err != nil {
+ t.Fatalf("Error failed: %s", err)
+ }
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/example/beep.go b/vendor/golang.org/x/sys/windows/svc/example/beep.go
new file mode 100644
index 000000000..dcf23408d
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/example/beep.go
@@ -0,0 +1,22 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package main
+
+import (
+ "syscall"
+)
+
+// BUG(brainman): MessageBeep Windows api is broken on Windows 7,
+// so this example does not beep when runs as service on Windows 7.
+
+var (
+ beepFunc = syscall.MustLoadDLL("user32.dll").MustFindProc("MessageBeep")
+)
+
+func beep() {
+ beepFunc.Call(0xffffffff)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/example/install.go b/vendor/golang.org/x/sys/windows/svc/example/install.go
new file mode 100644
index 000000000..39cb00d2a
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/example/install.go
@@ -0,0 +1,92 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "golang.org/x/sys/windows/svc/eventlog"
+ "golang.org/x/sys/windows/svc/mgr"
+)
+
+func exePath() (string, error) {
+ prog := os.Args[0]
+ p, err := filepath.Abs(prog)
+ if err != nil {
+ return "", err
+ }
+ fi, err := os.Stat(p)
+ if err == nil {
+ if !fi.Mode().IsDir() {
+ return p, nil
+ }
+ err = fmt.Errorf("%s is directory", p)
+ }
+ if filepath.Ext(p) == "" {
+ p += ".exe"
+ fi, err := os.Stat(p)
+ if err == nil {
+ if !fi.Mode().IsDir() {
+ return p, nil
+ }
+ err = fmt.Errorf("%s is directory", p)
+ }
+ }
+ return "", err
+}
+
+func installService(name, desc string) error {
+ exepath, err := exePath()
+ if err != nil {
+ return err
+ }
+ m, err := mgr.Connect()
+ if err != nil {
+ return err
+ }
+ defer m.Disconnect()
+ s, err := m.OpenService(name)
+ if err == nil {
+ s.Close()
+ return fmt.Errorf("service %s already exists", name)
+ }
+ s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: desc}, "is", "auto-started")
+ if err != nil {
+ return err
+ }
+ defer s.Close()
+ err = eventlog.InstallAsEventCreate(name, eventlog.Error|eventlog.Warning|eventlog.Info)
+ if err != nil {
+ s.Delete()
+ return fmt.Errorf("SetupEventLogSource() failed: %s", err)
+ }
+ return nil
+}
+
+func removeService(name string) error {
+ m, err := mgr.Connect()
+ if err != nil {
+ return err
+ }
+ defer m.Disconnect()
+ s, err := m.OpenService(name)
+ if err != nil {
+ return fmt.Errorf("service %s is not installed", name)
+ }
+ defer s.Close()
+ err = s.Delete()
+ if err != nil {
+ return err
+ }
+ err = eventlog.Remove(name)
+ if err != nil {
+ return fmt.Errorf("RemoveEventLogSource() failed: %s", err)
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/example/main.go b/vendor/golang.org/x/sys/windows/svc/example/main.go
new file mode 100644
index 000000000..dc96c081a
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/example/main.go
@@ -0,0 +1,76 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Example service program that beeps.
+//
+// The program demonstrates how to create Windows service and
+// install / remove it on a computer. It also shows how to
+// stop / start / pause / continue any service, and how to
+// write to event log. It also shows how to use debug
+// facilities available in debug package.
+//
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "strings"
+
+ "golang.org/x/sys/windows/svc"
+)
+
+func usage(errmsg string) {
+ fmt.Fprintf(os.Stderr,
+ "%s\n\n"+
+ "usage: %s <command>\n"+
+ " where <command> is one of\n"+
+ " install, remove, debug, start, stop, pause or continue.\n",
+ errmsg, os.Args[0])
+ os.Exit(2)
+}
+
+func main() {
+ const svcName = "myservice"
+
+ isIntSess, err := svc.IsAnInteractiveSession()
+ if err != nil {
+ log.Fatalf("failed to determine if we are running in an interactive session: %v", err)
+ }
+ if !isIntSess {
+ runService(svcName, false)
+ return
+ }
+
+ if len(os.Args) < 2 {
+ usage("no command specified")
+ }
+
+ cmd := strings.ToLower(os.Args[1])
+ switch cmd {
+ case "debug":
+ runService(svcName, true)
+ return
+ case "install":
+ err = installService(svcName, "my service")
+ case "remove":
+ err = removeService(svcName)
+ case "start":
+ err = startService(svcName)
+ case "stop":
+ err = controlService(svcName, svc.Stop, svc.Stopped)
+ case "pause":
+ err = controlService(svcName, svc.Pause, svc.Paused)
+ case "continue":
+ err = controlService(svcName, svc.Continue, svc.Running)
+ default:
+ usage(fmt.Sprintf("invalid command %s", cmd))
+ }
+ if err != nil {
+ log.Fatalf("failed to %s %s: %v", cmd, svcName, err)
+ }
+ return
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/example/manage.go b/vendor/golang.org/x/sys/windows/svc/example/manage.go
new file mode 100644
index 000000000..782dbd96c
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/example/manage.go
@@ -0,0 +1,62 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "golang.org/x/sys/windows/svc"
+ "golang.org/x/sys/windows/svc/mgr"
+)
+
+func startService(name string) error {
+ m, err := mgr.Connect()
+ if err != nil {
+ return err
+ }
+ defer m.Disconnect()
+ s, err := m.OpenService(name)
+ if err != nil {
+ return fmt.Errorf("could not access service: %v", err)
+ }
+ defer s.Close()
+ err = s.Start("is", "manual-started")
+ if err != nil {
+ return fmt.Errorf("could not start service: %v", err)
+ }
+ return nil
+}
+
+func controlService(name string, c svc.Cmd, to svc.State) error {
+ m, err := mgr.Connect()
+ if err != nil {
+ return err
+ }
+ defer m.Disconnect()
+ s, err := m.OpenService(name)
+ if err != nil {
+ return fmt.Errorf("could not access service: %v", err)
+ }
+ defer s.Close()
+ status, err := s.Control(c)
+ if err != nil {
+ return fmt.Errorf("could not send control=%d: %v", c, err)
+ }
+ timeout := time.Now().Add(10 * time.Second)
+ for status.State != to {
+ if timeout.Before(time.Now()) {
+ return fmt.Errorf("timeout waiting for service to go to state=%d", to)
+ }
+ time.Sleep(300 * time.Millisecond)
+ status, err = s.Query()
+ if err != nil {
+ return fmt.Errorf("could not retrieve service status: %v", err)
+ }
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/example/service.go b/vendor/golang.org/x/sys/windows/svc/example/service.go
new file mode 100644
index 000000000..237e80984
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/example/service.go
@@ -0,0 +1,82 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package main
+
+import (
+ "fmt"
+ "time"
+
+ "golang.org/x/sys/windows/svc"
+ "golang.org/x/sys/windows/svc/debug"
+ "golang.org/x/sys/windows/svc/eventlog"
+)
+
+var elog debug.Log
+
+type myservice struct{}
+
+func (m *myservice) Execute(args []string, r <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) {
+ const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue
+ changes <- svc.Status{State: svc.StartPending}
+ fasttick := time.Tick(500 * time.Millisecond)
+ slowtick := time.Tick(2 * time.Second)
+ tick := fasttick
+ changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
+loop:
+ for {
+ select {
+ case <-tick:
+ beep()
+ elog.Info(1, "beep")
+ case c := <-r:
+ switch c.Cmd {
+ case svc.Interrogate:
+ changes <- c.CurrentStatus
+ // Testing deadlock from https://code.google.com/p/winsvc/issues/detail?id=4
+ time.Sleep(100 * time.Millisecond)
+ changes <- c.CurrentStatus
+ case svc.Stop, svc.Shutdown:
+ break loop
+ case svc.Pause:
+ changes <- svc.Status{State: svc.Paused, Accepts: cmdsAccepted}
+ tick = slowtick
+ case svc.Continue:
+ changes <- svc.Status{State: svc.Running, Accepts: cmdsAccepted}
+ tick = fasttick
+ default:
+ elog.Error(1, fmt.Sprintf("unexpected control request #%d", c))
+ }
+ }
+ }
+ changes <- svc.Status{State: svc.StopPending}
+ return
+}
+
+func runService(name string, isDebug bool) {
+ var err error
+ if isDebug {
+ elog = debug.New(name)
+ } else {
+ elog, err = eventlog.Open(name)
+ if err != nil {
+ return
+ }
+ }
+ defer elog.Close()
+
+ elog.Info(1, fmt.Sprintf("starting %s service", name))
+ run := svc.Run
+ if isDebug {
+ run = debug.Run
+ }
+ err = run(name, &myservice{})
+ if err != nil {
+ elog.Error(1, fmt.Sprintf("%s service failed: %v", name, err))
+ return
+ }
+ elog.Info(1, fmt.Sprintf("%s service stopped", name))
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/go12.c b/vendor/golang.org/x/sys/windows/svc/go12.c
new file mode 100644
index 000000000..6f1be1fa3
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/go12.c
@@ -0,0 +1,24 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+// +build !go1.3
+
+// copied from pkg/runtime
+typedef unsigned int uint32;
+typedef unsigned long long int uint64;
+#ifdef _64BIT
+typedef uint64 uintptr;
+#else
+typedef uint32 uintptr;
+#endif
+
+// from sys_386.s or sys_amd64.s
+void ·servicemain(void);
+
+void
+·getServiceMain(uintptr *r)
+{
+ *r = (uintptr)·servicemain;
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/go12.go b/vendor/golang.org/x/sys/windows/svc/go12.go
new file mode 100644
index 000000000..6f0a924ea
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/go12.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+// +build !go1.3
+
+package svc
+
+// from go12.c
+func getServiceMain(r *uintptr)
diff --git a/vendor/golang.org/x/sys/windows/svc/go13.go b/vendor/golang.org/x/sys/windows/svc/go13.go
new file mode 100644
index 000000000..432a9e796
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/go13.go
@@ -0,0 +1,31 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+// +build go1.3
+
+package svc
+
+import "unsafe"
+
+const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
+
+// Should be a built-in for unsafe.Pointer?
+func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
+ return unsafe.Pointer(uintptr(p) + x)
+}
+
+// funcPC returns the entry PC of the function f.
+// It assumes that f is a func value. Otherwise the behavior is undefined.
+func funcPC(f interface{}) uintptr {
+ return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
+}
+
+// from sys_386.s and sys_amd64.s
+func servicectlhandler(ctl uint32) uintptr
+func servicemain(argc uint32, argv **uint16)
+
+func getServiceMain(r *uintptr) {
+ *r = funcPC(servicemain)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/mgr/config.go b/vendor/golang.org/x/sys/windows/svc/mgr/config.go
new file mode 100644
index 000000000..0a6edba4f
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/mgr/config.go
@@ -0,0 +1,139 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package mgr
+
+import (
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+const (
+ // Service start types.
+ StartManual = windows.SERVICE_DEMAND_START // the service must be started manually
+ StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots
+ StartDisabled = windows.SERVICE_DISABLED // the service cannot be started
+
+ // The severity of the error, and action taken,
+ // if this service fails to start.
+ ErrorCritical = windows.SERVICE_ERROR_CRITICAL
+ ErrorIgnore = windows.SERVICE_ERROR_IGNORE
+ ErrorNormal = windows.SERVICE_ERROR_NORMAL
+ ErrorSevere = windows.SERVICE_ERROR_SEVERE
+)
+
+// TODO(brainman): Password is not returned by windows.QueryServiceConfig, not sure how to get it.
+
+type Config struct {
+ ServiceType uint32
+ StartType uint32
+ ErrorControl uint32
+ BinaryPathName string // fully qualified path to the service binary file, can also include arguments for an auto-start service
+ LoadOrderGroup string
+ TagId uint32
+ Dependencies []string
+ ServiceStartName string // name of the account under which the service should run
+ DisplayName string
+ Password string
+ Description string
+}
+
+func toString(p *uint16) string {
+ if p == nil {
+ return ""
+ }
+ return syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(p))[:])
+}
+
+func toStringSlice(ps *uint16) []string {
+ if ps == nil {
+ return nil
+ }
+ r := make([]string, 0)
+ for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(ps)); true; i++ {
+ if p[i] == 0 {
+ // empty string marks the end
+ if i <= from {
+ break
+ }
+ r = append(r, string(utf16.Decode(p[from:i])))
+ from = i + 1
+ }
+ }
+ return r
+}
+
+// Config retrieves service s configuration paramteres.
+func (s *Service) Config() (Config, error) {
+ var p *windows.QUERY_SERVICE_CONFIG
+ n := uint32(1024)
+ for {
+ b := make([]byte, n)
+ p = (*windows.QUERY_SERVICE_CONFIG)(unsafe.Pointer(&b[0]))
+ err := windows.QueryServiceConfig(s.Handle, p, n, &n)
+ if err == nil {
+ break
+ }
+ if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
+ return Config{}, err
+ }
+ if n <= uint32(len(b)) {
+ return Config{}, err
+ }
+ }
+
+ var p2 *windows.SERVICE_DESCRIPTION
+ n = uint32(1024)
+ for {
+ b := make([]byte, n)
+ p2 = (*windows.SERVICE_DESCRIPTION)(unsafe.Pointer(&b[0]))
+ err := windows.QueryServiceConfig2(s.Handle,
+ windows.SERVICE_CONFIG_DESCRIPTION, &b[0], n, &n)
+ if err == nil {
+ break
+ }
+ if err.(syscall.Errno) != syscall.ERROR_INSUFFICIENT_BUFFER {
+ return Config{}, err
+ }
+ if n <= uint32(len(b)) {
+ return Config{}, err
+ }
+ }
+
+ return Config{
+ ServiceType: p.ServiceType,
+ StartType: p.StartType,
+ ErrorControl: p.ErrorControl,
+ BinaryPathName: toString(p.BinaryPathName),
+ LoadOrderGroup: toString(p.LoadOrderGroup),
+ TagId: p.TagId,
+ Dependencies: toStringSlice(p.Dependencies),
+ ServiceStartName: toString(p.ServiceStartName),
+ DisplayName: toString(p.DisplayName),
+ Description: toString(p2.Description),
+ }, nil
+}
+
+func updateDescription(handle windows.Handle, desc string) error {
+ d := windows.SERVICE_DESCRIPTION{toPtr(desc)}
+ return windows.ChangeServiceConfig2(handle,
+ windows.SERVICE_CONFIG_DESCRIPTION, (*byte)(unsafe.Pointer(&d)))
+}
+
+// UpdateConfig updates service s configuration parameters.
+func (s *Service) UpdateConfig(c Config) error {
+ err := windows.ChangeServiceConfig(s.Handle, c.ServiceType, c.StartType,
+ c.ErrorControl, toPtr(c.BinaryPathName), toPtr(c.LoadOrderGroup),
+ nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName),
+ toPtr(c.Password), toPtr(c.DisplayName))
+ if err != nil {
+ return err
+ }
+ return updateDescription(s.Handle, c.Description)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/mgr/mgr.go b/vendor/golang.org/x/sys/windows/svc/mgr/mgr.go
new file mode 100644
index 000000000..da8ceb6ed
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/mgr/mgr.go
@@ -0,0 +1,119 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package mgr can be used to manage Windows service programs.
+// It can be used to install and remove them. It can also start,
+// stop and pause them. The package can query / change current
+// service state and config parameters.
+//
+package mgr
+
+import (
+ "syscall"
+ "unicode/utf16"
+
+ "golang.org/x/sys/windows"
+)
+
+// Mgr is used to manage Windows service.
+type Mgr struct {
+ Handle windows.Handle
+}
+
+// Connect establishes a connection to the service control manager.
+func Connect() (*Mgr, error) {
+ return ConnectRemote("")
+}
+
+// ConnectRemote establishes a connection to the
+// service control manager on computer named host.
+func ConnectRemote(host string) (*Mgr, error) {
+ var s *uint16
+ if host != "" {
+ s = syscall.StringToUTF16Ptr(host)
+ }
+ h, err := windows.OpenSCManager(s, nil, windows.SC_MANAGER_ALL_ACCESS)
+ if err != nil {
+ return nil, err
+ }
+ return &Mgr{Handle: h}, nil
+}
+
+// Disconnect closes connection to the service control manager m.
+func (m *Mgr) Disconnect() error {
+ return windows.CloseServiceHandle(m.Handle)
+}
+
+func toPtr(s string) *uint16 {
+ if len(s) == 0 {
+ return nil
+ }
+ return syscall.StringToUTF16Ptr(s)
+}
+
+// toStringBlock terminates strings in ss with 0, and then
+// concatenates them together. It also adds extra 0 at the end.
+func toStringBlock(ss []string) *uint16 {
+ if len(ss) == 0 {
+ return nil
+ }
+ t := ""
+ for _, s := range ss {
+ if s != "" {
+ t += s + "\x00"
+ }
+ }
+ if t == "" {
+ return nil
+ }
+ t += "\x00"
+ return &utf16.Encode([]rune(t))[0]
+}
+
+// CreateService installs new service name on the system.
+// The service will be executed by running exepath binary.
+// Use config c to specify service parameters.
+// If service StartType is set to StartAutomatic,
+// args will be passed to svc.Handle.Execute.
+func (m *Mgr) CreateService(name, exepath string, c Config, args ...string) (*Service, error) {
+ if c.StartType == 0 {
+ c.StartType = StartManual
+ }
+ if c.ErrorControl == 0 {
+ c.ErrorControl = ErrorNormal
+ }
+ if c.ServiceType == 0 {
+ c.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
+ }
+ s := syscall.EscapeArg(exepath)
+ for _, v := range args {
+ s += " " + syscall.EscapeArg(v)
+ }
+ h, err := windows.CreateService(m.Handle, toPtr(name), toPtr(c.DisplayName),
+ windows.SERVICE_ALL_ACCESS, c.ServiceType,
+ c.StartType, c.ErrorControl, toPtr(s), toPtr(c.LoadOrderGroup),
+ nil, toStringBlock(c.Dependencies), toPtr(c.ServiceStartName), toPtr(c.Password))
+ if err != nil {
+ return nil, err
+ }
+ if c.Description != "" {
+ err = updateDescription(h, c.Description)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return &Service{Name: name, Handle: h}, nil
+}
+
+// OpenService retrieves access to service name, so it can
+// be interrogated and controlled.
+func (m *Mgr) OpenService(name string) (*Service, error) {
+ h, err := windows.OpenService(m.Handle, syscall.StringToUTF16Ptr(name), windows.SERVICE_ALL_ACCESS)
+ if err != nil {
+ return nil, err
+ }
+ return &Service{Name: name, Handle: h}, nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go b/vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go
new file mode 100644
index 000000000..78be970c0
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/mgr/mgr_test.go
@@ -0,0 +1,154 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package mgr_test
+
+import (
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+ "syscall"
+ "testing"
+ "time"
+
+ "golang.org/x/sys/windows/svc/mgr"
+)
+
+func TestOpenLanManServer(t *testing.T) {
+ m, err := mgr.Connect()
+ if err != nil {
+ if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
+ t.Skip("Skipping test: we don't have rights to manage services.")
+ }
+ t.Fatalf("SCM connection failed: %s", err)
+ }
+ defer m.Disconnect()
+
+ s, err := m.OpenService("LanmanServer")
+ if err != nil {
+ t.Fatalf("OpenService(lanmanserver) failed: %s", err)
+ }
+ defer s.Close()
+
+ _, err = s.Config()
+ if err != nil {
+ t.Fatalf("Config failed: %s", err)
+ }
+}
+
+func install(t *testing.T, m *mgr.Mgr, name, exepath string, c mgr.Config) {
+ // Sometimes it takes a while for the service to get
+ // removed after previous test run.
+ for i := 0; ; i++ {
+ s, err := m.OpenService(name)
+ if err != nil {
+ break
+ }
+ s.Close()
+
+ if i > 10 {
+ t.Fatalf("service %s already exists", name)
+ }
+ time.Sleep(300 * time.Millisecond)
+ }
+
+ s, err := m.CreateService(name, exepath, c)
+ if err != nil {
+ t.Fatalf("CreateService(%s) failed: %v", name, err)
+ }
+ defer s.Close()
+}
+
+func depString(d []string) string {
+ if len(d) == 0 {
+ return ""
+ }
+ for i := range d {
+ d[i] = strings.ToLower(d[i])
+ }
+ ss := sort.StringSlice(d)
+ ss.Sort()
+ return strings.Join([]string(ss), " ")
+}
+
+func testConfig(t *testing.T, s *mgr.Service, should mgr.Config) mgr.Config {
+ is, err := s.Config()
+ if err != nil {
+ t.Fatalf("Config failed: %s", err)
+ }
+ if should.DisplayName != is.DisplayName {
+ t.Fatalf("config mismatch: DisplayName is %q, but should have %q", is.DisplayName, should.DisplayName)
+ }
+ if should.StartType != is.StartType {
+ t.Fatalf("config mismatch: StartType is %v, but should have %v", is.StartType, should.StartType)
+ }
+ if should.Description != is.Description {
+ t.Fatalf("config mismatch: Description is %q, but should have %q", is.Description, should.Description)
+ }
+ if depString(should.Dependencies) != depString(is.Dependencies) {
+ t.Fatalf("config mismatch: Dependencies is %v, but should have %v", is.Dependencies, should.Dependencies)
+ }
+ return is
+}
+
+func remove(t *testing.T, s *mgr.Service) {
+ err := s.Delete()
+ if err != nil {
+ t.Fatalf("Delete failed: %s", err)
+ }
+}
+
+func TestMyService(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode - it modifies system services")
+ }
+
+ const name = "myservice"
+
+ m, err := mgr.Connect()
+ if err != nil {
+ if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERROR_ACCESS_DENIED {
+ t.Skip("Skipping test: we don't have rights to manage services.")
+ }
+ t.Fatalf("SCM connection failed: %s", err)
+ }
+ defer m.Disconnect()
+
+ c := mgr.Config{
+ StartType: mgr.StartDisabled,
+ DisplayName: "my service",
+ Description: "my service is just a test",
+ Dependencies: []string{"LanmanServer", "W32Time"},
+ }
+
+ exename := os.Args[0]
+ exepath, err := filepath.Abs(exename)
+ if err != nil {
+ t.Fatalf("filepath.Abs(%s) failed: %s", exename, err)
+ }
+
+ install(t, m, name, exepath, c)
+
+ s, err := m.OpenService(name)
+ if err != nil {
+ t.Fatalf("service %s is not installed", name)
+ }
+ defer s.Close()
+
+ c.BinaryPathName = exepath
+ c = testConfig(t, s, c)
+
+ c.StartType = mgr.StartManual
+ err = s.UpdateConfig(c)
+ if err != nil {
+ t.Fatalf("UpdateConfig failed: %v", err)
+ }
+
+ testConfig(t, s, c)
+
+ remove(t, s)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/mgr/service.go b/vendor/golang.org/x/sys/windows/svc/mgr/service.go
new file mode 100644
index 000000000..465f3c3d2
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/mgr/service.go
@@ -0,0 +1,74 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package mgr
+
+import (
+ "syscall"
+
+ "golang.org/x/sys/windows"
+ "golang.org/x/sys/windows/svc"
+)
+
+// TODO(brainman): Use EnumDependentServices to enumerate dependent services.
+
+// TODO(brainman): Use EnumServicesStatus to enumerate services in the specified service control manager database.
+
+// Service is used to access Windows service.
+type Service struct {
+ Name string
+ Handle windows.Handle
+}
+
+// Delete marks service s for deletion from the service control manager database.
+func (s *Service) Delete() error {
+ return windows.DeleteService(s.Handle)
+}
+
+// Close relinquish access to the service s.
+func (s *Service) Close() error {
+ return windows.CloseServiceHandle(s.Handle)
+}
+
+// Start starts service s.
+// args will be passed to svc.Handler.Execute.
+func (s *Service) Start(args ...string) error {
+ var p **uint16
+ if len(args) > 0 {
+ vs := make([]*uint16, len(args))
+ for i, _ := range vs {
+ vs[i] = syscall.StringToUTF16Ptr(args[i])
+ }
+ p = &vs[0]
+ }
+ return windows.StartService(s.Handle, uint32(len(args)), p)
+}
+
+// Control sends state change request c to the servce s.
+func (s *Service) Control(c svc.Cmd) (svc.Status, error) {
+ var t windows.SERVICE_STATUS
+ err := windows.ControlService(s.Handle, uint32(c), &t)
+ if err != nil {
+ return svc.Status{}, err
+ }
+ return svc.Status{
+ State: svc.State(t.CurrentState),
+ Accepts: svc.Accepted(t.ControlsAccepted),
+ }, nil
+}
+
+// Query returns current status of service s.
+func (s *Service) Query() (svc.Status, error) {
+ var t windows.SERVICE_STATUS
+ err := windows.QueryServiceStatus(s.Handle, &t)
+ if err != nil {
+ return svc.Status{}, err
+ }
+ return svc.Status{
+ State: svc.State(t.CurrentState),
+ Accepts: svc.Accepted(t.ControlsAccepted),
+ }, nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/security.go b/vendor/golang.org/x/sys/windows/svc/security.go
new file mode 100644
index 000000000..6fbc9236e
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/security.go
@@ -0,0 +1,62 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package svc
+
+import (
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+func allocSid(subAuth0 uint32) (*windows.SID, error) {
+ var sid *windows.SID
+ err := windows.AllocateAndInitializeSid(&windows.SECURITY_NT_AUTHORITY,
+ 1, subAuth0, 0, 0, 0, 0, 0, 0, 0, &sid)
+ if err != nil {
+ return nil, err
+ }
+ return sid, nil
+}
+
+// IsAnInteractiveSession determines if calling process is running interactively.
+// It queries the process token for membership in the Interactive group.
+// http://stackoverflow.com/questions/2668851/how-do-i-detect-that-my-application-is-running-as-service-or-in-an-interactive-s
+func IsAnInteractiveSession() (bool, error) {
+ interSid, err := allocSid(windows.SECURITY_INTERACTIVE_RID)
+ if err != nil {
+ return false, err
+ }
+ defer windows.FreeSid(interSid)
+
+ serviceSid, err := allocSid(windows.SECURITY_SERVICE_RID)
+ if err != nil {
+ return false, err
+ }
+ defer windows.FreeSid(serviceSid)
+
+ t, err := windows.OpenCurrentProcessToken()
+ if err != nil {
+ return false, err
+ }
+ defer t.Close()
+
+ gs, err := t.GetTokenGroups()
+ if err != nil {
+ return false, err
+ }
+ p := unsafe.Pointer(&gs.Groups[0])
+ groups := (*[2 << 20]windows.SIDAndAttributes)(p)[:gs.GroupCount]
+ for _, g := range groups {
+ if windows.EqualSid(g.Sid, interSid) {
+ return true, nil
+ }
+ if windows.EqualSid(g.Sid, serviceSid) {
+ return false, nil
+ }
+ }
+ return false, nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/service.go b/vendor/golang.org/x/sys/windows/svc/service.go
new file mode 100644
index 000000000..9864f7a72
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/service.go
@@ -0,0 +1,316 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package svc provides everything required to build Windows service.
+//
+package svc
+
+import (
+ "errors"
+ "runtime"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// State describes service execution state (Stopped, Running and so on).
+type State uint32
+
+const (
+ Stopped = State(windows.SERVICE_STOPPED)
+ StartPending = State(windows.SERVICE_START_PENDING)
+ StopPending = State(windows.SERVICE_STOP_PENDING)
+ Running = State(windows.SERVICE_RUNNING)
+ ContinuePending = State(windows.SERVICE_CONTINUE_PENDING)
+ PausePending = State(windows.SERVICE_PAUSE_PENDING)
+ Paused = State(windows.SERVICE_PAUSED)
+)
+
+// Cmd represents service state change request. It is sent to a service
+// by the service manager, and should be actioned upon by the service.
+type Cmd uint32
+
+const (
+ Stop = Cmd(windows.SERVICE_CONTROL_STOP)
+ Pause = Cmd(windows.SERVICE_CONTROL_PAUSE)
+ Continue = Cmd(windows.SERVICE_CONTROL_CONTINUE)
+ Interrogate = Cmd(windows.SERVICE_CONTROL_INTERROGATE)
+ Shutdown = Cmd(windows.SERVICE_CONTROL_SHUTDOWN)
+)
+
+// Accepted is used to describe commands accepted by the service.
+// Note that Interrogate is always accepted.
+type Accepted uint32
+
+const (
+ AcceptStop = Accepted(windows.SERVICE_ACCEPT_STOP)
+ AcceptShutdown = Accepted(windows.SERVICE_ACCEPT_SHUTDOWN)
+ AcceptPauseAndContinue = Accepted(windows.SERVICE_ACCEPT_PAUSE_CONTINUE)
+)
+
+// Status combines State and Accepted commands to fully describe running service.
+type Status struct {
+ State State
+ Accepts Accepted
+ CheckPoint uint32 // used to report progress during a lengthy operation
+ WaitHint uint32 // estimated time required for a pending operation, in milliseconds
+}
+
+// ChangeRequest is sent to the service Handler to request service status change.
+type ChangeRequest struct {
+ Cmd Cmd
+ CurrentStatus Status
+}
+
+// Handler is the interface that must be implemented to build Windows service.
+type Handler interface {
+
+ // Execute will be called by the package code at the start of
+ // the service, and the service will exit once Execute completes.
+ // Inside Execute you must read service change requests from r and
+ // act accordingly. You must keep service control manager up to date
+ // about state of your service by writing into s as required.
+ // args contains service name followed by argument strings passed
+ // to the service.
+ // You can provide service exit code in exitCode return parameter,
+ // with 0 being "no error". You can also indicate if exit code,
+ // if any, is service specific or not by using svcSpecificEC
+ // parameter.
+ Execute(args []string, r <-chan ChangeRequest, s chan<- Status) (svcSpecificEC bool, exitCode uint32)
+}
+
+var (
+ // These are used by asm code.
+ goWaitsH uintptr
+ cWaitsH uintptr
+ ssHandle uintptr
+ sName *uint16
+ sArgc uintptr
+ sArgv **uint16
+ ctlHandlerProc uintptr
+ cSetEvent uintptr
+ cWaitForSingleObject uintptr
+ cRegisterServiceCtrlHandlerW uintptr
+)
+
+func init() {
+ k := syscall.MustLoadDLL("kernel32.dll")
+ cSetEvent = k.MustFindProc("SetEvent").Addr()
+ cWaitForSingleObject = k.MustFindProc("WaitForSingleObject").Addr()
+ a := syscall.MustLoadDLL("advapi32.dll")
+ cRegisterServiceCtrlHandlerW = a.MustFindProc("RegisterServiceCtrlHandlerW").Addr()
+}
+
+type ctlEvent struct {
+ cmd Cmd
+ errno uint32
+}
+
+// service provides access to windows service api.
+type service struct {
+ name string
+ h windows.Handle
+ cWaits *event
+ goWaits *event
+ c chan ctlEvent
+ handler Handler
+}
+
+func newService(name string, handler Handler) (*service, error) {
+ var s service
+ var err error
+ s.name = name
+ s.c = make(chan ctlEvent)
+ s.handler = handler
+ s.cWaits, err = newEvent()
+ if err != nil {
+ return nil, err
+ }
+ s.goWaits, err = newEvent()
+ if err != nil {
+ s.cWaits.Close()
+ return nil, err
+ }
+ return &s, nil
+}
+
+func (s *service) close() error {
+ s.cWaits.Close()
+ s.goWaits.Close()
+ return nil
+}
+
+type exitCode struct {
+ isSvcSpecific bool
+ errno uint32
+}
+
+func (s *service) updateStatus(status *Status, ec *exitCode) error {
+ if s.h == 0 {
+ return errors.New("updateStatus with no service status handle")
+ }
+ var t windows.SERVICE_STATUS
+ t.ServiceType = windows.SERVICE_WIN32_OWN_PROCESS
+ t.CurrentState = uint32(status.State)
+ if status.Accepts&AcceptStop != 0 {
+ t.ControlsAccepted |= windows.SERVICE_ACCEPT_STOP
+ }
+ if status.Accepts&AcceptShutdown != 0 {
+ t.ControlsAccepted |= windows.SERVICE_ACCEPT_SHUTDOWN
+ }
+ if status.Accepts&AcceptPauseAndContinue != 0 {
+ t.ControlsAccepted |= windows.SERVICE_ACCEPT_PAUSE_CONTINUE
+ }
+ if ec.errno == 0 {
+ t.Win32ExitCode = windows.NO_ERROR
+ t.ServiceSpecificExitCode = windows.NO_ERROR
+ } else if ec.isSvcSpecific {
+ t.Win32ExitCode = uint32(windows.ERROR_SERVICE_SPECIFIC_ERROR)
+ t.ServiceSpecificExitCode = ec.errno
+ } else {
+ t.Win32ExitCode = ec.errno
+ t.ServiceSpecificExitCode = windows.NO_ERROR
+ }
+ t.CheckPoint = status.CheckPoint
+ t.WaitHint = status.WaitHint
+ return windows.SetServiceStatus(s.h, &t)
+}
+
+const (
+ sysErrSetServiceStatusFailed = uint32(syscall.APPLICATION_ERROR) + iota
+ sysErrNewThreadInCallback
+)
+
+func (s *service) run() {
+ s.goWaits.Wait()
+ s.h = windows.Handle(ssHandle)
+ argv := (*[100]*int16)(unsafe.Pointer(sArgv))[:sArgc]
+ args := make([]string, len(argv))
+ for i, a := range argv {
+ args[i] = syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(a))[:])
+ }
+
+ cmdsToHandler := make(chan ChangeRequest)
+ changesFromHandler := make(chan Status)
+ exitFromHandler := make(chan exitCode)
+
+ go func() {
+ ss, errno := s.handler.Execute(args, cmdsToHandler, changesFromHandler)
+ exitFromHandler <- exitCode{ss, errno}
+ }()
+
+ status := Status{State: Stopped}
+ ec := exitCode{isSvcSpecific: true, errno: 0}
+ var outch chan ChangeRequest
+ inch := s.c
+ var cmd Cmd
+loop:
+ for {
+ select {
+ case r := <-inch:
+ if r.errno != 0 {
+ ec.errno = r.errno
+ break loop
+ }
+ inch = nil
+ outch = cmdsToHandler
+ cmd = r.cmd
+ case outch <- ChangeRequest{cmd, status}:
+ inch = s.c
+ outch = nil
+ case c := <-changesFromHandler:
+ err := s.updateStatus(&c, &ec)
+ if err != nil {
+ // best suitable error number
+ ec.errno = sysErrSetServiceStatusFailed
+ if err2, ok := err.(syscall.Errno); ok {
+ ec.errno = uint32(err2)
+ }
+ break loop
+ }
+ status = c
+ case ec = <-exitFromHandler:
+ break loop
+ }
+ }
+
+ s.updateStatus(&Status{State: Stopped}, &ec)
+ s.cWaits.Set()
+}
+
+func newCallback(fn interface{}) (cb uintptr, err error) {
+ defer func() {
+ r := recover()
+ if r == nil {
+ return
+ }
+ cb = 0
+ switch v := r.(type) {
+ case string:
+ err = errors.New(v)
+ case error:
+ err = v
+ default:
+ err = errors.New("unexpected panic in syscall.NewCallback")
+ }
+ }()
+ return syscall.NewCallback(fn), nil
+}
+
+// BUG(brainman): There is no mechanism to run multiple services
+// inside one single executable. Perhaps, it can be overcome by
+// using RegisterServiceCtrlHandlerEx Windows api.
+
+// Run executes service name by calling appropriate handler function.
+func Run(name string, handler Handler) error {
+ runtime.LockOSThread()
+
+ tid := windows.GetCurrentThreadId()
+
+ s, err := newService(name, handler)
+ if err != nil {
+ return err
+ }
+
+ ctlHandler := func(ctl uint32) uintptr {
+ e := ctlEvent{cmd: Cmd(ctl)}
+ // We assume that this callback function is running on
+ // the same thread as Run. Nowhere in MS documentation
+ // I could find statement to guarantee that. So putting
+ // check here to verify, otherwise things will go bad
+ // quickly, if ignored.
+ i := windows.GetCurrentThreadId()
+ if i != tid {
+ e.errno = sysErrNewThreadInCallback
+ }
+ s.c <- e
+ return 0
+ }
+
+ var svcmain uintptr
+ getServiceMain(&svcmain)
+ t := []windows.SERVICE_TABLE_ENTRY{
+ {syscall.StringToUTF16Ptr(s.name), svcmain},
+ {nil, 0},
+ }
+
+ goWaitsH = uintptr(s.goWaits.h)
+ cWaitsH = uintptr(s.cWaits.h)
+ sName = t[0].ServiceName
+ ctlHandlerProc, err = newCallback(ctlHandler)
+ if err != nil {
+ return err
+ }
+
+ go s.run()
+
+ err = windows.StartServiceCtrlDispatcher(&t[0])
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/svc_test.go b/vendor/golang.org/x/sys/windows/svc/svc_test.go
new file mode 100644
index 000000000..764da54a5
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/svc_test.go
@@ -0,0 +1,118 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package svc_test
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "golang.org/x/sys/windows/svc"
+ "golang.org/x/sys/windows/svc/mgr"
+)
+
+func getState(t *testing.T, s *mgr.Service) svc.State {
+ status, err := s.Query()
+ if err != nil {
+ t.Fatalf("Query(%s) failed: %s", s.Name, err)
+ }
+ return status.State
+}
+
+func testState(t *testing.T, s *mgr.Service, want svc.State) {
+ have := getState(t, s)
+ if have != want {
+ t.Fatalf("%s state is=%d want=%d", s.Name, have, want)
+ }
+}
+
+func waitState(t *testing.T, s *mgr.Service, want svc.State) {
+ for i := 0; ; i++ {
+ have := getState(t, s)
+ if have == want {
+ return
+ }
+ if i > 10 {
+ t.Fatalf("%s state is=%d, waiting timeout", s.Name, have)
+ }
+ time.Sleep(300 * time.Millisecond)
+ }
+}
+
+func TestExample(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode - it modifies system services")
+ }
+
+ const name = "myservice"
+
+ m, err := mgr.Connect()
+ if err != nil {
+ t.Fatalf("SCM connection failed: %s", err)
+ }
+ defer m.Disconnect()
+
+ dir, err := ioutil.TempDir("", "svc")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ exepath := filepath.Join(dir, "a.exe")
+ o, err := exec.Command("go", "build", "-o", exepath, "golang.org/x/sys/windows/svc/example").CombinedOutput()
+ if err != nil {
+ t.Fatalf("failed to build service program: %v\n%v", err, string(o))
+ }
+
+ s, err := m.OpenService(name)
+ if err == nil {
+ err = s.Delete()
+ if err != nil {
+ s.Close()
+ t.Fatalf("Delete failed: %s", err)
+ }
+ s.Close()
+ }
+ s, err = m.CreateService(name, exepath, mgr.Config{DisplayName: "my service"}, "is", "auto-started")
+ if err != nil {
+ t.Fatalf("CreateService(%s) failed: %v", name, err)
+ }
+ defer s.Close()
+
+ testState(t, s, svc.Stopped)
+ err = s.Start("is", "manual-started")
+ if err != nil {
+ t.Fatalf("Start(%s) failed: %s", s.Name, err)
+ }
+ waitState(t, s, svc.Running)
+ time.Sleep(1 * time.Second)
+
+ // testing deadlock from issues 4.
+ _, err = s.Control(svc.Interrogate)
+ if err != nil {
+ t.Fatalf("Control(%s) failed: %s", s.Name, err)
+ }
+ _, err = s.Control(svc.Interrogate)
+ if err != nil {
+ t.Fatalf("Control(%s) failed: %s", s.Name, err)
+ }
+ time.Sleep(1 * time.Second)
+
+ _, err = s.Control(svc.Stop)
+ if err != nil {
+ t.Fatalf("Control(%s) failed: %s", s.Name, err)
+ }
+ waitState(t, s, svc.Stopped)
+
+ err = s.Delete()
+ if err != nil {
+ t.Fatalf("Delete failed: %s", err)
+ }
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/sys_386.s b/vendor/golang.org/x/sys/windows/svc/sys_386.s
new file mode 100644
index 000000000..5e11bfadb
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/sys_386.s
@@ -0,0 +1,67 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// func servicemain(argc uint32, argv **uint16)
+TEXT ·servicemain(SB),7,$0
+ MOVL argc+0(FP), AX
+ MOVL AX, ·sArgc(SB)
+ MOVL argv+4(FP), AX
+ MOVL AX, ·sArgv(SB)
+
+ PUSHL BP
+ PUSHL BX
+ PUSHL SI
+ PUSHL DI
+
+ SUBL $12, SP
+
+ MOVL ·sName(SB), AX
+ MOVL AX, (SP)
+ MOVL $·servicectlhandler(SB), AX
+ MOVL AX, 4(SP)
+ MOVL ·cRegisterServiceCtrlHandlerW(SB), AX
+ MOVL SP, BP
+ CALL AX
+ MOVL BP, SP
+ CMPL AX, $0
+ JE exit
+ MOVL AX, ·ssHandle(SB)
+
+ MOVL ·goWaitsH(SB), AX
+ MOVL AX, (SP)
+ MOVL ·cSetEvent(SB), AX
+ MOVL SP, BP
+ CALL AX
+ MOVL BP, SP
+
+ MOVL ·cWaitsH(SB), AX
+ MOVL AX, (SP)
+ MOVL $-1, AX
+ MOVL AX, 4(SP)
+ MOVL ·cWaitForSingleObject(SB), AX
+ MOVL SP, BP
+ CALL AX
+ MOVL BP, SP
+
+exit:
+ ADDL $12, SP
+
+ POPL DI
+ POPL SI
+ POPL BX
+ POPL BP
+
+ MOVL 0(SP), CX
+ ADDL $12, SP
+ JMP CX
+
+// I do not know why, but this seems to be the only way to call
+// ctlHandlerProc on Windows 7.
+
+// func servicectlhandler(ctl uint32) uintptr
+TEXT ·servicectlhandler(SB),7,$0
+ MOVL ·ctlHandlerProc(SB), CX
+ JMP CX
diff --git a/vendor/golang.org/x/sys/windows/svc/sys_amd64.s b/vendor/golang.org/x/sys/windows/svc/sys_amd64.s
new file mode 100644
index 000000000..87dbec839
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/sys_amd64.s
@@ -0,0 +1,41 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// func servicemain(argc uint32, argv **uint16)
+TEXT ·servicemain(SB),7,$0
+ MOVL CX, ·sArgc(SB)
+ MOVL DX, ·sArgv(SB)
+
+ SUBQ $32, SP // stack for the first 4 syscall params
+
+ MOVQ ·sName(SB), CX
+ MOVQ $·servicectlhandler(SB), DX
+ MOVQ ·cRegisterServiceCtrlHandlerW(SB), AX
+ CALL AX
+ CMPQ AX, $0
+ JE exit
+ MOVQ AX, ·ssHandle(SB)
+
+ MOVQ ·goWaitsH(SB), CX
+ MOVQ ·cSetEvent(SB), AX
+ CALL AX
+
+ MOVQ ·cWaitsH(SB), CX
+ MOVQ $4294967295, DX
+ MOVQ ·cWaitForSingleObject(SB), AX
+ CALL AX
+
+exit:
+ ADDQ $32, SP
+ RET
+
+// I do not know why, but this seems to be the only way to call
+// ctlHandlerProc on Windows 7.
+
+// func servicectlhandler(ctl uint32) uintptr
+TEXT ·servicectlhandler(SB),7,$0
+ MOVQ ·ctlHandlerProc(SB), AX
+ JMP AX
diff --git a/vendor/golang.org/x/sys/windows/syscall.go b/vendor/golang.org/x/sys/windows/syscall.go
new file mode 100644
index 000000000..4e2fbe86e
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/syscall.go
@@ -0,0 +1,71 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+// Package windows contains an interface to the low-level operating system
+// primitives. OS details vary depending on the underlying system, and
+// by default, godoc will display the OS-specific documentation for the current
+// system. If you want godoc to display syscall documentation for another
+// system, set $GOOS and $GOARCH to the desired system. For example, if
+// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
+// to freebsd and $GOARCH to arm.
+// The primary use of this package is inside other packages that provide a more
+// portable interface to the system, such as "os", "time" and "net". Use
+// those packages rather than this one if you can.
+// For details of the functions and data types in this package consult
+// the manuals for the appropriate operating system.
+// These calls return err == nil to indicate success; otherwise
+// err represents an operating system error describing the failure and
+// holds a value of type syscall.Errno.
+package windows // import "golang.org/x/sys/windows"
+
+import (
+ "syscall"
+)
+
+// ByteSliceFromString returns a NUL-terminated slice of bytes
+// containing the text of s. If s contains a NUL byte at any
+// location, it returns (nil, syscall.EINVAL).
+func ByteSliceFromString(s string) ([]byte, error) {
+ for i := 0; i < len(s); i++ {
+ if s[i] == 0 {
+ return nil, syscall.EINVAL
+ }
+ }
+ a := make([]byte, len(s)+1)
+ copy(a, s)
+ return a, nil
+}
+
+// BytePtrFromString returns a pointer to a NUL-terminated array of
+// bytes containing the text of s. If s contains a NUL byte at any
+// location, it returns (nil, syscall.EINVAL).
+func BytePtrFromString(s string) (*byte, error) {
+ a, err := ByteSliceFromString(s)
+ if err != nil {
+ return nil, err
+ }
+ return &a[0], nil
+}
+
+// Single-word zero for use when we need a valid pointer to 0 bytes.
+// See mksyscall.pl.
+var _zero uintptr
+
+func (ts *Timespec) Unix() (sec int64, nsec int64) {
+ return int64(ts.Sec), int64(ts.Nsec)
+}
+
+func (tv *Timeval) Unix() (sec int64, nsec int64) {
+ return int64(tv.Sec), int64(tv.Usec) * 1000
+}
+
+func (ts *Timespec) Nano() int64 {
+ return int64(ts.Sec)*1e9 + int64(ts.Nsec)
+}
+
+func (tv *Timeval) Nano() int64 {
+ return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
+}
diff --git a/vendor/golang.org/x/sys/windows/syscall_test.go b/vendor/golang.org/x/sys/windows/syscall_test.go
new file mode 100644
index 000000000..62588b91b
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/syscall_test.go
@@ -0,0 +1,33 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build windows
+
+package windows_test
+
+import (
+ "testing"
+
+ "golang.org/x/sys/windows"
+)
+
+func testSetGetenv(t *testing.T, key, value string) {
+ err := windows.Setenv(key, value)
+ if err != nil {
+ t.Fatalf("Setenv failed to set %q: %v", value, err)
+ }
+ newvalue, found := windows.Getenv(key)
+ if !found {
+ t.Fatalf("Getenv failed to find %v variable (want value %q)", key, value)
+ }
+ if newvalue != value {
+ t.Fatalf("Getenv(%v) = %q; want %q", key, newvalue, value)
+ }
+}
+
+func TestEnv(t *testing.T) {
+ testSetGetenv(t, "TESTENV", "AVALUE")
+ // make sure TESTENV gets set to "", not deleted
+ testSetGetenv(t, "TESTENV", "")
+}
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go
new file mode 100644
index 000000000..78991e8be
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -0,0 +1,991 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows system calls.
+
+package windows
+
+import (
+ errorspkg "errors"
+ "sync"
+ "syscall"
+ "unicode/utf16"
+ "unsafe"
+)
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go
+
+type Handle uintptr
+
+const InvalidHandle = ^Handle(0)
+
+// StringToUTF16 is deprecated. Use UTF16FromString instead.
+// If s contains a NUL byte this function panics instead of
+// returning an error.
+func StringToUTF16(s string) []uint16 {
+ a, err := UTF16FromString(s)
+ if err != nil {
+ panic("windows: string with NUL passed to StringToUTF16")
+ }
+ return a
+}
+
+// UTF16FromString returns the UTF-16 encoding of the UTF-8 string
+// s, with a terminating NUL added. If s contains a NUL byte at any
+// location, it returns (nil, syscall.EINVAL).
+func UTF16FromString(s string) ([]uint16, error) {
+ for i := 0; i < len(s); i++ {
+ if s[i] == 0 {
+ return nil, syscall.EINVAL
+ }
+ }
+ return utf16.Encode([]rune(s + "\x00")), nil
+}
+
+// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
+// with a terminating NUL removed.
+func UTF16ToString(s []uint16) string {
+ for i, v := range s {
+ if v == 0 {
+ s = s[0:i]
+ break
+ }
+ }
+ return string(utf16.Decode(s))
+}
+
+// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
+// If s contains a NUL byte this function panics instead of
+// returning an error.
+func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
+
+// UTF16PtrFromString returns pointer to the UTF-16 encoding of
+// the UTF-8 string s, with a terminating NUL added. If s
+// contains a NUL byte at any location, it returns (nil, syscall.EINVAL).
+func UTF16PtrFromString(s string) (*uint16, error) {
+ a, err := UTF16FromString(s)
+ if err != nil {
+ return nil, err
+ }
+ return &a[0], nil
+}
+
+func Getpagesize() int { return 4096 }
+
+// Converts a Go function to a function pointer conforming
+// to the stdcall or cdecl calling convention. This is useful when
+// interoperating with Windows code requiring callbacks.
+// Implemented in runtime/syscall_windows.goc
+func NewCallback(fn interface{}) uintptr
+func NewCallbackCDecl(fn interface{}) uintptr
+
+// windows api calls
+
+//sys GetLastError() (lasterr error)
+//sys LoadLibrary(libname string) (handle Handle, err error) = LoadLibraryW
+//sys LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) = LoadLibraryExW
+//sys FreeLibrary(handle Handle) (err error)
+//sys GetProcAddress(module Handle, procname string) (proc uintptr, err error)
+//sys GetVersion() (ver uint32, err error)
+//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
+//sys ExitProcess(exitcode uint32)
+//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
+//sys ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
+//sys WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
+//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff]
+//sys CloseHandle(handle Handle) (err error)
+//sys GetStdHandle(stdhandle int) (handle Handle, err error) [failretval==InvalidHandle]
+//sys findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) [failretval==InvalidHandle] = FindFirstFileW
+//sys findNextFile1(handle Handle, data *win32finddata1) (err error) = FindNextFileW
+//sys FindClose(handle Handle) (err error)
+//sys GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error)
+//sys GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) = GetCurrentDirectoryW
+//sys SetCurrentDirectory(path *uint16) (err error) = SetCurrentDirectoryW
+//sys CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) = CreateDirectoryW
+//sys RemoveDirectory(path *uint16) (err error) = RemoveDirectoryW
+//sys DeleteFile(path *uint16) (err error) = DeleteFileW
+//sys MoveFile(from *uint16, to *uint16) (err error) = MoveFileW
+//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
+//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
+//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
+//sys SetEndOfFile(handle Handle) (err error)
+//sys GetSystemTimeAsFileTime(time *Filetime)
+//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
+//sys CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error)
+//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error)
+//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error)
+//sys CancelIo(s Handle) (err error)
+//sys CancelIoEx(s Handle, o *Overlapped) (err error)
+//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
+//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error)
+//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
+//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
+//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
+//sys GetCurrentProcess() (pseudoHandle Handle, err error)
+//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
+//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
+//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
+//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPathW
+//sys CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error)
+//sys GetFileType(filehandle Handle) (n uint32, err error)
+//sys CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) = advapi32.CryptAcquireContextW
+//sys CryptReleaseContext(provhandle Handle, flags uint32) (err error) = advapi32.CryptReleaseContext
+//sys CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) = advapi32.CryptGenRandom
+//sys GetEnvironmentStrings() (envs *uint16, err error) [failretval==nil] = kernel32.GetEnvironmentStringsW
+//sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW
+//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW
+//sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW
+//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
+//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
+//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
+//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW
+//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
+//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
+//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0]
+//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
+//sys FlushFileBuffers(handle Handle) (err error)
+//sys GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) = kernel32.GetFullPathNameW
+//sys GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) = kernel32.GetLongPathNameW
+//sys GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) = kernel32.GetShortPathNameW
+//sys CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) = kernel32.CreateFileMappingW
+//sys MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error)
+//sys UnmapViewOfFile(addr uintptr) (err error)
+//sys FlushViewOfFile(addr uintptr, length uintptr) (err error)
+//sys VirtualLock(addr uintptr, length uintptr) (err error)
+//sys VirtualUnlock(addr uintptr, length uintptr) (err error)
+//sys TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) = mswsock.TransmitFile
+//sys ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) = kernel32.ReadDirectoryChangesW
+//sys CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) = crypt32.CertOpenSystemStoreW
+//sys CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) [failretval==InvalidHandle] = crypt32.CertOpenStore
+//sys CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) [failretval==nil] = crypt32.CertEnumCertificatesInStore
+//sys CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) = crypt32.CertAddCertificateContextToStore
+//sys CertCloseStore(store Handle, flags uint32) (err error) = crypt32.CertCloseStore
+//sys CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) = crypt32.CertGetCertificateChain
+//sys CertFreeCertificateChain(ctx *CertChainContext) = crypt32.CertFreeCertificateChain
+//sys CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) [failretval==nil] = crypt32.CertCreateCertificateContext
+//sys CertFreeCertificateContext(ctx *CertContext) (err error) = crypt32.CertFreeCertificateContext
+//sys CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) = crypt32.CertVerifyCertificateChainPolicy
+//sys RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) = advapi32.RegOpenKeyExW
+//sys RegCloseKey(key Handle) (regerrno error) = advapi32.RegCloseKey
+//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
+//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
+//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
+//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
+//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
+//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
+//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
+//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
+//sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW
+//sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW
+//sys DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error)
+// This function returns 1 byte BOOLEAN rather than the 4 byte BOOL.
+//sys CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) [failretval&0xff==0] = CreateSymbolicLinkW
+//sys CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardLinkW
+//sys GetCurrentThreadId() (id uint32)
+//sys CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) = kernel32.CreateEventW
+//sys SetEvent(event Handle) (err error) = kernel32.SetEvent
+
+// syscall interface implementation for other packages
+
+func Exit(code int) { ExitProcess(uint32(code)) }
+
+func makeInheritSa() *SecurityAttributes {
+ var sa SecurityAttributes
+ sa.Length = uint32(unsafe.Sizeof(sa))
+ sa.InheritHandle = 1
+ return &sa
+}
+
+func Open(path string, mode int, perm uint32) (fd Handle, err error) {
+ if len(path) == 0 {
+ return InvalidHandle, ERROR_FILE_NOT_FOUND
+ }
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return InvalidHandle, err
+ }
+ var access uint32
+ switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
+ case O_RDONLY:
+ access = GENERIC_READ
+ case O_WRONLY:
+ access = GENERIC_WRITE
+ case O_RDWR:
+ access = GENERIC_READ | GENERIC_WRITE
+ }
+ if mode&O_CREAT != 0 {
+ access |= GENERIC_WRITE
+ }
+ if mode&O_APPEND != 0 {
+ access &^= GENERIC_WRITE
+ access |= FILE_APPEND_DATA
+ }
+ sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
+ var sa *SecurityAttributes
+ if mode&O_CLOEXEC == 0 {
+ sa = makeInheritSa()
+ }
+ var createmode uint32
+ switch {
+ case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
+ createmode = CREATE_NEW
+ case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
+ createmode = CREATE_ALWAYS
+ case mode&O_CREAT == O_CREAT:
+ createmode = OPEN_ALWAYS
+ case mode&O_TRUNC == O_TRUNC:
+ createmode = TRUNCATE_EXISTING
+ default:
+ createmode = OPEN_EXISTING
+ }
+ h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
+ return h, e
+}
+
+func Read(fd Handle, p []byte) (n int, err error) {
+ var done uint32
+ e := ReadFile(fd, p, &done, nil)
+ if e != nil {
+ if e == ERROR_BROKEN_PIPE {
+ // NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
+ return 0, nil
+ }
+ return 0, e
+ }
+ if raceenabled {
+ if done > 0 {
+ raceWriteRange(unsafe.Pointer(&p[0]), int(done))
+ }
+ raceAcquire(unsafe.Pointer(&ioSync))
+ }
+ return int(done), nil
+}
+
+func Write(fd Handle, p []byte) (n int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ var done uint32
+ e := WriteFile(fd, p, &done, nil)
+ if e != nil {
+ return 0, e
+ }
+ if raceenabled && done > 0 {
+ raceReadRange(unsafe.Pointer(&p[0]), int(done))
+ }
+ return int(done), nil
+}
+
+var ioSync int64
+
+func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
+ var w uint32
+ switch whence {
+ case 0:
+ w = FILE_BEGIN
+ case 1:
+ w = FILE_CURRENT
+ case 2:
+ w = FILE_END
+ }
+ hi := int32(offset >> 32)
+ lo := int32(offset)
+ // use GetFileType to check pipe, pipe can't do seek
+ ft, _ := GetFileType(fd)
+ if ft == FILE_TYPE_PIPE {
+ return 0, syscall.EPIPE
+ }
+ rlo, e := SetFilePointer(fd, lo, &hi, w)
+ if e != nil {
+ return 0, e
+ }
+ return int64(hi)<<32 + int64(rlo), nil
+}
+
+func Close(fd Handle) (err error) {
+ return CloseHandle(fd)
+}
+
+var (
+ Stdin = getStdHandle(STD_INPUT_HANDLE)
+ Stdout = getStdHandle(STD_OUTPUT_HANDLE)
+ Stderr = getStdHandle(STD_ERROR_HANDLE)
+)
+
+func getStdHandle(h int) (fd Handle) {
+ r, _ := GetStdHandle(h)
+ CloseOnExec(r)
+ return r
+}
+
+const ImplementsGetwd = true
+
+func Getwd() (wd string, err error) {
+ b := make([]uint16, 300)
+ n, e := GetCurrentDirectory(uint32(len(b)), &b[0])
+ if e != nil {
+ return "", e
+ }
+ return string(utf16.Decode(b[0:n])), nil
+}
+
+func Chdir(path string) (err error) {
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return SetCurrentDirectory(pathp)
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return CreateDirectory(pathp, nil)
+}
+
+func Rmdir(path string) (err error) {
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return RemoveDirectory(pathp)
+}
+
+func Unlink(path string) (err error) {
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return DeleteFile(pathp)
+}
+
+func Rename(oldpath, newpath string) (err error) {
+ from, err := UTF16PtrFromString(oldpath)
+ if err != nil {
+ return err
+ }
+ to, err := UTF16PtrFromString(newpath)
+ if err != nil {
+ return err
+ }
+ return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
+}
+
+func ComputerName() (name string, err error) {
+ var n uint32 = MAX_COMPUTERNAME_LENGTH + 1
+ b := make([]uint16, n)
+ e := GetComputerName(&b[0], &n)
+ if e != nil {
+ return "", e
+ }
+ return string(utf16.Decode(b[0:n])), nil
+}
+
+func Ftruncate(fd Handle, length int64) (err error) {
+ curoffset, e := Seek(fd, 0, 1)
+ if e != nil {
+ return e
+ }
+ defer Seek(fd, curoffset, 0)
+ _, e = Seek(fd, length, 0)
+ if e != nil {
+ return e
+ }
+ e = SetEndOfFile(fd)
+ if e != nil {
+ return e
+ }
+ return nil
+}
+
+func Gettimeofday(tv *Timeval) (err error) {
+ var ft Filetime
+ GetSystemTimeAsFileTime(&ft)
+ *tv = NsecToTimeval(ft.Nanoseconds())
+ return nil
+}
+
+func Pipe(p []Handle) (err error) {
+ if len(p) != 2 {
+ return syscall.EINVAL
+ }
+ var r, w Handle
+ e := CreatePipe(&r, &w, makeInheritSa(), 0)
+ if e != nil {
+ return e
+ }
+ p[0] = r
+ p[1] = w
+ return nil
+}
+
+func Utimes(path string, tv []Timeval) (err error) {
+ if len(tv) != 2 {
+ return syscall.EINVAL
+ }
+ pathp, e := UTF16PtrFromString(path)
+ if e != nil {
+ return e
+ }
+ h, e := CreateFile(pathp,
+ FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
+ if e != nil {
+ return e
+ }
+ defer Close(h)
+ a := NsecToFiletime(tv[0].Nanoseconds())
+ w := NsecToFiletime(tv[1].Nanoseconds())
+ return SetFileTime(h, nil, &a, &w)
+}
+
+func UtimesNano(path string, ts []Timespec) (err error) {
+ if len(ts) != 2 {
+ return syscall.EINVAL
+ }
+ pathp, e := UTF16PtrFromString(path)
+ if e != nil {
+ return e
+ }
+ h, e := CreateFile(pathp,
+ FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
+ if e != nil {
+ return e
+ }
+ defer Close(h)
+ a := NsecToFiletime(TimespecToNsec(ts[0]))
+ w := NsecToFiletime(TimespecToNsec(ts[1]))
+ return SetFileTime(h, nil, &a, &w)
+}
+
+func Fsync(fd Handle) (err error) {
+ return FlushFileBuffers(fd)
+}
+
+func Chmod(path string, mode uint32) (err error) {
+ if mode == 0 {
+ return syscall.EINVAL
+ }
+ p, e := UTF16PtrFromString(path)
+ if e != nil {
+ return e
+ }
+ attrs, e := GetFileAttributes(p)
+ if e != nil {
+ return e
+ }
+ if mode&S_IWRITE != 0 {
+ attrs &^= FILE_ATTRIBUTE_READONLY
+ } else {
+ attrs |= FILE_ATTRIBUTE_READONLY
+ }
+ return SetFileAttributes(p, attrs)
+}
+
+func LoadCancelIoEx() error {
+ return procCancelIoEx.Find()
+}
+
+func LoadSetFileCompletionNotificationModes() error {
+ return procSetFileCompletionNotificationModes.Find()
+}
+
+// net api calls
+
+const socket_error = uintptr(^uint32(0))
+
+//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup
+//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup
+//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl
+//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
+//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
+//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
+//sys bind(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
+//sys connect(s Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
+//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
+//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
+//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
+//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown
+//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket
+//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx
+//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs
+//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv
+//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend
+//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom
+//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo
+//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname
+//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname
+//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
+//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname
+//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W
+//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
+//sys DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) = dnsapi.DnsNameCompare_W
+//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW
+//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW
+//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
+//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
+//sys SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) = kernel32.SetFileCompletionNotificationModes
+//sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW
+//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
+//sys GetACP() (acp uint32) = kernel32.GetACP
+//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
+
+type RawSockaddrInet4 struct {
+ Family uint16
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+type RawSockaddr struct {
+ Family uint16
+ Data [14]int8
+}
+
+type RawSockaddrAny struct {
+ Addr RawSockaddr
+ Pad [96]int8
+}
+
+type Sockaddr interface {
+ sockaddr() (ptr unsafe.Pointer, len int32, err error) // lowercase; only we can define Sockaddrs
+}
+
+type SockaddrInet4 struct {
+ Port int
+ Addr [4]byte
+ raw RawSockaddrInet4
+}
+
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, syscall.EINVAL
+ }
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
+}
+
+type SockaddrInet6 struct {
+ Port int
+ ZoneId uint32
+ Addr [16]byte
+ raw RawSockaddrInet6
+}
+
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, syscall.EINVAL
+ }
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil
+}
+
+type SockaddrUnix struct {
+ Name string
+}
+
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
+ // TODO(brainman): implement SockaddrUnix.sockaddr()
+ return nil, 0, syscall.EWINDOWS
+}
+
+func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
+ switch rsa.Addr.Family {
+ case AF_UNIX:
+ return nil, syscall.EWINDOWS
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ sa.ZoneId = pp.Scope_id
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+ }
+ return nil, syscall.EAFNOSUPPORT
+}
+
+func Socket(domain, typ, proto int) (fd Handle, err error) {
+ if domain == AF_INET6 && SocketDisableIPv6 {
+ return InvalidHandle, syscall.EAFNOSUPPORT
+ }
+ return socket(int32(domain), int32(typ), int32(proto))
+}
+
+func SetsockoptInt(fd Handle, level, opt int, value int) (err error) {
+ v := int32(value)
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v)))
+}
+
+func Bind(fd Handle, sa Sockaddr) (err error) {
+ ptr, n, err := sa.sockaddr()
+ if err != nil {
+ return err
+ }
+ return bind(fd, ptr, n)
+}
+
+func Connect(fd Handle, sa Sockaddr) (err error) {
+ ptr, n, err := sa.sockaddr()
+ if err != nil {
+ return err
+ }
+ return connect(fd, ptr, n)
+}
+
+func Getsockname(fd Handle) (sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ l := int32(unsafe.Sizeof(rsa))
+ if err = getsockname(fd, &rsa, &l); err != nil {
+ return
+ }
+ return rsa.Sockaddr()
+}
+
+func Getpeername(fd Handle) (sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ l := int32(unsafe.Sizeof(rsa))
+ if err = getpeername(fd, &rsa, &l); err != nil {
+ return
+ }
+ return rsa.Sockaddr()
+}
+
+func Listen(s Handle, n int) (err error) {
+ return listen(s, int32(n))
+}
+
+func Shutdown(fd Handle, how int) (err error) {
+ return shutdown(fd, int32(how))
+}
+
+func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (err error) {
+ rsa, l, err := to.sockaddr()
+ if err != nil {
+ return err
+ }
+ return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
+}
+
+func LoadGetAddrInfo() error {
+ return procGetAddrInfoW.Find()
+}
+
+var connectExFunc struct {
+ once sync.Once
+ addr uintptr
+ err error
+}
+
+func LoadConnectEx() error {
+ connectExFunc.once.Do(func() {
+ var s Handle
+ s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
+ if connectExFunc.err != nil {
+ return
+ }
+ defer CloseHandle(s)
+ var n uint32
+ connectExFunc.err = WSAIoctl(s,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ (*byte)(unsafe.Pointer(&WSAID_CONNECTEX)),
+ uint32(unsafe.Sizeof(WSAID_CONNECTEX)),
+ (*byte)(unsafe.Pointer(&connectExFunc.addr)),
+ uint32(unsafe.Sizeof(connectExFunc.addr)),
+ &n, nil, 0)
+ })
+ return connectExFunc.err
+}
+
+func connectEx(s Handle, name unsafe.Pointer, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
+ r1, _, e1 := syscall.Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error {
+ err := LoadConnectEx()
+ if err != nil {
+ return errorspkg.New("failed to find ConnectEx: " + err.Error())
+ }
+ ptr, n, err := sa.sockaddr()
+ if err != nil {
+ return err
+ }
+ return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
+}
+
+// Invented structures to support what package os expects.
+type Rusage struct {
+ CreationTime Filetime
+ ExitTime Filetime
+ KernelTime Filetime
+ UserTime Filetime
+}
+
+type WaitStatus struct {
+ ExitCode uint32
+}
+
+func (w WaitStatus) Exited() bool { return true }
+
+func (w WaitStatus) ExitStatus() int { return int(w.ExitCode) }
+
+func (w WaitStatus) Signal() Signal { return -1 }
+
+func (w WaitStatus) CoreDump() bool { return false }
+
+func (w WaitStatus) Stopped() bool { return false }
+
+func (w WaitStatus) Continued() bool { return false }
+
+func (w WaitStatus) StopSignal() Signal { return -1 }
+
+func (w WaitStatus) Signaled() bool { return false }
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+// Timespec is an invented structure on Windows, but here for
+// consistency with the corresponding package for other operating systems.
+type Timespec struct {
+ Sec int64
+ Nsec int64
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
+// TODO(brainman): fix all needed for net
+
+func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, syscall.EWINDOWS }
+func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error) {
+ return 0, nil, syscall.EWINDOWS
+}
+func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return syscall.EWINDOWS }
+func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return syscall.EWINDOWS }
+
+// The Linger struct is wrong but we only noticed after Go 1.
+// sysLinger is the real system call structure.
+
+// BUG(brainman): The definition of Linger is not appropriate for direct use
+// with Setsockopt and Getsockopt.
+// Use SetsockoptLinger instead.
+
+type Linger struct {
+ Onoff int32
+ Linger int32
+}
+
+type sysLinger struct {
+ Onoff uint16
+ Linger uint16
+}
+
+type IPMreq struct {
+ Multiaddr [4]byte /* in_addr */
+ Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+ Multiaddr [16]byte /* in6_addr */
+ Interface uint32
+}
+
+func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, syscall.EWINDOWS }
+
+func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) {
+ sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)}
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys)))
+}
+
+func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
+}
+func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
+}
+func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) {
+ return syscall.EWINDOWS
+}
+
+func Getpid() (pid int) { return int(getCurrentProcessId()) }
+
+func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
+ // NOTE(rsc): The Win32finddata struct is wrong for the system call:
+ // the two paths are each one uint16 short. Use the correct struct,
+ // a win32finddata1, and then copy the results out.
+ // There is no loss of expressivity here, because the final
+ // uint16, if it is used, is supposed to be a NUL, and Go doesn't need that.
+ // For Go 1.1, we might avoid the allocation of win32finddata1 here
+ // by adding a final Bug [2]uint16 field to the struct and then
+ // adjusting the fields in the result directly.
+ var data1 win32finddata1
+ handle, err = findFirstFile1(name, &data1)
+ if err == nil {
+ copyFindData(data, &data1)
+ }
+ return
+}
+
+func FindNextFile(handle Handle, data *Win32finddata) (err error) {
+ var data1 win32finddata1
+ err = findNextFile1(handle, &data1)
+ if err == nil {
+ copyFindData(data, &data1)
+ }
+ return
+}
+
+func getProcessEntry(pid int) (*ProcessEntry32, error) {
+ snapshot, err := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer CloseHandle(snapshot)
+ var procEntry ProcessEntry32
+ procEntry.Size = uint32(unsafe.Sizeof(procEntry))
+ if err = Process32First(snapshot, &procEntry); err != nil {
+ return nil, err
+ }
+ for {
+ if procEntry.ProcessID == uint32(pid) {
+ return &procEntry, nil
+ }
+ err = Process32Next(snapshot, &procEntry)
+ if err != nil {
+ return nil, err
+ }
+ }
+}
+
+func Getppid() (ppid int) {
+ pe, err := getProcessEntry(Getpid())
+ if err != nil {
+ return -1
+ }
+ return int(pe.ParentProcessID)
+}
+
+// TODO(brainman): fix all needed for os
+func Fchdir(fd Handle) (err error) { return syscall.EWINDOWS }
+func Link(oldpath, newpath string) (err error) { return syscall.EWINDOWS }
+func Symlink(path, link string) (err error) { return syscall.EWINDOWS }
+
+func Fchmod(fd Handle, mode uint32) (err error) { return syscall.EWINDOWS }
+func Chown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS }
+func Lchown(path string, uid int, gid int) (err error) { return syscall.EWINDOWS }
+func Fchown(fd Handle, uid int, gid int) (err error) { return syscall.EWINDOWS }
+
+func Getuid() (uid int) { return -1 }
+func Geteuid() (euid int) { return -1 }
+func Getgid() (gid int) { return -1 }
+func Getegid() (egid int) { return -1 }
+func Getgroups() (gids []int, err error) { return nil, syscall.EWINDOWS }
+
+type Signal int
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+ if 0 <= s && int(s) < len(signals) {
+ str := signals[s]
+ if str != "" {
+ return str
+ }
+ }
+ return "signal " + itoa(int(s))
+}
+
+func LoadCreateSymbolicLink() error {
+ return procCreateSymbolicLinkW.Find()
+}
+
+// Readlink returns the destination of the named symbolic link.
+func Readlink(path string, buf []byte) (n int, err error) {
+ fd, err := CreateFile(StringToUTF16Ptr(path), GENERIC_READ, 0, nil, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, 0)
+ if err != nil {
+ return -1, err
+ }
+ defer CloseHandle(fd)
+
+ rdbbuf := make([]byte, MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
+ var bytesReturned uint32
+ err = DeviceIoControl(fd, FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
+ if err != nil {
+ return -1, err
+ }
+
+ rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
+ var s string
+ switch rdb.ReparseTag {
+ case IO_REPARSE_TAG_SYMLINK:
+ data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+ p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+ s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+ p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+ s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+ default:
+ // the path is not a symlink or junction but another type of reparse
+ // point
+ return -1, syscall.ENOENT
+ }
+ n = copy(buf, []byte(s))
+
+ return n, nil
+}
diff --git a/vendor/golang.org/x/sys/windows/syscall_windows_test.go b/vendor/golang.org/x/sys/windows/syscall_windows_test.go
new file mode 100644
index 000000000..0f73c11ba
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/syscall_windows_test.go
@@ -0,0 +1,107 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows_test
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "syscall"
+ "testing"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+func TestWin32finddata(t *testing.T) {
+ dir, err := ioutil.TempDir("", "go-build")
+ if err != nil {
+ t.Fatalf("failed to create temp directory: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ path := filepath.Join(dir, "long_name.and_extension")
+ f, err := os.Create(path)
+ if err != nil {
+ t.Fatalf("failed to create %v: %v", path, err)
+ }
+ f.Close()
+
+ type X struct {
+ fd windows.Win32finddata
+ got byte
+ pad [10]byte // to protect ourselves
+
+ }
+ var want byte = 2 // it is unlikely to have this character in the filename
+ x := X{got: want}
+
+ pathp, _ := windows.UTF16PtrFromString(path)
+ h, err := windows.FindFirstFile(pathp, &(x.fd))
+ if err != nil {
+ t.Fatalf("FindFirstFile failed: %v", err)
+ }
+ err = windows.FindClose(h)
+ if err != nil {
+ t.Fatalf("FindClose failed: %v", err)
+ }
+
+ if x.got != want {
+ t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
+ }
+}
+
+func TestFormatMessage(t *testing.T) {
+ dll := windows.MustLoadDLL("pdh.dll")
+
+ pdhOpenQuery := func(datasrc *uint16, userdata uint32, query *windows.Handle) (errno uintptr) {
+ r0, _, _ := syscall.Syscall(dll.MustFindProc("PdhOpenQueryW").Addr(), 3, uintptr(unsafe.Pointer(datasrc)), uintptr(userdata), uintptr(unsafe.Pointer(query)))
+ return r0
+ }
+
+ pdhCloseQuery := func(query windows.Handle) (errno uintptr) {
+ r0, _, _ := syscall.Syscall(dll.MustFindProc("PdhCloseQuery").Addr(), 1, uintptr(query), 0, 0)
+ return r0
+ }
+
+ var q windows.Handle
+ name, err := windows.UTF16PtrFromString("no_such_source")
+ if err != nil {
+ t.Fatal(err)
+ }
+ errno := pdhOpenQuery(name, 0, &q)
+ if errno == 0 {
+ pdhCloseQuery(q)
+ t.Fatal("PdhOpenQuery succeeded, but expected to fail.")
+ }
+
+ const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
+ buf := make([]uint16, 300)
+ _, err = windows.FormatMessage(flags, uintptr(dll.Handle), uint32(errno), 0, buf, nil)
+ if err != nil {
+ t.Fatal("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, errno, err)
+ }
+}
+
+func abort(funcname string, err error) {
+ panic(funcname + " failed: " + err.Error())
+}
+
+func ExampleLoadLibrary() {
+ h, err := windows.LoadLibrary("kernel32.dll")
+ if err != nil {
+ abort("LoadLibrary", err)
+ }
+ defer windows.FreeLibrary(h)
+ proc, err := windows.GetProcAddress(h, "GetVersion")
+ if err != nil {
+ abort("GetProcAddress", err)
+ }
+ r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
+ major := byte(r)
+ minor := uint8(r >> 8)
+ build := uint16(r >> 16)
+ print("windows version ", major, ".", minor, " (Build ", build, ")\n")
+}
diff --git a/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
new file mode 100644
index 000000000..3ff8f5253
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -0,0 +1,2245 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package windows
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+var _ unsafe.Pointer
+
+var (
+ modadvapi32 = NewLazySystemDLL("advapi32.dll")
+ modkernel32 = NewLazySystemDLL("kernel32.dll")
+ modshell32 = NewLazySystemDLL("shell32.dll")
+ modmswsock = NewLazySystemDLL("mswsock.dll")
+ modcrypt32 = NewLazySystemDLL("crypt32.dll")
+ modws2_32 = NewLazySystemDLL("ws2_32.dll")
+ moddnsapi = NewLazySystemDLL("dnsapi.dll")
+ modiphlpapi = NewLazySystemDLL("iphlpapi.dll")
+ modsecur32 = NewLazySystemDLL("secur32.dll")
+ modnetapi32 = NewLazySystemDLL("netapi32.dll")
+ moduserenv = NewLazySystemDLL("userenv.dll")
+
+ procRegisterEventSourceW = modadvapi32.NewProc("RegisterEventSourceW")
+ procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource")
+ procReportEventW = modadvapi32.NewProc("ReportEventW")
+ procOpenSCManagerW = modadvapi32.NewProc("OpenSCManagerW")
+ procCloseServiceHandle = modadvapi32.NewProc("CloseServiceHandle")
+ procCreateServiceW = modadvapi32.NewProc("CreateServiceW")
+ procOpenServiceW = modadvapi32.NewProc("OpenServiceW")
+ procDeleteService = modadvapi32.NewProc("DeleteService")
+ procStartServiceW = modadvapi32.NewProc("StartServiceW")
+ procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus")
+ procControlService = modadvapi32.NewProc("ControlService")
+ procStartServiceCtrlDispatcherW = modadvapi32.NewProc("StartServiceCtrlDispatcherW")
+ procSetServiceStatus = modadvapi32.NewProc("SetServiceStatus")
+ procChangeServiceConfigW = modadvapi32.NewProc("ChangeServiceConfigW")
+ procQueryServiceConfigW = modadvapi32.NewProc("QueryServiceConfigW")
+ procChangeServiceConfig2W = modadvapi32.NewProc("ChangeServiceConfig2W")
+ procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W")
+ procGetLastError = modkernel32.NewProc("GetLastError")
+ procLoadLibraryW = modkernel32.NewProc("LoadLibraryW")
+ procLoadLibraryExW = modkernel32.NewProc("LoadLibraryExW")
+ procFreeLibrary = modkernel32.NewProc("FreeLibrary")
+ procGetProcAddress = modkernel32.NewProc("GetProcAddress")
+ procGetVersion = modkernel32.NewProc("GetVersion")
+ procFormatMessageW = modkernel32.NewProc("FormatMessageW")
+ procExitProcess = modkernel32.NewProc("ExitProcess")
+ procCreateFileW = modkernel32.NewProc("CreateFileW")
+ procReadFile = modkernel32.NewProc("ReadFile")
+ procWriteFile = modkernel32.NewProc("WriteFile")
+ procSetFilePointer = modkernel32.NewProc("SetFilePointer")
+ procCloseHandle = modkernel32.NewProc("CloseHandle")
+ procGetStdHandle = modkernel32.NewProc("GetStdHandle")
+ procFindFirstFileW = modkernel32.NewProc("FindFirstFileW")
+ procFindNextFileW = modkernel32.NewProc("FindNextFileW")
+ procFindClose = modkernel32.NewProc("FindClose")
+ procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
+ procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
+ procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
+ procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
+ procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
+ procDeleteFileW = modkernel32.NewProc("DeleteFileW")
+ procMoveFileW = modkernel32.NewProc("MoveFileW")
+ procMoveFileExW = modkernel32.NewProc("MoveFileExW")
+ procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
+ procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
+ procSetEndOfFile = modkernel32.NewProc("SetEndOfFile")
+ procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime")
+ procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation")
+ procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
+ procGetQueuedCompletionStatus = modkernel32.NewProc("GetQueuedCompletionStatus")
+ procPostQueuedCompletionStatus = modkernel32.NewProc("PostQueuedCompletionStatus")
+ procCancelIo = modkernel32.NewProc("CancelIo")
+ procCancelIoEx = modkernel32.NewProc("CancelIoEx")
+ procCreateProcessW = modkernel32.NewProc("CreateProcessW")
+ procOpenProcess = modkernel32.NewProc("OpenProcess")
+ procTerminateProcess = modkernel32.NewProc("TerminateProcess")
+ procGetExitCodeProcess = modkernel32.NewProc("GetExitCodeProcess")
+ procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW")
+ procGetCurrentProcess = modkernel32.NewProc("GetCurrentProcess")
+ procGetProcessTimes = modkernel32.NewProc("GetProcessTimes")
+ procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
+ procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
+ procGetTempPathW = modkernel32.NewProc("GetTempPathW")
+ procCreatePipe = modkernel32.NewProc("CreatePipe")
+ procGetFileType = modkernel32.NewProc("GetFileType")
+ procCryptAcquireContextW = modadvapi32.NewProc("CryptAcquireContextW")
+ procCryptReleaseContext = modadvapi32.NewProc("CryptReleaseContext")
+ procCryptGenRandom = modadvapi32.NewProc("CryptGenRandom")
+ procGetEnvironmentStringsW = modkernel32.NewProc("GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = modkernel32.NewProc("FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = modkernel32.NewProc("GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = modkernel32.NewProc("SetEnvironmentVariableW")
+ procSetFileTime = modkernel32.NewProc("SetFileTime")
+ procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
+ procSetFileAttributesW = modkernel32.NewProc("SetFileAttributesW")
+ procGetFileAttributesExW = modkernel32.NewProc("GetFileAttributesExW")
+ procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
+ procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW")
+ procLocalFree = modkernel32.NewProc("LocalFree")
+ procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
+ procFlushFileBuffers = modkernel32.NewProc("FlushFileBuffers")
+ procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
+ procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW")
+ procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW")
+ procCreateFileMappingW = modkernel32.NewProc("CreateFileMappingW")
+ procMapViewOfFile = modkernel32.NewProc("MapViewOfFile")
+ procUnmapViewOfFile = modkernel32.NewProc("UnmapViewOfFile")
+ procFlushViewOfFile = modkernel32.NewProc("FlushViewOfFile")
+ procVirtualLock = modkernel32.NewProc("VirtualLock")
+ procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
+ procTransmitFile = modmswsock.NewProc("TransmitFile")
+ procReadDirectoryChangesW = modkernel32.NewProc("ReadDirectoryChangesW")
+ procCertOpenSystemStoreW = modcrypt32.NewProc("CertOpenSystemStoreW")
+ procCertOpenStore = modcrypt32.NewProc("CertOpenStore")
+ procCertEnumCertificatesInStore = modcrypt32.NewProc("CertEnumCertificatesInStore")
+ procCertAddCertificateContextToStore = modcrypt32.NewProc("CertAddCertificateContextToStore")
+ procCertCloseStore = modcrypt32.NewProc("CertCloseStore")
+ procCertGetCertificateChain = modcrypt32.NewProc("CertGetCertificateChain")
+ procCertFreeCertificateChain = modcrypt32.NewProc("CertFreeCertificateChain")
+ procCertCreateCertificateContext = modcrypt32.NewProc("CertCreateCertificateContext")
+ procCertFreeCertificateContext = modcrypt32.NewProc("CertFreeCertificateContext")
+ procCertVerifyCertificateChainPolicy = modcrypt32.NewProc("CertVerifyCertificateChainPolicy")
+ procRegOpenKeyExW = modadvapi32.NewProc("RegOpenKeyExW")
+ procRegCloseKey = modadvapi32.NewProc("RegCloseKey")
+ procRegQueryInfoKeyW = modadvapi32.NewProc("RegQueryInfoKeyW")
+ procRegEnumKeyExW = modadvapi32.NewProc("RegEnumKeyExW")
+ procRegQueryValueExW = modadvapi32.NewProc("RegQueryValueExW")
+ procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId")
+ procGetConsoleMode = modkernel32.NewProc("GetConsoleMode")
+ procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")
+ procReadConsoleW = modkernel32.NewProc("ReadConsoleW")
+ procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
+ procProcess32FirstW = modkernel32.NewProc("Process32FirstW")
+ procProcess32NextW = modkernel32.NewProc("Process32NextW")
+ procDeviceIoControl = modkernel32.NewProc("DeviceIoControl")
+ procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW")
+ procCreateHardLinkW = modkernel32.NewProc("CreateHardLinkW")
+ procGetCurrentThreadId = modkernel32.NewProc("GetCurrentThreadId")
+ procCreateEventW = modkernel32.NewProc("CreateEventW")
+ procSetEvent = modkernel32.NewProc("SetEvent")
+ procWSAStartup = modws2_32.NewProc("WSAStartup")
+ procWSACleanup = modws2_32.NewProc("WSACleanup")
+ procWSAIoctl = modws2_32.NewProc("WSAIoctl")
+ procsocket = modws2_32.NewProc("socket")
+ procsetsockopt = modws2_32.NewProc("setsockopt")
+ procgetsockopt = modws2_32.NewProc("getsockopt")
+ procbind = modws2_32.NewProc("bind")
+ procconnect = modws2_32.NewProc("connect")
+ procgetsockname = modws2_32.NewProc("getsockname")
+ procgetpeername = modws2_32.NewProc("getpeername")
+ proclisten = modws2_32.NewProc("listen")
+ procshutdown = modws2_32.NewProc("shutdown")
+ procclosesocket = modws2_32.NewProc("closesocket")
+ procAcceptEx = modmswsock.NewProc("AcceptEx")
+ procGetAcceptExSockaddrs = modmswsock.NewProc("GetAcceptExSockaddrs")
+ procWSARecv = modws2_32.NewProc("WSARecv")
+ procWSASend = modws2_32.NewProc("WSASend")
+ procWSARecvFrom = modws2_32.NewProc("WSARecvFrom")
+ procWSASendTo = modws2_32.NewProc("WSASendTo")
+ procgethostbyname = modws2_32.NewProc("gethostbyname")
+ procgetservbyname = modws2_32.NewProc("getservbyname")
+ procntohs = modws2_32.NewProc("ntohs")
+ procgetprotobyname = modws2_32.NewProc("getprotobyname")
+ procDnsQuery_W = moddnsapi.NewProc("DnsQuery_W")
+ procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
+ procDnsNameCompare_W = moddnsapi.NewProc("DnsNameCompare_W")
+ procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW")
+ procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
+ procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
+ procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
+ procSetFileCompletionNotificationModes = modkernel32.NewProc("SetFileCompletionNotificationModes")
+ procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW")
+ procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
+ procGetACP = modkernel32.NewProc("GetACP")
+ procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
+ procTranslateNameW = modsecur32.NewProc("TranslateNameW")
+ procGetUserNameExW = modsecur32.NewProc("GetUserNameExW")
+ procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
+ procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation")
+ procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
+ procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
+ procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
+ procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
+ procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
+ procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
+ procCopySid = modadvapi32.NewProc("CopySid")
+ procAllocateAndInitializeSid = modadvapi32.NewProc("AllocateAndInitializeSid")
+ procFreeSid = modadvapi32.NewProc("FreeSid")
+ procEqualSid = modadvapi32.NewProc("EqualSid")
+ procOpenProcessToken = modadvapi32.NewProc("OpenProcessToken")
+ procGetTokenInformation = modadvapi32.NewProc("GetTokenInformation")
+ procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
+)
+
+func RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procRegisterEventSourceW.Addr(), 2, uintptr(unsafe.Pointer(uncServerName)), uintptr(unsafe.Pointer(sourceName)), 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func DeregisterEventSource(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procDeregisterEventSource.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) {
+ r1, _, e1 := syscall.Syscall9(procReportEventW.Addr(), 9, uintptr(log), uintptr(etype), uintptr(category), uintptr(eventId), uintptr(usrSId), uintptr(numStrings), uintptr(dataSize), uintptr(unsafe.Pointer(strings)), uintptr(unsafe.Pointer(rawData)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procOpenSCManagerW.Addr(), 3, uintptr(unsafe.Pointer(machineName)), uintptr(unsafe.Pointer(databaseName)), uintptr(access))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CloseServiceHandle(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procCloseServiceHandle.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall15(procCreateServiceW.Addr(), 13, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(unsafe.Pointer(displayName)), uintptr(access), uintptr(srvType), uintptr(startType), uintptr(errCtl), uintptr(unsafe.Pointer(pathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procOpenServiceW.Addr(), 3, uintptr(mgr), uintptr(unsafe.Pointer(serviceName)), uintptr(access))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func DeleteService(service Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procDeleteService.Addr(), 1, uintptr(service), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func StartService(service Handle, numArgs uint32, argVectors **uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procStartServiceW.Addr(), 3, uintptr(service), uintptr(numArgs), uintptr(unsafe.Pointer(argVectors)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func QueryServiceStatus(service Handle, status *SERVICE_STATUS) (err error) {
+ r1, _, e1 := syscall.Syscall(procQueryServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(status)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ControlService(service Handle, control uint32, status *SERVICE_STATUS) (err error) {
+ r1, _, e1 := syscall.Syscall(procControlService.Addr(), 3, uintptr(service), uintptr(control), uintptr(unsafe.Pointer(status)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func StartServiceCtrlDispatcher(serviceTable *SERVICE_TABLE_ENTRY) (err error) {
+ r1, _, e1 := syscall.Syscall(procStartServiceCtrlDispatcherW.Addr(), 1, uintptr(unsafe.Pointer(serviceTable)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetServiceStatus(service Handle, serviceStatus *SERVICE_STATUS) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetServiceStatus.Addr(), 2, uintptr(service), uintptr(unsafe.Pointer(serviceStatus)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ChangeServiceConfig(service Handle, serviceType uint32, startType uint32, errorControl uint32, binaryPathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16, displayName *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall12(procChangeServiceConfigW.Addr(), 11, uintptr(service), uintptr(serviceType), uintptr(startType), uintptr(errorControl), uintptr(unsafe.Pointer(binaryPathName)), uintptr(unsafe.Pointer(loadOrderGroup)), uintptr(unsafe.Pointer(tagId)), uintptr(unsafe.Pointer(dependencies)), uintptr(unsafe.Pointer(serviceStartName)), uintptr(unsafe.Pointer(password)), uintptr(unsafe.Pointer(displayName)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, bufSize uint32, bytesNeeded *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procQueryServiceConfigW.Addr(), 4, uintptr(service), uintptr(unsafe.Pointer(serviceConfig)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ChangeServiceConfig2(service Handle, infoLevel uint32, info *byte) (err error) {
+ r1, _, e1 := syscall.Syscall(procChangeServiceConfig2W.Addr(), 3, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(info)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func QueryServiceConfig2(service Handle, infoLevel uint32, buff *byte, buffSize uint32, bytesNeeded *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procQueryServiceConfig2W.Addr(), 5, uintptr(service), uintptr(infoLevel), uintptr(unsafe.Pointer(buff)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetLastError() (lasterr error) {
+ r0, _, _ := syscall.Syscall(procGetLastError.Addr(), 0, 0, 0, 0)
+ if r0 != 0 {
+ lasterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func LoadLibrary(libname string) (handle Handle, err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(libname)
+ if err != nil {
+ return
+ }
+ return _LoadLibrary(_p0)
+}
+
+func _LoadLibrary(libname *uint16) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procLoadLibraryW.Addr(), 1, uintptr(unsafe.Pointer(libname)), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func LoadLibraryEx(libname string, zero Handle, flags uintptr) (handle Handle, err error) {
+ var _p0 *uint16
+ _p0, err = syscall.UTF16PtrFromString(libname)
+ if err != nil {
+ return
+ }
+ return _LoadLibraryEx(_p0, zero, flags)
+}
+
+func _LoadLibraryEx(libname *uint16, zero Handle, flags uintptr) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procLoadLibraryExW.Addr(), 3, uintptr(unsafe.Pointer(libname)), uintptr(zero), uintptr(flags))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func FreeLibrary(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procFreeLibrary.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetProcAddress(module Handle, procname string) (proc uintptr, err error) {
+ var _p0 *byte
+ _p0, err = syscall.BytePtrFromString(procname)
+ if err != nil {
+ return
+ }
+ return _GetProcAddress(module, _p0)
+}
+
+func _GetProcAddress(module Handle, procname *byte) (proc uintptr, err error) {
+ r0, _, e1 := syscall.Syscall(procGetProcAddress.Addr(), 2, uintptr(module), uintptr(unsafe.Pointer(procname)), 0)
+ proc = uintptr(r0)
+ if proc == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetVersion() (ver uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetVersion.Addr(), 0, 0, 0, 0)
+ ver = uint32(r0)
+ if ver == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
+ var _p0 *uint16
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r0, _, e1 := syscall.Syscall9(procFormatMessageW.Addr(), 7, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ExitProcess(exitcode uint32) {
+ syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0)
+ return
+}
+
+func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r1, _, e1 := syscall.Syscall6(procReadFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WriteFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) {
+ var _p0 *byte
+ if len(buf) > 0 {
+ _p0 = &buf[0]
+ }
+ r1, _, e1 := syscall.Syscall6(procWriteFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) {
+ r0, _, e1 := syscall.Syscall6(procSetFilePointer.Addr(), 4, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
+ newlowoffset = uint32(r0)
+ if newlowoffset == 0xffffffff {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CloseHandle(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetStdHandle(stdhandle int) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procGetStdHandle.Addr(), 1, uintptr(stdhandle), 0, 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func findFirstFile1(name *uint16, data *win32finddata1) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procFindFirstFileW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func findNextFile1(handle Handle, data *win32finddata1) (err error) {
+ r1, _, e1 := syscall.Syscall(procFindNextFileW.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func FindClose(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetFileInformationByHandle(handle Handle, data *ByHandleFileInformation) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetFileInformationByHandle.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetCurrentDirectoryW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetCurrentDirectory(path *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateDirectory(path *uint16, sa *SecurityAttributes) (err error) {
+ r1, _, e1 := syscall.Syscall(procCreateDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func RemoveDirectory(path *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procRemoveDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func DeleteFile(path *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procDeleteFileW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func MoveFile(from *uint16, to *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procMoveFileW.Addr(), 2, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetComputerName(buf *uint16, n *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetComputerNameW.Addr(), 2, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nametype), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetEndOfFile(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetEndOfFile.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetSystemTimeAsFileTime(time *Filetime) {
+ syscall.Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0)
+ return
+}
+
+func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
+ rc = uint32(r0)
+ if rc == 0xffffffff {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error) {
+ r1, _, e1 := syscall.Syscall6(procPostQueuedCompletionStatus.Addr(), 4, uintptr(cphandle), uintptr(qty), uintptr(key), uintptr(unsafe.Pointer(overlapped)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CancelIo(s Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procCancelIo.Addr(), 1, uintptr(s), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CancelIoEx(s Handle, o *Overlapped) (err error) {
+ r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(s), uintptr(unsafe.Pointer(o)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) {
+ var _p0 uint32
+ if inheritHandles {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := syscall.Syscall12(procCreateProcessW.Addr(), 10, uintptr(unsafe.Pointer(appName)), uintptr(unsafe.Pointer(commandLine)), uintptr(unsafe.Pointer(procSecurity)), uintptr(unsafe.Pointer(threadSecurity)), uintptr(_p0), uintptr(creationFlags), uintptr(unsafe.Pointer(env)), uintptr(unsafe.Pointer(currentDir)), uintptr(unsafe.Pointer(startupInfo)), uintptr(unsafe.Pointer(outProcInfo)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error) {
+ var _p0 uint32
+ if inheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := syscall.Syscall(procOpenProcess.Addr(), 3, uintptr(da), uintptr(_p0), uintptr(pid))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func TerminateProcess(handle Handle, exitcode uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procTerminateProcess.Addr(), 2, uintptr(handle), uintptr(exitcode), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetExitCodeProcess(handle Handle, exitcode *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetExitCodeProcess.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(exitcode)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetStartupInfo(startupInfo *StartupInfo) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetCurrentProcess() (pseudoHandle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procGetCurrentProcess.Addr(), 0, 0, 0, 0)
+ pseudoHandle = Handle(r0)
+ if pseudoHandle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetProcessTimes.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(creationTime)), uintptr(unsafe.Pointer(exitTime)), uintptr(unsafe.Pointer(kernelTime)), uintptr(unsafe.Pointer(userTime)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) {
+ var _p0 uint32
+ if bInheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := syscall.Syscall9(procDuplicateHandle.Addr(), 7, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procWaitForSingleObject.Addr(), 2, uintptr(handle), uintptr(waitMilliseconds), 0)
+ event = uint32(r0)
+ if event == 0xffffffff {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetTempPath(buflen uint32, buf *uint16) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetTempPathW.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreatePipe(readhandle *Handle, writehandle *Handle, sa *SecurityAttributes, size uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procCreatePipe.Addr(), 4, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(sa)), uintptr(size), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetFileType(filehandle Handle) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CryptAcquireContext(provhandle *Handle, container *uint16, provider *uint16, provtype uint32, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procCryptAcquireContextW.Addr(), 5, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CryptReleaseContext(provhandle Handle, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procCryptReleaseContext.Addr(), 2, uintptr(provhandle), uintptr(flags), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CryptGenRandom(provhandle Handle, buflen uint32, buf *byte) (err error) {
+ r1, _, e1 := syscall.Syscall(procCryptGenRandom.Addr(), 3, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetEnvironmentStrings() (envs *uint16, err error) {
+ r0, _, e1 := syscall.Syscall(procGetEnvironmentStringsW.Addr(), 0, 0, 0, 0)
+ envs = (*uint16)(unsafe.Pointer(r0))
+ if envs == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func FreeEnvironmentStrings(envs *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procFreeEnvironmentStringsW.Addr(), 1, uintptr(unsafe.Pointer(envs)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetEnvironmentVariableW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetEnvironmentVariable(name *uint16, value *uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetEnvironmentVariableW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) {
+ r1, _, e1 := syscall.Syscall6(procSetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetFileAttributes(name *uint16) (attrs uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetFileAttributesW.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
+ attrs = uint32(r0)
+ if attrs == INVALID_FILE_ATTRIBUTES {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetFileAttributes(name *uint16, attrs uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetFileAttributesW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(attrs), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetFileAttributesExW.Addr(), 3, uintptr(unsafe.Pointer(name)), uintptr(level), uintptr(unsafe.Pointer(info)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetCommandLine() (cmd *uint16) {
+ r0, _, _ := syscall.Syscall(procGetCommandLineW.Addr(), 0, 0, 0, 0)
+ cmd = (*uint16)(unsafe.Pointer(r0))
+ return
+}
+
+func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
+ r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
+ argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
+ if argv == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func LocalFree(hmem Handle) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procLocalFree.Addr(), 1, uintptr(hmem), 0, 0)
+ handle = Handle(r0)
+ if handle != 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func FlushFileBuffers(handle Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procFlushFileBuffers.Addr(), 1, uintptr(handle), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetFullPathName(path *uint16, buflen uint32, buf *uint16, fname **uint16) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall6(procGetFullPathNameW.Addr(), 4, uintptr(unsafe.Pointer(path)), uintptr(buflen), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(fname)), 0, 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetLongPathNameW.Addr(), 3, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(buf)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uint32, err error) {
+ r0, _, e1 := syscall.Syscall(procGetShortPathNameW.Addr(), 3, uintptr(unsafe.Pointer(longpath)), uintptr(unsafe.Pointer(shortpath)), uintptr(buflen))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateFileMapping(fhandle Handle, sa *SecurityAttributes, prot uint32, maxSizeHigh uint32, maxSizeLow uint32, name *uint16) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(procCreateFileMappingW.Addr(), 6, uintptr(fhandle), uintptr(unsafe.Pointer(sa)), uintptr(prot), uintptr(maxSizeHigh), uintptr(maxSizeLow), uintptr(unsafe.Pointer(name)))
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow uint32, length uintptr) (addr uintptr, err error) {
+ r0, _, e1 := syscall.Syscall6(procMapViewOfFile.Addr(), 5, uintptr(handle), uintptr(access), uintptr(offsetHigh), uintptr(offsetLow), uintptr(length), 0)
+ addr = uintptr(r0)
+ if addr == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func UnmapViewOfFile(addr uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall(procUnmapViewOfFile.Addr(), 1, uintptr(addr), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func FlushViewOfFile(addr uintptr, length uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall(procFlushViewOfFile.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func VirtualLock(addr uintptr, length uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall(procVirtualLock.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func VirtualUnlock(addr uintptr, length uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall(procVirtualUnlock.Addr(), 2, uintptr(addr), uintptr(length), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func TransmitFile(s Handle, handle Handle, bytesToWrite uint32, bytsPerSend uint32, overlapped *Overlapped, transmitFileBuf *TransmitFileBuffers, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall9(procTransmitFile.Addr(), 7, uintptr(s), uintptr(handle), uintptr(bytesToWrite), uintptr(bytsPerSend), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transmitFileBuf)), uintptr(flags), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ReadDirectoryChanges(handle Handle, buf *byte, buflen uint32, watchSubTree bool, mask uint32, retlen *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
+ var _p0 uint32
+ if watchSubTree {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := syscall.Syscall9(procReadDirectoryChangesW.Addr(), 8, uintptr(handle), uintptr(unsafe.Pointer(buf)), uintptr(buflen), uintptr(_p0), uintptr(mask), uintptr(unsafe.Pointer(retlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertOpenSystemStore(hprov Handle, name *uint16) (store Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procCertOpenSystemStoreW.Addr(), 2, uintptr(hprov), uintptr(unsafe.Pointer(name)), 0)
+ store = Handle(r0)
+ if store == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertOpenStore(storeProvider uintptr, msgAndCertEncodingType uint32, cryptProv uintptr, flags uint32, para uintptr) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(procCertOpenStore.Addr(), 5, uintptr(storeProvider), uintptr(msgAndCertEncodingType), uintptr(cryptProv), uintptr(flags), uintptr(para), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertEnumCertificatesInStore(store Handle, prevContext *CertContext) (context *CertContext, err error) {
+ r0, _, e1 := syscall.Syscall(procCertEnumCertificatesInStore.Addr(), 2, uintptr(store), uintptr(unsafe.Pointer(prevContext)), 0)
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertAddCertificateContextToStore(store Handle, certContext *CertContext, addDisposition uint32, storeContext **CertContext) (err error) {
+ r1, _, e1 := syscall.Syscall6(procCertAddCertificateContextToStore.Addr(), 4, uintptr(store), uintptr(unsafe.Pointer(certContext)), uintptr(addDisposition), uintptr(unsafe.Pointer(storeContext)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertCloseStore(store Handle, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procCertCloseStore.Addr(), 2, uintptr(store), uintptr(flags), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertGetCertificateChain(engine Handle, leaf *CertContext, time *Filetime, additionalStore Handle, para *CertChainPara, flags uint32, reserved uintptr, chainCtx **CertChainContext) (err error) {
+ r1, _, e1 := syscall.Syscall9(procCertGetCertificateChain.Addr(), 8, uintptr(engine), uintptr(unsafe.Pointer(leaf)), uintptr(unsafe.Pointer(time)), uintptr(additionalStore), uintptr(unsafe.Pointer(para)), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(chainCtx)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateChain(ctx *CertChainContext) {
+ syscall.Syscall(procCertFreeCertificateChain.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ return
+}
+
+func CertCreateCertificateContext(certEncodingType uint32, certEncoded *byte, encodedLen uint32) (context *CertContext, err error) {
+ r0, _, e1 := syscall.Syscall(procCertCreateCertificateContext.Addr(), 3, uintptr(certEncodingType), uintptr(unsafe.Pointer(certEncoded)), uintptr(encodedLen))
+ context = (*CertContext)(unsafe.Pointer(r0))
+ if context == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertFreeCertificateContext(ctx *CertContext) (err error) {
+ r1, _, e1 := syscall.Syscall(procCertFreeCertificateContext.Addr(), 1, uintptr(unsafe.Pointer(ctx)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CertVerifyCertificateChainPolicy(policyOID uintptr, chain *CertChainContext, para *CertChainPolicyPara, status *CertChainPolicyStatus) (err error) {
+ r1, _, e1 := syscall.Syscall6(procCertVerifyCertificateChainPolicy.Addr(), 4, uintptr(policyOID), uintptr(unsafe.Pointer(chain)), uintptr(unsafe.Pointer(para)), uintptr(unsafe.Pointer(status)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func RegOpenKeyEx(key Handle, subkey *uint16, options uint32, desiredAccess uint32, result *Handle) (regerrno error) {
+ r0, _, _ := syscall.Syscall6(procRegOpenKeyExW.Addr(), 5, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(options), uintptr(desiredAccess), uintptr(unsafe.Pointer(result)), 0)
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func RegCloseKey(key Handle) (regerrno error) {
+ r0, _, _ := syscall.Syscall(procRegCloseKey.Addr(), 1, uintptr(key), 0, 0)
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+ r0, _, _ := syscall.Syscall12(procRegQueryInfoKeyW.Addr(), 12, uintptr(key), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(subkeysLen)), uintptr(unsafe.Pointer(maxSubkeyLen)), uintptr(unsafe.Pointer(maxClassLen)), uintptr(unsafe.Pointer(valuesLen)), uintptr(unsafe.Pointer(maxValueNameLen)), uintptr(unsafe.Pointer(maxValueLen)), uintptr(unsafe.Pointer(saLen)), uintptr(unsafe.Pointer(lastWriteTime)))
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) {
+ r0, _, _ := syscall.Syscall9(procRegEnumKeyExW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(class)), uintptr(unsafe.Pointer(classLen)), uintptr(unsafe.Pointer(lastWriteTime)), 0)
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
+ r0, _, _ := syscall.Syscall6(procRegQueryValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)))
+ if r0 != 0 {
+ regerrno = syscall.Errno(r0)
+ }
+ return
+}
+
+func getCurrentProcessId() (pid uint32) {
+ r0, _, _ := syscall.Syscall(procGetCurrentProcessId.Addr(), 0, 0, 0, 0)
+ pid = uint32(r0)
+ return
+}
+
+func GetConsoleMode(console Handle, mode *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) {
+ r1, _, e1 := syscall.Syscall6(procWriteConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(towrite), uintptr(unsafe.Pointer(written)), uintptr(unsafe.Pointer(reserved)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) {
+ r1, _, e1 := syscall.Syscall6(procReadConsoleW.Addr(), 5, uintptr(console), uintptr(unsafe.Pointer(buf)), uintptr(toread), uintptr(unsafe.Pointer(read)), uintptr(unsafe.Pointer(inputControl)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procCreateToolhelp32Snapshot.Addr(), 2, uintptr(flags), uintptr(processId), 0)
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) {
+ r1, _, e1 := syscall.Syscall(procProcess32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) {
+ r1, _, e1 := syscall.Syscall(procProcess32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(procEntry)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBufferSize uint32, outBuffer *byte, outBufferSize uint32, bytesReturned *uint32, overlapped *Overlapped) (err error) {
+ r1, _, e1 := syscall.Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(ioControlCode), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferSize), uintptr(unsafe.Pointer(outBuffer)), uintptr(outBufferSize), uintptr(unsafe.Pointer(bytesReturned)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags))
+ if r1&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func CreateHardLink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall(procCreateHardLinkW.Addr(), 3, uintptr(unsafe.Pointer(filename)), uintptr(unsafe.Pointer(existingfilename)), uintptr(reserved))
+ if r1&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetCurrentThreadId() (id uint32) {
+ r0, _, _ := syscall.Syscall(procGetCurrentThreadId.Addr(), 0, 0, 0, 0)
+ id = uint32(r0)
+ return
+}
+
+func CreateEvent(eventAttrs *syscall.SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(eventAttrs)), uintptr(manualReset), uintptr(initialState), uintptr(unsafe.Pointer(name)), 0, 0)
+ handle = Handle(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func SetEvent(event Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetEvent.Addr(), 1, uintptr(event), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
+ r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
+ if r0 != 0 {
+ sockerr = syscall.Errno(r0)
+ }
+ return
+}
+
+func WSACleanup() (err error) {
+ r1, _, e1 := syscall.Syscall(procWSACleanup.Addr(), 0, 0, 0, 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) {
+ r1, _, e1 := syscall.Syscall9(procWSAIoctl.Addr(), 9, uintptr(s), uintptr(iocc), uintptr(unsafe.Pointer(inbuf)), uintptr(cbif), uintptr(unsafe.Pointer(outbuf)), uintptr(cbob), uintptr(unsafe.Pointer(cbbr)), uintptr(unsafe.Pointer(overlapped)), uintptr(completionRoutine))
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func socket(af int32, typ int32, protocol int32) (handle Handle, err error) {
+ r0, _, e1 := syscall.Syscall(procsocket.Addr(), 3, uintptr(af), uintptr(typ), uintptr(protocol))
+ handle = Handle(r0)
+ if handle == InvalidHandle {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(unsafe.Pointer(optlen)), 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func bind(s Handle, name unsafe.Pointer, namelen int32) (err error) {
+ r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func connect(s Handle, name unsafe.Pointer, namelen int32) (err error) {
+ r1, _, e1 := syscall.Syscall(procconnect.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
+ r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) {
+ r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func listen(s Handle, backlog int32) (err error) {
+ r1, _, e1 := syscall.Syscall(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func shutdown(s Handle, how int32) (err error) {
+ r1, _, e1 := syscall.Syscall(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func Closesocket(s Handle) (err error) {
+ r1, _, e1 := syscall.Syscall(procclosesocket.Addr(), 1, uintptr(s), 0, 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) {
+ r1, _, e1 := syscall.Syscall9(procAcceptEx.Addr(), 8, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) {
+ syscall.Syscall9(procGetAcceptExSockaddrs.Addr(), 8, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0)
+ return
+}
+
+func WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) {
+ r1, _, e1 := syscall.Syscall9(procWSARecv.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) {
+ r1, _, e1 := syscall.Syscall9(procWSASend.Addr(), 7, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) {
+ r1, _, e1 := syscall.Syscall9(procWSARecvFrom.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) {
+ r1, _, e1 := syscall.Syscall9(procWSASendTo.Addr(), 9, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(to)), uintptr(tolen), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
+ if r1 == socket_error {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetHostByName(name string) (h *Hostent, err error) {
+ var _p0 *byte
+ _p0, err = syscall.BytePtrFromString(name)
+ if err != nil {
+ return
+ }
+ return _GetHostByName(_p0)
+}
+
+func _GetHostByName(name *byte) (h *Hostent, err error) {
+ r0, _, e1 := syscall.Syscall(procgethostbyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
+ h = (*Hostent)(unsafe.Pointer(r0))
+ if h == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetServByName(name string, proto string) (s *Servent, err error) {
+ var _p0 *byte
+ _p0, err = syscall.BytePtrFromString(name)
+ if err != nil {
+ return
+ }
+ var _p1 *byte
+ _p1, err = syscall.BytePtrFromString(proto)
+ if err != nil {
+ return
+ }
+ return _GetServByName(_p0, _p1)
+}
+
+func _GetServByName(name *byte, proto *byte) (s *Servent, err error) {
+ r0, _, e1 := syscall.Syscall(procgetservbyname.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(proto)), 0)
+ s = (*Servent)(unsafe.Pointer(r0))
+ if s == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func Ntohs(netshort uint16) (u uint16) {
+ r0, _, _ := syscall.Syscall(procntohs.Addr(), 1, uintptr(netshort), 0, 0)
+ u = uint16(r0)
+ return
+}
+
+func GetProtoByName(name string) (p *Protoent, err error) {
+ var _p0 *byte
+ _p0, err = syscall.BytePtrFromString(name)
+ if err != nil {
+ return
+ }
+ return _GetProtoByName(_p0)
+}
+
+func _GetProtoByName(name *byte) (p *Protoent, err error) {
+ r0, _, e1 := syscall.Syscall(procgetprotobyname.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
+ p = (*Protoent)(unsafe.Pointer(r0))
+ if p == nil {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) {
+ var _p0 *uint16
+ _p0, status = syscall.UTF16PtrFromString(name)
+ if status != nil {
+ return
+ }
+ return _DnsQuery(_p0, qtype, options, extra, qrs, pr)
+}
+
+func _DnsQuery(name *uint16, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) {
+ r0, _, _ := syscall.Syscall6(procDnsQuery_W.Addr(), 6, uintptr(unsafe.Pointer(name)), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
+ if r0 != 0 {
+ status = syscall.Errno(r0)
+ }
+ return
+}
+
+func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
+ syscall.Syscall(procDnsRecordListFree.Addr(), 2, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0)
+ return
+}
+
+func DnsNameCompare(name1 *uint16, name2 *uint16) (same bool) {
+ r0, _, _ := syscall.Syscall(procDnsNameCompare_W.Addr(), 2, uintptr(unsafe.Pointer(name1)), uintptr(unsafe.Pointer(name2)), 0)
+ same = r0 != 0
+ return
+}
+
+func GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) {
+ r0, _, _ := syscall.Syscall6(procGetAddrInfoW.Addr(), 4, uintptr(unsafe.Pointer(nodename)), uintptr(unsafe.Pointer(servicename)), uintptr(unsafe.Pointer(hints)), uintptr(unsafe.Pointer(result)), 0, 0)
+ if r0 != 0 {
+ sockerr = syscall.Errno(r0)
+ }
+ return
+}
+
+func FreeAddrInfoW(addrinfo *AddrinfoW) {
+ syscall.Syscall(procFreeAddrInfoW.Addr(), 1, uintptr(unsafe.Pointer(addrinfo)), 0, 0)
+ return
+}
+
+func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
+ r0, _, _ := syscall.Syscall(procGetIfEntry.Addr(), 1, uintptr(unsafe.Pointer(pIfRow)), 0, 0)
+ if r0 != 0 {
+ errcode = syscall.Errno(r0)
+ }
+ return
+}
+
+func GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) {
+ r0, _, _ := syscall.Syscall(procGetAdaptersInfo.Addr(), 2, uintptr(unsafe.Pointer(ai)), uintptr(unsafe.Pointer(ol)), 0)
+ if r0 != 0 {
+ errcode = syscall.Errno(r0)
+ }
+ return
+}
+
+func SetFileCompletionNotificationModes(handle Handle, flags uint8) (err error) {
+ r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(handle), uintptr(flags), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) {
+ r0, _, e1 := syscall.Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength)))
+ n = int32(r0)
+ if n == -1 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
+ r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0)
+ if r0 != 0 {
+ errcode = syscall.Errno(r0)
+ }
+ return
+}
+
+func GetACP() (acp uint32) {
+ r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0)
+ acp = uint32(r0)
+ return
+}
+
+func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) {
+ r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar))
+ nwrite = int32(r0)
+ if nwrite == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0)
+ if r1&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize)))
+ if r1&0xff == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) {
+ r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0)
+ if r0 != 0 {
+ neterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) {
+ r0, _, _ := syscall.Syscall(procNetGetJoinInformation.Addr(), 3, uintptr(unsafe.Pointer(server)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(bufType)))
+ if r0 != 0 {
+ neterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func NetApiBufferFree(buf *byte) (neterr error) {
+ r0, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0)
+ if r0 != 0 {
+ neterr = syscall.Errno(r0)
+ }
+ return
+}
+
+func LookupAccountSid(systemName *uint16, sid *SID, name *uint16, nameLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func LookupAccountName(systemName *uint16, accountName *uint16, sid *SID, sidLen *uint32, refdDomainName *uint16, refdDomainNameLen *uint32, use *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidLen)), uintptr(unsafe.Pointer(refdDomainName)), uintptr(unsafe.Pointer(refdDomainNameLen)), uintptr(unsafe.Pointer(use)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ConvertSidToStringSid(sid *SID, stringSid **uint16) (err error) {
+ r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(stringSid)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func ConvertStringSidToSid(stringSid *uint16, sid **SID) (err error) {
+ r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(stringSid)), uintptr(unsafe.Pointer(sid)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetLengthSid(sid *SID) (len uint32) {
+ r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+ len = uint32(r0)
+ return
+}
+
+func CopySid(destSidLen uint32, destSid *SID, srcSid *SID) (err error) {
+ r1, _, e1 := syscall.Syscall(procCopySid.Addr(), 3, uintptr(destSidLen), uintptr(unsafe.Pointer(destSid)), uintptr(unsafe.Pointer(srcSid)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func AllocateAndInitializeSid(identAuth *SidIdentifierAuthority, subAuth byte, subAuth0 uint32, subAuth1 uint32, subAuth2 uint32, subAuth3 uint32, subAuth4 uint32, subAuth5 uint32, subAuth6 uint32, subAuth7 uint32, sid **SID) (err error) {
+ r1, _, e1 := syscall.Syscall12(procAllocateAndInitializeSid.Addr(), 11, uintptr(unsafe.Pointer(identAuth)), uintptr(subAuth), uintptr(subAuth0), uintptr(subAuth1), uintptr(subAuth2), uintptr(subAuth3), uintptr(subAuth4), uintptr(subAuth5), uintptr(subAuth6), uintptr(subAuth7), uintptr(unsafe.Pointer(sid)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func FreeSid(sid *SID) (err error) {
+ r1, _, e1 := syscall.Syscall(procFreeSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
+ if r1 != 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func EqualSid(sid1 *SID, sid2 *SID) (isEqual bool) {
+ r0, _, _ := syscall.Syscall(procEqualSid.Addr(), 2, uintptr(unsafe.Pointer(sid1)), uintptr(unsafe.Pointer(sid2)), 0)
+ isEqual = r0 != 0
+ return
+}
+
+func OpenProcessToken(h Handle, access uint32, token *Token) (err error) {
+ r1, _, e1 := syscall.Syscall(procOpenProcessToken.Addr(), 3, uintptr(h), uintptr(access), uintptr(unsafe.Pointer(token)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall6(procGetTokenInformation.Addr(), 5, uintptr(t), uintptr(infoClass), uintptr(unsafe.Pointer(info)), uintptr(infoLen), uintptr(unsafe.Pointer(returnedLen)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
+func GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetUserProfileDirectoryW.Addr(), 3, uintptr(t), uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
diff --git a/vendor/golang.org/x/sys/windows/ztypes_windows.go b/vendor/golang.org/x/sys/windows/ztypes_windows.go
new file mode 100644
index 000000000..1fe19d1d7
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/ztypes_windows.go
@@ -0,0 +1,1242 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+import "syscall"
+
+const (
+ // Windows errors.
+ ERROR_FILE_NOT_FOUND syscall.Errno = 2
+ ERROR_PATH_NOT_FOUND syscall.Errno = 3
+ ERROR_ACCESS_DENIED syscall.Errno = 5
+ ERROR_NO_MORE_FILES syscall.Errno = 18
+ ERROR_HANDLE_EOF syscall.Errno = 38
+ ERROR_NETNAME_DELETED syscall.Errno = 64
+ ERROR_FILE_EXISTS syscall.Errno = 80
+ ERROR_BROKEN_PIPE syscall.Errno = 109
+ ERROR_BUFFER_OVERFLOW syscall.Errno = 111
+ ERROR_INSUFFICIENT_BUFFER syscall.Errno = 122
+ ERROR_MOD_NOT_FOUND syscall.Errno = 126
+ ERROR_PROC_NOT_FOUND syscall.Errno = 127
+ ERROR_ALREADY_EXISTS syscall.Errno = 183
+ ERROR_ENVVAR_NOT_FOUND syscall.Errno = 203
+ ERROR_MORE_DATA syscall.Errno = 234
+ ERROR_OPERATION_ABORTED syscall.Errno = 995
+ ERROR_IO_PENDING syscall.Errno = 997
+ ERROR_SERVICE_SPECIFIC_ERROR syscall.Errno = 1066
+ ERROR_NOT_FOUND syscall.Errno = 1168
+ ERROR_PRIVILEGE_NOT_HELD syscall.Errno = 1314
+ WSAEACCES syscall.Errno = 10013
+ WSAECONNRESET syscall.Errno = 10054
+)
+
+const (
+ // Invented values to support what package os expects.
+ O_RDONLY = 0x00000
+ O_WRONLY = 0x00001
+ O_RDWR = 0x00002
+ O_CREAT = 0x00040
+ O_EXCL = 0x00080
+ O_NOCTTY = 0x00100
+ O_TRUNC = 0x00200
+ O_NONBLOCK = 0x00800
+ O_APPEND = 0x00400
+ O_SYNC = 0x01000
+ O_ASYNC = 0x02000
+ O_CLOEXEC = 0x80000
+)
+
+const (
+ // More invented values for signals
+ SIGHUP = Signal(0x1)
+ SIGINT = Signal(0x2)
+ SIGQUIT = Signal(0x3)
+ SIGILL = Signal(0x4)
+ SIGTRAP = Signal(0x5)
+ SIGABRT = Signal(0x6)
+ SIGBUS = Signal(0x7)
+ SIGFPE = Signal(0x8)
+ SIGKILL = Signal(0x9)
+ SIGSEGV = Signal(0xb)
+ SIGPIPE = Signal(0xd)
+ SIGALRM = Signal(0xe)
+ SIGTERM = Signal(0xf)
+)
+
+var signals = [...]string{
+ 1: "hangup",
+ 2: "interrupt",
+ 3: "quit",
+ 4: "illegal instruction",
+ 5: "trace/breakpoint trap",
+ 6: "aborted",
+ 7: "bus error",
+ 8: "floating point exception",
+ 9: "killed",
+ 10: "user defined signal 1",
+ 11: "segmentation fault",
+ 12: "user defined signal 2",
+ 13: "broken pipe",
+ 14: "alarm clock",
+ 15: "terminated",
+}
+
+const (
+ GENERIC_READ = 0x80000000
+ GENERIC_WRITE = 0x40000000
+ GENERIC_EXECUTE = 0x20000000
+ GENERIC_ALL = 0x10000000
+
+ FILE_LIST_DIRECTORY = 0x00000001
+ FILE_APPEND_DATA = 0x00000004
+ FILE_WRITE_ATTRIBUTES = 0x00000100
+
+ FILE_SHARE_READ = 0x00000001
+ FILE_SHARE_WRITE = 0x00000002
+ FILE_SHARE_DELETE = 0x00000004
+ FILE_ATTRIBUTE_READONLY = 0x00000001
+ FILE_ATTRIBUTE_HIDDEN = 0x00000002
+ FILE_ATTRIBUTE_SYSTEM = 0x00000004
+ FILE_ATTRIBUTE_DIRECTORY = 0x00000010
+ FILE_ATTRIBUTE_ARCHIVE = 0x00000020
+ FILE_ATTRIBUTE_NORMAL = 0x00000080
+ FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400
+
+ INVALID_FILE_ATTRIBUTES = 0xffffffff
+
+ CREATE_NEW = 1
+ CREATE_ALWAYS = 2
+ OPEN_EXISTING = 3
+ OPEN_ALWAYS = 4
+ TRUNCATE_EXISTING = 5
+
+ FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
+ FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
+ FILE_FLAG_OVERLAPPED = 0x40000000
+
+ HANDLE_FLAG_INHERIT = 0x00000001
+ STARTF_USESTDHANDLES = 0x00000100
+ STARTF_USESHOWWINDOW = 0x00000001
+ DUPLICATE_CLOSE_SOURCE = 0x00000001
+ DUPLICATE_SAME_ACCESS = 0x00000002
+
+ STD_INPUT_HANDLE = -10
+ STD_OUTPUT_HANDLE = -11
+ STD_ERROR_HANDLE = -12
+
+ FILE_BEGIN = 0
+ FILE_CURRENT = 1
+ FILE_END = 2
+
+ LANG_ENGLISH = 0x09
+ SUBLANG_ENGLISH_US = 0x01
+
+ FORMAT_MESSAGE_ALLOCATE_BUFFER = 256
+ FORMAT_MESSAGE_IGNORE_INSERTS = 512
+ FORMAT_MESSAGE_FROM_STRING = 1024
+ FORMAT_MESSAGE_FROM_HMODULE = 2048
+ FORMAT_MESSAGE_FROM_SYSTEM = 4096
+ FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
+ FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
+
+ MAX_PATH = 260
+ MAX_LONG_PATH = 32768
+
+ MAX_COMPUTERNAME_LENGTH = 15
+
+ TIME_ZONE_ID_UNKNOWN = 0
+ TIME_ZONE_ID_STANDARD = 1
+
+ TIME_ZONE_ID_DAYLIGHT = 2
+ IGNORE = 0
+ INFINITE = 0xffffffff
+
+ WAIT_TIMEOUT = 258
+ WAIT_ABANDONED = 0x00000080
+ WAIT_OBJECT_0 = 0x00000000
+ WAIT_FAILED = 0xFFFFFFFF
+
+ CREATE_NEW_PROCESS_GROUP = 0x00000200
+ CREATE_UNICODE_ENVIRONMENT = 0x00000400
+
+ PROCESS_TERMINATE = 1
+ PROCESS_QUERY_INFORMATION = 0x00000400
+ SYNCHRONIZE = 0x00100000
+
+ PAGE_READONLY = 0x02
+ PAGE_READWRITE = 0x04
+ PAGE_WRITECOPY = 0x08
+ PAGE_EXECUTE_READ = 0x20
+ PAGE_EXECUTE_READWRITE = 0x40
+ PAGE_EXECUTE_WRITECOPY = 0x80
+
+ FILE_MAP_COPY = 0x01
+ FILE_MAP_WRITE = 0x02
+ FILE_MAP_READ = 0x04
+ FILE_MAP_EXECUTE = 0x20
+
+ CTRL_C_EVENT = 0
+ CTRL_BREAK_EVENT = 1
+
+ // Windows reserves errors >= 1<<29 for application use.
+ APPLICATION_ERROR = 1 << 29
+)
+
+const (
+ // flags for CreateToolhelp32Snapshot
+ TH32CS_SNAPHEAPLIST = 0x01
+ TH32CS_SNAPPROCESS = 0x02
+ TH32CS_SNAPTHREAD = 0x04
+ TH32CS_SNAPMODULE = 0x08
+ TH32CS_SNAPMODULE32 = 0x10
+ TH32CS_SNAPALL = TH32CS_SNAPHEAPLIST | TH32CS_SNAPMODULE | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD
+ TH32CS_INHERIT = 0x80000000
+)
+
+const (
+ // filters for ReadDirectoryChangesW
+ FILE_NOTIFY_CHANGE_FILE_NAME = 0x001
+ FILE_NOTIFY_CHANGE_DIR_NAME = 0x002
+ FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x004
+ FILE_NOTIFY_CHANGE_SIZE = 0x008
+ FILE_NOTIFY_CHANGE_LAST_WRITE = 0x010
+ FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x020
+ FILE_NOTIFY_CHANGE_CREATION = 0x040
+ FILE_NOTIFY_CHANGE_SECURITY = 0x100
+)
+
+const (
+ // do not reorder
+ FILE_ACTION_ADDED = iota + 1
+ FILE_ACTION_REMOVED
+ FILE_ACTION_MODIFIED
+ FILE_ACTION_RENAMED_OLD_NAME
+ FILE_ACTION_RENAMED_NEW_NAME
+)
+
+const (
+ // wincrypt.h
+ PROV_RSA_FULL = 1
+ PROV_RSA_SIG = 2
+ PROV_DSS = 3
+ PROV_FORTEZZA = 4
+ PROV_MS_EXCHANGE = 5
+ PROV_SSL = 6
+ PROV_RSA_SCHANNEL = 12
+ PROV_DSS_DH = 13
+ PROV_EC_ECDSA_SIG = 14
+ PROV_EC_ECNRA_SIG = 15
+ PROV_EC_ECDSA_FULL = 16
+ PROV_EC_ECNRA_FULL = 17
+ PROV_DH_SCHANNEL = 18
+ PROV_SPYRUS_LYNKS = 20
+ PROV_RNG = 21
+ PROV_INTEL_SEC = 22
+ PROV_REPLACE_OWF = 23
+ PROV_RSA_AES = 24
+ CRYPT_VERIFYCONTEXT = 0xF0000000
+ CRYPT_NEWKEYSET = 0x00000008
+ CRYPT_DELETEKEYSET = 0x00000010
+ CRYPT_MACHINE_KEYSET = 0x00000020
+ CRYPT_SILENT = 0x00000040
+ CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080
+
+ USAGE_MATCH_TYPE_AND = 0
+ USAGE_MATCH_TYPE_OR = 1
+
+ X509_ASN_ENCODING = 0x00000001
+ PKCS_7_ASN_ENCODING = 0x00010000
+
+ CERT_STORE_PROV_MEMORY = 2
+
+ CERT_STORE_ADD_ALWAYS = 4
+
+ CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG = 0x00000004
+
+ CERT_TRUST_NO_ERROR = 0x00000000
+ CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001
+ CERT_TRUST_IS_REVOKED = 0x00000004
+ CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008
+ CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010
+ CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020
+ CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040
+ CERT_TRUST_IS_CYCLIC = 0x00000080
+ CERT_TRUST_INVALID_EXTENSION = 0x00000100
+ CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200
+ CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400
+ CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800
+ CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000
+ CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000
+ CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000
+ CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000
+ CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000
+ CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000
+ CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000
+ CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000
+
+ CERT_CHAIN_POLICY_BASE = 1
+ CERT_CHAIN_POLICY_AUTHENTICODE = 2
+ CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3
+ CERT_CHAIN_POLICY_SSL = 4
+ CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5
+ CERT_CHAIN_POLICY_NT_AUTH = 6
+ CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7
+ CERT_CHAIN_POLICY_EV = 8
+
+ CERT_E_EXPIRED = 0x800B0101
+ CERT_E_ROLE = 0x800B0103
+ CERT_E_PURPOSE = 0x800B0106
+ CERT_E_UNTRUSTEDROOT = 0x800B0109
+ CERT_E_CN_NO_MATCH = 0x800B010F
+
+ AUTHTYPE_CLIENT = 1
+ AUTHTYPE_SERVER = 2
+)
+
+var (
+ OID_PKIX_KP_SERVER_AUTH = []byte("1.3.6.1.5.5.7.3.1\x00")
+ OID_SERVER_GATED_CRYPTO = []byte("1.3.6.1.4.1.311.10.3.3\x00")
+ OID_SGC_NETSCAPE = []byte("2.16.840.1.113730.4.1\x00")
+)
+
+// Invented values to support what package os expects.
+type Timeval struct {
+ Sec int32
+ Usec int32
+}
+
+func (tv *Timeval) Nanoseconds() int64 {
+ return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ tv.Sec = int32(nsec / 1e9)
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ return
+}
+
+type SecurityAttributes struct {
+ Length uint32
+ SecurityDescriptor uintptr
+ InheritHandle uint32
+}
+
+type Overlapped struct {
+ Internal uintptr
+ InternalHigh uintptr
+ Offset uint32
+ OffsetHigh uint32
+ HEvent Handle
+}
+
+type FileNotifyInformation struct {
+ NextEntryOffset uint32
+ Action uint32
+ FileNameLength uint32
+ FileName uint16
+}
+
+type Filetime struct {
+ LowDateTime uint32
+ HighDateTime uint32
+}
+
+// Nanoseconds returns Filetime ft in nanoseconds
+// since Epoch (00:00:00 UTC, January 1, 1970).
+func (ft *Filetime) Nanoseconds() int64 {
+ // 100-nanosecond intervals since January 1, 1601
+ nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
+ // change starting time to the Epoch (00:00:00 UTC, January 1, 1970)
+ nsec -= 116444736000000000
+ // convert into nanoseconds
+ nsec *= 100
+ return nsec
+}
+
+func NsecToFiletime(nsec int64) (ft Filetime) {
+ // convert into 100-nanosecond
+ nsec /= 100
+ // change starting time to January 1, 1601
+ nsec += 116444736000000000
+ // split into high / low
+ ft.LowDateTime = uint32(nsec & 0xffffffff)
+ ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff)
+ return ft
+}
+
+type Win32finddata struct {
+ FileAttributes uint32
+ CreationTime Filetime
+ LastAccessTime Filetime
+ LastWriteTime Filetime
+ FileSizeHigh uint32
+ FileSizeLow uint32
+ Reserved0 uint32
+ Reserved1 uint32
+ FileName [MAX_PATH - 1]uint16
+ AlternateFileName [13]uint16
+}
+
+// This is the actual system call structure.
+// Win32finddata is what we committed to in Go 1.
+type win32finddata1 struct {
+ FileAttributes uint32
+ CreationTime Filetime
+ LastAccessTime Filetime
+ LastWriteTime Filetime
+ FileSizeHigh uint32
+ FileSizeLow uint32
+ Reserved0 uint32
+ Reserved1 uint32
+ FileName [MAX_PATH]uint16
+ AlternateFileName [14]uint16
+}
+
+func copyFindData(dst *Win32finddata, src *win32finddata1) {
+ dst.FileAttributes = src.FileAttributes
+ dst.CreationTime = src.CreationTime
+ dst.LastAccessTime = src.LastAccessTime
+ dst.LastWriteTime = src.LastWriteTime
+ dst.FileSizeHigh = src.FileSizeHigh
+ dst.FileSizeLow = src.FileSizeLow
+ dst.Reserved0 = src.Reserved0
+ dst.Reserved1 = src.Reserved1
+
+ // The src is 1 element bigger than dst, but it must be NUL.
+ copy(dst.FileName[:], src.FileName[:])
+ copy(dst.AlternateFileName[:], src.AlternateFileName[:])
+}
+
+type ByHandleFileInformation struct {
+ FileAttributes uint32
+ CreationTime Filetime
+ LastAccessTime Filetime
+ LastWriteTime Filetime
+ VolumeSerialNumber uint32
+ FileSizeHigh uint32
+ FileSizeLow uint32
+ NumberOfLinks uint32
+ FileIndexHigh uint32
+ FileIndexLow uint32
+}
+
+const (
+ GetFileExInfoStandard = 0
+ GetFileExMaxInfoLevel = 1
+)
+
+type Win32FileAttributeData struct {
+ FileAttributes uint32
+ CreationTime Filetime
+ LastAccessTime Filetime
+ LastWriteTime Filetime
+ FileSizeHigh uint32
+ FileSizeLow uint32
+}
+
+// ShowWindow constants
+const (
+ // winuser.h
+ SW_HIDE = 0
+ SW_NORMAL = 1
+ SW_SHOWNORMAL = 1
+ SW_SHOWMINIMIZED = 2
+ SW_SHOWMAXIMIZED = 3
+ SW_MAXIMIZE = 3
+ SW_SHOWNOACTIVATE = 4
+ SW_SHOW = 5
+ SW_MINIMIZE = 6
+ SW_SHOWMINNOACTIVE = 7
+ SW_SHOWNA = 8
+ SW_RESTORE = 9
+ SW_SHOWDEFAULT = 10
+ SW_FORCEMINIMIZE = 11
+)
+
+type StartupInfo struct {
+ Cb uint32
+ _ *uint16
+ Desktop *uint16
+ Title *uint16
+ X uint32
+ Y uint32
+ XSize uint32
+ YSize uint32
+ XCountChars uint32
+ YCountChars uint32
+ FillAttribute uint32
+ Flags uint32
+ ShowWindow uint16
+ _ uint16
+ _ *byte
+ StdInput Handle
+ StdOutput Handle
+ StdErr Handle
+}
+
+type ProcessInformation struct {
+ Process Handle
+ Thread Handle
+ ProcessId uint32
+ ThreadId uint32
+}
+
+type ProcessEntry32 struct {
+ Size uint32
+ Usage uint32
+ ProcessID uint32
+ DefaultHeapID uintptr
+ ModuleID uint32
+ Threads uint32
+ ParentProcessID uint32
+ PriClassBase int32
+ Flags uint32
+ ExeFile [MAX_PATH]uint16
+}
+
+type Systemtime struct {
+ Year uint16
+ Month uint16
+ DayOfWeek uint16
+ Day uint16
+ Hour uint16
+ Minute uint16
+ Second uint16
+ Milliseconds uint16
+}
+
+type Timezoneinformation struct {
+ Bias int32
+ StandardName [32]uint16
+ StandardDate Systemtime
+ StandardBias int32
+ DaylightName [32]uint16
+ DaylightDate Systemtime
+ DaylightBias int32
+}
+
+// Socket related.
+
+const (
+ AF_UNSPEC = 0
+ AF_UNIX = 1
+ AF_INET = 2
+ AF_INET6 = 23
+ AF_NETBIOS = 17
+
+ SOCK_STREAM = 1
+ SOCK_DGRAM = 2
+ SOCK_RAW = 3
+ SOCK_SEQPACKET = 5
+
+ IPPROTO_IP = 0
+ IPPROTO_IPV6 = 0x29
+ IPPROTO_TCP = 6
+ IPPROTO_UDP = 17
+
+ SOL_SOCKET = 0xffff
+ SO_REUSEADDR = 4
+ SO_KEEPALIVE = 8
+ SO_DONTROUTE = 16
+ SO_BROADCAST = 32
+ SO_LINGER = 128
+ SO_RCVBUF = 0x1002
+ SO_SNDBUF = 0x1001
+ SO_UPDATE_ACCEPT_CONTEXT = 0x700b
+ SO_UPDATE_CONNECT_CONTEXT = 0x7010
+
+ IOC_OUT = 0x40000000
+ IOC_IN = 0x80000000
+ IOC_VENDOR = 0x18000000
+ IOC_INOUT = IOC_IN | IOC_OUT
+ IOC_WS2 = 0x08000000
+ SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6
+ SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4
+ SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12
+
+ // cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
+
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_LOOP = 0xb
+ IP_ADD_MEMBERSHIP = 0xc
+ IP_DROP_MEMBERSHIP = 0xd
+
+ IPV6_V6ONLY = 0x1b
+ IPV6_UNICAST_HOPS = 0x4
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+
+ SOMAXCONN = 0x7fffffff
+
+ TCP_NODELAY = 1
+
+ SHUT_RD = 0
+ SHUT_WR = 1
+ SHUT_RDWR = 2
+
+ WSADESCRIPTION_LEN = 256
+ WSASYS_STATUS_LEN = 128
+)
+
+type WSABuf struct {
+ Len uint32
+ Buf *byte
+}
+
+// Invented values to support what package os expects.
+const (
+ S_IFMT = 0x1f000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+ S_ISUID = 0x800
+ S_ISGID = 0x400
+ S_ISVTX = 0x200
+ S_IRUSR = 0x100
+ S_IWRITE = 0x80
+ S_IWUSR = 0x80
+ S_IXUSR = 0x40
+)
+
+const (
+ FILE_TYPE_CHAR = 0x0002
+ FILE_TYPE_DISK = 0x0001
+ FILE_TYPE_PIPE = 0x0003
+ FILE_TYPE_REMOTE = 0x8000
+ FILE_TYPE_UNKNOWN = 0x0000
+)
+
+type Hostent struct {
+ Name *byte
+ Aliases **byte
+ AddrType uint16
+ Length uint16
+ AddrList **byte
+}
+
+type Protoent struct {
+ Name *byte
+ Aliases **byte
+ Proto uint16
+}
+
+const (
+ DNS_TYPE_A = 0x0001
+ DNS_TYPE_NS = 0x0002
+ DNS_TYPE_MD = 0x0003
+ DNS_TYPE_MF = 0x0004
+ DNS_TYPE_CNAME = 0x0005
+ DNS_TYPE_SOA = 0x0006
+ DNS_TYPE_MB = 0x0007
+ DNS_TYPE_MG = 0x0008
+ DNS_TYPE_MR = 0x0009
+ DNS_TYPE_NULL = 0x000a
+ DNS_TYPE_WKS = 0x000b
+ DNS_TYPE_PTR = 0x000c
+ DNS_TYPE_HINFO = 0x000d
+ DNS_TYPE_MINFO = 0x000e
+ DNS_TYPE_MX = 0x000f
+ DNS_TYPE_TEXT = 0x0010
+ DNS_TYPE_RP = 0x0011
+ DNS_TYPE_AFSDB = 0x0012
+ DNS_TYPE_X25 = 0x0013
+ DNS_TYPE_ISDN = 0x0014
+ DNS_TYPE_RT = 0x0015
+ DNS_TYPE_NSAP = 0x0016
+ DNS_TYPE_NSAPPTR = 0x0017
+ DNS_TYPE_SIG = 0x0018
+ DNS_TYPE_KEY = 0x0019
+ DNS_TYPE_PX = 0x001a
+ DNS_TYPE_GPOS = 0x001b
+ DNS_TYPE_AAAA = 0x001c
+ DNS_TYPE_LOC = 0x001d
+ DNS_TYPE_NXT = 0x001e
+ DNS_TYPE_EID = 0x001f
+ DNS_TYPE_NIMLOC = 0x0020
+ DNS_TYPE_SRV = 0x0021
+ DNS_TYPE_ATMA = 0x0022
+ DNS_TYPE_NAPTR = 0x0023
+ DNS_TYPE_KX = 0x0024
+ DNS_TYPE_CERT = 0x0025
+ DNS_TYPE_A6 = 0x0026
+ DNS_TYPE_DNAME = 0x0027
+ DNS_TYPE_SINK = 0x0028
+ DNS_TYPE_OPT = 0x0029
+ DNS_TYPE_DS = 0x002B
+ DNS_TYPE_RRSIG = 0x002E
+ DNS_TYPE_NSEC = 0x002F
+ DNS_TYPE_DNSKEY = 0x0030
+ DNS_TYPE_DHCID = 0x0031
+ DNS_TYPE_UINFO = 0x0064
+ DNS_TYPE_UID = 0x0065
+ DNS_TYPE_GID = 0x0066
+ DNS_TYPE_UNSPEC = 0x0067
+ DNS_TYPE_ADDRS = 0x00f8
+ DNS_TYPE_TKEY = 0x00f9
+ DNS_TYPE_TSIG = 0x00fa
+ DNS_TYPE_IXFR = 0x00fb
+ DNS_TYPE_AXFR = 0x00fc
+ DNS_TYPE_MAILB = 0x00fd
+ DNS_TYPE_MAILA = 0x00fe
+ DNS_TYPE_ALL = 0x00ff
+ DNS_TYPE_ANY = 0x00ff
+ DNS_TYPE_WINS = 0xff01
+ DNS_TYPE_WINSR = 0xff02
+ DNS_TYPE_NBSTAT = 0xff01
+)
+
+const (
+ DNS_INFO_NO_RECORDS = 0x251D
+)
+
+const (
+ // flags inside DNSRecord.Dw
+ DnsSectionQuestion = 0x0000
+ DnsSectionAnswer = 0x0001
+ DnsSectionAuthority = 0x0002
+ DnsSectionAdditional = 0x0003
+)
+
+type DNSSRVData struct {
+ Target *uint16
+ Priority uint16
+ Weight uint16
+ Port uint16
+ Pad uint16
+}
+
+type DNSPTRData struct {
+ Host *uint16
+}
+
+type DNSMXData struct {
+ NameExchange *uint16
+ Preference uint16
+ Pad uint16
+}
+
+type DNSTXTData struct {
+ StringCount uint16
+ StringArray [1]*uint16
+}
+
+type DNSRecord struct {
+ Next *DNSRecord
+ Name *uint16
+ Type uint16
+ Length uint16
+ Dw uint32
+ Ttl uint32
+ Reserved uint32
+ Data [40]byte
+}
+
+const (
+ TF_DISCONNECT = 1
+ TF_REUSE_SOCKET = 2
+ TF_WRITE_BEHIND = 4
+ TF_USE_DEFAULT_WORKER = 0
+ TF_USE_SYSTEM_THREAD = 16
+ TF_USE_KERNEL_APC = 32
+)
+
+type TransmitFileBuffers struct {
+ Head uintptr
+ HeadLength uint32
+ Tail uintptr
+ TailLength uint32
+}
+
+const (
+ IFF_UP = 1
+ IFF_BROADCAST = 2
+ IFF_LOOPBACK = 4
+ IFF_POINTTOPOINT = 8
+ IFF_MULTICAST = 16
+)
+
+const SIO_GET_INTERFACE_LIST = 0x4004747F
+
+// TODO(mattn): SockaddrGen is union of sockaddr/sockaddr_in/sockaddr_in6_old.
+// will be fixed to change variable type as suitable.
+
+type SockaddrGen [24]byte
+
+type InterfaceInfo struct {
+ Flags uint32
+ Address SockaddrGen
+ BroadcastAddress SockaddrGen
+ Netmask SockaddrGen
+}
+
+type IpAddressString struct {
+ String [16]byte
+}
+
+type IpMaskString IpAddressString
+
+type IpAddrString struct {
+ Next *IpAddrString
+ IpAddress IpAddressString
+ IpMask IpMaskString
+ Context uint32
+}
+
+const MAX_ADAPTER_NAME_LENGTH = 256
+const MAX_ADAPTER_DESCRIPTION_LENGTH = 128
+const MAX_ADAPTER_ADDRESS_LENGTH = 8
+
+type IpAdapterInfo struct {
+ Next *IpAdapterInfo
+ ComboIndex uint32
+ AdapterName [MAX_ADAPTER_NAME_LENGTH + 4]byte
+ Description [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte
+ AddressLength uint32
+ Address [MAX_ADAPTER_ADDRESS_LENGTH]byte
+ Index uint32
+ Type uint32
+ DhcpEnabled uint32
+ CurrentIpAddress *IpAddrString
+ IpAddressList IpAddrString
+ GatewayList IpAddrString
+ DhcpServer IpAddrString
+ HaveWins bool
+ PrimaryWinsServer IpAddrString
+ SecondaryWinsServer IpAddrString
+ LeaseObtained int64
+ LeaseExpires int64
+}
+
+const MAXLEN_PHYSADDR = 8
+const MAX_INTERFACE_NAME_LEN = 256
+const MAXLEN_IFDESCR = 256
+
+type MibIfRow struct {
+ Name [MAX_INTERFACE_NAME_LEN]uint16
+ Index uint32
+ Type uint32
+ Mtu uint32
+ Speed uint32
+ PhysAddrLen uint32
+ PhysAddr [MAXLEN_PHYSADDR]byte
+ AdminStatus uint32
+ OperStatus uint32
+ LastChange uint32
+ InOctets uint32
+ InUcastPkts uint32
+ InNUcastPkts uint32
+ InDiscards uint32
+ InErrors uint32
+ InUnknownProtos uint32
+ OutOctets uint32
+ OutUcastPkts uint32
+ OutNUcastPkts uint32
+ OutDiscards uint32
+ OutErrors uint32
+ OutQLen uint32
+ DescrLen uint32
+ Descr [MAXLEN_IFDESCR]byte
+}
+
+type CertContext struct {
+ EncodingType uint32
+ EncodedCert *byte
+ Length uint32
+ CertInfo uintptr
+ Store Handle
+}
+
+type CertChainContext struct {
+ Size uint32
+ TrustStatus CertTrustStatus
+ ChainCount uint32
+ Chains **CertSimpleChain
+ LowerQualityChainCount uint32
+ LowerQualityChains **CertChainContext
+ HasRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+}
+
+type CertSimpleChain struct {
+ Size uint32
+ TrustStatus CertTrustStatus
+ NumElements uint32
+ Elements **CertChainElement
+ TrustListInfo uintptr
+ HasRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+}
+
+type CertChainElement struct {
+ Size uint32
+ CertContext *CertContext
+ TrustStatus CertTrustStatus
+ RevocationInfo *CertRevocationInfo
+ IssuanceUsage *CertEnhKeyUsage
+ ApplicationUsage *CertEnhKeyUsage
+ ExtendedErrorInfo *uint16
+}
+
+type CertRevocationInfo struct {
+ Size uint32
+ RevocationResult uint32
+ RevocationOid *byte
+ OidSpecificInfo uintptr
+ HasFreshnessTime uint32
+ FreshnessTime uint32
+ CrlInfo uintptr // *CertRevocationCrlInfo
+}
+
+type CertTrustStatus struct {
+ ErrorStatus uint32
+ InfoStatus uint32
+}
+
+type CertUsageMatch struct {
+ Type uint32
+ Usage CertEnhKeyUsage
+}
+
+type CertEnhKeyUsage struct {
+ Length uint32
+ UsageIdentifiers **byte
+}
+
+type CertChainPara struct {
+ Size uint32
+ RequestedUsage CertUsageMatch
+ RequstedIssuancePolicy CertUsageMatch
+ URLRetrievalTimeout uint32
+ CheckRevocationFreshnessTime uint32
+ RevocationFreshnessTime uint32
+ CacheResync *Filetime
+}
+
+type CertChainPolicyPara struct {
+ Size uint32
+ Flags uint32
+ ExtraPolicyPara uintptr
+}
+
+type SSLExtraCertChainPolicyPara struct {
+ Size uint32
+ AuthType uint32
+ Checks uint32
+ ServerName *uint16
+}
+
+type CertChainPolicyStatus struct {
+ Size uint32
+ Error uint32
+ ChainIndex uint32
+ ElementIndex uint32
+ ExtraPolicyStatus uintptr
+}
+
+const (
+ // do not reorder
+ HKEY_CLASSES_ROOT = 0x80000000 + iota
+ HKEY_CURRENT_USER
+ HKEY_LOCAL_MACHINE
+ HKEY_USERS
+ HKEY_PERFORMANCE_DATA
+ HKEY_CURRENT_CONFIG
+ HKEY_DYN_DATA
+
+ KEY_QUERY_VALUE = 1
+ KEY_SET_VALUE = 2
+ KEY_CREATE_SUB_KEY = 4
+ KEY_ENUMERATE_SUB_KEYS = 8
+ KEY_NOTIFY = 16
+ KEY_CREATE_LINK = 32
+ KEY_WRITE = 0x20006
+ KEY_EXECUTE = 0x20019
+ KEY_READ = 0x20019
+ KEY_WOW64_64KEY = 0x0100
+ KEY_WOW64_32KEY = 0x0200
+ KEY_ALL_ACCESS = 0xf003f
+)
+
+const (
+ // do not reorder
+ REG_NONE = iota
+ REG_SZ
+ REG_EXPAND_SZ
+ REG_BINARY
+ REG_DWORD_LITTLE_ENDIAN
+ REG_DWORD_BIG_ENDIAN
+ REG_LINK
+ REG_MULTI_SZ
+ REG_RESOURCE_LIST
+ REG_FULL_RESOURCE_DESCRIPTOR
+ REG_RESOURCE_REQUIREMENTS_LIST
+ REG_QWORD_LITTLE_ENDIAN
+ REG_DWORD = REG_DWORD_LITTLE_ENDIAN
+ REG_QWORD = REG_QWORD_LITTLE_ENDIAN
+)
+
+type AddrinfoW struct {
+ Flags int32
+ Family int32
+ Socktype int32
+ Protocol int32
+ Addrlen uintptr
+ Canonname *uint16
+ Addr uintptr
+ Next *AddrinfoW
+}
+
+const (
+ AI_PASSIVE = 1
+ AI_CANONNAME = 2
+ AI_NUMERICHOST = 4
+)
+
+type GUID struct {
+ Data1 uint32
+ Data2 uint16
+ Data3 uint16
+ Data4 [8]byte
+}
+
+var WSAID_CONNECTEX = GUID{
+ 0x25a207b9,
+ 0xddf3,
+ 0x4660,
+ [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
+}
+
+const (
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
+ FILE_SKIP_SET_EVENT_ON_HANDLE = 2
+)
+
+const (
+ WSAPROTOCOL_LEN = 255
+ MAX_PROTOCOL_CHAIN = 7
+ BASE_PROTOCOL = 1
+ LAYERED_PROTOCOL = 0
+
+ XP1_CONNECTIONLESS = 0x00000001
+ XP1_GUARANTEED_DELIVERY = 0x00000002
+ XP1_GUARANTEED_ORDER = 0x00000004
+ XP1_MESSAGE_ORIENTED = 0x00000008
+ XP1_PSEUDO_STREAM = 0x00000010
+ XP1_GRACEFUL_CLOSE = 0x00000020
+ XP1_EXPEDITED_DATA = 0x00000040
+ XP1_CONNECT_DATA = 0x00000080
+ XP1_DISCONNECT_DATA = 0x00000100
+ XP1_SUPPORT_BROADCAST = 0x00000200
+ XP1_SUPPORT_MULTIPOINT = 0x00000400
+ XP1_MULTIPOINT_CONTROL_PLANE = 0x00000800
+ XP1_MULTIPOINT_DATA_PLANE = 0x00001000
+ XP1_QOS_SUPPORTED = 0x00002000
+ XP1_UNI_SEND = 0x00008000
+ XP1_UNI_RECV = 0x00010000
+ XP1_IFS_HANDLES = 0x00020000
+ XP1_PARTIAL_MESSAGE = 0x00040000
+ XP1_SAN_SUPPORT_SDP = 0x00080000
+
+ PFL_MULTIPLE_PROTO_ENTRIES = 0x00000001
+ PFL_RECOMMENDED_PROTO_ENTRY = 0x00000002
+ PFL_HIDDEN = 0x00000004
+ PFL_MATCHES_PROTOCOL_ZERO = 0x00000008
+ PFL_NETWORKDIRECT_PROVIDER = 0x00000010
+)
+
+type WSAProtocolInfo struct {
+ ServiceFlags1 uint32
+ ServiceFlags2 uint32
+ ServiceFlags3 uint32
+ ServiceFlags4 uint32
+ ProviderFlags uint32
+ ProviderId GUID
+ CatalogEntryId uint32
+ ProtocolChain WSAProtocolChain
+ Version int32
+ AddressFamily int32
+ MaxSockAddr int32
+ MinSockAddr int32
+ SocketType int32
+ Protocol int32
+ ProtocolMaxOffset int32
+ NetworkByteOrder int32
+ SecurityScheme int32
+ MessageSize uint32
+ ProviderReserved uint32
+ ProtocolName [WSAPROTOCOL_LEN + 1]uint16
+}
+
+type WSAProtocolChain struct {
+ ChainLen int32
+ ChainEntries [MAX_PROTOCOL_CHAIN]uint32
+}
+
+type TCPKeepalive struct {
+ OnOff uint32
+ Time uint32
+ Interval uint32
+}
+
+type symbolicLinkReparseBuffer struct {
+ SubstituteNameOffset uint16
+ SubstituteNameLength uint16
+ PrintNameOffset uint16
+ PrintNameLength uint16
+ Flags uint32
+ PathBuffer [1]uint16
+}
+
+type mountPointReparseBuffer struct {
+ SubstituteNameOffset uint16
+ SubstituteNameLength uint16
+ PrintNameOffset uint16
+ PrintNameLength uint16
+ PathBuffer [1]uint16
+}
+
+type reparseDataBuffer struct {
+ ReparseTag uint32
+ ReparseDataLength uint16
+ Reserved uint16
+
+ // GenericReparseBuffer
+ reparseBuffer byte
+}
+
+const (
+ FSCTL_GET_REPARSE_POINT = 0x900A8
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024
+ IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
+ IO_REPARSE_TAG_SYMLINK = 0xA000000C
+ SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
+)
+
+const (
+ ComputerNameNetBIOS = 0
+ ComputerNameDnsHostname = 1
+ ComputerNameDnsDomain = 2
+ ComputerNameDnsFullyQualified = 3
+ ComputerNamePhysicalNetBIOS = 4
+ ComputerNamePhysicalDnsHostname = 5
+ ComputerNamePhysicalDnsDomain = 6
+ ComputerNamePhysicalDnsFullyQualified = 7
+ ComputerNameMax = 8
+)
+
+const (
+ MOVEFILE_REPLACE_EXISTING = 0x1
+ MOVEFILE_COPY_ALLOWED = 0x2
+ MOVEFILE_DELAY_UNTIL_REBOOT = 0x4
+ MOVEFILE_WRITE_THROUGH = 0x8
+ MOVEFILE_CREATE_HARDLINK = 0x10
+ MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20
+)
+
+const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
+
+const (
+ IF_TYPE_OTHER = 1
+ IF_TYPE_ETHERNET_CSMACD = 6
+ IF_TYPE_ISO88025_TOKENRING = 9
+ IF_TYPE_PPP = 23
+ IF_TYPE_SOFTWARE_LOOPBACK = 24
+ IF_TYPE_ATM = 37
+ IF_TYPE_IEEE80211 = 71
+ IF_TYPE_TUNNEL = 131
+ IF_TYPE_IEEE1394 = 144
+)
+
+type SocketAddress struct {
+ Sockaddr *syscall.RawSockaddrAny
+ SockaddrLength int32
+}
+
+type IpAdapterUnicastAddress struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterUnicastAddress
+ Address SocketAddress
+ PrefixOrigin int32
+ SuffixOrigin int32
+ DadState int32
+ ValidLifetime uint32
+ PreferredLifetime uint32
+ LeaseLifetime uint32
+ OnLinkPrefixLength uint8
+}
+
+type IpAdapterAnycastAddress struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterAnycastAddress
+ Address SocketAddress
+}
+
+type IpAdapterMulticastAddress struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterMulticastAddress
+ Address SocketAddress
+}
+
+type IpAdapterDnsServerAdapter struct {
+ Length uint32
+ Reserved uint32
+ Next *IpAdapterDnsServerAdapter
+ Address SocketAddress
+}
+
+type IpAdapterPrefix struct {
+ Length uint32
+ Flags uint32
+ Next *IpAdapterPrefix
+ Address SocketAddress
+ PrefixLength uint32
+}
+
+type IpAdapterAddresses struct {
+ Length uint32
+ IfIndex uint32
+ Next *IpAdapterAddresses
+ AdapterName *byte
+ FirstUnicastAddress *IpAdapterUnicastAddress
+ FirstAnycastAddress *IpAdapterAnycastAddress
+ FirstMulticastAddress *IpAdapterMulticastAddress
+ FirstDnsServerAddress *IpAdapterDnsServerAdapter
+ DnsSuffix *uint16
+ Description *uint16
+ FriendlyName *uint16
+ PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte
+ PhysicalAddressLength uint32
+ Flags uint32
+ Mtu uint32
+ IfType uint32
+ OperStatus uint32
+ Ipv6IfIndex uint32
+ ZoneIndices [16]uint32
+ FirstPrefix *IpAdapterPrefix
+ /* more fields might be present here. */
+}
+
+const (
+ IfOperStatusUp = 1
+ IfOperStatusDown = 2
+ IfOperStatusTesting = 3
+ IfOperStatusUnknown = 4
+ IfOperStatusDormant = 5
+ IfOperStatusNotPresent = 6
+ IfOperStatusLowerLayerDown = 7
+)
diff --git a/vendor/golang.org/x/sys/windows/ztypes_windows_386.go b/vendor/golang.org/x/sys/windows/ztypes_windows_386.go
new file mode 100644
index 000000000..10f33be0b
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/ztypes_windows_386.go
@@ -0,0 +1,22 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+type WSAData struct {
+ Version uint16
+ HighVersion uint16
+ Description [WSADESCRIPTION_LEN + 1]byte
+ SystemStatus [WSASYS_STATUS_LEN + 1]byte
+ MaxSockets uint16
+ MaxUdpDg uint16
+ VendorInfo *byte
+}
+
+type Servent struct {
+ Name *byte
+ Aliases **byte
+ Port uint16
+ Proto *byte
+}
diff --git a/vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go b/vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go
new file mode 100644
index 000000000..3f272c249
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/ztypes_windows_amd64.go
@@ -0,0 +1,22 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package windows
+
+type WSAData struct {
+ Version uint16
+ HighVersion uint16
+ MaxSockets uint16
+ MaxUdpDg uint16
+ VendorInfo *byte
+ Description [WSADESCRIPTION_LEN + 1]byte
+ SystemStatus [WSASYS_STATUS_LEN + 1]byte
+}
+
+type Servent struct {
+ Name *byte
+ Aliases **byte
+ Proto *byte
+ Port uint16
+}
diff --git a/vendor/gopkg.in/asn1-ber.v1/ber_test.go b/vendor/gopkg.in/asn1-ber.v1/ber_test.go
new file mode 100644
index 000000000..bbd22db6d
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/ber_test.go
@@ -0,0 +1,168 @@
+package ber
+
+import (
+ "bytes"
+ "math"
+
+ "io"
+ "testing"
+)
+
+func TestEncodeDecodeInteger(t *testing.T) {
+ for _, v := range []int64{0, 10, 128, 1024, math.MaxInt64, -1, -100, -128, -1024, math.MinInt64} {
+ enc := encodeInteger(v)
+ dec, err := parseInt64(enc)
+ if err != nil {
+ t.Fatalf("Error decoding %d : %s", v, err)
+ }
+ if v != dec {
+ t.Error("TestEncodeDecodeInteger failed for %d (got %d)", v, dec)
+ }
+
+ }
+}
+
+func TestBoolean(t *testing.T) {
+ var value bool = true
+
+ packet := NewBoolean(ClassUniversal, TypePrimitive, TagBoolean, value, "first Packet, True")
+
+ newBoolean, ok := packet.Value.(bool)
+ if !ok || newBoolean != value {
+ t.Error("error during creating packet")
+ }
+
+ encodedPacket := packet.Bytes()
+
+ newPacket := DecodePacket(encodedPacket)
+
+ newBoolean, ok = newPacket.Value.(bool)
+ if !ok || newBoolean != value {
+ t.Error("error during decoding packet")
+ }
+
+}
+
+func TestInteger(t *testing.T) {
+ var value int64 = 10
+
+ packet := NewInteger(ClassUniversal, TypePrimitive, TagInteger, value, "Integer, 10")
+
+ {
+ newInteger, ok := packet.Value.(int64)
+ if !ok || newInteger != value {
+ t.Error("error creating packet")
+ }
+ }
+
+ encodedPacket := packet.Bytes()
+
+ newPacket := DecodePacket(encodedPacket)
+
+ {
+ newInteger, ok := newPacket.Value.(int64)
+ if !ok || int64(newInteger) != value {
+ t.Error("error decoding packet")
+ }
+ }
+}
+
+func TestString(t *testing.T) {
+ var value string = "Hic sunt dracones"
+
+ packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, value, "String")
+
+ newValue, ok := packet.Value.(string)
+ if !ok || newValue != value {
+ t.Error("error during creating packet")
+ }
+
+ encodedPacket := packet.Bytes()
+
+ newPacket := DecodePacket(encodedPacket)
+
+ newValue, ok = newPacket.Value.(string)
+ if !ok || newValue != value {
+ t.Error("error during decoding packet")
+ }
+
+}
+
+func TestSequenceAndAppendChild(t *testing.T) {
+
+ values := []string{
+ "HIC SVNT LEONES",
+ "Iñtërnâtiônàlizætiøn",
+ "Terra Incognita",
+ }
+
+ sequence := NewSequence("a sequence")
+ for _, s := range values {
+ sequence.AppendChild(NewString(ClassUniversal, TypePrimitive, TagOctetString, s, "String"))
+ }
+
+ if len(sequence.Children) != len(values) {
+ t.Errorf("wrong length for children array should be %d, got %d", len(values), len(sequence.Children))
+ }
+
+ encodedSequence := sequence.Bytes()
+
+ decodedSequence := DecodePacket(encodedSequence)
+ if len(decodedSequence.Children) != len(values) {
+ t.Errorf("wrong length for children array should be %d => %d", len(values), len(decodedSequence.Children))
+ }
+
+ for i, s := range values {
+ if decodedSequence.Children[i].Value.(string) != s {
+ t.Errorf("expected %d to be %q, got %q", i, s, decodedSequence.Children[i].Value.(string))
+ }
+ }
+}
+
+func TestReadPacket(t *testing.T) {
+ packet := NewString(ClassUniversal, TypePrimitive, TagOctetString, "Ad impossibilia nemo tenetur", "string")
+ var buffer io.ReadWriter
+ buffer = new(bytes.Buffer)
+
+ buffer.Write(packet.Bytes())
+
+ newPacket, err := ReadPacket(buffer)
+ if err != nil {
+ t.Error("error during ReadPacket", err)
+ }
+ newPacket.ByteValue = nil
+ if !bytes.Equal(newPacket.ByteValue, packet.ByteValue) {
+ t.Error("packets should be the same")
+ }
+}
+
+func TestBinaryInteger(t *testing.T) {
+ // data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.7
+ var data = []struct {
+ v int64
+ e []byte
+ }{
+ {v: 0, e: []byte{0x02, 0x01, 0x00}},
+ {v: 127, e: []byte{0x02, 0x01, 0x7F}},
+ {v: 128, e: []byte{0x02, 0x02, 0x00, 0x80}},
+ {v: 256, e: []byte{0x02, 0x02, 0x01, 0x00}},
+ {v: -128, e: []byte{0x02, 0x01, 0x80}},
+ {v: -129, e: []byte{0x02, 0x02, 0xFF, 0x7F}},
+ {v: math.MaxInt64, e: []byte{0x02, 0x08, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {v: math.MinInt64, e: []byte{0x02, 0x08, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ }
+
+ for _, d := range data {
+ if b := NewInteger(ClassUniversal, TypePrimitive, TagInteger, int64(d.v), "").Bytes(); !bytes.Equal(d.e, b) {
+ t.Errorf("Wrong binary generated for %d : got % X, expected % X", d.v, b, d.e)
+ }
+ }
+}
+
+func TestBinaryOctetString(t *testing.T) {
+ // data src : http://luca.ntop.org/Teaching/Appunti/asn1.html 5.10
+
+ if !bytes.Equal([]byte{0x04, 0x08, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, NewString(ClassUniversal, TypePrimitive, TagOctetString, "\x01\x23\x45\x67\x89\xab\xcd\xef", "").Bytes()) {
+ t.Error("wrong binary generated")
+ }
+}
diff --git a/vendor/gopkg.in/asn1-ber.v1/header_test.go b/vendor/gopkg.in/asn1-ber.v1/header_test.go
new file mode 100644
index 000000000..cac1e2e2b
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/header_test.go
@@ -0,0 +1,135 @@
+package ber
+
+import (
+ "bytes"
+ "io"
+ "testing"
+)
+
+func TestReadHeader(t *testing.T) {
+ testcases := map[string]struct {
+ Data []byte
+ ExpectedIdentifier Identifier
+ ExpectedLength int
+ ExpectedBytesRead int
+ ExpectedError string
+ }{
+ "empty": {
+ Data: []byte{},
+ ExpectedIdentifier: Identifier{},
+ ExpectedLength: 0,
+ ExpectedBytesRead: 0,
+ ExpectedError: io.ErrUnexpectedEOF.Error(),
+ },
+
+ "valid short form": {
+ Data: []byte{
+ byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString),
+ 127,
+ },
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypePrimitive,
+ Tag: TagCharacterString,
+ },
+ ExpectedLength: 127,
+ ExpectedBytesRead: 2,
+ ExpectedError: "",
+ },
+
+ "valid long form": {
+ Data: []byte{
+ // 2-byte encoding of tag
+ byte(ClassUniversal) | byte(TypePrimitive) | byte(HighTag),
+ byte(TagCharacterString),
+
+ // 2-byte encoding of length
+ LengthLongFormBitmask | 1,
+ 127,
+ },
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypePrimitive,
+ Tag: TagCharacterString,
+ },
+ ExpectedLength: 127,
+ ExpectedBytesRead: 4,
+ ExpectedError: "",
+ },
+
+ "valid indefinite length": {
+ Data: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString),
+ LengthLongFormBitmask,
+ },
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagCharacterString,
+ },
+ ExpectedLength: LengthIndefinite,
+ ExpectedBytesRead: 2,
+ ExpectedError: "",
+ },
+
+ "invalid indefinite length": {
+ Data: []byte{
+ byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString),
+ LengthLongFormBitmask,
+ },
+ ExpectedIdentifier: Identifier{},
+ ExpectedLength: 0,
+ ExpectedBytesRead: 2,
+ ExpectedError: "indefinite length used with primitive type",
+ },
+ }
+
+ for k, tc := range testcases {
+ reader := bytes.NewBuffer(tc.Data)
+ identifier, length, read, err := readHeader(reader)
+
+ if err != nil {
+ if tc.ExpectedError == "" {
+ t.Errorf("%s: unexpected error: %v", k, err)
+ } else if err.Error() != tc.ExpectedError {
+ t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err)
+ }
+ } else if tc.ExpectedError != "" {
+ t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError)
+ continue
+ }
+
+ if read != tc.ExpectedBytesRead {
+ t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read)
+ }
+
+ if identifier.ClassType != tc.ExpectedIdentifier.ClassType {
+ t.Errorf("%s: expected class type %d (%s), got %d (%s)", k,
+ tc.ExpectedIdentifier.ClassType,
+ ClassMap[tc.ExpectedIdentifier.ClassType],
+ identifier.ClassType,
+ ClassMap[identifier.ClassType],
+ )
+ }
+ if identifier.TagType != tc.ExpectedIdentifier.TagType {
+ t.Errorf("%s: expected tag type %d (%s), got %d (%s)", k,
+ tc.ExpectedIdentifier.TagType,
+ TypeMap[tc.ExpectedIdentifier.TagType],
+ identifier.TagType,
+ TypeMap[identifier.TagType],
+ )
+ }
+ if identifier.Tag != tc.ExpectedIdentifier.Tag {
+ t.Errorf("%s: expected tag %d (%s), got %d (%s)", k,
+ tc.ExpectedIdentifier.Tag,
+ tagMap[tc.ExpectedIdentifier.Tag],
+ identifier.Tag,
+ tagMap[identifier.Tag],
+ )
+ }
+
+ if length != tc.ExpectedLength {
+ t.Errorf("%s: expected length %d, got %d", k, tc.ExpectedLength, length)
+ }
+ }
+}
diff --git a/vendor/gopkg.in/asn1-ber.v1/identifier_test.go b/vendor/gopkg.in/asn1-ber.v1/identifier_test.go
new file mode 100644
index 000000000..7169362e2
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/identifier_test.go
@@ -0,0 +1,344 @@
+package ber
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "testing"
+)
+
+func TestReadIdentifier(t *testing.T) {
+ testcases := map[string]struct {
+ Data []byte
+
+ ExpectedIdentifier Identifier
+ ExpectedBytesRead int
+ ExpectedError string
+ }{
+ "empty": {
+ Data: []byte{},
+ ExpectedBytesRead: 0,
+ ExpectedError: io.ErrUnexpectedEOF.Error(),
+ },
+
+ "universal primitive eoc": {
+ Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)},
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypePrimitive,
+ Tag: TagEOC,
+ },
+ ExpectedBytesRead: 1,
+ },
+ "universal primitive character string": {
+ Data: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)},
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypePrimitive,
+ Tag: TagCharacterString,
+ },
+ ExpectedBytesRead: 1,
+ },
+
+ "universal constructed bit string": {
+ Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)},
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagBitString,
+ },
+ ExpectedBytesRead: 1,
+ },
+ "universal constructed character string": {
+ Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)},
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagCharacterString,
+ },
+ ExpectedBytesRead: 1,
+ },
+
+ "application constructed object descriptor": {
+ Data: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassApplication,
+ TagType: TypeConstructed,
+ Tag: TagObjectDescriptor,
+ },
+ ExpectedBytesRead: 1,
+ },
+ "context constructed object descriptor": {
+ Data: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassContext,
+ TagType: TypeConstructed,
+ Tag: TagObjectDescriptor,
+ },
+ ExpectedBytesRead: 1,
+ },
+ "private constructed object descriptor": {
+ Data: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassPrivate,
+ TagType: TypeConstructed,
+ Tag: TagObjectDescriptor,
+ },
+ ExpectedBytesRead: 1,
+ },
+
+ "high-tag-number tag missing bytes": {
+ Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag)},
+ ExpectedError: io.ErrUnexpectedEOF.Error(),
+ ExpectedBytesRead: 1,
+ },
+ "high-tag-number tag invalid first byte": {
+ Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), 0x0},
+ ExpectedError: "invalid first high-tag-number tag byte",
+ ExpectedBytesRead: 2,
+ },
+ "high-tag-number tag invalid first byte with continue bit": {
+ Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask)},
+ ExpectedError: "invalid first high-tag-number tag byte",
+ ExpectedBytesRead: 2,
+ },
+ "high-tag-number tag continuation missing bytes": {
+ Data: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag), byte(HighTagContinueBitmask | 0x1)},
+ ExpectedError: io.ErrUnexpectedEOF.Error(),
+ ExpectedBytesRead: 2,
+ },
+ "high-tag-number tag overflow": {
+ Data: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(HighTagContinueBitmask | 0x1),
+ byte(0x1),
+ },
+ ExpectedError: "high-tag-number tag overflow",
+ ExpectedBytesRead: 11,
+ },
+ "max high-tag-number tag": {
+ Data: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(0x7f),
+ },
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: Tag(0x7FFFFFFFFFFFFFFF), // 01111111...(63)...11111b
+ },
+ ExpectedBytesRead: 10,
+ },
+ "high-tag-number encoding of low-tag value": {
+ Data: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
+ byte(TagObjectDescriptor),
+ },
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagObjectDescriptor,
+ },
+ ExpectedBytesRead: 2,
+ },
+ "max high-tag-number tag ignores extra data": {
+ Data: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(0x7f),
+ byte(0x01), // extra data, shouldn't be read
+ byte(0x02), // extra data, shouldn't be read
+ byte(0x03), // extra data, shouldn't be read
+ },
+ ExpectedIdentifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: Tag(0x7FFFFFFFFFFFFFFF), // 01111111...(63)...11111b
+ },
+ ExpectedBytesRead: 10,
+ },
+ }
+
+ for k, tc := range testcases {
+ reader := bytes.NewBuffer(tc.Data)
+ identifier, read, err := readIdentifier(reader)
+
+ if err != nil {
+ if tc.ExpectedError == "" {
+ t.Errorf("%s: unexpected error: %v", k, err)
+ } else if err.Error() != tc.ExpectedError {
+ t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err)
+ }
+ } else if tc.ExpectedError != "" {
+ t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError)
+ continue
+ }
+
+ if read != tc.ExpectedBytesRead {
+ t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read)
+ }
+
+ if identifier.ClassType != tc.ExpectedIdentifier.ClassType {
+ t.Errorf("%s: expected class type %d (%s), got %d (%s)", k,
+ tc.ExpectedIdentifier.ClassType,
+ ClassMap[tc.ExpectedIdentifier.ClassType],
+ identifier.ClassType,
+ ClassMap[identifier.ClassType],
+ )
+ }
+ if identifier.TagType != tc.ExpectedIdentifier.TagType {
+ t.Errorf("%s: expected tag type %d (%s), got %d (%s)", k,
+ tc.ExpectedIdentifier.TagType,
+ TypeMap[tc.ExpectedIdentifier.TagType],
+ identifier.TagType,
+ TypeMap[identifier.TagType],
+ )
+ }
+ if identifier.Tag != tc.ExpectedIdentifier.Tag {
+ t.Errorf("%s: expected tag %d (%s), got %d (%s)", k,
+ tc.ExpectedIdentifier.Tag,
+ tagMap[tc.ExpectedIdentifier.Tag],
+ identifier.Tag,
+ tagMap[identifier.Tag],
+ )
+ }
+ }
+}
+
+func TestEncodeIdentifier(t *testing.T) {
+ testcases := map[string]struct {
+ Identifier Identifier
+ ExpectedBytes []byte
+ }{
+ "universal primitive eoc": {
+ Identifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypePrimitive,
+ Tag: TagEOC,
+ },
+ ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagEOC)},
+ },
+ "universal primitive character string": {
+ Identifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypePrimitive,
+ Tag: TagCharacterString,
+ },
+ ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypePrimitive) | byte(TagCharacterString)},
+ },
+
+ "universal constructed bit string": {
+ Identifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagBitString,
+ },
+ ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBitString)},
+ },
+ "universal constructed character string": {
+ Identifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagCharacterString,
+ },
+ ExpectedBytes: []byte{byte(ClassUniversal) | byte(TypeConstructed) | byte(TagCharacterString)},
+ },
+
+ "application constructed object descriptor": {
+ Identifier: Identifier{
+ ClassType: ClassApplication,
+ TagType: TypeConstructed,
+ Tag: TagObjectDescriptor,
+ },
+ ExpectedBytes: []byte{byte(ClassApplication) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
+ },
+ "context constructed object descriptor": {
+ Identifier: Identifier{
+ ClassType: ClassContext,
+ TagType: TypeConstructed,
+ Tag: TagObjectDescriptor,
+ },
+ ExpectedBytes: []byte{byte(ClassContext) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
+ },
+ "private constructed object descriptor": {
+ Identifier: Identifier{
+ ClassType: ClassPrivate,
+ TagType: TypeConstructed,
+ Tag: TagObjectDescriptor,
+ },
+ ExpectedBytes: []byte{byte(ClassPrivate) | byte(TypeConstructed) | byte(TagObjectDescriptor)},
+ },
+
+ "max low-tag-number tag": {
+ Identifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagBMPString,
+ },
+ ExpectedBytes: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(TagBMPString),
+ },
+ },
+
+ "min high-tag-number tag": {
+ Identifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: TagBMPString + 1,
+ },
+ ExpectedBytes: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
+ byte(TagBMPString + 1),
+ },
+ },
+
+ "max high-tag-number tag": {
+ Identifier: Identifier{
+ ClassType: ClassUniversal,
+ TagType: TypeConstructed,
+ Tag: Tag(math.MaxInt64),
+ },
+ ExpectedBytes: []byte{
+ byte(ClassUniversal) | byte(TypeConstructed) | byte(HighTag),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(HighTagContinueBitmask | 0x7f),
+ byte(0x7f),
+ },
+ },
+ }
+
+ for k, tc := range testcases {
+ b := encodeIdentifier(tc.Identifier)
+ if bytes.Compare(tc.ExpectedBytes, b) != 0 {
+ t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedBytes, b)
+ }
+ }
+}
diff --git a/vendor/gopkg.in/asn1-ber.v1/length_test.go b/vendor/gopkg.in/asn1-ber.v1/length_test.go
new file mode 100644
index 000000000..afe0e8037
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/length_test.go
@@ -0,0 +1,158 @@
+package ber
+
+import (
+ "bytes"
+ "io"
+ "math"
+ "testing"
+)
+
+func TestReadLength(t *testing.T) {
+ testcases := map[string]struct {
+ Data []byte
+
+ ExpectedLength int
+ ExpectedBytesRead int
+ ExpectedError string
+ }{
+ "empty": {
+ Data: []byte{},
+ ExpectedBytesRead: 0,
+ ExpectedError: io.ErrUnexpectedEOF.Error(),
+ },
+ "invalid first byte": {
+ Data: []byte{0xFF},
+ ExpectedBytesRead: 1,
+ ExpectedError: "invalid length byte 0xff",
+ },
+
+ "indefinite form": {
+ Data: []byte{LengthLongFormBitmask},
+ ExpectedLength: LengthIndefinite,
+ ExpectedBytesRead: 1,
+ },
+
+ "short-definite-form zero length": {
+ Data: []byte{0},
+ ExpectedLength: 0,
+ ExpectedBytesRead: 1,
+ },
+ "short-definite-form length 1": {
+ Data: []byte{1},
+ ExpectedLength: 1,
+ ExpectedBytesRead: 1,
+ },
+ "short-definite-form max length": {
+ Data: []byte{127},
+ ExpectedLength: 127,
+ ExpectedBytesRead: 1,
+ },
+
+ "long-definite-form missing bytes": {
+ Data: []byte{LengthLongFormBitmask | 1},
+ ExpectedBytesRead: 1,
+ ExpectedError: io.ErrUnexpectedEOF.Error(),
+ },
+ "long-definite-form overflow": {
+ Data: []byte{LengthLongFormBitmask | 9},
+ ExpectedBytesRead: 1,
+ ExpectedError: "long-form length overflow",
+ },
+ "long-definite-form zero length": {
+ Data: []byte{LengthLongFormBitmask | 1, 0x0},
+ ExpectedLength: 0,
+ ExpectedBytesRead: 2,
+ },
+ "long-definite-form length 127": {
+ Data: []byte{LengthLongFormBitmask | 1, 127},
+ ExpectedLength: 127,
+ ExpectedBytesRead: 2,
+ },
+ "long-definite-form max length": {
+ Data: []byte{
+ LengthLongFormBitmask | 8,
+ 0x7F,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ },
+ ExpectedLength: math.MaxInt64,
+ ExpectedBytesRead: 9,
+ },
+ }
+
+ for k, tc := range testcases {
+ reader := bytes.NewBuffer(tc.Data)
+ length, read, err := readLength(reader)
+
+ if err != nil {
+ if tc.ExpectedError == "" {
+ t.Errorf("%s: unexpected error: %v", k, err)
+ } else if err.Error() != tc.ExpectedError {
+ t.Errorf("%s: expected error %v, got %v", k, tc.ExpectedError, err)
+ }
+ } else if tc.ExpectedError != "" {
+ t.Errorf("%s: expected error %v, got none", k, tc.ExpectedError)
+ continue
+ }
+
+ if read != tc.ExpectedBytesRead {
+ t.Errorf("%s: expected read %d, got %d", k, tc.ExpectedBytesRead, read)
+ }
+
+ if length != tc.ExpectedLength {
+ t.Errorf("%s: expected length %d, got %d", k, tc.ExpectedLength, length)
+ }
+ }
+}
+
+func TestEncodeLength(t *testing.T) {
+ testcases := map[string]struct {
+ Length int
+ ExpectedBytes []byte
+ }{
+ "0": {
+ Length: 0,
+ ExpectedBytes: []byte{0},
+ },
+ "1": {
+ Length: 1,
+ ExpectedBytes: []byte{1},
+ },
+
+ "max short-form length": {
+ Length: 127,
+ ExpectedBytes: []byte{127},
+ },
+ "min long-form length": {
+ Length: 128,
+ ExpectedBytes: []byte{LengthLongFormBitmask | 1, 128},
+ },
+
+ "max long-form length": {
+ Length: math.MaxInt64,
+ ExpectedBytes: []byte{
+ LengthLongFormBitmask | 8,
+ 0x7F,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ 0xFF,
+ },
+ },
+ }
+
+ for k, tc := range testcases {
+ b := encodeLength(tc.Length)
+ if bytes.Compare(tc.ExpectedBytes, b) != 0 {
+ t.Errorf("%s: Expected\n\t%#v\ngot\n\t%#v", k, tc.ExpectedBytes, b)
+ }
+ }
+}
diff --git a/vendor/gopkg.in/asn1-ber.v1/suite_test.go b/vendor/gopkg.in/asn1-ber.v1/suite_test.go
new file mode 100644
index 000000000..ace8e6705
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/suite_test.go
@@ -0,0 +1,182 @@
+package ber
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "testing"
+)
+
+var errEOF = io.ErrUnexpectedEOF.Error()
+
+// Tests from http://www.strozhevsky.com/free_docs/free_asn1_testsuite_descr.pdf
+// Source files and descriptions at http://www.strozhevsky.com/free_docs/TEST_SUITE.zip
+var testcases = []struct {
+ // File contains the path to the BER-encoded file
+ File string
+ // Error indicates whether a decoding error is expected
+ Error string
+ // AbnormalEncoding indicates whether a normalized re-encoding is expected to differ from the original source
+ AbnormalEncoding bool
+ // IndefiniteEncoding indicates the source file used indefinite-length encoding, so the re-encoding is expected to differ (since the length is known)
+ IndefiniteEncoding bool
+}{
+ // Common blocks
+ {File: "tests/tc1.ber", Error: "high-tag-number tag overflow"},
+ {File: "tests/tc2.ber", Error: errEOF},
+ {File: "tests/tc3.ber", Error: errEOF},
+ {File: "tests/tc4.ber", Error: "invalid length byte 0xff"},
+ {File: "tests/tc5.ber", Error: "", AbnormalEncoding: true},
+ // Real numbers (some expected failures are disabled until support is added)
+ {File: "tests/tc6.ber", Error: ""}, // Error: "REAL value +0 must be encoded with zero-length value block"},
+ {File: "tests/tc7.ber", Error: ""}, // Error: "REAL value -0 must be encoded as a special value"},
+ {File: "tests/tc8.ber", Error: ""},
+ {File: "tests/tc9.ber", Error: ""}, // Error: "Bits 6 and 5 of information octet for REAL are equal to 11"
+ {File: "tests/tc10.ber", Error: ""},
+ {File: "tests/tc11.ber", Error: ""}, // Error: "Incorrect NR form"
+ {File: "tests/tc12.ber", Error: ""}, // Error: "Encoding of "special value" not from ASN.1 standard"
+ {File: "tests/tc13.ber", Error: errEOF},
+ {File: "tests/tc14.ber", Error: errEOF},
+ {File: "tests/tc15.ber", Error: ""}, // Error: "Too big value of exponent"
+ {File: "tests/tc16.ber", Error: ""}, // Error: "Too big value of mantissa"
+ {File: "tests/tc17.ber", Error: ""}, // Error: "Too big values for exponent and mantissa + using of "scaling factor" value"
+ // Integers
+ {File: "tests/tc18.ber", Error: ""},
+ {File: "tests/tc19.ber", Error: errEOF},
+ {File: "tests/tc20.ber", Error: ""},
+ // Object identifiers
+ {File: "tests/tc21.ber", Error: ""},
+ {File: "tests/tc22.ber", Error: ""},
+ {File: "tests/tc23.ber", Error: errEOF},
+ {File: "tests/tc24.ber", Error: ""},
+ // Booleans
+ {File: "tests/tc25.ber", Error: ""},
+ {File: "tests/tc26.ber", Error: ""},
+ {File: "tests/tc27.ber", Error: errEOF},
+ {File: "tests/tc28.ber", Error: ""},
+ {File: "tests/tc29.ber", Error: ""},
+ // Null
+ {File: "tests/tc30.ber", Error: ""},
+ {File: "tests/tc31.ber", Error: errEOF},
+ {File: "tests/tc32.ber", Error: ""},
+ // Bitstring (some expected failures are disabled until support is added)
+ {File: "tests/tc33.ber", Error: ""}, // Error: "Too big value for "unused bits""
+ {File: "tests/tc34.ber", Error: errEOF},
+ {File: "tests/tc35.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from BIT STRING types as internal types for constructive encoding"
+ {File: "tests/tc36.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of "unused bits" in internal BIT STRINGs with constructive form of encoding"
+ {File: "tests/tc37.ber", Error: ""},
+ {File: "tests/tc38.ber", Error: "", IndefiniteEncoding: true},
+ {File: "tests/tc39.ber", Error: ""},
+ {File: "tests/tc40.ber", Error: ""},
+ // Octet string (some expected failures are disabled until support is added)
+ {File: "tests/tc41.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of different from OCTET STRING types as internal types for constructive encoding"
+ {File: "tests/tc42.ber", Error: errEOF},
+ {File: "tests/tc43.ber", Error: errEOF},
+ {File: "tests/tc44.ber", Error: ""},
+ {File: "tests/tc45.ber", Error: ""},
+ // Bitstring
+ {File: "tests/tc46.ber", Error: "indefinite length used with primitive type"},
+ {File: "tests/tc47.ber", Error: "eoc child not allowed with definite length"},
+ {File: "tests/tc48.ber", Error: "", IndefiniteEncoding: true}, // Error: "Using of more than 7 "unused bits" in BIT STRING with constrictive encoding form"
+}
+
+func TestSuiteDecodePacket(t *testing.T) {
+ // Debug = true
+ for _, tc := range testcases {
+ file := tc.File
+
+ dataIn, err := ioutil.ReadFile(file)
+ if err != nil {
+ t.Errorf("%s: %v", file, err)
+ continue
+ }
+
+ // fmt.Printf("%s: decode %d\n", file, len(dataIn))
+ packet, err := DecodePacketErr(dataIn)
+ if err != nil {
+ if tc.Error == "" {
+ t.Errorf("%s: unexpected error during DecodePacket: %v", file, err)
+ } else if tc.Error != err.Error() {
+ t.Errorf("%s: expected error %q during DecodePacket, got %q", file, tc.Error, err)
+ }
+ continue
+ }
+ if tc.Error != "" {
+ t.Errorf("%s: expected error %q, got none", file, tc.Error)
+ continue
+ }
+
+ dataOut := packet.Bytes()
+ if tc.AbnormalEncoding || tc.IndefiniteEncoding {
+ // Abnormal encodings and encodings that used indefinite length should re-encode differently
+ if bytes.Equal(dataOut, dataIn) {
+ t.Errorf("%s: data should have been re-encoded differently", file)
+ }
+ } else if !bytes.Equal(dataOut, dataIn) {
+ // Make sure the serialized data matches the source
+ t.Errorf("%s: data should be the same", file)
+ }
+
+ packet, err = DecodePacketErr(dataOut)
+ if err != nil {
+ t.Errorf("%s: unexpected error: %v", file, err)
+ continue
+ }
+
+ // Make sure the re-serialized data matches our original serialization
+ dataOut2 := packet.Bytes()
+ if !bytes.Equal(dataOut, dataOut2) {
+ t.Errorf("%s: data should be the same", file)
+ }
+ }
+}
+
+func TestSuiteReadPacket(t *testing.T) {
+ for _, tc := range testcases {
+ file := tc.File
+
+ dataIn, err := ioutil.ReadFile(file)
+ if err != nil {
+ t.Errorf("%s: %v", file, err)
+ continue
+ }
+
+ buffer := bytes.NewBuffer(dataIn)
+ packet, err := ReadPacket(buffer)
+ if err != nil {
+ if tc.Error == "" {
+ t.Errorf("%s: unexpected error during ReadPacket: %v", file, err)
+ } else if tc.Error != err.Error() {
+ t.Errorf("%s: expected error %q during ReadPacket, got %q", file, tc.Error, err)
+ }
+ continue
+ }
+ if tc.Error != "" {
+ t.Errorf("%s: expected error %q, got none", file, tc.Error)
+ continue
+ }
+
+ dataOut := packet.Bytes()
+ if tc.AbnormalEncoding || tc.IndefiniteEncoding {
+ // Abnormal encodings and encodings that used indefinite length should re-encode differently
+ if bytes.Equal(dataOut, dataIn) {
+ t.Errorf("%s: data should have been re-encoded differently", file)
+ }
+ } else if !bytes.Equal(dataOut, dataIn) {
+ // Make sure the serialized data matches the source
+ t.Errorf("%s: data should be the same", file)
+ }
+
+ packet, err = DecodePacketErr(dataOut)
+ if err != nil {
+ t.Errorf("%s: unexpected error: %v", file, err)
+ continue
+ }
+
+ // Make sure the re-serialized data matches our original serialization
+ dataOut2 := packet.Bytes()
+ if !bytes.Equal(dataOut, dataOut2) {
+ t.Errorf("%s: data should be the same", file)
+ }
+ }
+}
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc1.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc1.ber
new file mode 100644
index 000000000..5c6ba1c6a
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc1.ber
@@ -0,0 +1 @@
+@ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc10.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc10.ber
new file mode 100644
index 000000000..f733125d4
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc10.ber
@@ -0,0 +1 @@
+  \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc11.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc11.ber
new file mode 100644
index 000000000..cc4a609c8
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc11.ber
@@ -0,0 +1 @@
+  015625 \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc12.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc12.ber
new file mode 100644
index 000000000..dbb538d69
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc12.ber
@@ -0,0 +1 @@
+ I \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc13.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc13.ber
new file mode 100644
index 000000000..f4f438e0d
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc13.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc14.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc14.ber
new file mode 100644
index 000000000..b6f2fd3a4
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc14.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc15.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc15.ber
new file mode 100644
index 000000000..3d6da6764
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc15.ber
@@ -0,0 +1 @@
+  \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc16.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc16.ber
new file mode 100644
index 000000000..68634f5f3
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc16.ber
@@ -0,0 +1 @@
+  \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc17.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc17.ber
new file mode 100644
index 000000000..adb9e3320
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc17.ber
@@ -0,0 +1 @@
+   \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc18.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc18.ber
new file mode 100644
index 000000000..fb6843f7f
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc18.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc19.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc19.ber
new file mode 100644
index 000000000..03afaa5de
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc19.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc2.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc2.ber
new file mode 100644
index 000000000..7e785773c
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc2.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc20.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc20.ber
new file mode 100644
index 000000000..a976464b9
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc20.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc21.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc21.ber
new file mode 100644
index 000000000..d6c2f9aa7
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc21.ber
@@ -0,0 +1 @@
+Q \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc22.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc22.ber
new file mode 100644
index 000000000..d1d70afab
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc22.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc23.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc23.ber
new file mode 100644
index 000000000..0e8d18f62
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc23.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc24.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc24.ber
new file mode 100644
index 000000000..10565aefa
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc24.ber
@@ -0,0 +1 @@
+`HO Jc/ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc25.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc25.ber
new file mode 100644
index 000000000..1e1140524
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc25.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc26.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc26.ber
new file mode 100644
index 000000000..d28653b3b
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc26.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc27.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc27.ber
new file mode 100644
index 000000000..c8c781144
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc27.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc28.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc28.ber
new file mode 100644
index 000000000..415fe23ed
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc28.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc29.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc29.ber
new file mode 100644
index 000000000..4076f4487
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc29.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc3.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc3.ber
new file mode 100644
index 000000000..c05c900b6
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc3.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc30.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc30.ber
new file mode 100644
index 000000000..72bcf80f4
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc30.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc31.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc31.ber
new file mode 100644
index 000000000..1fcc4f254
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc31.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc32.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc32.ber
new file mode 100644
index 000000000..19b3e940a
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc32.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc33.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc33.ber
new file mode 100644
index 000000000..6ea70c4d2
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc33.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc34.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc34.ber
new file mode 100644
index 000000000..61337095d
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc34.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc35.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc35.ber
new file mode 100644
index 000000000..d27eb301a
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc35.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc36.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc36.ber
new file mode 100644
index 000000000..e5baaeacd
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc36.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc37.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc37.ber
new file mode 100644
index 000000000..d0b1cfbe1
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc37.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc38.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc38.ber
new file mode 100644
index 000000000..090bce74b
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc38.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc39.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc39.ber
new file mode 100644
index 000000000..d9d01199b
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc39.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc4.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc4.ber
new file mode 100644
index 000000000..2b888baac
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc4.ber
@@ -0,0 +1 @@
+ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc40.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc40.ber
new file mode 100644
index 000000000..15294a501
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc40.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc41.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc41.ber
new file mode 100644
index 000000000..276836b65
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc41.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc42.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc42.ber
new file mode 100644
index 000000000..21cbfd10f
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc42.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc43.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc43.ber
new file mode 100644
index 000000000..98dbd7419
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc43.ber
@@ -0,0 +1 @@
+$ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc44.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc44.ber
new file mode 100644
index 000000000..d825e1ad7
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc44.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc45.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc45.ber
new file mode 100644
index 000000000..7b861b02c
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc45.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc46.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc46.ber
new file mode 100644
index 000000000..e78deee34
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc46.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc47.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc47.ber
new file mode 100644
index 000000000..190bb86f6
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc47.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc48.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc48.ber
new file mode 100644
index 000000000..f7f111ae6
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc48.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc5.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc5.ber
new file mode 100644
index 000000000..45e0a0093
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc5.ber
@@ -0,0 +1 @@
+@ \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc6.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc6.ber
new file mode 100644
index 000000000..cee1aaf0c
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc6.ber
@@ -0,0 +1 @@
+ +0.E-5 \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc7.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc7.ber
new file mode 100644
index 000000000..d5ae68572
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc7.ber
@@ -0,0 +1 @@
+ -0.E-5 \ No newline at end of file
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc8.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc8.ber
new file mode 100644
index 000000000..cb32a09cb
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc8.ber
Binary files differ
diff --git a/vendor/gopkg.in/asn1-ber.v1/tests/tc9.ber b/vendor/gopkg.in/asn1-ber.v1/tests/tc9.ber
new file mode 100644
index 000000000..50b43a510
--- /dev/null
+++ b/vendor/gopkg.in/asn1-ber.v1/tests/tc9.ber
@@ -0,0 +1 @@
+  \ No newline at end of file
diff --git a/vendor/gopkg.in/fsnotify.v1/example_test.go b/vendor/gopkg.in/fsnotify.v1/example_test.go
new file mode 100644
index 000000000..700502cb3
--- /dev/null
+++ b/vendor/gopkg.in/fsnotify.v1/example_test.go
@@ -0,0 +1,42 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9
+
+package fsnotify_test
+
+import (
+ "log"
+
+ "github.com/fsnotify/fsnotify"
+)
+
+func ExampleNewWatcher() {
+ watcher, err := fsnotify.NewWatcher()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer watcher.Close()
+
+ done := make(chan bool)
+ go func() {
+ for {
+ select {
+ case event := <-watcher.Events:
+ log.Println("event:", event)
+ if event.Op&fsnotify.Write == fsnotify.Write {
+ log.Println("modified file:", event.Name)
+ }
+ case err := <-watcher.Errors:
+ log.Println("error:", err)
+ }
+ }
+ }()
+
+ err = watcher.Add("/tmp/foo")
+ if err != nil {
+ log.Fatal(err)
+ }
+ <-done
+}
diff --git a/vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go b/vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go
new file mode 100644
index 000000000..26623efef
--- /dev/null
+++ b/vendor/gopkg.in/fsnotify.v1/inotify_poller_test.go
@@ -0,0 +1,229 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package fsnotify
+
+import (
+ "testing"
+ "time"
+
+ "golang.org/x/sys/unix"
+)
+
+type testFd [2]int
+
+func makeTestFd(t *testing.T) testFd {
+ var tfd testFd
+ errno := unix.Pipe(tfd[:])
+ if errno != nil {
+ t.Fatalf("Failed to create pipe: %v", errno)
+ }
+ return tfd
+}
+
+func (tfd testFd) fd() int {
+ return tfd[0]
+}
+
+func (tfd testFd) closeWrite(t *testing.T) {
+ errno := unix.Close(tfd[1])
+ if errno != nil {
+ t.Fatalf("Failed to close write end of pipe: %v", errno)
+ }
+}
+
+func (tfd testFd) put(t *testing.T) {
+ buf := make([]byte, 10)
+ _, errno := unix.Write(tfd[1], buf)
+ if errno != nil {
+ t.Fatalf("Failed to write to pipe: %v", errno)
+ }
+}
+
+func (tfd testFd) get(t *testing.T) {
+ buf := make([]byte, 10)
+ _, errno := unix.Read(tfd[0], buf)
+ if errno != nil {
+ t.Fatalf("Failed to read from pipe: %v", errno)
+ }
+}
+
+func (tfd testFd) close() {
+ unix.Close(tfd[1])
+ unix.Close(tfd[0])
+}
+
+func makePoller(t *testing.T) (testFd, *fdPoller) {
+ tfd := makeTestFd(t)
+ poller, err := newFdPoller(tfd.fd())
+ if err != nil {
+ t.Fatalf("Failed to create poller: %v", err)
+ }
+ return tfd, poller
+}
+
+func TestPollerWithBadFd(t *testing.T) {
+ _, err := newFdPoller(-1)
+ if err != unix.EBADF {
+ t.Fatalf("Expected EBADF, got: %v", err)
+ }
+}
+
+func TestPollerWithData(t *testing.T) {
+ tfd, poller := makePoller(t)
+ defer tfd.close()
+ defer poller.close()
+
+ tfd.put(t)
+ ok, err := poller.wait()
+ if err != nil {
+ t.Fatalf("poller failed: %v", err)
+ }
+ if !ok {
+ t.Fatalf("expected poller to return true")
+ }
+ tfd.get(t)
+}
+
+func TestPollerWithWakeup(t *testing.T) {
+ tfd, poller := makePoller(t)
+ defer tfd.close()
+ defer poller.close()
+
+ err := poller.wake()
+ if err != nil {
+ t.Fatalf("wake failed: %v", err)
+ }
+ ok, err := poller.wait()
+ if err != nil {
+ t.Fatalf("poller failed: %v", err)
+ }
+ if ok {
+ t.Fatalf("expected poller to return false")
+ }
+}
+
+func TestPollerWithClose(t *testing.T) {
+ tfd, poller := makePoller(t)
+ defer tfd.close()
+ defer poller.close()
+
+ tfd.closeWrite(t)
+ ok, err := poller.wait()
+ if err != nil {
+ t.Fatalf("poller failed: %v", err)
+ }
+ if !ok {
+ t.Fatalf("expected poller to return true")
+ }
+}
+
+func TestPollerWithWakeupAndData(t *testing.T) {
+ tfd, poller := makePoller(t)
+ defer tfd.close()
+ defer poller.close()
+
+ tfd.put(t)
+ err := poller.wake()
+ if err != nil {
+ t.Fatalf("wake failed: %v", err)
+ }
+
+ // both data and wakeup
+ ok, err := poller.wait()
+ if err != nil {
+ t.Fatalf("poller failed: %v", err)
+ }
+ if !ok {
+ t.Fatalf("expected poller to return true")
+ }
+
+ // data is still in the buffer, wakeup is cleared
+ ok, err = poller.wait()
+ if err != nil {
+ t.Fatalf("poller failed: %v", err)
+ }
+ if !ok {
+ t.Fatalf("expected poller to return true")
+ }
+
+ tfd.get(t)
+ // data is gone, only wakeup now
+ err = poller.wake()
+ if err != nil {
+ t.Fatalf("wake failed: %v", err)
+ }
+ ok, err = poller.wait()
+ if err != nil {
+ t.Fatalf("poller failed: %v", err)
+ }
+ if ok {
+ t.Fatalf("expected poller to return false")
+ }
+}
+
+func TestPollerConcurrent(t *testing.T) {
+ tfd, poller := makePoller(t)
+ defer tfd.close()
+ defer poller.close()
+
+ oks := make(chan bool)
+ live := make(chan bool)
+ defer close(live)
+ go func() {
+ defer close(oks)
+ for {
+ ok, err := poller.wait()
+ if err != nil {
+ t.Fatalf("poller failed: %v", err)
+ }
+ oks <- ok
+ if !<-live {
+ return
+ }
+ }
+ }()
+
+ // Try a write
+ select {
+ case <-time.After(50 * time.Millisecond):
+ case <-oks:
+ t.Fatalf("poller did not wait")
+ }
+ tfd.put(t)
+ if !<-oks {
+ t.Fatalf("expected true")
+ }
+ tfd.get(t)
+ live <- true
+
+ // Try a wakeup
+ select {
+ case <-time.After(50 * time.Millisecond):
+ case <-oks:
+ t.Fatalf("poller did not wait")
+ }
+ err := poller.wake()
+ if err != nil {
+ t.Fatalf("wake failed: %v", err)
+ }
+ if <-oks {
+ t.Fatalf("expected false")
+ }
+ live <- true
+
+ // Try a close
+ select {
+ case <-time.After(50 * time.Millisecond):
+ case <-oks:
+ t.Fatalf("poller did not wait")
+ }
+ tfd.closeWrite(t)
+ if !<-oks {
+ t.Fatalf("expected true")
+ }
+ tfd.get(t)
+}
diff --git a/vendor/gopkg.in/fsnotify.v1/inotify_test.go b/vendor/gopkg.in/fsnotify.v1/inotify_test.go
new file mode 100644
index 000000000..2527cad1f
--- /dev/null
+++ b/vendor/gopkg.in/fsnotify.v1/inotify_test.go
@@ -0,0 +1,344 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build linux
+
+package fsnotify
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "golang.org/x/sys/unix"
+)
+
+func TestInotifyCloseRightAway(t *testing.T) {
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher")
+ }
+
+ // Close immediately; it won't even reach the first unix.Read.
+ w.Close()
+
+ // Wait for the close to complete.
+ <-time.After(50 * time.Millisecond)
+ isWatcherReallyClosed(t, w)
+}
+
+func TestInotifyCloseSlightlyLater(t *testing.T) {
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher")
+ }
+
+ // Wait until readEvents has reached unix.Read, and Close.
+ <-time.After(50 * time.Millisecond)
+ w.Close()
+
+ // Wait for the close to complete.
+ <-time.After(50 * time.Millisecond)
+ isWatcherReallyClosed(t, w)
+}
+
+func TestInotifyCloseSlightlyLaterWithWatch(t *testing.T) {
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher")
+ }
+ w.Add(testDir)
+
+ // Wait until readEvents has reached unix.Read, and Close.
+ <-time.After(50 * time.Millisecond)
+ w.Close()
+
+ // Wait for the close to complete.
+ <-time.After(50 * time.Millisecond)
+ isWatcherReallyClosed(t, w)
+}
+
+func TestInotifyCloseAfterRead(t *testing.T) {
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher")
+ }
+
+ err = w.Add(testDir)
+ if err != nil {
+ t.Fatalf("Failed to add .")
+ }
+
+ // Generate an event.
+ os.Create(filepath.Join(testDir, "somethingSOMETHINGsomethingSOMETHING"))
+
+ // Wait for readEvents to read the event, then close the watcher.
+ <-time.After(50 * time.Millisecond)
+ w.Close()
+
+ // Wait for the close to complete.
+ <-time.After(50 * time.Millisecond)
+ isWatcherReallyClosed(t, w)
+}
+
+func isWatcherReallyClosed(t *testing.T, w *Watcher) {
+ select {
+ case err, ok := <-w.Errors:
+ if ok {
+ t.Fatalf("w.Errors is not closed; readEvents is still alive after closing (error: %v)", err)
+ }
+ default:
+ t.Fatalf("w.Errors would have blocked; readEvents is still alive!")
+ }
+
+ select {
+ case _, ok := <-w.Events:
+ if ok {
+ t.Fatalf("w.Events is not closed; readEvents is still alive after closing")
+ }
+ default:
+ t.Fatalf("w.Events would have blocked; readEvents is still alive!")
+ }
+}
+
+func TestInotifyCloseCreate(t *testing.T) {
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher: %v", err)
+ }
+ defer w.Close()
+
+ err = w.Add(testDir)
+ if err != nil {
+ t.Fatalf("Failed to add testDir: %v", err)
+ }
+ h, err := os.Create(filepath.Join(testDir, "testfile"))
+ if err != nil {
+ t.Fatalf("Failed to create file in testdir: %v", err)
+ }
+ h.Close()
+ select {
+ case _ = <-w.Events:
+ case err := <-w.Errors:
+ t.Fatalf("Error from watcher: %v", err)
+ case <-time.After(50 * time.Millisecond):
+ t.Fatalf("Took too long to wait for event")
+ }
+
+ // At this point, we've received one event, so the goroutine is ready.
+ // It's also blocking on unix.Read.
+ // Now we try to swap the file descriptor under its nose.
+ w.Close()
+ w, err = NewWatcher()
+ defer w.Close()
+ if err != nil {
+ t.Fatalf("Failed to create second watcher: %v", err)
+ }
+
+ <-time.After(50 * time.Millisecond)
+ err = w.Add(testDir)
+ if err != nil {
+ t.Fatalf("Error adding testDir again: %v", err)
+ }
+}
+
+func TestInotifyStress(t *testing.T) {
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+ testFile := filepath.Join(testDir, "testfile")
+
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher: %v", err)
+ }
+ defer w.Close()
+
+ killchan := make(chan struct{})
+ defer close(killchan)
+
+ err = w.Add(testDir)
+ if err != nil {
+ t.Fatalf("Failed to add testDir: %v", err)
+ }
+
+ proc, err := os.FindProcess(os.Getpid())
+ if err != nil {
+ t.Fatalf("Error finding process: %v", err)
+ }
+
+ go func() {
+ for {
+ select {
+ case <-time.After(5 * time.Millisecond):
+ err := proc.Signal(unix.SIGUSR1)
+ if err != nil {
+ t.Fatalf("Signal failed: %v", err)
+ }
+ case <-killchan:
+ return
+ }
+ }
+ }()
+
+ go func() {
+ for {
+ select {
+ case <-time.After(11 * time.Millisecond):
+ err := w.poller.wake()
+ if err != nil {
+ t.Fatalf("Wake failed: %v", err)
+ }
+ case <-killchan:
+ return
+ }
+ }
+ }()
+
+ go func() {
+ for {
+ select {
+ case <-killchan:
+ return
+ default:
+ handle, err := os.Create(testFile)
+ if err != nil {
+ t.Fatalf("Create failed: %v", err)
+ }
+ handle.Close()
+ time.Sleep(time.Millisecond)
+ err = os.Remove(testFile)
+ if err != nil {
+ t.Fatalf("Remove failed: %v", err)
+ }
+ }
+ }
+ }()
+
+ creates := 0
+ removes := 0
+ after := time.After(5 * time.Second)
+ for {
+ select {
+ case <-after:
+ if creates-removes > 1 || creates-removes < -1 {
+ t.Fatalf("Creates and removes should not be off by more than one: %d creates, %d removes", creates, removes)
+ }
+ if creates < 50 {
+ t.Fatalf("Expected at least 50 creates, got %d", creates)
+ }
+ return
+ case err := <-w.Errors:
+ t.Fatalf("Got an error from watcher: %v", err)
+ case evt := <-w.Events:
+ if evt.Name != testFile {
+ t.Fatalf("Got an event for an unknown file: %s", evt.Name)
+ }
+ if evt.Op == Create {
+ creates++
+ }
+ if evt.Op == Remove {
+ removes++
+ }
+ }
+ }
+}
+
+func TestInotifyRemoveTwice(t *testing.T) {
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+ testFile := filepath.Join(testDir, "testfile")
+
+ handle, err := os.Create(testFile)
+ if err != nil {
+ t.Fatalf("Create failed: %v", err)
+ }
+ handle.Close()
+
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher: %v", err)
+ }
+ defer w.Close()
+
+ err = w.Add(testFile)
+ if err != nil {
+ t.Fatalf("Failed to add testFile: %v", err)
+ }
+
+ err = os.Remove(testFile)
+ if err != nil {
+ t.Fatalf("Failed to remove testFile: %v", err)
+ }
+
+ err = w.Remove(testFile)
+ if err == nil {
+ t.Fatalf("no error on removing invalid file")
+ }
+ s1 := fmt.Sprintf("%s", err)
+
+ err = w.Remove(testFile)
+ if err == nil {
+ t.Fatalf("no error on removing invalid file")
+ }
+ s2 := fmt.Sprintf("%s", err)
+
+ if s1 != s2 {
+ t.Fatalf("receive different error - %s / %s", s1, s2)
+ }
+}
+
+func TestInotifyInnerMapLength(t *testing.T) {
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+ testFile := filepath.Join(testDir, "testfile")
+
+ handle, err := os.Create(testFile)
+ if err != nil {
+ t.Fatalf("Create failed: %v", err)
+ }
+ handle.Close()
+
+ w, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("Failed to create watcher: %v", err)
+ }
+ defer w.Close()
+
+ err = w.Add(testFile)
+ if err != nil {
+ t.Fatalf("Failed to add testFile: %v", err)
+ }
+ go func() {
+ for err := range w.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ err = os.Remove(testFile)
+ if err != nil {
+ t.Fatalf("Failed to remove testFile: %v", err)
+ }
+ _ = <-w.Events // consume Remove event
+ <-time.After(50 * time.Millisecond) // wait IN_IGNORE propagated
+
+ w.mu.Lock()
+ defer w.mu.Unlock()
+ if len(w.watches) != 0 {
+ t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches)
+ }
+ if len(w.paths) != 0 {
+ t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths)
+ }
+}
diff --git a/vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go b/vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go
new file mode 100644
index 000000000..5564554f7
--- /dev/null
+++ b/vendor/gopkg.in/fsnotify.v1/integration_darwin_test.go
@@ -0,0 +1,147 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fsnotify
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+ "time"
+
+ "golang.org/x/sys/unix"
+)
+
+// testExchangedataForWatcher tests the watcher with the exchangedata operation on OS X.
+//
+// This is widely used for atomic saves on OS X, e.g. TextMate and in Apple's NSDocument.
+//
+// See https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html
+// Also see: https://github.com/textmate/textmate/blob/cd016be29489eba5f3c09b7b70b06da134dda550/Frameworks/io/src/swap_file_data.cc#L20
+func testExchangedataForWatcher(t *testing.T, watchDir bool) {
+ // Create directory to watch
+ testDir1 := tempMkdir(t)
+
+ // For the intermediate file
+ testDir2 := tempMkdir(t)
+
+ defer os.RemoveAll(testDir1)
+ defer os.RemoveAll(testDir2)
+
+ resolvedFilename := "TestFsnotifyEvents.file"
+
+ // TextMate does:
+ //
+ // 1. exchangedata (intermediate, resolved)
+ // 2. unlink intermediate
+ //
+ // Let's try to simulate that:
+ resolved := filepath.Join(testDir1, resolvedFilename)
+ intermediate := filepath.Join(testDir2, resolvedFilename+"~")
+
+ // Make sure we create the file before we start watching
+ createAndSyncFile(t, resolved)
+
+ watcher := newWatcher(t)
+
+ // Test both variants in isolation
+ if watchDir {
+ addWatch(t, watcher, testDir1)
+ } else {
+ addWatch(t, watcher, resolved)
+ }
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var removeReceived counter
+ var createReceived counter
+
+ done := make(chan bool)
+
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(resolved) {
+ if event.Op&Remove == Remove {
+ removeReceived.increment()
+ }
+ if event.Op&Create == Create {
+ createReceived.increment()
+ }
+ }
+ t.Logf("event received: %s", event)
+ }
+ done <- true
+ }()
+
+ // Repeat to make sure the watched file/directory "survives" the REMOVE/CREATE loop.
+ for i := 1; i <= 3; i++ {
+ // The intermediate file is created in a folder outside the watcher
+ createAndSyncFile(t, intermediate)
+
+ // 1. Swap
+ if err := unix.Exchangedata(intermediate, resolved, 0); err != nil {
+ t.Fatalf("[%d] exchangedata failed: %s", i, err)
+ }
+
+ time.Sleep(50 * time.Millisecond)
+
+ // 2. Delete the intermediate file
+ err := os.Remove(intermediate)
+
+ if err != nil {
+ t.Fatalf("[%d] remove %s failed: %s", i, intermediate, err)
+ }
+
+ time.Sleep(50 * time.Millisecond)
+
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+
+ // The events will be (CHMOD + REMOVE + CREATE) X 2. Let's focus on the last two:
+ if removeReceived.value() < 3 {
+ t.Fatal("fsnotify remove events have not been received after 500 ms")
+ }
+
+ if createReceived.value() < 3 {
+ t.Fatal("fsnotify create events have not been received after 500 ms")
+ }
+
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+}
+
+// TestExchangedataInWatchedDir test exchangedata operation on file in watched dir.
+func TestExchangedataInWatchedDir(t *testing.T) {
+ testExchangedataForWatcher(t, true)
+}
+
+// TestExchangedataInWatchedDir test exchangedata operation on watched file.
+func TestExchangedataInWatchedFile(t *testing.T) {
+ testExchangedataForWatcher(t, false)
+}
+
+func createAndSyncFile(t *testing.T, filepath string) {
+ f1, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating %s failed: %s", filepath, err)
+ }
+ f1.Sync()
+ f1.Close()
+}
diff --git a/vendor/gopkg.in/fsnotify.v1/integration_test.go b/vendor/gopkg.in/fsnotify.v1/integration_test.go
new file mode 100644
index 000000000..8b7e9d3ec
--- /dev/null
+++ b/vendor/gopkg.in/fsnotify.v1/integration_test.go
@@ -0,0 +1,1237 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !plan9,!solaris
+
+package fsnotify
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path"
+ "path/filepath"
+ "runtime"
+ "sync/atomic"
+ "testing"
+ "time"
+)
+
+// An atomic counter
+type counter struct {
+ val int32
+}
+
+func (c *counter) increment() {
+ atomic.AddInt32(&c.val, 1)
+}
+
+func (c *counter) value() int32 {
+ return atomic.LoadInt32(&c.val)
+}
+
+func (c *counter) reset() {
+ atomic.StoreInt32(&c.val, 0)
+}
+
+// tempMkdir makes a temporary directory
+func tempMkdir(t *testing.T) string {
+ dir, err := ioutil.TempDir("", "fsnotify")
+ if err != nil {
+ t.Fatalf("failed to create test directory: %s", err)
+ }
+ return dir
+}
+
+// tempMkFile makes a temporary file.
+func tempMkFile(t *testing.T, dir string) string {
+ f, err := ioutil.TempFile(dir, "fsnotify")
+ if err != nil {
+ t.Fatalf("failed to create test file: %v", err)
+ }
+ defer f.Close()
+ return f.Name()
+}
+
+// newWatcher initializes an fsnotify Watcher instance.
+func newWatcher(t *testing.T) *Watcher {
+ watcher, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("NewWatcher() failed: %s", err)
+ }
+ return watcher
+}
+
+// addWatch adds a watch for a directory
+func addWatch(t *testing.T, watcher *Watcher, dir string) {
+ if err := watcher.Add(dir); err != nil {
+ t.Fatalf("watcher.Add(%q) failed: %s", dir, err)
+ }
+}
+
+func TestFsnotifyMultipleOperations(t *testing.T) {
+ watcher := newWatcher(t)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Create directory that's not watched
+ testDirToMoveFiles := tempMkdir(t)
+ defer os.RemoveAll(testDirToMoveFiles)
+
+ testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
+ testFileRenamed := filepath.Join(testDirToMoveFiles, "TestFsnotifySeqRename.testfile")
+
+ addWatch(t, watcher, testDir)
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var createReceived, modifyReceived, deleteReceived, renameReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
+ t.Logf("event received: %s", event)
+ if event.Op&Remove == Remove {
+ deleteReceived.increment()
+ }
+ if event.Op&Write == Write {
+ modifyReceived.increment()
+ }
+ if event.Op&Create == Create {
+ createReceived.increment()
+ }
+ if event.Op&Rename == Rename {
+ renameReceived.increment()
+ }
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the fsnotify event queue
+ var f *os.File
+ f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+
+ time.Sleep(time.Millisecond)
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ if err := testRename(testFile, testFileRenamed); err != nil {
+ t.Fatalf("rename failed: %s", err)
+ }
+
+ // Modify the file outside of the watched dir
+ f, err = os.Open(testFileRenamed)
+ if err != nil {
+ t.Fatalf("open test renamed file failed: %s", err)
+ }
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ // Recreate the file that was moved
+ f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Close()
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ cReceived := createReceived.value()
+ if cReceived != 2 {
+ t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
+ }
+ mReceived := modifyReceived.value()
+ if mReceived != 1 {
+ t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
+ }
+ dReceived := deleteReceived.value()
+ rReceived := renameReceived.value()
+ if dReceived+rReceived != 1 {
+ t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", rReceived+dReceived, 1)
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+}
+
+func TestFsnotifyMultipleCreates(t *testing.T) {
+ watcher := newWatcher(t)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ testFile := filepath.Join(testDir, "TestFsnotifySeq.testfile")
+
+ addWatch(t, watcher, testDir)
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var createReceived, modifyReceived, deleteReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
+ t.Logf("event received: %s", event)
+ if event.Op&Remove == Remove {
+ deleteReceived.increment()
+ }
+ if event.Op&Create == Create {
+ createReceived.increment()
+ }
+ if event.Op&Write == Write {
+ modifyReceived.increment()
+ }
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the fsnotify event queue
+ var f *os.File
+ f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+
+ time.Sleep(time.Millisecond)
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ os.Remove(testFile)
+
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ // Recreate the file
+ f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Close()
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ // Modify
+ f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+
+ time.Sleep(time.Millisecond)
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ // Modify
+ f, err = os.OpenFile(testFile, os.O_WRONLY, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+
+ time.Sleep(time.Millisecond)
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ cReceived := createReceived.value()
+ if cReceived != 2 {
+ t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
+ }
+ mReceived := modifyReceived.value()
+ if mReceived < 3 {
+ t.Fatalf("incorrect number of modify events received after 500 ms (%d vs atleast %d)", mReceived, 3)
+ }
+ dReceived := deleteReceived.value()
+ if dReceived != 1 {
+ t.Fatalf("incorrect number of rename+delete events received after 500 ms (%d vs %d)", dReceived, 1)
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+}
+
+func TestFsnotifyDirOnly(t *testing.T) {
+ watcher := newWatcher(t)
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Create a file before watching directory
+ // This should NOT add any events to the fsnotify event queue
+ testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
+ {
+ var f *os.File
+ f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+ f.Close()
+ }
+
+ addWatch(t, watcher, testDir)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ testFile := filepath.Join(testDir, "TestFsnotifyDirOnly.testfile")
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var createReceived, modifyReceived, deleteReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileAlreadyExists) {
+ t.Logf("event received: %s", event)
+ if event.Op&Remove == Remove {
+ deleteReceived.increment()
+ }
+ if event.Op&Write == Write {
+ modifyReceived.increment()
+ }
+ if event.Op&Create == Create {
+ createReceived.increment()
+ }
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the fsnotify event queue
+ var f *os.File
+ f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+
+ time.Sleep(time.Millisecond)
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ time.Sleep(50 * time.Millisecond) // give system time to sync write change before delete
+
+ os.Remove(testFile)
+ os.Remove(testFileAlreadyExists)
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ cReceived := createReceived.value()
+ if cReceived != 1 {
+ t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 1)
+ }
+ mReceived := modifyReceived.value()
+ if mReceived != 1 {
+ t.Fatalf("incorrect number of modify events received after 500 ms (%d vs %d)", mReceived, 1)
+ }
+ dReceived := deleteReceived.value()
+ if dReceived != 2 {
+ t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+}
+
+func TestFsnotifyDeleteWatchedDir(t *testing.T) {
+ watcher := newWatcher(t)
+ defer watcher.Close()
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Create a file before watching directory
+ testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
+ {
+ var f *os.File
+ f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+ f.Close()
+ }
+
+ addWatch(t, watcher, testDir)
+
+ // Add a watch for testFile
+ addWatch(t, watcher, testFileAlreadyExists)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var deleteReceived counter
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFileAlreadyExists) {
+ t.Logf("event received: %s", event)
+ if event.Op&Remove == Remove {
+ deleteReceived.increment()
+ }
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ }()
+
+ os.RemoveAll(testDir)
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ dReceived := deleteReceived.value()
+ if dReceived < 2 {
+ t.Fatalf("did not receive at least %d delete events, received %d after 500 ms", 2, dReceived)
+ }
+}
+
+func TestFsnotifySubDir(t *testing.T) {
+ watcher := newWatcher(t)
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ testFile1 := filepath.Join(testDir, "TestFsnotifyFile1.testfile")
+ testSubDir := filepath.Join(testDir, "sub")
+ testSubDirFile := filepath.Join(testDir, "sub/TestFsnotifyFile1.testfile")
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var createReceived, deleteReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testSubDir) || event.Name == filepath.Clean(testFile1) {
+ t.Logf("event received: %s", event)
+ if event.Op&Create == Create {
+ createReceived.increment()
+ }
+ if event.Op&Remove == Remove {
+ deleteReceived.increment()
+ }
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ addWatch(t, watcher, testDir)
+
+ // Create sub-directory
+ if err := os.Mkdir(testSubDir, 0777); err != nil {
+ t.Fatalf("failed to create test sub-directory: %s", err)
+ }
+
+ // Create a file
+ var f *os.File
+ f, err := os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+ f.Close()
+
+ // Create a file (Should not see this! we are not watching subdir)
+ var fs *os.File
+ fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ fs.Sync()
+ fs.Close()
+
+ time.Sleep(200 * time.Millisecond)
+
+ // Make sure receive deletes for both file and sub-directory
+ os.RemoveAll(testSubDir)
+ os.Remove(testFile1)
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ cReceived := createReceived.value()
+ if cReceived != 2 {
+ t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", cReceived, 2)
+ }
+ dReceived := deleteReceived.value()
+ if dReceived != 2 {
+ t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", dReceived, 2)
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+}
+
+func TestFsnotifyRename(t *testing.T) {
+ watcher := newWatcher(t)
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ addWatch(t, watcher, testDir)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ testFile := filepath.Join(testDir, "TestFsnotifyEvents.testfile")
+ testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var renameReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
+ if event.Op&Rename == Rename {
+ renameReceived.increment()
+ }
+ t.Logf("event received: %s", event)
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the fsnotify event queue
+ var f *os.File
+ f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ // Add a watch for testFile
+ addWatch(t, watcher, testFile)
+
+ if err := testRename(testFile, testFileRenamed); err != nil {
+ t.Fatalf("rename failed: %s", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ if renameReceived.value() == 0 {
+ t.Fatal("fsnotify rename events have not been received after 500 ms")
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+
+ os.Remove(testFileRenamed)
+}
+
+func TestFsnotifyRenameToCreate(t *testing.T) {
+ watcher := newWatcher(t)
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Create directory to get file
+ testDirFrom := tempMkdir(t)
+ defer os.RemoveAll(testDirFrom)
+
+ addWatch(t, watcher, testDir)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
+ testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var createReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) || event.Name == filepath.Clean(testFileRenamed) {
+ if event.Op&Create == Create {
+ createReceived.increment()
+ }
+ t.Logf("event received: %s", event)
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the fsnotify event queue
+ var f *os.File
+ f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+ f.Close()
+
+ if err := testRename(testFile, testFileRenamed); err != nil {
+ t.Fatalf("rename failed: %s", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ if createReceived.value() == 0 {
+ t.Fatal("fsnotify create events have not been received after 500 ms")
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+
+ os.Remove(testFileRenamed)
+}
+
+func TestFsnotifyRenameToOverwrite(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("skipping test on %q (os.Rename over existing file does not create event).", runtime.GOOS)
+ }
+
+ watcher := newWatcher(t)
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Create directory to get file
+ testDirFrom := tempMkdir(t)
+ defer os.RemoveAll(testDirFrom)
+
+ testFile := filepath.Join(testDirFrom, "TestFsnotifyEvents.testfile")
+ testFileRenamed := filepath.Join(testDir, "TestFsnotifyEvents.testfileRenamed")
+
+ // Create a file
+ var fr *os.File
+ fr, err := os.OpenFile(testFileRenamed, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ fr.Sync()
+ fr.Close()
+
+ addWatch(t, watcher, testDir)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ var eventReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testFileRenamed) {
+ eventReceived.increment()
+ t.Logf("event received: %s", event)
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the fsnotify event queue
+ var f *os.File
+ f, err = os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+ f.Close()
+
+ if err := testRename(testFile, testFileRenamed); err != nil {
+ t.Fatalf("rename failed: %s", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+ if eventReceived.value() == 0 {
+ t.Fatal("fsnotify events have not been received after 500 ms")
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(2 * time.Second):
+ t.Fatal("event stream was not closed after 2 seconds")
+ }
+
+ os.Remove(testFileRenamed)
+}
+
+func TestRemovalOfWatch(t *testing.T) {
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Create a file before watching directory
+ testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
+ {
+ var f *os.File
+ f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+ f.Close()
+ }
+
+ watcher := newWatcher(t)
+ defer watcher.Close()
+
+ addWatch(t, watcher, testDir)
+ if err := watcher.Remove(testDir); err != nil {
+ t.Fatalf("Could not remove the watch: %v\n", err)
+ }
+
+ go func() {
+ select {
+ case ev := <-watcher.Events:
+ t.Fatalf("We received event: %v\n", ev)
+ case <-time.After(500 * time.Millisecond):
+ t.Log("No event received, as expected.")
+ }
+ }()
+
+ time.Sleep(200 * time.Millisecond)
+ // Modify the file outside of the watched dir
+ f, err := os.Open(testFileAlreadyExists)
+ if err != nil {
+ t.Fatalf("Open test file failed: %s", err)
+ }
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+ if err := os.Chmod(testFileAlreadyExists, 0700); err != nil {
+ t.Fatalf("chmod failed: %s", err)
+ }
+ time.Sleep(400 * time.Millisecond)
+}
+
+func TestFsnotifyAttrib(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("attributes don't work on Windows.")
+ }
+
+ watcher := newWatcher(t)
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Errors {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ testFile := filepath.Join(testDir, "TestFsnotifyAttrib.testfile")
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Events
+ // The modifyReceived counter counts IsModify events that are not IsAttrib,
+ // and the attribReceived counts IsAttrib events (which are also IsModify as
+ // a consequence).
+ var modifyReceived counter
+ var attribReceived counter
+ done := make(chan bool)
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == filepath.Clean(testDir) || event.Name == filepath.Clean(testFile) {
+ if event.Op&Write == Write {
+ modifyReceived.increment()
+ }
+ if event.Op&Chmod == Chmod {
+ attribReceived.increment()
+ }
+ t.Logf("event received: %s", event)
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ done <- true
+ }()
+
+ // Create a file
+ // This should add at least one event to the fsnotify event queue
+ var f *os.File
+ f, err := os.OpenFile(testFile, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+
+ f.WriteString("data")
+ f.Sync()
+ f.Close()
+
+ // Add a watch for testFile
+ addWatch(t, watcher, testFile)
+
+ if err := os.Chmod(testFile, 0700); err != nil {
+ t.Fatalf("chmod failed: %s", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ // Creating/writing a file changes also the mtime, so IsAttrib should be set to true here
+ time.Sleep(500 * time.Millisecond)
+ if modifyReceived.value() != 0 {
+ t.Fatal("received an unexpected modify event when creating a test file")
+ }
+ if attribReceived.value() == 0 {
+ t.Fatal("fsnotify attribute events have not received after 500 ms")
+ }
+
+ // Modifying the contents of the file does not set the attrib flag (although eg. the mtime
+ // might have been modified).
+ modifyReceived.reset()
+ attribReceived.reset()
+
+ f, err = os.OpenFile(testFile, os.O_WRONLY, 0)
+ if err != nil {
+ t.Fatalf("reopening test file failed: %s", err)
+ }
+
+ f.WriteString("more data")
+ f.Sync()
+ f.Close()
+
+ time.Sleep(500 * time.Millisecond)
+
+ if modifyReceived.value() != 1 {
+ t.Fatal("didn't receive a modify event after changing test file contents")
+ }
+
+ if attribReceived.value() != 0 {
+ t.Fatal("did receive an unexpected attrib event after changing test file contents")
+ }
+
+ modifyReceived.reset()
+ attribReceived.reset()
+
+ // Doing a chmod on the file should trigger an event with the "attrib" flag set (the contents
+ // of the file are not changed though)
+ if err := os.Chmod(testFile, 0600); err != nil {
+ t.Fatalf("chmod failed: %s", err)
+ }
+
+ time.Sleep(500 * time.Millisecond)
+
+ if attribReceived.value() != 1 {
+ t.Fatal("didn't receive an attribute change after 500ms")
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ select {
+ case <-done:
+ t.Log("event channel closed")
+ case <-time.After(1e9):
+ t.Fatal("event stream was not closed after 1 second")
+ }
+
+ os.Remove(testFile)
+}
+
+func TestFsnotifyClose(t *testing.T) {
+ watcher := newWatcher(t)
+ watcher.Close()
+
+ var done int32
+ go func() {
+ watcher.Close()
+ atomic.StoreInt32(&done, 1)
+ }()
+
+ time.Sleep(50e6) // 50 ms
+ if atomic.LoadInt32(&done) == 0 {
+ t.Fatal("double Close() test failed: second Close() call didn't return")
+ }
+
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ if err := watcher.Add(testDir); err == nil {
+ t.Fatal("expected error on Watch() after Close(), got nil")
+ }
+}
+
+func TestFsnotifyFakeSymlink(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("symlinks don't work on Windows.")
+ }
+
+ watcher := newWatcher(t)
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ var errorsReceived counter
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for errors := range watcher.Errors {
+ t.Logf("Received error: %s", errors)
+ errorsReceived.increment()
+ }
+ }()
+
+ // Count the CREATE events received
+ var createEventsReceived, otherEventsReceived counter
+ go func() {
+ for ev := range watcher.Events {
+ t.Logf("event received: %s", ev)
+ if ev.Op&Create == Create {
+ createEventsReceived.increment()
+ } else {
+ otherEventsReceived.increment()
+ }
+ }
+ }()
+
+ addWatch(t, watcher, testDir)
+
+ if err := os.Symlink(filepath.Join(testDir, "zzz"), filepath.Join(testDir, "zzznew")); err != nil {
+ t.Fatalf("Failed to create bogus symlink: %s", err)
+ }
+ t.Logf("Created bogus symlink")
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+
+ // Should not be error, just no events for broken links (watching nothing)
+ if errorsReceived.value() > 0 {
+ t.Fatal("fsnotify errors have been received.")
+ }
+ if otherEventsReceived.value() > 0 {
+ t.Fatal("fsnotify other events received on the broken link")
+ }
+
+ // Except for 1 create event (for the link itself)
+ if createEventsReceived.value() == 0 {
+ t.Fatal("fsnotify create events were not received after 500 ms")
+ }
+ if createEventsReceived.value() > 1 {
+ t.Fatal("fsnotify more create events received than expected")
+ }
+
+ // Try closing the fsnotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+}
+
+func TestCyclicSymlink(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Skip("symlinks don't work on Windows.")
+ }
+
+ watcher := newWatcher(t)
+
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ link := path.Join(testDir, "link")
+ if err := os.Symlink(".", link); err != nil {
+ t.Fatalf("could not make symlink: %v", err)
+ }
+ addWatch(t, watcher, testDir)
+
+ var createEventsReceived counter
+ go func() {
+ for ev := range watcher.Events {
+ if ev.Op&Create == Create {
+ createEventsReceived.increment()
+ }
+ }
+ }()
+
+ if err := os.Remove(link); err != nil {
+ t.Fatalf("Error removing link: %v", err)
+ }
+
+ // It would be nice to be able to expect a delete event here, but kqueue has
+ // no way for us to get events on symlinks themselves, because opening them
+ // opens an fd to the file to which they point.
+
+ if err := ioutil.WriteFile(link, []byte("foo"), 0700); err != nil {
+ t.Fatalf("could not make symlink: %v", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
+ time.Sleep(500 * time.Millisecond)
+
+ if got := createEventsReceived.value(); got == 0 {
+ t.Errorf("want at least 1 create event got %v", got)
+ }
+
+ watcher.Close()
+}
+
+// TestConcurrentRemovalOfWatch tests that concurrent calls to RemoveWatch do not race.
+// See https://codereview.appspot.com/103300045/
+// go test -test.run=TestConcurrentRemovalOfWatch -test.cpu=1,1,1,1,1 -race
+func TestConcurrentRemovalOfWatch(t *testing.T) {
+ if runtime.GOOS != "darwin" {
+ t.Skip("regression test for race only present on darwin")
+ }
+
+ // Create directory to watch
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ // Create a file before watching directory
+ testFileAlreadyExists := filepath.Join(testDir, "TestFsnotifyEventsExisting.testfile")
+ {
+ var f *os.File
+ f, err := os.OpenFile(testFileAlreadyExists, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ f.Sync()
+ f.Close()
+ }
+
+ watcher := newWatcher(t)
+ defer watcher.Close()
+
+ addWatch(t, watcher, testDir)
+
+ // Test that RemoveWatch can be invoked concurrently, with no data races.
+ removed1 := make(chan struct{})
+ go func() {
+ defer close(removed1)
+ watcher.Remove(testDir)
+ }()
+ removed2 := make(chan struct{})
+ go func() {
+ close(removed2)
+ watcher.Remove(testDir)
+ }()
+ <-removed1
+ <-removed2
+}
+
+func TestClose(t *testing.T) {
+ // Regression test for #59 bad file descriptor from Close
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ watcher := newWatcher(t)
+ if err := watcher.Add(testDir); err != nil {
+ t.Fatalf("Expected no error on Add, got %v", err)
+ }
+ err := watcher.Close()
+ if err != nil {
+ t.Fatalf("Expected no error on Close, got %v.", err)
+ }
+}
+
+// TestRemoveWithClose tests if one can handle Remove events and, at the same
+// time, close Watcher object without any data races.
+func TestRemoveWithClose(t *testing.T) {
+ testDir := tempMkdir(t)
+ defer os.RemoveAll(testDir)
+
+ const fileN = 200
+ tempFiles := make([]string, 0, fileN)
+ for i := 0; i < fileN; i++ {
+ tempFiles = append(tempFiles, tempMkFile(t, testDir))
+ }
+ watcher := newWatcher(t)
+ if err := watcher.Add(testDir); err != nil {
+ t.Fatalf("Expected no error on Add, got %v", err)
+ }
+ startC, stopC := make(chan struct{}), make(chan struct{})
+ errC := make(chan error)
+ go func() {
+ for {
+ select {
+ case <-watcher.Errors:
+ case <-watcher.Events:
+ case <-stopC:
+ return
+ }
+ }
+ }()
+ go func() {
+ <-startC
+ for _, fileName := range tempFiles {
+ os.Remove(fileName)
+ }
+ }()
+ go func() {
+ <-startC
+ errC <- watcher.Close()
+ }()
+ close(startC)
+ defer close(stopC)
+ if err := <-errC; err != nil {
+ t.Fatalf("Expected no error on Close, got %v.", err)
+ }
+}
+
+func testRename(file1, file2 string) error {
+ switch runtime.GOOS {
+ case "windows", "plan9":
+ return os.Rename(file1, file2)
+ default:
+ cmd := exec.Command("mv", file1, file2)
+ return cmd.Run()
+ }
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/common_test.go b/vendor/gopkg.in/throttled/throttled.v1/common_test.go
new file mode 100644
index 000000000..ddb57fb1c
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/common_test.go
@@ -0,0 +1,65 @@
+package throttled
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "sync"
+ "time"
+
+ "github.com/PuerkitoBio/boom/commands"
+)
+
+type stats struct {
+ sync.Mutex
+ ok int
+ dropped int
+ ts []time.Time
+
+ body func()
+}
+
+func (s *stats) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if s.body != nil {
+ s.body()
+ }
+ s.Lock()
+ defer s.Unlock()
+ s.ts = append(s.ts, time.Now())
+ s.ok++
+ w.WriteHeader(200)
+}
+
+func (s *stats) DeniedHTTP(w http.ResponseWriter, r *http.Request) {
+ s.Lock()
+ defer s.Unlock()
+ s.dropped++
+ w.WriteHeader(deniedStatus)
+}
+
+func (s *stats) Stats() (int, int, []time.Time) {
+ s.Lock()
+ defer s.Unlock()
+ return s.ok, s.dropped, s.ts
+}
+
+func runTest(h http.Handler, b ...commands.Boom) []*commands.Report {
+ srv := httptest.NewServer(h)
+ defer srv.Close()
+
+ var rpts []*commands.Report
+ var wg sync.WaitGroup
+ var mu sync.Mutex
+ wg.Add(len(b))
+ for i, bo := range b {
+ bo.Req.Url = srv.URL + fmt.Sprintf("/%d", i)
+ go func(bo commands.Boom) {
+ mu.Lock()
+ defer mu.Unlock()
+ rpts = append(rpts, bo.Run())
+ wg.Done()
+ }(bo)
+ }
+ wg.Wait()
+ return rpts
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/delayer_test.go b/vendor/gopkg.in/throttled/throttled.v1/delayer_test.go
new file mode 100644
index 000000000..822978e5d
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/delayer_test.go
@@ -0,0 +1,65 @@
+package throttled
+
+import (
+ "testing"
+ "time"
+)
+
+func TestDelayer(t *testing.T) {
+ cases := []struct {
+ in Delayer
+ out time.Duration
+ }{
+ 0: {PerSec(1), time.Second},
+ 1: {PerSec(2), 500 * time.Millisecond},
+ 2: {PerSec(4), 250 * time.Millisecond},
+ 3: {PerSec(5), 200 * time.Millisecond},
+ 4: {PerSec(10), 100 * time.Millisecond},
+ 5: {PerSec(100), 10 * time.Millisecond},
+ 6: {PerSec(3), 333333333 * time.Nanosecond},
+ 7: {PerMin(1), time.Minute},
+ 8: {PerMin(2), 30 * time.Second},
+ 9: {PerMin(4), 15 * time.Second},
+ 10: {PerMin(5), 12 * time.Second},
+ 11: {PerMin(10), 6 * time.Second},
+ 12: {PerMin(60), time.Second},
+ 13: {PerHour(1), time.Hour},
+ 14: {PerHour(2), 30 * time.Minute},
+ 15: {PerHour(4), 15 * time.Minute},
+ 16: {PerHour(60), time.Minute},
+ 17: {PerHour(120), 30 * time.Second},
+ 18: {D(time.Second), time.Second},
+ 19: {D(5 * time.Minute), 5 * time.Minute},
+ 20: {PerSec(200), 5 * time.Millisecond},
+ 21: {PerDay(24), time.Hour},
+ }
+ for i, c := range cases {
+ got := c.in.Delay()
+ if got != c.out {
+ t.Errorf("%d: expected %s, got %s", i, c.out, got)
+ }
+ }
+}
+
+func TestQuota(t *testing.T) {
+ cases := []struct {
+ q Quota
+ reqs int
+ win time.Duration
+ }{
+ 0: {PerSec(10), 10, time.Second},
+ 1: {PerMin(30), 30, time.Minute},
+ 2: {PerHour(124), 124, time.Hour},
+ 3: {PerDay(1), 1, 24 * time.Hour},
+ 4: {Q{148, 17 * time.Second}, 148, 17 * time.Second},
+ }
+ for i, c := range cases {
+ r, w := c.q.Quota()
+ if r != c.reqs {
+ t.Errorf("%d: expected %d requests, got %d", i, c.reqs, r)
+ }
+ if w != c.win {
+ t.Errorf("%d: expected %s window, got %s", i, c.win, w)
+ }
+ }
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/doc.go b/vendor/gopkg.in/throttled/throttled.v1/doc.go
index acf5213b0..a2c8d4c75 100644
--- a/vendor/gopkg.in/throttled/throttled.v1/doc.go
+++ b/vendor/gopkg.in/throttled/throttled.v1/doc.go
@@ -74,4 +74,4 @@
// The BSD 3-clause license. Copyright (c) 2014 Martin Angers and Contributors.
// http://opensource.org/licenses/BSD-3-Clause
//
-package throttled
+package throttled // import "gopkg.in/throttled/throttled.v1"
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/README.md b/vendor/gopkg.in/throttled/throttled.v1/examples/README.md
new file mode 100644
index 000000000..6b12dad20
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/README.md
@@ -0,0 +1,12 @@
+# Examples
+
+This directory contains examples for all the throttlers implemented by the throttled package, as well as an example of a custom limiter.
+
+* custom/ : implements a custom limiter that allows requests to path /a on even seconds, and on path /b on odd seconds.
+* interval-many/ : implements a common interval throttler to control two different handlers, one for path /a and another for path /b, so that requests to any one of the handlers go through at the specified interval.
+* interval-vary/ : implements an interval throttler that varies by path, so that requests to each different path goes through at the specified interval.
+* interval/ : implements an interval throttler so that any request goes through at the specified interval, regardless of path or any other criteria.
+* memstats/ : implements a memory-usage throttler that limits access based on current memory statistics.
+* rate-limit/ : implements a rate-limiter throttler that varies by path, so that the number of requests allowed are counted based on the requested path.
+
+Each example app supports a number of command-line flags. Run the example with the -h flag to display usage and defaults.
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/custom/main.go b/vendor/gopkg.in/throttled/throttled.v1/examples/custom/main.go
new file mode 100644
index 000000000..b3fe993e8
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/custom/main.go
@@ -0,0 +1,90 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "math/rand"
+ "net/http"
+ "sync"
+ "time"
+
+ "gopkg.in/throttled/throttled.v1"
+)
+
+var (
+ delayRes = flag.Duration("delay-response", 0, "delay the response by a random duration between 0 and this value")
+ output = flag.String("output", "v", "type of output, one of `v`erbose, `q`uiet, `ok`-only, `ko`-only")
+)
+
+// Custom limiter: allow requests to the /a path on even seconds only, and
+// allow access to the /b path on odd seconds only.
+//
+// Yes this is absurd. A more realistic case could be to allow requests to some
+// contest page only during a limited time window.
+type customLimiter struct {
+}
+
+func (c *customLimiter) Start() {
+ // No-op
+}
+
+func (c *customLimiter) Limit(w http.ResponseWriter, r *http.Request) (<-chan bool, error) {
+ s := time.Now().Second()
+ ch := make(chan bool, 1)
+ ok := (r.URL.Path == "/a" && s%2 == 0) || (r.URL.Path == "/b" && s%2 != 0)
+ ch <- ok
+ if *output == "v" {
+ log.Printf("Custom Limiter: Path=%s, Second=%d; ok? %v", r.URL.Path, s, ok)
+ }
+ return ch, nil
+}
+
+func main() {
+ flag.Parse()
+
+ var h http.Handler
+ var ok, ko int
+ var mu sync.Mutex
+
+ // Keep the start time to print since-time
+ start := time.Now()
+ // Create the custom throttler using our custom limiter
+ t := throttled.Custom(&customLimiter{})
+ // Set its denied handler
+ t.DeniedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ko" {
+ log.Printf("KO: %s", time.Since(start))
+ }
+ throttled.DefaultDeniedHandler.ServeHTTP(w, r)
+ mu.Lock()
+ defer mu.Unlock()
+ ko++
+ })
+ // Throttle the OK handler
+ rand.Seed(time.Now().Unix())
+ h = t.Throttle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ok" {
+ log.Printf("ok: %s", time.Since(start))
+ }
+ if *delayRes > 0 {
+ wait := time.Duration(rand.Intn(int(*delayRes)))
+ time.Sleep(wait)
+ }
+ w.WriteHeader(200)
+ mu.Lock()
+ defer mu.Unlock()
+ ok++
+ }))
+
+ // Print stats once in a while
+ go func() {
+ for _ = range time.Tick(10 * time.Second) {
+ mu.Lock()
+ log.Printf("ok: %d, ko: %d", ok, ko)
+ mu.Unlock()
+ }
+ }()
+ fmt.Println("server listening on port 9000")
+ http.ListenAndServe(":9000", h)
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/interval-many/main.go b/vendor/gopkg.in/throttled/throttled.v1/examples/interval-many/main.go
new file mode 100644
index 000000000..51a4ca023
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/interval-many/main.go
@@ -0,0 +1,79 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "math/rand"
+ "net/http"
+ "sync"
+ "time"
+
+ "gopkg.in/throttled/throttled.v1"
+)
+
+var (
+ delay = flag.Duration("delay", 200*time.Millisecond, "delay between calls")
+ bursts = flag.Int("bursts", 10, "number of bursts allowed")
+ delayRes = flag.Duration("delay-response", 0, "delay the response by a random duration between 0 and this value")
+ output = flag.String("output", "v", "type of output, one of `v`erbose, `q`uiet, `ok`-only, `ko`-only")
+)
+
+func main() {
+ flag.Parse()
+
+ var ok, ko int
+ var mu sync.Mutex
+
+ // Keep start time to log since-time
+ start := time.Now()
+
+ // Create the interval throttle
+ t := throttled.Interval(throttled.D(*delay), *bursts, nil, 0)
+ // Set its denied handler
+ t.DeniedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ko" {
+ log.Printf("%s: KO: %s", r.URL.Path, time.Since(start))
+ }
+ throttled.DefaultDeniedHandler.ServeHTTP(w, r)
+ mu.Lock()
+ defer mu.Unlock()
+ ko++
+ })
+ // Create OK handlers
+ rand.Seed(time.Now().Unix())
+ makeHandler := func(ix int) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ok" {
+ log.Printf("handler %d: %s: ok: %s", ix, r.URL.Path, time.Since(start))
+ }
+ if *delayRes > 0 {
+ wait := time.Duration(rand.Intn(int(*delayRes)))
+ time.Sleep(wait)
+ }
+ w.WriteHeader(200)
+ mu.Lock()
+ defer mu.Unlock()
+ ok++
+ })
+ }
+ // Throttle them using the same interval throttler
+ h1 := t.Throttle(makeHandler(1))
+ h2 := t.Throttle(makeHandler(2))
+
+ // Handle two paths
+ mux := http.NewServeMux()
+ mux.Handle("/a", h1)
+ mux.Handle("/b", h2)
+
+ // Print stats once in a while
+ go func() {
+ for _ = range time.Tick(10 * time.Second) {
+ mu.Lock()
+ log.Printf("ok: %d, ko: %d", ok, ko)
+ mu.Unlock()
+ }
+ }()
+ fmt.Println("server listening on port 9000")
+ http.ListenAndServe(":9000", mux)
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/main.go b/vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/main.go
new file mode 100644
index 000000000..f43cdc122
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/main.go
@@ -0,0 +1,74 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "math/rand"
+ "net/http"
+ "sync"
+ "time"
+
+ "gopkg.in/throttled/throttled.v1"
+)
+
+var (
+ delay = flag.Duration("delay", 200*time.Millisecond, "delay between calls")
+ bursts = flag.Int("bursts", 10, "number of bursts allowed")
+ maxkeys = flag.Int("max-keys", 1000, "maximum number of keys")
+ delayRes = flag.Duration("delay-response", 0, "delay the response by a random duration between 0 and this value")
+ output = flag.String("output", "v", "type of output, one of `v`erbose, `q`uiet, `ok`-only, `ko`-only")
+)
+
+func main() {
+ flag.Parse()
+
+ var h http.Handler
+ var ok, ko int
+ var mu sync.Mutex
+
+ // Keep the start time to print since-time
+ start := time.Now()
+
+ // Create the interval throttler
+ t := throttled.Interval(throttled.D(*delay), *bursts, &throttled.VaryBy{
+ Path: true,
+ }, *maxkeys)
+ // Set the denied handler
+ t.DeniedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ko" {
+ log.Printf("KO: %s", time.Since(start))
+ }
+ throttled.DefaultDeniedHandler.ServeHTTP(w, r)
+ mu.Lock()
+ defer mu.Unlock()
+ ko++
+ })
+
+ // Throttle the OK handler
+ rand.Seed(time.Now().Unix())
+ h = t.Throttle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ok" {
+ log.Printf("%s: ok: %s", r.URL.Path, time.Since(start))
+ }
+ if *delayRes > 0 {
+ wait := time.Duration(rand.Intn(int(*delayRes)))
+ time.Sleep(wait)
+ }
+ w.WriteHeader(200)
+ mu.Lock()
+ defer mu.Unlock()
+ ok++
+ }))
+
+ // Print stats once in a while
+ go func() {
+ for _ = range time.Tick(10 * time.Second) {
+ mu.Lock()
+ log.Printf("ok: %d, ko: %d", ok, ko)
+ mu.Unlock()
+ }
+ }()
+ fmt.Println("server listening on port 9000")
+ http.ListenAndServe(":9000", h)
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/siege-urls b/vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/siege-urls
new file mode 100644
index 000000000..9a2d0d312
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/interval-vary/siege-urls
@@ -0,0 +1,4 @@
+http://localhost:9000/a
+http://localhost:9000/b
+http://localhost:9000/c
+
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/interval/main.go b/vendor/gopkg.in/throttled/throttled.v1/examples/interval/main.go
new file mode 100644
index 000000000..ef8ee2cb8
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/interval/main.go
@@ -0,0 +1,69 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "math/rand"
+ "net/http"
+ "sync"
+ "time"
+
+ "gopkg.in/throttled/throttled.v1"
+)
+
+var (
+ delay = flag.Duration("delay", 200*time.Millisecond, "delay between calls")
+ bursts = flag.Int("bursts", 10, "number of bursts allowed")
+ delayRes = flag.Duration("delay-response", 0, "delay the response by a random duration between 0 and this value")
+ output = flag.String("output", "v", "type of output, one of `v`erbose, `q`uiet, `ok`-only, `ko`-only")
+)
+
+func main() {
+ flag.Parse()
+
+ var h http.Handler
+ var ok, ko int
+ var mu sync.Mutex
+
+ // Keep the start time to print since-time
+ start := time.Now()
+ // Create the interval throttler
+ t := throttled.Interval(throttled.D(*delay), *bursts, nil, 0)
+ // Set its denied handler
+ t.DeniedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ko" {
+ log.Printf("KO: %s", time.Since(start))
+ }
+ throttled.DefaultDeniedHandler.ServeHTTP(w, r)
+ mu.Lock()
+ defer mu.Unlock()
+ ko++
+ })
+ // Throttle the OK handler
+ rand.Seed(time.Now().Unix())
+ h = t.Throttle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ok" {
+ log.Printf("ok: %s", time.Since(start))
+ }
+ if *delayRes > 0 {
+ wait := time.Duration(rand.Intn(int(*delayRes)))
+ time.Sleep(wait)
+ }
+ w.WriteHeader(200)
+ mu.Lock()
+ defer mu.Unlock()
+ ok++
+ }))
+
+ // Print stats once in a while
+ go func() {
+ for _ = range time.Tick(10 * time.Second) {
+ mu.Lock()
+ log.Printf("ok: %d, ko: %d", ok, ko)
+ mu.Unlock()
+ }
+ }()
+ fmt.Println("server listening on port 9000")
+ http.ListenAndServe(":9000", h)
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/memstats/main.go b/vendor/gopkg.in/throttled/throttled.v1/examples/memstats/main.go
new file mode 100644
index 000000000..50d4cc69b
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/memstats/main.go
@@ -0,0 +1,97 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "math/rand"
+ "net/http"
+ "runtime"
+ "sync"
+ "time"
+
+ "gopkg.in/throttled/throttled.v1"
+)
+
+var (
+ numgc = flag.Int("gc", 0, "number of GC runs")
+ mallocs = flag.Int("mallocs", 0, "number of mallocs")
+ total = flag.Int("total", 0, "total number of bytes allocated")
+ allocs = flag.Int("allocs", 0, "number of bytes allocated")
+ refrate = flag.Duration("refresh", 0, "refresh rate of the memory stats")
+ delayRes = flag.Duration("delay-response", 0, "delay the response by a random duration between 0 and this value")
+ output = flag.String("output", "v", "type of output, one of `v`erbose, `q`uiet, `ok`-only, `ko`-only")
+)
+
+func main() {
+ flag.Parse()
+
+ var h http.Handler
+ var ok, ko int
+ var mu sync.Mutex
+
+ // Keep the start time to print since-time
+ start := time.Now()
+ // Create the thresholds struct
+ thresh := throttled.MemThresholds(&runtime.MemStats{
+ NumGC: uint32(*numgc),
+ Mallocs: uint64(*mallocs),
+ TotalAlloc: uint64(*total),
+ Alloc: uint64(*allocs),
+ })
+ if *output != "q" {
+ log.Printf("thresholds: NumGC: %d, Mallocs: %d, Alloc: %dKb, Total: %dKb", thresh.NumGC, thresh.Mallocs, thresh.Alloc/1024, thresh.TotalAlloc/1024)
+ }
+ // Create the MemStats throttler
+ t := throttled.MemStats(thresh, *refrate)
+ // Set its denied handler
+ t.DeniedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ko" {
+ log.Printf("KO: %s", time.Since(start))
+ }
+ throttled.DefaultDeniedHandler.ServeHTTP(w, r)
+ mu.Lock()
+ defer mu.Unlock()
+ ko++
+ })
+
+ // Throttle the OK handler
+ rand.Seed(time.Now().Unix())
+ h = t.Throttle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ok" {
+ log.Printf("ok: %s", time.Since(start))
+ }
+ if *delayRes > 0 {
+ wait := time.Duration(rand.Intn(int(*delayRes)))
+ time.Sleep(wait)
+ }
+ // Read the whole file in memory, to actually use 64Kb (instead of streaming to w)
+ b, err := ioutil.ReadFile("test-file")
+ if err != nil {
+ throttled.Error(w, r, err)
+ return
+ }
+ _, err = w.Write(b)
+ if err != nil {
+ throttled.Error(w, r, err)
+ }
+ mu.Lock()
+ defer mu.Unlock()
+ ok++
+ }))
+
+ // Print stats once in a while
+ go func() {
+ var mem runtime.MemStats
+ for _ = range time.Tick(10 * time.Second) {
+ mu.Lock()
+ runtime.ReadMemStats(&mem)
+ log.Printf("ok: %d, ko: %d", ok, ko)
+ log.Printf("TotalAllocs: %d Kb, Allocs: %d Kb, Mallocs: %d, NumGC: %d", mem.TotalAlloc/1024, mem.Alloc/1024, mem.Mallocs, mem.NumGC)
+ mu.Unlock()
+ }
+ }()
+ fmt.Println("server listening on port 9000")
+ http.ListenAndServe(":9000", h)
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/memstats/test-file b/vendor/gopkg.in/throttled/throttled.v1/examples/memstats/test-file
new file mode 100644
index 000000000..c97c12f9b
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/memstats/test-file
Binary files differ
diff --git a/vendor/gopkg.in/throttled/throttled.v1/examples/rate-limit/main.go b/vendor/gopkg.in/throttled/throttled.v1/examples/rate-limit/main.go
new file mode 100644
index 000000000..b00119f63
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/examples/rate-limit/main.go
@@ -0,0 +1,101 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "math/rand"
+ "net/http"
+ "sync"
+ "time"
+
+ "github.com/garyburd/redigo/redis"
+ "gopkg.in/throttled/throttled.v1"
+ "gopkg.in/throttled/throttled.v1/store"
+)
+
+var (
+ requests = flag.Int("requests", 10, "number of requests allowed in the time window")
+ window = flag.Duration("window", time.Minute, "time window for the limit of requests")
+ storeType = flag.String("store", "mem", "store to use, one of `mem` or `redis` (on default localhost port)")
+ delayRes = flag.Duration("delay-response", 0, "delay the response by a random duration between 0 and this value")
+ output = flag.String("output", "v", "type of output, one of `v`erbose, `q`uiet, `ok`-only, `ko`-only")
+)
+
+func main() {
+ flag.Parse()
+
+ var h http.Handler
+ var ok, ko int
+ var mu sync.Mutex
+ var st throttled.Store
+
+ // Keep the start time to print since-time
+ start := time.Now()
+ // Create the rate-limit store
+ switch *storeType {
+ case "mem":
+ st = store.NewMemStore(0)
+ case "redis":
+ st = store.NewRedisStore(setupRedis(), "throttled:", 0)
+ default:
+ log.Fatalf("unsupported store: %s", *storeType)
+ }
+ // Create the rate-limit throttler, varying on path
+ t := throttled.RateLimit(throttled.Q{Requests: *requests, Window: *window}, &throttled.VaryBy{
+ Path: true,
+ }, st)
+
+ // Set its denied handler
+ t.DeniedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ko" {
+ log.Printf("KO: %s", time.Since(start))
+ }
+ throttled.DefaultDeniedHandler.ServeHTTP(w, r)
+ mu.Lock()
+ defer mu.Unlock()
+ ko++
+ })
+
+ // Throttle the OK handler
+ rand.Seed(time.Now().Unix())
+ h = t.Throttle(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if *output == "v" || *output == "ok" {
+ log.Printf("ok: %s", time.Since(start))
+ }
+ if *delayRes > 0 {
+ wait := time.Duration(rand.Intn(int(*delayRes)))
+ time.Sleep(wait)
+ }
+ w.WriteHeader(200)
+ mu.Lock()
+ defer mu.Unlock()
+ ok++
+ }))
+
+ // Print stats once in a while
+ go func() {
+ for _ = range time.Tick(10 * time.Second) {
+ mu.Lock()
+ log.Printf("ok: %d, ko: %d", ok, ko)
+ mu.Unlock()
+ }
+ }()
+ fmt.Println("server listening on port 9000")
+ http.ListenAndServe(":9000", h)
+}
+
+func setupRedis() *redis.Pool {
+ pool := &redis.Pool{
+ MaxIdle: 3,
+ IdleTimeout: 30 * time.Second,
+ Dial: func() (redis.Conn, error) {
+ return redis.Dial("tcp", ":6379")
+ },
+ TestOnBorrow: func(c redis.Conn, t time.Time) error {
+ _, err := c.Do("PING")
+ return err
+ },
+ }
+ return pool
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/interval_test.go b/vendor/gopkg.in/throttled/throttled.v1/interval_test.go
new file mode 100644
index 000000000..bc584e134
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/interval_test.go
@@ -0,0 +1,114 @@
+package throttled
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/PuerkitoBio/boom/commands"
+)
+
+func TestInterval(t *testing.T) {
+ if testing.Short() {
+ t.Skip()
+ }
+ cases := []struct {
+ n int
+ c int
+ rps int
+ bursts int
+ }{
+ 0: {60, 10, 20, 100},
+ 1: {300, 20, 100, 100},
+ 2: {10, 10, 1, 10},
+ 3: {1000, 100, 1000, 100},
+ }
+ for i, c := range cases {
+ // Setup the stats handler
+ st := &stats{}
+ // Create the throttler
+ th := Interval(PerSec(c.rps), c.bursts, nil, 0)
+ th.DeniedHandler = http.HandlerFunc(st.DeniedHTTP)
+ b := commands.Boom{
+ Req: &commands.ReqOpts{},
+ N: c.n,
+ C: c.c,
+ Output: "quiet",
+ }
+ // Run the test
+ rpts := runTest(th.Throttle(st), b)
+ // Assert results
+ for _, rpt := range rpts {
+ assertRPS(t, i, c.rps, rpt)
+ }
+ assertStats(t, i, st, rpts)
+ }
+}
+
+func TestIntervalVary(t *testing.T) {
+ if testing.Short() {
+ t.Skip()
+ }
+ cases := []struct {
+ n int
+ c int
+ urls int
+ rps int
+ bursts int
+ }{
+ 0: {60, 10, 3, 20, 100},
+ 1: {300, 20, 3, 100, 100},
+ 2: {10, 10, 3, 1, 10},
+ 3: {500, 10, 2, 1000, 100},
+ }
+ for i, c := range cases {
+ // Setup the stats handler
+ st := &stats{}
+ // Create the throttler
+ th := Interval(PerSec(c.rps), c.bursts, nil, 0)
+ th.DeniedHandler = http.HandlerFunc(st.DeniedHTTP)
+ var booms []commands.Boom
+ for j := 0; j < c.urls; j++ {
+ booms = append(booms, commands.Boom{
+ Req: &commands.ReqOpts{},
+ N: c.n,
+ C: c.c,
+ Output: "quiet",
+ })
+ }
+ // Run the test
+ rpts := runTest(th.Throttle(st), booms...)
+ // Assert results
+ for _, rpt := range rpts {
+ assertRPS(t, i, c.rps, rpt)
+ }
+ assertStats(t, i, st, rpts)
+ }
+}
+
+func assertRPS(t *testing.T, ix int, exp int, rpt *commands.Report) {
+ wigglef := 0.2 * float64(exp)
+ if rpt.SuccessRPS < float64(exp)-wigglef || rpt.SuccessRPS > float64(exp)+wigglef {
+ t.Errorf("%d: expected RPS to be around %d, got %f", ix, exp, rpt.SuccessRPS)
+ }
+}
+
+func assertStats(t *testing.T, ix int, st *stats, rpts []*commands.Report) {
+ ok, ko, _ := st.Stats()
+ var twos, fives, max int
+ for _, rpt := range rpts {
+ twos += rpt.StatusCodeDist[200]
+ fives += rpt.StatusCodeDist[deniedStatus]
+ if len(rpt.StatusCodeDist) > max {
+ max = len(rpt.StatusCodeDist)
+ }
+ }
+ if ok != twos {
+ t.Errorf("%d: expected %d status 200, got %d", ix, twos, ok)
+ }
+ if ko != fives {
+ t.Errorf("%d: expected %d status 429, got %d", ix, fives, ok)
+ }
+ if max > 2 {
+ t.Errorf("%d: expected at most 2 different status codes, got %d", ix, max)
+ }
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/memstats_test.go b/vendor/gopkg.in/throttled/throttled.v1/memstats_test.go
new file mode 100644
index 000000000..2b8faa721
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/memstats_test.go
@@ -0,0 +1,64 @@
+package throttled
+
+import (
+ "net/http"
+ "runtime"
+ "testing"
+ "time"
+
+ "github.com/PuerkitoBio/boom/commands"
+)
+
+func TestMemStats(t *testing.T) {
+ if testing.Short() {
+ t.Skip()
+ }
+ cases := []struct {
+ n int
+ c int
+ gc uint32
+ total uint64
+ rate time.Duration
+ }{
+ 0: {1000, 10, 3, 0, 0},
+ 1: {200, 10, 0, 600000, 0},
+ 2: {500, 10, 2, 555555, 10 * time.Millisecond},
+ }
+ for i, c := range cases {
+ // Setup the stats handler
+ st := &stats{}
+ // Create the throttler
+ limit := MemThresholds(&runtime.MemStats{NumGC: c.gc, TotalAlloc: c.total})
+ th := MemStats(limit, c.rate)
+ th.DeniedHandler = http.HandlerFunc(st.DeniedHTTP)
+ // Run the test
+ b := commands.Boom{
+ Req: &commands.ReqOpts{},
+ N: c.n,
+ C: c.c,
+ Output: "quiet",
+ }
+ rpts := runTest(th.Throttle(st), b)
+ // Assert results
+ assertStats(t, i, st, rpts)
+ assertMem(t, i, limit)
+ }
+}
+
+func assertMem(t *testing.T, ix int, limit *runtime.MemStats) {
+ var mem runtime.MemStats
+ runtime.ReadMemStats(&mem)
+ if mem.NumGC < limit.NumGC {
+ t.Errorf("%d: expected gc to be at least %d, got %d", ix, limit.NumGC, mem.NumGC)
+ }
+ if mem.TotalAlloc < limit.TotalAlloc {
+ t.Errorf("%d: expected total alloc to be at least %dKb, got %dKb", ix, limit.TotalAlloc/1024, mem.TotalAlloc/1024)
+ }
+}
+
+func BenchmarkReadMemStats(b *testing.B) {
+ var mem runtime.MemStats
+ for i := 0; i < b.N; i++ {
+ runtime.ReadMemStats(&mem)
+ }
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/misc/pre-commit b/vendor/gopkg.in/throttled/throttled.v1/misc/pre-commit
new file mode 100755
index 000000000..88b61bfde
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/misc/pre-commit
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Copyright 2012 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# git gofmt pre-commit hook
+#
+# To use, store as .git/hooks/pre-commit inside your repository and make sure
+# it has execute permissions.
+#
+# This script does not handle file names that contain spaces.
+
+# golint is purely informational, it doesn't fail with exit code != 0 if it finds something,
+# because it may find a lot of false positives. Just print out its result for information.
+echo "lint result (informational only):"
+echo
+golint .
+
+# go vet returns 1 if an error was found. Exit the hook with this exit code.
+go vet ./...
+vetres=$?
+
+# Check for gofmt problems and report if any.
+gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.go$')
+[ -z "$gofiles" ] && echo "EXIT $vetres" && exit $vetres
+
+unformatted=$(gofmt -l $gofiles)
+[ -z "$unformatted" ] && echo "EXIT $vetres" && exit $vetres
+
+# Some files are not gofmt'd. Print message and fail.
+
+echo >&2 "Go files must be formatted with gofmt. Please run:"
+for fn in $unformatted; do
+ echo >&2 " gofmt -w $PWD/$fn"
+done
+
+echo "EXIT 1"
+exit 1
diff --git a/vendor/gopkg.in/throttled/throttled.v1/rate_test.go b/vendor/gopkg.in/throttled/throttled.v1/rate_test.go
new file mode 100644
index 000000000..67dea74b1
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/rate_test.go
@@ -0,0 +1,101 @@
+package throttled
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "strconv"
+ "testing"
+ "time"
+)
+
+const deniedStatus = 429
+
+// Simple memory store for tests, unsafe for concurrent access
+type mapStore struct {
+ cnt map[string]int
+ ts map[string]time.Time
+}
+
+func newMapStore() *mapStore {
+ return &mapStore{
+ make(map[string]int),
+ make(map[string]time.Time),
+ }
+}
+func (ms *mapStore) Incr(key string, window time.Duration) (int, int, error) {
+ if _, ok := ms.cnt[key]; !ok {
+ return 0, 0, ErrNoSuchKey
+ }
+ ms.cnt[key]++
+ ts := ms.ts[key]
+ return ms.cnt[key], RemainingSeconds(ts, window), nil
+}
+func (ms *mapStore) Reset(key string, win time.Duration) error {
+ ms.cnt[key] = 1
+ ms.ts[key] = time.Now().UTC()
+ return nil
+}
+
+func TestRateLimit(t *testing.T) {
+ quota := Q{5, 5 * time.Second}
+ cases := []struct {
+ limit, remain, reset, status int
+ }{
+ 0: {5, 4, 5, 200},
+ 1: {5, 3, 4, 200},
+ 2: {5, 2, 4, 200},
+ 3: {5, 1, 3, 200},
+ 4: {5, 0, 3, 200},
+ 5: {5, 0, 2, deniedStatus},
+ }
+ // Limit the requests to 2 per second
+ th := Interval(PerSec(2), 0, nil, 0)
+ // Rate limit
+ rl := RateLimit(quota, nil, newMapStore())
+ // Create the stats
+ st := &stats{}
+ // Create the handler
+ h := th.Throttle(rl.Throttle(st))
+
+ // Start the server
+ srv := httptest.NewServer(h)
+ defer srv.Close()
+ for i, c := range cases {
+ callRateLimited(t, i, c.limit, c.remain, c.reset, c.status, srv.URL)
+ }
+ // Wait 3 seconds and call again, should start a new window
+ time.Sleep(3 * time.Second)
+ callRateLimited(t, len(cases), 5, 4, 5, 200, srv.URL)
+}
+
+func callRateLimited(t *testing.T, i, limit, remain, reset, status int, url string) {
+ res, err := http.Get(url)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ // Assert status code
+ if status != res.StatusCode {
+ t.Errorf("%d: expected status %d, got %d", i, status, res.StatusCode)
+ }
+ // Assert headers
+ if v := res.Header.Get("X-RateLimit-Limit"); v != strconv.Itoa(limit) {
+ t.Errorf("%d: expected limit header to be %d, got %s", i, limit, v)
+ }
+ if v := res.Header.Get("X-RateLimit-Remaining"); v != strconv.Itoa(remain) {
+ t.Errorf("%d: expected remain header to be %d, got %s", i, remain, v)
+ }
+ // Allow 1 second wiggle room
+ v := res.Header.Get("X-RateLimit-Reset")
+ vi, _ := strconv.Atoi(v)
+ if vi < reset-1 || vi > reset+1 {
+ t.Errorf("%d: expected reset header to be close to %d, got %d", i, reset, vi)
+ }
+ if status == deniedStatus {
+ v := res.Header.Get("Retry-After")
+ vi, _ := strconv.Atoi(v)
+ if vi < reset-1 || vi > reset+1 {
+ t.Errorf("%d: expected retry after header to be close to %d, got %d", i, reset, vi)
+ }
+ }
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/store/doc.go b/vendor/gopkg.in/throttled/throttled.v1/store/doc.go
index adb4618d3..8e33f2c98 100644
--- a/vendor/gopkg.in/throttled/throttled.v1/store/doc.go
+++ b/vendor/gopkg.in/throttled/throttled.v1/store/doc.go
@@ -1,2 +1,2 @@
// Package store offers a memory-based and a Redis-based throttled.Store implementation.
-package store
+package store // import "gopkg.in/throttled/throttled.v1/store"
diff --git a/vendor/gopkg.in/throttled/throttled.v1/store/mem_test.go b/vendor/gopkg.in/throttled/throttled.v1/store/mem_test.go
new file mode 100644
index 000000000..e8ef8d0da
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/store/mem_test.go
@@ -0,0 +1,43 @@
+package store
+
+import (
+ "testing"
+ "time"
+)
+
+func TestMemStore(t *testing.T) {
+ st := NewMemStore(0)
+ win := time.Second
+
+ // Reset stores a key with count of 1, current timestamp
+ err := st.Reset("k", time.Second)
+ if err != nil {
+ t.Errorf("expected reset to return nil, got %s", err)
+ }
+ cnt, sec1, _ := st.Incr("k", win)
+ if cnt != 2 {
+ t.Errorf("expected reset+incr to set count to 2, got %d", cnt)
+ }
+
+ // Incr increments the key, keeps same timestamp
+ cnt, sec2, err := st.Incr("k", win)
+ if err != nil {
+ t.Errorf("expected 2nd incr to return nil error, got %s", err)
+ }
+ if cnt != 3 {
+ t.Errorf("expected 2nd incr to return 3, got %d", cnt)
+ }
+ if sec1 != sec2 {
+ t.Errorf("expected 2nd incr to return %d secs, got %d", sec1, sec2)
+ }
+
+ // Reset on existing key brings it back to 1, new timestamp
+ err = st.Reset("k", win)
+ if err != nil {
+ t.Errorf("expected reset on existing key to return nil, got %s", err)
+ }
+ cnt, _, _ = st.Incr("k", win)
+ if cnt != 2 {
+ t.Errorf("expected last reset+incr to return 2, got %d", cnt)
+ }
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/store/redis_test.go b/vendor/gopkg.in/throttled/throttled.v1/store/redis_test.go
new file mode 100644
index 000000000..a282d6d25
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/store/redis_test.go
@@ -0,0 +1,66 @@
+package store
+
+import (
+ "testing"
+ "time"
+
+ "github.com/garyburd/redigo/redis"
+)
+
+func getPool() *redis.Pool {
+ pool := &redis.Pool{
+ MaxIdle: 3,
+ IdleTimeout: 30 * time.Second,
+ Dial: func() (redis.Conn, error) {
+ return redis.Dial("tcp", ":6379")
+ },
+ TestOnBorrow: func(c redis.Conn, t time.Time) error {
+ _, err := c.Do("PING")
+ return err
+ },
+ }
+ return pool
+}
+
+func TestRedisStore(t *testing.T) {
+ pool := getPool()
+ c := pool.Get()
+ if _, err := redis.String(c.Do("PING")); err != nil {
+ c.Close()
+ t.Skip("redis server not available on localhost port 6379")
+ }
+ st := NewRedisStore(pool, "throttled:", 1)
+ win := 2 * time.Second
+
+ // Incr increments the key, even if it does not exist
+ cnt, secs, err := st.Incr("k", win)
+ if err != nil {
+ t.Errorf("expected initial incr to return nil error, got %s", err)
+ }
+ if cnt != 1 {
+ t.Errorf("expected initial incr to return 1, got %d", cnt)
+ }
+ if secs != int(win.Seconds()) {
+ t.Errorf("expected initial incr to return %d secs, got %d", int(win.Seconds()), secs)
+ }
+
+ // Waiting a second diminishes the remaining seconds
+ time.Sleep(time.Second)
+ _, sec2, _ := st.Incr("k", win)
+ if sec2 != secs-1 {
+ t.Errorf("expected 2nd incr after a 1s sleep to return %d secs, got %d", secs-1, sec2)
+ }
+
+ // Waiting a second so the key expires, Incr should set back to 1, initial secs
+ time.Sleep(1100 * time.Millisecond)
+ cnt, sec3, err := st.Incr("k", win)
+ if err != nil {
+ t.Errorf("expected last incr to return nil error, got %s", err)
+ }
+ if cnt != 1 {
+ t.Errorf("expected last incr to return 1, got %d", cnt)
+ }
+ if sec3 != int(win.Seconds()) {
+ t.Errorf("expected last incr to return %d secs, got %d", int(win.Seconds()), sec3)
+ }
+}
diff --git a/vendor/gopkg.in/throttled/throttled.v1/varyby_test.go b/vendor/gopkg.in/throttled/throttled.v1/varyby_test.go
new file mode 100644
index 000000000..91b7ae0ae
--- /dev/null
+++ b/vendor/gopkg.in/throttled/throttled.v1/varyby_test.go
@@ -0,0 +1,56 @@
+package throttled
+
+import (
+ "net/http"
+ "net/url"
+ "testing"
+)
+
+func TestVaryBy(t *testing.T) {
+ u, err := url.Parse("http://localhost/test/path?q=s")
+ if err != nil {
+ panic(err)
+ }
+ ck := &http.Cookie{Name: "ssn", Value: "test"}
+ cases := []struct {
+ vb *VaryBy
+ r *http.Request
+ k string
+ }{
+ 0: {nil, &http.Request{}, ""},
+ 1: {&VaryBy{RemoteAddr: true}, &http.Request{RemoteAddr: "::"}, "::\n"},
+ 2: {
+ &VaryBy{Method: true, Path: true},
+ &http.Request{Method: "POST", URL: u},
+ "post\n/test/path\n",
+ },
+ 3: {
+ &VaryBy{Headers: []string{"Content-length"}},
+ &http.Request{Header: http.Header{"Content-Type": []string{"text/plain"}, "Content-Length": []string{"123"}}},
+ "123\n",
+ },
+ 4: {
+ &VaryBy{Separator: ",", Method: true, Headers: []string{"Content-length"}, Params: []string{"q", "user"}},
+ &http.Request{Method: "GET", Header: http.Header{"Content-Type": []string{"text/plain"}, "Content-Length": []string{"123"}}, Form: url.Values{"q": []string{"s"}, "pwd": []string{"secret"}, "user": []string{"test"}}},
+ "get,123,s,test,",
+ },
+ 5: {
+ &VaryBy{Cookies: []string{"ssn"}},
+ &http.Request{Header: http.Header{"Cookie": []string{ck.String()}}},
+ "test\n",
+ },
+ 6: {
+ &VaryBy{Cookies: []string{"ssn"}, RemoteAddr: true, Custom: func(r *http.Request) string {
+ return "blah"
+ }},
+ &http.Request{Header: http.Header{"Cookie": []string{ck.String()}}},
+ "blah",
+ },
+ }
+ for i, c := range cases {
+ got := c.vb.Key(c.r)
+ if got != c.k {
+ t.Errorf("%d: expected '%s' (%d), got '%s' (%d)", i, c.k, len(c.k), got, len(got))
+ }
+ }
+}
diff --git a/vendor/gopkg.in/yaml.v2/decode_test.go b/vendor/gopkg.in/yaml.v2/decode_test.go
new file mode 100644
index 000000000..c159760b6
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v2/decode_test.go
@@ -0,0 +1,988 @@
+package yaml_test
+
+import (
+ "errors"
+ . "gopkg.in/check.v1"
+ "gopkg.in/yaml.v2"
+ "math"
+ "net"
+ "reflect"
+ "strings"
+ "time"
+)
+
+var unmarshalIntTest = 123
+
+var unmarshalTests = []struct {
+ data string
+ value interface{}
+}{
+ {
+ "",
+ &struct{}{},
+ }, {
+ "{}", &struct{}{},
+ }, {
+ "v: hi",
+ map[string]string{"v": "hi"},
+ }, {
+ "v: hi", map[string]interface{}{"v": "hi"},
+ }, {
+ "v: true",
+ map[string]string{"v": "true"},
+ }, {
+ "v: true",
+ map[string]interface{}{"v": true},
+ }, {
+ "v: 10",
+ map[string]interface{}{"v": 10},
+ }, {
+ "v: 0b10",
+ map[string]interface{}{"v": 2},
+ }, {
+ "v: 0xA",
+ map[string]interface{}{"v": 10},
+ }, {
+ "v: 4294967296",
+ map[string]int64{"v": 4294967296},
+ }, {
+ "v: 0.1",
+ map[string]interface{}{"v": 0.1},
+ }, {
+ "v: .1",
+ map[string]interface{}{"v": 0.1},
+ }, {
+ "v: .Inf",
+ map[string]interface{}{"v": math.Inf(+1)},
+ }, {
+ "v: -.Inf",
+ map[string]interface{}{"v": math.Inf(-1)},
+ }, {
+ "v: -10",
+ map[string]interface{}{"v": -10},
+ }, {
+ "v: -.1",
+ map[string]interface{}{"v": -0.1},
+ },
+
+ // Simple values.
+ {
+ "123",
+ &unmarshalIntTest,
+ },
+
+ // Floats from spec
+ {
+ "canonical: 6.8523e+5",
+ map[string]interface{}{"canonical": 6.8523e+5},
+ }, {
+ "expo: 685.230_15e+03",
+ map[string]interface{}{"expo": 685.23015e+03},
+ }, {
+ "fixed: 685_230.15",
+ map[string]interface{}{"fixed": 685230.15},
+ }, {
+ "neginf: -.inf",
+ map[string]interface{}{"neginf": math.Inf(-1)},
+ }, {
+ "fixed: 685_230.15",
+ map[string]float64{"fixed": 685230.15},
+ },
+ //{"sexa: 190:20:30.15", map[string]interface{}{"sexa": 0}}, // Unsupported
+ //{"notanum: .NaN", map[string]interface{}{"notanum": math.NaN()}}, // Equality of NaN fails.
+
+ // Bools from spec
+ {
+ "canonical: y",
+ map[string]interface{}{"canonical": true},
+ }, {
+ "answer: NO",
+ map[string]interface{}{"answer": false},
+ }, {
+ "logical: True",
+ map[string]interface{}{"logical": true},
+ }, {
+ "option: on",
+ map[string]interface{}{"option": true},
+ }, {
+ "option: on",
+ map[string]bool{"option": true},
+ },
+ // Ints from spec
+ {
+ "canonical: 685230",
+ map[string]interface{}{"canonical": 685230},
+ }, {
+ "decimal: +685_230",
+ map[string]interface{}{"decimal": 685230},
+ }, {
+ "octal: 02472256",
+ map[string]interface{}{"octal": 685230},
+ }, {
+ "hexa: 0x_0A_74_AE",
+ map[string]interface{}{"hexa": 685230},
+ }, {
+ "bin: 0b1010_0111_0100_1010_1110",
+ map[string]interface{}{"bin": 685230},
+ }, {
+ "bin: -0b101010",
+ map[string]interface{}{"bin": -42},
+ }, {
+ "decimal: +685_230",
+ map[string]int{"decimal": 685230},
+ },
+
+ //{"sexa: 190:20:30", map[string]interface{}{"sexa": 0}}, // Unsupported
+
+ // Nulls from spec
+ {
+ "empty:",
+ map[string]interface{}{"empty": nil},
+ }, {
+ "canonical: ~",
+ map[string]interface{}{"canonical": nil},
+ }, {
+ "english: null",
+ map[string]interface{}{"english": nil},
+ }, {
+ "~: null key",
+ map[interface{}]string{nil: "null key"},
+ }, {
+ "empty:",
+ map[string]*bool{"empty": nil},
+ },
+
+ // Flow sequence
+ {
+ "seq: [A,B]",
+ map[string]interface{}{"seq": []interface{}{"A", "B"}},
+ }, {
+ "seq: [A,B,C,]",
+ map[string][]string{"seq": []string{"A", "B", "C"}},
+ }, {
+ "seq: [A,1,C]",
+ map[string][]string{"seq": []string{"A", "1", "C"}},
+ }, {
+ "seq: [A,1,C]",
+ map[string][]int{"seq": []int{1}},
+ }, {
+ "seq: [A,1,C]",
+ map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
+ },
+ // Block sequence
+ {
+ "seq:\n - A\n - B",
+ map[string]interface{}{"seq": []interface{}{"A", "B"}},
+ }, {
+ "seq:\n - A\n - B\n - C",
+ map[string][]string{"seq": []string{"A", "B", "C"}},
+ }, {
+ "seq:\n - A\n - 1\n - C",
+ map[string][]string{"seq": []string{"A", "1", "C"}},
+ }, {
+ "seq:\n - A\n - 1\n - C",
+ map[string][]int{"seq": []int{1}},
+ }, {
+ "seq:\n - A\n - 1\n - C",
+ map[string]interface{}{"seq": []interface{}{"A", 1, "C"}},
+ },
+
+ // Literal block scalar
+ {
+ "scalar: | # Comment\n\n literal\n\n \ttext\n\n",
+ map[string]string{"scalar": "\nliteral\n\n\ttext\n"},
+ },
+
+ // Folded block scalar
+ {
+ "scalar: > # Comment\n\n folded\n line\n \n next\n line\n * one\n * two\n\n last\n line\n\n",
+ map[string]string{"scalar": "\nfolded line\nnext line\n * one\n * two\n\nlast line\n"},
+ },
+
+ // Map inside interface with no type hints.
+ {
+ "a: {b: c}",
+ map[interface{}]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
+ },
+
+ // Structs and type conversions.
+ {
+ "hello: world",
+ &struct{ Hello string }{"world"},
+ }, {
+ "a: {b: c}",
+ &struct{ A struct{ B string } }{struct{ B string }{"c"}},
+ }, {
+ "a: {b: c}",
+ &struct{ A *struct{ B string } }{&struct{ B string }{"c"}},
+ }, {
+ "a: {b: c}",
+ &struct{ A map[string]string }{map[string]string{"b": "c"}},
+ }, {
+ "a: {b: c}",
+ &struct{ A *map[string]string }{&map[string]string{"b": "c"}},
+ }, {
+ "a:",
+ &struct{ A map[string]string }{},
+ }, {
+ "a: 1",
+ &struct{ A int }{1},
+ }, {
+ "a: 1",
+ &struct{ A float64 }{1},
+ }, {
+ "a: 1.0",
+ &struct{ A int }{1},
+ }, {
+ "a: 1.0",
+ &struct{ A uint }{1},
+ }, {
+ "a: [1, 2]",
+ &struct{ A []int }{[]int{1, 2}},
+ }, {
+ "a: 1",
+ &struct{ B int }{0},
+ }, {
+ "a: 1",
+ &struct {
+ B int "a"
+ }{1},
+ }, {
+ "a: y",
+ &struct{ A bool }{true},
+ },
+
+ // Some cross type conversions
+ {
+ "v: 42",
+ map[string]uint{"v": 42},
+ }, {
+ "v: -42",
+ map[string]uint{},
+ }, {
+ "v: 4294967296",
+ map[string]uint64{"v": 4294967296},
+ }, {
+ "v: -4294967296",
+ map[string]uint64{},
+ },
+
+ // int
+ {
+ "int_max: 2147483647",
+ map[string]int{"int_max": math.MaxInt32},
+ },
+ {
+ "int_min: -2147483648",
+ map[string]int{"int_min": math.MinInt32},
+ },
+ {
+ "int_overflow: 9223372036854775808", // math.MaxInt64 + 1
+ map[string]int{},
+ },
+
+ // int64
+ {
+ "int64_max: 9223372036854775807",
+ map[string]int64{"int64_max": math.MaxInt64},
+ },
+ {
+ "int64_max_base2: 0b111111111111111111111111111111111111111111111111111111111111111",
+ map[string]int64{"int64_max_base2": math.MaxInt64},
+ },
+ {
+ "int64_min: -9223372036854775808",
+ map[string]int64{"int64_min": math.MinInt64},
+ },
+ {
+ "int64_neg_base2: -0b111111111111111111111111111111111111111111111111111111111111111",
+ map[string]int64{"int64_neg_base2": -math.MaxInt64},
+ },
+ {
+ "int64_overflow: 9223372036854775808", // math.MaxInt64 + 1
+ map[string]int64{},
+ },
+
+ // uint
+ {
+ "uint_min: 0",
+ map[string]uint{"uint_min": 0},
+ },
+ {
+ "uint_max: 4294967295",
+ map[string]uint{"uint_max": math.MaxUint32},
+ },
+ {
+ "uint_underflow: -1",
+ map[string]uint{},
+ },
+
+ // uint64
+ {
+ "uint64_min: 0",
+ map[string]uint{"uint64_min": 0},
+ },
+ {
+ "uint64_max: 18446744073709551615",
+ map[string]uint64{"uint64_max": math.MaxUint64},
+ },
+ {
+ "uint64_max_base2: 0b1111111111111111111111111111111111111111111111111111111111111111",
+ map[string]uint64{"uint64_max_base2": math.MaxUint64},
+ },
+ {
+ "uint64_maxint64: 9223372036854775807",
+ map[string]uint64{"uint64_maxint64": math.MaxInt64},
+ },
+ {
+ "uint64_underflow: -1",
+ map[string]uint64{},
+ },
+
+ // float32
+ {
+ "float32_max: 3.40282346638528859811704183484516925440e+38",
+ map[string]float32{"float32_max": math.MaxFloat32},
+ },
+ {
+ "float32_nonzero: 1.401298464324817070923729583289916131280e-45",
+ map[string]float32{"float32_nonzero": math.SmallestNonzeroFloat32},
+ },
+ {
+ "float32_maxuint64: 18446744073709551615",
+ map[string]float32{"float32_maxuint64": float32(math.MaxUint64)},
+ },
+ {
+ "float32_maxuint64+1: 18446744073709551616",
+ map[string]float32{"float32_maxuint64+1": float32(math.MaxUint64 + 1)},
+ },
+
+ // float64
+ {
+ "float64_max: 1.797693134862315708145274237317043567981e+308",
+ map[string]float64{"float64_max": math.MaxFloat64},
+ },
+ {
+ "float64_nonzero: 4.940656458412465441765687928682213723651e-324",
+ map[string]float64{"float64_nonzero": math.SmallestNonzeroFloat64},
+ },
+ {
+ "float64_maxuint64: 18446744073709551615",
+ map[string]float64{"float64_maxuint64": float64(math.MaxUint64)},
+ },
+ {
+ "float64_maxuint64+1: 18446744073709551616",
+ map[string]float64{"float64_maxuint64+1": float64(math.MaxUint64 + 1)},
+ },
+
+ // Overflow cases.
+ {
+ "v: 4294967297",
+ map[string]int32{},
+ }, {
+ "v: 128",
+ map[string]int8{},
+ },
+
+ // Quoted values.
+ {
+ "'1': '\"2\"'",
+ map[interface{}]interface{}{"1": "\"2\""},
+ }, {
+ "v:\n- A\n- 'B\n\n C'\n",
+ map[string][]string{"v": []string{"A", "B\nC"}},
+ },
+
+ // Explicit tags.
+ {
+ "v: !!float '1.1'",
+ map[string]interface{}{"v": 1.1},
+ }, {
+ "v: !!null ''",
+ map[string]interface{}{"v": nil},
+ }, {
+ "%TAG !y! tag:yaml.org,2002:\n---\nv: !y!int '1'",
+ map[string]interface{}{"v": 1},
+ },
+
+ // Anchors and aliases.
+ {
+ "a: &x 1\nb: &y 2\nc: *x\nd: *y\n",
+ &struct{ A, B, C, D int }{1, 2, 1, 2},
+ }, {
+ "a: &a {c: 1}\nb: *a",
+ &struct {
+ A, B struct {
+ C int
+ }
+ }{struct{ C int }{1}, struct{ C int }{1}},
+ }, {
+ "a: &a [1, 2]\nb: *a",
+ &struct{ B []int }{[]int{1, 2}},
+ }, {
+ "b: *a\na: &a {c: 1}",
+ &struct {
+ A, B struct {
+ C int
+ }
+ }{struct{ C int }{1}, struct{ C int }{1}},
+ },
+
+ // Bug #1133337
+ {
+ "foo: ''",
+ map[string]*string{"foo": new(string)},
+ }, {
+ "foo: null",
+ map[string]string{"foo": ""},
+ }, {
+ "foo: null",
+ map[string]interface{}{"foo": nil},
+ },
+
+ // Ignored field
+ {
+ "a: 1\nb: 2\n",
+ &struct {
+ A int
+ B int "-"
+ }{1, 0},
+ },
+
+ // Bug #1191981
+ {
+ "" +
+ "%YAML 1.1\n" +
+ "--- !!str\n" +
+ `"Generic line break (no glyph)\n\` + "\n" +
+ ` Generic line break (glyphed)\n\` + "\n" +
+ ` Line separator\u2028\` + "\n" +
+ ` Paragraph separator\u2029"` + "\n",
+ "" +
+ "Generic line break (no glyph)\n" +
+ "Generic line break (glyphed)\n" +
+ "Line separator\u2028Paragraph separator\u2029",
+ },
+
+ // Struct inlining
+ {
+ "a: 1\nb: 2\nc: 3\n",
+ &struct {
+ A int
+ C inlineB `yaml:",inline"`
+ }{1, inlineB{2, inlineC{3}}},
+ },
+
+ // Map inlining
+ {
+ "a: 1\nb: 2\nc: 3\n",
+ &struct {
+ A int
+ C map[string]int `yaml:",inline"`
+ }{1, map[string]int{"b": 2, "c": 3}},
+ },
+
+ // bug 1243827
+ {
+ "a: -b_c",
+ map[string]interface{}{"a": "-b_c"},
+ },
+ {
+ "a: +b_c",
+ map[string]interface{}{"a": "+b_c"},
+ },
+ {
+ "a: 50cent_of_dollar",
+ map[string]interface{}{"a": "50cent_of_dollar"},
+ },
+
+ // Duration
+ {
+ "a: 3s",
+ map[string]time.Duration{"a": 3 * time.Second},
+ },
+
+ // Issue #24.
+ {
+ "a: <foo>",
+ map[string]string{"a": "<foo>"},
+ },
+
+ // Base 60 floats are obsolete and unsupported.
+ {
+ "a: 1:1\n",
+ map[string]string{"a": "1:1"},
+ },
+
+ // Binary data.
+ {
+ "a: !!binary gIGC\n",
+ map[string]string{"a": "\x80\x81\x82"},
+ }, {
+ "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
+ map[string]string{"a": strings.Repeat("\x90", 54)},
+ }, {
+ "a: !!binary |\n " + strings.Repeat("A", 70) + "\n ==\n",
+ map[string]string{"a": strings.Repeat("\x00", 52)},
+ },
+
+ // Ordered maps.
+ {
+ "{b: 2, a: 1, d: 4, c: 3, sub: {e: 5}}",
+ &yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
+ },
+
+ // Issue #39.
+ {
+ "a:\n b:\n c: d\n",
+ map[string]struct{ B interface{} }{"a": {map[interface{}]interface{}{"c": "d"}}},
+ },
+
+ // Custom map type.
+ {
+ "a: {b: c}",
+ M{"a": M{"b": "c"}},
+ },
+
+ // Support encoding.TextUnmarshaler.
+ {
+ "a: 1.2.3.4\n",
+ map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
+ },
+ {
+ "a: 2015-02-24T18:19:39Z\n",
+ map[string]time.Time{"a": time.Unix(1424801979, 0)},
+ },
+
+ // Encode empty lists as zero-length slices.
+ {
+ "a: []",
+ &struct{ A []int }{[]int{}},
+ },
+
+ // UTF-16-LE
+ {
+ "\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n\x00",
+ M{"ñoño": "very yes"},
+ },
+ // UTF-16-LE with surrogate.
+ {
+ "\xff\xfe\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \x00=\xd8\xd4\xdf\n\x00",
+ M{"ñoño": "very yes 🟔"},
+ },
+
+ // UTF-16-BE
+ {
+ "\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00\n",
+ M{"ñoño": "very yes"},
+ },
+ // UTF-16-BE with surrogate.
+ {
+ "\xfe\xff\x00\xf1\x00o\x00\xf1\x00o\x00:\x00 \x00v\x00e\x00r\x00y\x00 \x00y\x00e\x00s\x00 \xd8=\xdf\xd4\x00\n",
+ M{"ñoño": "very yes 🟔"},
+ },
+}
+
+type M map[interface{}]interface{}
+
+type inlineB struct {
+ B int
+ inlineC `yaml:",inline"`
+}
+
+type inlineC struct {
+ C int
+}
+
+func (s *S) TestUnmarshal(c *C) {
+ for _, item := range unmarshalTests {
+ t := reflect.ValueOf(item.value).Type()
+ var value interface{}
+ switch t.Kind() {
+ case reflect.Map:
+ value = reflect.MakeMap(t).Interface()
+ case reflect.String:
+ value = reflect.New(t).Interface()
+ case reflect.Ptr:
+ value = reflect.New(t.Elem()).Interface()
+ default:
+ c.Fatalf("missing case for %s", t)
+ }
+ err := yaml.Unmarshal([]byte(item.data), value)
+ if _, ok := err.(*yaml.TypeError); !ok {
+ c.Assert(err, IsNil)
+ }
+ if t.Kind() == reflect.String {
+ c.Assert(*value.(*string), Equals, item.value)
+ } else {
+ c.Assert(value, DeepEquals, item.value)
+ }
+ }
+}
+
+func (s *S) TestUnmarshalNaN(c *C) {
+ value := map[string]interface{}{}
+ err := yaml.Unmarshal([]byte("notanum: .NaN"), &value)
+ c.Assert(err, IsNil)
+ c.Assert(math.IsNaN(value["notanum"].(float64)), Equals, true)
+}
+
+var unmarshalErrorTests = []struct {
+ data, error string
+}{
+ {"v: !!float 'error'", "yaml: cannot decode !!str `error` as a !!float"},
+ {"v: [A,", "yaml: line 1: did not find expected node content"},
+ {"v:\n- [A,", "yaml: line 2: did not find expected node content"},
+ {"a: *b\n", "yaml: unknown anchor 'b' referenced"},
+ {"a: &a\n b: *a\n", "yaml: anchor 'a' value contains itself"},
+ {"value: -", "yaml: block sequence entries are not allowed in this context"},
+ {"a: !!binary ==", "yaml: !!binary value contains invalid base64 data"},
+ {"{[.]}", `yaml: invalid map key: \[\]interface \{\}\{"\."\}`},
+ {"{{.}}", `yaml: invalid map key: map\[interface\ \{\}\]interface \{\}\{".":interface \{\}\(nil\)\}`},
+}
+
+func (s *S) TestUnmarshalErrors(c *C) {
+ for _, item := range unmarshalErrorTests {
+ var value interface{}
+ err := yaml.Unmarshal([]byte(item.data), &value)
+ c.Assert(err, ErrorMatches, item.error, Commentf("Partial unmarshal: %#v", value))
+ }
+}
+
+var unmarshalerTests = []struct {
+ data, tag string
+ value interface{}
+}{
+ {"_: {hi: there}", "!!map", map[interface{}]interface{}{"hi": "there"}},
+ {"_: [1,A]", "!!seq", []interface{}{1, "A"}},
+ {"_: 10", "!!int", 10},
+ {"_: null", "!!null", nil},
+ {`_: BAR!`, "!!str", "BAR!"},
+ {`_: "BAR!"`, "!!str", "BAR!"},
+ {"_: !!foo 'BAR!'", "!!foo", "BAR!"},
+}
+
+var unmarshalerResult = map[int]error{}
+
+type unmarshalerType struct {
+ value interface{}
+}
+
+func (o *unmarshalerType) UnmarshalYAML(unmarshal func(v interface{}) error) error {
+ if err := unmarshal(&o.value); err != nil {
+ return err
+ }
+ if i, ok := o.value.(int); ok {
+ if result, ok := unmarshalerResult[i]; ok {
+ return result
+ }
+ }
+ return nil
+}
+
+type unmarshalerPointer struct {
+ Field *unmarshalerType "_"
+}
+
+type unmarshalerValue struct {
+ Field unmarshalerType "_"
+}
+
+func (s *S) TestUnmarshalerPointerField(c *C) {
+ for _, item := range unmarshalerTests {
+ obj := &unmarshalerPointer{}
+ err := yaml.Unmarshal([]byte(item.data), obj)
+ c.Assert(err, IsNil)
+ if item.value == nil {
+ c.Assert(obj.Field, IsNil)
+ } else {
+ c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value))
+ c.Assert(obj.Field.value, DeepEquals, item.value)
+ }
+ }
+}
+
+func (s *S) TestUnmarshalerValueField(c *C) {
+ for _, item := range unmarshalerTests {
+ obj := &unmarshalerValue{}
+ err := yaml.Unmarshal([]byte(item.data), obj)
+ c.Assert(err, IsNil)
+ c.Assert(obj.Field, NotNil, Commentf("Pointer not initialized (%#v)", item.value))
+ c.Assert(obj.Field.value, DeepEquals, item.value)
+ }
+}
+
+func (s *S) TestUnmarshalerWholeDocument(c *C) {
+ obj := &unmarshalerType{}
+ err := yaml.Unmarshal([]byte(unmarshalerTests[0].data), obj)
+ c.Assert(err, IsNil)
+ value, ok := obj.value.(map[interface{}]interface{})
+ c.Assert(ok, Equals, true, Commentf("value: %#v", obj.value))
+ c.Assert(value["_"], DeepEquals, unmarshalerTests[0].value)
+}
+
+func (s *S) TestUnmarshalerTypeError(c *C) {
+ unmarshalerResult[2] = &yaml.TypeError{[]string{"foo"}}
+ unmarshalerResult[4] = &yaml.TypeError{[]string{"bar"}}
+ defer func() {
+ delete(unmarshalerResult, 2)
+ delete(unmarshalerResult, 4)
+ }()
+
+ type T struct {
+ Before int
+ After int
+ M map[string]*unmarshalerType
+ }
+ var v T
+ data := `{before: A, m: {abc: 1, def: 2, ghi: 3, jkl: 4}, after: B}`
+ err := yaml.Unmarshal([]byte(data), &v)
+ c.Assert(err, ErrorMatches, ""+
+ "yaml: unmarshal errors:\n"+
+ " line 1: cannot unmarshal !!str `A` into int\n"+
+ " foo\n"+
+ " bar\n"+
+ " line 1: cannot unmarshal !!str `B` into int")
+ c.Assert(v.M["abc"], NotNil)
+ c.Assert(v.M["def"], IsNil)
+ c.Assert(v.M["ghi"], NotNil)
+ c.Assert(v.M["jkl"], IsNil)
+
+ c.Assert(v.M["abc"].value, Equals, 1)
+ c.Assert(v.M["ghi"].value, Equals, 3)
+}
+
+type proxyTypeError struct{}
+
+func (v *proxyTypeError) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var s string
+ var a int32
+ var b int64
+ if err := unmarshal(&s); err != nil {
+ panic(err)
+ }
+ if s == "a" {
+ if err := unmarshal(&b); err == nil {
+ panic("should have failed")
+ }
+ return unmarshal(&a)
+ }
+ if err := unmarshal(&a); err == nil {
+ panic("should have failed")
+ }
+ return unmarshal(&b)
+}
+
+func (s *S) TestUnmarshalerTypeErrorProxying(c *C) {
+ type T struct {
+ Before int
+ After int
+ M map[string]*proxyTypeError
+ }
+ var v T
+ data := `{before: A, m: {abc: a, def: b}, after: B}`
+ err := yaml.Unmarshal([]byte(data), &v)
+ c.Assert(err, ErrorMatches, ""+
+ "yaml: unmarshal errors:\n"+
+ " line 1: cannot unmarshal !!str `A` into int\n"+
+ " line 1: cannot unmarshal !!str `a` into int32\n"+
+ " line 1: cannot unmarshal !!str `b` into int64\n"+
+ " line 1: cannot unmarshal !!str `B` into int")
+}
+
+type failingUnmarshaler struct{}
+
+var failingErr = errors.New("failingErr")
+
+func (ft *failingUnmarshaler) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ return failingErr
+}
+
+func (s *S) TestUnmarshalerError(c *C) {
+ err := yaml.Unmarshal([]byte("a: b"), &failingUnmarshaler{})
+ c.Assert(err, Equals, failingErr)
+}
+
+type sliceUnmarshaler []int
+
+func (su *sliceUnmarshaler) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ var slice []int
+ err := unmarshal(&slice)
+ if err == nil {
+ *su = slice
+ return nil
+ }
+
+ var intVal int
+ err = unmarshal(&intVal)
+ if err == nil {
+ *su = []int{intVal}
+ return nil
+ }
+
+ return err
+}
+
+func (s *S) TestUnmarshalerRetry(c *C) {
+ var su sliceUnmarshaler
+ err := yaml.Unmarshal([]byte("[1, 2, 3]"), &su)
+ c.Assert(err, IsNil)
+ c.Assert(su, DeepEquals, sliceUnmarshaler([]int{1, 2, 3}))
+
+ err = yaml.Unmarshal([]byte("1"), &su)
+ c.Assert(err, IsNil)
+ c.Assert(su, DeepEquals, sliceUnmarshaler([]int{1}))
+}
+
+// From http://yaml.org/type/merge.html
+var mergeTests = `
+anchors:
+ list:
+ - &CENTER { "x": 1, "y": 2 }
+ - &LEFT { "x": 0, "y": 2 }
+ - &BIG { "r": 10 }
+ - &SMALL { "r": 1 }
+
+# All the following maps are equal:
+
+plain:
+ # Explicit keys
+ "x": 1
+ "y": 2
+ "r": 10
+ label: center/big
+
+mergeOne:
+ # Merge one map
+ << : *CENTER
+ "r": 10
+ label: center/big
+
+mergeMultiple:
+ # Merge multiple maps
+ << : [ *CENTER, *BIG ]
+ label: center/big
+
+override:
+ # Override
+ << : [ *BIG, *LEFT, *SMALL ]
+ "x": 1
+ label: center/big
+
+shortTag:
+ # Explicit short merge tag
+ !!merge "<<" : [ *CENTER, *BIG ]
+ label: center/big
+
+longTag:
+ # Explicit merge long tag
+ !<tag:yaml.org,2002:merge> "<<" : [ *CENTER, *BIG ]
+ label: center/big
+
+inlineMap:
+ # Inlined map
+ << : {"x": 1, "y": 2, "r": 10}
+ label: center/big
+
+inlineSequenceMap:
+ # Inlined map in sequence
+ << : [ *CENTER, {"r": 10} ]
+ label: center/big
+`
+
+func (s *S) TestMerge(c *C) {
+ var want = map[interface{}]interface{}{
+ "x": 1,
+ "y": 2,
+ "r": 10,
+ "label": "center/big",
+ }
+
+ var m map[interface{}]interface{}
+ err := yaml.Unmarshal([]byte(mergeTests), &m)
+ c.Assert(err, IsNil)
+ for name, test := range m {
+ if name == "anchors" {
+ continue
+ }
+ c.Assert(test, DeepEquals, want, Commentf("test %q failed", name))
+ }
+}
+
+func (s *S) TestMergeStruct(c *C) {
+ type Data struct {
+ X, Y, R int
+ Label string
+ }
+ want := Data{1, 2, 10, "center/big"}
+
+ var m map[string]Data
+ err := yaml.Unmarshal([]byte(mergeTests), &m)
+ c.Assert(err, IsNil)
+ for name, test := range m {
+ if name == "anchors" {
+ continue
+ }
+ c.Assert(test, Equals, want, Commentf("test %q failed", name))
+ }
+}
+
+var unmarshalNullTests = []func() interface{}{
+ func() interface{} { var v interface{}; v = "v"; return &v },
+ func() interface{} { var s = "s"; return &s },
+ func() interface{} { var s = "s"; sptr := &s; return &sptr },
+ func() interface{} { var i = 1; return &i },
+ func() interface{} { var i = 1; iptr := &i; return &iptr },
+ func() interface{} { m := map[string]int{"s": 1}; return &m },
+ func() interface{} { m := map[string]int{"s": 1}; return m },
+}
+
+func (s *S) TestUnmarshalNull(c *C) {
+ for _, test := range unmarshalNullTests {
+ item := test()
+ zero := reflect.Zero(reflect.TypeOf(item).Elem()).Interface()
+ err := yaml.Unmarshal([]byte("null"), item)
+ c.Assert(err, IsNil)
+ if reflect.TypeOf(item).Kind() == reflect.Map {
+ c.Assert(reflect.ValueOf(item).Interface(), DeepEquals, reflect.MakeMap(reflect.TypeOf(item)).Interface())
+ } else {
+ c.Assert(reflect.ValueOf(item).Elem().Interface(), DeepEquals, zero)
+ }
+ }
+}
+
+func (s *S) TestUnmarshalSliceOnPreset(c *C) {
+ // Issue #48.
+ v := struct{ A []int }{[]int{1}}
+ yaml.Unmarshal([]byte("a: [2]"), &v)
+ c.Assert(v.A, DeepEquals, []int{2})
+}
+
+//var data []byte
+//func init() {
+// var err error
+// data, err = ioutil.ReadFile("/tmp/file.yaml")
+// if err != nil {
+// panic(err)
+// }
+//}
+//
+//func (s *S) BenchmarkUnmarshal(c *C) {
+// var err error
+// for i := 0; i < c.N; i++ {
+// var v map[string]interface{}
+// err = yaml.Unmarshal(data, &v)
+// }
+// if err != nil {
+// panic(err)
+// }
+//}
+//
+//func (s *S) BenchmarkMarshal(c *C) {
+// var v map[string]interface{}
+// yaml.Unmarshal(data, &v)
+// c.ResetTimer()
+// for i := 0; i < c.N; i++ {
+// yaml.Marshal(&v)
+// }
+//}
diff --git a/vendor/gopkg.in/yaml.v2/encode_test.go b/vendor/gopkg.in/yaml.v2/encode_test.go
new file mode 100644
index 000000000..84099bd38
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v2/encode_test.go
@@ -0,0 +1,501 @@
+package yaml_test
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+ "time"
+
+ . "gopkg.in/check.v1"
+ "gopkg.in/yaml.v2"
+ "net"
+ "os"
+)
+
+var marshalIntTest = 123
+
+var marshalTests = []struct {
+ value interface{}
+ data string
+}{
+ {
+ nil,
+ "null\n",
+ }, {
+ &struct{}{},
+ "{}\n",
+ }, {
+ map[string]string{"v": "hi"},
+ "v: hi\n",
+ }, {
+ map[string]interface{}{"v": "hi"},
+ "v: hi\n",
+ }, {
+ map[string]string{"v": "true"},
+ "v: \"true\"\n",
+ }, {
+ map[string]string{"v": "false"},
+ "v: \"false\"\n",
+ }, {
+ map[string]interface{}{"v": true},
+ "v: true\n",
+ }, {
+ map[string]interface{}{"v": false},
+ "v: false\n",
+ }, {
+ map[string]interface{}{"v": 10},
+ "v: 10\n",
+ }, {
+ map[string]interface{}{"v": -10},
+ "v: -10\n",
+ }, {
+ map[string]uint{"v": 42},
+ "v: 42\n",
+ }, {
+ map[string]interface{}{"v": int64(4294967296)},
+ "v: 4294967296\n",
+ }, {
+ map[string]int64{"v": int64(4294967296)},
+ "v: 4294967296\n",
+ }, {
+ map[string]uint64{"v": 4294967296},
+ "v: 4294967296\n",
+ }, {
+ map[string]interface{}{"v": "10"},
+ "v: \"10\"\n",
+ }, {
+ map[string]interface{}{"v": 0.1},
+ "v: 0.1\n",
+ }, {
+ map[string]interface{}{"v": float64(0.1)},
+ "v: 0.1\n",
+ }, {
+ map[string]interface{}{"v": -0.1},
+ "v: -0.1\n",
+ }, {
+ map[string]interface{}{"v": math.Inf(+1)},
+ "v: .inf\n",
+ }, {
+ map[string]interface{}{"v": math.Inf(-1)},
+ "v: -.inf\n",
+ }, {
+ map[string]interface{}{"v": math.NaN()},
+ "v: .nan\n",
+ }, {
+ map[string]interface{}{"v": nil},
+ "v: null\n",
+ }, {
+ map[string]interface{}{"v": ""},
+ "v: \"\"\n",
+ }, {
+ map[string][]string{"v": []string{"A", "B"}},
+ "v:\n- A\n- B\n",
+ }, {
+ map[string][]string{"v": []string{"A", "B\nC"}},
+ "v:\n- A\n- |-\n B\n C\n",
+ }, {
+ map[string][]interface{}{"v": []interface{}{"A", 1, map[string][]int{"B": []int{2, 3}}}},
+ "v:\n- A\n- 1\n- B:\n - 2\n - 3\n",
+ }, {
+ map[string]interface{}{"a": map[interface{}]interface{}{"b": "c"}},
+ "a:\n b: c\n",
+ }, {
+ map[string]interface{}{"a": "-"},
+ "a: '-'\n",
+ },
+
+ // Simple values.
+ {
+ &marshalIntTest,
+ "123\n",
+ },
+
+ // Structures
+ {
+ &struct{ Hello string }{"world"},
+ "hello: world\n",
+ }, {
+ &struct {
+ A struct {
+ B string
+ }
+ }{struct{ B string }{"c"}},
+ "a:\n b: c\n",
+ }, {
+ &struct {
+ A *struct {
+ B string
+ }
+ }{&struct{ B string }{"c"}},
+ "a:\n b: c\n",
+ }, {
+ &struct {
+ A *struct {
+ B string
+ }
+ }{},
+ "a: null\n",
+ }, {
+ &struct{ A int }{1},
+ "a: 1\n",
+ }, {
+ &struct{ A []int }{[]int{1, 2}},
+ "a:\n- 1\n- 2\n",
+ }, {
+ &struct {
+ B int "a"
+ }{1},
+ "a: 1\n",
+ }, {
+ &struct{ A bool }{true},
+ "a: true\n",
+ },
+
+ // Conditional flag
+ {
+ &struct {
+ A int "a,omitempty"
+ B int "b,omitempty"
+ }{1, 0},
+ "a: 1\n",
+ }, {
+ &struct {
+ A int "a,omitempty"
+ B int "b,omitempty"
+ }{0, 0},
+ "{}\n",
+ }, {
+ &struct {
+ A *struct{ X, y int } "a,omitempty,flow"
+ }{&struct{ X, y int }{1, 2}},
+ "a: {x: 1}\n",
+ }, {
+ &struct {
+ A *struct{ X, y int } "a,omitempty,flow"
+ }{nil},
+ "{}\n",
+ }, {
+ &struct {
+ A *struct{ X, y int } "a,omitempty,flow"
+ }{&struct{ X, y int }{}},
+ "a: {x: 0}\n",
+ }, {
+ &struct {
+ A struct{ X, y int } "a,omitempty,flow"
+ }{struct{ X, y int }{1, 2}},
+ "a: {x: 1}\n",
+ }, {
+ &struct {
+ A struct{ X, y int } "a,omitempty,flow"
+ }{struct{ X, y int }{0, 1}},
+ "{}\n",
+ }, {
+ &struct {
+ A float64 "a,omitempty"
+ B float64 "b,omitempty"
+ }{1, 0},
+ "a: 1\n",
+ },
+
+ // Flow flag
+ {
+ &struct {
+ A []int "a,flow"
+ }{[]int{1, 2}},
+ "a: [1, 2]\n",
+ }, {
+ &struct {
+ A map[string]string "a,flow"
+ }{map[string]string{"b": "c", "d": "e"}},
+ "a: {b: c, d: e}\n",
+ }, {
+ &struct {
+ A struct {
+ B, D string
+ } "a,flow"
+ }{struct{ B, D string }{"c", "e"}},
+ "a: {b: c, d: e}\n",
+ },
+
+ // Unexported field
+ {
+ &struct {
+ u int
+ A int
+ }{0, 1},
+ "a: 1\n",
+ },
+
+ // Ignored field
+ {
+ &struct {
+ A int
+ B int "-"
+ }{1, 2},
+ "a: 1\n",
+ },
+
+ // Struct inlining
+ {
+ &struct {
+ A int
+ C inlineB `yaml:",inline"`
+ }{1, inlineB{2, inlineC{3}}},
+ "a: 1\nb: 2\nc: 3\n",
+ },
+
+ // Map inlining
+ {
+ &struct {
+ A int
+ C map[string]int `yaml:",inline"`
+ }{1, map[string]int{"b": 2, "c": 3}},
+ "a: 1\nb: 2\nc: 3\n",
+ },
+
+ // Duration
+ {
+ map[string]time.Duration{"a": 3 * time.Second},
+ "a: 3s\n",
+ },
+
+ // Issue #24: bug in map merging logic.
+ {
+ map[string]string{"a": "<foo>"},
+ "a: <foo>\n",
+ },
+
+ // Issue #34: marshal unsupported base 60 floats quoted for compatibility
+ // with old YAML 1.1 parsers.
+ {
+ map[string]string{"a": "1:1"},
+ "a: \"1:1\"\n",
+ },
+
+ // Binary data.
+ {
+ map[string]string{"a": "\x00"},
+ "a: \"\\0\"\n",
+ }, {
+ map[string]string{"a": "\x80\x81\x82"},
+ "a: !!binary gIGC\n",
+ }, {
+ map[string]string{"a": strings.Repeat("\x90", 54)},
+ "a: !!binary |\n " + strings.Repeat("kJCQ", 17) + "kJ\n CQ\n",
+ },
+
+ // Ordered maps.
+ {
+ &yaml.MapSlice{{"b", 2}, {"a", 1}, {"d", 4}, {"c", 3}, {"sub", yaml.MapSlice{{"e", 5}}}},
+ "b: 2\na: 1\nd: 4\nc: 3\nsub:\n e: 5\n",
+ },
+
+ // Encode unicode as utf-8 rather than in escaped form.
+ {
+ map[string]string{"a": "你好"},
+ "a: 你好\n",
+ },
+
+ // Support encoding.TextMarshaler.
+ {
+ map[string]net.IP{"a": net.IPv4(1, 2, 3, 4)},
+ "a: 1.2.3.4\n",
+ },
+ {
+ map[string]time.Time{"a": time.Unix(1424801979, 0)},
+ "a: 2015-02-24T18:19:39Z\n",
+ },
+
+ // Ensure strings containing ": " are quoted (reported as PR #43, but not reproducible).
+ {
+ map[string]string{"a": "b: c"},
+ "a: 'b: c'\n",
+ },
+
+ // Containing hash mark ('#') in string should be quoted
+ {
+ map[string]string{"a": "Hello #comment"},
+ "a: 'Hello #comment'\n",
+ },
+ {
+ map[string]string{"a": "你好 #comment"},
+ "a: '你好 #comment'\n",
+ },
+}
+
+func (s *S) TestMarshal(c *C) {
+ defer os.Setenv("TZ", os.Getenv("TZ"))
+ os.Setenv("TZ", "UTC")
+ for _, item := range marshalTests {
+ data, err := yaml.Marshal(item.value)
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, item.data)
+ }
+}
+
+var marshalErrorTests = []struct {
+ value interface{}
+ error string
+ panic string
+}{{
+ value: &struct {
+ B int
+ inlineB ",inline"
+ }{1, inlineB{2, inlineC{3}}},
+ panic: `Duplicated key 'b' in struct struct \{ B int; .*`,
+}, {
+ value: &struct {
+ A int
+ B map[string]int ",inline"
+ }{1, map[string]int{"a": 2}},
+ panic: `Can't have key "a" in inlined map; conflicts with struct field`,
+}}
+
+func (s *S) TestMarshalErrors(c *C) {
+ for _, item := range marshalErrorTests {
+ if item.panic != "" {
+ c.Assert(func() { yaml.Marshal(item.value) }, PanicMatches, item.panic)
+ } else {
+ _, err := yaml.Marshal(item.value)
+ c.Assert(err, ErrorMatches, item.error)
+ }
+ }
+}
+
+func (s *S) TestMarshalTypeCache(c *C) {
+ var data []byte
+ var err error
+ func() {
+ type T struct{ A int }
+ data, err = yaml.Marshal(&T{})
+ c.Assert(err, IsNil)
+ }()
+ func() {
+ type T struct{ B int }
+ data, err = yaml.Marshal(&T{})
+ c.Assert(err, IsNil)
+ }()
+ c.Assert(string(data), Equals, "b: 0\n")
+}
+
+var marshalerTests = []struct {
+ data string
+ value interface{}
+}{
+ {"_:\n hi: there\n", map[interface{}]interface{}{"hi": "there"}},
+ {"_:\n- 1\n- A\n", []interface{}{1, "A"}},
+ {"_: 10\n", 10},
+ {"_: null\n", nil},
+ {"_: BAR!\n", "BAR!"},
+}
+
+type marshalerType struct {
+ value interface{}
+}
+
+func (o marshalerType) MarshalText() ([]byte, error) {
+ panic("MarshalText called on type with MarshalYAML")
+}
+
+func (o marshalerType) MarshalYAML() (interface{}, error) {
+ return o.value, nil
+}
+
+type marshalerValue struct {
+ Field marshalerType "_"
+}
+
+func (s *S) TestMarshaler(c *C) {
+ for _, item := range marshalerTests {
+ obj := &marshalerValue{}
+ obj.Field.value = item.value
+ data, err := yaml.Marshal(obj)
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, string(item.data))
+ }
+}
+
+func (s *S) TestMarshalerWholeDocument(c *C) {
+ obj := &marshalerType{}
+ obj.value = map[string]string{"hello": "world!"}
+ data, err := yaml.Marshal(obj)
+ c.Assert(err, IsNil)
+ c.Assert(string(data), Equals, "hello: world!\n")
+}
+
+type failingMarshaler struct{}
+
+func (ft *failingMarshaler) MarshalYAML() (interface{}, error) {
+ return nil, failingErr
+}
+
+func (s *S) TestMarshalerError(c *C) {
+ _, err := yaml.Marshal(&failingMarshaler{})
+ c.Assert(err, Equals, failingErr)
+}
+
+func (s *S) TestSortedOutput(c *C) {
+ order := []interface{}{
+ false,
+ true,
+ 1,
+ uint(1),
+ 1.0,
+ 1.1,
+ 1.2,
+ 2,
+ uint(2),
+ 2.0,
+ 2.1,
+ "",
+ ".1",
+ ".2",
+ ".a",
+ "1",
+ "2",
+ "a!10",
+ "a/2",
+ "a/10",
+ "a~10",
+ "ab/1",
+ "b/1",
+ "b/01",
+ "b/2",
+ "b/02",
+ "b/3",
+ "b/03",
+ "b1",
+ "b01",
+ "b3",
+ "c2.10",
+ "c10.2",
+ "d1",
+ "d12",
+ "d12a",
+ }
+ m := make(map[interface{}]int)
+ for _, k := range order {
+ m[k] = 1
+ }
+ data, err := yaml.Marshal(m)
+ c.Assert(err, IsNil)
+ out := "\n" + string(data)
+ last := 0
+ for i, k := range order {
+ repr := fmt.Sprint(k)
+ if s, ok := k.(string); ok {
+ if _, err = strconv.ParseFloat(repr, 32); s == "" || err == nil {
+ repr = `"` + repr + `"`
+ }
+ }
+ index := strings.Index(out, "\n"+repr+":")
+ if index == -1 {
+ c.Fatalf("%#v is not in the output: %#v", k, out)
+ }
+ if index < last {
+ c.Fatalf("%#v was generated before %#v: %q", k, order[i-1], out)
+ }
+ last = index
+ }
+}
diff --git a/vendor/gopkg.in/yaml.v2/suite_test.go b/vendor/gopkg.in/yaml.v2/suite_test.go
new file mode 100644
index 000000000..c5cf1ed4f
--- /dev/null
+++ b/vendor/gopkg.in/yaml.v2/suite_test.go
@@ -0,0 +1,12 @@
+package yaml_test
+
+import (
+ . "gopkg.in/check.v1"
+ "testing"
+)
+
+func Test(t *testing.T) { TestingT(t) }
+
+type S struct{}
+
+var _ = Suite(&S{})